summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Dodge <mikedodge04@fb.com>2017-03-10 14:46:20 -0800
committerMike Dodge <mikedodge04@fb.com>2017-03-10 14:46:20 -0800
commit05ee356ca5c97d1b972f3f4877ad16c40609a58e (patch)
treeb5c8e59fc6a3eea70e6a63addef4eb079f538dea
parent1130d5472a2da541a9c03c4aeb0eac52c71db8fc (diff)
downloadchef-05ee356ca5c97d1b972f3f4877ad16c40609a58e.tar.gz
Squash
Signed-off-by: Mike Dodge <mikedodge04@fb.com>
-rw-r--r--.bundle/config2
-rw-r--r--.github/ISSUE_TEMPLATE.md36
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md15
-rw-r--r--.gitignore23
-rw-r--r--.kitchen.yml82
-rw-r--r--.mailmap65
-rw-r--r--.rubocop.yml6
-rw-r--r--.travis.yml404
-rw-r--r--CBGB.md40
-rw-r--r--CBGB.toml96
-rw-r--r--CHANGELOG.md592
-rw-r--r--CONTRIBUTING.md247
-rw-r--r--DOC_CHANGES.md460
-rw-r--r--Dockerfile11
-rw-r--r--Gemfile89
-rw-r--r--Gemfile.lock593
-rw-r--r--HISTORY.md1331
-rw-r--r--MAINTAINERS.md47
-rw-r--r--MAINTAINERS.toml112
-rw-r--r--NOTICE20
-rw-r--r--README.md260
-rw-r--r--RELEASE_NOTES.md191
-rw-r--r--ROADMAP.md15
-rw-r--r--Rakefile79
-rw-r--r--VERSION2
-rw-r--r--acceptance/.gitignore3
-rw-r--r--acceptance/.shared/kitchen_acceptance/.kitchen.digitalocean.yml33
-rw-r--r--acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml282
-rw-r--r--acceptance/.shared/kitchen_acceptance/.kitchen.vagrant.yml59
-rw-r--r--acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb68
-rw-r--r--acceptance/.shared/kitchen_acceptance/metadata.rb1
-rw-r--r--acceptance/Gemfile16
-rw-r--r--acceptance/Gemfile.lock258
-rw-r--r--acceptance/README.md137
-rw-r--r--acceptance/basics/.acceptance/acceptance-cookbook/.gitignore2
-rw-r--r--acceptance/basics/.acceptance/acceptance-cookbook/metadata.rb3
-rw-r--r--acceptance/basics/.acceptance/acceptance-cookbook/recipes/destroy.rb1
-rw-r--r--acceptance/basics/.acceptance/acceptance-cookbook/recipes/provision.rb1
-rw-r--r--acceptance/basics/.acceptance/acceptance-cookbook/recipes/verify.rb1
-rw-r--r--acceptance/basics/.kitchen.yml4
-rw-r--r--acceptance/basics/test/integration/chef-current-install/serverspec/chef_client_spec.rb19
-rw-r--r--acceptance/basics/test/integration/chef-current-install/serverspec/spec_helper.rb6
-rw-r--r--acceptance/basics/test/integration/helpers/serverspec/Gemfile8
-rw-r--r--acceptance/data-collector/.acceptance/acceptance-cookbook/.gitignore2
-rw-r--r--acceptance/data-collector/.acceptance/acceptance-cookbook/metadata.rb3
-rw-r--r--acceptance/data-collector/.acceptance/acceptance-cookbook/recipes/destroy.rb2
-rw-r--r--acceptance/data-collector/.acceptance/acceptance-cookbook/recipes/provision.rb2
-rw-r--r--acceptance/data-collector/.acceptance/acceptance-cookbook/recipes/verify.rb2
-rw-r--r--acceptance/data-collector/.acceptance/data-collector-test/.gitignore16
-rw-r--r--acceptance/data-collector/.acceptance/data-collector-test/Berksfile3
-rw-r--r--acceptance/data-collector/.acceptance/data-collector-test/files/default/api.rb85
-rw-r--r--acceptance/data-collector/.acceptance/data-collector-test/files/default/apigemfile3
-rw-r--r--acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-both-mode.rb4
-rw-r--r--acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-client-mode.rb4
-rw-r--r--acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-no-endpoint.rb2
-rw-r--r--acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-solo-mode.rb4
-rw-r--r--acceptance/data-collector/.acceptance/data-collector-test/files/default/config.ru2
-rw-r--r--acceptance/data-collector/.acceptance/data-collector-test/metadata.rb7
-rw-r--r--acceptance/data-collector/.acceptance/data-collector-test/recipes/default.rb38
-rw-r--r--acceptance/data-collector/.kitchen.yml9
-rw-r--r--acceptance/data-collector/Berksfile3
-rw-r--r--acceptance/data-collector/test/integration/default/serverspec/default_spec.rb204
-rw-r--r--acceptance/data-collector/test/integration/helpers/serverspec/Gemfile8
-rw-r--r--acceptance/fips/.acceptance/acceptance-cookbook/.gitignore2
-rw-r--r--acceptance/fips/.acceptance/acceptance-cookbook/metadata.rb2
-rw-r--r--acceptance/fips/.acceptance/acceptance-cookbook/recipes/destroy.rb1
-rw-r--r--acceptance/fips/.acceptance/acceptance-cookbook/recipes/provision.rb1
-rw-r--r--acceptance/fips/.acceptance/acceptance-cookbook/recipes/verify.rb1
-rw-r--r--acceptance/fips/.kitchen.yml8
-rw-r--r--acceptance/fips/test/integration/fips-integration/serverspec/Gemfile9
-rw-r--r--acceptance/fips/test/integration/fips-integration/serverspec/fips-integration_spec.rb52
-rw-r--r--acceptance/fips/test/integration/fips-unit-functional/serverspec/Gemfile7
-rw-r--r--acceptance/fips/test/integration/fips-unit-functional/serverspec/fips-unit-functional_spec.rb56
-rw-r--r--acceptance/omnitruck/.acceptance/acceptance-cookbook/.gitignore2
-rw-r--r--acceptance/omnitruck/.acceptance/acceptance-cookbook/metadata.rb1
-rw-r--r--acceptance/omnitruck/.acceptance/acceptance-cookbook/recipes/destroy.rb1
-rw-r--r--acceptance/omnitruck/.acceptance/acceptance-cookbook/recipes/provision.rb1
-rw-r--r--acceptance/omnitruck/.acceptance/acceptance-cookbook/recipes/verify.rb61
-rw-r--r--acceptance/top-cookbooks/.acceptance/acceptance-cookbook/.gitignore2
-rw-r--r--acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/cookbook_kitchen.rb43
-rw-r--r--acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/top_cookbooks.rb45
-rw-r--r--acceptance/top-cookbooks/.acceptance/acceptance-cookbook/metadata.rb3
-rw-r--r--acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/destroy.rb1
-rw-r--r--acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/provision.rb1
-rw-r--r--acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/verify.rb1
-rw-r--r--acceptance/top-cookbooks/.gitignore1
-rw-r--r--acceptance/top-cookbooks/.kitchen.chocolatey.yml6
-rw-r--r--acceptance/top-cookbooks/.kitchen.docker.yml9
-rw-r--r--acceptance/top-cookbooks/.kitchen.git.yml11
-rw-r--r--acceptance/top-cookbooks/.kitchen.iis.yml4
-rw-r--r--acceptance/top-cookbooks/.kitchen.learn-the-basics-rhel.yml7
-rw-r--r--acceptance/top-cookbooks/.kitchen.learn-the-basics-ubuntu.yml7
-rw-r--r--acceptance/top-cookbooks/.kitchen.learn-the-basics-windows.yml7
-rw-r--r--acceptance/top-cookbooks/.kitchen.powershell.yml4
-rw-r--r--acceptance/top-cookbooks/.kitchen.sql_server.yml5
-rw-r--r--acceptance/top-cookbooks/.kitchen.winbox.yml8
-rw-r--r--acceptance/top-cookbooks/.kitchen.windows.yml38
-rw-r--r--acceptance/trivial/.acceptance/acceptance-cookbook/.gitignore2
-rw-r--r--acceptance/trivial/.acceptance/acceptance-cookbook/metadata.rb2
-rw-r--r--acceptance/trivial/.acceptance/acceptance-cookbook/recipes/destroy.rb1
-rw-r--r--acceptance/trivial/.acceptance/acceptance-cookbook/recipes/provision.rb1
-rw-r--r--acceptance/trivial/.acceptance/acceptance-cookbook/recipes/verify.rb1
-rw-r--r--acceptance/trivial/.kitchen.yml7
-rw-r--r--acceptance/trivial/test/integration/chef-current-install/inspec/chef_client_spec.rb5
-rw-r--r--acceptance/windows-service/.acceptance/acceptance-cookbook/.gitignore2
-rw-r--r--acceptance/windows-service/.acceptance/acceptance-cookbook/metadata.rb2
-rw-r--r--acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/destroy.rb1
-rw-r--r--acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/provision.rb1
-rw-r--r--acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/verify.rb1
-rw-r--r--acceptance/windows-service/.kitchen.yml7
-rw-r--r--acceptance/windows-service/test/integration/chef-windows-service/inspec/chef_windows_service_spec.rb58
-rw-r--r--appveyor.yml18
-rwxr-xr-xbin/chef-apply6
-rwxr-xr-xbin/chef-client10
-rwxr-xr-xbin/chef-service-manager14
-rwxr-xr-xbin/chef-shell5
-rwxr-xr-xbin/chef-solo8
-rwxr-xr-xbin/chef-windows-service10
-rwxr-xr-xbin/knife9
-rw-r--r--chef-config/Gemfile2
-rw-r--r--chef-config/Rakefile19
-rw-r--r--chef-config/VERSION1
-rw-r--r--chef-config/chef-config.gemspec12
-rw-r--r--chef-config/lib/chef-config.rb2
-rw-r--r--chef-config/lib/chef-config/config.rb479
-rw-r--r--chef-config/lib/chef-config/exceptions.rb7
-rw-r--r--chef-config/lib/chef-config/fips.rb51
-rw-r--r--chef-config/lib/chef-config/logger.rb5
-rw-r--r--chef-config/lib/chef-config/mixin/dot_d.rb38
-rw-r--r--chef-config/lib/chef-config/mixin/fuzzy_hostname_matcher.rb41
-rw-r--r--chef-config/lib/chef-config/package_task.rb127
-rw-r--r--chef-config/lib/chef-config/path_helper.rb81
-rw-r--r--chef-config/lib/chef-config/version.rb6
-rw-r--r--chef-config/lib/chef-config/windows.rb3
-rw-r--r--chef-config/lib/chef-config/workstation_config_loader.rb63
-rw-r--r--chef-config/spec/spec_helper.rb4
-rw-r--r--chef-config/spec/unit/config_spec.rb633
-rw-r--r--chef-config/spec/unit/fips_spec.rb122
-rw-r--r--chef-config/spec/unit/path_helper_spec.rb52
-rw-r--r--chef-config/spec/unit/workstation_config_loader_spec.rb101
-rw-r--r--chef-universal-mingw32.gemspec (renamed from chef-windows.gemspec)10
-rw-r--r--chef.gemspec45
-rwxr-xr-xci/bundle_install.sh10
-rwxr-xr-xci/dependency_update.sh9
-rw-r--r--ci/jenkins_run_tests.bat14
-rwxr-xr-xci/jenkins_run_tests.sh13
-rwxr-xr-xci/verify-chef.bat67
-rwxr-xr-xci/verify-chef.sh125
-rwxr-xr-xci/version_bump.sh13
-rwxr-xr-xci/version_show.sh3
-rw-r--r--distro/common/html/_static/basic.css2
-rw-r--r--distro/common/html/_static/doctools.js2
-rw-r--r--distro/common/html/_static/searchtools.js2
-rw-r--r--distro/common/html/_static/websupport.js2
-rw-r--r--distro/common/html/knife_bootstrap.html2
-rw-r--r--distro/common/html/knife_environment.html12
-rw-r--r--distro/common/man/man1/README.md4
-rw-r--r--distro/common/man/man1/knife-client.12
-rw-r--r--distro/common/man/man1/knife-environment.120
-rw-r--r--distro/common/markdown/man1/knife-configure.mkd5
-rw-r--r--distro/common/markdown/man8/chef-client.mkd2
-rw-r--r--distro/powershell/chef/chef.psm1163
-rw-r--r--ext/win32-eventlog/Rakefile25
-rw-r--r--habitat/default.toml11
-rw-r--r--habitat/hooks/run8
-rw-r--r--habitat/plan.sh100
-rw-r--r--kitchen-tests/.kitchen.travis.yml136
-rw-r--r--kitchen-tests/.kitchen.yml33
-rw-r--r--kitchen-tests/Berksfile14
-rw-r--r--kitchen-tests/Berksfile.lock134
-rw-r--r--kitchen-tests/Gemfile18
-rw-r--r--kitchen-tests/Gemfile.lock259
-rw-r--r--kitchen-tests/cookbooks/audit_test/.gitignore1
-rw-r--r--kitchen-tests/cookbooks/audit_test/Berksfile2
-rw-r--r--kitchen-tests/cookbooks/audit_test/Berksfile.lock7
-rw-r--r--kitchen-tests/cookbooks/audit_test/metadata.rb15
-rw-r--r--kitchen-tests/cookbooks/audit_test/recipes/default.rb2
-rw-r--r--kitchen-tests/cookbooks/audit_test/recipes/error_duplicate_control_groups.rb2
-rw-r--r--kitchen-tests/cookbooks/audit_test/recipes/error_no_block.rb2
-rw-r--r--kitchen-tests/cookbooks/audit_test/recipes/error_orphan_control.rb2
-rw-r--r--kitchen-tests/cookbooks/audit_test/recipes/failed_specs.rb2
-rw-r--r--kitchen-tests/cookbooks/audit_test/recipes/serverspec_collision.rb2
-rw-r--r--kitchen-tests/cookbooks/audit_test/recipes/serverspec_support.rb2
-rw-r--r--kitchen-tests/cookbooks/audit_test/recipes/with_include_recipe.rb2
-rw-r--r--kitchen-tests/cookbooks/awesome_customers_rhel_wrapper/metadata.rb9
-rw-r--r--kitchen-tests/cookbooks/awesome_customers_rhel_wrapper/recipes/default.rb6
-rw-r--r--kitchen-tests/cookbooks/awesome_customers_ubuntu_wrapper/metadata.rb9
-rw-r--r--kitchen-tests/cookbooks/awesome_customers_ubuntu_wrapper/recipes/default.rb6
-rw-r--r--kitchen-tests/cookbooks/base/Berksfile5
-rw-r--r--kitchen-tests/cookbooks/base/README.md3
-rw-r--r--kitchen-tests/cookbooks/base/attributes/default.rb84
-rw-r--r--kitchen-tests/cookbooks/base/libraries/chef-sugar.rb4
-rw-r--r--kitchen-tests/cookbooks/base/metadata.rb24
-rw-r--r--kitchen-tests/cookbooks/base/recipes/default.rb54
-rw-r--r--kitchen-tests/cookbooks/base/recipes/packages.rb18
-rw-r--r--kitchen-tests/cookbooks/base/recipes/tests.rb21
-rw-r--r--kitchen-tests/cookbooks/webapp/Berksfile2
-rw-r--r--kitchen-tests/cookbooks/webapp/attributes/default.rb14
-rw-r--r--kitchen-tests/cookbooks/webapp/metadata.rb22
-rw-r--r--kitchen-tests/cookbooks/webapp/recipes/default.rb42
-rw-r--r--kitchen-tests/data_bags/users/adam.json9
-rw-r--r--kitchen-tests/test/fixtures/serverspec_helper.rb16
-rw-r--r--kitchen-tests/test/integration/webapp/default_spec.rb118
-rw-r--r--kitchen-tests/test/integration/webapp/serverspec/Gemfile4
-rw-r--r--kitchen-tests/test/integration/webapp/serverspec/localhost/default_spec.rb127
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/acl_entry.rb5
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/already_exists_error.rb20
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb5
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/chef_server_root_dir.rb5
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/cookbook_frozen_error.rb20
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb20
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/file_system_error.rb20
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/must_delete_recursively_error.rb20
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/not_found_error.rb20
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/operation_failed_error.rb20
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/operation_not_allowed_error.rb20
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir.rb5
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_client_keys_dir.rb5
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb6
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir.rb5
-rw-r--r--lib-backcompat/chef/chef_fs/file_system/repository/file_system_root_dir.rb34
-rw-r--r--lib/chef.rb34
-rw-r--r--lib/chef/api_client.rb65
-rw-r--r--lib/chef/api_client/registration.rb52
-rw-r--r--lib/chef/api_client_v1.rb80
-rw-r--r--lib/chef/application.rb200
-rw-r--r--lib/chef/application/apply.rb68
-rw-r--r--lib/chef/application/client.rb198
-rw-r--r--lib/chef/application/exit_code.rb233
-rw-r--r--lib/chef/application/knife.rb52
-rw-r--r--lib/chef/application/solo.rb154
-rw-r--r--lib/chef/application/windows_service.rb120
-rw-r--r--lib/chef/application/windows_service_manager.rb55
-rw-r--r--lib/chef/applications.rb8
-rw-r--r--lib/chef/audit/audit_event_proxy.rb12
-rw-r--r--lib/chef/audit/audit_reporter.rb24
-rw-r--r--lib/chef/audit/control_group_data.rb21
-rw-r--r--lib/chef/audit/logger.rb6
-rw-r--r--lib/chef/audit/rspec_formatter.rb4
-rw-r--r--lib/chef/audit/runner.rb32
-rw-r--r--lib/chef/chef_class.rb49
-rw-r--r--lib/chef/chef_fs.rb52
-rw-r--r--lib/chef/chef_fs/chef_fs_data_store.rb598
-rw-r--r--lib/chef/chef_fs/command_line.rb65
-rw-r--r--lib/chef/chef_fs/config.rb81
-rw-r--r--lib/chef/chef_fs/data_handler/acl_data_handler.rb18
-rw-r--r--lib/chef/chef_fs/data_handler/client_data_handler.rb24
-rw-r--r--lib/chef/chef_fs/data_handler/client_key_data_handler.rb11
-rw-r--r--lib/chef/chef_fs/data_handler/container_data_handler.rb20
-rw-r--r--lib/chef/chef_fs/data_handler/cookbook_data_handler.rb26
-rw-r--r--lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb30
-rw-r--r--lib/chef/chef_fs/data_handler/data_handler_base.rb45
-rw-r--r--lib/chef/chef_fs/data_handler/environment_data_handler.rb26
-rw-r--r--lib/chef/chef_fs/data_handler/group_data_handler.rb36
-rw-r--r--lib/chef/chef_fs/data_handler/node_data_handler.rb26
-rw-r--r--lib/chef/chef_fs/data_handler/organization_data_handler.rb26
-rw-r--r--lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb4
-rw-r--r--lib/chef/chef_fs/data_handler/organization_members_data_handler.rb4
-rw-r--r--lib/chef/chef_fs/data_handler/policy_data_handler.rb39
-rw-r--r--lib/chef/chef_fs/data_handler/policy_group_data_handler.rb33
-rw-r--r--lib/chef/chef_fs/data_handler/role_data_handler.rb30
-rw-r--r--lib/chef/chef_fs/data_handler/user_data_handler.rb22
-rw-r--r--lib/chef/chef_fs/file_pattern.rb76
-rw-r--r--lib/chef/chef_fs/file_system.rb320
-rw-r--r--lib/chef/chef_fs/file_system/acl_dir.rb63
-rw-r--r--lib/chef/chef_fs/file_system/acl_entry.rb58
-rw-r--r--lib/chef/chef_fs/file_system/acls_dir.rb72
-rw-r--r--lib/chef/chef_fs/file_system/base_fs_dir.rb8
-rw-r--r--lib/chef/chef_fs/file_system/base_fs_object.rb24
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb37
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb102
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb80
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb82
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb81
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb196
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/acl_dir.rb65
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/acl_entry.rb67
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/acls_dir.rb75
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/chef_server_root_dir.rb196
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/cookbook_artifact_dir.rb (renamed from lib/chef/platform/handler_map.rb)28
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir.rb102
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb221
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/cookbook_file.rb78
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/cookbook_subdir.rb61
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/cookbooks_acl_dir.rb42
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb101
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/data_bag_dir.rb76
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/data_bag_entry.rb19
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/data_bags_dir.rb67
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/environments_dir.rb56
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/nodes_dir.rb (renamed from lib/chef/chef_fs/file_system/nodes_dir.rb)36
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/org_entry.rb35
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/organization_invites_entry.rb65
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/organization_members_entry.rb64
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/policies_acl_dir.rb41
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/policies_dir.rb158
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/policy_group_entry.rb135
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/policy_groups_dir.rb (renamed from lib/chef/chef_fs/file_system/operation_not_allowed_error.rb)37
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/policy_revision_entry.rb38
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/rest_list_dir.rb176
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/rest_list_entry.rb198
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb45
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir.rb107
-rw-r--r--lib/chef/chef_fs/file_system/chef_server_root_dir.rb165
-rw-r--r--lib/chef/chef_fs/file_system/cookbook_dir.rb224
-rw-r--r--lib/chef/chef_fs/file_system/cookbook_file.rb82
-rw-r--r--lib/chef/chef_fs/file_system/cookbook_subdir.rb54
-rw-r--r--lib/chef/chef_fs/file_system/cookbooks_acl_dir.rb41
-rw-r--r--lib/chef/chef_fs/file_system/cookbooks_dir.rb156
-rw-r--r--lib/chef/chef_fs/file_system/data_bag_dir.rb69
-rw-r--r--lib/chef/chef_fs/file_system/data_bags_dir.rb71
-rw-r--r--lib/chef/chef_fs/file_system/environments_dir.rb60
-rw-r--r--lib/chef/chef_fs/file_system/exceptions.rb105
-rw-r--r--lib/chef/chef_fs/file_system/file_system_entry.rb111
-rw-r--r--lib/chef/chef_fs/file_system/memory/memory_dir.rb53
-rw-r--r--lib/chef/chef_fs/file_system/memory/memory_file.rb20
-rw-r--r--lib/chef/chef_fs/file_system/memory/memory_root.rb23
-rw-r--r--lib/chef/chef_fs/file_system/memory_dir.rb51
-rw-r--r--lib/chef/chef_fs/file_system/memory_file.rb17
-rw-r--r--lib/chef/chef_fs/file_system/memory_root.rb21
-rw-r--r--lib/chef/chef_fs/file_system/multiplexed_dir.rb28
-rw-r--r--lib/chef/chef_fs/file_system/nonexistent_fs_object.rb12
-rw-r--r--lib/chef/chef_fs/file_system/org_entry.rb34
-rw-r--r--lib/chef/chef_fs/file_system/organization_invites_entry.rb59
-rw-r--r--lib/chef/chef_fs/file_system/organization_members_entry.rb58
-rw-r--r--lib/chef/chef_fs/file_system/repository/acl.rb (renamed from lib/chef/chef_fs/file_system/operation_failed_error.rb)31
-rw-r--r--lib/chef/chef_fs/file_system/repository/acls_dir.rb50
-rw-r--r--lib/chef/chef_fs/file_system/repository/acls_sub_dir.rb38
-rw-r--r--lib/chef/chef_fs/file_system/repository/base_file.rb155
-rw-r--r--lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifact_dir.rb41
-rw-r--r--lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb144
-rw-r--r--lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb177
-rw-r--r--lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb231
-rw-r--r--lib/chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbook_dir.rb42
-rw-r--r--lib/chef/chef_fs/file_system/repository/client.rb38
-rw-r--r--lib/chef/chef_fs/file_system/repository/client_key.rb38
-rw-r--r--lib/chef/chef_fs/file_system/repository/client_keys_dir.rb (renamed from lib/chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir.rb)26
-rw-r--r--lib/chef/chef_fs/file_system/repository/client_keys_sub_dir.rb38
-rw-r--r--lib/chef/chef_fs/file_system/repository/clients_dir.rb37
-rw-r--r--lib/chef/chef_fs/file_system/repository/container.rb38
-rw-r--r--lib/chef/chef_fs/file_system/repository/containers_dir.rb37
-rw-r--r--lib/chef/chef_fs/file_system/repository/cookbook_artifacts_dir.rb36
-rw-r--r--lib/chef/chef_fs/file_system/repository/cookbooks_dir.rb51
-rw-r--r--lib/chef/chef_fs/file_system/repository/data_bag.rb39
-rw-r--r--lib/chef/chef_fs/file_system/repository/data_bag_item.rb38
-rw-r--r--lib/chef/chef_fs/file_system/repository/data_bags_dir.rb39
-rw-r--r--lib/chef/chef_fs/file_system/repository/directory.rb167
-rw-r--r--lib/chef/chef_fs/file_system/repository/environment.rb38
-rw-r--r--lib/chef/chef_fs/file_system/repository/environments_dir.rb37
-rw-r--r--lib/chef/chef_fs/file_system/repository/file_system_entry.rb151
-rw-r--r--lib/chef/chef_fs/file_system/repository/group.rb38
-rw-r--r--lib/chef/chef_fs/file_system/repository/groups_dir.rb37
-rw-r--r--lib/chef/chef_fs/file_system/repository/node.rb (renamed from lib/chef/chef_fs/file_system/already_exists_error.rb)19
-rw-r--r--lib/chef/chef_fs/file_system/repository/nodes_dir.rb59
-rw-r--r--lib/chef/chef_fs/file_system/repository/policies_dir.rb (renamed from lib/chef/chef_fs/file_system/chef_repository_file_system_policies_dir.rb)26
-rw-r--r--lib/chef/chef_fs/file_system/repository/policy.rb38
-rw-r--r--lib/chef/chef_fs/file_system/repository/policy_group.rb38
-rw-r--r--lib/chef/chef_fs/file_system/repository/policy_groups_dir.rb37
-rw-r--r--lib/chef/chef_fs/file_system/repository/role.rb (renamed from lib/chef/chef_fs/file_system/cookbook_frozen_error.rb)19
-rw-r--r--lib/chef/chef_fs/file_system/repository/roles_dir.rb (renamed from lib/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb)21
-rw-r--r--lib/chef/chef_fs/file_system/repository/user.rb38
-rw-r--r--lib/chef/chef_fs/file_system/repository/users_dir.rb37
-rw-r--r--lib/chef/chef_fs/file_system/repository/versioned_cookbooks_dir.rb34
-rw-r--r--lib/chef/chef_fs/file_system/rest_list_dir.rb110
-rw-r--r--lib/chef/chef_fs/file_system/rest_list_entry.rb185
-rw-r--r--lib/chef/chef_fs/file_system_cache.rb80
-rw-r--r--lib/chef/chef_fs/knife.rb34
-rw-r--r--lib/chef/chef_fs/parallelizer.rb26
-rw-r--r--lib/chef/chef_fs/parallelizer/flatten_enumerable.rb4
-rw-r--r--lib/chef/chef_fs/parallelizer/parallel_enumerable.rb18
-rw-r--r--lib/chef/chef_fs/path_utils.rb25
-rw-r--r--lib/chef/client.rb169
-rw-r--r--lib/chef/config.rb20
-rw-r--r--lib/chef/config_fetcher.rb28
-rw-r--r--lib/chef/constants.rb3
-rw-r--r--lib/chef/cookbook/chefignore.rb11
-rw-r--r--lib/chef/cookbook/cookbook_collection.rb30
-rw-r--r--lib/chef/cookbook/cookbook_version_loader.rb160
-rw-r--r--lib/chef/cookbook/file_system_file_vendor.rb23
-rw-r--r--lib/chef/cookbook/file_vendor.rb7
-rw-r--r--lib/chef/cookbook/gem_installer.rb84
-rw-r--r--lib/chef/cookbook/metadata.rb371
-rw-r--r--lib/chef/cookbook/remote_file_vendor.rb14
-rw-r--r--lib/chef/cookbook/synchronizer.rb31
-rw-r--r--lib/chef/cookbook/syntax_check.rb32
-rw-r--r--lib/chef/cookbook_loader.rb54
-rw-r--r--lib/chef/cookbook_manifest.rb27
-rw-r--r--lib/chef/cookbook_site_streaming_uploader.rb49
-rw-r--r--lib/chef/cookbook_uploader.rb43
-rw-r--r--lib/chef/cookbook_version.rb206
-rw-r--r--lib/chef/daemon.rb16
-rw-r--r--lib/chef/data_bag.rb65
-rw-r--r--lib/chef/data_bag_item.rb87
-rw-r--r--lib/chef/data_collector.rb489
-rw-r--r--lib/chef/data_collector/messages.rb98
-rw-r--r--lib/chef/data_collector/messages/helpers.rb161
-rw-r--r--lib/chef/data_collector/resource_report.rb95
-rw-r--r--lib/chef/decorator.rb81
-rw-r--r--lib/chef/decorator/lazy.rb60
-rw-r--r--lib/chef/decorator/lazy_array.rb59
-rw-r--r--lib/chef/decorator/unchain.rb59
-rw-r--r--lib/chef/delayed_evaluator.rb2
-rw-r--r--lib/chef/deprecated.rb250
-rw-r--r--lib/chef/deprecation/mixin/template.rb8
-rw-r--r--lib/chef/deprecation/provider/cookbook_file.rb5
-rw-r--r--lib/chef/deprecation/provider/file.rb20
-rw-r--r--lib/chef/deprecation/provider/remote_directory.rb12
-rw-r--r--lib/chef/deprecation/provider/remote_file.rb10
-rw-r--r--lib/chef/deprecation/provider/template.rb6
-rw-r--r--lib/chef/deprecation/warnings.rb12
-rw-r--r--lib/chef/digester.rb12
-rw-r--r--lib/chef/dsl.rb12
-rw-r--r--lib/chef/dsl/audit.rb12
-rw-r--r--lib/chef/dsl/chef_provisioning.rb57
-rw-r--r--lib/chef/dsl/cheffish.rb65
-rw-r--r--lib/chef/dsl/core.rb52
-rw-r--r--lib/chef/dsl/data_query.rb20
-rw-r--r--lib/chef/dsl/declare_resource.rb295
-rw-r--r--lib/chef/dsl/definitions.rb3
-rw-r--r--lib/chef/dsl/include_attribute.rb10
-rw-r--r--lib/chef/dsl/include_recipe.rb8
-rw-r--r--lib/chef/dsl/method_missing.rb75
-rw-r--r--lib/chef/dsl/platform_introspection.rb98
-rw-r--r--lib/chef/dsl/powershell.rb6
-rw-r--r--lib/chef/dsl/reboot_pending.rb27
-rw-r--r--lib/chef/dsl/recipe.rb203
-rw-r--r--lib/chef/dsl/registry_helper.rb10
-rw-r--r--lib/chef/dsl/resources.rb45
-rw-r--r--lib/chef/dsl/universal.rb50
-rw-r--r--lib/chef/encrypted_data_bag_item.rb24
-rw-r--r--lib/chef/encrypted_data_bag_item/assertions.rb8
-rw-r--r--lib/chef/encrypted_data_bag_item/check_encrypted.rb6
-rw-r--r--lib/chef/encrypted_data_bag_item/decryption_failure.rb4
-rw-r--r--lib/chef/encrypted_data_bag_item/decryptor.rb30
-rw-r--r--lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb2
-rw-r--r--lib/chef/encrypted_data_bag_item/encryption_failure.rb2
-rw-r--r--lib/chef/encrypted_data_bag_item/encryptor.rb40
-rw-r--r--lib/chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format.rb4
-rw-r--r--lib/chef/encrypted_data_bag_item/unsupported_cipher.rb4
-rw-r--r--lib/chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format.rb4
-rw-r--r--lib/chef/environment.rb101
-rw-r--r--lib/chef/event_dispatch/base.rb37
-rw-r--r--lib/chef/event_dispatch/dispatcher.rb9
-rw-r--r--lib/chef/event_dispatch/dsl.rb11
-rw-r--r--lib/chef/event_dispatch/events_output_stream.rb8
-rw-r--r--lib/chef/event_loggers/base.rb10
-rw-r--r--lib/chef/event_loggers/windows_eventlog.rb18
-rw-r--r--lib/chef/exceptions.rb114
-rw-r--r--lib/chef/file_access_control.rb12
-rw-r--r--lib/chef/file_access_control/unix.rb50
-rw-r--r--lib/chef/file_access_control/windows.rb22
-rw-r--r--lib/chef/file_cache.rb40
-rw-r--r--lib/chef/file_content_management/content_base.rb4
-rw-r--r--lib/chef/file_content_management/deploy.rb11
-rw-r--r--lib/chef/file_content_management/deploy/cp.rb4
-rw-r--r--lib/chef/file_content_management/deploy/mv_unix.rb5
-rw-r--r--lib/chef/file_content_management/deploy/mv_windows.rb10
-rw-r--r--lib/chef/file_content_management/tempfile.rb21
-rw-r--r--lib/chef/formatters/base.rb44
-rw-r--r--lib/chef/formatters/doc.rb77
-rw-r--r--lib/chef/formatters/error_description.rb (renamed from lib/chef/formatters/error_descriptor.rb)14
-rw-r--r--lib/chef/formatters/error_inspectors.rb10
-rw-r--r--lib/chef/formatters/error_inspectors/api_error_formatting.rb74
-rw-r--r--lib/chef/formatters/error_inspectors/compile_error_inspector.rb22
-rw-r--r--lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb16
-rw-r--r--lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb14
-rw-r--r--lib/chef/formatters/error_inspectors/node_load_error_inspector.rb27
-rw-r--r--lib/chef/formatters/error_inspectors/registration_error_inspector.rb36
-rw-r--r--lib/chef/formatters/error_inspectors/resource_failure_inspector.rb21
-rw-r--r--lib/chef/formatters/error_inspectors/run_list_expansion_error_inspector.rb29
-rw-r--r--lib/chef/formatters/error_mapper.rb16
-rw-r--r--lib/chef/formatters/indentable_output_stream.rb15
-rw-r--r--lib/chef/formatters/minimal.rb16
-rw-r--r--lib/chef/guard_interpreter.rb6
-rw-r--r--lib/chef/guard_interpreter/default_guard_interpreter.rb7
-rw-r--r--lib/chef/guard_interpreter/resource_guard_interpreter.rb20
-rw-r--r--lib/chef/handler.rb41
-rw-r--r--lib/chef/handler/error_report.rb8
-rw-r--r--lib/chef/handler/json_file.rb10
-rw-r--r--lib/chef/http.rb197
-rw-r--r--lib/chef/http/api_versions.rb50
-rw-r--r--lib/chef/http/auth_credentials.rb24
-rw-r--r--lib/chef/http/authenticator.rb33
-rw-r--r--lib/chef/http/basic_client.rb91
-rw-r--r--lib/chef/http/cookie_jar.rb14
-rw-r--r--lib/chef/http/cookie_manager.rb16
-rw-r--r--lib/chef/http/decompressor.rb16
-rw-r--r--lib/chef/http/http_request.rb67
-rw-r--r--lib/chef/http/json_input.rb18
-rw-r--r--lib/chef/http/json_output.rb18
-rw-r--r--lib/chef/http/json_to_model_output.rb8
-rw-r--r--lib/chef/http/remote_request_id.rb12
-rw-r--r--lib/chef/http/simple.rb28
-rw-r--r--lib/chef/http/simple_json.rb43
-rw-r--r--lib/chef/http/socketless_chef_zero_client.rb123
-rw-r--r--lib/chef/http/ssl_policies.rb26
-rw-r--r--lib/chef/http/validate_content_length.rb32
-rw-r--r--lib/chef/json_compat.rb30
-rw-r--r--lib/chef/key.rb157
-rw-r--r--lib/chef/knife.rb266
-rw-r--r--lib/chef/knife/bootstrap.rb93
-rw-r--r--lib/chef/knife/bootstrap/chef_vault_handler.rb39
-rw-r--r--lib/chef/knife/bootstrap/client_builder.rb28
-rw-r--r--lib/chef/knife/bootstrap/templates/chef-full.erb7
-rw-r--r--lib/chef/knife/client_bulk_delete.rb12
-rw-r--r--lib/chef/knife/client_create.rb18
-rw-r--r--lib/chef/knife/client_delete.rb33
-rw-r--r--lib/chef/knife/client_edit.rb12
-rw-r--r--lib/chef/knife/client_key_create.rb12
-rw-r--r--lib/chef/knife/client_key_delete.rb12
-rw-r--r--lib/chef/knife/client_key_edit.rb17
-rw-r--r--lib/chef/knife/client_key_list.rb10
-rw-r--r--lib/chef/knife/client_key_show.rb10
-rw-r--r--lib/chef/knife/client_list.rb10
-rw-r--r--lib/chef/knife/client_reregister.rb10
-rw-r--r--lib/chef/knife/client_show.rb10
-rw-r--r--lib/chef/knife/configure.rb32
-rw-r--r--lib/chef/knife/configure_client.rb12
-rw-r--r--lib/chef/knife/cookbook_bulk_delete.rb21
-rw-r--r--lib/chef/knife/cookbook_create.rb78
-rw-r--r--lib/chef/knife/cookbook_delete.rb20
-rw-r--r--lib/chef/knife/cookbook_download.rb18
-rw-r--r--lib/chef/knife/cookbook_list.rb10
-rw-r--r--lib/chef/knife/cookbook_metadata.rb19
-rw-r--r--lib/chef/knife/cookbook_metadata_from_file.rb10
-rw-r--r--lib/chef/knife/cookbook_show.rb38
-rw-r--r--lib/chef/knife/cookbook_site_download.rb53
-rw-r--r--lib/chef/knife/cookbook_site_install.rb46
-rw-r--r--lib/chef/knife/cookbook_site_list.rb25
-rw-r--r--lib/chef/knife/cookbook_site_search.rb24
-rw-r--r--lib/chef/knife/cookbook_site_share.rb62
-rw-r--r--lib/chef/knife/cookbook_site_show.rb32
-rw-r--r--lib/chef/knife/cookbook_site_unshare.rb19
-rw-r--r--lib/chef/knife/cookbook_site_vendor.rb10
-rw-r--r--lib/chef/knife/cookbook_test.rb15
-rw-r--r--lib/chef/knife/cookbook_upload.rb47
-rw-r--r--lib/chef/knife/core/bootstrap_context.rb125
-rw-r--r--lib/chef/knife/core/cookbook_scm_repo.rb29
-rw-r--r--lib/chef/knife/core/custom_manifest_loader.rb6
-rw-r--r--lib/chef/knife/core/gem_glob_loader.rb38
-rw-r--r--lib/chef/knife/core/generic_presenter.rb97
-rw-r--r--lib/chef/knife/core/hashed_command_loader.rb37
-rw-r--r--lib/chef/knife/core/node_editor.rb99
-rw-r--r--lib/chef/knife/core/node_presenter.rb29
-rw-r--r--lib/chef/knife/core/object_loader.rb18
-rw-r--r--lib/chef/knife/core/status_presenter.rb36
-rw-r--r--lib/chef/knife/core/subcommand_loader.rb53
-rw-r--r--lib/chef/knife/core/text_formatter.rb27
-rw-r--r--lib/chef/knife/core/ui.rb100
-rw-r--r--lib/chef/knife/data_bag_create.rb21
-rw-r--r--lib/chef/knife/data_bag_delete.rb14
-rw-r--r--lib/chef/knife/data_bag_edit.rb25
-rw-r--r--lib/chef/knife/data_bag_from_file.rb25
-rw-r--r--lib/chef/knife/data_bag_list.rb12
-rw-r--r--lib/chef/knife/data_bag_secret_options.rb18
-rw-r--r--lib/chef/knife/data_bag_show.rb62
-rw-r--r--lib/chef/knife/delete.rb15
-rw-r--r--lib/chef/knife/deps.rb86
-rw-r--r--lib/chef/knife/diff.rb17
-rw-r--r--lib/chef/knife/download.rb25
-rw-r--r--lib/chef/knife/edit.rb17
-rw-r--r--lib/chef/knife/environment_compare.rb46
-rw-r--r--lib/chef/knife/environment_create.rb12
-rw-r--r--lib/chef/knife/environment_delete.rb10
-rw-r--r--lib/chef/knife/environment_edit.rb10
-rw-r--r--lib/chef/knife/environment_from_file.rb9
-rw-r--r--lib/chef/knife/environment_list.rb10
-rw-r--r--lib/chef/knife/environment_show.rb10
-rw-r--r--lib/chef/knife/exec.rb14
-rw-r--r--lib/chef/knife/help.rb18
-rw-r--r--lib/chef/knife/index_rebuild.rb13
-rw-r--r--lib/chef/knife/key_create.rb16
-rw-r--r--lib/chef/knife/key_create_base.rb2
-rw-r--r--lib/chef/knife/key_delete.rb6
-rw-r--r--lib/chef/knife/key_edit.rb16
-rw-r--r--lib/chef/knife/key_edit_base.rb2
-rw-r--r--lib/chef/knife/key_list.rb24
-rw-r--r--lib/chef/knife/key_list_base.rb2
-rw-r--r--lib/chef/knife/key_show.rb8
-rw-r--r--lib/chef/knife/list.rb32
-rw-r--r--lib/chef/knife/node_bulk_delete.rb18
-rw-r--r--lib/chef/knife/node_create.rb15
-rw-r--r--lib/chef/knife/node_delete.rb23
-rw-r--r--lib/chef/knife/node_edit.rb14
-rw-r--r--lib/chef/knife/node_environment_set.rb8
-rw-r--r--lib/chef/knife/node_from_file.rb22
-rw-r--r--lib/chef/knife/node_list.rb12
-rw-r--r--lib/chef/knife/node_run_list_add.rb16
-rw-r--r--lib/chef/knife/node_run_list_remove.rb16
-rw-r--r--lib/chef/knife/node_run_list_set.rb12
-rw-r--r--lib/chef/knife/node_show.rb18
-rw-r--r--lib/chef/knife/osc_user_create.rb14
-rw-r--r--lib/chef/knife/osc_user_delete.rb10
-rw-r--r--lib/chef/knife/osc_user_edit.rb14
-rw-r--r--lib/chef/knife/osc_user_list.rb10
-rw-r--r--lib/chef/knife/osc_user_reregister.rb10
-rw-r--r--lib/chef/knife/osc_user_show.rb11
-rw-r--r--lib/chef/knife/raw.rb43
-rw-r--r--lib/chef/knife/recipe_list.rb8
-rw-r--r--lib/chef/knife/rehash.rb23
-rw-r--r--lib/chef/knife/role_bulk_delete.rb15
-rw-r--r--lib/chef/knife/role_create.rb14
-rw-r--r--lib/chef/knife/role_delete.rb11
-rw-r--r--lib/chef/knife/role_edit.rb13
-rw-r--r--lib/chef/knife/role_env_run_list_add.rb18
-rw-r--r--lib/chef/knife/role_env_run_list_clear.rb8
-rw-r--r--lib/chef/knife/role_env_run_list_remove.rb26
-rw-r--r--lib/chef/knife/role_env_run_list_replace.rb12
-rw-r--r--lib/chef/knife/role_env_run_list_set.rb12
-rw-r--r--lib/chef/knife/role_from_file.rb19
-rw-r--r--lib/chef/knife/role_list.rb11
-rw-r--r--lib/chef/knife/role_run_list_add.rb18
-rw-r--r--lib/chef/knife/role_run_list_clear.rb8
-rw-r--r--lib/chef/knife/role_run_list_remove.rb26
-rw-r--r--lib/chef/knife/role_run_list_replace.rb12
-rw-r--r--lib/chef/knife/role_run_list_set.rb12
-rw-r--r--lib/chef/knife/role_show.rb13
-rw-r--r--lib/chef/knife/search.rb34
-rw-r--r--lib/chef/knife/serve.rb22
-rw-r--r--lib/chef/knife/show.rb8
-rw-r--r--lib/chef/knife/ssh.rb208
-rw-r--r--lib/chef/knife/ssl_check.rb35
-rw-r--r--lib/chef/knife/ssl_fetch.rb43
-rw-r--r--lib/chef/knife/status.rb30
-rw-r--r--lib/chef/knife/supermarket_download.rb33
-rw-r--r--lib/chef/knife/supermarket_install.rb33
-rw-r--r--lib/chef/knife/supermarket_list.rb33
-rw-r--r--lib/chef/knife/supermarket_search.rb33
-rw-r--r--lib/chef/knife/supermarket_share.rb33
-rw-r--r--lib/chef/knife/supermarket_show.rb33
-rw-r--r--lib/chef/knife/supermarket_unshare.rb33
-rw-r--r--lib/chef/knife/tag_create.rb10
-rw-r--r--lib/chef/knife/tag_delete.rb10
-rw-r--r--lib/chef/knife/tag_list.rb10
-rw-r--r--lib/chef/knife/upload.rb25
-rw-r--r--lib/chef/knife/user_create.rb20
-rw-r--r--lib/chef/knife/user_delete.rb15
-rw-r--r--lib/chef/knife/user_edit.rb15
-rw-r--r--lib/chef/knife/user_key_create.rb14
-rw-r--r--lib/chef/knife/user_key_delete.rb12
-rw-r--r--lib/chef/knife/user_key_edit.rb17
-rw-r--r--lib/chef/knife/user_key_list.rb10
-rw-r--r--lib/chef/knife/user_key_show.rb10
-rw-r--r--lib/chef/knife/user_list.rb10
-rw-r--r--lib/chef/knife/user_reregister.rb13
-rw-r--r--lib/chef/knife/user_show.rb12
-rw-r--r--lib/chef/knife/xargs.rb53
-rw-r--r--lib/chef/local_mode.rb24
-rw-r--r--lib/chef/log.rb36
-rw-r--r--lib/chef/log/syslog.rb11
-rw-r--r--lib/chef/log/winevt.rb14
-rw-r--r--lib/chef/mash.rb13
-rw-r--r--lib/chef/mixin/api_version_request_handling.rb2
-rw-r--r--lib/chef/mixin/checksum.rb13
-rw-r--r--lib/chef/mixin/command.rb36
-rw-r--r--lib/chef/mixin/command/unix.rb20
-rw-r--r--lib/chef/mixin/command/windows.rb13
-rw-r--r--lib/chef/mixin/convert_to_class_name.rb22
-rw-r--r--lib/chef/mixin/create_path.rb14
-rw-r--r--lib/chef/mixin/deep_merge.rb8
-rw-r--r--lib/chef/mixin/deprecation.rb59
-rw-r--r--lib/chef/mixin/descendants_tracker.rb5
-rw-r--r--lib/chef/mixin/enforce_ownership_and_permissions.rb6
-rw-r--r--lib/chef/mixin/file_class.rb20
-rw-r--r--lib/chef/mixin/from_file.rb10
-rw-r--r--lib/chef/mixin/get_source_from_package.rb16
-rw-r--r--lib/chef/mixin/homebrew_user.rb12
-rw-r--r--lib/chef/mixin/language.rb10
-rw-r--r--lib/chef/mixin/language_include_attribute.rb9
-rw-r--r--lib/chef/mixin/language_include_recipe.rb9
-rw-r--r--lib/chef/mixin/lazy_module_include.rb77
-rw-r--r--lib/chef/mixin/notifying_block.rb51
-rw-r--r--lib/chef/mixin/params_validate.rb66
-rw-r--r--lib/chef/mixin/path_sanity.rb16
-rw-r--r--lib/chef/mixin/powershell_out.rb10
-rw-r--r--lib/chef/mixin/powershell_type_coercions.rb44
-rw-r--r--lib/chef/mixin/properties.rb22
-rw-r--r--lib/chef/mixin/provides.rb5
-rw-r--r--lib/chef/mixin/proxified_socket.rb42
-rw-r--r--lib/chef/mixin/recipe_definition_dsl_core.rb8
-rw-r--r--lib/chef/mixin/securable.rb43
-rw-r--r--lib/chef/mixin/shell_out.rb148
-rw-r--r--lib/chef/mixin/subclass_directive.rb37
-rw-r--r--lib/chef/mixin/template.rb19
-rw-r--r--lib/chef/mixin/unformatter.rb6
-rw-r--r--lib/chef/mixin/uris.rb16
-rw-r--r--lib/chef/mixin/versioned_api.rb69
-rw-r--r--lib/chef/mixin/which.rb43
-rw-r--r--lib/chef/mixin/why_run.rb17
-rw-r--r--lib/chef/mixin/wide_string.rb16
-rw-r--r--lib/chef/mixin/windows_architecture_helper.rb30
-rw-r--r--lib/chef/mixin/windows_env_helper.rb25
-rw-r--r--lib/chef/mixin/xml_escape.rb40
-rw-r--r--lib/chef/mixins.rb27
-rw-r--r--lib/chef/monkey_patches/net-ssh-multi.rb140
-rw-r--r--lib/chef/monkey_patches/net_http.rb4
-rw-r--r--lib/chef/monkey_patches/webrick-utils.rb20
-rw-r--r--lib/chef/monkey_patches/win32/registry.rb44
-rw-r--r--lib/chef/monologger.rb12
-rw-r--r--lib/chef/node.rb207
-rw-r--r--lib/chef/node/attribute.rb669
-rw-r--r--lib/chef/node/attribute_collections.rb208
-rw-r--r--lib/chef/node/common_api.rb121
-rw-r--r--lib/chef/node/immutable_collections.rb118
-rw-r--r--lib/chef/node/mixin/deep_merge_cache.rb61
-rw-r--r--lib/chef/node/mixin/immutablize_array.rb67
-rw-r--r--lib/chef/node/mixin/immutablize_hash.rb54
-rw-r--r--lib/chef/node/mixin/state_tracking.rb96
-rw-r--r--lib/chef/node_map.rb46
-rw-r--r--lib/chef/null_logger.rb6
-rw-r--r--lib/chef/org.rb79
-rw-r--r--lib/chef/platform.rb8
-rw-r--r--lib/chef/platform/priority_map.rb4
-rw-r--r--lib/chef/platform/provider_handler_map.rb8
-rw-r--r--lib/chef/platform/provider_mapping.rb88
-rw-r--r--lib/chef/platform/provider_priority_map.rb4
-rw-r--r--lib/chef/platform/query_helpers.rb36
-rw-r--r--lib/chef/platform/rebooter.rb37
-rw-r--r--lib/chef/platform/resource_handler_map.rb8
-rw-r--r--lib/chef/platform/resource_priority_map.rb4
-rw-r--r--lib/chef/platform/service_helpers.rb62
-rw-r--r--lib/chef/policy_builder.rb10
-rw-r--r--lib/chef/policy_builder/dynamic.rb19
-rw-r--r--lib/chef/policy_builder/expand_node_object.rb61
-rw-r--r--lib/chef/policy_builder/policyfile.rb47
-rw-r--r--lib/chef/property.rb270
-rw-r--r--lib/chef/provider.rb168
-rw-r--r--lib/chef/provider/apt_repository.rb253
-rw-r--r--lib/chef/provider/apt_update.rb87
-rw-r--r--lib/chef/provider/batch.rb14
-rw-r--r--lib/chef/provider/breakpoint.rb4
-rw-r--r--lib/chef/provider/cookbook_file.rb16
-rw-r--r--lib/chef/provider/cookbook_file/content.rb8
-rw-r--r--lib/chef/provider/cron.rb93
-rw-r--r--lib/chef/provider/cron/aix.rb2
-rw-r--r--lib/chef/provider/cron/solaris.rb2
-rw-r--r--lib/chef/provider/cron/unix.rb14
-rw-r--r--lib/chef/provider/deploy.rb173
-rw-r--r--lib/chef/provider/deploy/revision.rb30
-rw-r--r--lib/chef/provider/deploy/timestamped.rb2
-rw-r--r--lib/chef/provider/directory.rb94
-rw-r--r--lib/chef/provider/dsc_resource.rb125
-rw-r--r--lib/chef/provider/dsc_script.rb40
-rw-r--r--lib/chef/provider/env.rb70
-rw-r--r--lib/chef/provider/env/windows.rb8
-rw-r--r--lib/chef/provider/erl_call.rb36
-rw-r--r--lib/chef/provider/execute.rb39
-rw-r--r--lib/chef/provider/file.rb147
-rw-r--r--lib/chef/provider/file/content.rb8
-rw-r--r--lib/chef/provider/git.rb204
-rw-r--r--lib/chef/provider/group.rb106
-rw-r--r--lib/chef/provider/group/aix.rb37
-rw-r--r--lib/chef/provider/group/dscl.rb107
-rw-r--r--lib/chef/provider/group/gpasswd.rb20
-rw-r--r--lib/chef/provider/group/groupadd.rb74
-rw-r--r--lib/chef/provider/group/groupmod.rb65
-rw-r--r--lib/chef/provider/group/pw.rb63
-rw-r--r--lib/chef/provider/group/suse.rb47
-rw-r--r--lib/chef/provider/group/usermod.rb37
-rw-r--r--lib/chef/provider/group/windows.rb57
-rw-r--r--lib/chef/provider/http_request.rb92
-rw-r--r--lib/chef/provider/ifconfig.rb136
-rw-r--r--lib/chef/provider/ifconfig/aix.rb60
-rw-r--r--lib/chef/provider/ifconfig/debian.rb57
-rw-r--r--lib/chef/provider/ifconfig/redhat.rb30
-rw-r--r--lib/chef/provider/launchd.rb208
-rw-r--r--lib/chef/provider/link.rb123
-rw-r--r--lib/chef/provider/log.rb6
-rw-r--r--lib/chef/provider/lwrp_base.rb17
-rw-r--r--lib/chef/provider/mdadm.rb55
-rw-r--r--lib/chef/provider/mount.rb38
-rw-r--r--lib/chef/provider/mount/aix.rb32
-rw-r--r--lib/chef/provider/mount/mount.rb50
-rw-r--r--lib/chef/provider/mount/solaris.rb60
-rw-r--r--lib/chef/provider/mount/windows.rb14
-rw-r--r--lib/chef/provider/noop.rb37
-rw-r--r--lib/chef/provider/ohai.rb14
-rw-r--r--lib/chef/provider/osx_profile.rb257
-rw-r--r--lib/chef/provider/package.rb359
-rw-r--r--lib/chef/provider/package/aix.rb116
-rw-r--r--lib/chef/provider/package/apt.rb226
-rw-r--r--lib/chef/provider/package/cab.rb179
-rw-r--r--lib/chef/provider/package/chocolatey.rb275
-rw-r--r--lib/chef/provider/package/dnf.rb185
-rw-r--r--lib/chef/provider/package/dnf/dnf_helper.py91
-rw-r--r--lib/chef/provider/package/dnf/python_helper.rb157
-rw-r--r--lib/chef/provider/package/dnf/version.rb56
-rw-r--r--lib/chef/provider/package/dpkg.rb228
-rw-r--r--lib/chef/provider/package/easy_install.rb67
-rw-r--r--lib/chef/provider/package/freebsd/base.rb30
-rw-r--r--lib/chef/provider/package/freebsd/pkg.rb38
-rw-r--r--lib/chef/provider/package/freebsd/pkgng.rb34
-rw-r--r--lib/chef/provider/package/freebsd/port.rb18
-rw-r--r--lib/chef/provider/package/homebrew.rb45
-rw-r--r--lib/chef/provider/package/ips.rb53
-rw-r--r--lib/chef/provider/package/macports.rb49
-rw-r--r--lib/chef/provider/package/msu.rb162
-rw-r--r--lib/chef/provider/package/openbsd.rb65
-rw-r--r--lib/chef/provider/package/pacman.rb47
-rw-r--r--lib/chef/provider/package/paludis.rb64
-rw-r--r--lib/chef/provider/package/portage.rb69
-rw-r--r--lib/chef/provider/package/powershell.rb114
-rw-r--r--lib/chef/provider/package/rpm.rb67
-rw-r--r--lib/chef/provider/package/rubygems.rb243
-rw-r--r--lib/chef/provider/package/smartos.rb45
-rw-r--r--lib/chef/provider/package/solaris.rb105
-rw-r--r--lib/chef/provider/package/windows.rb163
-rw-r--r--lib/chef/provider/package/windows/exe.rb115
-rw-r--r--lib/chef/provider/package/windows/msi.rb59
-rw-r--r--lib/chef/provider/package/windows/registry_uninstall_entry.rb87
-rw-r--r--lib/chef/provider/package/yum.rb1496
-rw-r--r--lib/chef/provider/package/yum/rpm_utils.rb642
-rw-r--r--lib/chef/provider/package/yum/yum-dump.py (renamed from lib/chef/provider/package/yum-dump.py)2
-rw-r--r--lib/chef/provider/package/yum/yum_cache.rb376
-rw-r--r--lib/chef/provider/package/zypper.rb142
-rw-r--r--lib/chef/provider/powershell_script.rb50
-rw-r--r--lib/chef/provider/reboot.rb28
-rw-r--r--lib/chef/provider/registry_key.rb127
-rw-r--r--lib/chef/provider/remote_directory.rb38
-rw-r--r--lib/chef/provider/remote_file.rb16
-rw-r--r--lib/chef/provider/remote_file/cache_control_data.rb60
-rw-r--r--lib/chef/provider/remote_file/content.rb24
-rw-r--r--lib/chef/provider/remote_file/fetcher.rb6
-rw-r--r--lib/chef/provider/remote_file/ftp.rb41
-rw-r--r--lib/chef/provider/remote_file/http.rb42
-rw-r--r--lib/chef/provider/remote_file/local_file.rb10
-rw-r--r--lib/chef/provider/remote_file/network_file.rb8
-rw-r--r--lib/chef/provider/remote_file/sftp.rb105
-rw-r--r--lib/chef/provider/route.rb314
-rw-r--r--lib/chef/provider/ruby_block.rb12
-rw-r--r--lib/chef/provider/script.rb59
-rw-r--r--lib/chef/provider/service.rb192
-rw-r--r--lib/chef/provider/service/aix.rb8
-rw-r--r--lib/chef/provider/service/aixinit.rb28
-rw-r--r--lib/chef/provider/service/arch.rb20
-rw-r--r--lib/chef/provider/service/debian.rb31
-rw-r--r--lib/chef/provider/service/freebsd.rb18
-rw-r--r--lib/chef/provider/service/gentoo.rb18
-rw-r--r--lib/chef/provider/service/init.rb8
-rw-r--r--lib/chef/provider/service/insserv.rb14
-rw-r--r--lib/chef/provider/service/invokercd.rb6
-rw-r--r--lib/chef/provider/service/macosx.rb44
-rw-r--r--lib/chef/provider/service/openbsd.rb34
-rw-r--r--lib/chef/provider/service/redhat.rb36
-rw-r--r--lib/chef/provider/service/simple.rb26
-rw-r--r--lib/chef/provider/service/solaris.rb25
-rw-r--r--lib/chef/provider/service/systemd.rb73
-rw-r--r--lib/chef/provider/service/upstart.rb71
-rw-r--r--lib/chef/provider/service/windows.rb108
-rw-r--r--lib/chef/provider/subversion.rb110
-rw-r--r--lib/chef/provider/support/yum_repo.erb132
-rw-r--r--lib/chef/provider/systemd_unit.rb240
-rw-r--r--lib/chef/provider/template.rb22
-rw-r--r--lib/chef/provider/template/content.rb8
-rw-r--r--lib/chef/provider/template_finder.rb5
-rw-r--r--lib/chef/provider/user.rb176
-rw-r--r--lib/chef/provider/user/aix.rb59
-rw-r--r--lib/chef/provider/user/dscl.rb198
-rw-r--r--lib/chef/provider/user/linux.rb125
-rw-r--r--lib/chef/provider/user/pw.rb77
-rw-r--r--lib/chef/provider/user/solaris.rb64
-rw-r--r--lib/chef/provider/user/useradd.rb67
-rw-r--r--lib/chef/provider/user/windows.rb67
-rw-r--r--lib/chef/provider/whyrun_safe_ruby_block.rb10
-rw-r--r--lib/chef/provider/windows_script.rb17
-rw-r--r--lib/chef/provider/yum_repository.rb120
-rw-r--r--lib/chef/provider_resolver.rb16
-rw-r--r--lib/chef/providers.rb234
-rw-r--r--lib/chef/recipe.rb36
-rw-r--r--lib/chef/request_id.rb8
-rw-r--r--lib/chef/resource.rb375
-rw-r--r--lib/chef/resource/action_class.rb17
-rw-r--r--lib/chef/resource/apt_package.rb23
-rw-r--r--lib/chef/resource/apt_repository.rb46
-rw-r--r--lib/chef/resource/apt_update.rb (renamed from lib/chef/chef_fs/file_system/file_system_error.rb)24
-rw-r--r--lib/chef/resource/bash.rb10
-rw-r--r--lib/chef/resource/batch.rb8
-rw-r--r--lib/chef/resource/bff_package.rb6
-rw-r--r--lib/chef/resource/breakpoint.rb7
-rw-r--r--lib/chef/resource/cab_package.rb44
-rw-r--r--lib/chef/resource/chef_gem.rb41
-rw-r--r--lib/chef/resource/chocolatey_package.rb40
-rw-r--r--lib/chef/resource/conditional.rb26
-rw-r--r--lib/chef/resource/conditional_action_not_nothing.rb2
-rw-r--r--lib/chef/resource/cookbook_file.rb20
-rw-r--r--lib/chef/resource/cron.rb40
-rw-r--r--lib/chef/resource/csh.rb10
-rw-r--r--lib/chef/resource/deploy.rb90
-rw-r--r--lib/chef/resource/deploy_revision.rb2
-rw-r--r--lib/chef/resource/directory.rb20
-rw-r--r--lib/chef/resource/dnf_package.rb67
-rw-r--r--lib/chef/resource/dpkg_package.rb10
-rw-r--r--lib/chef/resource/dsc_resource.rb211
-rw-r--r--lib/chef/resource/dsc_script.rb32
-rw-r--r--lib/chef/resource/easy_install_package.rb31
-rw-r--r--lib/chef/resource/env.rb12
-rw-r--r--lib/chef/resource/erl_call.rb20
-rw-r--r--lib/chef/resource/execute.rb114
-rw-r--r--lib/chef/resource/file.rb112
-rw-r--r--lib/chef/resource/file/verification.rb26
-rw-r--r--lib/chef/resource/file/verification/systemd_unit.rb67
-rw-r--r--lib/chef/resource/freebsd_package.rb23
-rw-r--r--lib/chef/resource/gem_package.rb31
-rw-r--r--lib/chef/resource/git.rb6
-rw-r--r--lib/chef/resource/group.rb27
-rw-r--r--lib/chef/resource/homebrew_package.rb25
-rw-r--r--lib/chef/resource/http_request.rb18
-rw-r--r--lib/chef/resource/ifconfig.rb32
-rw-r--r--lib/chef/resource/ips_package.rb21
-rw-r--r--lib/chef/resource/ksh.rb (renamed from lib/chef/chef_fs/file_system/not_found_error.rb)19
-rw-r--r--lib/chef/resource/launchd.rb156
-rw-r--r--lib/chef/resource/link.rb25
-rw-r--r--lib/chef/resource/log.rb14
-rw-r--r--lib/chef/resource/lwrp_base.rb24
-rw-r--r--lib/chef/resource/macosx_service.rb10
-rw-r--r--lib/chef/resource/macports_package.rb5
-rw-r--r--lib/chef/resource/mdadm.rb30
-rw-r--r--lib/chef/resource/mount.rb44
-rw-r--r--lib/chef/resource/msu_package.rb47
-rw-r--r--lib/chef/resource/ohai.rb34
-rw-r--r--lib/chef/resource/openbsd_package.rb13
-rw-r--r--lib/chef/resource/osx_profile.rb74
-rw-r--r--lib/chef/resource/package.rb87
-rw-r--r--lib/chef/resource/pacman_package.rb5
-rw-r--r--lib/chef/resource/paludis_package.rb12
-rw-r--r--lib/chef/resource/perl.rb10
-rw-r--r--lib/chef/resource/portage_package.rb9
-rw-r--r--lib/chef/resource/powershell_package.rb41
-rw-r--r--lib/chef/resource/powershell_script.rb12
-rw-r--r--lib/chef/resource/python.rb10
-rw-r--r--lib/chef/resource/reboot.rb14
-rw-r--r--lib/chef/resource/registry_key.rb32
-rw-r--r--lib/chef/resource/remote_directory.rb31
-rw-r--r--lib/chef/resource/remote_file.rb45
-rw-r--r--lib/chef/resource/resource_notification.rb4
-rw-r--r--lib/chef/resource/route.rb30
-rw-r--r--lib/chef/resource/rpm_package.rb22
-rw-r--r--lib/chef/resource/ruby.rb10
-rw-r--r--lib/chef/resource/ruby_block.rb16
-rw-r--r--lib/chef/resource/scm.rb47
-rw-r--r--lib/chef/resource/script.rb20
-rw-r--r--lib/chef/resource/service.rb62
-rw-r--r--lib/chef/resource/smartos_package.rb7
-rw-r--r--lib/chef/resource/solaris_package.rb7
-rw-r--r--lib/chef/resource/subversion.rb12
-rw-r--r--lib/chef/resource/systemd_unit.rb63
-rw-r--r--lib/chef/resource/template.rb28
-rw-r--r--lib/chef/resource/timestamped_deploy.rb2
-rw-r--r--lib/chef/resource/user.rb52
-rw-r--r--lib/chef/resource/user/aix_user.rb (renamed from lib/chef/shell/shell_rest.rb)21
-rw-r--r--lib/chef/resource/user/dscl_user.rb (renamed from lib/chef/chef_fs/file_system/file_system_root_dir.rb)18
-rw-r--r--lib/chef/resource/user/linux_user.rb41
-rw-r--r--lib/chef/resource/user/pw_user.rb (renamed from lib/chef/chef_fs/file_system/must_delete_recursively_error.rb)18
-rw-r--r--lib/chef/resource/user/solaris_user.rb31
-rw-r--r--lib/chef/resource/user/windows_user.rb31
-rw-r--r--lib/chef/resource/whyrun_safe_ruby_block.rb2
-rw-r--r--lib/chef/resource/windows_package.rb87
-rw-r--r--lib/chef/resource/windows_script.rb14
-rw-r--r--lib/chef/resource/windows_service.rb12
-rw-r--r--lib/chef/resource/yum_package.rb86
-rw-r--r--lib/chef/resource/yum_repository.rb78
-rw-r--r--lib/chef/resource/zypper_package.rb5
-rw-r--r--lib/chef/resource_builder.rb40
-rw-r--r--lib/chef/resource_collection.rb75
-rw-r--r--lib/chef/resource_collection/resource_collection_serialization.rb16
-rw-r--r--lib/chef/resource_collection/resource_list.rb25
-rw-r--r--lib/chef/resource_collection/resource_set.rb41
-rw-r--r--lib/chef/resource_collection/stepable_iterator.rb12
-rw-r--r--lib/chef/resource_definition.rb14
-rw-r--r--lib/chef/resource_definition_list.rb10
-rw-r--r--lib/chef/resource_reporter.rb52
-rw-r--r--lib/chef/resource_resolver.rb14
-rw-r--r--lib/chef/resources.rb159
-rw-r--r--lib/chef/rest.rb47
-rw-r--r--lib/chef/role.rb94
-rw-r--r--lib/chef/run_context.rb166
-rw-r--r--lib/chef/run_context/cookbook_compiler.rb29
-rw-r--r--lib/chef/run_list.rb44
-rw-r--r--lib/chef/run_list/run_list_expansion.rb48
-rw-r--r--lib/chef/run_list/run_list_item.rb19
-rw-r--r--lib/chef/run_list/versioned_recipe_list.rb36
-rw-r--r--lib/chef/run_lock.rb26
-rw-r--r--lib/chef/run_status.rb6
-rw-r--r--lib/chef/runner.rb68
-rw-r--r--lib/chef/scan_access_control.rb22
-rw-r--r--lib/chef/search/query.rb63
-rw-r--r--lib/chef/server_api.rb56
-rw-r--r--lib/chef/server_api_versions.rb40
-rw-r--r--lib/chef/shell.rb58
-rw-r--r--lib/chef/shell/ext.rb72
-rw-r--r--lib/chef/shell/model_wrapper.rb18
-rw-r--r--lib/chef/shell/shell_session.rb49
-rw-r--r--lib/chef/shell_out.rb4
-rw-r--r--lib/chef/tasks/chef_repo.rake125
-rw-r--r--lib/chef/user.rb97
-rw-r--r--lib/chef/user_v1.rb131
-rw-r--r--lib/chef/util/backup.rb12
-rw-r--r--lib/chef/util/diff.rb18
-rw-r--r--lib/chef/util/dsc/configuration_generator.rb26
-rw-r--r--lib/chef/util/dsc/lcm_output_parser.rb20
-rw-r--r--lib/chef/util/dsc/local_configuration_manager.rb30
-rw-r--r--lib/chef/util/dsc/resource_info.rb30
-rw-r--r--lib/chef/util/dsc/resource_store.rb147
-rw-r--r--lib/chef/util/editor.rb3
-rw-r--r--lib/chef/util/file_edit.rb10
-rw-r--r--lib/chef/util/path_helper.rb4
-rw-r--r--lib/chef/util/powershell/cmdlet.rb247
-rw-r--r--lib/chef/util/powershell/cmdlet_result.rb72
-rw-r--r--lib/chef/util/powershell/ps_credential.rb9
-rw-r--r--lib/chef/util/selinux.rb16
-rw-r--r--lib/chef/util/threaded_job_queue.rb4
-rw-r--r--lib/chef/util/windows.rb2
-rw-r--r--lib/chef/util/windows/net_group.rb157
-rw-r--r--lib/chef/util/windows/net_use.rb30
-rw-r--r--lib/chef/util/windows/net_user.rb56
-rw-r--r--lib/chef/util/windows/volume.rb30
-rw-r--r--lib/chef/version.rb6
-rw-r--r--lib/chef/version/platform.rb10
-rw-r--r--lib/chef/version_class.rb23
-rw-r--r--lib/chef/version_constraint.rb30
-rw-r--r--lib/chef/version_constraint/platform.rb6
-rw-r--r--lib/chef/whitelist.rb4
-rw-r--r--lib/chef/win32/api.rb33
-rw-r--r--lib/chef/win32/api/crypto.rb126
-rw-r--r--lib/chef/win32/api/error.rb60
-rw-r--r--lib/chef/win32/api/file.rb148
-rw-r--r--lib/chef/win32/api/installer.rb33
-rw-r--r--lib/chef/win32/api/memory.rb8
-rw-r--r--lib/chef/win32/api/net.rb236
-rw-r--r--lib/chef/win32/api/process.rb8
-rw-r--r--lib/chef/win32/api/psapi.rb8
-rw-r--r--lib/chef/win32/api/registry.rb8
-rw-r--r--lib/chef/win32/api/security.rb105
-rw-r--r--lib/chef/win32/api/synchronization.rb8
-rw-r--r--lib/chef/win32/api/system.rb8
-rw-r--r--lib/chef/win32/api/unicode.rb8
-rw-r--r--lib/chef/win32/crypto.rb100
-rw-r--r--lib/chef/win32/error.rb47
-rw-r--r--lib/chef/win32/eventlog.rb8
-rw-r--r--lib/chef/win32/file.rb57
-rw-r--r--lib/chef/win32/file/info.rb7
-rw-r--r--lib/chef/win32/file/version_info.rb93
-rw-r--r--lib/chef/win32/handle.rb12
-rw-r--r--lib/chef/win32/memory.rb10
-rw-r--r--lib/chef/win32/mutex.rb8
-rw-r--r--lib/chef/win32/net.rb87
-rw-r--r--lib/chef/win32/process.rb14
-rw-r--r--lib/chef/win32/registry.rb78
-rw-r--r--lib/chef/win32/security.rb110
-rw-r--r--lib/chef/win32/security/ace.rb12
-rw-r--r--lib/chef/win32/security/acl.rb20
-rw-r--r--lib/chef/win32/security/securable_object.rb10
-rw-r--r--lib/chef/win32/security/security_descriptor.rb10
-rw-r--r--lib/chef/win32/security/sid.rb136
-rw-r--r--lib/chef/win32/security/token.rb14
-rwxr-xr-xlib/chef/win32/system.rb8
-rw-r--r--lib/chef/win32/unicode.rb16
-rw-r--r--lib/chef/win32/version.rb58
-rw-r--r--lib/chef/workstation_config_loader.rb4
-rw-r--r--omnibus/.gitignore11
-rw-r--r--omnibus/.kitchen.vmware.yml6
-rw-r--r--omnibus/.kitchen.yml137
-rw-r--r--omnibus/Berksfile12
-rw-r--r--omnibus/Gemfile24
-rw-r--r--omnibus/Gemfile.lock270
-rw-r--r--omnibus/README.md152
-rw-r--r--omnibus/config/projects/angrychef.rb42
-rw-r--r--omnibus/config/projects/chef.rb79
-rw-r--r--omnibus/config/software/chef-appbundle.rb18
-rw-r--r--omnibus/config/software/chef-cleanup.rb30
-rw-r--r--omnibus/config/software/chef-complete.rb20
-rw-r--r--omnibus/config/software/chef-gem-bcrypt_pbkdf-ruby.rb10
-rw-r--r--omnibus/config/software/chef-gem-binding_of_caller.rb10
-rw-r--r--omnibus/config/software/chef-gem-byebug.rb10
-rw-r--r--omnibus/config/software/chef-gem-debug_inspector.rb10
-rw-r--r--omnibus/config/software/chef-gem-ffi-yajl.rb12
-rw-r--r--omnibus/config/software/chef-gem-ffi.rb12
-rw-r--r--omnibus/config/software/chef-gem-json.rb11
-rw-r--r--omnibus/config/software/chef-gem-libyajl2.rb10
-rw-r--r--omnibus/config/software/chef-gem-mini_portile2.rb10
-rw-r--r--omnibus/config/software/chef-gem-nokogiri.rb13
-rw-r--r--omnibus/config/software/chef-gem-pkg-config.rb10
-rw-r--r--omnibus/config/software/chef-gem-rbnacl-libsodium.rb10
-rw-r--r--omnibus/config/software/chef-gem-ruby-prof.rb10
-rw-r--r--omnibus/config/software/chef-gem-ruby-shadow.rb11
-rw-r--r--omnibus/config/software/chef.rb87
-rw-r--r--omnibus/files/chef-appbundle/build-chef-appbundle.rb93
-rw-r--r--omnibus/files/chef-gem/build-chef-gem.rb123
-rw-r--r--omnibus/files/chef-gem/build-chef-gem/gem-install-software-def.rb118
-rw-r--r--omnibus/files/chef/build-chef.rb127
-rw-r--r--omnibus/files/openssl-customization/windows/ssl_env_hack.rb34
-rw-r--r--omnibus/omnibus.rb55
-rwxr-xr-xomnibus/package-scripts/angrychef/postinst111
-rwxr-xr-xomnibus/package-scripts/angrychef/postrm42
-rwxr-xr-xomnibus/package-scripts/chef-fips/postinst111
-rwxr-xr-xomnibus/package-scripts/chef-fips/postrm42
-rwxr-xr-xomnibus/package-scripts/chef/postinst111
-rwxr-xr-xomnibus/package-scripts/chef/postrm42
-rw-r--r--omnibus/resources/chef/dmg/background.pngbin0 -> 44066 bytes
-rw-r--r--omnibus/resources/chef/dmg/icon.pngbin0 -> 245378 bytes
-rw-r--r--omnibus/resources/chef/ips/symlinks.erb6
-rw-r--r--omnibus/resources/chef/msi/assets/LICENSE.rtf197
-rw-r--r--omnibus/resources/chef/msi/assets/banner_background.bmpbin0 -> 114432 bytes
-rw-r--r--omnibus/resources/chef/msi/assets/dialog_background.bmpbin0 -> 615320 bytes
-rw-r--r--omnibus/resources/chef/msi/assets/oc.icobin0 -> 41880 bytes
-rw-r--r--omnibus/resources/chef/msi/assets/oc_16x16.icobin0 -> 1286 bytes
-rw-r--r--omnibus/resources/chef/msi/assets/oc_32x32.icobin0 -> 4682 bytes
-rw-r--r--omnibus/resources/chef/msi/localization-en-us.wxl.erb42
-rw-r--r--omnibus/resources/chef/msi/parameters.wxi.erb9
-rw-r--r--omnibus/resources/chef/msi/source.wxs.erb333
-rw-r--r--omnibus/resources/chef/pkg/background.pngbin0 -> 55731 bytes
-rw-r--r--omnibus/resources/chef/pkg/license.html.erb202
-rw-r--r--omnibus/resources/chef/pkg/welcome.html.erb5
-rw-r--r--omnibus_overrides.rb19
-rw-r--r--pedant.gemfile25
-rw-r--r--rubygems-pkg/rubygems-update-2.4.6.gembin451072 -> 0 bytes
-rw-r--r--spec/data/apt/chef-integration-test-1.0/debian/copyright4
-rw-r--r--spec/data/apt/chef-integration-test-1.1/debian/copyright4
-rw-r--r--spec/data/apt/chef-integration-test2-1.0/debian/changelog5
-rw-r--r--spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log45
-rw-r--r--spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars1
-rw-r--r--spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles1
-rw-r--r--spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control10
-rw-r--r--spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums1
-rw-r--r--spec/data/apt/chef-integration-test2-1.0/debian/compat1
-rw-r--r--spec/data/apt/chef-integration-test2-1.0/debian/conffiles1
-rw-r--r--spec/data/apt/chef-integration-test2-1.0/debian/control13
-rw-r--r--spec/data/apt/chef-integration-test2-1.0/debian/copyright34
-rw-r--r--spec/data/apt/chef-integration-test2-1.0/debian/files1
-rwxr-xr-xspec/data/apt/chef-integration-test2-1.0/debian/rules13
-rw-r--r--spec/data/apt/chef-integration-test2-1.0/debian/source/format1
-rw-r--r--spec/data/apt/chef-integration-test2_1.0-1.debian.tar.gzbin0 -> 1369 bytes
-rw-r--r--spec/data/apt/chef-integration-test2_1.0-1.dsc18
-rw-r--r--spec/data/apt/chef-integration-test2_1.0-1_amd64.build91
-rw-r--r--spec/data/apt/chef-integration-test2_1.0-1_amd64.changes31
-rw-r--r--spec/data/apt/chef-integration-test2_1.0-1_amd64.debbin0 -> 1694 bytes
-rw-r--r--spec/data/apt/chef-integration-test2_1.0.orig.tar.gzbin0 -> 248 bytes
-rw-r--r--spec/data/client.d_00/00-foo.rb2
-rw-r--r--spec/data/client.d_00/01-bar.rb1
-rw-r--r--spec/data/client.d_00/bar1
-rw-r--r--spec/data/client.d_01/foo/bar.rb1
-rw-r--r--spec/data/client.d_02/foo.rb/foo.txt1
-rw-r--r--spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb2
-rw-r--r--spec/data/cookbooks/openldap/.root_dotfile (renamed from spec/unit/provider/package_spec.rbe)0
-rw-r--r--spec/data/cookbooks/openldap/spec/spec_helper.rb0
-rw-r--r--spec/data/cookbooks/supports-platform-constraints/metadata.rb5
-rw-r--r--spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb2
-rw-r--r--spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb3
-rw-r--r--spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb2
-rw-r--r--spec/data/prefer_metadata_json/metadata.json51
-rw-r--r--spec/data/prefer_metadata_json/metadata.rb6
-rw-r--r--spec/data/prefer_metadata_json/recipes/default.rb0
-rw-r--r--spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb6
-rw-r--r--spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb5
-rw-r--r--spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb4
-rw-r--r--spec/data/run_context/cookbooks/dependency1/attributes/default.rb4
-rw-r--r--spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb5
-rw-r--r--spec/data/run_context/cookbooks/dependency2/attributes/default.rb5
-rw-r--r--spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb5
-rw-r--r--spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb5
-rw-r--r--spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb5
-rw-r--r--spec/data/sample_msu1.xml10
-rw-r--r--spec/data/sample_msu2.xml14
-rw-r--r--spec/data/sample_msu3.xml16
-rw-r--r--spec/data/templates/chef-seattle20160930-4388-1crv7ef.txt1
-rw-r--r--spec/data/templates/chef-seattle20160930-4388-jjfoae.txt1
-rw-r--r--spec/data/templates/chef-seattle20160930-4388-umeq2c.txt1
-rw-r--r--spec/data/trusted_certs/example_no_cn.crt36
-rw-r--r--spec/functional/application_spec.rb16
-rw-r--r--spec/functional/assets/chocolatey_feed/test-A.1.0.nupkgbin0 -> 2678 bytes
-rw-r--r--spec/functional/assets/chocolatey_feed/test-A.1.5.nupkgbin0 -> 2679 bytes
-rw-r--r--spec/functional/assets/chocolatey_feed/test-A.2.0.nupkgbin0 -> 2678 bytes
-rw-r--r--spec/functional/assets/chocolatey_feed/test-B.1.0.nupkgbin0 -> 2678 bytes
-rwxr-xr-xspec/functional/assets/testchefsubsys5
-rw-r--r--spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.i686.rpmbin0 -> 6530 bytes
-rw-r--r--spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.src.rpmbin0 -> 6331 bytes
-rw-r--r--spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.x86_64.rpmbin0 -> 6498 bytes
-rw-r--r--spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.i686.rpmbin0 -> 6526 bytes
-rw-r--r--spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.src.rpmbin0 -> 6331 bytes
-rw-r--r--spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpmbin0 -> 6494 bytes
-rw-r--r--spec/functional/assets/yumrepo/repodata/313329137b55fd333b2dc66394a6661a2befa6cc535d8460d92a4a78a9c581f0-primary.sqlite.bz2bin0 -> 2460 bytes
-rw-r--r--spec/functional/assets/yumrepo/repodata/31ac4db5d5ac593728fcc26aef82b7b93c4cc4dbec843786b1845b939b658553-other.xml.gzbin0 -> 413 bytes
-rw-r--r--spec/functional/assets/yumrepo/repodata/4ac40fa3c6728c1401318e2e20a997436624e83dcf7a5f952b851ef422637773-filelists.sqlite.bz2bin0 -> 1131 bytes
-rw-r--r--spec/functional/assets/yumrepo/repodata/66391e53f0510b98b3f0b79f40ba1048026d9a1ef20905d9c40ba6f5411f3243-primary.xml.gzbin0 -> 859 bytes
-rw-r--r--spec/functional/assets/yumrepo/repodata/8b34697595fcc87928e12d24644dda9462c3857bd932861e28bc77ae1f31be16-filelists.xml.gzbin0 -> 419 bytes
-rw-r--r--spec/functional/assets/yumrepo/repodata/b97cca3fe14bcf06c52be4449b6108f7731239ff221111dcce8aada5467f60dc-other.sqlite.bz2bin0 -> 967 bytes
-rw-r--r--spec/functional/assets/yumrepo/repodata/repomd.xml55
-rw-r--r--spec/functional/audit/rspec_formatter_spec.rb16
-rw-r--r--spec/functional/audit/runner_spec.rb22
-rw-r--r--spec/functional/dsl/reboot_pending_spec.rb25
-rw-r--r--spec/functional/dsl/registry_helper_spec.rb18
-rw-r--r--spec/functional/event_loggers/windows_eventlog_spec.rb64
-rw-r--r--spec/functional/file_content_management/deploy_strategies_spec.rb21
-rw-r--r--spec/functional/http/simple_spec.rb26
-rw-r--r--spec/functional/knife/configure_spec.rb15
-rw-r--r--spec/functional/knife/cookbook_delete_spec.rb121
-rw-r--r--spec/functional/knife/exec_spec.rb24
-rw-r--r--spec/functional/knife/rehash_spec.rb39
-rw-r--r--spec/functional/knife/smoke_test.rb14
-rw-r--r--spec/functional/knife/ssh_spec.rb70
-rw-r--r--spec/functional/mixin/powershell_out_spec.rb10
-rw-r--r--spec/functional/mixin/shell_out_spec.rb24
-rw-r--r--spec/functional/notifications_spec.rb87
-rwxr-xr-xspec/functional/provider/remote_file/cache_control_data_spec.rb23
-rw-r--r--spec/functional/provider/whyrun_safe_ruby_block_spec.rb12
-rw-r--r--spec/functional/rebooter_spec.rb36
-rwxr-xr-xspec/functional/resource/aix_service_spec.rb19
-rwxr-xr-xspec/functional/resource/aixinit_service_spec.rb40
-rw-r--r--spec/functional/resource/base.rb4
-rw-r--r--spec/functional/resource/bash_spec.rb20
-rw-r--r--spec/functional/resource/batch_spec.rb14
-rw-r--r--spec/functional/resource/bff_spec.rb22
-rw-r--r--spec/functional/resource/chocolatey_package_spec.rb125
-rw-r--r--spec/functional/resource/cookbook_file_spec.rb20
-rw-r--r--spec/functional/resource/cron_spec.rb37
-rw-r--r--spec/functional/resource/deploy_revision_spec.rb42
-rw-r--r--spec/functional/resource/directory_spec.rb8
-rw-r--r--spec/functional/resource/dnf_package_spec.rb686
-rw-r--r--spec/functional/resource/dpkg_package_spec.rb339
-rw-r--r--spec/functional/resource/dsc_resource_spec.rb51
-rw-r--r--spec/functional/resource/dsc_script_spec.rb271
-rwxr-xr-xspec/functional/resource/env_spec.rb68
-rw-r--r--spec/functional/resource/execute_spec.rb45
-rw-r--r--spec/functional/resource/file_spec.rb25
-rw-r--r--spec/functional/resource/git_spec.rb48
-rw-r--r--spec/functional/resource/group_spec.rb109
-rw-r--r--spec/functional/resource/ifconfig_spec.rb32
-rw-r--r--spec/functional/resource/link_spec.rb385
-rw-r--r--spec/functional/resource/mount_spec.rb49
-rw-r--r--spec/functional/resource/msu_package_spec.rb84
-rw-r--r--spec/functional/resource/ohai_spec.rb25
-rw-r--r--spec/functional/resource/package_spec.rb26
-rw-r--r--spec/functional/resource/powershell_script_spec.rb122
-rw-r--r--spec/functional/resource/reboot_spec.rb28
-rw-r--r--spec/functional/resource/registry_spec.rb271
-rw-r--r--spec/functional/resource/remote_directory_spec.rb46
-rw-r--r--spec/functional/resource/remote_file_spec.rb55
-rw-r--r--spec/functional/resource/rpm_spec.rb43
-rw-r--r--spec/functional/resource/template_spec.rb24
-rw-r--r--spec/functional/resource/user/dscl_spec.rb22
-rw-r--r--spec/functional/resource/user/useradd_spec.rb140
-rw-r--r--spec/functional/resource/user/windows_spec.rb40
-rw-r--r--spec/functional/resource/windows_package_spec.rb168
-rw-r--r--spec/functional/resource/windows_service_spec.rb50
-rw-r--r--spec/functional/rest_spec.rb15
-rw-r--r--spec/functional/run_lock_spec.rb86
-rw-r--r--spec/functional/shell_spec.rb23
-rw-r--r--spec/functional/tiny_server_spec.rb49
-rw-r--r--spec/functional/util/path_helper_spec.rb12
-rw-r--r--spec/functional/util/powershell/cmdlet_spec.rb51
-rw-r--r--spec/functional/version_spec.rb12
-rw-r--r--spec/functional/win32/crypto_spec.rb19
-rw-r--r--spec/functional/win32/registry_spec.rb213
-rw-r--r--spec/functional/win32/security_spec.rb50
-rw-r--r--spec/functional/win32/service_manager_spec.rb25
-rw-r--r--spec/functional/win32/sid_spec.rb26
-rw-r--r--spec/functional/win32/version_info_spec.rb50
-rw-r--r--spec/functional/win32/versions_spec.rb30
-rw-r--r--spec/integration/client/client_spec.rb223
-rw-r--r--spec/integration/client/exit_code_spec.rb245
-rw-r--r--spec/integration/client/ipv6_spec.rb31
-rw-r--r--spec/integration/knife/chef_fs_data_store_spec.rb678
-rw-r--r--spec/integration/knife/chef_repo_path_spec.rb591
-rw-r--r--spec/integration/knife/chef_repository_file_system_spec.rb172
-rw-r--r--spec/integration/knife/chefignore_spec.rb164
-rw-r--r--spec/integration/knife/client_bulk_delete_spec.rb130
-rw-r--r--spec/integration/knife/client_create_spec.rb69
-rw-r--r--spec/integration/knife/client_delete_spec.rb63
-rw-r--r--spec/integration/knife/client_key_create_spec.rb65
-rw-r--r--spec/integration/knife/client_key_delete_spec.rb42
-rw-r--r--spec/integration/knife/client_key_list_spec.rb60
-rw-r--r--spec/integration/knife/client_key_show_spec.rb44
-rw-r--r--spec/integration/knife/client_list_spec.rb48
-rw-r--r--spec/integration/knife/client_show_spec.rb36
-rw-r--r--spec/integration/knife/common_options_spec.rb82
-rw-r--r--spec/integration/knife/cookbook_api_ipv6_spec.rb18
-rw-r--r--spec/integration/knife/cookbook_bulk_delete_spec.rb64
-rw-r--r--spec/integration/knife/cookbook_download_spec.rb95
-rw-r--r--spec/integration/knife/cookbook_list_spec.rb54
-rw-r--r--spec/integration/knife/cookbook_show_spec.rb159
-rw-r--r--spec/integration/knife/cookbook_upload_spec.rb90
-rw-r--r--spec/integration/knife/data_bag_create_spec.rb55
-rw-r--r--spec/integration/knife/data_bag_delete_spec.rb58
-rw-r--r--spec/integration/knife/data_bag_from_file_spec.rb115
-rw-r--r--spec/integration/knife/data_bag_list_spec.rb43
-rw-r--r--spec/integration/knife/data_bag_show_spec.rb53
-rw-r--r--spec/integration/knife/delete_spec.rb510
-rw-r--r--spec/integration/knife/deps_spec.rb568
-rw-r--r--spec/integration/knife/diff_spec.rb474
-rw-r--r--spec/integration/knife/download_spec.rb952
-rw-r--r--spec/integration/knife/environment_compare_spec.rb74
-rw-r--r--spec/integration/knife/environment_create_spec.rb40
-rw-r--r--spec/integration/knife/environment_delete_spec.rb36
-rw-r--r--spec/integration/knife/environment_from_file_spec.rb115
-rw-r--r--spec/integration/knife/environment_list_spec.rb41
-rw-r--r--spec/integration/knife/environment_show_spec.rb76
-rw-r--r--spec/integration/knife/list_spec.rb430
-rw-r--r--spec/integration/knife/node_bulk_delete_spec.rb51
-rw-r--r--spec/integration/knife/node_create_spec.rb46
-rw-r--r--spec/integration/knife/node_delete_spec.rb47
-rw-r--r--spec/integration/knife/node_environment_set_spec.rb45
-rw-r--r--spec/integration/knife/node_from_file_spec.rb58
-rw-r--r--spec/integration/knife/node_list_spec.rb44
-rw-r--r--spec/integration/knife/node_run_list_add_spec.rb53
-rw-r--r--spec/integration/knife/node_run_list_remove_spec.rb35
-rw-r--r--spec/integration/knife/node_run_list_set_spec.rb40
-rw-r--r--spec/integration/knife/node_show_spec.rb35
-rw-r--r--spec/integration/knife/raw_spec.rb80
-rw-r--r--spec/integration/knife/redirection_spec.rb24
-rw-r--r--spec/integration/knife/role_bulk_delete_spec.rb51
-rw-r--r--spec/integration/knife/role_create_spec.rb40
-rw-r--r--spec/integration/knife/role_delete_spec.rb47
-rw-r--r--spec/integration/knife/role_from_file_spec.rb95
-rw-r--r--spec/integration/knife/role_list_spec.rb44
-rw-r--r--spec/integration/knife/role_show_spec.rb50
-rw-r--r--spec/integration/knife/serve_spec.rb24
-rw-r--r--spec/integration/knife/show_spec.rb118
-rw-r--r--spec/integration/knife/upload_spec.rb1243
-rw-r--r--spec/integration/recipes/accumulator_spec.rb232
-rw-r--r--spec/integration/recipes/lwrp_inline_resources_spec.rb151
-rw-r--r--spec/integration/recipes/lwrp_spec.rb14
-rw-r--r--spec/integration/recipes/noop_resource_spec.rb24
-rw-r--r--spec/integration/recipes/notifies_spec.rb334
-rw-r--r--spec/integration/recipes/notifying_block_spec.rb111
-rw-r--r--spec/integration/recipes/provider_choice.rb9
-rw-r--r--spec/integration/recipes/recipe_dsl_spec.rb923
-rw-r--r--spec/integration/recipes/remote_directory.rb4
-rw-r--r--spec/integration/recipes/resource_action_spec.rb650
-rw-r--r--spec/integration/recipes/resource_converge_if_changed_spec.rb153
-rw-r--r--spec/integration/recipes/resource_load_spec.rb124
-rw-r--r--spec/integration/solo/solo_spec.rb182
-rw-r--r--spec/scripts/ssl-serve.rb29
-rw-r--r--spec/spec_helper.rb132
-rw-r--r--spec/stress/win32/file_spec.rb10
-rw-r--r--spec/stress/win32/memory_spec.rb8
-rw-r--r--spec/stress/win32/security_spec.rb28
-rw-r--r--spec/support/chef_helpers.rb45
-rw-r--r--spec/support/key_helpers.rb4
-rw-r--r--spec/support/lib/chef/provider/easy.rb4
-rw-r--r--spec/support/lib/chef/provider/openldap_includer.rb4
-rw-r--r--spec/support/lib/chef/provider/snakeoil.rb5
-rw-r--r--spec/support/lib/chef/resource/cat.rb11
-rw-r--r--spec/support/lib/chef/resource/one_two_three_four.rb7
-rw-r--r--spec/support/lib/chef/resource/openldap_includer.rb7
-rw-r--r--spec/support/lib/chef/resource/with_state.rb10
-rw-r--r--spec/support/lib/chef/resource/zen_follower.rb8
-rw-r--r--spec/support/lib/chef/resource/zen_master.rb12
-rw-r--r--spec/support/lib/library_load_order.rb2
-rw-r--r--spec/support/matchers/leak.rb12
-rw-r--r--spec/support/mock/constant.rb10
-rw-r--r--spec/support/mock/platform.rb12
-rw-r--r--spec/support/pedant/Gemfile3
-rw-r--r--spec/support/pedant/pedant_config.rb129
-rw-r--r--spec/support/pedant/run_pedant.rb63
-rw-r--r--spec/support/pedant/stickywicket.pem27
-rw-r--r--spec/support/platform_helpers.rb117
-rw-r--r--spec/support/platforms/prof/gc.rb15
-rw-r--r--spec/support/platforms/prof/win32.rb7
-rw-r--r--spec/support/platforms/win32/spec_service.rb8
-rw-r--r--spec/support/shared/context/client.rb48
-rw-r--r--spec/support/shared/context/config.rb6
-rw-r--r--spec/support/shared/context/win32.rb18
-rw-r--r--spec/support/shared/examples/client.rb8
-rw-r--r--spec/support/shared/functional/diff_disabled.rb2
-rw-r--r--spec/support/shared/functional/directory_resource.rb20
-rw-r--r--spec/support/shared/functional/execute_resource.rb150
-rw-r--r--spec/support/shared/functional/file_resource.rb60
-rw-r--r--spec/support/shared/functional/http.rb95
-rw-r--r--spec/support/shared/functional/knife.rb6
-rw-r--r--spec/support/shared/functional/securable_resource.rb108
-rw-r--r--spec/support/shared/functional/securable_resource_with_reporting.rb20
-rw-r--r--spec/support/shared/functional/win32_service.rb20
-rw-r--r--spec/support/shared/functional/windows_script.rb106
-rw-r--r--spec/support/shared/integration/app_server_support.rb18
-rw-r--r--spec/support/shared/integration/integration_helper.rb48
-rw-r--r--spec/support/shared/integration/knife_support.rb46
-rw-r--r--spec/support/shared/matchers/exit_with_code.rb6
-rw-r--r--spec/support/shared/matchers/match_environment_variable.rb4
-rw-r--r--spec/support/shared/shared_examples.rb4
-rw-r--r--spec/support/shared/unit/api_error_inspector.rb8
-rw-r--r--spec/support/shared/unit/api_versioning.rb20
-rw-r--r--spec/support/shared/unit/application_dot_d.rb73
-rw-r--r--spec/support/shared/unit/execute_resource.rb54
-rw-r--r--spec/support/shared/unit/file_system_support.rb25
-rw-r--r--spec/support/shared/unit/knife_shared.rb3
-rw-r--r--spec/support/shared/unit/mock_shellout.rb7
-rw-r--r--spec/support/shared/unit/platform_introspector.rb76
-rw-r--r--spec/support/shared/unit/provider/file.rb87
-rw-r--r--spec/support/shared/unit/provider/useradd_based_user_provider.rb204
-rw-r--r--spec/support/shared/unit/resource/static_provider_resolution.rb11
-rw-r--r--spec/support/shared/unit/script_resource.rb34
-rw-r--r--spec/support/shared/unit/user_and_client_shared.rb25
-rw-r--r--spec/support/shared/unit/windows_script_resource.rb15
-rw-r--r--spec/tiny_server.rb149
-rw-r--r--spec/unit/api_client/registration_spec.rb88
-rw-r--r--spec/unit/api_client_spec.rb29
-rw-r--r--spec/unit/api_client_v1_spec.rb38
-rw-r--r--spec/unit/application/apply_spec.rb17
-rw-r--r--spec/unit/application/client_spec.rb246
-rw-r--r--spec/unit/application/exit_code_spec.rb229
-rw-r--r--spec/unit/application/knife_spec.rb86
-rw-r--r--spec/unit/application/solo_spec.rb252
-rw-r--r--spec/unit/application_spec.rb473
-rw-r--r--spec/unit/audit/audit_event_proxy_spec.rb81
-rw-r--r--spec/unit/audit/audit_reporter_spec.rb84
-rw-r--r--spec/unit/audit/control_group_data_spec.rb64
-rw-r--r--spec/unit/audit/logger_spec.rb10
-rw-r--r--spec/unit/audit/rspec_formatter_spec.rb8
-rw-r--r--spec/unit/audit/runner_spec.rb23
-rw-r--r--spec/unit/chef_class_spec.rb20
-rw-r--r--spec/unit/chef_fs/config_spec.rb155
-rw-r--r--spec/unit/chef_fs/data_handler/group_handler_spec.rb36
-rw-r--r--spec/unit/chef_fs/diff_spec.rb158
-rw-r--r--spec/unit/chef_fs/file_pattern_spec.rb737
-rw-r--r--spec/unit/chef_fs/file_system/cookbook_subdir_spec.rb34
-rw-r--r--spec/unit/chef_fs/file_system/operation_failed_error_spec.rb26
-rw-r--r--spec/unit/chef_fs/file_system/repository/base_file_spec.rb126
-rw-r--r--spec/unit/chef_fs/file_system/repository/directory_spec.rb175
-rw-r--r--spec/unit/chef_fs/file_system_spec.rb150
-rw-r--r--spec/unit/chef_fs/parallelizer.rb147
-rw-r--r--spec/unit/chef_fs/path_util_spec.rb90
-rw-r--r--spec/unit/chef_spec.rb6
-rw-r--r--spec/unit/client_spec.rb90
-rw-r--r--spec/unit/config_fetcher_spec.rb86
-rw-r--r--spec/unit/config_spec.rb4
-rw-r--r--spec/unit/cookbook/chefignore_spec.rb24
-rw-r--r--spec/unit/cookbook/cookbook_version_loader_spec.rb32
-rw-r--r--spec/unit/cookbook/file_vendor_spec.rb32
-rw-r--r--spec/unit/cookbook/metadata_spec.rb500
-rw-r--r--spec/unit/cookbook/synchronizer_spec.rb74
-rw-r--r--spec/unit/cookbook/syntax_check_spec.rb56
-rw-r--r--spec/unit/cookbook_loader_spec.rb78
-rw-r--r--spec/unit/cookbook_manifest_spec.rb55
-rw-r--r--spec/unit/cookbook_site_streaming_uploader_spec.rb52
-rw-r--r--spec/unit/cookbook_spec.rb10
-rw-r--r--spec/unit/cookbook_uploader_spec.rb21
-rw-r--r--spec/unit/cookbook_version_file_specificity_spec.rb126
-rw-r--r--spec/unit/cookbook_version_spec.rb271
-rw-r--r--spec/unit/daemon_spec.rb12
-rw-r--r--spec/unit/data_bag_item_spec.rb156
-rw-r--r--spec/unit/data_bag_spec.rb102
-rw-r--r--spec/unit/data_collector/messages/helpers_spec.rb193
-rw-r--r--spec/unit/data_collector/messages_spec.rb192
-rw-r--r--spec/unit/data_collector_spec.rb741
-rw-r--r--spec/unit/decorator/lazy_array_spec.rb58
-rw-r--r--spec/unit/decorator/lazy_spec.rb39
-rw-r--r--spec/unit/decorator_spec.rb142
-rw-r--r--spec/unit/deprecated_spec.rb59
-rw-r--r--spec/unit/deprecation_spec.rb29
-rw-r--r--spec/unit/digester_spec.rb11
-rw-r--r--spec/unit/dsl/audit_spec.rb14
-rw-r--r--spec/unit/dsl/data_query_spec.rb29
-rw-r--r--spec/unit/dsl/declare_resource_spec.rb365
-rw-r--r--spec/unit/dsl/platform_introspection_spec.rb39
-rw-r--r--spec/unit/dsl/reboot_pending_spec.rb36
-rw-r--r--spec/unit/dsl/recipe_spec.rb23
-rw-r--r--spec/unit/dsl/registry_helper_spec.rb (renamed from spec/unit/dsl/regsitry_helper_spec.rb)23
-rw-r--r--spec/unit/dsl/resources_spec.rb28
-rw-r--r--spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb21
-rw-r--r--spec/unit/encrypted_data_bag_item_spec.rb33
-rw-r--r--spec/unit/environment_spec.rb132
-rw-r--r--spec/unit/event_dispatch/dispatcher_spec.rb11
-rw-r--r--spec/unit/event_dispatch/dsl_spec.rb32
-rw-r--r--spec/unit/exceptions_spec.rb22
-rw-r--r--spec/unit/file_access_control_spec.rb70
-rw-r--r--spec/unit/file_cache_spec.rb38
-rw-r--r--spec/unit/file_content_management/deploy/cp_spec.rb8
-rw-r--r--spec/unit/file_content_management/deploy/mv_unix_spec.rb8
-rw-r--r--spec/unit/file_content_management/deploy/mv_windows_spec.rb17
-rw-r--r--spec/unit/file_content_management/tempfile_spec.rb115
-rw-r--r--spec/unit/formatters/base_spec.rb35
-rw-r--r--spec/unit/formatters/doc_spec.rb28
-rw-r--r--spec/unit/formatters/error_description_spec.rb96
-rw-r--r--spec/unit/formatters/error_inspectors/api_error_formatting_spec.rb23
-rw-r--r--spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb22
-rw-r--r--spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb11
-rw-r--r--spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb6
-rw-r--r--spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb7
-rw-r--r--spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb7
-rw-r--r--spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb10
-rw-r--r--spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb12
-rw-r--r--spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb22
-rw-r--r--spec/unit/guard_interpreter_spec.rb6
-rw-r--r--spec/unit/handler/json_file_spec.rb23
-rw-r--r--spec/unit/handler_spec.rb105
-rw-r--r--spec/unit/http/api_versions_spec.rb69
-rw-r--r--spec/unit/http/authenticator_spec.rb16
-rw-r--r--spec/unit/http/basic_client_spec.rb113
-rw-r--r--spec/unit/http/http_request_spec.rb44
-rw-r--r--spec/unit/http/json_input_spec.rb14
-rw-r--r--spec/unit/http/simple_spec.rb6
-rw-r--r--spec/unit/http/socketless_chef_zero_client_spec.rb7
-rw-r--r--spec/unit/http/ssl_policies_spec.rb37
-rw-r--r--spec/unit/http/validate_content_length_spec.rb59
-rw-r--r--spec/unit/http_spec.rb166
-rw-r--r--spec/unit/json_compat_spec.rb25
-rw-r--r--spec/unit/key_spec.rb83
-rw-r--r--spec/unit/knife/bootstrap/chef_vault_handler_spec.rb87
-rw-r--r--spec/unit/knife/bootstrap/client_builder_spec.rb62
-rw-r--r--spec/unit/knife/bootstrap_spec.rb196
-rw-r--r--spec/unit/knife/client_bulk_delete_spec.rb32
-rw-r--r--spec/unit/knife/client_create_spec.rb27
-rw-r--r--spec/unit/knife/client_delete_spec.rb44
-rw-r--r--spec/unit/knife/client_edit_spec.rb24
-rw-r--r--spec/unit/knife/client_list_spec.rb10
-rw-r--r--spec/unit/knife/client_reregister_spec.rb26
-rw-r--r--spec/unit/knife/client_show_spec.rb24
-rw-r--r--spec/unit/knife/configure_client_spec.rb43
-rw-r--r--spec/unit/knife/configure_spec.rb78
-rw-r--r--spec/unit/knife/cookbook_bulk_delete_spec.rb36
-rw-r--r--spec/unit/knife/cookbook_create_spec.rb157
-rw-r--r--spec/unit/knife/cookbook_delete_spec.rb158
-rw-r--r--spec/unit/knife/cookbook_download_spec.rb169
-rw-r--r--spec/unit/knife/cookbook_list_spec.rb52
-rw-r--r--spec/unit/knife/cookbook_metadata_from_file_spec.rb10
-rw-r--r--spec/unit/knife/cookbook_metadata_spec.rb251
-rw-r--r--spec/unit/knife/cookbook_show_spec.rb206
-rw-r--r--spec/unit/knife/cookbook_site_download_spec.rb105
-rw-r--r--spec/unit/knife/cookbook_site_install_spec.rb29
-rw-r--r--spec/unit/knife/cookbook_site_share_spec.rb94
-rw-r--r--spec/unit/knife/cookbook_site_unshare_spec.rb40
-rw-r--r--spec/unit/knife/cookbook_test_spec.rb16
-rw-r--r--spec/unit/knife/cookbook_upload_spec.rb152
-rw-r--r--spec/unit/knife/core/bootstrap_context_spec.rb154
-rw-r--r--spec/unit/knife/core/cookbook_scm_repo_spec.rb64
-rw-r--r--spec/unit/knife/core/custom_manifest_loader_spec.rb14
-rw-r--r--spec/unit/knife/core/gem_glob_loader_spec.rb49
-rw-r--r--spec/unit/knife/core/hashed_command_loader_spec.rb49
-rw-r--r--spec/unit/knife/core/node_editor_spec.rb211
-rw-r--r--spec/unit/knife/core/object_loader_spec.rb24
-rw-r--r--spec/unit/knife/core/subcommand_loader_spec.rb26
-rw-r--r--spec/unit/knife/core/ui_spec.rb146
-rw-r--r--spec/unit/knife/data_bag_create_spec.rb28
-rw-r--r--spec/unit/knife/data_bag_edit_spec.rb26
-rw-r--r--spec/unit/knife/data_bag_from_file_spec.rb25
-rw-r--r--spec/unit/knife/data_bag_secret_options_spec.rb12
-rw-r--r--spec/unit/knife/data_bag_show_spec.rb43
-rw-r--r--spec/unit/knife/environment_compare_spec.rb66
-rw-r--r--spec/unit/knife/environment_create_spec.rb6
-rw-r--r--spec/unit/knife/environment_delete_spec.rb4
-rw-r--r--spec/unit/knife/environment_edit_spec.rb8
-rw-r--r--spec/unit/knife/environment_from_file_spec.rb10
-rw-r--r--spec/unit/knife/environment_list_spec.rb8
-rw-r--r--spec/unit/knife/environment_show_spec.rb4
-rw-r--r--spec/unit/knife/index_rebuild_spec.rb31
-rw-r--r--spec/unit/knife/key_create_spec.rb55
-rw-r--r--spec/unit/knife/key_delete_spec.rb22
-rw-r--r--spec/unit/knife/key_edit_spec.rb67
-rw-r--r--spec/unit/knife/key_helper.rb4
-rw-r--r--spec/unit/knife/key_list_spec.rb38
-rw-r--r--spec/unit/knife/key_show_spec.rb30
-rw-r--r--spec/unit/knife/knife_help.rb4
-rw-r--r--spec/unit/knife/node_bulk_delete_spec.rb23
-rw-r--r--spec/unit/knife/node_delete_spec.rb39
-rw-r--r--spec/unit/knife/node_edit_spec.rb35
-rw-r--r--spec/unit/knife/node_environment_set_spec.rb34
-rw-r--r--spec/unit/knife/node_from_file_spec.rb12
-rw-r--r--spec/unit/knife/node_list_spec.rb13
-rw-r--r--spec/unit/knife/node_run_list_add_spec.rb15
-rw-r--r--spec/unit/knife/node_run_list_remove_spec.rb54
-rw-r--r--spec/unit/knife/node_run_list_set_spec.rb33
-rw-r--r--spec/unit/knife/node_show_spec.rb14
-rw-r--r--spec/unit/knife/osc_user_create_spec.rb18
-rw-r--r--spec/unit/knife/osc_user_delete_spec.rb14
-rw-r--r--spec/unit/knife/osc_user_edit_spec.rb14
-rw-r--r--spec/unit/knife/osc_user_list_spec.rb6
-rw-r--r--spec/unit/knife/osc_user_reregister_spec.rb20
-rw-r--r--spec/unit/knife/osc_user_show_spec.rb16
-rw-r--r--spec/unit/knife/raw_spec.rb12
-rw-r--r--spec/unit/knife/role_bulk_delete_spec.rb10
-rw-r--r--spec/unit/knife/role_create_spec.rb12
-rw-r--r--spec/unit/knife/role_delete_spec.rb10
-rw-r--r--spec/unit/knife/role_edit_spec.rb16
-rw-r--r--spec/unit/knife/role_env_run_list_add_spec.rb20
-rw-r--r--spec/unit/knife/role_env_run_list_clear_spec.rb86
-rw-r--r--spec/unit/knife/role_env_run_list_remove_spec.rb100
-rw-r--r--spec/unit/knife/role_env_run_list_replace_spec.rb103
-rw-r--r--spec/unit/knife/role_env_run_list_set_spec.rb39
-rw-r--r--spec/unit/knife/role_from_file_spec.rb16
-rw-r--r--spec/unit/knife/role_list_spec.rb14
-rw-r--r--spec/unit/knife/role_run_list_add_spec.rb16
-rw-r--r--spec/unit/knife/role_run_list_clear_spec.rb64
-rw-r--r--spec/unit/knife/role_run_list_remove_spec.rb80
-rw-r--r--spec/unit/knife/role_run_list_replace_spec.rb89
-rw-r--r--spec/unit/knife/role_run_list_set_spec.rb17
-rw-r--r--spec/unit/knife/role_show_spec.rb28
-rw-r--r--spec/unit/knife/ssh_spec.rb148
-rw-r--r--spec/unit/knife/ssl_check_spec.rb40
-rw-r--r--spec/unit/knife/ssl_fetch_spec.rb58
-rw-r--r--spec/unit/knife/status_spec.rb11
-rw-r--r--spec/unit/knife/tag_create_spec.rb2
-rw-r--r--spec/unit/knife/tag_delete_spec.rb4
-rw-r--r--spec/unit/knife/tag_list_spec.rb4
-rw-r--r--spec/unit/knife/user_create_spec.rb70
-rw-r--r--spec/unit/knife/user_delete_spec.rb22
-rw-r--r--spec/unit/knife/user_edit_spec.rb20
-rw-r--r--spec/unit/knife/user_list_spec.rb6
-rw-r--r--spec/unit/knife/user_reregister_spec.rb26
-rw-r--r--spec/unit/knife/user_show_spec.rb24
-rw-r--r--spec/unit/knife_spec.rb189
-rw-r--r--spec/unit/lib_backcompat_spec.rb34
-rw-r--r--spec/unit/log/syslog_spec.rb6
-rw-r--r--spec/unit/log/winevt_spec.rb6
-rw-r--r--spec/unit/log_spec.rb10
-rw-r--r--spec/unit/lwrp_spec.rb155
-rw-r--r--spec/unit/mash_spec.rb16
-rw-r--r--spec/unit/mixin/api_version_request_handling_spec.rb31
-rw-r--r--spec/unit/mixin/checksum_spec.rb25
-rw-r--r--spec/unit/mixin/command_spec.rb31
-rw-r--r--spec/unit/mixin/convert_to_class_name_spec.rb4
-rw-r--r--spec/unit/mixin/deep_merge_spec.rb214
-rw-r--r--spec/unit/mixin/deprecation_spec.rb12
-rw-r--r--spec/unit/mixin/enforce_ownership_and_permissions_spec.rb18
-rw-r--r--spec/unit/mixin/homebrew_user_spec.rb30
-rw-r--r--spec/unit/mixin/lazy_module_include.rb71
-rw-r--r--spec/unit/mixin/params_validate_spec.rb275
-rw-r--r--spec/unit/mixin/path_sanity_spec.rb38
-rw-r--r--spec/unit/mixin/powershell_out_spec.rb40
-rw-r--r--spec/unit/mixin/powershell_type_coercions_spec.rb59
-rw-r--r--spec/unit/mixin/properties_spec.rb54
-rw-r--r--spec/unit/mixin/proxified_socket_spec.rb97
-rw-r--r--spec/unit/mixin/securable_spec.rb74
-rw-r--r--spec/unit/mixin/shell_out_spec.rb131
-rw-r--r--spec/unit/mixin/subclass_directive_spec.rb45
-rw-r--r--spec/unit/mixin/template_spec.rb27
-rw-r--r--spec/unit/mixin/unformatter_spec.rb6
-rw-r--r--spec/unit/mixin/uris_spec.rb16
-rw-r--r--spec/unit/mixin/versioned_api_spec.rb107
-rw-r--r--spec/unit/mixin/which.rb160
-rw-r--r--spec/unit/mixin/windows_architecture_helper_spec.rb33
-rw-r--r--spec/unit/mixin/xml_escape_spec.rb12
-rw-r--r--spec/unit/monkey_patches/uri_spec.rb6
-rw-r--r--spec/unit/monologger_spec.rb8
-rw-r--r--spec/unit/node/attribute_spec.rb548
-rw-r--r--spec/unit/node/immutable_collections_spec.rb52
-rw-r--r--spec/unit/node/vivid_mash_spec.rb353
-rw-r--r--spec/unit/node_map_spec.rb10
-rw-r--r--spec/unit/node_spec.rb611
-rw-r--r--spec/unit/org_spec.rb34
-rw-r--r--spec/unit/platform/query_helpers_spec.rb52
-rw-r--r--spec/unit/platform_spec.rb50
-rw-r--r--spec/unit/policy_builder/dynamic_spec.rb20
-rw-r--r--spec/unit/policy_builder/expand_node_object_spec.rb32
-rw-r--r--spec/unit/policy_builder/policyfile_spec.rb85
-rw-r--r--spec/unit/policy_builder_spec.rb8
-rw-r--r--spec/unit/property/state_spec.rb132
-rw-r--r--spec/unit/property/validation_spec.rb513
-rw-r--r--spec/unit/property_spec.rb381
-rw-r--r--spec/unit/provider/apt_repository_spec.rb183
-rw-r--r--spec/unit/provider/apt_update_spec.rb114
-rw-r--r--spec/unit/provider/breakpoint_spec.rb5
-rw-r--r--spec/unit/provider/cookbook_file/content_spec.rb19
-rw-r--r--spec/unit/provider/cookbook_file_spec.rb30
-rw-r--r--spec/unit/provider/cron/unix_spec.rb22
-rw-r--r--spec/unit/provider/cron_spec.rb170
-rw-r--r--spec/unit/provider/deploy/revision_spec.rb13
-rw-r--r--spec/unit/provider/deploy/timestamped_spec.rb4
-rw-r--r--spec/unit/provider/deploy_spec.rb67
-rw-r--r--spec/unit/provider/directory_spec.rb51
-rw-r--r--spec/unit/provider/dsc_resource_spec.rb330
-rw-r--r--spec/unit/provider/dsc_script_spec.rb113
-rw-r--r--spec/unit/provider/env/windows_spec.rb54
-rw-r--r--spec/unit/provider/env_spec.rb10
-rw-r--r--spec/unit/provider/erl_call_spec.rb7
-rw-r--r--spec/unit/provider/execute_spec.rb135
-rw-r--r--spec/unit/provider/file/content_spec.rb28
-rw-r--r--spec/unit/provider/file_spec.rb25
-rw-r--r--spec/unit/provider/git_spec.rb206
-rw-r--r--spec/unit/provider/group/dscl_spec.rb76
-rw-r--r--spec/unit/provider/group/gpasswd_spec.rb26
-rw-r--r--spec/unit/provider/group/groupadd_spec.rb238
-rw-r--r--spec/unit/provider/group/groupmod_spec.rb56
-rw-r--r--spec/unit/provider/group/pw_spec.rb36
-rw-r--r--spec/unit/provider/group/suse_spec.rb90
-rw-r--r--spec/unit/provider/group/usermod_spec.rb44
-rw-r--r--spec/unit/provider/group/windows_spec.rb18
-rw-r--r--spec/unit/provider/group_spec.rb32
-rw-r--r--spec/unit/provider/http_request_spec.rb14
-rw-r--r--spec/unit/provider/ifconfig/aix_spec.rb37
-rw-r--r--spec/unit/provider/ifconfig/debian_spec.rb40
-rw-r--r--spec/unit/provider/ifconfig/redhat_spec.rb14
-rw-r--r--spec/unit/provider/ifconfig_spec.rb47
-rw-r--r--spec/unit/provider/launchd_spec.rb268
-rw-r--r--spec/unit/provider/link_spec.rb179
-rw-r--r--spec/unit/provider/log_spec.rb18
-rw-r--r--spec/unit/provider/mdadm_spec.rb33
-rw-r--r--spec/unit/provider/mount/aix_spec.rb17
-rw-r--r--spec/unit/provider/mount/mount_spec.rb58
-rw-r--r--spec/unit/provider/mount/solaris_spec.rb150
-rw-r--r--spec/unit/provider/mount/windows_spec.rb30
-rw-r--r--spec/unit/provider/mount_spec.rb39
-rw-r--r--spec/unit/provider/ohai_spec.rb28
-rw-r--r--spec/unit/provider/osx_profile_spec.rb255
-rw-r--r--spec/unit/provider/package/aix_spec.rb63
-rw-r--r--spec/unit/provider/package/apt_spec.rb231
-rw-r--r--spec/unit/provider/package/cab_spec.rb272
-rw-r--r--spec/unit/provider/package/chocolatey_spec.rb489
-rw-r--r--spec/unit/provider/package/dnf/python_helper_spec.rb29
-rw-r--r--spec/unit/provider/package/dpkg_spec.rb299
-rw-r--r--spec/unit/provider/package/easy_install_spec.rb56
-rw-r--r--spec/unit/provider/package/freebsd/pkg_spec.rb40
-rw-r--r--spec/unit/provider/package/freebsd/pkgng_spec.rb39
-rw-r--r--spec/unit/provider/package/freebsd/port_spec.rb47
-rw-r--r--spec/unit/provider/package/homebrew_spec.rb278
-rw-r--r--spec/unit/provider/package/ips_spec.rb83
-rw-r--r--spec/unit/provider/package/macports_spec.rb26
-rw-r--r--spec/unit/provider/package/msu_spec.rb283
-rw-r--r--spec/unit/provider/package/openbsd_spec.rb92
-rw-r--r--spec/unit/provider/package/pacman_spec.rb19
-rw-r--r--spec/unit/provider/package/paludis_spec.rb25
-rw-r--r--spec/unit/provider/package/portage_spec.rb23
-rw-r--r--spec/unit/provider/package/powershell_spec.rb337
-rw-r--r--spec/unit/provider/package/rpm_spec.rb64
-rw-r--r--spec/unit/provider/package/rubygems_spec.rb783
-rw-r--r--spec/unit/provider/package/smartos_spec.rb18
-rw-r--r--spec/unit/provider/package/solaris_spec.rb38
-rw-r--r--spec/unit/provider/package/windows/exe_spec.rb201
-rw-r--r--spec/unit/provider/package/windows/msi_spec.rb123
-rw-r--r--spec/unit/provider/package/windows_spec.rb350
-rw-r--r--spec/unit/provider/package/yum/yum_cache_spec.rb27
-rw-r--r--spec/unit/provider/package/yum_spec.rb567
-rw-r--r--spec/unit/provider/package/zypper_spec.rb215
-rw-r--r--spec/unit/provider/package_spec.rb952
-rw-r--r--spec/unit/provider/powershell_script_spec.rb56
-rw-r--r--spec/unit/provider/registry_key_spec.rb152
-rw-r--r--spec/unit/provider/remote_directory_spec.rb109
-rw-r--r--spec/unit/provider/remote_file/cache_control_data_spec.rb115
-rw-r--r--spec/unit/provider/remote_file/content_spec.rb14
-rw-r--r--spec/unit/provider/remote_file/fetcher_spec.rb6
-rw-r--r--spec/unit/provider/remote_file/ftp_spec.rb18
-rw-r--r--spec/unit/provider/remote_file/http_spec.rb43
-rw-r--r--spec/unit/provider/remote_file/local_file_spec.rb10
-rw-r--r--spec/unit/provider/remote_file/network_file_spec.rb4
-rw-r--r--spec/unit/provider/remote_file/sftp_spec.rb150
-rw-r--r--spec/unit/provider/remote_file_spec.rb28
-rw-r--r--spec/unit/provider/route_spec.rb99
-rw-r--r--spec/unit/provider/ruby_block_spec.rb9
-rw-r--r--spec/unit/provider/script_spec.rb83
-rw-r--r--spec/unit/provider/service/aix_service_spec.rb11
-rw-r--r--spec/unit/provider/service/aixinit_service_spec.rb49
-rw-r--r--spec/unit/provider/service/arch_service_spec.rb30
-rw-r--r--spec/unit/provider/service/debian_service_spec.rb82
-rw-r--r--spec/unit/provider/service/freebsd_service_spec.rb48
-rw-r--r--spec/unit/provider/service/gentoo_service_spec.rb8
-rw-r--r--spec/unit/provider/service/init_service_spec.rb18
-rw-r--r--spec/unit/provider/service/insserv_service_spec.rb6
-rw-r--r--spec/unit/provider/service/invokercd_service_spec.rb18
-rw-r--r--spec/unit/provider/service/macosx_spec.rb56
-rw-r--r--spec/unit/provider/service/openbsd_service_spec.rb80
-rw-r--r--spec/unit/provider/service/redhat_spec.rb50
-rw-r--r--spec/unit/provider/service/simple_service_spec.rb10
-rw-r--r--spec/unit/provider/service/solaris_smf_service_spec.rb102
-rw-r--r--spec/unit/provider/service/systemd_service_spec.rb155
-rw-r--r--spec/unit/provider/service/upstart_service_spec.rb95
-rw-r--r--spec/unit/provider/service/windows_spec.rb87
-rw-r--r--spec/unit/provider/service_spec.rb5
-rw-r--r--spec/unit/provider/subversion_spec.rb174
-rw-r--r--spec/unit/provider/systemd_unit_spec.rb885
-rw-r--r--spec/unit/provider/template/content_spec.rb64
-rw-r--r--spec/unit/provider/template_spec.rb47
-rw-r--r--spec/unit/provider/user/dscl_spec.rb279
-rw-r--r--spec/unit/provider/user/linux_spec.rb112
-rw-r--r--spec/unit/provider/user/pw_spec.rb75
-rw-r--r--spec/unit/provider/user/solaris_spec.rb161
-rw-r--r--spec/unit/provider/user/useradd_spec.rb51
-rw-r--r--spec/unit/provider/user/windows_spec.rb24
-rw-r--r--spec/unit/provider/user_spec.rb83
-rw-r--r--spec/unit/provider/whyrun_safe_ruby_block_spec.rb7
-rw-r--r--spec/unit/provider/yum_repository_spec.rb35
-rw-r--r--spec/unit/provider_resolver_spec.rb664
-rw-r--r--spec/unit/provider_spec.rb15
-rw-r--r--spec/unit/pure_application_spec.rb6
-rw-r--r--spec/unit/recipe_spec.rb172
-rw-r--r--spec/unit/resource/apt_package_spec.rb10
-rw-r--r--spec/unit/resource/apt_repository_spec.rb50
-rw-r--r--spec/unit/resource/apt_update_spec.rb50
-rw-r--r--spec/unit/resource/bash_spec.rb6
-rw-r--r--spec/unit/resource/batch_spec.rb10
-rw-r--r--spec/unit/resource/breakpoint_spec.rb8
-rw-r--r--spec/unit/resource/cab_package_spec.rb38
-rw-r--r--spec/unit/resource/chef_gem_spec.rb22
-rw-r--r--spec/unit/resource/chocolatey_package_spec.rb79
-rw-r--r--spec/unit/resource/conditional_action_not_nothing_spec.rb4
-rw-r--r--spec/unit/resource/conditional_spec.rb70
-rw-r--r--spec/unit/resource/cookbook_file_spec.rb47
-rw-r--r--spec/unit/resource/cron_spec.rb16
-rw-r--r--spec/unit/resource/csh_spec.rb6
-rw-r--r--spec/unit/resource/deploy_revision_spec.rb10
-rw-r--r--spec/unit/resource/deploy_spec.rb49
-rw-r--r--spec/unit/resource/directory_spec.rb8
-rw-r--r--spec/unit/resource/dnf_package_spec.rb99
-rw-r--r--spec/unit/resource/dpkg_package_spec.rb10
-rw-r--r--spec/unit/resource/dsc_resource_spec.rb59
-rw-r--r--spec/unit/resource/dsc_script_spec.rb38
-rw-r--r--spec/unit/resource/easy_install_package_spec.rb8
-rw-r--r--spec/unit/resource/env_spec.rb10
-rw-r--r--spec/unit/resource/erl_call_spec.rb6
-rw-r--r--spec/unit/resource/execute_spec.rb222
-rw-r--r--spec/unit/resource/file/verification/systemd_unit_spec.rb103
-rw-r--r--spec/unit/resource/file/verification_spec.rb24
-rw-r--r--spec/unit/resource/file_spec.rb20
-rw-r--r--spec/unit/resource/freebsd_package_spec.rb31
-rw-r--r--spec/unit/resource/gem_package_spec.rb10
-rw-r--r--spec/unit/resource/git_spec.rb8
-rw-r--r--spec/unit/resource/group_spec.rb21
-rw-r--r--spec/unit/resource/homebrew_package_spec.rb28
-rw-r--r--spec/unit/resource/http_request_spec.rb10
-rw-r--r--spec/unit/resource/ifconfig_spec.rb18
-rw-r--r--spec/unit/resource/ips_package_spec.rb10
-rw-r--r--spec/unit/resource/ksh_spec.rb40
-rw-r--r--spec/unit/resource/launchd_spec.rb32
-rw-r--r--spec/unit/resource/link_spec.rb12
-rw-r--r--spec/unit/resource/log_spec.rb6
-rw-r--r--spec/unit/resource/macports_package_spec.rb8
-rw-r--r--spec/unit/resource/mdadm_spec.rb19
-rw-r--r--spec/unit/resource/mount_spec.rb23
-rw-r--r--spec/unit/resource/msu_package_spec.rb49
-rw-r--r--spec/unit/resource/ohai_spec.rb7
-rw-r--r--spec/unit/resource/openbsd_package_spec.rb11
-rw-r--r--spec/unit/resource/osx_profile_spec.rb62
-rw-r--r--spec/unit/resource/package_spec.rb17
-rw-r--r--spec/unit/resource/pacman_package_spec.rb8
-rw-r--r--spec/unit/resource/perl_spec.rb6
-rw-r--r--spec/unit/resource/portage_package_spec.rb4
-rw-r--r--spec/unit/resource/powershell_package_spec.rb68
-rw-r--r--spec/unit/resource/powershell_script_spec.rb30
-rw-r--r--spec/unit/resource/python_spec.rb6
-rw-r--r--spec/unit/resource/registry_key_spec.rb72
-rw-r--r--spec/unit/resource/remote_directory_spec.rb6
-rw-r--r--spec/unit/resource/remote_file_spec.rb42
-rw-r--r--spec/unit/resource/resource_notification_spec.rb36
-rw-r--r--spec/unit/resource/route_spec.rb6
-rw-r--r--spec/unit/resource/rpm_package_spec.rb6
-rw-r--r--spec/unit/resource/ruby_block_spec.rb8
-rw-r--r--spec/unit/resource/ruby_spec.rb6
-rw-r--r--spec/unit/resource/scm_spec.rb16
-rw-r--r--spec/unit/resource/script_spec.rb8
-rw-r--r--spec/unit/resource/service_spec.rb37
-rw-r--r--spec/unit/resource/smartos_package_spec.rb8
-rw-r--r--spec/unit/resource/solaris_package_spec.rb8
-rw-r--r--spec/unit/resource/subversion_spec.rb12
-rw-r--r--spec/unit/resource/systemd_unit_spec.rb133
-rw-r--r--spec/unit/resource/template_spec.rb15
-rw-r--r--spec/unit/resource/timestamped_deploy_spec.rb8
-rw-r--r--spec/unit/resource/user_spec.rb10
-rw-r--r--spec/unit/resource/windows_package_spec.rb12
-rw-r--r--spec/unit/resource/windows_service_spec.rb4
-rw-r--r--spec/unit/resource/yum_package_spec.rb73
-rw-r--r--spec/unit/resource/yum_repository_spec.rb49
-rw-r--r--spec/unit/resource_collection/resource_list_spec.rb14
-rw-r--r--spec/unit/resource_collection/resource_set_spec.rb18
-rw-r--r--spec/unit/resource_collection/stepable_iterator_spec.rb12
-rw-r--r--spec/unit/resource_collection_spec.rb127
-rw-r--r--spec/unit/resource_definition_spec.rb28
-rw-r--r--spec/unit/resource_reporter_spec.rb150
-rw-r--r--spec/unit/resource_resolver_spec.rb23
-rw-r--r--spec/unit/resource_spec.rb649
-rw-r--r--spec/unit/rest/auth_credentials_spec.rb238
-rw-r--r--spec/unit/rest_spec.rb188
-rw-r--r--spec/unit/role_spec.rb138
-rw-r--r--spec/unit/run_context/child_run_context_spec.rb54
-rw-r--r--spec/unit/run_context/cookbook_compiler_spec.rb56
-rw-r--r--spec/unit/run_context_spec.rb36
-rw-r--r--spec/unit/run_list/run_list_expansion_spec.rb52
-rw-r--r--spec/unit/run_list/run_list_item_spec.rb56
-rw-r--r--spec/unit/run_list/versioned_recipe_list_spec.rb55
-rw-r--r--spec/unit/run_list_spec.rb80
-rw-r--r--spec/unit/run_lock_spec.rb20
-rw-r--r--spec/unit/run_status_spec.rb11
-rw-r--r--spec/unit/runner_spec.rb19
-rw-r--r--spec/unit/scan_access_control_spec.rb9
-rw-r--r--spec/unit/search/query_spec.rb141
-rw-r--r--spec/unit/server_api_spec.rb50
-rw-r--r--spec/unit/server_api_versions_spec.rb44
-rw-r--r--spec/unit/shell/model_wrapper_spec.rb25
-rw-r--r--spec/unit/shell/shell_ext_spec.rb10
-rw-r--r--spec/unit/shell/shell_session_spec.rb19
-rw-r--r--spec/unit/shell_out_spec.rb2
-rw-r--r--spec/unit/shell_spec.rb18
-rw-r--r--spec/unit/user_spec.rb29
-rw-r--r--spec/unit/user_v1_spec.rb59
-rw-r--r--spec/unit/util/backup_spec.rb35
-rw-r--r--spec/unit/util/diff_spec.rb23
-rw-r--r--spec/unit/util/dsc/configuration_generator_spec.rb120
-rw-r--r--spec/unit/util/dsc/lcm_output_parser_spec.rb60
-rw-r--r--spec/unit/util/dsc/local_configuration_manager_spec.rb96
-rw-r--r--spec/unit/util/dsc/resource_store.rb58
-rw-r--r--spec/unit/util/editor_spec.rb142
-rw-r--r--spec/unit/util/file_edit_spec.rb14
-rw-r--r--spec/unit/util/powershell/cmdlet_spec.rb74
-rw-r--r--spec/unit/util/powershell/ps_credential_spec.rb27
-rw-r--r--spec/unit/util/selinux_spec.rb32
-rw-r--r--spec/unit/util/threaded_job_queue_spec.rb4
-rw-r--r--spec/unit/version/platform_spec.rb11
-rw-r--r--spec/unit/version_class_spec.rb17
-rw-r--r--spec/unit/version_constraint/platform_spec.rb7
-rw-r--r--spec/unit/version_constraint_spec.rb38
-rw-r--r--spec/unit/win32/error_spec.rb67
-rw-r--r--spec/unit/win32/registry_spec.rb50
-rw-r--r--spec/unit/win32/security_spec.rb66
-rw-r--r--spec/unit/windows_service_spec.rb133
-rw-r--r--tasks/announce.rb58
-rwxr-xr-xtasks/bin/bundle-platform20
-rw-r--r--tasks/bin/bundle-platform.bat2
-rw-r--r--tasks/bin/bundler_patch.rb27
-rwxr-xr-xtasks/bin/create-override-gemfile110
-rwxr-xr-xtasks/bin/gem-version-diff37
-rwxr-xr-xtasks/bin/run_external_test47
-rw-r--r--tasks/bundle.rb97
-rw-r--r--tasks/bundle_util.rb110
-rw-r--r--tasks/cbgb.rb84
-rw-r--r--tasks/changelog.rb33
-rw-r--r--tasks/dependencies.rb151
-rw-r--r--tasks/external_tests.rb53
-rw-r--r--tasks/gemfile_util.rb390
-rw-r--r--tasks/maintainers.rb37
-rw-r--r--tasks/rspec.rb36
-rw-r--r--tasks/templates/prerelease.md.erb26
-rw-r--r--tasks/templates/release.md.erb26
-rw-r--r--version_policy.rb120
1920 files changed, 81363 insertions, 37692 deletions
diff --git a/.bundle/config b/.bundle/config
new file mode 100644
index 0000000000..e520135ebc
--- /dev/null
+++ b/.bundle/config
@@ -0,0 +1,2 @@
+---
+BUNDLE_FROZEN: "1"
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000000..d6ca06036d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,36 @@
+## Description
+
+Briefly describe the issue
+
+## Chef Version
+
+Tell us which version of chef-client you are using (see below for Server+ChefDK bugs).
+
+## Platform Version
+
+Tell us which Operating System distribution and version chef-client is running on.
+
+## Replication Case
+
+Tell us what steps to take to replicate your problem. See [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve)
+for information on how to create a good replication case.
+
+## Client Output
+
+The relevant output of the chef-client run or a link to a gist of the entire run, if there is one.
+
+The debug output (chef-client -l debug) may be useful, but please link to a gist, or truncate it.
+
+## Stacktrace
+
+Please include the stacktrace.out output or link to a gist of it, if there is one.
+
+### NOTE: CHEF CLIENT BUGS ONLY
+
+This issue tracker is for the code contained within this repo -- `chef-client`, base `knife` functionality (not
+plugins), `chef-apply`, `chef-solo`, `chef-client -z`, etc.
+
+* Requests for new or alternative functionality should be made to [feedback.chef.io](https://feedback.chef.io/forums/301644-chef-product-feedback/category/110832-chef-client)
+* [Chef Server issues](https://github.com/chef/chef-server/issues/new)
+* [ChefDK issues](https://github.com/chef/chef-dk/issues/new)
+* Cookbook Issues (see the https://github.com/chef-cookbooks repos or search [Supermarket](https://supermarket.chef.io) or GitHub/Google)
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000000..aca7c10237
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,15 @@
+### Description
+
+[Please describe what this change achieves]
+
+### Issues Resolved
+
+[List any existing issues this PR resolves, or any Discourse or
+StackOverflow discussion that's relevant]
+
+### Check List
+
+- [ ] New functionality includes tests
+- [ ] All tests pass
+- [ ] RELEASE\_NOTES.md, has been updated if required (not required for bugfixes, required for API changes)
+- [ ] All commits have been signed-off for the Developer Certificate of Origin. See <https://github.com/chef/chef/blob/master/CONTRIBUTING.md#developer-certification-of-origin-dco>
diff --git a/.gitignore b/.gitignore
index 953f58919f..03d53ceb10 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,24 +1,22 @@
.autotest
coverage
.DS_Store
-pkg
+pkg/*
tags
*/tags
*~
+.chef
+results
-# you should check in your Gemfile.lock in applications, and not in gems
+# You should check in your Gemfile.lock in applications, and not in gems
external_tests/*.lock
-Gemfile.lock
-Gemfile.local
-
-# Do not check in the .bundle directory, or any of the files inside it. Those files are specific to each particular machine, and are used to persist installation options between runs of the bundle install command.
-.bundle
+/Gemfile.local
# ignore some common Bundler 'binstubs' directory names
# http://gembundler.com/man/bundle-exec.1.html
b/
binstubs/
-
+**/.bundle
# RVM and RBENV ruby version files
.rbenv-version
.rvmrc
@@ -35,7 +33,6 @@ doc/
# Test Kitchen
.kitchen/
-Berksfile.lock
# Vagrant
Vagrantfile
@@ -46,3 +43,11 @@ kitchen-tests/nodes/*
# Temporary files present during spec runs
spec/data/test-dir
+/config/
+
+# acceptance binstubs
+acceptance/bin/*
+
+vendor/
+acceptance/vendor
+kitchen-tests/vendor
diff --git a/.kitchen.yml b/.kitchen.yml
deleted file mode 100644
index ed49eb3e57..0000000000
--- a/.kitchen.yml
+++ /dev/null
@@ -1,82 +0,0 @@
-driver:
- name: vagrant
- forward_agent: yes
- customize:
- cpus: 4
- memory: 4096
- synced_folders:
- - ['.', '/home/vagrant/chef']
-
-provisioner:
- name: chef_zero
- require_chef_omnibus: 12.0.0.rc.1
-
-platforms:
- - name: centos-5.10
- run_list:
- - name: centos-6.5
- run_list:
- - name: debian-7.2.0
- run_list:
- - name: debian-7.4
- run_list:
- - name: debian-6.0.8
- run_list:
- - name: freebsd-9.2
- run_list:
- - name: freebsd-10.0
- run_list:
- - name: ubuntu-10.04
- run_list:
- - name: ubuntu-12.04
- run_list:
- - name: ubuntu-12.10
- run_list:
- - name: ubuntu-13.04
- run_list:
- - name: ubuntu-13.10
- run_list:
- - name: ubuntu-14.04
- run_list:
- # The following boxes are shared via VagrantCloud. Until kitchen-vagrant
- # is updated you'll need to add the box manually:
- #
- # vagrant box add chef/windows-8.1-professional
- #
- # Please note this may require a `vagrant login` if the box is private.
- #
- # The following boxes are VMware only also. You can enable VMware Fusion
- # as the default provider by copying `.kitchen.local.yml.vmware.example`
- # over to `.kitchen.local.yml`.
- #
- - name: macosx-10.8
- driver:
- box: chef/macosx-10.8 # private
- - name: macosx-10.9
- driver:
- box: chef/macosx-10.9 # private
- - name: macosx-10.10
- driver:
- box: chef/macosx-10.10 # private
- # - name: windows-7-professional
- # provisioner:
- # name: windows_chef_zero
- # require_chef_omnibus: 11.12.4
- # driver:
- # box: chef/windows-7-professional # private
- # - name: windows-8.1-professional
- # provisioner:
- # name: windows_chef_zero
- # require_chef_omnibus: 11.12.4
- # driver:
- # box: chef/windows-8.1-professional # private
- # - name: windows-2008r2-standard
- # provisioner:
- # name: windows_chef_zero
- # require_chef_omnibus: 11.12.4
- # driver:
- # box: chef/windows-server-2008r2-standard # private
-
-suites:
- - name: chef
- run_list:
diff --git a/.mailmap b/.mailmap
index a7b6b6b277..614100091a 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1,5 +1,6 @@
# Daniel DeLeo
Daniel DeLeo <dan@chef.io> Daniel DeLeo <dan@opscode.com>
+Daniel DeLeo <dan@chef.io> danielsdeleo <dan@chef.io>
Daniel DeLeo <dan@chef.io> Dan DeLeo <danielsdeleo@mac.com>
Daniel DeLeo <dan@chef.io> Dan DeLeo <dan@kallistec.com>
Daniel DeLeo <dan@chef.io> danielsdeleo <dan@getchef.com>
@@ -62,11 +63,11 @@ Nuo Yan <nuo@opscode.com> Nuo Yan <nuoyan@nuo-yans-macbook-pro.(none)>
Nuo Yan <nuo@opscode.com> Nuo Yan <nuoyan@nuo-yans-macbook-pro.local>
# Thom May
-Thom May <thom@clearairturbulence.org>
-Thom May <thom@clearairturbulence.org> Thom May <thom.may@betfair.com>
-Thom May <thom@clearairturbulence.org> Thom May <thom@digital-science.com>
-Thom May <thom@clearairturbulence.org> Thom May <thom@virelais.nyc.joostas.com>
-Thom May <thom@clearairturbulence.org> Thom May <tmay@expedia.com>
+Thom May <thom@chef.io> Thom May <thom@clearairturbulence.org>
+Thom May <thom@chef.io> Thom May <thom.may@betfair.com>
+Thom May <thom@chef.io> Thom May <thom@digital-science.com>
+Thom May <thom@chef.io> Thom May <thom@virelais.nyc.joostas.com>
+Thom May <thom@chef.io> Thom May <tmay@expedia.com>
# Stephen Delano
Stephen Delano <stephen@chef.io> Stephen Delano <stephen@opscode.com>
@@ -114,4 +115,56 @@ Marc Paradise <marc@chef.io> marc@opscode.com <marc@opscode.com>
Tyler Ball <tyleraball@gmail.com> tyler-ball <tyleraball@gmail.com>
# Steven Danna
-Steven Danna <steve@chef.io> Steven Danna <steve@opscode.com> \ No newline at end of file
+Steven Danna <steve@chef.io> Steven Danna <steve@opscode.com>
+
+# Salim Alam
+Salim Alam <salam@chef.io> chefsalim <salam@chef.io>
+
+# Isa Farnik
+Isa Farnik <isa@chef.io> curiositycasualty <isa@getchef.com>
+Isa Farnik <isa@chef.io> curiositycasualty <isa@opscode.com>
+
+# Paul Mooring
+Paul Mooring <paul@chef.io> Paul Mooring <paul@opscode.com>
+
+# Jeremiah Snapp
+Jeremiah Snapp <jeremiah@chef.io> Jeremiah Snapp <jeremiah@getchef.com>
+Jeremiah Snapp <jeremiah@chef.io> Jeremiah Snapp <jeremiah.snapp@opscode.com>
+Jeremiah Snapp <jeremiah@chef.io> Jeremiah Snapp <jeremiah@opscode.com>
+
+# Mark Myzk
+Mark Mzyk <mmzyk@chef.io> Mark Mzyk <mmzyk@opscode.com>
+Mark Mzyk <mmzyk@chef.io> mmzyk <mmzyk@opscode.com>
+Mark Mzyk <mmzyk@chef.io> Mark Mzyk <markmzyk@Marks-MacBook-Pro.local>
+
+# Chris Doherty
+Chris Doherty <cdoherty@chef.io> Chris Doherty <cdoherty@getchef.com>
+Chris Doherty <cdoherty@chef.io> Chris Doherty <cdoherty@ooyala.com>
+Chris Doherty <cdoherty@chef.io> Chris Doherty <randomcamel@users.noreply.github.com>
+Chris Doherty <cdoherty@chef.io> unknown <cdoherty@chef.io>
+
+# Christopher Webber
+Christopher Webber <cwebber@chef.io> Christopher Webber <cwebber@getchef.com>
+
+# Tyler Cloke
+Tyler Cloke <tyler@chef.io> tylercloke <tyler@opscode.com>
+Tyler Cloke <tyler@chef.io> tylercloke <tylercloke@gmail.com>
+Tyler Cloke <tyler@chef.io> Tyler Cloke <tylercloke@gmail.com>
+
+# Julian Dunn
+Julian C. Dunn <jdunn@chef.io> Julian C. Dunn <jdunn@getchef.com>
+Julian C. Dunn <jdunn@chef.io> Julian C. Dunn <jdunn@opscode.com>
+Julian C. Dunn <jdunn@chef.io> Julian C. Dunn <jdunn@aquezada.com>
+
+# Tom Duffield
+Tom Duffield <tom@chef.io> Tom Duffield <tom@getchef.com>
+Tom Duffield <tom@chef.io> Tom Duffield <tom@opscode.com>
+
+# Scott Hain
+Scott Hain <shain@chef.io> Scott Hain <shain@getchef.com>
+
+# Peter Burkholder
+Peter Burkholder <pburkholder@chef.io> Peter Burkholder <peterb@getchef.com>
+
+# JJ Ashgar
+JJ Asghar <jj@chef.io> JJ Asghar <jj@getchef.com>
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000000..3c2a48e548
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,6 @@
+AllCops:
+ Exclude:
+ - "spec/data/**/*"
+ - "vendor/**/*"
+ - "pkg/**/*"
+ - "chef-config/pkg/**/*"
diff --git a/.travis.yml b/.travis.yml
index 9f253df6c4..279dcd0929 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,114 +1,336 @@
language: ruby
+sudo: false
cache: bundler
-sudo: false
# Early warning system to catch if Rubygems breaks something
before_install:
- gem update --system
+ - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+ - gem --version
+ - gem uninstall bundler -a -x
+ - rvm @global do gem uninstall bundler -a -x
+ - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+ - bundle --version
+ - rm -f .bundle/config
+
+bundler_args: --without changelog development docgen guard maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+
+before_script:
+ # force all .rspec tests into progress display to reduce line count
+ - echo --color > .rspec
+ - echo -fp >> .rspec
+ # necessary for sudo: true tests, ingore failures on tests invoked with sudo: false
+ - sudo sed -i -e 's/^Defaults\tsecure_path.*$//' /etc/sudoers || true
+# do not run expensive spec tests on PRs, only on branches
branches:
only:
- master
- - 10-stable
- 11-stable
-# do not run expensive spec tests on PRs, only on branches
-script: "
-echo '--color\n-fp' > .rspec;
-bundle exec rake spec;
-"
-
env:
global:
- FORCE_FFI_YAJL=ext
+ - BUNDLE_ENABLE_TRAMPOLINE=1
matrix:
include:
- - rvm: 2.1
- - rvm: 2.2
- - rvm: 2.2
- gemfile: pedant.gemfile
- script: bundle exec rake pedant
- - rvm: 2.2
- env: "GEMFILE_MOD=\"gem 'cheffish', github: 'chef/cheffish'\""
- script: bundle exec rake cheffish_spec
- - rvm: 2.2
- env: "GEMFILE_MOD=\"gem 'chef-provisioning', github: 'chef/chef-provisioning'\""
- script: bundle exec rake chef_provisioning_spec
- - rvm: 2.2
- env: "GEMFILE_MOD=\"gem 'chef-provisioning-aws', github: 'chef/chef-provisioning-aws'\""
- script: bundle exec rake chef_provisioning_aws_spec
- - rvm: 2.2
- env: "GEMFILE_MOD=\"gem 'chefspec'\""
- script: bundle exec rake chefspec_spec
- - rvm: 2.2
- env: "GEMFILE_MOD=\"gem 'chef-sugar'\""
- script: bundle exec rake chef_sugar_spec
- - rvm: 2.2
- env: "GEMFILE_MOD=\"gem 'chef-rewind'\""
- script: bundle exec rake chef_rewind_spec
- - rvm: 2.2
- env: "GEMFILE_MOD=\"gem 'foodcritic', github: 'acrmp/foodcritic', branch: 'v5.0.0'\""
- script: bundle exec rake foodcritic_spec
- - rvm: 2.2
- env: "GEMFILE_MOD=\"gem 'halite', github: 'poise/halite'\""
- script: bundle exec rake halite_spec
- - rvm: 2.2
- env: "GEMFILE_MOD=\"gem 'poise', github: 'poise/poise'\""
- script: bundle exec rake poise_spec
- # Not working yet: halite
- # - rvm: 2.2
- # script: bundle exec rake poise_spec
+ - rvm: 2.2.6
+ sudo: true
+ script: sudo -E $(which bundle) exec rake spec;
+ # also remove integration / external tests
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ - rvm: 2.3.3
+ sudo: true
+ script: sudo -E $(which bundle) exec rake spec;
+ # also remove integration / external tests
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ - rvm: 2.4.0
+ sudo: true
+ script: sudo -E $(which bundle) exec rake spec;
+ # also remove integration / external tests
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ - env:
+ CHEFSTYLE: 1
+ rvm: 2.3.3
+ script: bundle exec rake style
+ # also remove integration / external tests
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ - env:
+ AUDIT_CHECK: 1
+ rvm: 2.3.3
+ script: bundle exec bundle-audit check --update
+ # also remove integration / external tests
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ #
+ # External tests
+ #
+ - env:
+ TEST_GEM: chef-provisioning
+ script: tasks/bin/run_external_test $TEST_GEM rake spec
+ rvm: 2.3.3
+ - env:
+ TEST_GEM: chef-sugar
+ script: tasks/bin/run_external_test $TEST_GEM rake
+ rvm: 2.3.3
+ - env:
+ - TEST_GEM: chef-zero
+ script: tasks/bin/run_external_test $TEST_GEM rake spec cheffs
+ rvm: 2.3.3
+ - env:
+ TEST_GEM: cheffish
+ script: tasks/bin/run_external_test $TEST_GEM rake spec
+ rvm: 2.3.3
+ #- env:
+ # TEST_GEM: chefspec
+ ## The chefspec tests + bundler cache + "gem update --system" interact badly :/
+ ## (Cucumber doesn't start.)
+ #before_install:
+ # - gem uninstall bundler -a -x
+ # - rvm @global do gem uninstall bundler -a -x
+ # - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+ # - bundle config --local without server:docgen:maintenance:omnibus_package:development:ruby_prof:pry
+ #script: tasks/bin/run_external_test $TEST_GEM rake
+ #rvm: 2.3.3
+ - env:
+ TEST_GEM: foodcritic
+ script: tasks/bin/run_external_test $TEST_GEM rake test
+ rvm: 2.3.3
+ - env:
+ TEST_GEM: halite
+ script: tasks/bin/run_external_test $TEST_GEM rake spec
+ rvm: 2.3.3
+ - env:
+ TEST_GEM: knife-windows
+ script: tasks/bin/run_external_test $TEST_GEM rake unit_spec
+ rvm: 2.3.3
+ - env:
+ TEST_GEM: poise
+ script: tasks/bin/run_external_test $TEST_GEM rake spec
+ rvm: 2.3.3
### START TEST KITCHEN ONLY ###
- - rvm: 2.2
+ #
+ - rvm: 2.3.3
+ services: docker
+ sudo: required
gemfile: kitchen-tests/Gemfile
before_install:
- - echo -n $DO_KEY_CHUNK_{0..30} >> ~/.ssh/id_aws.base64
- - cat ~/.ssh/id_aws.base64 | tr -d ' ' | base64 --decode > ~/.ssh/id_aws.pem
+ - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+ - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
before_script:
- - cd kitchen-tests
+ - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER )
+ - cd kitchen-tests
script:
-# FIXME: we should fix centos-6 against AWS and then enable it here
- - if [ "$TRAVIS_SECURE_ENV_VARS" = "true" ]; then bundle exec kitchen test ubuntu; fi
+ - bundle exec kitchen test webapp-ubuntu-1204
after_failure:
- - cat .kitchen/logs/kitchen.log
- after_script:
- - if [ "$TRAVIS_SECURE_ENV_VARS" = "true" ]; then bundle exec kitchen destroy ubuntu; fi
+ - cat .kitchen/logs/kitchen.log
env:
- - KITCHEN_YAML=.kitchen.travis.yml
- - EC2_SSH_KEY_PATH=~/.ssh/id_aws.pem
- - secure: VAauyVnAMWhqvnhJOJ/tCDn3XAdWqzbWiDVQPNBkqtm2SBIvhmZl2hlrusvw6YLU31Prdf8fSFhOSysVQQs/rJYrmD/1BfV79p6M7cGXYZ0nGWwldF81N296lyFoZLyrqtmG4G0cx3Pw2ojADFgFe+B5eTGlqJFD+z371g4RF/Y=
- - secure: A+qtUF2LPJGkUAdvt04AwZMt69rzaeTyR0/1XEOAuntBKKXSCzddUzr5ePDc9QQ/57AWywKxhVLpnxk3QzKN7r7zerDxyIJBgklNDpNAKkeQjP3T6FpaKEIN9ROcpPtsM6FJ5Agb+bEQoRJF7s+ampO3wLV3XpTiWNuWkcAhv9A=
- - secure: J8JIg15trrPgc8X/1DsaUWDQCdDWTvN/AorXzZ/ReudHS6G/KpoynZ5lTmKjlgFiFNE/TGMDv486pStGtIcarTKTuIEmNADdEWlAVH7bxclpayMjtppVuapRCkZWccs5gz5CJyhX7yhQCFTYoqVox9Y4qHGCluF3oqCcPRtCOOw=
- - secure: NJYn0blTMwIoFxZlsoMWK8hPO/fi45rgWOqEImnjvSRk++5WL+GgjLBgLvEi7wCMkBijhIMWtnva60ojd4MrxeS7evrmGRjJKXnPuSKEsrGbArZPskBjCAcg+3PlnQQUkFf6hvbGD3HZlJtcbs4hrx8tbDT2Ie7bmQfqpsawKY4=
- - secure: FipoX1VzZkzPUP6Gxd05DEva7cX6xKK2Wdq+Y18nNkyW2afPLXCNl5kCsNrgvbqAzbjKaP2M8+b0zwKjrFzNebqmmx1RRfZUJWUkNRF1EgE+tHytmMZW6tNcQlTlvA0KqXi4Dt6SIQ0l/DhwwNKZ80jmpiyYi/ErxIXzbVgVtYA=
- - secure: T2MbE9twIkdaor796/lDioCgb2+FP3G8lXq+lIqnjaL22WMP8yKtkjNo8ggSlvQZE7MAQHqi5LISw5MU2MI6ImTU50/pgdWreM5Cx37WWYqntcbJ0Sz7v396KGJzeqbDql1fGolHDlykfi+OJzzbIGC8cjz7iAD2RUZU95wEC5s=
- - secure: hWEQInvuanQavFCE3m6/q9BjNEFZQmLc94EWnBKTMiwUAdYgQQMLohN7K1Gc8irxYKp86F+P+XWE4lfDZNK3sqmxyk51TtT2EfmKWs+jSLq4+NBYQwXCpRELC5Irpm0GRCYthhsQSuarpVWss/0s0o7iJQaHxrSPcQiwDouIpwU=
- - secure: OllJUaR/WUu+H0FIjU7vQxU10JT4d+/FZuTqnX6ZTcXN3dXCirnabYp/j+r5OBY3QeOojOyzGfHUWYEUGH/PTxcxYjrohtFTWht9N9x+SxfX2fLqieH/kRKyDmIidsY8qKChf/LD9f+SwpXRXND/PctKhNR4C5BH57fGUEqE9FU=
- - secure: KgKnGtM4e+cVYfLn78eTWJ1q4ORv128abB72QBc/xiSh0rvxSIojVKZCXmRetQPXIl7NoIzU2IyjR1ABEZ+vA83PayTEsOr2KDRDgolSIgZSSiDFt4U2phQsxl4fX7wFv/jWlbxM2fysKBSIRAF57CwBjGhLjmpUO+5PdoR7N2s=
- - secure: IgOx4STauKnJWENQGcn2iBp32XcNd2anNR0Fua0ugjudu1+CV+IxcIhI8ohOfZEXyVK4MGTF8uXWrYtoiwyExG4mTXqpRWJCgIkncqiWlfT+8BoAGWxCQhUYub3MaNZANPgebKPJhTPQ8OwNz09gPMNkewRfAqNF05eb8FU2kGA=
- - secure: CPXP6g3c1FH4Zm4U19XaPvq9nnyNsQCXRkxiPcGqsJZsGG2QMgzPQyjiAuPqnWxxZHit/6NgzUszJC+skSgcTzDTeD6rOA0Wcxtbr/Un4RRxRnTcRc6mSEZqSu9RbAZMYur/mSQ9HDHnjFe1ok85He4s9jM1iFdgjtg1ToelEmA=
- - secure: fp9pzNe09PIyZ/8NjbMPGW1zdG3Q/KhJ+stUKqA+FRopAMX/Hh24gFIVJhFOmfr4Vhn0J8sF7RsFaR1mdzcPewliOzKxknWhGEGMcG9LFCZcv+vVK0Fxs4nUzCRtaXUt08FpsRofG0iBvfapZ7YBhK7lslqGVI+fxCd3ZXmayG8=
- - secure: NT/6qcecxmuKYOnw1Atc6hsyJlfB6XI2Z1lg7dE0PhlEVW2EpkckHjAc+5hgg8Zt7TifYm2qDQWJwblwPP0mMj3ra4ZIMaZAiG2kzQoZ5kthqwjAV9fatZvrDXi+jd9wBF2hPyiCokAQiTLmKTYjzY2FBqPO3VDLWdf9qZqRmxw=
- - secure: MjIWyfquKANh/YeoyHGksdvAUQ4wc2tBCQmq1QcRhKwb7Sy6wcDk1nujDmnGE7HFpZUS6CyoZF7AMzJGFkCzrChpsLQYUP4hc7VjkXOLzi90vJUl+ANq7KPOmxC0MjKpgeHqCysRbTYbUsnJZfbbZbIZjCAjY0YCY2pGniXpvQc=
- - secure: AsZLOiFrHkGsY6jp2ShI5kYz78V6PEUyizgtPCWTgevTRGWpdCq9csIEoqUBY+vMUxmQPC6IY4fwHkrRCbv/rJyhwRl/Rnwa3aw8bdD+YD17IxnpXKGXXUyXdTZmF7HzAkVgStehL+qWZ3x9TBdExIV37KVgrVw/b+S0QqBUlQo=
- - secure: jwEnSquLreMM1M6N3gGpgTGHd8VtjBUTLDdkrokhiH1jHLpz7Hmr6xeajhZws+2sLtLiB7hYi6WsZBE5VcymBoObh9MeodO9Ve5/1z06lFmx1DyYV6euyo9WUkU2WpoVfu8k7O+eAvyrXXZVqm8Oz1p7Isb6Bh5+fJH2H8rhed4=
- - secure: HOAK620U6mlS11XK+JtXTBk26Tt2vWO4shA/6Zit/y0/kAz7JnbXtup7FSysXliBoSv4YsxA6IbgZ8V0tuIXj+q7EcqtHMmQhqzMJG5jRKVhtGiFIhDmwmxJvdfIvwtZOO3mMk0OspLz24sWp8wCciYZMPj0hZJR04R9aWEO3cE=
- - secure: DfTRP74UWWxA460XfLoJFgRLwoKbHWNIueL6qr982AnuAxeZFofsxCqxSxcSJmu67TxuPc+b201+BmanHKYmSauGS31t0F4QXk7lCTaT/x38mAPsWvMFkY8HEl56JhmzEp2hAKDB/t0/HItwmvxT1vd5WvNRSSojEVzChftV/zE=
- - secure: JoCWsJzTgj+epgzmgbvV7/bdAPHwUGXZA7Jdvv9vIJ5lCo6h9WwCw6/KCvH+bHtrT/RfZmUmxouCxJCLKwts1ZrMmedTIXpMrQJo/YgWRp7ziFnLyZ8jG8bD7rep3ngq1x/cRGc3cZvYN6IK3GS6C27OviYLFsTw74AUnWTaFSo=
- - secure: iXfl0WnAnfKurZUrMeV1yOoFiiZ+MKx/Zj6ZVP2++A9EOxxIxb/fS/gIOzSjBQwzrR+fJVHIlX0g42CiBKDQWUvIl5I8kZCVIP6AHa1jyzlmZE9lqSlojz3k5RPS7pW6nIX+z1NHMvtb3e5xeLv8y4J5kwZErqZ+YDJmBRtPxPU=
- - secure: RhAW5kABDPB3GWKD+NCg05Kcd92F/+kg+0icXXN166DWQYUut3MLrSY80xNzkz5nXTI9EFU4fUqlKLDiF/kelr0Zp/zpCQAB54o4cu5FkZz0Bgs9k7yUdCRyz6Vt2ChV5cYI4JTn9bMaeXEaGlOjP1iE51rYT6KO6kKlwsEnjUc=
- - secure: jy/3fC+UtrDcE/X6/IxkyT2SrYMKkiEMP1ht4d5mxvNA0Xxn43E16c6FNP0JWPpWRGRIP38vnQRB4yOPU9BXvRmmswVL9Ge4e/6flJvKwD5Rlqb2dfaGaHRYV9v8Nkdzl2FvZ9eBH5KHxgG19gCG6L3RXP/+zYwrr4AQdm0fpfw=
- - secure: RYEwBWYVXRTEdUWhQxdWXo6tldlVx8pha9zB0rgafcUQxaatAefnRc4X4HXTQnqr2n9TZ2TQGpM8vte/wr6Pjc85VZbimWGzgrvn0kg4MwPR8ZYiEM5qQ/pUpj4+93rpA91PhCGvZoZTqOrXHm4kMPuKro5I6qA4BFUXuANeC/s=
- - secure: gHSicpqkqcZT04QurSgszrAiI6HOCw1DBlfIIi9KAJj7mG5GijD/4AQ6HCmcRMbCDJ0nUuvm/kckASnRtF5+3xvIJnuoyyEfCZWxt1lhK2UbS87VU+pVdws/VzwpisXuKsh3H0uT8DDVkWPH/ZWDgfVa74eYDEHiQFjo+2xx5ZA=
- - secure: Q42bco3JXEpyVbL2akiOsaCHnAagAFIb3TF6H5qJfaLLqmGs/XrrgxliNaVMfWVSwPT2wpQvg9UGF9x37No9bZBv33DgYcWExmXb/lvGPpkctX37+FTMzECQHxOuUbYPQA7ZEuJ4AA7bwgpMISUeSyz5XXz44KcXIrZK2GWH+X4=
- - secure: hugd8NVukJc3redDvlOt6zhaqa63XLNMp/eIIlNllW8VfQ6CJ1P7KJPwgxH24sDyrw7rLzOkBl6R4kaVWsCLCFp+NE6yFFHl9wDkSdLC1OX1DMrJnDsogwUqqe+jX8dxePSy26MSTfG8eo9/NxN9uXr+tKaHoi6G7BRXDHtQ8dQ=
- - secure: TRkW9pIuIYHXJmPlDYoddxIp2M2W2f7qBGNJKEMB5xrOezES7w9XTg2eQXrD8jBO+fUUmMnAaDAXZuU58nMysPXx3vhtZKncg8w5CyuXJk2P8nkdPh0u5nmRhEpWrLKtLwJrX48xmJhNQvQqDAyL5c9WUzlWJ4WJFgoP5IDWmLc=
- - secure: QHuMdtFCvttiIOx6iS+lH4bKXZMwsgVQ6FPsUW5zJ7uw6mAEWKEil9xNk4aYV9FywinwUs4fnFlnIW/Gj1gLkUjm4DtxdmRZIlRXIbgsNch6H916TCPg4Q2oPsW2nVdXPjW/2jhkfLUiSnuhL+ylami1NF8Up7vokXknh/jFNZU=
- - secure: GTfrUVmMQSxho3Ia4Y1ONqKvVMD34GHF2/TJb8UdQV7iH+nVxVXpy3nWaCXa9ri7lRzMefkoVLy0gKK13YoVd7w3d2S3/IfNakC85XfN6VuOzK/FDkA0WoPrgKjcQ64I+3dQ6cgrMWWTieKwRZy+Ve24iRbnN055Hk+VRMu6OGw=
- - secure: SOMYGVfHLkHsH6koxpw68YQ4ydEo6YXPhHbrYGQbehUbFa6+OZzBcAJRJbKjyhD2AZRvNr2jB8XnjYKvVyDGQRpkWhGYZ7CpHqINpDsqKBsbiMe3/+KmKQqS+UKxNGefquoOvyQ1N8Xy77dkWYokRtGMEuR12RkZLonxiDW8Qyg=
- - secure: bSsDg+dJnPFdFiC/tbb61HdLh/Q0z2RVVAReT1wvV1BN4fN4NydvkUGbQmyFNyyunLulEs+X0oFma9L0497nUlTnan8UOg9sIleTSybPX6E9xSKKCItH1GgDw8bM9Igez5OOrrePBD3altVrH+FmGx0dlTQgM/KZMN50BJ79cXw=
+ - UBUNTU=12.04
+ - KITCHEN_YAML=.kitchen.travis.yml
+ - rvm: 2.3.3
+ services: docker
+ sudo: required
+ gemfile: kitchen-tests/Gemfile
+ before_install:
+ - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+ - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ before_script:
+ - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER )
+ - cd kitchen-tests
+ script:
+ - bundle exec kitchen test webapp-ubuntu-1404
+ after_failure:
+ - cat .kitchen/logs/kitchen.log
+ env:
+ - UBUNTU=14.04
+ - KITCHEN_YAML=.kitchen.travis.yml
+ - rvm: 2.3.3
+ services: docker
+ sudo: required
+ gemfile: kitchen-tests/Gemfile
+ before_install:
+ - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+ - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ before_script:
+ - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER )
+ - cd kitchen-tests
+ script:
+ - bundle exec kitchen test webapp-ubuntu-1604
+ after_failure:
+ - cat .kitchen/logs/kitchen.log
+ env:
+ - UBUNTU=16.04
+ - KITCHEN_YAML=.kitchen.travis.yml
+ - rvm: 2.3.3
+ services: docker
+ sudo: required
+ gemfile: kitchen-tests/Gemfile
+ before_install:
+ - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+ - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ before_script:
+ - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER )
+ - cd kitchen-tests
+ script:
+ - bundle exec kitchen test webapp-debian-7
+ after_failure:
+ - cat .kitchen/logs/kitchen.log
+ env:
+ - DEBIAN=7
+ - KITCHEN_YAML=.kitchen.travis.yml
+ - rvm: 2.3.3
+ services: docker
+ sudo: required
+ gemfile: kitchen-tests/Gemfile
+ before_install:
+ - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+ - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ before_script:
+ - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER )
+ - cd kitchen-tests
+ script:
+ - bundle exec kitchen test webapp-debian-8
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ after_failure:
+ - cat .kitchen/logs/kitchen.log
+ env:
+ - DEBIAN=8
+ - KITCHEN_YAML=.kitchen.travis.yml
+ - rvm: 2.3.3
+ services: docker
+ sudo: required
+ gemfile: kitchen-tests/Gemfile
+ before_install:
+ - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+ - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ before_script:
+ - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER )
+ - cd kitchen-tests
+ script:
+ - bundle exec kitchen test webapp-centos-6
+ after_failure:
+ - cat .kitchen/logs/kitchen.log
+ env:
+ - CENTOS=6
+ - KITCHEN_YAML=.kitchen.travis.yml
+ - rvm: 2.3.3
+ services: docker
+ sudo: required
+ gemfile: kitchen-tests/Gemfile
+ before_install:
+ - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+ - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ before_script:
+ - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER )
+ - cd kitchen-tests
+ script:
+ - bundle exec kitchen test webapp-centos-7
+ after_failure:
+ - cat .kitchen/logs/kitchen.log
+ env:
+ - CENTOS=7
+ - KITCHEN_YAML=.kitchen.travis.yml
+# - rvm: 2.3.3
+# services: docker
+# sudo: required
+# gemfile: kitchen-tests/Gemfile
+# before_install:
+# - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+# - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+# bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+# before_script:
+# - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER )
+# - cd kitchen-tests
+# script:
+# - bundle exec kitchen test webapp-fedora-latest
+# after_failure:
+# - cat .kitchen/logs/kitchen.log
+# env:
+# - FEDORA=latest
+# - KITCHEN_YAML=.kitchen.travis.yml
+# can re-enable amazonlinux when we get a build in current that contains the crypto libs added in #5687
+# - rvm: 2.3.3
+# services: docker
+# sudo: required
+# gemfile: kitchen-tests/Gemfile
+# before_install:
+# - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+# - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+# bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+# before_script:
+# - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER )
+# - cd kitchen-tests
+# script:
+# - travis_wait bundle exec kitchen test webapp-amazonlinux
+# after_failure:
+# - cat .kitchen/logs/kitchen.log
+# env:
+# - AMAZONLINUX=LATEST
+# - KITCHEN_YAML=.kitchen.travis.yml
+ - rvm: 2.3.3
+ services: docker
+ sudo: required
+ gemfile: kitchen-tests/Gemfile
+ before_install:
+ - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+ - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ before_script:
+ - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER )
+ - cd kitchen-tests
+ script:
+ - bundle exec kitchen test awesome-customers-ubuntu-ubuntu-1404
+ after_failure:
+ - cat .kitchen/logs/kitchen.log
+ env:
+ - AWESOME_CUSTOMERS_UBUNTU=1
+ - KITCHEN_YAML=.kitchen.travis.yml
+ - rvm: 2.3.3
+ services: docker
+ sudo: required
+ gemfile: kitchen-tests/Gemfile
+ before_install:
+ - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+ - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ before_script:
+ - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER )
+ - cd kitchen-tests
+ script:
+ - bundle exec kitchen test awesome-customers-rhel-centos-7
+ after_failure:
+ - cat .kitchen/logs/kitchen.log
+ env:
+ - AWESOME_CUSTOMERS_RHEL=1
+ - KITCHEN_YAML=.kitchen.travis.yml
### END TEST KITCHEN ONLY ###
+ - rvm: 2.3.3
+ sudo: required
+ dist: trusty
+ before_install:
+ - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2)
+ - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+ - sudo apt-get update
+ - sudo apt-get -y install squid3 git curl
+ bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen
+ env:
+ - PROXY_TESTS_DIR=proxy_tests/files/default/scripts
+ - PROXY_TESTS_REPO=$PROXY_TESTS_DIR/repo
+ script:
+ - bundle exec chef-client --version
+ - git clone https://github.com/chef/proxy_tests.git
+ - rvmsudo -E bundle exec bash $PROXY_TESTS_DIR/run_tests.sh chef_client \* \* /tmp/out.txt
+ after_script:
+ - cat /tmp/out.txt
+ - sudo cat /var/log/squid3/cache.log
+ - sudo cat /var/log/squid3/access.log
+
notifications:
on_change: true
on_failure: true
@@ -117,13 +339,3 @@ notifications:
irc:
channels:
- chat.freenode.net#chef-hacking
- webhooks:
- urls:
- # Gitter IM
- - secure: HmMKr/ysKVyKUJ24PRCHcA8QCmlFoukrYumY0GRLzvaFWO8PknHO1t/0RbrKRb2ed/hgkFd+RKNCYvSvcE8Ahr2vlMrBeGHGfVeOGkWtbhLgNqo1b50Ll9CqvTM8X2ZIq6hIWraanwoYRQu/8uGL29yH4lBi7DhpTkFwBMLulhQ=
- hipchat:
- rooms:
- # Build Statuses
- - secure: G8MNo94L8bmWWwkH2/ViB2QaZnZHZscYM/mEjDbOGd15sqrruwckeARyBoUcRI7P1C6AFmS4IKCNVXa6KzX4Pbh51gQWM92zRpRTZpplwtXz53/1l8ajLFLLMLvEMTlBFAANUKEUFAQPY4dMa14V3Qc5oijfIncN61k4nZNTKpY=
- # Open Source
- - secure: hmcex4PpG5dn8WvjndONO4xCUKOC5kPU/bUEGRrfVbe2YKJE7t0XXbNDC96W/xBgzgnJzvf1Er0zJKDrNf4qEDEWFoozdN00WLcqREgaLLS3Seto2FjR/BpBk5q+sCV0rwwEMms2P4Qk+VSnDCnm9EaeM55hOabqNuOrRzoZLBQ=
diff --git a/CBGB.md b/CBGB.md
new file mode 100644
index 0000000000..2ce26fc3ab
--- /dev/null
+++ b/CBGB.md
@@ -0,0 +1,40 @@
+<!-- This is a generated file. Please do not edit directly -->
+<!-- Modify CBGB.toml file and run `rake cbgb:generate` to regenerate -->
+
+# Chef Board of Governance (CBGB)
+
+ Chef was designed from the outset to have a very open structure, including open design, open contribution, and consistent use of tools across the project. Given the large numbers of contributors, users, and companies with a stake in the future of the project, Chef leadership has established an advisory board, as part of its long term commitment to open governance.
+
+ The Chef Board of Governance (CBGB) shall advise the Leadership on matters related to supporting the long-term governance, structure, and roadmap of the Project.
+
+More information can be found in the [Chef Board of Governance RFC](Chef Board of Governance).
+
+# Board of Governors
+
+## Project Lead
+
+* [Adam Jacob](https://github.com/adamhjk)
+
+### Users/Contributors (4)
+
+* [Ranjib Dey](https://github.com/ranjib)
+* [Doug Ireton](https://github.com/dougireton)
+* [Noah Kantrowitz](https://github.com/coderanger)
+* [Charity Majors](https://github.com/charity)
+
+
+### Corporate Contributors (4)
+
+* Etsy - Katherine Daniels
+* Facebook - Phil Dibowitz
+* Nordstrom - Mark Ayers
+* PagerDuty - Evan Gilman
+
+
+### Lieutenants (3)
+
+* [Jon Cowie](https://github.com/jonlives)
+* [Joshua Timberman](https://github.com/jtimberman)
+* [Seth Vargo](https://github.com/sethvargo)
+
+
diff --git a/CBGB.toml b/CBGB.toml
new file mode 100644
index 0000000000..07e9c9a25a
--- /dev/null
+++ b/CBGB.toml
@@ -0,0 +1,96 @@
+#
+# This file is structured to be consumed by both humans and computers.
+# It is a TOML document containing Markdown
+#
+[Preamble]
+ title = "Chef Board of Governance (CBGB)"
+ text = """
+ Chef was designed from the outset to have a very open structure, including open design, open contribution, and consistent use of tools across the project. Given the large numbers of contributors, users, and companies with a stake in the future of the project, Chef leadership has established an advisory board, as part of its long term commitment to open governance.
+
+ The Chef Board of Governance (CBGB) shall advise the Leadership on matters related to supporting the long-term governance, structure, and roadmap of the Project.
+
+More information can be found in the [Chef Board of Governance RFC](Chef Board of Governance).
+"""
+
+[Org]
+ [Org.Lead]
+ title = "Project Lead"
+ person = "adamhjk"
+
+ [Org.Contributors]
+ title = "Users/Contributors (4)"
+ governers = [
+ "ranjibdey",
+ "dougireton",
+ "coderanger",
+ "charitymajors"
+ ]
+
+ [Org.Corporate-Contributors]
+ title = "Corporate Contributors (4)"
+ governers = [
+ "etsy",
+ "facebook",
+ "nordstrom",
+ "pagerduty"
+ ]
+
+ [Org.Lieutenants]
+ title = "Lieutenants (3)"
+ governers = [
+ "jonlives",
+ "jtimberman",
+ "sethvargo"
+ ]
+
+[people]
+ [people.adamhjk]
+ Name = "Adam Jacob"
+ GitHub = "adamhjk"
+ IRC = "holoway"
+
+ [people.jonlives]
+ Name = "Jon Cowie"
+ GitHub = "jonlives"
+ IRC = "jonlives"
+
+ [people.coderanger]
+ Name = "Noah Kantrowitz"
+ GitHub = "coderanger"
+
+ [people.jtimberman]
+ Name = "Joshua Timberman"
+ GitHub = "jtimberman"
+
+ [people.ranjibdey]
+ Name = "Ranjib Dey"
+ GitHub = "ranjib"
+
+ [people.sethvargo]
+ Name = "Seth Vargo"
+ GitHub = "sethvargo"
+
+ [people.dougireton]
+ Name = "Doug Ireton"
+ GitHub = "dougireton"
+
+ [people.charitymajors]
+ Name = "Charity Majors"
+ GitHub = "charity"
+
+[corporations]
+ [corporations.etsy]
+ Name = "Etsy"
+ Person = "Katherine Daniels"
+
+ [corporations.facebook]
+ Name = "Facebook"
+ Person = "Phil Dibowitz"
+
+ [corporations.nordstrom]
+ Name = "Nordstrom"
+ Person = "Mark Ayers"
+
+ [corporations.pagerduty]
+ Name = "PagerDuty"
+ Person = "Evan Gilman"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 00041ca584..e2d50e9ce8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,14 +1,489 @@
+This changelog reflects the current state of chef's master branch on github and may not reflect the current released version of chef, which is [![Gem Version](https://badge.fury.io/rb/chef.svg)](https://badge.fury.io/rb/chef).
-## Unreleased
+## [v12.18.31](https://github.com/chef/chef/tree/v12.18.31) (2017-01-11)
+[Full Changelog](https://github.com/chef/chef/compare/v12.17.44...v12.18.31)
+
+**Implemented enhancements:**
+
+- yum\_repository: Allow baseurl to be an array & allow fastestmirror\_enabled false [\#5708](https://github.com/chef/chef/pull/5708) ([tas50](https://github.com/tas50))
+- Adding returns property to chocolatey\_package resource [\#5688](https://github.com/chef/chef/pull/5688) ([Vasu1105](https://github.com/Vasu1105))
+- Code cleanup in the user provider [\#5674](https://github.com/chef/chef/pull/5674) ([lamont-granquist](https://github.com/lamont-granquist))
+- Code cleanup in the group provider [\#5673](https://github.com/chef/chef/pull/5673) ([lamont-granquist](https://github.com/lamont-granquist))
+- Core: Formally deprecate run\_command [\#5666](https://github.com/chef/chef/pull/5666) ([lamont-granquist](https://github.com/lamont-granquist))
+- Set MSI Scheduled Task name to match chef-client cookbook managed name [\#5657](https://github.com/chef/chef/pull/5657) ([mwrock](https://github.com/mwrock))
+- remove Chef::Platform::HandlerMap [\#5636](https://github.com/chef/chef/pull/5636) ([lamont-granquist](https://github.com/lamont-granquist))
+- Core: Properly deprecate old Chef::Platform methods [\#5631](https://github.com/chef/chef/pull/5631) ([lamont-granquist](https://github.com/lamont-granquist))
+
+**Fixed bugs:**
+
+- Fix error thrown by solo when run on Windows as SYSTEM [\#5693](https://github.com/chef/chef/pull/5693) ([scottopherson](https://github.com/scottopherson))
+- Report a blank resource if sensitive is enabled [\#5668](https://github.com/chef/chef/pull/5668) ([afiune](https://github.com/afiune))
+- Ensure node.docker? returns boolean [\#5645](https://github.com/chef/chef/pull/5645) ([andrewjamesbrown](https://github.com/andrewjamesbrown))
+- Fix Data Collector organization parsing regex [\#5630](https://github.com/chef/chef/pull/5630) ([adamleff](https://github.com/adamleff))
+- Core: Use object ID when detected unprocessed Resources [\#5604](https://github.com/chef/chef/pull/5604) ([adamleff](https://github.com/adamleff))
+
+**Merged pull requests:**
+
+- Core: fix node attribute "unless" API methods [\#5717](https://github.com/chef/chef/pull/5717) ([lamont-granquist](https://github.com/lamont-granquist))
+
+## [v12.17.44](https://github.com/chef/chef/tree/v12.17.44) (2016-12-07)
+[Full Changelog](https://github.com/chef/chef/compare/v12.16.42...v12.17.44)
+
+**Implemented enhancements:**
+
+- Action :umount for mount resource is an obtuse anachronism [\#5595](https://github.com/chef/chef/issues/5595)
+- Core: Update ohai resource to new style, stop overwriting name property [\#5607](https://github.com/chef/chef/pull/5607) ([adamleff](https://github.com/adamleff))
+- Linux: mount provider - skip device detection for zfs [\#5603](https://github.com/chef/chef/pull/5603) ([ttr](https://github.com/ttr))
+- Core: Ensure chef-solo creates node files w/ correct permissions [\#5601](https://github.com/chef/chef/pull/5601) ([scottopherson](https://github.com/scottopherson))
+- Resources: Add unmount as an alias to umount in the mount resource [\#5599](https://github.com/chef/chef/pull/5599) ([shortdudey123](https://github.com/shortdudey123))
+- Core: Update Data Collector to use Chef::JSONCompat [\#5590](https://github.com/chef/chef/pull/5590) ([adamleff](https://github.com/adamleff))
+- Knife: Add ability to pass multiple nodes to knife node/client delete [\#5572](https://github.com/chef/chef/pull/5572) ([jeunito](https://github.com/jeunito))
+- Core: Data Collector debug log should output JSON [\#5570](https://github.com/chef/chef/pull/5570) ([adamleff](https://github.com/adamleff))
+- Yum: Purge yum cache before deleting repo config [\#5509](https://github.com/chef/chef/pull/5509) ([iancward](https://github.com/iancward))
+- Knife Bootstrap: Passing config\_log\_level and config\_log\_location from config.rb [\#5502](https://github.com/chef/chef/pull/5502) ([dheerajd-msys](https://github.com/dheerajd-msys))
+
+**Fixed bugs:**
+
+- Custom Resources: Undefined method up\_to\_date thrown by Chef 12.16.42 [\#5593](https://github.com/chef/chef/issues/5593)
+- Core: Ensure deprecation messages are always included [\#5618](https://github.com/chef/chef/pull/5618) ([thommay](https://github.com/thommay))
+- Core: Fix bug where Access Controls on existing symlink resources would be ignored on first chef-client run [\#5616](https://github.com/chef/chef/pull/5616) ([tduffield](https://github.com/tduffield))
+- The suggested fix for the manage\_home deprecation is incorrect [\#5615](https://github.com/chef/chef/pull/5615) ([tas50](https://github.com/tas50))
+- change choco -version to choco --version [\#5613](https://github.com/chef/chef/pull/5613) ([spuder](https://github.com/spuder))
+- Knife: Correct example `chef\_server\_url` in `knife configure` [\#5602](https://github.com/chef/chef/pull/5602) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
+- Windows: Ensure correct version of shutdown is called when using the reboot resource [\#5596](https://github.com/chef/chef/pull/5596) ([Xoph](https://github.com/Xoph))
+- Windows: Support for running cab\_package on non-English system locales [\#5591](https://github.com/chef/chef/pull/5591) ([jugatsu](https://github.com/jugatsu))
+- Core: Ensure Data Collector resource report exists before updating [\#5571](https://github.com/chef/chef/pull/5571) ([adamleff](https://github.com/adamleff))
+- Windows: Use the full path to expand.exe for msu\_package [\#5564](https://github.com/chef/chef/pull/5564) ([NimishaS](https://github.com/NimishaS))
+- Unset http\[s\]\_proxy in the subversion spec [\#5562](https://github.com/chef/chef/pull/5562) ([stefanor](https://github.com/stefanor))
+- Core: fix Lint/UnifiedInteger cop [\#5547](https://github.com/chef/chef/pull/5547) ([lamont-granquist](https://github.com/lamont-granquist))
+- Core: fix ImmutableArray slices [\#5541](https://github.com/chef/chef/pull/5541) ([lamont-granquist](https://github.com/lamont-granquist))
+- Prevent apt\_update failures on non-Linux platforms [\#5524](https://github.com/chef/chef/pull/5524) ([tas50](https://github.com/tas50))
+- Core: Ensure that the sensitive property is correctly accessed [\#5508](https://github.com/chef/chef/pull/5508) ([axos88](https://github.com/axos88))
+
+**Closed issues:**
+
+- cab\_package doesn't support running on non-English system locales [\#5592](https://github.com/chef/chef/issues/5592)
+- Support restarting/stopping/ the service from state paused on windows [\#5586](https://github.com/chef/chef/issues/5586)
+
+## [v12.16.42](https://github.com/chef/chef/tree/v12.16.42) (2016-11-04)
+[Full Changelog](https://github.com/chef/chef/compare/v12.15.19...v12.16.42)
+
+**Implemented enhancements:**
+
+- Core: improve readability of property-resource namespace collision exception message [\#5500](https://github.com/chef/chef/pull/5500) ([lamont-granquist](https://github.com/lamont-granquist))
+- Omnibus: Pull in Ohai 8.21.0 and other new deps [\#5499](https://github.com/chef/chef/pull/5499) ([tas50](https://github.com/tas50))
+- Core: Add deprecations to Data Collector run completion messages [\#5496](https://github.com/chef/chef/pull/5496) ([adamleff](https://github.com/adamleff))
+- Core: add attribute\_changed hook to event handlers [\#5495](https://github.com/chef/chef/pull/5495) ([lamont-granquist](https://github.com/lamont-granquist))
+- Knife: Add the `--field-separator` flag to knife show commands [\#5489](https://github.com/chef/chef/pull/5489) ([tduffield](https://github.com/tduffield))
+- Core: Enable Signed Header Auth for Data Collector, and Configure the Data Collector Automatically [\#5487](https://github.com/chef/chef/pull/5487) ([danielsdeleo](https://github.com/danielsdeleo))
+- Core: set use\_inline\_resources in package superclass [\#5483](https://github.com/chef/chef/pull/5483) ([lamont-granquist](https://github.com/lamont-granquist))
+- Package: Add new "lock" action for apt, yum and zypper packages [\#5395](https://github.com/chef/chef/pull/5395) ([yeoldegrove](https://github.com/yeoldegrove))
+
+**Fixed bugs:**
+
+- Enable data collector w/o token for solo, but require explicit URL [\#5511](https://github.com/chef/chef/pull/5511) ([danielsdeleo](https://github.com/danielsdeleo))
+- Core: Include chef/chef\_class in Chef::REST for method log\_deprecation [\#5504](https://github.com/chef/chef/pull/5504) ([smalltown](https://github.com/smalltown))
+- Knife: Updating knife ssl fetch to correctly store certificate when it does not have a CN [\#5498](https://github.com/chef/chef/pull/5498) ([tyler-ball](https://github.com/tyler-ball))
+- Knife: Fixed knife download cookbooks issue which used to corrupt the certificate files each time the command was fired. [\#5494](https://github.com/chef/chef/pull/5494) ([Aliasgar16](https://github.com/Aliasgar16))
+- Solaris: Properly check lock status of users on solaris2 [\#5486](https://github.com/chef/chef/pull/5486) ([tduffield](https://github.com/tduffield))
+- Solaris: Fix IPS package must create symlinks to package commands [\#5485](https://github.com/chef/chef/pull/5485) ([jaymalasinha](https://github.com/jaymalasinha))
+
+## [v12.15.19](https://github.com/chef/chef/tree/v12.15.19) (2016-10-07)
+[Full Changelog](https://github.com/chef/chef/compare/v12.14.89...v12.15.19)
+
+**Enhancements:**
+
+- Adding support for rfc 62 exit code 213 (Chef upgrades) [\#5428](https://github.com/chef/chef/pull/5428) ([jeremymv2](https://github.com/jeremymv2))
+- Allow raw_key to override the configured signing\_key [\#5314](https://github.com/chef/chef/pull/5314) ([thommay](https://github.com/thommay))
+- Set yum\_repository gpgcheck default to true [\#5398](https://github.com/chef/chef/pull/5398) ([shortdudey123](https://github.com/shortdudey123))
+- Allow deletion of registry\_key without the need for users to pass data key in values hash. [\#5359](https://github.com/chef/chef/pull/5359) ([Aliasgar16](https://github.com/Aliasgar16))
+- Adding support for cab files to Chef package provider on windows [\#5285](https://github.com/chef/chef/pull/5285) ([Vasu1105](https://github.com/Vasu1105))
+- Ignore unknown metadata fields in metadata.rb [\#5299](https://github.com/chef/chef/pull/5299) ([lamont-granquist](https://github.com/lamont-granquist))
+
+**Fixed Bugs:**
+
+- knife ssh: use the command line prompt for sudo if set [\#5427](https://github.com/chef/chef/pull/5427) ([lamont-granquist](https://github.com/lamont-granquist))
+- User provider: Fix manage\_home provider inconsistency for Mac and FreeBSD providers [\#5423](https://github.com/chef/chef/pull/5423) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix for "Chefspec template rendering fails when cookbook\_name != directory name" [\#5417](https://github.com/chef/chef/pull/5417) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix solaris handling for useradd -m/-M behavior [\#5408](https://github.com/chef/chef/pull/5408) ([coderanger](https://github.com/coderanger))
+- Normalize full key name to avoid resource update on identical key names [\#5290](https://github.com/chef/chef/pull/5290) ([bai](https://github.com/bai))
+- Add trailing newline to generated 15update-stamp [\#5382](https://github.com/chef/chef/pull/5382) ([pwalz](https://github.com/pwalz))
+- Invalid `dsc_scripts` should fail the run [\#5377](https://github.com/chef/chef/pull/5377) ([NimishaS](https://github.com/NimishaS))
+- Revert --local filter for gems installed from paths [\#5379](https://github.com/chef/chef/pull/5379) ([mwrock](https://github.com/mwrock))
+- Fix knife list\_commands\(\) [\#5386](https://github.com/chef/chef/pull/5386) ([lamont-granquist](https://github.com/lamont-granquist))
+- Don't use -r for users or groups on Solaris. [\#5355](https://github.com/chef/chef/pull/5355) ([coderanger](https://github.com/coderanger))
+- Chef 12 Attribute Regression [\#5360](https://github.com/chef/chef/pull/5360) ([gbagnoli](https://github.com/gbagnoli))
+- Handling Errno::ETIMEDOUT [\#5358](https://github.com/chef/chef/pull/5358) ([NimishaS](https://github.com/NimishaS))
+
+## [v12.14.89](https://github.com/chef/chef/tree/v12.14.89) (2016-09-22)
+[Full Changelog](https://github.com/chef/chef/compare/v12.14.77...v12.14.89)
+
+**Fixed Bugs:**
+
+- Revert "Verify systemd\_unit file during create" [\#5326](https://github.com/chef/chef/pull/5326) ([mwrock](https://github.com/mwrock))
+- Fix method\_access and array handling in node presenter [\#5351](https://github.com/chef/chef/pull/5351) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fixed undefined short\_cksum method issue and checksum in uppercase issue for windows\_package resource. [\#5332](https://github.com/chef/chef/pull/5332) ([Aliasgar16](https://github.com/Aliasgar16))
+- Fix makecache action name in yum\_repository [\#5348](https://github.com/chef/chef/pull/5348) ([tas50](https://github.com/tas50))
+
+## [v12.14.77](https://github.com/chef/chef/tree/v12.14.77) (2016-09-19)
+[Full Changelog](https://github.com/chef/chef/compare/v12.14.60...v12.14.77)
+
+**Fixed Bugs:**
+
+- Revert supports\[:manage\_home\] behavior [\#5322](https://github.com/chef/chef/pull/5322) ([lamont-granquist](https://github.com/lamont-granquist))
+- Preserve the extension of the file in the rendered tempfile in File providers [\#5327](https://github.com/chef/chef/pull/5327) ([lamont-granquist](https://github.com/lamont-granquist))
+- Allow the :delete action for yum\_repository + fix old property support [\#5320](https://github.com/chef/chef/pull/5320) ([tas50](https://github.com/tas50))
+
+## [v12.14.60](https://github.com/chef/chef/tree/v12.14.60) (2016-09-09)
+[Full Changelog](https://github.com/chef/chef/compare/v12.13.37...v12.14.60)
+
+**Enhancements:**
+
+- Only support Solaris 10u11 and newer [\#5264](https://github.com/chef/chef/pull/5264) ([rhass](https://github.com/rhass))
+- Added code to handle deletion of directories on Windows that are symlinks. [\#5234](https://github.com/chef/chef/pull/5234) ([Aliasgar16](https://github.com/Aliasgar16))
+- Readability improvements to options parsing code [\#5289](https://github.com/chef/chef/pull/5289) ([lamont-granquist](https://github.com/lamont-granquist))
+- Add Hash type to launchd:keep\_alive [\#5182](https://github.com/chef/chef/pull/5182) ([erikng](https://github.com/erikng))
+- Added timeout during removing of windows package [\#5250](https://github.com/chef/chef/pull/5250) ([dheerajd-msys](https://github.com/dheerajd-msys))
+- Bump openssl to 1.0.2h [\#5260](https://github.com/chef/chef/pull/5260) ([lamont-granquist](https://github.com/lamont-granquist))
+- Rewrite linux\_user provider check\_lock [\#5248](https://github.com/chef/chef/pull/5248) ([lamont-granquist](https://github.com/lamont-granquist))
+- Allow flagging a resource property as sensitive [\#5185](https://github.com/chef/chef/pull/5185) ([adamleff](https://github.com/adamleff))
+- Rewrite linux useradd provider [\#5243](https://github.com/chef/chef/pull/5243) ([lamont-granquist](https://github.com/lamont-granquist))
+- Add yum_repository resource from the yum cookbook [\#5187](https://github.com/chef/chef/pull/5187) ([thommay](https://github.com/thommay))
+- Verify systemd\_unit file during create [\#5210](https://github.com/chef/chef/pull/5210) ([mal](https://github.com/mal))
+- Add a warning for guard blocks that return a non-empty string [\#5233](https://github.com/chef/chef/pull/5233) ([coderanger](https://github.com/coderanger))
+- Forward package cookbook\_name to underlying remote\_file [\#5128](https://github.com/chef/chef/pull/5128) ([Annih](https://github.com/Annih))
+- Fix "URI.escape is obsolete" warnings [\#5230](https://github.com/chef/chef/pull/5230) ([jkeiser](https://github.com/jkeiser))
+- Remove ruby 2.1 support [\#5220](https://github.com/chef/chef/pull/5220) ([lamont-granquist](https://github.com/lamont-granquist))
+- User provider manage\_home behavior and refactor [\#5122](https://github.com/chef/chef/pull/5122) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix Style/BlockDelimiters, Style/MultilineBlockLayout and 0.42.0 engine upgrade [\#5218](https://github.com/chef/chef/pull/5218) ([lamont-granquist](https://github.com/lamont-granquist))
+- Switch from Ruby 2.1.9 to Ruby 2.3.1 [\#5190](https://github.com/chef/chef/pull/5190) ([jkeiser](https://github.com/jkeiser))
+- Update to latest chefstyle [\#5217](https://github.com/chef/chef/pull/5217) ([jkeiser](https://github.com/jkeiser))
+- Rubygems memory performance improvement [\#5203](https://github.com/chef/chef/pull/5203) ([lamont-granquist](https://github.com/lamont-granquist))
+- HTTP 1.1 keepalives for cookbook synchronization [\#5151](https://github.com/chef/chef/pull/5151) ([lamont-granquist](https://github.com/lamont-granquist))
+
+**Fixed Bugs:**
+
+- Fixes GH-4955, allowing local gems with remote dependencies [\#5098](https://github.com/chef/chef/pull/5098) ([jyaworski](https://github.com/jyaworski))
+- Hook up the recipe\_file\_loaded event which was defined but not actually called [\#5281](https://github.com/chef/chef/pull/5281) ([coderanger](https://github.com/coderanger))
+- fix gem\_package regression in master [\#5262](https://github.com/chef/chef/pull/5262) ([lamont-granquist](https://github.com/lamont-granquist))
+- Added fix for spaces in profile identifiers [\#5159](https://github.com/chef/chef/pull/5159) ([natewalck](https://github.com/natewalck))
+- Add a hook for compat\_resource [\#5259](https://github.com/chef/chef/pull/5259) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix flush\_cache issues in yum\_package [\#5258](https://github.com/chef/chef/pull/5258) ([jaymzh](https://github.com/jaymzh))
+- Use symbols instead of strings as keys for systemd user property [\#5241](https://github.com/chef/chef/pull/5241) ([joshuamiller01](https://github.com/joshuamiller01))
+- Use upstart goal state as service status [\#5249](https://github.com/chef/chef/pull/5249) ([evan2645](https://github.com/evan2645))
+- Fix the useradd test filters [\#5236](https://github.com/chef/chef/pull/5236) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix specify members of group on suse/openbsd/solaris2/hpux [\#5152](https://github.com/chef/chef/pull/5152) ([tas50](https://github.com/tas50))
+- Fix cookbook upload of symlinked cookbooks in Ruby 2.3 on Windows [\#5216](https://github.com/chef/chef/pull/5216) ([jkeiser](https://github.com/jkeiser))
+- Don't use relative\_path\_from on glob results [\#5215](https://github.com/chef/chef/pull/5215) ([jkeiser](https://github.com/jkeiser))
+
+## [v12.13.37](https://github.com/chef/chef/tree/v12.13.37) (2016-08-12)
+[Full Changelog](https://github.com/chef/chef/compare/v12.13.30...v12.13.37)
+
+**Enhancements:**
+
+- Bumping ohai and mixlib-log to fix regression [\#5197](https://github.com/chef/chef/pull/5197) ([mwrock](https://github.com/mwrock))
+- Remove requires in Chef::Recipe that are no longer necessary [\#5189](https://github.com/chef/chef/pull/5189) ([lamont-granquist](https://github.com/lamont-granquist))
+
+## [v12.13.30](https://github.com/chef/chef/tree/v12.13.30) (2016-08-05)
+[Full Changelog](https://github.com/chef/chef/compare/v12.12.15...v12.13.30)
+
+**Enhancements:**
+
+- noop apt_update similar to apt_repository [\#5173](https://github.com/chef/chef/pull/5173) ([lamont-granquist](https://github.com/lamont-granquist))
+- Bump dependencies to bring in Ohai 8.18 [\#5168](https://github.com/chef/chef/pull/5168) ([tas50](https://github.com/tas50))
+- Make Chef work with Ruby 2.3, update Ruby to 2.1.9 [\#5165](https://github.com/chef/chef/pull/5165) ([jkeiser](https://github.com/jkeiser))
+- Log cause chain for exceptions [\#3354](https://github.com/chef/chef/pull/3354) ([jaym](https://github.com/jaym))
+- First pass on --config-option handling. [\#5045](https://github.com/chef/chef/pull/5045) ([coderanger](https://github.com/coderanger))
+- Add bootstrap proxy authentication support. [\#4059](https://github.com/chef/chef/pull/4059) ([yossigo](https://github.com/yossigo))
+- Support setting an empty string for cron attrs [\#5127](https://github.com/chef/chef/pull/5127) ([thommay](https://github.com/thommay))
+- Also clear notifications when deleting a resource. [\#5146](https://github.com/chef/chef/pull/5146) ([coderanger](https://github.com/coderanger))
+- Clean up subscribes internals and notification storage. [\#5145](https://github.com/chef/chef/pull/5145) ([coderanger](https://github.com/coderanger))
+- Cache ChefFS children [\#5131](https://github.com/chef/chef/pull/5131) ([thommay](https://github.com/thommay))
+- Update to rspec 3.5 [\#5126](https://github.com/chef/chef/pull/5126) ([thommay](https://github.com/thommay))
+- Add `chef\_data\_bag\_item` to Cheffish DSL methods [\#5125](https://github.com/chef/chef/pull/5125) ([danielsdeleo](https://github.com/danielsdeleo))
+- replace glibc resolver with ruby resolver [\#5123](https://github.com/chef/chef/pull/5123) ([lamont-granquist](https://github.com/lamont-granquist))
+- The user must specify a category for a new cookbook [\#5091](https://github.com/chef/chef/pull/5091) ([thommay](https://github.com/thommay))
+- Warn if not installing an individual bff fileset [\#5093](https://github.com/chef/chef/pull/5093) ([mwrock](https://github.com/mwrock))
+- Use Mixlib::Archive to extract tarballs [\#5080](https://github.com/chef/chef/pull/5080) ([thommay](https://github.com/thommay))
+- Data Collector server URL validation, and disable on host down [\#5076](https://github.com/chef/chef/pull/5076) ([adamleff](https://github.com/adamleff))
+
+**Fixed Bugs:**
+
+- Don't log error for reporting audit data in when in chef-zero [\#5016](https://github.com/chef/chef/pull/5016) ([erichelgeson](https://github.com/erichelgeson))
+- Invalidate the file system cache on deletion [\#5154](https://github.com/chef/chef/pull/5154) ([thommay](https://github.com/thommay))
+- Root ACLs are a top level json file not a sub-directory [\#5155](https://github.com/chef/chef/pull/5155) ([thommay](https://github.com/thommay))
+- Install nokogiri and pin mixlib-cli [\#5118](https://github.com/chef/chef/pull/5118) ([ksubrama](https://github.com/ksubrama))
+- Ensure that the valid option is given back to the option parser [\#5114](https://github.com/chef/chef/pull/5114) ([dldinternet](https://github.com/dldinternet))
+- Fixed regex for zypper version 1.13.\*. [\#5109](https://github.com/chef/chef/pull/5109) ([yeoldegrove](https://github.com/yeoldegrove))
+- add back method\_missing support to set\_unless [\#5103](https://github.com/chef/chef/pull/5103) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix \#5094 node.default\_unless issue in 12.12.13 [\#5097](https://github.com/chef/chef/pull/5097) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix \#5078 using cwd parameter instead of Dir.pwd [\#5079](https://github.com/chef/chef/pull/5079) ([Tensibai](https://github.com/Tensibai))
+
+## [v12.12.15](https://github.com/chef/chef/tree/v12.12.15) (2016-07-08)
+[Full Changelog](https://github.com/chef/chef/compare/v12.12.13...v12.12.15)
+
+**Fixed Bugs:**
+
+- Fix for #5094 12.12.13 node.default_unless issue [\#5097](https://github.com/chef/chef/pull/5097) ([lamont-granquist](https://github.com/lamont-granquist))
+
+## [v12.12.13](https://github.com/chef/chef/tree/v12.12.13) (2016-07-01)
+[Full Changelog](https://github.com/chef/chef/compare/v12.11.18...v12.12.13)
+
+**Implemented Enhancements:**
+
+- Tweak 3694 warnings [\#5075](https://github.com/chef/chef/pull/5075) ([lamont-granquist](https://github.com/lamont-granquist))
+- Adding node object to Data collector run\_converge message [\#5065](https://github.com/chef/chef/pull/5065) ([adamleff](https://github.com/adamleff))
+- Attribute API improvements [\#5029](https://github.com/chef/chef/pull/5029) ([lamont-granquist](https://github.com/lamont-granquist))
+- Remove deprecated Thread.exclusive around require call. [\#5068](https://github.com/chef/chef/pull/5068) ([maxlazio](https://github.com/maxlazio))
+- Ensure that chef-solo uses the expected repo dir [\#5059](https://github.com/chef/chef/pull/5059) ([thommay](https://github.com/thommay))
+- Expand data\_collector resource list to include all resources [\#5058](https://github.com/chef/chef/pull/5058) ([adamleff](https://github.com/adamleff))
+- Turn off fips with an empty environment var [\#5048](https://github.com/chef/chef/pull/5048) ([mwrock](https://github.com/mwrock))
+- Deprecate knife-supermarket gem [\#4896](https://github.com/chef/chef/pull/4896) ([thommay](https://github.com/thommay))
+- Update Nokogiri [\#5042](https://github.com/chef/chef/pull/5042) ([mwrock](https://github.com/mwrock))
+- Remote resource should respect sensitive flag [\#5025](https://github.com/chef/chef/pull/5025) ([PrajaktaPurohit](https://github.com/PrajaktaPurohit))
+- Convert the 3694 warning to a deprecation so it will be subject to the usual deprecation formatting \(collected at the bottom, can be made an error, etc\). [\#5022](https://github.com/chef/chef/pull/5022) ([coderanger](https://github.com/coderanger))
+- Deprecate `knife cookbook create` in favor of `chef generate cookbook`. [\#5021](https://github.com/chef/chef/pull/5021) ([tylercloke](https://github.com/tylercloke))
+
+**Fixed Bugs:**
+
+- Fixes windows_package uninstall scenarios by calling uninstall string directly [\#5050](https://github.com/chef/chef/pull/5050) ([mwrock](https://github.com/mwrock))
+- Fix gem_package idempotency [\#5046](https://github.com/chef/chef/pull/5046) ([thommay](https://github.com/thommay))
+- Undefined local variable lookup in multiplexed_dir.rb [\#5027](https://github.com/chef/chef/issues/5027) ([robdimarco](https://github.com/robdimarco))
+- Correctly write out data collector metadata file [\#5019](https://github.com/chef/chef/pull/5019) ([adamleff](https://github.com/adamleff))
+- Eliminate missing constant errors for LWRP class [\#5000](https://github.com/chef/chef/pull/5000) ([PrajaktaPurohit](https://github.com/PrajaktaPurohit))
+- Updated_resource_count to data collector should only include updated resources [\#5006](https://github.com/chef/chef/pull/5006) ([adamleff](https://github.com/adamleff))
+- Don't mask directory deletion errors [\#4991](https://github.com/chef/chef/pull/4991) ([jaymzh](https://github.com/jaymzh))
+
+## [v12.11.18](https://github.com/chef/chef/tree/v12.11.18) (2016-06-02)
+[Full Changelog](https://github.com/chef/chef/compare/v12.11.17...v12.11.18)
+
+**Implemented Enhancements:**
+
+- Creation of the new DataCollector reporter [\#4973](https://github.com/chef/chef/pull/4973) ([adamleff](https://github.com/adamleff))
+- Add systemd\_unit try-restart, reload-or-restart, reload-or-try-restart actions [\#4908](https://github.com/chef/chef/pull/4908) ([nathwill](https://github.com/nathwill))
+- RFC062 exit status chef client [\#4611](https://github.com/chef/chef/pull/4611) ([smurawski](https://github.com/smurawski))
+- Create 'universal' DSL [\#4942](https://github.com/chef/chef/pull/4942) ([lamont-granquist](https://github.com/lamont-granquist))
+- Handle numeric id for the user value in the git resource [\#4902](https://github.com/chef/chef/pull/4902) ([MichaelPereira](https://github.com/MichaelPereira))
+- RFC 31 - Default solo to local mode [\#4919](https://github.com/chef/chef/pull/4919) ([thommay](https://github.com/thommay))
+- Wire up chef handlers directly from libraries [\#4933](https://github.com/chef/chef/pull/4933) ([lamont-granquist](https://github.com/lamont-granquist))
+- Reject malformed ini content in systemd\_unit resource [\#4907](https://github.com/chef/chef/pull/4907) ([nathwill](https://github.com/nathwill))
+- Update usage of @new\_resource.destination to `cwd` within the git hwrp [\#4898](https://github.com/chef/chef/pull/4898) ([joshburt](https://github.com/joshburt))
+- Support Ruby Files in ChefFS [\#4887](https://github.com/chef/chef/pull/4887) ([thommay](https://github.com/thommay))
+- Adds a system check for fips enablement and runs in fips mode if enabled [\#4880](https://github.com/chef/chef/pull/4880) ([mwrock](https://github.com/mwrock))
+- Lazy'ing candidate\_version in package provider [\#4869](https://github.com/chef/chef/pull/4869) ([lamont-granquist](https://github.com/lamont-granquist))
+- Add systemd\_unit resource [\#4700](https://github.com/chef/chef/pull/4700) ([nathwill](https://github.com/nathwill))
+- Bump chef-zero to avoid aggressive logging [\#4878](https://github.com/chef/chef/pull/4878) ([stevendanna](https://github.com/stevendanna))
+
+**Fixed Bugs:**
+
+- Fix \#4949 and Avoid Errno::EBUSY on docker containers [\#4979](https://github.com/chef/chef/pull/4979) ([andrewjamesbrown](https://github.com/andrewjamesbrown))
+- Ensure recipe-url works right in solo [\#4957](https://github.com/chef/chef/pull/4957) ([thommay](https://github.com/thommay))
+- Fix portage provider to support version with character [\#4966](https://github.com/chef/chef/pull/4966) ([crigor](https://github.com/crigor))
+- Fixes \#4968 and only retrieves the latest version of packages from chocolatey [\#4977](https://github.com/chef/chef/pull/4977) ([mwrock](https://github.com/mwrock))
+- Update contributing doc to better reflect reality [\#4962](https://github.com/chef/chef/pull/4962) ([tas50](https://github.com/tas50))
+- Load cookbook versions correctly for knife [\#4936](https://github.com/chef/chef/pull/4936) ([thommay](https://github.com/thommay))
+- Gem metadata command needs Gem.clear\_paths [\#4929](https://github.com/chef/chef/pull/4929) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix os x profile provider for nil [\#4921](https://github.com/chef/chef/pull/4921) ([achand](https://github.com/achand))
+- Cookbook site install : tar error on windows [\#4867](https://github.com/chef/chef/pull/4867) ([willoucom](https://github.com/willoucom))
+- Fix yum\_package breakage \(the =~ operator in ruby is awful\) [\#4912](https://github.com/chef/chef/pull/4912) ([lamont-granquist](https://github.com/lamont-granquist))
+- Encode registry enumerated values and keys to utf8 instead of the local codepage [\#4906](https://github.com/chef/chef/pull/4906) ([mwrock](https://github.com/mwrock))
+- Chocolatey Package Provider chomps nil object [\#4760](https://github.com/chef/chef/pull/4760) ([svmastersamurai](https://github.com/svmastersamurai))
+- Fixes knife ssl check on windows [\#4886](https://github.com/chef/chef/pull/4886) ([mwrock](https://github.com/mwrock))
+
+## [v12.10.24](https://github.com/chef/chef/tree/v12.10.24) (2016-04-27)
+[Full Changelog](https://github.com/chef/chef/compare/v12.10.23...v12.10.24)
+
+**Fixed Bugs:**
+
+- Removing non-existent members from group should not fail [\#4812](https://github.com/chef/chef/pull/4812) ([chefsalim](https://github.com/chefsalim))
+- The easy\_install provider and resource are deprecated and will be removed in Chef 13 [\#4860](https://github.com/chef/chef/pull/4860) ([coderanger](https://github.com/coderanger))
+
+**Tech cleanup:**
+
+- Refactor ChefFS files to be files [\#4837](https://github.com/chef/chef/pull/4837) ([thommay](https://github.com/thommay))
+- Rename and add backcompat requires for ChefFS dirs [\#4830](https://github.com/chef/chef/pull/4830) ([thommay](https://github.com/thommay))
+- Refactor ChefFS directories to be directories [\#4826](https://github.com/chef/chef/pull/4826) ([thommay](https://github.com/thommay))
+- Move all ChefFS exceptions into a single file [\#4822](https://github.com/chef/chef/pull/4822) ([thommay](https://github.com/thommay))
+
+**Enhancements:**
+
+- Add layout option support for device creation to mdadm resource provider [\#4855](https://github.com/chef/chef/pull/4855) ([kbruner](https://github.com/kbruner))
+- add notifying\_block and subcontext\_block to chef [\#4818](https://github.com/chef/chef/pull/4818) ([lamont-granquist](https://github.com/lamont-granquist))
+- modernize shell\_out method syntax [\#4865](https://github.com/chef/chef/pull/4865) ([lamont-granquist](https://github.com/lamont-granquist))
+- Update rubygems provider to support local install of gems if so specified [\#4847](https://github.com/chef/chef/pull/4847) ([PrajaktaPurohit](https://github.com/PrajaktaPurohit))
+- fix details in with\_run\_context [\#4839](https://github.com/chef/chef/pull/4839) ([lamont-granquist](https://github.com/lamont-granquist))
+- Lock dependencies of chef through a `Gemfile.lock` [\#4820](https://github.com/chef/chef/pull/4820) ([jkeiser](https://github.com/jkeiser))
+- add better resource manipulation API [\#4834](https://github.com/chef/chef/pull/4834) ([lamont-granquist](https://github.com/lamont-granquist))
+- add nillable apt\_repository and nillable properties [\#4832](https://github.com/chef/chef/pull/4832) ([lamont-granquist](https://github.com/lamont-granquist))
+
+## [v12.9](https://github.com/chef/chef/tree/v12.9.38) (2016-04-09)
+[Full Changelog](https://github.com/chef/chef/compare/v12.8.2...v12.9.38)
+
+**Implemented enhancements:**
+
+- Sftp remote file support [\#4750](https://github.com/chef/chef/pull/4750) ([jkerry](https://github.com/jkerry))
+- Setting init\_command should be accepted instead of specific command overrides [\#4709](https://github.com/chef/chef/pull/4709) ([coderanger](https://github.com/coderanger))
+- Add a NoOp provider [\#4798](https://github.com/chef/chef/pull/4798) ([thommay](https://github.com/thommay))
+- Add ability to notify from inside LWRP to wrapping resource\_collections [\#4017](https://github.com/chef/chef/issues/4017)
+- Notifications from LWRPS/sub-resources can trigger resources in outer run\_context scopes [\#4741](https://github.com/chef/chef/pull/4741) ([lamont-granquist](https://github.com/lamont-granquist))
+- Improve the docs generated by knife cookbook create [\#4757](https://github.com/chef/chef/pull/4757) ([tas50](https://github.com/tas50))
+- Need Config/CLI options to move interval+splay sleep to end of client loop [\#3305](https://github.com/chef/chef/issues/3305)
+- Add optional integer argument for --daemonize option [\#4759](https://github.com/chef/chef/pull/4759) ([jrunning](https://github.com/jrunning))
+- Add shorthand :syslog and :win\_evt for log\_location config [\#4751](https://github.com/chef/chef/pull/4751) ([jrunning](https://github.com/jrunning))
+
+**Fixed bugs:**
+
+- chef\_gem and gem metadata don't play well [\#4710](https://github.com/chef/chef/issues/4710)
+- Fix cookbook metadata 'gem' command to make it useful [\#4809](https://github.com/chef/chef/pull/4809) ([lamont-granquist](https://github.com/lamont-granquist))
+- Convert timeout config to integer [\#4787](https://github.com/chef/chef/pull/4787) ([chefsalim](https://github.com/chefsalim))
+- The mount resource is not idempotent on windows [\#3861](https://github.com/chef/chef/issues/3861)
+- fix for \#4715 - unset TMPDIR in homebrew package provider [\#4716](https://github.com/chef/chef/pull/4716) ([gips0n](https://github.com/gips0n))
+- tons of "Deprecation class overwrites LWRP resource" WARNING SPAM with chefspec [\#4668](https://github.com/chef/chef/issues/4668)
+
+**Merged pull requests:**
+
+- Add apt\_repository resource [\#4782](https://github.com/chef/chef/pull/4782) ([thommay](https://github.com/thommay))
+- Point to the right license file for chef. [\#4811](https://github.com/chef/chef/pull/4811) ([sersut](https://github.com/sersut))
+- add omnibus license metadata [\#4805](https://github.com/chef/chef/pull/4805) ([patrick-wright](https://github.com/patrick-wright))
+- Add default timeout [\#4804](https://github.com/chef/chef/pull/4804) ([chefsalim](https://github.com/chefsalim))
+- Spec break on Windows due to temp dir and short path names [\#4776](https://github.com/chef/chef/pull/4776) ([adamedx](https://github.com/adamedx))
+- Require chef/version since it's used here [\#4762](https://github.com/chef/chef/pull/4762) ([jkeiser](https://github.com/jkeiser))
+- remove pry from rbx build [\#4761](https://github.com/chef/chef/pull/4761) ([lamont-granquist](https://github.com/lamont-granquist))
+- ruby 2.0.0 is EOL [\#4752](https://github.com/chef/chef/pull/4752) ([lamont-granquist](https://github.com/lamont-granquist))
+- supresses parser gem errors [\#4755](https://github.com/chef/chef/pull/4755) ([lamont-granquist](https://github.com/lamont-granquist))
+- Set inherit=false on the fallback provider constant lookup. [\#4753](https://github.com/chef/chef/pull/4753) ([coderanger](https://github.com/coderanger))
+
+**Closed issues:**
+
+- Uploading an encrypted data bag to Chef server fails [\#4815](https://github.com/chef/chef/issues/4815)
+- powershell\_script does not have PSCredential capability [\#4589](https://github.com/chef/chef/issues/4589)
+- Documentation don't include how to setup mail server during deployment of Chef server [\#4807](https://github.com/chef/chef/issues/4807)
+- Resource 'mount' and chef 12.5.1 [\#4056](https://github.com/chef/chef/issues/4056)
+- Incorrect $TMPDIR environment variable on OS X [\#4715](https://github.com/chef/chef/issues/4715)
+- group provider on suse Linux adds user multiple times [\#4689](https://github.com/chef/chef/issues/4689)
+- Unexpected error when using "knife cookbook show ...." [\#4659](https://github.com/chef/chef/issues/4659)
+
+## [12.8.1](https://github.com/chef/chef/tree/12.8.1) (2016-03-07)
+[Full Changelog](https://github.com/chef/chef/compare/12.7.2...12.8.1)
+
+**Implemented enhancements:**
+
+- Clarify the probable cause of tempfile creation failure during cookbook sync [\#2171](https://github.com/chef/chef/issues/2171)
+- Remove static libraries from Chef package [\#4654](https://github.com/chef/chef/pull/4654) ([chefsalim](https://github.com/chefsalim))
+- Have client.rb verify that FIPS mode can be enforced [\#4630](https://github.com/chef/chef/pull/4630) ([ksubrama](https://github.com/ksubrama))
+- List all of the unignored files when loading a cookbook [\#4629](https://github.com/chef/chef/pull/4629) ([danielsdeleo](https://github.com/danielsdeleo))
+- adding pry and pry-byebug to dev dependencies [\#4601](https://github.com/chef/chef/pull/4601) ([mwrock](https://github.com/mwrock))
+- Split group members on commas [\#4583](https://github.com/chef/chef/pull/4583) ([thommay](https://github.com/thommay))
+- Make tempfiles easier to read \(prepend chef to the name\) [\#4582](https://github.com/chef/chef/pull/4582) ([thommay](https://github.com/thommay))
+- Extend cookbook shadowing deprecation warnings more broadly [\#4574](https://github.com/chef/chef/pull/4574) ([lamont-granquist](https://github.com/lamont-granquist))
+- tell knife's edit\_data what the object is [\#4548](https://github.com/chef/chef/pull/4548) ([thommay](https://github.com/thommay))
+- Implement knife bootstrap client.d RFC [\#4529](https://github.com/chef/chef/pull/4529) ([jaym](https://github.com/jaym))
+- Update to Log Level when showing unencrypted databag [\#4524](https://github.com/chef/chef/pull/4524) ([PatrickWalker](https://github.com/PatrickWalker))
+- RFC-060 gem metadata MVP [\#4478](https://github.com/chef/chef/pull/4478) ([lamont-granquist](https://github.com/lamont-granquist))
+- chef-client: add --\[no\]skip-cookbook-sync option [\#4316](https://github.com/chef/chef/pull/4316) ([josb](https://github.com/josb))
+- Extend service resource to support masking [\#4307](https://github.com/chef/chef/pull/4307) ([davide125](https://github.com/davide125))
+- launchd for osx [\#4111](https://github.com/chef/chef/pull/4111) ([mikedodge04](https://github.com/mikedodge04))
+
+**Fixed bugs:**
+
+- Chef::DataBagItem.to\_hash is modifying Chef::DataBagItem.raw\_data [\#4614](https://github.com/chef/chef/issues/4614)
+- Chef 12 seeing a ton of these in debug mode [\#2396](https://github.com/chef/chef/issues/2396)
+- Data bag item hash can have name key [\#4664](https://github.com/chef/chef/pull/4664) ([chefsalim](https://github.com/chefsalim))
+- Clearer exception for loading non-existent data bag items in solo mode. [\#4655](https://github.com/chef/chef/pull/4655) ([coderanger](https://github.com/coderanger))
+- Always rehash from gem source and not existing hash file [\#4651](https://github.com/chef/chef/pull/4651) ([tyler-ball](https://github.com/tyler-ball))
+- Handle negative content length headers too. [\#4646](https://github.com/chef/chef/pull/4646) ([coderanger](https://github.com/coderanger))
+- if no module name is found for a valid dsc resource default to PSDesiredStateConfiguration [\#4638](https://github.com/chef/chef/pull/4638) ([mwrock](https://github.com/mwrock))
+- removing disabling of readline in chef-shell [\#4635](https://github.com/chef/chef/pull/4635) ([mwrock](https://github.com/mwrock))
+- Fix a bug that was causing DataBagItem.to\_hash to mutate the data bag item [\#4631](https://github.com/chef/chef/pull/4631) ([itmustbejj](https://github.com/itmustbejj))
+- ensure paths maintain utf-8ness in non ascii encodings [\#4626](https://github.com/chef/chef/pull/4626) ([mwrock](https://github.com/mwrock))
+- Fix the Chocolatey-missing error again [\#4621](https://github.com/chef/chef/pull/4621) ([randomcamel](https://github.com/randomcamel))
+- fixes exe package downloads [\#4612](https://github.com/chef/chef/pull/4612) ([mwrock](https://github.com/mwrock))
+- fallback to netmsg.dll error table if error message is not found in system errors [\#4600](https://github.com/chef/chef/pull/4600) ([mwrock](https://github.com/mwrock))
+- zypper multipackage performance fix [\#4591](https://github.com/chef/chef/pull/4591) ([lamont-granquist](https://github.com/lamont-granquist))
+- bugfix \#2865 check for validation\_key [\#4581](https://github.com/chef/chef/pull/4581) ([thommay](https://github.com/thommay))
+- remove bogus recalculation of cookbook upload failures [\#4580](https://github.com/chef/chef/pull/4580) ([thommay](https://github.com/thommay))
+- Make sure we have a valid object before calling close! [\#4579](https://github.com/chef/chef/pull/4579) ([thommay](https://github.com/thommay))
+- Fix policyfile\_zero provisioner in 12.7 [\#4571](https://github.com/chef/chef/pull/4571) ([andy-dufour](https://github.com/andy-dufour))
+- do not include source parameter when removing a chocolatey package and ensure source is used on all functional tests [\#4570](https://github.com/chef/chef/pull/4570) ([mwrock](https://github.com/mwrock))
+- Fix databag globbing issues for chef-solo on windows [\#4569](https://github.com/chef/chef/pull/4569) ([jaym](https://github.com/jaym))
+- remove Chef::Mixin::Command use [\#4566](https://github.com/chef/chef/pull/4566) ([lamont-granquist](https://github.com/lamont-granquist))
+
+## 12.7.2
+
+* [pr#4559](https://github.com/chef/chef/pull/4559) Remove learnchef acceptance tests until we make them more reliable
+* [pr#4545](https://github.com/chef/chef/pull/4545) Removing rm -rf in chef-solo recipe_url
+
+## 12.7.1
+* [**Daniel Steen**](https://github.com/dansteen)
+ * [pr#3183](https://github.com/chef/chef/pull/3183) Provide more helpful error message when accidentally using --secret instead of --secret-file
+
+* [pr#4532](https://github.com/chef/chef/pull/4532) Bump Bundler + Rubygems
+* [pr#4550](https://github.com/chef/chef/pull/4550) Use a streaming request to download cookbook
+
+## 12.7.0
+
+* [**Nate Walck**](https://github.com/natewalck)
+ * [pr#4078](https://github.com/chef/chef/pull/4078) Add `osx_profile` resource for OS X
+* [**Timothy Cyrus**](https://github.com/tcyrus)
+ * [pr#4420](https://github.com/chef/chef/pull/4420) Update code climate badge and code climate blocks in README.md
+* [**Jordan Running**](https://github.com/jrunning)
+ * [pr#4399](https://github.com/chef/chef/pull/4399) Correctly save policy_name and policy_group with `knife node edit`
+* [**Brian Goad**](https://github.com/bbbco)
+ * [pr#4315](https://github.com/chef/chef/pull/4315) Add extra tests around whether to skip with multiple guards
+
+* [pr#4516](https://github.com/chef/chef/pull/4516) Return propper error messages when using windows based `mount`, `user` and `group` resources
+* [pr#4500](https://github.com/chef/chef/pull/4500) Explicitly declare directory permissions of chef install on windows to restrict rights on Windows client versions
+* [pr#4498](https://github.com/chef/chef/pull/4498) Correct major and minor OS versions for Windows 10 and add versions for Windows 2016 Server
+* [pr#4375](https://github.com/chef/chef/pull/4375) No longer try to auto discover package version of `exe` based windows packages
+* [pr#4369](https://github.com/chef/chef/pull/4396) Import omnibus-chef chef project definition and history
+* [pr#4399](https://github.com/chef/chef/pull/4399) Correctly save `policy_name` and `policy_group` with `knife node edit`
+* [pr#4278](https://github.com/chef/chef/pull/4278) make file resource use properties
+* [pr#4479](https://github.com/chef/chef/pull/4479) Remove incorrect cookbook artifact normalization
+* [pr#4470](https://github.com/chef/chef/pull/4470) Fix sh spacing issues
+* [pr#4434](https://github.com/chef/chef/pull/4434) adds EOFError message to handlers
+* [pr#4422](https://github.com/chef/chef/pull/4422) Add an apt_update resource
+* [pr#4287](https://github.com/chef/chef/pull/4287) Default Chef with FIPS OpenSSL to use sign v1.3
+* [pr#4461](https://github.com/chef/chef/pull/4461) debian-6 is EOL next month
+* [pr#4460](https://github.com/chef/chef/pull/4460) Set range of system user/group id to max of 200
+* [pr#4231](https://github.com/chef/chef/pull/4231) zypper multipackage patch
+* [pr#4459](https://github.com/chef/chef/pull/4459) use require_paths and not path so bundler grabs all paths from a git reference
+* [pr#4450](https://github.com/chef/chef/pull/4450) don't warn about ambiguous property usage
+* [pr#4445](https://github.com/chef/chef/pull/4445) Add CBGB to the repository
+* [pr#4423](https://github.com/chef/chef/pull/4423) Add deprecation warnings to Chef::REST and all json_creates
+* [pr#4439](https://github.com/chef/chef/pull/4439) Sometimes chocolately doesn't appear on the path
+* [pr#4432](https://github.com/chef/chef/pull/4432) add get_rest etc calls to ServerAPI
+* [pr#4435](https://github.com/chef/chef/pull/4435) add nokogiri to omnibus-chef
+* [pr#4419](https://github.com/chef/chef/pull/4419) explicitly adding .bat to service executable called by service in case users remove .bat from PATHEXT
+* [pr#4413](https://github.com/chef/chef/pull/4413) configure chef client windows service to the correct chef directory
+* [pr#4377](https://github.com/chef/chef/pull/4377) fixing candidate filtering and adding functional tests for chocolatey_package
+* [pr#4406](https://github.com/chef/chef/pull/4406) Updating to the latest release of net-ssh to consume https://github.com/net-ssh/net-ssh/pull/280
+* [pr#4405](https://github.com/chef/chef/pull/4405) ServerAPI will return a raw hash, so do that
+* [pr#4400](https://github.com/chef/chef/pull/4400) inflate an environment after loading it
+* [pr#4396](https://github.com/chef/chef/pull/4396) Remove duplicate initialization of @password in user_v1
+* [pr#4344](https://github.com/chef/chef/pull/4344) Warn (v. info) when reloading resources
+* [pr#4369](https://github.com/chef/chef/pull/4369) Migrate omnibus-chef project/software definitions for chef in here
+* [pr#4106](https://github.com/chef/chef/pull/4106) add chocolatey_package to core chef
+* [pr#4321](https://github.com/chef/chef/pull/4321) fix run_as_user of windows_service
+* [pr#4333](https://github.com/chef/chef/pull/4333) no longer wait on node search to refresh vault but pass created ApiCient instead
+* [pr#4325](https://github.com/chef/chef/pull/4325) Pin win32-eventlog to 0.6.3 to avoid clashing CreateEvent definition
+* [pr#4312](https://github.com/chef/chef/pull/4312) Updates the template to use omnitruck-direct.chef.io
+* [pr#4277](https://github.com/chef/chef/pull/4277) non msi packages must explicitly provide a source attribute on install
+* [pr#4309](https://github.com/chef/chef/pull/4309) tags always an array; fix set_unless
+* [pr#4278](https://github.com/chef/chef/pull/4278) make file resource use properties
+* [pr#4288](https://github.com/chef/chef/pull/4288) Fix no_proxy setting in chef-config
+* [pr#4273](https://github.com/chef/chef/pull/4273) Use signing protocol 1.1 by default
+* [pr#4520](https://github.com/chef/chef/pull/4520) Fix a few `dsc_resource` bugs
+
+## 12.6.0
* [**Dave Eddy**](https://github.com/bahamas10)
[pr#3187](https://github.com/chef/chef/pull/3187) overhaul solaris SMF service provider
* [**Mikhail Zholobov**](https://github.com/legal90)
- [pr#3192](https://github.com/chef/chef/pull/3192) provider/user/dscl: Set default gid to 20
-* [**Mikhail Zholobov**](https://github.com/legal90)
- [pr#3193](https://github.com/chef/chef/pull/3193) provider/user/dscl: Set "comment" default value
+ - [pr#3192](https://github.com/chef/chef/pull/3192) provider/user/dscl: Set default gid to 20
+ - [pr#3193](https://github.com/chef/chef/pull/3193) provider/user/dscl: Set "comment" default value
* [**Jordan Evans**](https://github.com/jordane)
- [pr#3263](https://github.com/chef/chef/pull/3263) `value_for_platform` should use `Chef::VersionConstraint::Platform`
+ - [pr#3263](https://github.com/chef/chef/pull/3263) `value_for_platform` should use `Chef::VersionConstraint::Platform`
+ - [pr#3633](https://github.com/chef/chef/pull/3633) add the word group to `converge_by` call for group provider
* [**Scott McGillivray**](https://github.com/thechile)
[pr#3450](https://github.com/chef/chef/pull/3450) Fix 'knife cookbook show' to work on root files
* [**Aubrey Holland**](https://github.com/aub)
@@ -18,24 +493,47 @@
* [**Michael Pereira**](https://github.com/MichaelPereira)
[pr#3968](https://github.com/chef/chef/pull/3968) Fix cookbook installation from supermarket on windows
* [**Yukihiko SAWANOBORI**](https://github.com/sawanoboly)
- [pr#3941](https://github.com/chef/chef/pull/3941) allow reboot by reboot resource with chef-apply
+ - [pr#3941](https://github.com/chef/chef/pull/3941) allow reboot by reboot resource with chef-apply
+ - [pr#3900](https://github.com/chef/chef/pull/3900) Add new option json attributes file to bootstraping
* [**permyakovsv**](https://github.com/permyakovsv)
[pr#3901](https://github.com/chef/chef/pull/3901) Add tmux-split parameter to knife ssh
-* [**Yukihiko SAWANOBORI**](https://github.com/sawanoboly)
- [pr#3900](https://github.com/chef/chef/pull/3900) Add new option json attributes file to bootstraping
* [**Evan Gilman**](https://github.com/evan2645)
[pr#3864](https://github.com/chef/chef/pull/3864) Knife `bootstrap_environment` should use Explicit config before Implicit
* [**Ranjib Dey**](https://github.com/ranjib)
[pr#3834](https://github.com/chef/chef/pull/3834) Dont spit out stdout and stderr for execute resource failure, if its declared sensitive
* [**Jeff Blaine**](https://github.com/jblaine)
- [pr#3776](https://github.com/chef/chef/pull/3776) Changes --hide-healthy to --hide-by-mins MINS
+ - [pr#3776](https://github.com/chef/chef/pull/3776) Changes --hide-healthy to --hide-by-mins MINS
+ - [pr#3848](https://github.com/chef/chef/pull/3848) Migrate to --ssh-identity-file instead of --identity-file
* [**dbresson**](https://github.com/dbresson)
[pr#3650](https://github.com/chef/chef/pull/3650) Define == for node objects
-* [**Jordan Evans**](https://github.com/jordane)
- [pr#3633](https://github.com/chef/chef/pull/3633) add the word group to `converge_by` call for group provider
* [**Patrick Connolly**](https://github.com/patcon)
[pr#3529](https://github.com/chef/chef/pull/3529) Allow user@hostname format for knife-bootstrap
+* [**Justin Seubert**](https://github.com/dude051)
+ [pr#4160](https://github.com/chef/chef/pull/4160) Correcting regex for upstart_state
+* [**Sarah Michaelson**](https://github.com/skmichaelson)
+ [pr#3810](https://github.com/chef/chef/pull/3810) GH-1909 Add validation for chef_server_url
+* [**Maxime Brugidou**](https://github.com/brugidou)
+ [pr#4052](https://github.com/chef/chef/pull/4052) Add make_child_entry in ChefFS CookbookSubdir
+* [**Nathan Williams**](https://github.com/nathwill)
+ [pr#3836](https://github.com/chef/chef/pull/3836) simplify service helpers
+* [**Paul Welch**](https://github.com/pwelch)
+ [pr#4066](https://github.com/chef/chef/pull/4066) Fix chef-apply usage banner
+* [**Mat Schaffer**](https://github.com/matschaffer)
+ [pr#4153](https://github.com/chef/chef/pull/4153) Require ShellOut before Knife::SSH definition
+* [**Donald Guy**](https://github.com/donaldguy)
+ [pr#4158](https://github.com/chef/chef/pull/4158) Allow named_run_list to be loaded from config
+* [**Jos Backus**](https://github.com/josb)
+ [pr#4064](https://github.com/chef/chef/pull/4064) Ensure that tags are properly initialized
+* [**John Bellone**](https://github.com/johnbellone)
+ [pr#4101](https://github.com/chef/chef/pull/4101) Adds alias method upgrade_package for solaris package
+* [**Nolan Davidson**](https://github.com/nsdavidson)
+ [pr#4014](https://github.com/chef/chef/pull/4014) Adding ksh resource
+* [pr#4193](https://github.com/chef/chef/pull/4196) support for inno, nsis, wise and installshield installer types in windows_package resource
+* [pr#4196](https://github.com/chef/chef/pull/4196) multipackage dpkg_package and bonus fixes
+* [pr#4185](https://github.com/chef/chef/pull/4185) dpkg provider cleanup
+* [pr#4165](https://github.com/chef/chef/pull/4165) Multipackage internal API improvements
+* [pr#4081](https://github.com/chef/chef/pull/4081) RFC-037: add `chef_version` and `ohai_version` metadata
* [pr#3530](https://github.com/chef/chef/pull/3530) Allow using --sudo option with user's home folder in knife bootstrap
* [pr#3858](https://github.com/chef/chef/pull/3858) Remove duplicate 'Accept' header in spec
* [pr#3911](https://github.com/chef/chef/pull/3911) Avoid subclassing Struct.new
@@ -46,12 +544,28 @@
* [pr#4021](https://github.com/chef/chef/pull/4021) add missing requires for Chef::DSL::Recipe to LWRPBase
* [pr#3597](https://github.com/chef/chef/pull/3597) print STDOUT from the powershell_script
* [pr#4091](https://github.com/chef/chef/pull/4091) Allow downloading of root_files in a chef repository
-
-## 12.5.1
-
-* [**Ranjib Dey**](https://github.com/ranjib):
- [pr#3588](https://github.com/chef/chef/pull/3588) Count skipped resources among total resources in doc formatter
-
+* [pr#4112](https://github.com/chef/chef/pull/4112) Update knife bootstrap command to honor --no-color flag in chef-client run that is part of the bootstrap process.
+* [pr#4090](https://github.com/chef/chef/pull/4090) Improve detection of ChefFS-based commands in `knife rehash`
+* [pr#3991](https://github.com/chef/chef/pull/3991) Modify remote_file cache_control_data to use sha256 for its name
+* [pr#4079](https://github.com/chef/chef/pull/4079) add logger to windows service shellout
+* [pr#3966](https://github.com/chef/chef/pull/3966) Report expanded run list json tree to reporting
+* [pr#4080](https://github.com/chef/chef/pull/4080) Make property modules possible
+* [pr#4069](https://github.com/chef/chef/pull/4069) Improvements to log messages
+* [pr#4049](https://github.com/chef/chef/pull/4049) Add gemspec files to allow bundler to run from the gem
+* [pr#4029](https://github.com/chef/chef/pull/4029) Fix search result pagination
+* [pr#4048](https://github.com/chef/chef/pull/4048) Accept coercion as a way to accept nil values
+* [pr#4046](https://github.com/chef/chef/pull/4046) ignore gid in the user resource on windows
+* [pr#4118](https://github.com/chef/chef/pull/4118) Make Property.derive create derived properties of the same type
+* [pr#4133](https://github.com/chef/chef/pull/4133) Add retries to `Chef::HTTP` for transient SSL errors
+* [pr#4135](https://github.com/chef/chef/pull/4135) Windows service uses log file location from config if none is given on commandline
+* [pr#4142](https://github.com/chef/chef/pull/4142) Use the proper python interpretor for yum-dump.py on Fedora 21
+* [pr#4149](https://github.com/chef/chef/pull/4149) Handle nil run list option in knife bootstrap
+* [pr#4040](https://github.com/chef/chef/pull/4040) Implement live streaming for execute resources
+* [pr#4167](https://github.com/chef/chef/pull/4167) Add `reboot_action` to `dsc_resource`
+* [pr#4167](https://github.com/chef/chef/pull/4167) Allow `dsc_resource` to run with the LCM enabled
+* [pr#4188](https://github.com/chef/chef/pull/4188) Update `dsc_resource` to use verbose stream output
+* [pr#4200](https://github.com/chef/chef/pull/4200) Prevent inspect of PsCredential from printing out plain text password
+* [pr#4237](https://github.com/chef/chef/pull/4237) Enabling 'knife ssl check/fetch' commands to respect proxy environment variables and moving proxy environment variables export to Chef::Config
## 12.5.1
* [**Ranjib Dey**](https://github.com/ranjib):
@@ -300,7 +814,7 @@ of partial templates.
Typo fixes
* [**Tim Smith**](https://github.com/tas50)
Typo fixes
-* [Pull 2505](https://github.com/opscode/chef/pull/2505) Make Chef handle URIs in a case-insensitive manner
+* [Pull 2505](https://github.com/chef/chef/pull/2505) Make Chef handle URIs in a case-insensitive manner
* [**Phil Dibowitz**](https://github.com/jaymzh):
Drop SSL warnings now that we have a safe default
* [Pull 2684](https://github.com/chef/chef/pull/2684) Remove ole_initialize/uninitialize which cause problems with Ruby >= 2
@@ -386,32 +900,32 @@ of partial templates.
## 12.0.3
* [**Phil Dibowitz**](https://github.com/jaymzh):
-[Issue 2594](https://github.com/opscode/chef/issues/2594) Restore missing require in `digester`.
+[Issue 2594](https://github.com/chef/chef/issues/2594) Restore missing require in `digester`.
## 12.0.2
-* [Issue 2578](https://github.com/opscode/chef/issues/2578) Check that `installed` is not empty for `keg_only` formula in Homebrew provider
-* [Issue 2609](https://github.com/opscode/chef/issues/2609) Resolve the circular dependency between ProviderResolver and Resource.
-* [Issue 2596](https://github.com/opscode/chef/issues/2596) Fix nodes not writing to disk
-* [Issue 2580](https://github.com/opscode/chef/issues/2580) Make sure the relative paths are preserved when using link resource.
-* [Pull 2630](https://github.com/opscode/chef/pull/2630) Improve knife's SSL error messaging
-* [Issue 2606](https://github.com/opscode/chef/issues/2606) chef 12 ignores default_release for apt_package
-* [Issue 2602](https://github.com/opscode/chef/issues/2602) Fix `subscribes` resource notifications.
-* [Issue 2578](https://github.com/opscode/chef/issues/2578) Check that `installed` is not empty for `keg_only` formula in Homebrew provider.
+* [Issue 2578](https://github.com/chef/chef/issues/2578) Check that `installed` is not empty for `keg_only` formula in Homebrew provider
+* [Issue 2609](https://github.com/chef/chef/issues/2609) Resolve the circular dependency between ProviderResolver and Resource.
+* [Issue 2596](https://github.com/chef/chef/issues/2596) Fix nodes not writing to disk
+* [Issue 2580](https://github.com/chef/chef/issues/2580) Make sure the relative paths are preserved when using link resource.
+* [Pull 2630](https://github.com/chef/chef/pull/2630) Improve knife's SSL error messaging
+* [Issue 2606](https://github.com/chef/chef/issues/2606) chef 12 ignores default_release for apt_package
+* [Issue 2602](https://github.com/chef/chef/issues/2602) Fix `subscribes` resource notifications.
+* [Issue 2578](https://github.com/chef/chef/issues/2578) Check that `installed` is not empty for `keg_only` formula in Homebrew provider.
* [**gh2k**](https://github.com/gh2k):
- [Issue 2625](https://github.com/opscode/chef/issues/2625) Fix missing `shell_out!` for `windows_package` resource
+ [Issue 2625](https://github.com/chef/chef/issues/2625) Fix missing `shell_out!` for `windows_package` resource
* [**BackSlasher**](https://github.com/BackSlasher):
- [Issue 2634](https://github.com/opscode/chef/issues/2634) Fix `option ':command' is not a valid option` error in subversion provider.
+ [Issue 2634](https://github.com/chef/chef/issues/2634) Fix `option ':command' is not a valid option` error in subversion provider.
* [**Seth Vargo**](https://github.com/sethvargo):
- [Issue 2345](https://github.com/opscode/chef/issues/2345) Allow knife to install cookbooks with metadata.json.
+ [Issue 2345](https://github.com/chef/chef/issues/2345) Allow knife to install cookbooks with metadata.json.
## 12.0.1
-* [Issue 2552](https://github.com/opscode/chef/issues/2552) Create constant for LWRP before calling `provides`
-* [Issue 2545](https://github.com/opscode/chef/issues/2545) `path` attribute of `execute` resource is restored to provide backwards compatibility with Chef 11.
-* [Issue 2565](https://github.com/opscode/chef/issues/2565) Fix `Chef::Knife::Core::BootstrapContext` constructor for knife-windows compat.
-* [Issue 2566](https://github.com/opscode/chef/issues/2566) Make sure Client doesn't raise error when interval is set on Windows.
-* [Issue 2560](https://github.com/opscode/chef/issues/2560) Fix `uninitialized constant Windows::Constants` in `windows_eventlog`.
-* [Issue 2563](https://github.com/opscode/chef/issues/2563) Make sure the Chef Client rpm packages are signed with GPG keys correctly.
+* [Issue 2552](https://github.com/chef/chef/issues/2552) Create constant for LWRP before calling `provides`
+* [Issue 2545](https://github.com/chef/chef/issues/2545) `path` attribute of `execute` resource is restored to provide backwards compatibility with Chef 11.
+* [Issue 2565](https://github.com/chef/chef/issues/2565) Fix `Chef::Knife::Core::BootstrapContext` constructor for knife-windows compat.
+* [Issue 2566](https://github.com/chef/chef/issues/2566) Make sure Client doesn't raise error when interval is set on Windows.
+* [Issue 2560](https://github.com/chef/chef/issues/2560) Fix `uninitialized constant Windows::Constants` in `windows_eventlog`.
+* [Issue 2563](https://github.com/chef/chef/issues/2563) Make sure the Chef Client rpm packages are signed with GPG keys correctly.
## 12.0.0
@@ -524,7 +1038,7 @@ of partial templates.
* [**Ionuț Arțăriși**](https://github.com/mapleoin):
Changed the default group provider to gpasswd on SLES versions 12 and higher.
* [**Noah Kantrowitz**](https://github.com/coderanger):
- Implemented [RFC017 - File Specificity Overhaul](https://github.com/opscode/chef-rfc/blob/master/rfc017-file-specificity.md).
+ Implemented [RFC017 - File Specificity Overhaul](https://github.com/chef/chef-rfc/blob/master/rfc017-file-specificity.md).
* [**James Bence**](https://github.com/jbence):
Improved the reliability of Git provider by making it to be more specific when selecting tags.
* [**Jean Mertz**](https://github.com/JeanMertz):
@@ -562,7 +1076,7 @@ of partial templates.
### Chef Contributions
* ruby 1.9.3 support is dropped
-* Added RFC-023 Chef 12 Attribute Changes (https://github.com/opscode/chef-rfc/blob/master/rfc023-chef-12-attributes-changes.md)
+* Added RFC-023 Chef 12 Attribute Changes (https://github.com/chef/chef-rfc/blob/master/rfc023-chef-12-attributes-changes.md)
* Added os/platform_family options to provides syntax on the Chef::Resource DSL
* Added provides methods to the Chef::Provider DSL
* Added supported?(resource, action) class method to all Providers for late-evaluation if a provider can handle a
@@ -817,3 +1331,5 @@ of partial templates.
* Raise error if a guard_interpreter is specified and a block is passed to a guard (conditional)
* Allow specifying a guard_interpreter after a conditional on a resource (Fixes #1943)
* Windows package type should be a symbol (Fixes #1997)
+
+\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b2f9ece975..1f197360f5 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,208 +1,151 @@
-# Contributing to Chef
+# Contributing to Chef Projects
-We are glad you want to contribute to Chef!
+We're glad you want to contribute to a Chef project! This document will help answer common questions you may have during your first contribution.
-We utilize **Github Issues** for issue tracking and contributions. You can contribute in two ways:
+## Submitting Issues
-1. Reporting an issue or making a feature request [here](#issues).
-2. Adding features or fixing bugs yourself and contributing your code to Chef.
+Not every contribution comes in the form of code. Submitting, confirming, and triaging issues is an important task for any project. At Chef we use Github to track all project issues.
-## Contribution Process
-
-We have a 3 step process that utilizes **Github Issues**:
-
-1. Sign or be added to an existing [Contributor License Agreement (CLA)](https://supermarket.chef.io/become-a-contributor).
-2. Create a Github Pull Request.
-3. Do [Code Review](#cr) with the **Chef Engineering Team** or **Chef Core Committers** on the pull request.
-
-### <a name="pulls"></a> Chef Pull Requests
+If you are familiar with Chef and know the component, that is causing you a problem, you can file an issue in the corresponding Github project. All of our Open Source Software can be found in our [Github organization](https://github.com/chef/). All projects include Github issue templates to help gather information needed for a thorough review.
-Chef is built to last. We strive to ensure high quality throughout the Chef experience. In order to ensure
- this, we require a couple of things for all pull requests to Chef:
+We ask you not to submit security concerns via Github. For details on submitting potential security issues please see <https://www.chef.io/security/>
-1. **Tests:** To ensure high quality code and protect against future regressions, we require all the
- code in Chef to have at least unit test coverage. See the [spec/unit](https://github.com/chef/chef/tree/master/spec/unit)
- directory for the existing tests and use ```bundle exec rake spec``` to run them.
-2. **Green Travis Run:** We use [Travis CI](https://travis-ci.org/) in order to run our tests
- continuously on all the pull requests. We require the Travis runs to succeed on every pull
- request before being merged.
+In addition to Github issues, we also utilize a feedback site that helps our product team track and rank feature requests. If you have a feature request, this is an excellent place to start <https://feedback.chef.io>
-In addition to this it would be nice to include the description of the problem you are solving
- with your change. You can use [Chef Issue Template](#issuetemplate) in the description section
- of the pull request.
+## Contribution Process
-### <a name="cr"></a> Chef Code Review Process
+We have a 3 step process for contributions:
-The Chef Code Review process happens on Github pull requests. See
- [this article](https://help.github.com/articles/using-pull-requests) if you're not
- familiar with Github Pull Requests.
+1. Commit changes to a git branch, making sure to sign-off those changes for the [Developer Certificate of Origin](#developer-certification-of-origin-dco).
+2. Create a Github Pull Request for your change, following the instructions in the pull request template.
+3. Perform a [Code Review](#code-review-process) with the project maintainers on the pull request.
-Once you a pull request, the **Chef Engineering Team** or **Chef Core Committers** will review your code
- and respond to you with any feedback they might have. The process at this point is as follows:
+### Pull Request Requirements
-1. 2 thumbs-ups are required from the **Chef Engineering Team** or **Chef Core Committers** for all merges.
-2. When ready, your pull request will be tagged with label `Ready For Merge`.
-3. Your patch will be merged into `master` including necessary documentation updates
- and you will be included in `CHANGELOG.md`. Our goal is to have patches merged in 2 weeks
- after they are marked to be merged.
+Chef Projects are built to last. We strive to ensure high quality throughout the experience. In order to ensure this, we require that all pull requests to Chef projects meet these specifications:
-If you would like to learn about when your code will be available in a release of Chef, read more about
- [Chef Release Process](#release).
+1. **Tests:** To ensure high quality code and protect against future regressions, we require all the code in Chef Projects to have at least unit test coverage. We use [RSpec](http://rspec.info/) for unit testing.
+2. **Green CI Tests:** We use [Travis CI](https://travis-ci.org/) and/or [AppVeyor](https://www.appveyor.com/) CI systems to test all pull requests. We require these test runs to succeed on every pull request before being merged.
-### <a name="oh"></a> Developer Office Hours
+### Code Review Process
-We hold regular "office hours" on Google Hangouts On-The-Air that you can join to review contributions together,
-ask questions about contributing, or just hang out with Chef Software employees. The regularly scheduled Chef hangouts occur on Mondays and Wednesdays at 3pm Eastern / Noon Pacific.
+Code review takes place in Github pull requests. See [this article](https://help.github.com/articles/about-pull-requests/) if you're not familiar with Github Pull Requests.
-The link to join the Hangout or watch it live is usually tweeted from [@ChefOfficeHours](https://twitter.com/ChefOfficeHours)
-and posted in the #chef IRC channel on irc.freenode.net when the hangout is about to start.
+Once you open a pull request, project maintainers will review your code and respond to your pull request with any feedback they might have. The process at this point is as follows:
-You can watch the recordings of the old Code Review hangouts on the [opscodebtm](http://www.youtube.com/opscodebtm) youtube account.
+1. Two thumbs-up (:+1:) are required from project maintainers. See the master maintainers document for Chef projects at <https://github.com/chef/chef/blob/master/MAINTAINERS.md>.
+2. When ready, your pull request will be tagged with label `Ready For Merge`.
+3. Your change will be merged into the project's `master` branch and will be noted in the project's `CHANGELOG.md` at the time of release.
-### Contributor License Agreement (CLA)
-Licensing is very important to open source projects. It helps ensure the
- software continues to be available under the terms that the author desired.
+If you would like to learn about when your code will be available in a release of Chef, read more about [Chef Release Cycles](#release-cycles).
-Chef uses [the Apache 2.0 license](https://github.com/chef/chef/blob/master/LICENSE)
- to strike a balance between open contribution and allowing you to use the
- software however you would like to.
+### Developer Certification of Origin (DCO)
-The license tells you what rights you have that are provided by the copyright holder.
- It is important that the contributor fully understands what rights they are
- licensing and agrees to them. Sometimes the copyright holder isn't the contributor,
- such as when the contributor is doing work for a company.
+Licensing is very important to open source projects. It helps ensure the software continues to be available under the terms that the author desired.
-To make a good faith effort to ensure these criteria are met, Chef requires an Individual CLA
- or a Corporate CLA for contributions. This agreement helps ensure you are aware of the
- terms of the license you are contributing your copyrighted works under, which helps to
- prevent the inclusion of works in the projects that the contributor does not hold the rights
- to share.
+Chef uses [the Apache 2.0 license](https://github.com/chef/chef/blob/master/LICENSE) to strike a balance between open contribution and allowing you to use the software however you would like to.
-It only takes a few minutes to complete a CLA, and you retain the copyright to your contribution.
+The license tells you what rights you have that are provided by the copyright holder. It is important that the contributor fully understands what rights they are licensing and agrees to them. Sometimes the copyright holder isn't the contributor, such as when the contributor is doing work on behalf of a company.
-You can complete our
- [Individual CLA](https://supermarket.chef.io/icla-signatures/new) online.
- If you're contributing on behalf of your employer and they retain the copyright for your works,
- have your employer fill out our
- [Corporate CLA](https://supermarket.chef.io/ccla-signatures/new) instead.
+To make a good faith effort to ensure these criteria are met, Chef requires the Developer Certificate of Origin (DCO) process to be followed.
-### Chef Obvious Fix Policy
+The DCO is an attestation attached to every contribution made by every developer. In the commit message of the contribution, the developer simply adds a Signed-off-by statement and thereby agrees to the DCO, which you can find below or at <http://developercertificate.org/>.
-Small contributions such as fixing spelling errors, where the content is small enough
- to not be considered intellectual property, can be submitted by a contributor as a patch,
- without a CLA.
+```
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the
+ best of my knowledge, is covered under an appropriate open
+ source license and I have the right under that license to
+ submit that work with modifications, whether created in whole
+ or in part by me, under the same open source license (unless
+ I am permitted to submit under a different license), as
+ Indicated in the file; or
+
+(c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+(d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including
+ all personal information I submit with it, including my
+ sign-off) is maintained indefinitely and may be redistributed
+ consistent with this project or the open source license(s)
+ involved.
+```
-As a rule of thumb, changes are obvious fixes if they do not introduce any new functionality
- or creative thinking. As long as the change does not affect functionality, some likely
- examples include the following:
+For more information on the change see the Chef Blog post [Introducing Developer Certificate of Origin](https://blog.chef.io/2016/09/19/introducing-developer-certificate-of-origin/)
-* Spelling / grammar fixes
-* Typo correction, white space and formatting changes
-* Comment clean up
-* Bug fixes that change default return values or error codes stored in constants
-* Adding logging messages or debugging output
-* Changes to ‘metadata’ files like Gemfile, .gitignore, build scripts, etc.
-* Moving source files from one directory or package to another
+#### DCO Sign-Off Methods
-**Whenever you invoke the “obvious fix” rule, please say so in your commit message:**
+The DCO requires a sign-off message in the following format appear on each commit in the pull request:
```
-------------------------------------------------------------------------
-commit 370adb3f82d55d912b0cf9c1d1e99b132a8ed3b5
-Author: danielsdeleo <dan@chef.io>
-Date: Wed Sep 18 11:44:40 2013 -0700
-
- Fix typo in config file docs.
-
- Obvious fix.
-
-------------------------------------------------------------------------
+Signed-off-by: Julia Child <juliachild@chef.io>
```
-## <a name="issues"></a> Chef Issue Tracking
+The DCO text can either be manually added to your commit body, or you can add either **-s** or **--signoff** to your usual git commit commands. If you forget to add the sign-off you can also amend a previous commit with the sign-off by running **git commit –-amend -s**. If you've pushed your changes to Github already you'll need to force push your branch after this with **git push -f**.
-Chef Issue Tracking is handled using Github Issues.
+### Chef Obvious Fix Policy
-If you are familiar with Chef and know the component that is causing you a problem or if you
- have a feature request on a specific component you can file an issue in the corresponding
- Github project. All of our Open Source Software can be found in our
- [Github organization](https://github.com/chef/).
+Small contributions, such as fixing spelling errors, where the content is small enough to not be considered intellectual property, can be submitted without signing the contribution for the DCO.
-There is also a listing of the various Chef products and where to file issues that can be
- found in the Chef docs in the [community contributions section](https://docs.chef.io/community_contributions.html#issues-and-bug-reports).
+As a rule of thumb, changes are obvious fixes if they do not introduce any new functionality or creative thinking. Assuming the change does not affect functionality, some common obvious fix examples include the following:
-Otherwise you can file your issue in the [Chef project](https://github.com/chef/chef/issues)
- and we will make sure it gets filed against the appropriate project.
+- Spelling / grammar fixes
+- Typo correction, white space and formatting changes
+- Comment clean up
+- Bug fixes that change default return values or error codes stored in constants
+- Adding logging messages or debugging output
+- Changes to 'metadata' files like Gemfile, .gitignore, build scripts, etc.
+- Moving source files from one directory or package to another
-In order to decrease the back and forth in issues, and to help us get to the bottom of them quickly
- we use the below issue template. You can copy/paste this template into the issue you are opening and
- edit it accordingly.
+**Whenever you invoke the "obvious fix" rule, please say so in your commit message:**
-<a name="issuetemplate"></a>
```
-### Version:
-[Version of the project installed]
-
-### Environment: [Details about the environment such as the Operating System, cookbook details, etc...]
-
-### Scenario:
-[What you are trying to achieve and you can't?]
+------------------------------------------------------------------------
+commit 370adb3f82d55d912b0cf9c1d1e99b132a8ed3b5
+Author: Julia Child <juliachild@chef.io>
+Date: Wed Sep 18 11:44:40 2015 -0700
-### Steps to Reproduce:
-[If you are filing an issue what are the things we need to do in order to repro your problem?]
+ Fix typo in the README.
-### Expected Result:
-[What are you expecting to happen as the consequence of above reproduction steps?]
+ Obvious fix.
-### Actual Result:
-[What actually happens after the reproduction steps?]
+------------------------------------------------------------------------
```
-### Useful Github Queries
-
-Contributions go through a review process to improve code quality and avoid regressions. Managing a large number of contributions requires a workflow to provide queues for work such as triage, code review, and merging. A semi-formal process has evolved over the life of the project. Chef maintains this process pending community development and acceptance of an [RFC](https://github.com/chef/chef-rfc). These queries will help track contributions through this process:
-
-* [Issues that are not assigned to a team](https://github.com/chef/chef/issues?q=is%3Aopen+-label%3AAIX+-label%3ABSD+-label%3Awindows+-label%3A%22Chef+Core%22++-label%3A%22Dev+Tools%22+-label%3AUbuntu+-label%3A%22Enterprise+Linux%22+-label%3A%22Ready+For+Merge%22+-label%3AMac+-label%3ASolaris+)
-* [Untriaged Issues](https://github.com/chef/chef/issues?q=is%3Aopen+is%3Aissue+-label%3ABug+-label%3AEnhancement+-label%3A%22Tech+Cleanup%22+-label%3A%22Ready+For+Merge%22)
-* [PRs to be Reviewed](https://github.com/chef/chef/labels/Pending%20Maintainer%20Review)
-* [Suitable for First Contribution](https://github.com/chef/chef/labels/Easy)
-
-## <a name="release"></a> Chef Release Cycles
-
-Our primary shipping vehicle is operating system specific packages that includes
- all the requirements of Chef. We call these [Omnibus packages](https://github.com/chef/omnibus)
+## Release Cycles
-We also release our software as gems to [Rubygems](https://rubygems.org/) but we strongly
- recommend using Chef packages since they are the only combination of native libraries &
- gems required by Chef that we test throughly.
+Our primary shipping vehicle is operating system specific packages that includes all the requirements of Chef. We call these [Omnibus packages](https://github.com/chef/omnibus)
-Our version numbering closely follows [Semantic Versioning](http://semver.org/) standard. Our
- standard version numbers look like X.Y.Z which mean:
+We also release our software as gems to [Rubygems](https://rubygems.org/) but we strongly recommend using Chef packages since they are the only combination of native libraries & gems required by Chef that we test throughly.
-* X is a major release, which may not be fully compatible with prior major releases
-* Y is a minor release, which adds both new features and bug fixes
-* Z is a patch release, which adds just bug fixes
+Our version numbering roughly follows [Semantic Versioning](http://semver.org/) standard. Our standard version numbers look like X.Y.Z which mean:
-We frequently make `alpha` and `beta` releases with version numbers that look like
- `X.Y.Z.alpha.0` or `X.Y.Z.beta.1`. These releases are still well tested but not as
- throughly as **Minor** or **Patch** releases.
+- X is a major release, which may not be fully compatible with prior major releases
+- Y is a minor release, which adds both new features and bug fixes
+- Z is a patch release, which adds just bug fixes
-We do a `Minor` release approximately every 3 months and `Patch` releases on a when-needed
- basis for regressions, significant bugs, and security issues.
+After shipping a release of Chef we bump the `Minor` version by one to start development of the next minor release. All merges to master trigger an increment of the `Patch` version, and a build through our internal testing pipeline. We do a `Minor` release approximately every month, which consist of shipping one of the already auto-incremented and tested `Patch` versions. For example after shiping 12.10.24, we incremented Chef to 12.11.0\. From there 18 commits where merged bringing the version to 12.11.18, which we shipped as an omnibus package.
-Announcements of releases are available on [Chef Blog](http://www.chef.io/blog) when they are
- available.
+Announcements of releases are made to the [chef mailing list](https://discourse.chef.io/c/chef-release) when they are available.
## Chef Community
-Chef is made possible by a strong community of developers and system administrators. If you have
- any questions or if you would like to get involved in the Chef community you can check out:
+Chef is made possible by a strong community of developers and system administrators. If you have any questions or if you would like to get involved in the Chef community you can check out:
-* [chef](http://lists.opscode.com/sympa/info/chef) and [chef-dev](http://lists.opscode.com/sympa/info/chef-dev) mailing lists
-* [\#chef](https://botbot.me/freenode/chef) and [\#chef-hacking](https://botbot.me/freenode/chef-hacking) IRC channels on irc.freenode.net
+- [Chef Mailing List](https://discourse.chef.io/)
+- [Chef Community Slack](https://community-slack.chef.io/)
Also here are some additional pointers to some awesome Chef content:
-* [Chef Docs](https://docs.chef.io/)
-* [Learn Chef](https://learn.chef.io/)
-* [Chef Inc](https://www.chef.io/)
+- [Chef Docs](https://docs.chef.io/)
+- [Learn Chef](https://learn.chef.io/)
+- [Chef Website](https://www.chef.io/)
diff --git a/DOC_CHANGES.md b/DOC_CHANGES.md
deleted file mode 100644
index 0b467f2570..0000000000
--- a/DOC_CHANGES.md
+++ /dev/null
@@ -1,460 +0,0 @@
-<!---
-This file is reset every time a new release is done. This file describes changes that have not yet been released.
-
-Example Doc Change:
-### Headline for the required change
-Description of the required change.
--->
-
-### client.rb named run list setting
-
-Policyfiles allow for multiple named run lists to be specified. To use
-them in chef-client, one can either specify them on the command line
-with:
-
-```
-chef-client --named-run-list NAME
-```
-
-or use the short option:
-
-```
-chef-client -n NAME
-```
-
-or specify the named run list in client.rb:
-
-```ruby
-named_run_list "NAME"
-```
-
-NOTE: ChefDK has supported named run lists in policyfiles for a few
-releases, but is affected by a bug where named run lists can be deleted
-from a Policyfile.lock.json during the upload. The fix will likely be
-included in ChefDK 0.8.0. See: https://github.com/chef/chef-dk/pull/520
-
-### client.rb policyfile settings
-
-Chef client can be configured to run in policyfile mode by setting
-`policy_name` and `policy_group` in client.rb. In order to use
-policyfiles, _both_ settings should be set. Example:
-
-```ruby
-policy_name "appserver"
-policy_group "staging"
-```
-
-As of Chef Client 12.5, when used in conjunction with Chef Server 12.3,
-these settings can instead be set directly on the node object. Setting
-them via the node JSON as described below will result in Chef Client
-creating the node object with these settings.
-
-### `chef-client -j JSON`
-
-Chef client node JSON can now be used to specify the policyfile settings
-`policy_name` and `policy_group`, like so:
-
-```json
-{
- "policy_name": "appserver",
- "policy_group": "staging"
-}
-```
-
-Doing so will cause `chef-client` to switch to policyfile mode
-automatically (i.e., the `use_policy` flag in `client.rb` is not
-required).
-
-Users who wish to take advantage of this functionality should upgrade
-the Chef Server to at least 12.3, which is the first Chef Server release
-capable of storing `policy_name` and `policy_group` in the node data.
-
-### PSCredential Support for `dsc_script`
-
-`dsc_script` now supports the use of `ps_credential` to create a PSCredential
-object similar to `dsc_resource`. The `ps_credential` helper function takes in
-a string and when `to_s` is called on it, produces an object that can be embedded
-in your `dsc_script`. For example, you can write:
-
-```ruby
-dsc_script 'create-foo-user' do
- code <<-EOH
- User FooUser
- {
- UserName = 'FooUser'
- Password = #{ps_credential('FooBarBaz1!')}
- }
- EOH
- configuration_data <<-EOH
- @{
- AllNodes = @(
- @{
- NodeName = "localhost";
- CertificateID = 'A8DB81D8059F349F7EF19104399B898F701D4167'
- }
- )
- }
- EOH
-end
-```
-
-Note, you still need to configure the CertificateID in the LCM.
-
-### chef-client -j JSON
-Add to the [description of chef-client options](https://docs.chef.io/ctl_chef_client.html#options):
-
-> This option can also be used to set a node's `chef_environment`. For example,
-running `chef-client -j /path/to/file.json` where `/path/to/file.json` is
-similar to:
-```
-{
- "chef_environment": "pre-production"
-}
-```
-will set the node's environment to `"pre-production"`.
-
-> *Note that the environment specified by `chef_environment` in your JSON will
-take precedence over an environment specified by `-E ENVIROMENT` when both options
-are provided.*
-
-### Resources Made Easy
-
-Resources are central to Chef. The system is extensible so that you can write
-your own reusable resources, and use them in your recipes, and even publish them
-so that others can use them too!
-
-However, writing these resources has not been as easy as we would have liked. In
-Chef 12.5, we are fixing this with a large number of DSL improvements designed
-to reduce the number of things you need to type and think about when you create
-a resource. Resources should be your go-to solution for many Chef problems, and
-these changes make them easy enough to dash off in an instant, while retaining
-all the power you're accustomed to.
-
-The process to create a resource is now:
-
-1. Make a resource file in your cookbook (like `resources/my_resource.rb`).
-2. Add the recipes defining your actions using the `action :create <recipe>` DSL.
-3. Add properties so the user can tweak some knobs on your resource (like paths,
- or preferences), using the `property :my_property, <type>, <options>` DSL.
-4. Use the resource in your recipe!
-
-There are other things you can do, but this is the most basic (and the first)
-thing you will start with.
-
-Let's demonstrate the new features by taking a simple recipe from the awesome
-[learnchef tutorial](https://learn.chef.io/learn-the-basics/rhel/configure-a-package-and-service/),
-and turning it into a reusable resource:
-
-```ruby
-package 'httpd'
-
-service 'httpd' do
- action [:enable, :start]
-end
-
-file '/var/www/html/index.html' do
- content '<html>
- <body>
- <h1>hello world</h1>
- </body>
-</html>'
-end
-
-service 'iptables' do
- action :stop
-end
-```
-
-We'll design a resource that lets you write this recipe instead:
-
-```ruby
-single_page_website 'mysite' do
- homepage '<html>
- <body>
- <h1>hello world</h1>
- </body>
- </html>'
-end
-```
-
-#### Declaring the Resource
-
-The first thing we do is declare the resource. We can do that by creating an
-empty file, `resources/single_page_website.rb`, in our cookbook.
-
-When you do this, the `single_page_website` resource will work in all recipes!
-
-```ruby
-single_page_website 'mysite'
-```
-
-It won't do anything yet, though :)
-
-#### Declaring an Action
-
-Let's make our resource do something. To start with, we'll just have it do exactly
-what the learnchef tutorial does, but in the resource. Put this in
-`resources/single_page_website.rb`:
-
-```ruby
-action :create do
- package 'httpd'
-
- service 'httpd' do
- action [:enable, :start]
- end
-
- file '/var/www/html/index.html' do
- content '<html>
- <body>
- <h1>hello world</h1>
- </body>
- </html>'
- end
-
- service 'iptables' do
- action :stop
- end
-end
-```
-
-Now, your simple recipe can use this resource to do what learnchef did:
-
-```ruby
-single_page_website 'mysite'
-```
-
-We've got ourselves an httpd!
-
-You will notice the only thing we've done is to add `action :create` around the
-recipe. The `action` keyword lets you declare a recipe inline, which will be
-executed when the user uses your resource in a recipe.
-
-#### Declaring a resource property: "homepage"
-
-This isn't super reusable yet--you might want your webpage to say something other
-than "hello world". Let's add a couple of properties for that, by putting this
-at the top of `resources/single_page_website`, and modifying the recipe to use
-"title" and "body":
-
-```ruby
-property :homepage, String, default: '<h1>hello world</h1>'
-
-action :create do
- package 'httpd'
-
- service 'httpd' do
- action [:enable, :start]
- end
-
- file '/var/www/html/index.html' do
- content homepage
- end
-
- service 'iptables' do
- action :stop
- end
-end
-```
-
-Now you can run this recipe:
-
-```ruby
-single_page_website 'mysite' do
- homepage '<h1>My own page</h1>'
-end
-```
-
-And you've got a website with your stuff!
-
-What you've done here is add *properties*. Properties are the *desired state* of
-a resource, in this case, `homepage` defines the text on the website. When you
-add a property, you're letting a user give it whatever value they want.
-
-When you define a property, there are three bits:
-`property :<name>, <type>, <options>`. *Name* defines the name of the property,
-so that people can set the property using `name <value>` when they use your
-resource. *Type* defines the type of the property: for example, String, Integer
-and Array are all possible types. Type is optional. *Options* define a large
-number of validation and other options. You've seen `default` already now,
-but there are a ton of others.
-
-#### Adding another property: "not_found_page"
-
-What if we want a custom 404 page for when people try to go to other pages in
-our website? Let's add one more property, to make this even nicer:
-
-```ruby
-property :homepage, String, default: '<h1>hello world</h1>'
-property :not_found_page, String, default: '<h1>No such page! Sorry. 404.</h1>'
-
-action :create do
- package 'httpd'
-
- service 'httpd' do
- action [:enable, :start]
- end
-
- file '/var/www/html/index.html' do
- content homepage
- end
-
- # These together tell Apache to use your custom 404 page:
- file '/var/www/html/404.html' do
- content not_found_page
- end
- file '/var/www/html/.htaccess' do
- content 'ErrorDocument 404 /404.html'
- end
-
- service 'iptables' do
- action :stop
- end
-end
-```
-
-Now you can run this recipe:
-
-```ruby
-single_page_website 'mysite' do
- homepage '<h1>My own page</h1>'
- not_found_page '<h1>Grr. Page not found. Sorry. (404)</h1>'
-end
-```
-
-#### Adding another action: "stop"
-
-What if we want to stop the website? Just add another action into the bottom of
-`resources/single_page_website.rb`:
-
-```ruby
-action :stop do
- service 'httpd' do
- action :stop
- end
-end
-```
-
-This action looks a lot like the other.
-
-There are a ton of other things you can do to create resources, but this should
-give you a pretty basic idea.
-
-### Advanced Resource Capabilities
-
-#### Ruby Developers: Resources as Classes
-
-If you are a Ruby developer, we've made it easier to create a Resource outside
-of a cookbook (or in a library) by declaring a class! Declare
-`class SinglePageWebsite < Chef::Resource` and put the entire resource
-declaration inside, and the `single_page_website` resource will work!
-
-#### Reading the current value: load_current_value
-
-There is a pitfall inherent in a resource, where users will sometimes omit a
-property from a resource, and become surprised when the system overwrites it
-with the default! For example, if your website already exists, this recipe
-will replace the *homepage* with "hello world":
-
-```ruby
-single_page_website 'mysite' do
- not_found_page '<h1>nice</h1>'
-end
-```
-
-It's not at all clear that that's what the user wanted--they didn't say anything
-about the homepage, so why did something happen to it?
-
-To guard against this, you can implement `load_current_value` in your resource.
-Put this in `resources/single_page_website.rb`:
-
-```ruby
-load_current_value do
- if File.exist?('/var/www/html/index.html')
- homepage IO.read('/var/www/html/index.html')
- end
- if File.exist?('/var/www/html/404.html')
- not_found_page IO.read('/var/www/html/404.html')
- end
-end
-```
-
-Now, the above recipe knows what the current homepage is, and will not change it!
-
-This capability is also used for several other things, including reporting (to
-describe what changed) and pure Ruby actions.
-
-#### Pure Ruby Actions
-
-Some resources need to talk directly to Ruby to do their dirty work, rather than using other resources. In those cases, you need to:
-
-- Make the updates only if the user specified properties that *need* to change.
-- Make sure and call updates if the resource does not exist (need to be created).
-- Print useful green text if the update is happening.
-- Not actually make any changes in why-run mode!
-
-`converge_if_changed` handles all of the above by comparing the user's desired
-property values against the *current* value as loaded by `load_current_value`.
-Simply wrap the part of your recipe that does a set in `converge_if_changed`.
-As an example, here is a basic `my_file` resource that creates a file with the
-given content:
-
-```ruby
-# resources/my_file.rb
-property :path, String, name_property: true
-property :content, String
-
-load_current_value do
- if File.exist?(path)
- content IO.read(path)
- end
-end
-
-action :create do
- converge_if_changed do
- IO.write(path, content)
- end
-end
-```
-
-The above code will only call `IO.write` if the file does not exist, or if the
-user specified content that is different from what is on disk. It will print out
-something like this, showing the changes:
-
-```ruby
-Recipe: basic_chef_client::block
- * my_file[blah] action create
- - update my_file[blah]
- - set content to "hola mundo" (was "hello world")
- ```
-
-##### Handling Multiple Operations
-
-If you have two separate, expensive operations to handle converge, `converge_if_changed`
-can be called multiple times with multiple properties. Adding `mode` to `my_file`
-demonstrates this:
-
-```ruby
-# resources/my_file.rb
-property :path, String, name_property: true
-property :content, String
-property :mode, String
-
-load_current_value do
- if File.exist?(path)
- content IO.read(path)
- mode File.stat(path).mode
- end
-end
-
-action :create do
- # Only change content here
- converge_if_changed :content do
- IO.write(path, content)
- end
- # Only change mode here
- converge_if_changed :mode do
- File.chmod(mode, path)
- end
-end
-```
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000..cf1f1a64dd
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,11 @@
+FROM busybox
+MAINTAINER Chef Software, Inc. <docker@chef.io>
+
+ARG CHANNEL=stable
+ARG VERSION=12.19.36
+
+RUN wget "http://packages.chef.io/files/${CHANNEL}/chef/${VERSION}/el/5/chef-${VERSION}-1.el5.x86_64.rpm" -O /tmp/chef-client.rpm && \
+ rpm2cpio /tmp/chef-client.rpm | cpio -idmv && \
+ rm -rf /tmp/chef-client.rpm
+
+VOLUME [ "/opt/chef" ]
diff --git a/Gemfile b/Gemfile
index 1bc5c79675..b3fa6b01a3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,9 +1,50 @@
+# This buys us the ability to be included in other Gemfiles
+require_relative "tasks/gemfile_util"
+extend GemfileUtil
+
source "https://rubygems.org"
-gemspec :name => "chef"
-gem "activesupport", "< 4.0.0", :group => :compat_testing, :platform => "ruby"
+# Note we do not use the gemspec DSL which restricts to the
+# gemspec for the current platform and filters out other platforms
+# during a bundle lock operation. We actually want dependencies from
+# both of our gemspecs. Also note this this mimics gemspec behavior
+# of bundler versions prior to 1.12.0 (https://github.com/bundler/bundler/commit/193a14fe5e0d56294c7b370a0e59f93b2c216eed)
+gem "chef", path: "."
+
+gem "chef-config", path: File.expand_path("../chef-config", __FILE__) if File.exist?(File.expand_path("../chef-config", __FILE__))
+gem "rake"
+gem "bundler"
+gem "cheffish" # required for rspec tests
+
+group(:omnibus_package) do
+ gem "appbundler"
+ gem "rb-readline"
+ gem "nokogiri"
+end
+
+group(:omnibus_package, :pry) do
+ gem "pry"
+ gem "pry-byebug"
+ gem "pry-remote"
+ gem "pry-stack_explorer"
+end
+
+# These are used for external tests
+group(:integration) do
+ gem "chef-provisioning"
+ gem "chef-sugar"
+ gem "chefspec"
+ gem "halite"
+ gem "poise"
+ gem "poise-boiler"
+ gem "knife-windows"
+ gem "foodcritic"
-gem 'chef-config', path: "chef-config" if File.exists?(__FILE__ + '../chef-config')
+ # We pin this so nobody brings in a cucumber-core incompatible with cucumber latest
+ gem "cucumber", ">= 2.4.0"
+ # We pin oc-chef-pedant to prevent it from updating out of lockstep with chef-zero
+ gem "oc-chef-pedant", git: "https://github.com/chef/chef-server"
+end
group(:docgen) do
gem "yard"
@@ -17,32 +58,38 @@ group(:maintenance) do
gem "netrc"
end
-group(:development, :test) do
- # for profiling
+# Everything except AIX
+group(:linux, :bsd, :mac_os_x, :solaris, :windows) do
+ # may need to disable this in insolation on fussy builds like AIX, RHEL4, etc
gem "ruby-prof"
+end
+
+# Everything except AIX and Windows
+group(:linux, :bsd, :mac_os_x, :solaris) do
+ gem "ruby-shadow", platforms: :ruby
+end
+group(:development, :test) do
gem "simplecov"
- gem 'rack', "~> 1.5.1"
+ # for testing new chefstyle rules
+ # gem 'chefstyle', github: 'chef/chefstyle'
+ gem "chefstyle", git: "https://github.com/chef/chefstyle.git", branch: "master"
+end
- gem 'ruby-shadow', :platforms => :ruby unless RUBY_PLATFORM.downcase.match(/(aix|cygwin)/)
+group(:changelog) do
+ gem "github_changelog_generator", git: "https://github.com/chef/github-changelog-generator"
+ gem "mixlib-install"
+end
- # For external tests
-# gem 'chef-zero', github: 'chef/chef-zero'
-# gem 'cheffish', github: 'chef/cheffish'
-# gem 'chef-provisioning'#, github: 'chef/chef-provisioning'
-# gem 'chef-provisioning-aws', github: 'chef/chef-provisioning-aws'
-# gem 'test-kitchen'
-# gem 'chefspec'
-# gem 'chef-sugar'
-# gem 'poise', github: 'poise/poise', branch: 'deeecb890a6a0bc2037dfb09ce0fd0a8931519aa'
-# gem 'halite', github: 'poise/halite'
-# gem 'foodcritic', github: 'acrmp/foodcritic', branch: 'v5.0.0'
-# gem 'chef-rewind'
+group(:travis) do
+ # See `bundler-audit` in .travis.yml
+ gem "bundler-audit", git: "https://github.com/rubysec/bundler-audit.git"
+ gem "travis"
end
-instance_eval(ENV['GEMFILE_MOD']) if ENV['GEMFILE_MOD']
+instance_eval(ENV["GEMFILE_MOD"]) if ENV["GEMFILE_MOD"]
# If you want to load debugging tools into the bundle exec sandbox,
# add these additional dependencies into chef/Gemfile.local
-eval(IO.read(__FILE__ + '.local'), binding) if File.exists?(__FILE__ + '.local')
+eval(IO.read(__FILE__ + ".local"), binding) if File.exist?(__FILE__ + ".local")
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000000..e712ef3f51
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,593 @@
+GIT
+ remote: https://github.com/chef/chef-server
+ revision: 53b28425d56005a92b0e3bb153f95b505168354a
+ specs:
+ oc-chef-pedant (2.2.0)
+ activesupport (>= 4.2.7.1, < 6.0)
+ erubis (~> 2.7)
+ mixlib-authentication (~> 1.4)
+ mixlib-config (~> 2.0)
+ mixlib-shellout (>= 1.1)
+ net-http-spy (~> 0.2)
+ rest-client (>= 1.6)
+ rspec (~> 3.2)
+ rspec-rerun (~> 1.0)
+ rspec_junit_formatter (~> 0.2)
+
+GIT
+ remote: https://github.com/chef/chefstyle.git
+ revision: 7e47afd6141d3c44a11322916e3fc85c89aa9b59
+ branch: master
+ specs:
+ chefstyle (0.5.0)
+ rubocop (= 0.47.1)
+
+GIT
+ remote: https://github.com/chef/github-changelog-generator
+ revision: 7ab4953b47598dccf10e106058673c1592b8f9bf
+ specs:
+ github_changelog_generator (1.14.2)
+ activesupport
+ faraday-http-cache
+ multi_json
+ octokit (~> 4.6)
+ rainbow (>= 2.1)
+ rake (>= 10.0)
+ retriable (>= 1.4)
+
+GIT
+ remote: https://github.com/rubysec/bundler-audit.git
+ revision: 6eb5a81e9b184fbb8db03f3e57dc758c65dd7383
+ specs:
+ bundler-audit (0.5.0)
+ bundler (~> 1.2)
+ thor (~> 0.18)
+
+PATH
+ remote: .
+ specs:
+ chef (12.19.39)
+ addressable
+ bundler (>= 1.10)
+ chef-config (= 12.19.39)
+ chef-zero (>= 4.8)
+ diff-lcs (~> 1.2, >= 1.2.4)
+ erubis (~> 2.7)
+ ffi-yajl (~> 2.2)
+ highline (~> 1.6, >= 1.6.9)
+ iniparse (~> 1.4)
+ mixlib-archive (~> 0.4)
+ mixlib-authentication (~> 1.4)
+ mixlib-cli (~> 1.7)
+ mixlib-log (~> 1.3)
+ mixlib-shellout (~> 2.0)
+ net-sftp (~> 2.1, >= 2.1.2)
+ net-ssh (>= 2.9, < 5.0)
+ net-ssh-multi (~> 1.2, >= 1.2.1)
+ ohai (>= 8.6.0.alpha.1, < 13)
+ plist (~> 3.2)
+ proxifier (~> 1.0)
+ rspec-core (~> 3.5)
+ rspec-expectations (~> 3.5)
+ rspec-mocks (~> 3.5)
+ rspec_junit_formatter (~> 0.2.0)
+ serverspec (~> 2.7)
+ specinfra (~> 2.10)
+ syslog-logger (~> 1.6)
+ uuidtools (~> 2.1.5)
+ chef (12.19.39-universal-mingw32)
+ addressable
+ bundler (>= 1.10)
+ chef-config (= 12.19.39)
+ chef-zero (>= 4.8)
+ diff-lcs (~> 1.2, >= 1.2.4)
+ erubis (~> 2.7)
+ ffi (~> 1.9)
+ ffi-yajl (~> 2.2)
+ highline (~> 1.6, >= 1.6.9)
+ iniparse (~> 1.4)
+ mixlib-archive (~> 0.4)
+ mixlib-authentication (~> 1.4)
+ mixlib-cli (~> 1.7)
+ mixlib-log (~> 1.3)
+ mixlib-shellout (~> 2.0)
+ net-sftp (~> 2.1, >= 2.1.2)
+ net-ssh (>= 2.9, < 5.0)
+ net-ssh-multi (~> 1.2, >= 1.2.1)
+ ohai (>= 8.6.0.alpha.1, < 13)
+ plist (~> 3.2)
+ proxifier (~> 1.0)
+ rspec-core (~> 3.5)
+ rspec-expectations (~> 3.5)
+ rspec-mocks (~> 3.5)
+ rspec_junit_formatter (~> 0.2.0)
+ serverspec (~> 2.7)
+ specinfra (~> 2.10)
+ syslog-logger (~> 1.6)
+ uuidtools (~> 2.1.5)
+ win32-api (~> 1.5.3)
+ win32-dir (~> 0.5.0)
+ win32-event (~> 0.6.1)
+ win32-eventlog (= 0.6.3)
+ win32-mmap (~> 0.4.1)
+ win32-mutex (~> 0.4.2)
+ win32-process (~> 0.8.2)
+ win32-service (~> 0.8.7)
+ windows-api (~> 0.4.4)
+ wmi-lite (~> 1.0)
+
+PATH
+ remote: chef-config
+ specs:
+ chef-config (12.19.39)
+ addressable
+ fuzzyurl
+ mixlib-config (~> 2.0)
+ mixlib-shellout (~> 2.0)
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ activesupport (5.0.1)
+ concurrent-ruby (~> 1.0, >= 1.0.2)
+ i18n (~> 0.7)
+ minitest (~> 5.1)
+ tzinfo (~> 1.1)
+ addressable (2.4.0)
+ appbundler (0.10.0)
+ mixlib-cli (~> 1.4)
+ artifactory (2.6.0)
+ ast (2.3.0)
+ aws-sdk (2.7.7)
+ aws-sdk-resources (= 2.7.7)
+ aws-sdk-core (2.7.7)
+ aws-sigv4 (~> 1.0)
+ jmespath (~> 1.0)
+ aws-sdk-resources (2.7.7)
+ aws-sdk-core (= 2.7.7)
+ aws-sigv4 (1.0.0)
+ backports (3.6.8)
+ binding_of_caller (0.7.2)
+ debug_inspector (>= 0.0.1)
+ builder (3.2.3)
+ byebug (9.0.6)
+ chef-api (0.7.0)
+ logify (~> 0.1)
+ mime-types
+ chef-provisioning (2.1.0)
+ cheffish (~> 4.0)
+ inifile (>= 2.0.2)
+ mixlib-install (>= 1.0, < 3.0)
+ net-scp (~> 1.0)
+ net-ssh (>= 2.9, < 5.0)
+ net-ssh-gateway (~> 1.2)
+ winrm-fs (~> 1.0)
+ chef-sugar (3.4.0)
+ chef-zero (5.3.0)
+ ffi-yajl (~> 2.2)
+ hashie (>= 2.0, < 4.0)
+ mixlib-log (~> 1.3)
+ rack (~> 2.0)
+ uuidtools (~> 2.1)
+ cheffish (4.1.1)
+ chef-zero (~> 5.0)
+ net-ssh
+ chefspec (5.4.0)
+ chef (>= 12.0)
+ fauxhai (~> 3.6)
+ rspec (~> 3.0)
+ codeclimate-test-reporter (0.6.0)
+ simplecov (>= 0.7.1, < 1.0.0)
+ codecov (0.1.9)
+ json
+ simplecov
+ url
+ coderay (1.1.1)
+ concurrent-ruby (1.0.4)
+ cucumber (2.4.0)
+ builder (>= 2.1.2)
+ cucumber-core (~> 1.5.0)
+ cucumber-wire (~> 0.0.1)
+ diff-lcs (>= 1.1.3)
+ gherkin (~> 4.0)
+ multi_json (>= 1.7.5, < 2.0)
+ multi_test (>= 0.1.2)
+ cucumber-core (1.5.0)
+ gherkin (~> 4.0)
+ cucumber-wire (0.0.1)
+ debug_inspector (0.0.2)
+ diff-lcs (1.3)
+ docile (1.1.5)
+ domain_name (0.5.20161129)
+ unf (>= 0.0.5, < 1.0.0)
+ erubis (2.7.0)
+ ethon (0.10.1)
+ ffi (>= 1.3.0)
+ excon (0.55.0)
+ faraday (0.11.0)
+ multipart-post (>= 1.2, < 3)
+ faraday-http-cache (2.0.0)
+ faraday (~> 0.8)
+ faraday_middleware (0.11.0.1)
+ faraday (>= 0.7.4, < 1.0)
+ fauxhai (3.10.0)
+ net-ssh
+ ffi (1.9.17)
+ ffi (1.9.17-x86-mingw32)
+ ffi-win32-extensions (1.0.3)
+ ffi
+ ffi-yajl (2.3.0)
+ libyajl2 (~> 1.2)
+ foodcritic (8.2.0)
+ cucumber-core (>= 1.3)
+ erubis
+ nokogiri (>= 1.5, < 2.0)
+ rake
+ rufus-lru (~> 1.0)
+ treetop (~> 1.4)
+ yajl-ruby (~> 1.1)
+ fuubar (2.2.0)
+ rspec-core (~> 3.0)
+ ruby-progressbar (~> 1.4)
+ fuzzyurl (0.9.0)
+ gh (0.15.0)
+ addressable (~> 2.4.0)
+ backports
+ faraday (~> 0.8)
+ multi_json (~> 1.0)
+ net-http-persistent (~> 2.9)
+ net-http-pipeline
+ gherkin (4.0.0)
+ git (1.3.0)
+ gssapi (1.2.0)
+ ffi (>= 1.0.1)
+ gyoku (1.3.1)
+ builder (>= 2.1.2)
+ halite (1.4.0)
+ bundler
+ chef (~> 12.0)
+ stove (~> 4.0)
+ thor
+ hashie (3.5.3)
+ highline (1.7.8)
+ http-cookie (1.0.3)
+ domain_name (~> 0.5)
+ httpclient (2.8.3)
+ i18n (0.8.0)
+ inifile (3.0.0)
+ iniparse (1.4.2)
+ ipaddress (0.8.3)
+ jmespath (1.3.1)
+ json (2.0.3)
+ kitchen-docker (2.6.0)
+ test-kitchen (>= 1.0.0)
+ kitchen-ec2 (1.3.0)
+ aws-sdk (~> 2)
+ excon
+ multi_json
+ retryable (~> 2.0)
+ test-kitchen (~> 1.4, >= 1.4.1)
+ kitchen-sync (2.1.2)
+ net-sftp
+ test-kitchen (>= 1.0.0)
+ kitchen-vagrant (1.0.1)
+ test-kitchen (~> 1.4)
+ knife-windows (1.9.0)
+ winrm (~> 2.1)
+ winrm-elevated (~> 1.0)
+ launchy (2.4.3)
+ addressable (~> 2.3)
+ libyajl2 (1.2.0)
+ little-plugger (1.1.4)
+ logging (2.1.0)
+ little-plugger (~> 1.1)
+ multi_json (~> 1.10)
+ logify (0.2.0)
+ method_source (0.8.2)
+ mime-types (3.1)
+ mime-types-data (~> 3.2015)
+ mime-types-data (3.2016.0521)
+ mini_portile2 (2.1.0)
+ minitest (5.10.1)
+ mixlib-archive (0.4.1)
+ mixlib-log
+ mixlib-authentication (1.4.1)
+ mixlib-log
+ mixlib-cli (1.7.0)
+ mixlib-config (2.2.4)
+ mixlib-install (2.1.12)
+ artifactory
+ mixlib-shellout
+ mixlib-versioning
+ thor
+ mixlib-log (1.7.1)
+ mixlib-shellout (2.2.7)
+ mixlib-shellout (2.2.7-universal-mingw32)
+ win32-process (~> 0.8.2)
+ wmi-lite (~> 1.0)
+ mixlib-versioning (1.1.0)
+ multi_json (1.12.1)
+ multi_test (0.1.2)
+ multipart-post (2.0.0)
+ net-http-persistent (2.9.4)
+ net-http-pipeline (1.0.1)
+ net-http-spy (0.2.1)
+ net-scp (1.2.1)
+ net-ssh (>= 2.6.5)
+ net-sftp (2.1.2)
+ net-ssh (>= 2.6.5)
+ net-ssh (4.0.1)
+ net-ssh-gateway (1.3.0)
+ net-ssh (>= 2.6.5)
+ net-ssh-multi (1.2.1)
+ net-ssh (>= 2.6.5)
+ net-ssh-gateway (>= 1.2.0)
+ net-telnet (0.1.1)
+ netrc (0.11.0)
+ nokogiri (1.7.0.1)
+ mini_portile2 (~> 2.1.0)
+ nokogiri (1.7.0.1-x86-mingw32)
+ mini_portile2 (~> 2.1.0)
+ nori (2.6.0)
+ octokit (4.6.2)
+ sawyer (~> 0.8.0, >= 0.5.3)
+ ohai (8.23.0)
+ chef-config (>= 12.5.0.alpha.1, < 13)
+ ffi (~> 1.9)
+ ffi-yajl (~> 2.2)
+ ipaddress
+ mixlib-cli
+ mixlib-config (~> 2.0)
+ mixlib-log (>= 1.7.1, < 2.0)
+ mixlib-shellout (~> 2.0)
+ plist (~> 3.1)
+ systemu (~> 2.6.4)
+ wmi-lite (~> 1.0)
+ parser (2.4.0.0)
+ ast (~> 2.2)
+ plist (3.2.0)
+ poise (2.7.2)
+ halite (~> 1.0)
+ poise-boiler (1.13.2)
+ bundler
+ chefspec (~> 5.0)
+ codeclimate-test-reporter (~> 0.4)
+ codecov (~> 0.0, >= 0.0.2)
+ foodcritic (>= 7, < 9)
+ fuubar (~> 2.0)
+ git (~> 1.2)
+ halite (~> 1.2)
+ kitchen-docker (>= 2.6.0.rc.0)
+ kitchen-ec2 (~> 1.0)
+ kitchen-sync (~> 2.1)
+ kitchen-vagrant
+ mixlib-shellout (>= 1.4, < 3.0)
+ poise-profiler (~> 1.0)
+ pry
+ pry-byebug
+ rake (>= 10.4, < 12.0)
+ rspec (~> 3.2)
+ rspec-its (~> 1.2)
+ simplecov (~> 0.9)
+ test-kitchen (~> 1.7, >= 1.7.1)
+ travis (~> 1.8, >= 1.8.1)
+ vagrant-wrapper
+ winrm (>= 1.6, < 3)
+ winrm-fs (>= 0.4, < 2)
+ yard (~> 0.8)
+ yard-classmethods (~> 1.0)
+ poise-profiler (1.0.1)
+ halite (~> 1.0)
+ polyglot (0.3.5)
+ powerpack (0.1.1)
+ proxifier (1.0.3)
+ pry (0.10.4)
+ coderay (~> 1.1.0)
+ method_source (~> 0.8.1)
+ slop (~> 3.4)
+ pry-byebug (3.4.2)
+ byebug (~> 9.0)
+ pry (~> 0.10)
+ pry-remote (0.1.8)
+ pry (~> 0.9)
+ slop (~> 3.0)
+ pry-stack_explorer (0.4.9.2)
+ binding_of_caller (>= 0.7)
+ pry (>= 0.9.11)
+ pusher-client (0.6.2)
+ json
+ websocket (~> 1.0)
+ rack (2.0.1)
+ rainbow (2.2.1)
+ rake (11.3.0)
+ rb-readline (0.5.4)
+ rest-client (2.0.0)
+ http-cookie (>= 1.0.2, < 2.0)
+ mime-types (>= 1.16, < 4.0)
+ netrc (~> 0.8)
+ rest-client (2.0.0-x86-mingw32)
+ ffi (~> 1.9)
+ http-cookie (>= 1.0.2, < 2.0)
+ mime-types (>= 1.16, < 4.0)
+ netrc (~> 0.8)
+ retriable (3.0.0)
+ retryable (2.0.4)
+ rspec (3.5.0)
+ rspec-core (~> 3.5.0)
+ rspec-expectations (~> 3.5.0)
+ rspec-mocks (~> 3.5.0)
+ rspec-core (3.5.4)
+ rspec-support (~> 3.5.0)
+ rspec-expectations (3.5.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.5.0)
+ rspec-its (1.2.0)
+ rspec-core (>= 3.0.0)
+ rspec-expectations (>= 3.0.0)
+ rspec-mocks (3.5.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.5.0)
+ rspec-rerun (1.1.0)
+ rspec (~> 3.0)
+ rspec-support (3.5.0)
+ rspec_junit_formatter (0.2.3)
+ builder (< 4)
+ rspec-core (>= 2, < 4, != 2.12.0)
+ rubocop (0.47.1)
+ parser (>= 2.3.3.1, < 3.0)
+ powerpack (~> 0.1)
+ rainbow (>= 1.99.1, < 3.0)
+ ruby-progressbar (~> 1.7)
+ unicode-display_width (~> 1.0, >= 1.0.1)
+ ruby-prof (0.16.2)
+ ruby-progressbar (1.8.1)
+ ruby-shadow (2.5.0)
+ rubyntlm (0.6.1)
+ rubyzip (1.2.1)
+ rufus-lru (1.1.0)
+ safe_yaml (1.0.4)
+ sawyer (0.8.1)
+ addressable (>= 2.3.5, < 2.6)
+ faraday (~> 0.8, < 1.0)
+ serverspec (2.38.0)
+ multi_json
+ rspec (~> 3.0)
+ rspec-its
+ specinfra (~> 2.53)
+ sfl (2.3)
+ simplecov (0.13.0)
+ docile (~> 1.1.0)
+ json (>= 1.8, < 3)
+ simplecov-html (~> 0.10.0)
+ simplecov-html (0.10.0)
+ slop (3.6.0)
+ specinfra (2.66.9)
+ net-scp
+ net-ssh (>= 2.7, < 5.0)
+ net-telnet
+ sfl
+ stove (4.1.1)
+ chef-api (~> 0.5)
+ logify (~> 0.2)
+ syslog-logger (1.6.8)
+ systemu (2.6.5)
+ test-kitchen (1.15.0)
+ mixlib-install (>= 1.2, < 3.0)
+ mixlib-shellout (>= 1.2, < 3.0)
+ net-scp (~> 1.1)
+ net-ssh (>= 2.9, < 5.0)
+ net-ssh-gateway (~> 1.2)
+ safe_yaml (~> 1.0)
+ thor (~> 0.18)
+ thor (0.19.4)
+ thread_safe (0.3.5)
+ tomlrb (1.2.3)
+ travis (1.8.6)
+ backports
+ faraday (~> 0.9)
+ faraday_middleware (~> 0.9, >= 0.9.1)
+ gh (~> 0.13)
+ highline (~> 1.6)
+ launchy (~> 2.1)
+ pusher-client (~> 0.4)
+ typhoeus (~> 0.6, >= 0.6.8)
+ treetop (1.6.8)
+ polyglot (~> 0.3)
+ typhoeus (0.8.0)
+ ethon (>= 0.8.0)
+ tzinfo (1.2.2)
+ thread_safe (~> 0.1)
+ unf (0.1.4)
+ unf_ext
+ unf_ext (0.0.7.2)
+ unf_ext (0.0.7.2-x86-mingw32)
+ unicode-display_width (1.1.3)
+ url (0.3.2)
+ uuidtools (2.1.5)
+ vagrant-wrapper (2.0.3)
+ websocket (1.2.4)
+ win32-api (1.5.3-universal-mingw32)
+ win32-dir (0.5.1)
+ ffi (>= 1.0.0)
+ win32-event (0.6.3)
+ win32-ipc (>= 0.6.0)
+ win32-eventlog (0.6.3)
+ ffi
+ win32-ipc (0.7.0)
+ ffi
+ win32-mmap (0.4.2)
+ ffi
+ win32-mutex (0.4.3)
+ win32-ipc (>= 0.6.0)
+ win32-process (0.8.3)
+ ffi (>= 1.0.0)
+ win32-service (0.8.10)
+ ffi
+ ffi-win32-extensions
+ windows-api (0.4.4)
+ win32-api (>= 1.4.5)
+ winrm (2.1.2)
+ builder (>= 2.1.2)
+ erubis (~> 2.7)
+ gssapi (~> 1.2)
+ gyoku (~> 1.0)
+ httpclient (~> 2.2, >= 2.2.0.2)
+ logging (>= 1.6.1, < 3.0)
+ nori (~> 2.0)
+ rubyntlm (~> 0.6.0, >= 0.6.1)
+ winrm-elevated (1.1.0)
+ winrm (~> 2.0)
+ winrm-fs (~> 1.0)
+ winrm-fs (1.0.1)
+ erubis (~> 2.7)
+ logging (>= 1.6.1, < 3.0)
+ rubyzip (~> 1.1)
+ winrm (~> 2.0)
+ wmi-lite (1.0.0)
+ yajl-ruby (1.3.0)
+ yard (0.9.8)
+ yard-classmethods (1.0.0)
+ yard
+
+PLATFORMS
+ ruby
+ x86-mingw32
+
+DEPENDENCIES
+ appbundler
+ bundler
+ bundler-audit!
+ chef!
+ chef-config!
+ chef-provisioning
+ chef-sugar
+ cheffish
+ chefspec
+ chefstyle!
+ cucumber (>= 2.4.0)
+ foodcritic
+ github_changelog_generator!
+ halite
+ knife-windows
+ mixlib-install
+ netrc
+ nokogiri
+ oc-chef-pedant!
+ octokit
+ poise
+ poise-boiler
+ pry
+ pry-byebug
+ pry-remote
+ pry-stack_explorer
+ rake
+ rb-readline
+ ruby-prof
+ ruby-shadow
+ simplecov
+ tomlrb
+ travis
+ yard
+
+BUNDLED WITH
+ 1.12.5
diff --git a/HISTORY.md b/HISTORY.md
new file mode 100644
index 0000000000..acce953a47
--- /dev/null
+++ b/HISTORY.md
@@ -0,0 +1,1331 @@
+## [v12.18.31](https://github.com/chef/chef/tree/v12.18.31) (2017-01-11)
+[Full Changelog](https://github.com/chef/chef/compare/v12.17.44...v12.18.31)
+
+**Implemented enhancements:**
+
+- yum\_repository: Allow baseurl to be an array & allow fastestmirror\_enabled false [\#5708](https://github.com/chef/chef/pull/5708) ([tas50](https://github.com/tas50))
+- Adding returns property to chocolatey\_package resource [\#5688](https://github.com/chef/chef/pull/5688) ([Vasu1105](https://github.com/Vasu1105))
+- Code cleanup in the user provider [\#5674](https://github.com/chef/chef/pull/5674) ([lamont-granquist](https://github.com/lamont-granquist))
+- Code cleanup in the group provider [\#5673](https://github.com/chef/chef/pull/5673) ([lamont-granquist](https://github.com/lamont-granquist))
+- Core: Formally deprecate run\_command [\#5666](https://github.com/chef/chef/pull/5666) ([lamont-granquist](https://github.com/lamont-granquist))
+- Set MSI Scheduled Task name to match chef-client cookbook managed name [\#5657](https://github.com/chef/chef/pull/5657) ([mwrock](https://github.com/mwrock))
+- remove Chef::Platform::HandlerMap [\#5636](https://github.com/chef/chef/pull/5636) ([lamont-granquist](https://github.com/lamont-granquist))
+- Core: Properly deprecate old Chef::Platform methods [\#5631](https://github.com/chef/chef/pull/5631) ([lamont-granquist](https://github.com/lamont-granquist))
+
+**Fixed bugs:**
+
+- Fix error thrown by solo when run on Windows as SYSTEM [\#5693](https://github.com/chef/chef/pull/5693) ([scottopherson](https://github.com/scottopherson))
+- Report a blank resource if sensitive is enabled [\#5668](https://github.com/chef/chef/pull/5668) ([afiune](https://github.com/afiune))
+- Ensure node.docker? returns boolean [\#5645](https://github.com/chef/chef/pull/5645) ([andrewjamesbrown](https://github.com/andrewjamesbrown))
+- Fix Data Collector organization parsing regex [\#5630](https://github.com/chef/chef/pull/5630) ([adamleff](https://github.com/adamleff))
+- Core: Use object ID when detected unprocessed Resources [\#5604](https://github.com/chef/chef/pull/5604) ([adamleff](https://github.com/adamleff))
+
+**Merged pull requests:**
+
+- Core: fix node attribute "unless" API methods [\#5717](https://github.com/chef/chef/pull/5717) ([lamont-granquist](https://github.com/lamont-granquist))
+
+## [v12.17.44](https://github.com/chef/chef/tree/v12.17.44) (2016-12-07)
+[Full Changelog](https://github.com/chef/chef/compare/v12.16.42...v12.17.44)
+
+**Implemented enhancements:**
+
+- Action :umount for mount resource is an obtuse anachronism [\#5595](https://github.com/chef/chef/issues/5595)
+- Core: Update ohai resource to new style, stop overwriting name property [\#5607](https://github.com/chef/chef/pull/5607) ([adamleff](https://github.com/adamleff))
+- Linux: mount provider - skip device detection for zfs [\#5603](https://github.com/chef/chef/pull/5603) ([ttr](https://github.com/ttr))
+- Core: Ensure chef-solo creates node files w/ correct permissions [\#5601](https://github.com/chef/chef/pull/5601) ([scottopherson](https://github.com/scottopherson))
+- Resources: Add unmount as an alias to umount in the mount resource [\#5599](https://github.com/chef/chef/pull/5599) ([shortdudey123](https://github.com/shortdudey123))
+- Core: Update Data Collector to use Chef::JSONCompat [\#5590](https://github.com/chef/chef/pull/5590) ([adamleff](https://github.com/adamleff))
+- Knife: Add ability to pass multiple nodes to knife node/client delete [\#5572](https://github.com/chef/chef/pull/5572) ([jeunito](https://github.com/jeunito))
+- Core: Data Collector debug log should output JSON [\#5570](https://github.com/chef/chef/pull/5570) ([adamleff](https://github.com/adamleff))
+- Yum: Purge yum cache before deleting repo config [\#5509](https://github.com/chef/chef/pull/5509) ([iancward](https://github.com/iancward))
+- Knife Bootstrap: Passing config\_log\_level and config\_log\_location from config.rb [\#5502](https://github.com/chef/chef/pull/5502) ([dheerajd-msys](https://github.com/dheerajd-msys))
+
+**Fixed bugs:**
+
+- Custom Resources: Undefined method up\_to\_date thrown by Chef 12.16.42 [\#5593](https://github.com/chef/chef/issues/5593)
+- Core: Ensure deprecation messages are always included [\#5618](https://github.com/chef/chef/pull/5618) ([thommay](https://github.com/thommay))
+- Core: Fix bug where Access Controls on existing symlink resources would be ignored on first chef-client run [\#5616](https://github.com/chef/chef/pull/5616) ([tduffield](https://github.com/tduffield))
+- The suggested fix for the manage\_home deprecation is incorrect [\#5615](https://github.com/chef/chef/pull/5615) ([tas50](https://github.com/tas50))
+- change choco -version to choco --version [\#5613](https://github.com/chef/chef/pull/5613) ([spuder](https://github.com/spuder))
+- Knife: Correct example `chef\_server\_url` in `knife configure` [\#5602](https://github.com/chef/chef/pull/5602) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
+- Windows: Ensure correct version of shutdown is called when using the reboot resource [\#5596](https://github.com/chef/chef/pull/5596) ([Xoph](https://github.com/Xoph))
+- Windows: Support for running cab\_package on non-English system locales [\#5591](https://github.com/chef/chef/pull/5591) ([jugatsu](https://github.com/jugatsu))
+- Core: Ensure Data Collector resource report exists before updating [\#5571](https://github.com/chef/chef/pull/5571) ([adamleff](https://github.com/adamleff))
+- Windows: Use the full path to expand.exe for msu\_package [\#5564](https://github.com/chef/chef/pull/5564) ([NimishaS](https://github.com/NimishaS))
+- Unset http\[s\]\_proxy in the subversion spec [\#5562](https://github.com/chef/chef/pull/5562) ([stefanor](https://github.com/stefanor))
+- Core: fix Lint/UnifiedInteger cop [\#5547](https://github.com/chef/chef/pull/5547) ([lamont-granquist](https://github.com/lamont-granquist))
+- Core: fix ImmutableArray slices [\#5541](https://github.com/chef/chef/pull/5541) ([lamont-granquist](https://github.com/lamont-granquist))
+- Prevent apt\_update failures on non-Linux platforms [\#5524](https://github.com/chef/chef/pull/5524) ([tas50](https://github.com/tas50))
+- Core: Ensure that the sensitive property is correctly accessed [\#5508](https://github.com/chef/chef/pull/5508) ([axos88](https://github.com/axos88))
+
+**Closed issues:**
+
+- cab\_package doesn't support running on non-English system locales [\#5592](https://github.com/chef/chef/issues/5592)
+- Support restarting/stopping/ the service from state paused on windows [\#5586](https://github.com/chef/chef/issues/5586)
+
+## [v12.16.42](https://github.com/chef/chef/tree/v12.16.42) (2016-11-04)
+[Full Changelog](https://github.com/chef/chef/compare/v12.15.19...v12.16.42)
+
+**Implemented enhancements:**
+
+- Core: improve readability of property-resource namespace collision exception message [\#5500](https://github.com/chef/chef/pull/5500) ([lamont-granquist](https://github.com/lamont-granquist))
+- Omnibus: Pull in Ohai 8.21.0 and other new deps [\#5499](https://github.com/chef/chef/pull/5499) ([tas50](https://github.com/tas50))
+- Core: Add deprecations to Data Collector run completion messages [\#5496](https://github.com/chef/chef/pull/5496) ([adamleff](https://github.com/adamleff))
+- Core: add attribute\_changed hook to event handlers [\#5495](https://github.com/chef/chef/pull/5495) ([lamont-granquist](https://github.com/lamont-granquist))
+- Knife: Add the `--field-separator` flag to knife show commands [\#5489](https://github.com/chef/chef/pull/5489) ([tduffield](https://github.com/tduffield))
+- Core: Enable Signed Header Auth for Data Collector, and Configure the Data Collector Automatically [\#5487](https://github.com/chef/chef/pull/5487) ([danielsdeleo](https://github.com/danielsdeleo))
+- Core: set use\_inline\_resources in package superclass [\#5483](https://github.com/chef/chef/pull/5483) ([lamont-granquist](https://github.com/lamont-granquist))
+- Package: Add new "lock" action for apt, yum and zypper packages [\#5395](https://github.com/chef/chef/pull/5395) ([yeoldegrove](https://github.com/yeoldegrove))
+
+**Fixed bugs:**
+
+- Enable data collector w/o token for solo, but require explicit URL [\#5511](https://github.com/chef/chef/pull/5511) ([danielsdeleo](https://github.com/danielsdeleo))
+- Core: Include chef/chef\_class in Chef::REST for method log\_deprecation [\#5504](https://github.com/chef/chef/pull/5504) ([smalltown](https://github.com/smalltown))
+- Knife: Updating knife ssl fetch to correctly store certificate when it does not have a CN [\#5498](https://github.com/chef/chef/pull/5498) ([tyler-ball](https://github.com/tyler-ball))
+- Knife: Fixed knife download cookbooks issue which used to corrupt the certificate files each time the command was fired. [\#5494](https://github.com/chef/chef/pull/5494) ([Aliasgar16](https://github.com/Aliasgar16))
+- Solaris: Properly check lock status of users on solaris2 [\#5486](https://github.com/chef/chef/pull/5486) ([tduffield](https://github.com/tduffield))
+- Solaris: Fix IPS package must create symlinks to package commands [\#5485](https://github.com/chef/chef/pull/5485) ([jaymalasinha](https://github.com/jaymalasinha))
+
+## [v12.15.19](https://github.com/chef/chef/tree/v12.15.19) (2016-10-07)
+[Full Changelog](https://github.com/chef/chef/compare/v12.14.89...v12.15.19)
+
+**Enhancements:**
+
+- Adding support for rfc 62 exit code 213 (Chef upgrades) [\#5428](https://github.com/chef/chef/pull/5428) ([jeremymv2](https://github.com/jeremymv2))
+- Allow raw_key to override the configured signing\_key [\#5314](https://github.com/chef/chef/pull/5314) ([thommay](https://github.com/thommay))
+- Set yum\_repository gpgcheck default to true [\#5398](https://github.com/chef/chef/pull/5398) ([shortdudey123](https://github.com/shortdudey123))
+- Allow deletion of registry\_key without the need for users to pass data key in values hash. [\#5359](https://github.com/chef/chef/pull/5359) ([Aliasgar16](https://github.com/Aliasgar16))
+- Adding support for cab files to Chef package provider on windows [\#5285](https://github.com/chef/chef/pull/5285) ([Vasu1105](https://github.com/Vasu1105))
+- Ignore unknown metadata fields in metadata.rb [\#5299](https://github.com/chef/chef/pull/5299) ([lamont-granquist](https://github.com/lamont-granquist))
+
+**Fixed Bugs:**
+
+- knife ssh: use the command line prompt for sudo if set [\#5427](https://github.com/chef/chef/pull/5427) ([lamont-granquist](https://github.com/lamont-granquist))
+- User provider: Fix manage\_home provider inconsistency for Mac and FreeBSD providers [\#5423](https://github.com/chef/chef/pull/5423) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix for "Chefspec template rendering fails when cookbook\_name != directory name" [\#5417](https://github.com/chef/chef/pull/5417) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix solaris handling for useradd -m/-M behavior [\#5408](https://github.com/chef/chef/pull/5408) ([coderanger](https://github.com/coderanger))
+- Normalize full key name to avoid resource update on identical key names [\#5290](https://github.com/chef/chef/pull/5290) ([bai](https://github.com/bai))
+- Add trailing newline to generated 15update-stamp [\#5382](https://github.com/chef/chef/pull/5382) ([pwalz](https://github.com/pwalz))
+- Invalid `dsc_scripts` should fail the run [\#5377](https://github.com/chef/chef/pull/5377) ([NimishaS](https://github.com/NimishaS))
+- Revert --local filter for gems installed from paths [\#5379](https://github.com/chef/chef/pull/5379) ([mwrock](https://github.com/mwrock))
+- Fix knife list\_commands\(\) [\#5386](https://github.com/chef/chef/pull/5386) ([lamont-granquist](https://github.com/lamont-granquist))
+- Don't use -r for users or groups on Solaris. [\#5355](https://github.com/chef/chef/pull/5355) ([coderanger](https://github.com/coderanger))
+- Chef 12 Attribute Regression [\#5360](https://github.com/chef/chef/pull/5360) ([gbagnoli](https://github.com/gbagnoli))
+- Handling Errno::ETIMEDOUT [\#5358](https://github.com/chef/chef/pull/5358) ([NimishaS](https://github.com/NimishaS))
+
+## [v12.14.89](https://github.com/chef/chef/tree/v12.14.89) (2016-09-22)
+[Full Changelog](https://github.com/chef/chef/compare/v12.14.77...v12.14.89)
+
+**Fixed Bugs:**
+
+- Revert "Verify systemd\_unit file during create" [\#5326](https://github.com/chef/chef/pull/5326) ([mwrock](https://github.com/mwrock))
+- Fix method\_access and array handling in node presenter [\#5351](https://github.com/chef/chef/pull/5351) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fixed undefined short\_cksum method issue and checksum in uppercase issue for windows\_package resource. [\#5332](https://github.com/chef/chef/pull/5332) ([Aliasgar16](https://github.com/Aliasgar16))
+- Fix makecache action name in yum\_repository [\#5348](https://github.com/chef/chef/pull/5348) ([tas50](https://github.com/tas50))
+
+## [v12.14.77](https://github.com/chef/chef/tree/v12.14.77) (2016-09-19)
+[Full Changelog](https://github.com/chef/chef/compare/v12.14.60...v12.14.77)
+
+**Fixed Bugs:**
+
+- Revert supports\[:manage\_home\] behavior [\#5322](https://github.com/chef/chef/pull/5322) ([lamont-granquist](https://github.com/lamont-granquist))
+- Preserve the extension of the file in the rendered tempfile in File providers [\#5327](https://github.com/chef/chef/pull/5327) ([lamont-granquist](https://github.com/lamont-granquist))
+- Allow the :delete action for yum\_repository + fix old property support [\#5320](https://github.com/chef/chef/pull/5320) ([tas50](https://github.com/tas50))
+
+## [v12.14.60](https://github.com/chef/chef/tree/v12.14.60) (2016-09-09)
+[Full Changelog](https://github.com/chef/chef/compare/v12.13.37...v12.14.60)
+
+**Enhancements:**
+
+- Only support Solaris 10u11 and newer [\#5264](https://github.com/chef/chef/pull/5264) ([rhass](https://github.com/rhass))
+- Added code to handle deletion of directories on Windows that are symlinks. [\#5234](https://github.com/chef/chef/pull/5234) ([Aliasgar16](https://github.com/Aliasgar16))
+- Readability improvements to options parsing code [\#5289](https://github.com/chef/chef/pull/5289) ([lamont-granquist](https://github.com/lamont-granquist))
+- Add Hash type to launchd:keep\_alive [\#5182](https://github.com/chef/chef/pull/5182) ([erikng](https://github.com/erikng))
+- Added timeout during removing of windows package [\#5250](https://github.com/chef/chef/pull/5250) ([dheerajd-msys](https://github.com/dheerajd-msys))
+- Bump openssl to 1.0.2h [\#5260](https://github.com/chef/chef/pull/5260) ([lamont-granquist](https://github.com/lamont-granquist))
+- Rewrite linux\_user provider check\_lock [\#5248](https://github.com/chef/chef/pull/5248) ([lamont-granquist](https://github.com/lamont-granquist))
+- Allow flagging a resource property as sensitive [\#5185](https://github.com/chef/chef/pull/5185) ([adamleff](https://github.com/adamleff))
+- Rewrite linux useradd provider [\#5243](https://github.com/chef/chef/pull/5243) ([lamont-granquist](https://github.com/lamont-granquist))
+- Add yum_repository resource from the yum cookbook [\#5187](https://github.com/chef/chef/pull/5187) ([thommay](https://github.com/thommay))
+- Verify systemd\_unit file during create [\#5210](https://github.com/chef/chef/pull/5210) ([mal](https://github.com/mal))
+- Add a warning for guard blocks that return a non-empty string [\#5233](https://github.com/chef/chef/pull/5233) ([coderanger](https://github.com/coderanger))
+- Forward package cookbook\_name to underlying remote\_file [\#5128](https://github.com/chef/chef/pull/5128) ([Annih](https://github.com/Annih))
+- Fix "URI.escape is obsolete" warnings [\#5230](https://github.com/chef/chef/pull/5230) ([jkeiser](https://github.com/jkeiser))
+- Remove ruby 2.1 support [\#5220](https://github.com/chef/chef/pull/5220) ([lamont-granquist](https://github.com/lamont-granquist))
+- User provider manage\_home behavior and refactor [\#5122](https://github.com/chef/chef/pull/5122) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix Style/BlockDelimiters, Style/MultilineBlockLayout and 0.42.0 engine upgrade [\#5218](https://github.com/chef/chef/pull/5218) ([lamont-granquist](https://github.com/lamont-granquist))
+- Switch from Ruby 2.1.9 to Ruby 2.3.1 [\#5190](https://github.com/chef/chef/pull/5190) ([jkeiser](https://github.com/jkeiser))
+- Update to latest chefstyle [\#5217](https://github.com/chef/chef/pull/5217) ([jkeiser](https://github.com/jkeiser))
+- Rubygems memory performance improvement [\#5203](https://github.com/chef/chef/pull/5203) ([lamont-granquist](https://github.com/lamont-granquist))
+- HTTP 1.1 keepalives for cookbook synchronization [\#5151](https://github.com/chef/chef/pull/5151) ([lamont-granquist](https://github.com/lamont-granquist))
+
+**Fixed Bugs:**
+
+- Fixes GH-4955, allowing local gems with remote dependencies [\#5098](https://github.com/chef/chef/pull/5098) ([jyaworski](https://github.com/jyaworski))
+- Hook up the recipe\_file\_loaded event which was defined but not actually called [\#5281](https://github.com/chef/chef/pull/5281) ([coderanger](https://github.com/coderanger))
+- fix gem\_package regression in master [\#5262](https://github.com/chef/chef/pull/5262) ([lamont-granquist](https://github.com/lamont-granquist))
+- Added fix for spaces in profile identifiers [\#5159](https://github.com/chef/chef/pull/5159) ([natewalck](https://github.com/natewalck))
+- Add a hook for compat\_resource [\#5259](https://github.com/chef/chef/pull/5259) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix flush\_cache issues in yum\_package [\#5258](https://github.com/chef/chef/pull/5258) ([jaymzh](https://github.com/jaymzh))
+- Use symbols instead of strings as keys for systemd user property [\#5241](https://github.com/chef/chef/pull/5241) ([joshuamiller01](https://github.com/joshuamiller01))
+- Use upstart goal state as service status [\#5249](https://github.com/chef/chef/pull/5249) ([evan2645](https://github.com/evan2645))
+- Fix the useradd test filters [\#5236](https://github.com/chef/chef/pull/5236) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix specify members of group on suse/openbsd/solaris2/hpux [\#5152](https://github.com/chef/chef/pull/5152) ([tas50](https://github.com/tas50))
+- Fix cookbook upload of symlinked cookbooks in Ruby 2.3 on Windows [\#5216](https://github.com/chef/chef/pull/5216) ([jkeiser](https://github.com/jkeiser))
+- Don't use relative\_path\_from on glob results [\#5215](https://github.com/chef/chef/pull/5215) ([jkeiser](https://github.com/jkeiser))
+
+## [v12.13.37](https://github.com/chef/chef/tree/v12.13.37) (2016-08-12)
+[Full Changelog](https://github.com/chef/chef/compare/v12.13.30...v12.13.37)
+
+**Enhancements:**
+
+- Bumping ohai and mixlib-log to fix regression [\#5197](https://github.com/chef/chef/pull/5197) ([mwrock](https://github.com/mwrock))
+- Remove requires in Chef::Recipe that are no longer necessary [\#5189](https://github.com/chef/chef/pull/5189) ([lamont-granquist](https://github.com/lamont-granquist))
+
+## [v12.13.30](https://github.com/chef/chef/tree/v12.13.30) (2016-08-05)
+[Full Changelog](https://github.com/chef/chef/compare/v12.12.15...v12.13.30)
+
+**Enhancements:**
+
+- noop apt_update similar to apt_repository [\#5173](https://github.com/chef/chef/pull/5173) ([lamont-granquist](https://github.com/lamont-granquist))
+- Bump dependencies to bring in Ohai 8.18 [\#5168](https://github.com/chef/chef/pull/5168) ([tas50](https://github.com/tas50))
+- Make Chef work with Ruby 2.3, update Ruby to 2.1.9 [\#5165](https://github.com/chef/chef/pull/5165) ([jkeiser](https://github.com/jkeiser))
+- Log cause chain for exceptions [\#3354](https://github.com/chef/chef/pull/3354) ([jaym](https://github.com/jaym))
+- First pass on --config-option handling. [\#5045](https://github.com/chef/chef/pull/5045) ([coderanger](https://github.com/coderanger))
+- Add bootstrap proxy authentication support. [\#4059](https://github.com/chef/chef/pull/4059) ([yossigo](https://github.com/yossigo))
+- Support setting an empty string for cron attrs [\#5127](https://github.com/chef/chef/pull/5127) ([thommay](https://github.com/thommay))
+- Also clear notifications when deleting a resource. [\#5146](https://github.com/chef/chef/pull/5146) ([coderanger](https://github.com/coderanger))
+- Clean up subscribes internals and notification storage. [\#5145](https://github.com/chef/chef/pull/5145) ([coderanger](https://github.com/coderanger))
+- Cache ChefFS children [\#5131](https://github.com/chef/chef/pull/5131) ([thommay](https://github.com/thommay))
+- Update to rspec 3.5 [\#5126](https://github.com/chef/chef/pull/5126) ([thommay](https://github.com/thommay))
+- Add `chef\_data\_bag\_item` to Cheffish DSL methods [\#5125](https://github.com/chef/chef/pull/5125) ([danielsdeleo](https://github.com/danielsdeleo))
+- replace glibc resolver with ruby resolver [\#5123](https://github.com/chef/chef/pull/5123) ([lamont-granquist](https://github.com/lamont-granquist))
+- The user must specify a category for a new cookbook [\#5091](https://github.com/chef/chef/pull/5091) ([thommay](https://github.com/thommay))
+- Warn if not installing an individual bff fileset [\#5093](https://github.com/chef/chef/pull/5093) ([mwrock](https://github.com/mwrock))
+- Use Mixlib::Archive to extract tarballs [\#5080](https://github.com/chef/chef/pull/5080) ([thommay](https://github.com/thommay))
+- Data Collector server URL validation, and disable on host down [\#5076](https://github.com/chef/chef/pull/5076) ([adamleff](https://github.com/adamleff))
+
+**Fixed Bugs:**
+
+- Don't log error for reporting audit data in when in chef-zero [\#5016](https://github.com/chef/chef/pull/5016) ([erichelgeson](https://github.com/erichelgeson))
+- Invalidate the file system cache on deletion [\#5154](https://github.com/chef/chef/pull/5154) ([thommay](https://github.com/thommay))
+- Root ACLs are a top level json file not a sub-directory [\#5155](https://github.com/chef/chef/pull/5155) ([thommay](https://github.com/thommay))
+- Install nokogiri and pin mixlib-cli [\#5118](https://github.com/chef/chef/pull/5118) ([ksubrama](https://github.com/ksubrama))
+- Ensure that the valid option is given back to the option parser [\#5114](https://github.com/chef/chef/pull/5114) ([dldinternet](https://github.com/dldinternet))
+- Fixed regex for zypper version 1.13.\*. [\#5109](https://github.com/chef/chef/pull/5109) ([yeoldegrove](https://github.com/yeoldegrove))
+- add back method\_missing support to set\_unless [\#5103](https://github.com/chef/chef/pull/5103) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix \#5094 node.default\_unless issue in 12.12.13 [\#5097](https://github.com/chef/chef/pull/5097) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix \#5078 using cwd parameter instead of Dir.pwd [\#5079](https://github.com/chef/chef/pull/5079) ([Tensibai](https://github.com/Tensibai))
+
+## [v12.12.15](https://github.com/chef/chef/tree/v12.12.15) (2016-07-08)
+[Full Changelog](https://github.com/chef/chef/compare/v12.12.13...v12.12.15)
+
+**Fixed Bugs:**
+
+- Fix for #5094 12.12.13 node.default_unless issue [\#5097](https://github.com/chef/chef/pull/5097) ([lamont-granquist](https://github.com/lamont-granquist))
+
+## [v12.12.13](https://github.com/chef/chef/tree/v12.12.13) (2016-07-01)
+[Full Changelog](https://github.com/chef/chef/compare/v12.11.18...v12.12.13)
+
+**Implemented Enhancements:**
+
+- Tweak 3694 warnings [\#5075](https://github.com/chef/chef/pull/5075) ([lamont-granquist](https://github.com/lamont-granquist))
+- Adding node object to Data collector run\_converge message [\#5065](https://github.com/chef/chef/pull/5065) ([adamleff](https://github.com/adamleff))
+- Attribute API improvements [\#5029](https://github.com/chef/chef/pull/5029) ([lamont-granquist](https://github.com/lamont-granquist))
+- Remove deprecated Thread.exclusive around require call. [\#5068](https://github.com/chef/chef/pull/5068) ([maxlazio](https://github.com/maxlazio))
+- Ensure that chef-solo uses the expected repo dir [\#5059](https://github.com/chef/chef/pull/5059) ([thommay](https://github.com/thommay))
+- Expand data\_collector resource list to include all resources [\#5058](https://github.com/chef/chef/pull/5058) ([adamleff](https://github.com/adamleff))
+- Turn off fips with an empty environment var [\#5048](https://github.com/chef/chef/pull/5048) ([mwrock](https://github.com/mwrock))
+- Deprecate knife-supermarket gem [\#4896](https://github.com/chef/chef/pull/4896) ([thommay](https://github.com/thommay))
+- Update Nokogiri [\#5042](https://github.com/chef/chef/pull/5042) ([mwrock](https://github.com/mwrock))
+- Remote resource should respect sensitive flag [\#5025](https://github.com/chef/chef/pull/5025) ([PrajaktaPurohit](https://github.com/PrajaktaPurohit))
+- Convert the 3694 warning to a deprecation so it will be subject to the usual deprecation formatting \(collected at the bottom, can be made an error, etc\). [\#5022](https://github.com/chef/chef/pull/5022) ([coderanger](https://github.com/coderanger))
+- Deprecate `knife cookbook create` in favor of `chef generate cookbook`. [\#5021](https://github.com/chef/chef/pull/5021) ([tylercloke](https://github.com/tylercloke))
+
+**Fixed Bugs:**
+
+- Fixes windows_package uninstall scenarios by calling uninstall string directly [\#5050](https://github.com/chef/chef/pull/5050) ([mwrock](https://github.com/mwrock))
+- Fix gem_package idempotency [\#5046](https://github.com/chef/chef/pull/5046) ([thommay](https://github.com/thommay))
+- Undefined local variable lookup in multiplexed_dir.rb [\#5027](https://github.com/chef/chef/issues/5027) ([robdimarco](https://github.com/robdimarco))
+- Correctly write out data collector metadata file [\#5019](https://github.com/chef/chef/pull/5019) ([adamleff](https://github.com/adamleff))
+- Eliminate missing constant errors for LWRP class [\#5000](https://github.com/chef/chef/pull/5000) ([PrajaktaPurohit](https://github.com/PrajaktaPurohit))
+- Updated_resource_count to data collector should only include updated resources [\#5006](https://github.com/chef/chef/pull/5006) ([adamleff](https://github.com/adamleff))
+- Don't mask directory deletion errors [\#4991](https://github.com/chef/chef/pull/4991) ([jaymzh](https://github.com/jaymzh))
+
+## [v12.11.18](https://github.com/chef/chef/tree/v12.11.18) (2016-06-02)
+[Full Changelog](https://github.com/chef/chef/compare/v12.11.17...v12.11.18)
+
+**Implemented Enhancements:**
+
+- Creation of the new DataCollector reporter [\#4973](https://github.com/chef/chef/pull/4973) ([adamleff](https://github.com/adamleff))
+- Add systemd\_unit try-restart, reload-or-restart, reload-or-try-restart actions [\#4908](https://github.com/chef/chef/pull/4908) ([nathwill](https://github.com/nathwill))
+- RFC062 exit status chef client [\#4611](https://github.com/chef/chef/pull/4611) ([smurawski](https://github.com/smurawski))
+- Create 'universal' DSL [\#4942](https://github.com/chef/chef/pull/4942) ([lamont-granquist](https://github.com/lamont-granquist))
+- Handle numeric id for the user value in the git resource [\#4902](https://github.com/chef/chef/pull/4902) ([MichaelPereira](https://github.com/MichaelPereira))
+- RFC 31 - Default solo to local mode [\#4919](https://github.com/chef/chef/pull/4919) ([thommay](https://github.com/thommay))
+- Wire up chef handlers directly from libraries [\#4933](https://github.com/chef/chef/pull/4933) ([lamont-granquist](https://github.com/lamont-granquist))
+- Reject malformed ini content in systemd\_unit resource [\#4907](https://github.com/chef/chef/pull/4907) ([nathwill](https://github.com/nathwill))
+- Update usage of @new\_resource.destination to `cwd` within the git hwrp [\#4898](https://github.com/chef/chef/pull/4898) ([joshburt](https://github.com/joshburt))
+- Support Ruby Files in ChefFS [\#4887](https://github.com/chef/chef/pull/4887) ([thommay](https://github.com/thommay))
+- Adds a system check for fips enablement and runs in fips mode if enabled [\#4880](https://github.com/chef/chef/pull/4880) ([mwrock](https://github.com/mwrock))
+- Lazy'ing candidate\_version in package provider [\#4869](https://github.com/chef/chef/pull/4869) ([lamont-granquist](https://github.com/lamont-granquist))
+- Add systemd\_unit resource [\#4700](https://github.com/chef/chef/pull/4700) ([nathwill](https://github.com/nathwill))
+- Bump chef-zero to avoid aggressive logging [\#4878](https://github.com/chef/chef/pull/4878) ([stevendanna](https://github.com/stevendanna))
+
+**Fixed Bugs:**
+
+- Fix \#4949 and Avoid Errno::EBUSY on docker containers [\#4979](https://github.com/chef/chef/pull/4979) ([andrewjamesbrown](https://github.com/andrewjamesbrown))
+- Ensure recipe-url works right in solo [\#4957](https://github.com/chef/chef/pull/4957) ([thommay](https://github.com/thommay))
+- Fix portage provider to support version with character [\#4966](https://github.com/chef/chef/pull/4966) ([crigor](https://github.com/crigor))
+- Fixes \#4968 and only retrieves the latest version of packages from chocolatey [\#4977](https://github.com/chef/chef/pull/4977) ([mwrock](https://github.com/mwrock))
+- Update contributing doc to better reflect reality [\#4962](https://github.com/chef/chef/pull/4962) ([tas50](https://github.com/tas50))
+- Load cookbook versions correctly for knife [\#4936](https://github.com/chef/chef/pull/4936) ([thommay](https://github.com/thommay))
+- Gem metadata command needs Gem.clear\_paths [\#4929](https://github.com/chef/chef/pull/4929) ([lamont-granquist](https://github.com/lamont-granquist))
+- Fix os x profile provider for nil [\#4921](https://github.com/chef/chef/pull/4921) ([achand](https://github.com/achand))
+- Cookbook site install : tar error on windows [\#4867](https://github.com/chef/chef/pull/4867) ([willoucom](https://github.com/willoucom))
+- Fix yum\_package breakage \(the =~ operator in ruby is awful\) [\#4912](https://github.com/chef/chef/pull/4912) ([lamont-granquist](https://github.com/lamont-granquist))
+- Encode registry enumerated values and keys to utf8 instead of the local codepage [\#4906](https://github.com/chef/chef/pull/4906) ([mwrock](https://github.com/mwrock))
+- Chocolatey Package Provider chomps nil object [\#4760](https://github.com/chef/chef/pull/4760) ([svmastersamurai](https://github.com/svmastersamurai))
+- Fixes knife ssl check on windows [\#4886](https://github.com/chef/chef/pull/4886) ([mwrock](https://github.com/mwrock))
+
+## [v12.10.24](https://github.com/chef/chef/tree/v12.10.24) (2016-04-27)
+[Full Changelog](https://github.com/chef/chef/compare/v12.10.23...v12.10.24)
+
+**Fixed Bugs:**
+
+- Removing non-existent members from group should not fail [\#4812](https://github.com/chef/chef/pull/4812) ([chefsalim](https://github.com/chefsalim))
+- The easy\_install provider and resource are deprecated and will be removed in Chef 13 [\#4860](https://github.com/chef/chef/pull/4860) ([coderanger](https://github.com/coderanger))
+
+**Tech cleanup:**
+
+- Refactor ChefFS files to be files [\#4837](https://github.com/chef/chef/pull/4837) ([thommay](https://github.com/thommay))
+- Rename and add backcompat requires for ChefFS dirs [\#4830](https://github.com/chef/chef/pull/4830) ([thommay](https://github.com/thommay))
+- Refactor ChefFS directories to be directories [\#4826](https://github.com/chef/chef/pull/4826) ([thommay](https://github.com/thommay))
+- Move all ChefFS exceptions into a single file [\#4822](https://github.com/chef/chef/pull/4822) ([thommay](https://github.com/thommay))
+
+**Enhancements:**
+
+- Add layout option support for device creation to mdadm resource provider [\#4855](https://github.com/chef/chef/pull/4855) ([kbruner](https://github.com/kbruner))
+- add notifying\_block and subcontext\_block to chef [\#4818](https://github.com/chef/chef/pull/4818) ([lamont-granquist](https://github.com/lamont-granquist))
+- modernize shell\_out method syntax [\#4865](https://github.com/chef/chef/pull/4865) ([lamont-granquist](https://github.com/lamont-granquist))
+- Update rubygems provider to support local install of gems if so specified [\#4847](https://github.com/chef/chef/pull/4847) ([PrajaktaPurohit](https://github.com/PrajaktaPurohit))
+- fix details in with\_run\_context [\#4839](https://github.com/chef/chef/pull/4839) ([lamont-granquist](https://github.com/lamont-granquist))
+- Lock dependencies of chef through a `Gemfile.lock` [\#4820](https://github.com/chef/chef/pull/4820) ([jkeiser](https://github.com/jkeiser))
+- add better resource manipulation API [\#4834](https://github.com/chef/chef/pull/4834) ([lamont-granquist](https://github.com/lamont-granquist))
+- add nillable apt\_repository and nillable properties [\#4832](https://github.com/chef/chef/pull/4832) ([lamont-granquist](https://github.com/lamont-granquist))
+
+## [v12.9](https://github.com/chef/chef/tree/v12.9.38) (2016-04-09)
+[Full Changelog](https://github.com/chef/chef/compare/v12.8.2...v12.9.38)
+
+**Implemented enhancements:**
+
+- Sftp remote file support [\#4750](https://github.com/chef/chef/pull/4750) ([jkerry](https://github.com/jkerry))
+- Setting init\_command should be accepted instead of specific command overrides [\#4709](https://github.com/chef/chef/pull/4709) ([coderanger](https://github.com/coderanger))
+- Add a NoOp provider [\#4798](https://github.com/chef/chef/pull/4798) ([thommay](https://github.com/thommay))
+- Add ability to notify from inside LWRP to wrapping resource\_collections [\#4017](https://github.com/chef/chef/issues/4017)
+- Notifications from LWRPS/sub-resources can trigger resources in outer run\_context scopes [\#4741](https://github.com/chef/chef/pull/4741) ([lamont-granquist](https://github.com/lamont-granquist))
+- Improve the docs generated by knife cookbook create [\#4757](https://github.com/chef/chef/pull/4757) ([tas50](https://github.com/tas50))
+- Need Config/CLI options to move interval+splay sleep to end of client loop [\#3305](https://github.com/chef/chef/issues/3305)
+- Add optional integer argument for --daemonize option [\#4759](https://github.com/chef/chef/pull/4759) ([jrunning](https://github.com/jrunning))
+- Add shorthand :syslog and :win\_evt for log\_location config [\#4751](https://github.com/chef/chef/pull/4751) ([jrunning](https://github.com/jrunning))
+
+**Fixed bugs:**
+
+- chef\_gem and gem metadata don't play well [\#4710](https://github.com/chef/chef/issues/4710)
+- Fix cookbook metadata 'gem' command to make it useful [\#4809](https://github.com/chef/chef/pull/4809) ([lamont-granquist](https://github.com/lamont-granquist))
+- Convert timeout config to integer [\#4787](https://github.com/chef/chef/pull/4787) ([chefsalim](https://github.com/chefsalim))
+- The mount resource is not idempotent on windows [\#3861](https://github.com/chef/chef/issues/3861)
+- fix for \#4715 - unset TMPDIR in homebrew package provider [\#4716](https://github.com/chef/chef/pull/4716) ([gips0n](https://github.com/gips0n))
+- tons of "Deprecation class overwrites LWRP resource" WARNING SPAM with chefspec [\#4668](https://github.com/chef/chef/issues/4668)
+
+**Merged pull requests:**
+
+- Add apt\_repository resource [\#4782](https://github.com/chef/chef/pull/4782) ([thommay](https://github.com/thommay))
+- Point to the right license file for chef. [\#4811](https://github.com/chef/chef/pull/4811) ([sersut](https://github.com/sersut))
+- add omnibus license metadata [\#4805](https://github.com/chef/chef/pull/4805) ([patrick-wright](https://github.com/patrick-wright))
+- Add default timeout [\#4804](https://github.com/chef/chef/pull/4804) ([chefsalim](https://github.com/chefsalim))
+- Spec break on Windows due to temp dir and short path names [\#4776](https://github.com/chef/chef/pull/4776) ([adamedx](https://github.com/adamedx))
+- Require chef/version since it's used here [\#4762](https://github.com/chef/chef/pull/4762) ([jkeiser](https://github.com/jkeiser))
+- remove pry from rbx build [\#4761](https://github.com/chef/chef/pull/4761) ([lamont-granquist](https://github.com/lamont-granquist))
+- ruby 2.0.0 is EOL [\#4752](https://github.com/chef/chef/pull/4752) ([lamont-granquist](https://github.com/lamont-granquist))
+- supresses parser gem errors [\#4755](https://github.com/chef/chef/pull/4755) ([lamont-granquist](https://github.com/lamont-granquist))
+- Set inherit=false on the fallback provider constant lookup. [\#4753](https://github.com/chef/chef/pull/4753) ([coderanger](https://github.com/coderanger))
+
+**Closed issues:**
+
+- Uploading an encrypted data bag to Chef server fails [\#4815](https://github.com/chef/chef/issues/4815)
+- powershell\_script does not have PSCredential capability [\#4589](https://github.com/chef/chef/issues/4589)
+- Documentation don't include how to setup mail server during deployment of Chef server [\#4807](https://github.com/chef/chef/issues/4807)
+- Resource 'mount' and chef 12.5.1 [\#4056](https://github.com/chef/chef/issues/4056)
+- Incorrect $TMPDIR environment variable on OS X [\#4715](https://github.com/chef/chef/issues/4715)
+- group provider on suse Linux adds user multiple times [\#4689](https://github.com/chef/chef/issues/4689)
+- Unexpected error when using "knife cookbook show ...." [\#4659](https://github.com/chef/chef/issues/4659)
+
+## [12.8.1](https://github.com/chef/chef/tree/12.8.1) (2016-03-07)
+[Full Changelog](https://github.com/chef/chef/compare/12.7.2...12.8.1)
+
+**Implemented enhancements:**
+
+- Clarify the probable cause of tempfile creation failure during cookbook sync [\#2171](https://github.com/chef/chef/issues/2171)
+- Remove static libraries from Chef package [\#4654](https://github.com/chef/chef/pull/4654) ([chefsalim](https://github.com/chefsalim))
+- Have client.rb verify that FIPS mode can be enforced [\#4630](https://github.com/chef/chef/pull/4630) ([ksubrama](https://github.com/ksubrama))
+- List all of the unignored files when loading a cookbook [\#4629](https://github.com/chef/chef/pull/4629) ([danielsdeleo](https://github.com/danielsdeleo))
+- adding pry and pry-byebug to dev dependencies [\#4601](https://github.com/chef/chef/pull/4601) ([mwrock](https://github.com/mwrock))
+- Split group members on commas [\#4583](https://github.com/chef/chef/pull/4583) ([thommay](https://github.com/thommay))
+- Make tempfiles easier to read \(prepend chef to the name\) [\#4582](https://github.com/chef/chef/pull/4582) ([thommay](https://github.com/thommay))
+- Extend cookbook shadowing deprecation warnings more broadly [\#4574](https://github.com/chef/chef/pull/4574) ([lamont-granquist](https://github.com/lamont-granquist))
+- tell knife's edit\_data what the object is [\#4548](https://github.com/chef/chef/pull/4548) ([thommay](https://github.com/thommay))
+- Implement knife bootstrap client.d RFC [\#4529](https://github.com/chef/chef/pull/4529) ([jaym](https://github.com/jaym))
+- Update to Log Level when showing unencrypted databag [\#4524](https://github.com/chef/chef/pull/4524) ([PatrickWalker](https://github.com/PatrickWalker))
+- RFC-060 gem metadata MVP [\#4478](https://github.com/chef/chef/pull/4478) ([lamont-granquist](https://github.com/lamont-granquist))
+- chef-client: add --\[no\]skip-cookbook-sync option [\#4316](https://github.com/chef/chef/pull/4316) ([josb](https://github.com/josb))
+- Extend service resource to support masking [\#4307](https://github.com/chef/chef/pull/4307) ([davide125](https://github.com/davide125))
+- launchd for osx [\#4111](https://github.com/chef/chef/pull/4111) ([mikedodge04](https://github.com/mikedodge04))
+
+**Fixed bugs:**
+
+- Chef::DataBagItem.to\_hash is modifying Chef::DataBagItem.raw\_data [\#4614](https://github.com/chef/chef/issues/4614)
+- Chef 12 seeing a ton of these in debug mode [\#2396](https://github.com/chef/chef/issues/2396)
+- Data bag item hash can have name key [\#4664](https://github.com/chef/chef/pull/4664) ([chefsalim](https://github.com/chefsalim))
+- Clearer exception for loading non-existent data bag items in solo mode. [\#4655](https://github.com/chef/chef/pull/4655) ([coderanger](https://github.com/coderanger))
+- Always rehash from gem source and not existing hash file [\#4651](https://github.com/chef/chef/pull/4651) ([tyler-ball](https://github.com/tyler-ball))
+- Handle negative content length headers too. [\#4646](https://github.com/chef/chef/pull/4646) ([coderanger](https://github.com/coderanger))
+- if no module name is found for a valid dsc resource default to PSDesiredStateConfiguration [\#4638](https://github.com/chef/chef/pull/4638) ([mwrock](https://github.com/mwrock))
+- removing disabling of readline in chef-shell [\#4635](https://github.com/chef/chef/pull/4635) ([mwrock](https://github.com/mwrock))
+- Fix a bug that was causing DataBagItem.to\_hash to mutate the data bag item [\#4631](https://github.com/chef/chef/pull/4631) ([itmustbejj](https://github.com/itmustbejj))
+- ensure paths maintain utf-8ness in non ascii encodings [\#4626](https://github.com/chef/chef/pull/4626) ([mwrock](https://github.com/mwrock))
+- Fix the Chocolatey-missing error again [\#4621](https://github.com/chef/chef/pull/4621) ([randomcamel](https://github.com/randomcamel))
+- fixes exe package downloads [\#4612](https://github.com/chef/chef/pull/4612) ([mwrock](https://github.com/mwrock))
+- fallback to netmsg.dll error table if error message is not found in system errors [\#4600](https://github.com/chef/chef/pull/4600) ([mwrock](https://github.com/mwrock))
+- zypper multipackage performance fix [\#4591](https://github.com/chef/chef/pull/4591) ([lamont-granquist](https://github.com/lamont-granquist))
+- bugfix \#2865 check for validation\_key [\#4581](https://github.com/chef/chef/pull/4581) ([thommay](https://github.com/thommay))
+- remove bogus recalculation of cookbook upload failures [\#4580](https://github.com/chef/chef/pull/4580) ([thommay](https://github.com/thommay))
+- Make sure we have a valid object before calling close! [\#4579](https://github.com/chef/chef/pull/4579) ([thommay](https://github.com/thommay))
+- Fix policyfile\_zero provisioner in 12.7 [\#4571](https://github.com/chef/chef/pull/4571) ([andy-dufour](https://github.com/andy-dufour))
+- do not include source parameter when removing a chocolatey package and ensure source is used on all functional tests [\#4570](https://github.com/chef/chef/pull/4570) ([mwrock](https://github.com/mwrock))
+- Fix databag globbing issues for chef-solo on windows [\#4569](https://github.com/chef/chef/pull/4569) ([jaym](https://github.com/jaym))
+- remove Chef::Mixin::Command use [\#4566](https://github.com/chef/chef/pull/4566) ([lamont-granquist](https://github.com/lamont-granquist))
+
+## 12.7.2
+
+* [pr#4559](https://github.com/chef/chef/pull/4559) Remove learnchef acceptance tests until we make them more reliable
+* [pr#4545](https://github.com/chef/chef/pull/4545) Removing rm -rf in chef-solo recipe_url
+
+## 12.7.1
+* [**Daniel Steen**](https://github.com/dansteen)
+ * [pr#3183](https://github.com/chef/chef/pull/3183) Provide more helpful error message when accidentally using --secret instead of --secret-file
+
+* [pr#4532](https://github.com/chef/chef/pull/4532) Bump Bundler + Rubygems
+* [pr#4550](https://github.com/chef/chef/pull/4550) Use a streaming request to download cookbook
+
+## 12.7.0
+
+* [**Nate Walck**](https://github.com/natewalck)
+ * [pr#4078](https://github.com/chef/chef/pull/4078) Add `osx_profile` resource for OS X
+* [**Timothy Cyrus**](https://github.com/tcyrus)
+ * [pr#4420](https://github.com/chef/chef/pull/4420) Update code climate badge and code climate blocks in README.md
+* [**Jordan Running**](https://github.com/jrunning)
+ * [pr#4399](https://github.com/chef/chef/pull/4399) Correctly save policy_name and policy_group with `knife node edit`
+* [**Brian Goad**](https://github.com/bbbco)
+ * [pr#4315](https://github.com/chef/chef/pull/4315) Add extra tests around whether to skip with multiple guards
+
+* [pr#4516](https://github.com/chef/chef/pull/4516) Return propper error messages when using windows based `mount`, `user` and `group` resources
+* [pr#4500](https://github.com/chef/chef/pull/4500) Explicitly declare directory permissions of chef install on windows to restrict rights on Windows client versions
+* [pr#4498](https://github.com/chef/chef/pull/4498) Correct major and minor OS versions for Windows 10 and add versions for Windows 2016 Server
+* [pr#4375](https://github.com/chef/chef/pull/4375) No longer try to auto discover package version of `exe` based windows packages
+* [pr#4369](https://github.com/chef/chef/pull/4396) Import omnibus-chef chef project definition and history
+* [pr#4399](https://github.com/chef/chef/pull/4399) Correctly save `policy_name` and `policy_group` with `knife node edit`
+* [pr#4278](https://github.com/chef/chef/pull/4278) make file resource use properties
+* [pr#4479](https://github.com/chef/chef/pull/4479) Remove incorrect cookbook artifact normalization
+* [pr#4470](https://github.com/chef/chef/pull/4470) Fix sh spacing issues
+* [pr#4434](https://github.com/chef/chef/pull/4434) adds EOFError message to handlers
+* [pr#4422](https://github.com/chef/chef/pull/4422) Add an apt_update resource
+* [pr#4287](https://github.com/chef/chef/pull/4287) Default Chef with FIPS OpenSSL to use sign v1.3
+* [pr#4461](https://github.com/chef/chef/pull/4461) debian-6 is EOL next month
+* [pr#4460](https://github.com/chef/chef/pull/4460) Set range of system user/group id to max of 200
+* [pr#4231](https://github.com/chef/chef/pull/4231) zypper multipackage patch
+* [pr#4459](https://github.com/chef/chef/pull/4459) use require_paths and not path so bundler grabs all paths from a git reference
+* [pr#4450](https://github.com/chef/chef/pull/4450) don't warn about ambiguous property usage
+* [pr#4445](https://github.com/chef/chef/pull/4445) Add CBGB to the repository
+* [pr#4423](https://github.com/chef/chef/pull/4423) Add deprecation warnings to Chef::REST and all json_creates
+* [pr#4439](https://github.com/chef/chef/pull/4439) Sometimes chocolately doesn't appear on the path
+* [pr#4432](https://github.com/chef/chef/pull/4432) add get_rest etc calls to ServerAPI
+* [pr#4435](https://github.com/chef/chef/pull/4435) add nokogiri to omnibus-chef
+* [pr#4419](https://github.com/chef/chef/pull/4419) explicitly adding .bat to service executable called by service in case users remove .bat from PATHEXT
+* [pr#4413](https://github.com/chef/chef/pull/4413) configure chef client windows service to the correct chef directory
+* [pr#4377](https://github.com/chef/chef/pull/4377) fixing candidate filtering and adding functional tests for chocolatey_package
+* [pr#4406](https://github.com/chef/chef/pull/4406) Updating to the latest release of net-ssh to consume https://github.com/net-ssh/net-ssh/pull/280
+* [pr#4405](https://github.com/chef/chef/pull/4405) ServerAPI will return a raw hash, so do that
+* [pr#4400](https://github.com/chef/chef/pull/4400) inflate an environment after loading it
+* [pr#4396](https://github.com/chef/chef/pull/4396) Remove duplicate initialization of @password in user_v1
+* [pr#4344](https://github.com/chef/chef/pull/4344) Warn (v. info) when reloading resources
+* [pr#4369](https://github.com/chef/chef/pull/4369) Migrate omnibus-chef project/software definitions for chef in here
+* [pr#4106](https://github.com/chef/chef/pull/4106) add chocolatey_package to core chef
+* [pr#4321](https://github.com/chef/chef/pull/4321) fix run_as_user of windows_service
+* [pr#4333](https://github.com/chef/chef/pull/4333) no longer wait on node search to refresh vault but pass created ApiCient instead
+* [pr#4325](https://github.com/chef/chef/pull/4325) Pin win32-eventlog to 0.6.3 to avoid clashing CreateEvent definition
+* [pr#4312](https://github.com/chef/chef/pull/4312) Updates the template to use omnitruck-direct.chef.io
+* [pr#4277](https://github.com/chef/chef/pull/4277) non msi packages must explicitly provide a source attribute on install
+* [pr#4309](https://github.com/chef/chef/pull/4309) tags always an array; fix set_unless
+* [pr#4278](https://github.com/chef/chef/pull/4278) make file resource use properties
+* [pr#4288](https://github.com/chef/chef/pull/4288) Fix no_proxy setting in chef-config
+* [pr#4273](https://github.com/chef/chef/pull/4273) Use signing protocol 1.1 by default
+* [pr#4520](https://github.com/chef/chef/pull/4520) Fix a few `dsc_resource` bugs
+
+## 12.6.0
+
+* [**Dave Eddy**](https://github.com/bahamas10)
+ [pr#3187](https://github.com/chef/chef/pull/3187) overhaul solaris SMF service provider
+* [**Mikhail Zholobov**](https://github.com/legal90)
+ - [pr#3192](https://github.com/chef/chef/pull/3192) provider/user/dscl: Set default gid to 20
+ - [pr#3193](https://github.com/chef/chef/pull/3193) provider/user/dscl: Set "comment" default value
+* [**Jordan Evans**](https://github.com/jordane)
+ - [pr#3263](https://github.com/chef/chef/pull/3263) `value_for_platform` should use `Chef::VersionConstraint::Platform`
+ - [pr#3633](https://github.com/chef/chef/pull/3633) add the word group to `converge_by` call for group provider
+* [**Scott McGillivray**](https://github.com/thechile)
+ [pr#3450](https://github.com/chef/chef/pull/3450) Fix 'knife cookbook show' to work on root files
+* [**Aubrey Holland**](https://github.com/aub)
+ [pr#3986](https://github.com/chef/chef/pull/3986) fix errors when files go away during chown
+* [**James Michael DuPont**](https://github.com/h4ck3rm1k3)
+ [pr#3973](https://github.com/chef/chef/pull/3973) better error reporting
+* [**Michael Pereira**](https://github.com/MichaelPereira)
+ [pr#3968](https://github.com/chef/chef/pull/3968) Fix cookbook installation from supermarket on windows
+* [**Yukihiko SAWANOBORI**](https://github.com/sawanoboly)
+ - [pr#3941](https://github.com/chef/chef/pull/3941) allow reboot by reboot resource with chef-apply
+ - [pr#3900](https://github.com/chef/chef/pull/3900) Add new option json attributes file to bootstraping
+* [**permyakovsv**](https://github.com/permyakovsv)
+ [pr#3901](https://github.com/chef/chef/pull/3901) Add tmux-split parameter to knife ssh
+* [**Evan Gilman**](https://github.com/evan2645)
+ [pr#3864](https://github.com/chef/chef/pull/3864) Knife `bootstrap_environment` should use Explicit config before Implicit
+* [**Ranjib Dey**](https://github.com/ranjib)
+ [pr#3834](https://github.com/chef/chef/pull/3834) Dont spit out stdout and stderr for execute resource failure, if its declared sensitive
+* [**Jeff Blaine**](https://github.com/jblaine)
+ - [pr#3776](https://github.com/chef/chef/pull/3776) Changes --hide-healthy to --hide-by-mins MINS
+ - [pr#3848](https://github.com/chef/chef/pull/3848) Migrate to --ssh-identity-file instead of --identity-file
+* [**dbresson**](https://github.com/dbresson)
+ [pr#3650](https://github.com/chef/chef/pull/3650) Define == for node objects
+* [**Patrick Connolly**](https://github.com/patcon)
+ [pr#3529](https://github.com/chef/chef/pull/3529) Allow user@hostname format for knife-bootstrap
+* [**Justin Seubert**](https://github.com/dude051)
+ [pr#4160](https://github.com/chef/chef/pull/4160) Correcting regex for upstart_state
+* [**Sarah Michaelson**](https://github.com/skmichaelson)
+ [pr#3810](https://github.com/chef/chef/pull/3810) GH-1909 Add validation for chef_server_url
+* [**Maxime Brugidou**](https://github.com/brugidou)
+ [pr#4052](https://github.com/chef/chef/pull/4052) Add make_child_entry in ChefFS CookbookSubdir
+* [**Nathan Williams**](https://github.com/nathwill)
+ [pr#3836](https://github.com/chef/chef/pull/3836) simplify service helpers
+* [**Paul Welch**](https://github.com/pwelch)
+ [pr#4066](https://github.com/chef/chef/pull/4066) Fix chef-apply usage banner
+* [**Mat Schaffer**](https://github.com/matschaffer)
+ [pr#4153](https://github.com/chef/chef/pull/4153) Require ShellOut before Knife::SSH definition
+* [**Donald Guy**](https://github.com/donaldguy)
+ [pr#4158](https://github.com/chef/chef/pull/4158) Allow named_run_list to be loaded from config
+* [**Jos Backus**](https://github.com/josb)
+ [pr#4064](https://github.com/chef/chef/pull/4064) Ensure that tags are properly initialized
+* [**John Bellone**](https://github.com/johnbellone)
+ [pr#4101](https://github.com/chef/chef/pull/4101) Adds alias method upgrade_package for solaris package
+* [**Nolan Davidson**](https://github.com/nsdavidson)
+ [pr#4014](https://github.com/chef/chef/pull/4014) Adding ksh resource
+
+* [pr#4193](https://github.com/chef/chef/pull/4196) support for inno, nsis, wise and installshield installer types in windows_package resource
+* [pr#4196](https://github.com/chef/chef/pull/4196) multipackage dpkg_package and bonus fixes
+* [pr#4185](https://github.com/chef/chef/pull/4185) dpkg provider cleanup
+* [pr#4165](https://github.com/chef/chef/pull/4165) Multipackage internal API improvements
+* [pr#4081](https://github.com/chef/chef/pull/4081) RFC-037: add `chef_version` and `ohai_version` metadata
+* [pr#3530](https://github.com/chef/chef/pull/3530) Allow using --sudo option with user's home folder in knife bootstrap
+* [pr#3858](https://github.com/chef/chef/pull/3858) Remove duplicate 'Accept' header in spec
+* [pr#3911](https://github.com/chef/chef/pull/3911) Avoid subclassing Struct.new
+* [pr#3990](https://github.com/chef/chef/pull/3990) Use SHA256 instead of MD5 for `registry_key` when data is not displayable
+* [pr#4034](https://github.com/chef/chef/pull/4034) add optional ruby-profiling with --profile-ruby
+* [pr#3119](https://github.com/chef/chef/pull/3119) allow removing user, even if their GID isn't resolvable
+* [pr#4068](https://github.com/chef/chef/pull/4068) update messaging from LWRP to Custom Resource in logging and spec
+* [pr#4021](https://github.com/chef/chef/pull/4021) add missing requires for Chef::DSL::Recipe to LWRPBase
+* [pr#3597](https://github.com/chef/chef/pull/3597) print STDOUT from the powershell_script
+* [pr#4091](https://github.com/chef/chef/pull/4091) Allow downloading of root_files in a chef repository
+* [pr#4112](https://github.com/chef/chef/pull/4112) Update knife bootstrap command to honor --no-color flag in chef-client run that is part of the bootstrap process.
+* [pr#4090](https://github.com/chef/chef/pull/4090) Improve detection of ChefFS-based commands in `knife rehash`
+* [pr#3991](https://github.com/chef/chef/pull/3991) Modify remote_file cache_control_data to use sha256 for its name
+* [pr#4079](https://github.com/chef/chef/pull/4079) add logger to windows service shellout
+* [pr#3966](https://github.com/chef/chef/pull/3966) Report expanded run list json tree to reporting
+* [pr#4080](https://github.com/chef/chef/pull/4080) Make property modules possible
+* [pr#4069](https://github.com/chef/chef/pull/4069) Improvements to log messages
+* [pr#4049](https://github.com/chef/chef/pull/4049) Add gemspec files to allow bundler to run from the gem
+* [pr#4029](https://github.com/chef/chef/pull/4029) Fix search result pagination
+* [pr#4048](https://github.com/chef/chef/pull/4048) Accept coercion as a way to accept nil values
+* [pr#4046](https://github.com/chef/chef/pull/4046) ignore gid in the user resource on windows
+* [pr#4118](https://github.com/chef/chef/pull/4118) Make Property.derive create derived properties of the same type
+* [pr#4133](https://github.com/chef/chef/pull/4133) Add retries to `Chef::HTTP` for transient SSL errors
+* [pr#4135](https://github.com/chef/chef/pull/4135) Windows service uses log file location from config if none is given on commandline
+* [pr#4142](https://github.com/chef/chef/pull/4142) Use the proper python interpretor for yum-dump.py on Fedora 21
+* [pr#4149](https://github.com/chef/chef/pull/4149) Handle nil run list option in knife bootstrap
+* [pr#4040](https://github.com/chef/chef/pull/4040) Implement live streaming for execute resources
+* [pr#4167](https://github.com/chef/chef/pull/4167) Add `reboot_action` to `dsc_resource`
+* [pr#4167](https://github.com/chef/chef/pull/4167) Allow `dsc_resource` to run with the LCM enabled
+* [pr#4188](https://github.com/chef/chef/pull/4188) Update `dsc_resource` to use verbose stream output
+* [pr#4200](https://github.com/chef/chef/pull/4200) Prevent inspect of PsCredential from printing out plain text password
+* [pr#4237](https://github.com/chef/chef/pull/4237) Enabling 'knife ssl check/fetch' commands to respect proxy environment variables and moving proxy environment variables export to Chef::Config
+## 12.5.1
+
+* [**Ranjib Dey**](https://github.com/ranjib):
+ [pr#3588](https://github.com/chef/chef/pull/3588) Count skipped resources among total resources in doc formatter
+* [**John Kerry**](https://github.com/jkerry):
+ [pr#3539](https://github.com/chef/chef/pull/3539) Fix issue: registry\_key resource is case sensitive in chef but not on windows
+* [**David Eddy**](https://github.com/bahamas10):
+ - [pr#3443](https://github.com/chef/chef/pull/3443) remove extraneous space
+ - [pr#3091](https://github.com/chef/chef/pull/3091) fix locking/unlocking users on SmartOS
+* [**margueritepd**](https://github.com/margueritepd):
+ [pr#3693](https://github.com/chef/chef/pull/3693) Interpolate `%{path}` in verify command
+* [**Jeremy Fleischman**](https://github.com/jfly):
+ [pr#3383](https://github.com/chef/chef/pull/3383) gem\_package should install to the systemwide Ruby when using ChefDK
+* [**Stefano Rivera**](https://github.com/stefanor):
+ [pr#3657](https://github.com/chef/chef/pull/3657) fix upstart status\_commands
+* [**ABE Satoru**](https://github.com/polamjag):
+ [pr#3764](https://github.com/chef/chef/pull/3764) uniquify chef\_repo\_path
+* [**Renan Vicente**](https://github.com/renanvicente):
+ [pr#3771](https://github.com/chef/chef/pull/3771) add depth property for deploy resource
+* [**James Belchamber**](https://github.com/JamesBelchamber):
+ [pr#1796](https://github.com/chef/chef/pull/1796): make mount options aware
+* [**Nate Walck**](https://github.com/natewalck):
+ - [pr#3594](https://github.com/chef/chef/pull/3594): Update service provider for OSX 10.11
+ - [pr#3704](https://github.com/chef/chef/pull/3704): Add SIP (OS X 10.11) support
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+ [pr#3805](https://github.com/chef/chef/pull/3805) LWRP parameter validators should use truthiness
+* [**Igor Shpakov**](https://github.com/Igorshp):
+ [pr#3743](https://github.com/chef/chef/pull/3743) speed improvement for `remote_directory` resource
+* [**James FitzGibbon**](https://github.com/jf647):
+ [pr#3027](https://github.com/chef/chef/pull/3027) Add warnings to 'knife node run list remove ...'
+* [**Backslasher**](https://github.com/backslasher):
+ [pr#3172](https://github.com/chef/chef/pull/3172) Migrated deploy resource to use shell\_out instead of run\_command
+* [**Sean Walberg**](https://github.com/swalberg):
+ [pr#3190](https://github.com/chef/chef/pull/3190) Allow tags to be set on a node during bootstrap
+* [**ckaushik**](https://github.com/ckaushik) and [**Sam Dunne**](https://github.com/samdunne):
+ [pr#3510](https://github.com/chef/chef/pull/3510) Fix broken rendering
+of partial templates.
+* [**Simon Detheridge**](https://github.com/gh2k):
+ [pr#3806](https://github.com/chef/chef/pull/3806) Replace output\_of\_command with shell\_out! in subversion provider
+* [**Joel Handwell**](https://github.com/joelhandwell):
+ [pr#3821](https://github.com/chef/chef/pull/3821) Human friendly elapsed time in log
+
+* [pr#3985](https://github.com/chef/chef/pull/3985) Simplify the regex which determines the rpm version to resolve issue #3671
+* [pr#3928](https://github.com/chef/chef/pull/3928) Add named run list support when using policyfiles
+* [pr#3913](https://github.com/chef/chef/pull/3913) Add `policy_name`and `policy_group` fields to the node object
+* [pr#3875](https://github.com/chef/chef/pull/3875) Patch Win32::Registry#delete_key, #delete_value to use wide (W) APIs
+* [pr#3850](https://github.com/chef/chef/pull/3850) Patch Win32::Registry#write to fix encoding errors
+* [pr#3837](https://github.com/chef/chef/pull/3837) refactor remote_directory provider for mem+perf improvement
+* [pr#3799](https://github.com/chef/chef/pull/3799) fix supports hash issues in service providers
+* [pr#3797](https://github.com/chef/chef/pull/3797) Fix dsc_script spec failure on 64-bit Ruby
+* [pr#3817](https://github.com/chef/chef/pull/3817) Remove now-useless forcing of ruby Garbage Collector run
+* [pr#3775](https://github.com/chef/chef/pull/3775) Enable 64-bit support for Powershell and Batch scripts
+* [pr#3774](https://github.com/chef/chef/pull/3774) Add support for yum-deprecated in yum provider
+* [pr#3793](https://github.com/chef/chef/pull/3793) CHEF-5372: Support specific `run_levels` for RedHat service
+* [pr#2460](https://github.com/chef/chef/pull/2460) add privacy flag
+* [pr#1259](https://github.com/chef/chef/pull/1259) CHEF-5012: add methods for template breadcrumbs
+* [pr#3656](https://github.com/chef/chef/pull/3656) remove use of self.provides?
+* [pr#3455](https://github.com/chef/chef/pull/3455) powershell\_script: do not allow suppression of syntax errors
+* [pr#3519](https://github.com/chef/chef/pull/3519) The wording seemed odd.
+* [pr#3208](https://github.com/chef/chef/pull/3208) Missing require (require what you use).
+* [pr#3449](https://github.com/chef/chef/pull/3449) correcting minor typo in user\_edit knife action
+* [pr#3572](https://github.com/chef/chef/pull/3572) Use windows paths without case-sensitivity.
+* [pr#3666](https://github.com/chef/chef/pull/3666) Support SNI in `knife ssl check`.
+* [pr#3667](https://github.com/chef/chef/pull/3667) Change chef service to start as 'Automatic delayed start'.
+* [pr#3683](https://github.com/chef/chef/pull/3683) Correct Windows reboot command to delay in minutes, per the property.
+* [pr#3698](https://github.com/chef/chef/pull/3698) Add ability to specify dependencies in chef-service-manager.
+* [pr#3728](https://github.com/chef/chef/pull/3728) Rewrite NetLocalGroup things to use FFI
+* [pr#3754](https://github.com/chef/chef/pull/3754) Fix functional tests for group resource - fix #3728
+* [pr#3498](https://github.com/chef/chef/pull/3498) Use dpkg-deb directly rather than regex
+* [pr#3759](https://github.com/chef/chef/pull/3759) Repair service convergence test on AIX
+* [pr#3329](https://github.com/chef/chef/pull/3329) Use ifconfig target property
+* [pr#3652](https://github.com/chef/chef/pull/3652) Fix explanation for configuring audit mode in client.rb
+* [pr#3687](https://github.com/chef/chef/pull/3687) Add formatter and force-logger/formatter options to chef-apply
+* [pr#3768](https://github.com/chef/chef/pull/3768) Make reboot\_pending? look for CBS RebootPending
+* [pr#3815](https://github.com/chef/chef/pull/3815) Fix `powershell_script` validation to use correct architecture
+* [pr#3772](https://github.com/chef/chef/pull/3772) Add `ps_credential` dsl method to `dsc_script`
+* [pr#3462](https://github.com/chef/chef/pull/3462) Fix issue where `ps_credential` does not work over winrm
+
+## 12.4.1
+
+* [**Noah Kantrowitz**](https://github.com/coderanger):
+ [pr#3605](https://github.com/chef/chef/pull/3605) Rework `Resource#action` to match 12.3 API
+
+* [pr#3586](https://github.com/chef/chef/issues/3586) Fix bug preventing light weight resources from being used with heavy weight providers
+* [Issue #3593](https://github.com/chef/chef/issues/3593) Fix bug where provider priority map did not take into consideration a provided block
+* [pr#3630](https://github.com/chef/chef/pull/3630) Restore Chef::User and Chef::ApiClient namespace to API V0 functionality and move new functionality into Chef::UserV1 and Chef::ApiClientV1 until Chef 13.
+* [pr#3611](https://github.com/chef/chef/pull/3611) Call `provides?` even if `provides` is not called
+* [pr#3589](https://github.com/chef/chef/pull/3589) Fix errant bashisms
+* [pr#3620](https://github.com/chef/chef/pull/3620) Fix issue where recipe names in run list mutate when version constaints are present
+* [pr#3623](https://github.com/chef/chef/pull/3623) Allow LWRPs to access the real class when accessed through `Chef::Resource` and `Chef::Provider`
+* [pr#3627](https://github.com/chef/chef/pull/3627) Separate priority map and DSL handler map so that `provides` has veto power over priority
+* [pr#3638](https://github.com/chef/chef/pull/3638) Deprecate passing more than 1 argument to create a resource
+
+## 12.4.0
+
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+ Fix multipackage and architectures
+* [**Igor Shpakov**](https://github.com/Igorshp):
+ Always run exception handlers
+ Prioritise manual ssh attribute over automatic ones for knife
+* [**Noah Kantrowitz**](https://github.com/coderanger):
+ Cache service\_resource\_providers for the duration of the run. #2953
+* [**Slava Kardakov**](https://github.com/ojab):
+ Fix installation of yum packages with version constraints #3155
+* [**Dave Eddy**](https://github.com/bahamas10):
+ fix smartos\_package for new "pkgin" output, fixes #3112 #3165
+* [**Yukihiko SAWANOBORI**](https://github.com/sawanoboly):
+ Show Chef version on chef shell prompt
+* [**Jacob Minshall**](https://github.com/minshallj):
+ Ensure suid bit is preserved if group or owner changes
+* [**Tim Smith**](https://github.com/tas50):
+ Convert wiki links to point to docs.chef.io
+* [**SAWANOBORI Yukihiko**](https://github.com/sawanoboly):
+ Add Chef::Log::Syslog class for integrating sending logs to syslog
+* [**Pavel Yudin**](https://github.com/Kasen):
+ Ensure LWRP and HWRP @action variable is consistent #3156
+* [**Dan Bjorge**](https://github.com/dbjorge):
+ Fix bad Windows securable\_resource functional spec assumptions for default file owners/groups #3266
+* [**Yukihiko SAWANOBORI**](https://github.com/sawanoboly): Pass name by
+ knife cil attribute [pr#3195](https://github.com/chef/chef/pull/3195)
+* [**Torben Knerr**](https://github.com/tknerr):
+ Allow knife sub-command loader to match platform specific gems. [pr#3281](https://github.com/chef/chef/pull/3281)
+* [**Steve Lowe**](https://github.com/SteveLowe):
+ Fix copying ntfs dacl and sacl when they are nil. [pr#3066](https://github.com/chef/chef/pull/3066)
+
+* [pr#3339](https://github.com/chef/chef/pull/3339): Powershell command wrappers to make argument passing to knife/chef-client etc. easier.
+* [pr#3720](https://github.com/chef/chef/pull/3270): Extract chef's configuration to a separate gem. Code stays in the Chef git repo.
+* [pr#3321](https://github.com/chef/chef/pull/3321): Add an integration test of chef-client with empty ENV.
+* [pr#3278](https://github.com/chef/chef/pull/3278): Switch over Windows builds to universal builds.
+* [pr#2877](https://github.com/chef/chef/pull/2877): Convert bootstrap template to use sh.
+* [Issue #3316](https://github.com/chef/chef/issues/3316): Fix idempotency issues with the `windows_package` resource
+* [pr#3295](https://github.com/chef/chef/pull/3295): Stop mutating `new_resource.checksum` in file providers. Fixes some ChecksumMismatch exceptions like [issue#3168](https://github.com/chef/chef/issues/3168)
+* [pr#3320](https://github.com/chef/chef/pull/3320): Sanitize non-UTF8 characters in the node data before doing node.save(). Works around many UTF8 exception issues reported on node.save().
+* Implemented X-Ops-Server-API-Version with a API version of 0, as well as error handling when the Chef server does not support the API version that the client supports.
+* [pr#3327](https://github.com/chef/chef/pull/3327): Fix unreliable AIX service group parsing mechanism.
+* [pr#3333](https://github.com/chef/chef/pull/3333): Fix SSL errors when connecting to private Supermarkets
+* [pr#3340](https://github.com/chef/chef/pull/3340): Allow Event dispatch subscribers to be inspected.
+* [Issue #3055](https://github.com/chef/chef/issues/3055): Fix regex parsing for recipe failures on Windows
+* [pr#3345](https://github.com/chef/chef/pull/3345): Windows Event log logger
+* [pr#3336](https://github.com/chef/chef/pull/3336): Remote file understands UNC paths
+* [pr#3269](https://github.com/chef/chef/pull/3269): Deprecate automatic recipe DSL for classes in `Chef::Resource`
+* [pr#3360](https://github.com/chef/chef/pull/3360): Add check_resource_semantics! lifecycle method to provider
+* [pr#3344](https://github.com/chef/chef/pull/3344): Rewrite Windows user resouce code to use ffi instead of win32-api
+* [pr#3318](https://github.com/chef/chef/pull/3318): Modify Windows package provider to allow for url source
+* [pr#3381](https://github.com/chef/chef/pull/3381): warn on cookbook self-deps
+* [pr#2312](https://github.com/chef/chef/pull/2312): fix `node[:recipes]` duplication, add `node[:cookbooks]` and `node[:expanded_run_list]`
+* [pr#3325](https://github.com/chef/chef/pull/3325): enforce passing a node name with validatorless bootstrapping
+* [pr#3398](https://github.com/chef/chef/pull/3398): Allow spaces in files for the `remote_file` resource
+* [Issue #3010](https://github.com/chef/chef/issues/3010) Fixed `knife user` for use with current and future versions of Chef Server 12, with continued backwards compatible support for use with Open Source Server 11.
+* [pr#3438](https://github.com/chef/chef/pull/3438) Server API V1 support. Vast improvements to and testing expansion for Chef::User, Chef::ApiClient, and related knife commands. Deprecated Open Source Server 11 user support to the Chef::OscUser and knife osc_user namespace, but with backwards compatible support via knife user.
+* [Issue #2247](https://github.com/chef/chef/issues/2247): `powershell_script` returns 0 for scripts with syntax errors
+* [pr#3080](https://github.com/chef/chef/pull/3080): Issue 2247: `powershell_script` exit status should be nonzero for syntax errors
+* [pr#3441](https://github.com/chef/chef/pull/3441): Add `powershell_out` mixin to core chef
+* [pr#3448](https://github.com/chef/chef/pull/3448): Fix `dsc_resource` to work with wmf5 april preview
+* [pr#3392](https://github.com/chef/chef/pull/3392): Comment up `Chef::Client` and privatize/deprecate unused things
+* [pr#3419](https://github.com/chef/chef/pull/3419): Fix cli issue with `chef_repo_path` when ENV variable is unset
+* [pr#3358](https://github.com/chef/chef/pull/3358): Separate audit and converge failures
+* [pr#3431](https://github.com/chef/chef/pull/3431): Fix backups on windows for the file resource
+* [pr#3397](https://github.com/chef/chef/pull/3397): Validate owner exists in directory resources
+* [pr#3418](https://github.com/chef/chef/pull/3418): Add `shell_out` mixin to Chef::Resource class for use in `not_if`/`only_if` conditionals, etc.
+* [pr#3406](https://github.com/chef/chef/pull/3406): Add wide-char 'Environment' to `broadcast_env_change` mixin for setting windows environment variables
+* [pr#3442](https://github.com/chef/chef/pull/3442): Add `resource_name` to top-level Resource class to make defining resources easier.
+* [pr#3447](https://github.com/chef/chef/pull/3447): Add `allowed_actions` and `default_action` to top-level Resource class.
+* [pr#3475](https://github.com/chef/chef/pull/3475): Fix `shell_out` timeouts in all package providers to respect timeout property on the resource.
+* [pr#3477](https://github.com/chef/chef/pull/3477): Update `zypper_package` to look like the rest of our package classes.
+* [pr#3483](https://github.com/chef/chef/pull/3483): Allow `include_recipe` from LWRP providers.
+* [pr#3495](https://github.com/chef/chef/pull/3495): Make resource name automatically determined from class name, and provide DSL for it.
+* [pr#3497](https://github.com/chef/chef/pull/3497): Issue 3485: Corruption of node's run\_context when non-default guard\_interpreter is evaluated
+* [pr#3299](https://github.com/chef/chef/pull/3299): Remove experimental warning on audit mode
+
+## 12.3.0
+
+* [pr#3160](https://github.com/chef/chef/pull/3160): Use Chef Zero in
+ socketless mode for local mode, add `--no-listen` flag to disable port
+ binding
+* [**Nolan Davidson**](https://github.com/nsdavidson):
+ Removed after_created and added test to recipe_spec
+* [**Tim Sogard**](https://github.com/drags):
+ Reset $HOME to user running chef-client when running via sudo
+* [**Torben Knerr**](https://github.com/tknerr):
+ Allow for the chef gem installation to succeed without elevated privileges #3126
+* [**Mike Dodge**](https://github.com/mikedodge04)
+ MacOSX services: Load LaunchAgents as console user, adding plist and
+ session_type options.
+* [**Eric Herot**](https://github.com/eherot)
+ Ensure knife ssh doesn't use a non-existant field for hostname #3131
+* [**Tom Hughes**](https://github.com/tomhughes)
+ Ensure searches progress in the face of incomplete responses #3135
+
+* [pr#3162](https://github.com/chef/chef/pull/3162): Add
+ `--minimal-ohai` flag to client/solo/apply; restricts ohai to only the
+ bare minimum of plugins.
+* Ensure link's path attribute works with delayed #3130
+* gem_package, chef_gem should not shell out to using https://rubygems.org #2867
+* Add dynamic resource resolution similar to dynamic provider resolution
+* Add Chef class fascade to internal structures
+* Fix nil pointer for windows event logger #3200
+* Use partial search for knife status
+* Ensure chef/knife properly honours proxy config
+
+## 12.2.1
+* [Issue 3153](https://github.com/chef/chef/issues/3153): Fix bug where unset HOME would cause chef to crash
+
+## 12.2.0
+* Update policyfile API usage to match forthcoming Chef Server release
+* `knife ssh` now has an --exit-on-error option that allows users to
+ fail-fast rather than moving on to the next machine.
+* migrate macosx, windows, openbsd, and netbsd resources to dynamic resolution
+* migrate cron and mdadm resources to dynamic resolution
+* [Issue 3096](https://github.com/chef/chef/issues/3096) Fix OpenBSD package provider installation issues
+* New `dsc_resource` resource to invoke Powershell DSC resources
+
+## 12.1.2
+* [Issue 3022](https://github.com/chef/chef/issues/3022): Homebrew Cask install fails
+ FIXME (remove on 12.2.0 release): 3022 was only merged to 12-stable and #3077 or its descendant should fix this
+* [Issue 3059](https://github.com/chef/chef/issues/3059): Chef 12.1.1 yum_package silently fails
+* [Issue 3078](https://github.com/chef/chef/issues/3078): Compat break in audit-mode changes
+
+## 12.1.1
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+ [Issue 3008](https://github.com/chef/chef/issues/3008) Allow people to pass in `source` to package
+* [Issue 3011](https://github.com/chef/chef/issues/3011) `package` provider base should include
+ `Chef::Mixin::Command` as there are still providers that use it.
+* [**Ranjib Dey**](https://github.com/ranjib):
+ [Issue 3019](https://github.com/chef/chef/issues/3019) Fix data fetching when explicit attributes are passed
+
+## 12.1.0
+
+* [**Andre Elizondo**](https://github.com/andrewelizondo)
+ Typo fixes
+* [**Vasiliy Tolstov**](https://github.com/vtolstov):
+ cleanup cookbook path from stale files (when using chef-solo with a tarball url)
+* [**Nathan Cerny**](https://github.com/ncerny):
+ Fix rubygems provider to use https instead of http.
+* [**Anshul Sharma**](https://github.com/justanshulsharma)
+ removed securerandom patch
+* [**Scott Bonds**](https://github.com/bonds)
+ add package support for OpenBSD
+* [**Lucy Wyman**](https://github.com/lucywyman)
+ Added support for handling empty version strings to rubygems provider.
+* [**Yulian Kuncheff**](https://github.com/Daegalus)
+ Correctly set the pre-release identifier during knife bootstrap.
+* [**Anshul Sharma**](https://github.com/justanshulsharma)
+ `knife node run_list remove` now accepts run_list options in the same form as add
+* [**Veres Lajos**](https://github.com/vlajos)
+ Typo fixes
+* [**Tim Smith**](https://github.com/tas50)
+ Typo fixes
+* [Pull 2505](https://github.com/chef/chef/pull/2505) Make Chef handle URIs in a case-insensitive manner
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+ Drop SSL warnings now that we have a safe default
+* [Pull 2684](https://github.com/chef/chef/pull/2684) Remove ole_initialize/uninitialize which cause problems with Ruby >= 2
+* [**BinaryBabel**](https://github.com/binarybabel)
+ Make knife cookbook site share prefer gnutar when packaging
+* [**Dave Eddy**](https://github.com/bahamas10)
+ Support arrays for not_if and only_if
+* [**Scott Bonds**](https://github.com/bonds)
+ Add service provider for OpenBSD
+* [**Alex Slynko**](https://github.com/alex-slynko-wonga)
+ Change env provider to preserve ordering
+* [**Rob Redpath**](https://github.com/robredpath)
+ Add --lockfile opt for chef-client and chef-solo
+* [**Josh Murphy**](https://github.com/jdmurphy)
+ Check cookbooks exist in path(s) before attempting to upload them with --all
+* [**Vasiliy Tolstov**](https://github.com/vtolstov)
+ add ability to fetch recipes like in chef-solo when using local-mode
+* [**Jan**](https://github.com/habermann24)
+ FIX data_bag_item.rb:161: warning: circular argument reference - data_bag
+* [**David Radcliffe**](https://github.com/dwradcliffe)
+ add banner for knife serve command
+* [**Yukihiko Sawanobori**](https://github.com/sawanoboly)
+ use Chef::JSONCompat.parse for file_contents
+* [**Xabier de Zuazo**] (https://github.com/zuazo)
+ Remove some simple Ruby 1.8 and 1.9 code
+* [**Xabier de Zuazo**] (https://github.com/zuazo)
+ Remove all RSpec test filters related to Ruby 1.8 and 1.9
+* [**Xabier de Zuazo**] (https://github.com/zuazo)
+ Fix knife cookbook upload messages
+* [**David Crowder**] (https://github.com/david-crowder)
+ refactor to use shell_out in rpm provider
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+ Multi-package support
+* [**Naotoshi Seo**](https://github.com/sonots):
+ Support HTTP/FTP source on rpm_package
+ add json_attribs option for chef-apply command
+ allow_downgrade in rpm_package
+* [**AJ Christensen**](https://github.com/fujin):
+ Isolate/fix the no-fork fault. [Issue 2709](https://github.com/chef/chef/issues/2709)
+* [**Cory Stephenson**](https://github.com/Aevin1387):
+ Remove comments of a service being enabled/disabled in FreeBSD. [Fixes #1791](https://github.com/chef/chef/issues/1791)
+* [**Will Albenzi**](https://github.com/walbenzi):
+ CHEF-4591: Knife commands to manipulate env_run_list on nodes
+* [**Jon Cowie**](https://github.com/jonlives):
+ CHEF-2911: Fix yum_package provider to respect version requirements in package name and version attribute
+* [**Anshul Sharma**](https://github.com/justanshulsharma):
+ * Node::Attribute to_s should print merged attributes [Issue 1526](https://github.com/chef/chef/issues/1562)
+ * Access keys attribute in `knife show` list incorrect information [Issue 1974](https://github.com/chef/chef/issues/1974)
+ * Guard interpreter loading incorrect resource [Issue 2683](https://github.com/chef/chef/issues/2683)
+
+### Chef Contributions
+* ruby 1.9.3 support is dropped
+* Update Chef to use RSpec 3.2
+* Cleaned up script and execute provider + specs
+* Added deprecation warnings around the use of command attribute in script resources
+* Audit mode feature added - see the RELEASE_NOTES for details
+* shell_out now sets `LANGUAGE` and `LANG` to the `Chef::Config[:internal_locale]` in addition to `LC_ALL` forcing
+* chef_gem supports a compile_time flag and will warn if it is not set (behavior will change in the future)
+* suppress CHEF-3694 warnings on the most trivial resource cloning
+* fixed bugs in the deep_merge_cache logic introduced in 12.0.0 around `node['foo']` vs `node[:foo]` vs. `node.foo`
+* add `include_recipe "::recipe"` sugar to reference a recipe in the current cookbook
+* Add --proxy-auth option to `knife raw`
+* added Chef::Org model class for Chef Organizations in Chef 12 Server
+* `powershell_script` should now correctly get the exit code for scripts that it runs. See [Issue 2348](https://github.com/chef/chef/issues/2348)
+* Useradd functional tests fail randomly
+* Add comments to trusted_certs_content
+* fixes a bug where providers would not get defined if a top-level ruby constant with the same name was already defined (ark cookbook, chrome cookbook)
+* Fix a bug in `reboot`, `ips_package`, `paludis_package`, `windows_package` resources where `action :nothing` was not permitted
+* Use Chef::ApiClient#from_hash in `knife client create` to avoid json_class requirement. [Issue 2542](https://github.com/chef/chef/issues/2542)
+* Add support for policyfile native API (preview). These APIs are unstable, and you may be forced to delete data uploaded to them in a
+ future release, so only use them for demonstration purposes.
+* Deprecation warning for 'knife cookbook test'
+* dsc_script should now correctly honor timeout. See [Issue 2831](https://github.com/chef/chef/issues/2831)
+* Added an `imports` attribute to dsc_script. This attribute allows you to specify DSC resources that need to be imported for your script.
+* Fixed error where guard resources (using :guard_interpreter) were not ran in `why_run` mode [Issue 2694](https://github.com/chef/chef/issues/2694)
+* Add `verify` method to File resource per RFC027
+* Move supermarket.getchef.com to supermarket.chef.io
+* Check with AccessCheck for permission to write to directory on Windows
+* Add declare_resource/build_resource comments, fix faulty ||=
+* Knife bootstrap creates a client and ships it to the node to implement validatorless bootstraps
+* Knife bootstrap can use the client it creates to setup chef-vault items for the node
+* windows service now has a configurable timeout
+
+## 12.0.3
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+[Issue 2594](https://github.com/chef/chef/issues/2594) Restore missing require in `digester`.
+
+## 12.0.2
+* [Issue 2578](https://github.com/chef/chef/issues/2578) Check that `installed` is not empty for `keg_only` formula in Homebrew provider
+* [Issue 2609](https://github.com/chef/chef/issues/2609) Resolve the circular dependency between ProviderResolver and Resource.
+* [Issue 2596](https://github.com/chef/chef/issues/2596) Fix nodes not writing to disk
+* [Issue 2580](https://github.com/chef/chef/issues/2580) Make sure the relative paths are preserved when using link resource.
+* [Pull 2630](https://github.com/chef/chef/pull/2630) Improve knife's SSL error messaging
+* [Issue 2606](https://github.com/chef/chef/issues/2606) chef 12 ignores default_release for apt_package
+* [Issue 2602](https://github.com/chef/chef/issues/2602) Fix `subscribes` resource notifications.
+* [Issue 2578](https://github.com/chef/chef/issues/2578) Check that `installed` is not empty for `keg_only` formula in Homebrew provider.
+* [**gh2k**](https://github.com/gh2k):
+ [Issue 2625](https://github.com/chef/chef/issues/2625) Fix missing `shell_out!` for `windows_package` resource
+* [**BackSlasher**](https://github.com/BackSlasher):
+ [Issue 2634](https://github.com/chef/chef/issues/2634) Fix `option ':command' is not a valid option` error in subversion provider.
+* [**Seth Vargo**](https://github.com/sethvargo):
+ [Issue 2345](https://github.com/chef/chef/issues/2345) Allow knife to install cookbooks with metadata.json.
+
+## 12.0.1
+
+* [Issue 2552](https://github.com/chef/chef/issues/2552) Create constant for LWRP before calling `provides`
+* [Issue 2545](https://github.com/chef/chef/issues/2545) `path` attribute of `execute` resource is restored to provide backwards compatibility with Chef 11.
+* [Issue 2565](https://github.com/chef/chef/issues/2565) Fix `Chef::Knife::Core::BootstrapContext` constructor for knife-windows compat.
+* [Issue 2566](https://github.com/chef/chef/issues/2566) Make sure Client doesn't raise error when interval is set on Windows.
+* [Issue 2560](https://github.com/chef/chef/issues/2560) Fix `uninitialized constant Windows::Constants` in `windows_eventlog`.
+* [Issue 2563](https://github.com/chef/chef/issues/2563) Make sure the Chef Client rpm packages are signed with GPG keys correctly.
+
+## 12.0.0
+
+* [**Jesse Hu**](https://github.com/jessehu):
+ retry on HTTP 50X Error when calling Chef REST API
+* [**Nolan Davidson**](https://github.com/nsdavidson):
+ The chef-apply command now prints usage information when called without arguments
+* [**Kazuki Saito**](https://github.com/sakazuki):
+ CHEF-4933: idempotency fixes for ifconfig provider
+* [**Kirill Shirinkin**](https://github.com/Fodoj):
+ The knife bootstrap command expands the path of the secret-file
+* [**Malte Swart**](https://github.com/mswart):
+ [CHEF-4101] DeepMerge - support overwriting hash values with nil
+* [**James Belchamber**](https://github.com/JamesBelchamber):
+ Mount provider remount action now honours options
+* [**Mark Gibbons**](https://github.com/MarkGibbons):
+ Fix noauto support in Solaris Mount Provider
+* [**Jordan Evans**](https://github.com/jordane):
+ support version constraints in value_for_platform
+* [**Yukihiko Sawanobori**](https://github.com/sawanoboly):
+ Add environment resource attribute to scm resources
+* [**Grzesiek Kolodziejczyk**](https://github.com/grk):
+ Use thread-safe OpenSSL::Digest instead of Digest
+* [**Grzesiek Kolodziejczyk**](https://github.com/grk):
+ Chef::Digester converted to thread-safe Singleton mixin.
+* [**Vasiliy Tolstov**](https://github.com/vtolstov):
+ Reload systemd service only if it's running, otherwise start.
+* [**Chris Jerdonek**](https://github.com/cjerdonek):
+ knife diagnostic messages sent to stdout instead of stderr
+* [**Xabier de Zuazo**](https://github.com/zuazo):
+ Remove the unused StreamingCookbookUploader class (CHEF-4586)
+* [**Jacob Vosmaer**](https://github.com/jacobvosmaer):
+ Fix creation of non-empty FreeBSD groups (#1698)
+* [**Nathan Huff**](https://github.com/nhuff):
+ Check local repository for ips package installs (#1703)
+* [**Sean Clemmer**](https://github.com/sczizzo):
+ Fix "cron" resource handling of special strings (e.g. @reboot, @yearly) (#1708)
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+ 'group' provider on OSX properly uses 'dscl' to determine existing groups
+* [**Hugo Lopes Tavares**](https://github.com/hltbra):
+ Catch StandardError in Chef::ResourceReporter#post_reporting_data (Issue 1550).
+* [**Daniel O'Connor**](https://github.com/CloCkWeRX):
+ Fix regex causing DuplicateRole error (Issue 1739).
+* [**Xeron**](https://github.com/xeron):
+ Ability to specify an array for data_bag_path. (CHEF-3399, CHEF-4753)
+* [**Jordan**](https://github.com/jordane):
+ Use Systemd for recent Fedora and RHEL 7.
+* [**Xabier de Zuazo**](https://github.com/zuazo):
+ Encrypted data bags should use different HMAC key and include the IV in the HMAC (CHEF-5356).
+* [**Pierre Ynard**](https://github.com/linkfanel):
+ Don't modify variable passed to env resource when updating.
+* [**Chris Aumann**](https://github.com/chr4):
+ Add "force" attribute to resource/user, pass "-f" to userdel. (Issue 1601)
+* [**Brian Cobb**](https://github.com/bcobb):
+ Chef::VersionConstraint#to_s should accurately reflect constraint's behavior.
+* [**Kevin Graham**](https://github.com/kgraham):
+ Do not override ShellOut:live_stream if already set.
+* [**Mike Heijmans**](https://github.com/parabuzzle):
+ Change knife option --force to --delete-validators. (Issue 1652)
+* [**Pavel Yudin**](https://github.com/Kasen):
+ Add Parallels Cloud Server (PCS) platform support.
+* [**tbe**](https://github.com/tbe):
+ Minor fixes for the Paludis package provider:
+ * only search for non-masked packages,
+ * increase command timeout length for package installation.
+* [**sawanoboly**](https://github.com/sawanoboly):
+ Use shared_path for deploy resource.
+* [**Victor Hahn**](https://github.com/victorhahncastell):
+ Add template syntax check to files in the templates/ dir only.
+* [**Jordan**](https://github.com/jordane):
+ Allow git provider to checkout existing branch names.
+* [**Eric Herot**](https://github.com/eherot):
+ Add whitespace boundaries to some mount point references in mount provider.
+* [**Dave Eddy**](https://github.com/bahamas10):
+ Improve the regex for /etc/rc.conf for the FreeBSD service provider
+* [**Stanislav Bogatyrev**](https://github.com/realloc):
+ Fetch recipe_url before loading json_attribs in chef-solo (CHEF-5075)
+* [**Mal Graty**](https://github.com/mal):
+ Workaround for a breaking change in git's shallow-clone behavior. (Issue 1563)
+* [**Dave Eddy**](https://github.com/bahamas10):
+ Fix version detection in FreeBSD pkgng provider. (PR 1980)
+* [**Dan Rathbone**](https://github.com/rathers):
+ Fixed gem_package resource to be able to upgrade gems when version is not set.
+* [**Jean Mertz**](https://github.com/JeanMertz):
+ Made Chef Client load library folder recursively.
+* [**Eric Saxby**](https://github.com/sax):
+ Made Chef Client read the non-root crontab entries as the user specified in the resource.
+* [**sawanoboly**](https://github.com/sawanoboly):
+ Added `--dry-run` option to `knife cookbook site share` which displays the files that are to be uploaded to Supermarket.
+* [**Sander van Harmelen**](https://github.com/svanharmelen):
+ Fixed `Chef::HTTP` to be able to follow relative redirects.
+* [**Cory Stephenson**](https://github.com/Aevin1387):
+ Fixed FreeBSD port package provider to interpret FreeBSD version 10 correctly.
+* [**Brett Chalupa**](https://github.com/brettchalupa):
+ Added `source_url` and `issues_url` options to metadata to be used by Supermarket.
+* [**Anshul Sharma**](https://github.com/justanshulsharma):
+ Fixed Chef Client to use the `:client_name` instead of `:node_name` during initial client registration.
+* [**tbe**](https://github.com/tbe):
+ Fixed Paludis package provider to be able to interpret the package category.
+* [**David Workman**](https://github.com/workmad3):
+ Added a more clear error message to chef-apply when no recipe is given.
+* [**Joe Nuspl**](https://github.com/nvwls):
+ Added support for `sensitive` property to the execute resource.
+* [**Nolan Davidson**](https://github.com/nsdavidson):
+ Added an error message to prevent unintentional running of `exec()` in recipes.
+* [**wacky612**](https://github.com/wacky612):
+ Fixed a bug in pacman package provider that was preventing the installation of `bind` package.
+* [**Ionuț Arțăriși**](https://github.com/mapleoin):
+ Changed the default service provider to systemd on SLES versions 12 and higher.
+* [**Ionuț Arțăriși**](https://github.com/mapleoin):
+ Changed the default group provider to gpasswd on SLES versions 12 and higher.
+* [**Noah Kantrowitz**](https://github.com/coderanger):
+ Implemented [RFC017 - File Specificity Overhaul](https://github.com/chef/chef-rfc/blob/master/rfc017-file-specificity.md).
+* [**James Bence**](https://github.com/jbence):
+ Improved the reliability of Git provider by making it to be more specific when selecting tags.
+* [**Jean Mertz**](https://github.com/JeanMertz):
+ Changed knife upload not to validate the ruby files under files & templates directories.
+* [**Alex Pop**](https://github.com/alexpop):
+ Made `knife cookbook create` to display the directory of the cookbook that is being created.
+* [**Alex Pop**](https://github.com/alexpop):
+ Fixed the information debug output for the configuration file being used when running knife.
+* [**Martin Smith**](https://github.com/martinb3):
+ Changed `knife cookbook site share` to make category an optional parameter when uploading cookbooks.
+ It is still required when the cookbook is being uploaded for the first time but on the consequent
+ uploads existing category of the cookbook will be used.
+* [**Nicolas DUPEUX**](https://github.com/vaxvms):
+ Added JSON output to `knife status` command. `--medium` and `--long` output formatting parameters are now supported in knife status.
+* [**Trevor North**](https://github.com/trvrnrth):
+ Removed dead code from `knife ssh`.
+* [**Nicolas Szalay**](https://github.com/rottenbytes):
+ Fixed a bug preventing mounting of cgroup type devices in the mount provider.
+* [**Anshul Sharma**](https://github.com/justanshulsharma):
+ Fixed inconsistent globbing in `knife from file` command.
+* [**Nicolas Szalay**](https://github.com/rottenbytes):
+ Made user prompts in knife more beautiful by adding a space after Y/N prompts.
+* [**Ivan Larionov**](https://github.com/xeron):
+ Made empty run_list to produce an empty array when using node.to_hash.
+* [**Siddheshwar More**](https://github.com/siddheshwar-more):
+ Fixed a bug in knife bootstrap that caused config options to override command line options.
+* [**Thiago Oliveira**](https://github.com/chilicheech):
+ Fixed a bug in Mac OSX group provider and made it idempotent.
+* [**liseki**](https://github.com/liseki):
+ Fixed a bug in why-run mode for freebsd service resources without configured init scripts.
+* [**liseki**](https://github.com/liseki):
+ Fixed a bug in freebsd service providers to load the status correctly.
+
+
+### Chef Contributions
+
+* ruby 1.9.3 support is dropped
+* Added RFC-023 Chef 12 Attribute Changes (https://github.com/chef/chef-rfc/blob/master/rfc023-chef-12-attributes-changes.md)
+* Added os/platform_family options to provides syntax on the Chef::Resource DSL
+* Added provides methods to the Chef::Provider DSL
+* Added supported?(resource, action) class method to all Providers for late-evaluation if a provider can handle a
+ resource
+* Added ProviderResolver feature to handle late resolution of providers based on what kinds of support is in the
+ base operating system.
+* Partial Deprecation of Chef::Platform provider mapping. The static mapping will be removed as Chef-12 progresses
+ and the hooks will be completely dropped in Chef-13.
+* Default `guard_interpreter` for `powershell_script` resource set to `:powershell_script`, for `batch` to `:batch`
+* Recipe definition now returns the retval of the definition
+* Add support for Windows 10 to version helper.
+* `dsc_script` resource should honor configuration parameters when `configuration_data_script` is not set (Issue #2209)
+* Ruby has been updated to 2.1.3 along with rubygems update to 2.4.2
+* Removed shelling out to erubis/ruby for syntax checks (>= 1.9 has been able
+ to do this in the ruby vm itself for awhile now and we've dropped 1.8.7 which
+ could not do this and had to shell_out)
+* Report the request and response when a non-200 error code happens
+* [FEATURE] Upgrade `knife upload` and `knife download` to download
+ **everything** in an organization, now including the organization definition
+ itself (`knife download /org.json`) and the invitations and member list
+ (`knife download /invitations.json` and `knife download /members.json`).
+ Should be compatible with knife-ec-backup.
+* Make default Windows paths more backslashy
+* `knife` now prefers to load `config.rb` in preference to `knife.rb`;
+`knife.rb` will be used if `config.rb` is not found.
+* Fixed Config[:cache_path] to use path_join()
+* Updated chef-zero to 3.0, so that client tests can be run against Enterprise
+ Chef as well as Open Source.
+* knife cookbook site download/list/search/share/show/unshare now uses
+ supermerket.getchef.com urls
+* added Chef::ResourceCollection#insert_at API to the ResourceCollection
+* http_proxy and related config vars no longer clobber already set ENV vars
+* all http_proxy configs now set lowercase + uppercase versions of ENV vars
+* https_proxy/ftp_proxy support setting `http://` URLs (and whatever mix and match makes sense)
+* End-to-end tests for Ubuntu 12.04
+* Only run end-to-end tests when secure environment variables are present.
+* Remove recipe DSL from base provisioner (Issue 1446).
+* Enable client-side key generation by default. (Issue 1711)
+* CookbookSiteStreamingUploader now uses ssl_verify_mode config option (Issue 1518).
+* chef/json_compat now throws its own exceptions not JSON gem exceptions
+* Modify action for env raises Chef::Exceptions::Env exception on Windows (Chef Issues 1754)
+* Fix a bug in the experimental Policyfile mode that caused errors when
+ using templates.
+* Disable JSON encoding of request body when non-JSON content type is
+ specified.
+* Clean up FileVendor and CookbookUploader internal APIs
+* log resource now marks itself as supporting why-run
+* http_request no longer appends "?message=" query string to GET and HEAD requests
+* added shell_out commands directly to the recipe DSL
+* cookbook synchronizer deletes old files from cookbooks
+* do not clear file cache when override run list is set (CHEF-3684)
+* ruby 1.8.7/1.9.1/1.9.2 support is dropped
+* set no_lazy_load to true (CHEF-4961)
+* set file_stating_uses_destdir config option default to true (CHEF-5040)
+* remove dependency on rest-client gem
+* Add method shell_out_with_systems_locale to ShellOut.
+* chef-repo rake tasks are deprecated; print relevant information for
+ each one.
+* Fix RPM package version detection (Issue 1554)
+* Don't override :default provider map if :default passed as platform (OC-11667).
+* Fix SuSE package removal failure (Issue 1732).
+* Enable Travis to run Test Kitchen with Kitchen EC2.
+* Fix a bug in reporting not to post negative duration values.
+* Add password setting support for Mac 10.7, 10.8 and 10.9 to the dscl user provider.
+* ChefSpec can find freebsd_package resource correctly when a package resource is declared on Freebsd.
+* Autodetect/decrypt encrypted data bag items with data_bag_item dsl method. (Issue 1837, Issue 1849)
+* windows_user: look up username instead of resource name (Issue #1705)
+* Remove the unused bootstrap templates that install chef from rubygems
+* Remove the Chef 10 functionality from bootstrap.
+* Deprecate --distro / --template_file options in favor of --boostrap-template
+* Add `:node_ssl_verify_mode` & `:node_verify_api_cert` options to bootstrap
+ to be able to configure these settings on the bootstrapped node.
+* Add partial_search dsl method to Chef::Search::Query, add result filtering to search.
+* Transfer trusted certificates under :trusted_certs_dir during bootstrap.
+* Set :ssl_verify_mode to :verify_peer by default.
+* Add homebrew provider for package resource, use it by default on OS X (Issue #1709)
+* Add escape_glob method to PathHelper, update glob operations.
+* Verify x509 properties of certificates in the :trusted_certs_dir during knife ssl check.
+* Disable unforked interval chef-client runs.
+* Removed dependencies on the 'json' gem, replaced with ffi-yajl. Use Chef::JSONCompat library for parsing and printing.
+* Restore the deprecation logic of #valid_actions in LWRPs until Chef 13.
+* Now that we don't allow unforked chef-client interval runs, remove the reloading of previously defined LWRPs.
+* Use shell_out to determine Chef::Config[:internal_locale], fix CentOS locale detection bug.
+* `only_if` and `not_if` attributes of `execute` resource now inherits the parent resource's
+ attributes when set to a `String`.
+* Retain the original value of `retries` for resources and display the original value when the run fails.
+* Added service provider for AIX.
+* The Windows env provider will delete elements even if they are only in ENV (and not in the registry)
+* Allow events to be logged to Windows Event Log
+* Fixed bug in env resource where a value containing the delimiter could never correctly match the existing values
+* More intelligent service check for systemd on Ubuntu 14.10.
+
+## 11.16.4
+
+* Windows omnibus installer security updates for redistributed bash.exe / sh.exe
+ vulnerabilities ("Shellshock") CVE-2014-6271, CVE-2014-6271, CVE-2014-6278,
+ CVE-2014-7186, CVE-2014-7187.
+* Fix bug on Windows where using the env resource on path could render the path unusable.
+* Chef Client now retries when it gets 50X from Chef Server.
+* Chef Client 11.16.4 can use the policyfiles generated with Chef DK 0.3.0.
+
+## 11.16.2
+
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+ Fix a regression in whyrun_safe_ruby_block.
+
+## 11.16.0
+
+* Fix a bug in user dscl provider to enable managing password and other properties at the same time.
+* Add `dsc_script` resource to Chef for PowerShell DSC support on Windows
+
+## 11.14.6:
+
+* Modify action for env raises Chef::Exceptions::Env exception on Windows (Chef Issues 1754)
+* Fix RPM package version detection (Issue 1554)
+* Fix a bug in reporting not to post negative duration values.
+* Add password setting support for Mac 10.7, 10.8 and 10.9 to the dscl user provider.
+* ChefSpec can find freebsd_package resource correctly when a package resource is declared on Freebsd.
+* http_proxy and related config vars no longer clobber already set ENV vars
+* all http_proxy configs now set lowercase + uppercase versions of ENV vars
+* https_proxy/ftp_proxy support setting `http://` URLs (and whatever mix and match makes sense)
+
+## 11.14.2
+
+* [**Jess Mink**](https://github.com/jmink):
+ Symlinks to directories should be swingable on windows (CHEF-3960)
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+ SIGTERM will once-more kill a non-daemonized chef-client (CHEF-5172)
+* [**Pierre Ynard**](https://github.com/linkfanel):
+ chef-service-manager should run as a non-interactive service (CHEF-5150)
+* [**Tensibai Zhaoying**](https://github.com/Tensibai):
+ Fix file:// URI support in remote\_file on windows (CHEF-4472)
+* [**John Dyer**](https://github.com/johntdyer):
+ Catch HTTPServerException for 404 in remote_file retry (CHEF-5116)
+* [**Pavel Yudin**](https://github.com/Kasen):
+ Providers are now set correctly on CloudLinux. (CHEF-5182)
+* [**Joe Richards**](https://github.com/viyh):
+ Made -E option to work with single lettered environments. (CHEF-3075)
+* [**Jimmy McCrory**](https://github.com/JimmyMcCrory):
+ Added a 'knife node environment set' command. (CHEF-1910)
+* [**Hongbin Lu**](https://github.com/hongbin):
+ Made bootstrap report authentication exceptions. (CHEF-5161)
+* [**Richard Manyanza**](https://github.com/liseki):
+ Made `freebsd_package` resource use the brand new "pkgng" package
+ manager when available.(CHEF-4637)
+* [**Nikhil Benesch**](https://github.com/benesch):
+ Implemented a threaded download queue for synchronizing cookbooks. (CHEF-4423)
+* [**Chulki Lee**](https://github.com/chulkilee):
+ Raise an error when source is accidentally passed to apt_package (CHEF-5113)
+* [**Cam Cope**](https://github.com/ccope):
+ Add an open_timeout when opening an http connection (CHEF-5152)
+* [**Sander van Harmelen**](https://github.com/svanharmelen):
+ Allow environment variables set on Windows to be used immediately (CHEF-5174)
+* [**Luke Amdor**](https://github.com/rubbish):
+ Add an option to configure the chef-zero port (CHEF-5228)
+* [**Ricardo Signes**](https://github.com/rjbs):
+ Added support for the usermod provider on OmniOS
+* [**Anand Suresh**](https://github.com/anandsuresh):
+ Only modify password when one has been specified. (CHEF-5327)
+* [**Stephan Renatus**](https://github.com/srenatus):
+ Add exception when JSON parsing fails. (CHEF-5309)
+* [**Xabier de Zuazo**](https://github.com/zuazo):
+ OK to exclude space in dependencies in metadata.rb. (CHEF-4298)
+* [**Łukasz Jagiełło**](https://github.com/ljagiello):
+ Allow cookbook names with leading underscores. (CHEF-4562)
+* [**Michael Bernstein**](https://github.com/mrb):
+ Add Code Climate badge to README.
+* [**Phil Sturgeon**](https://github.com/philsturgeon):
+ Documentation that -E is not respected by knife ssh [search]. (CHEF-4778)
+* [**Stephan Renatus**](https://github.com/srenatus):
+ Fix resource_spec.rb.
+* [**Sander van Harmelen**](https://github.com/svanharmelen):
+ Ensure URI compliant urls. (CHEF-5261)
+* [**Robby Dyer**](https://github.com/robbydyer):
+ Correctly detect when rpm_package does not exist in upgrade action. (CHEF-5273)
+* [**Sergey Sergeev**](https://github.com/zhirafovod):
+ Hide sensitive data output on chef-client error (CHEF-5098)
+* [**Mark Vanderwiel**](https://github.com/kramvan1):
+ Add config option :yum-lock-timeout for yum-dump.py
+* [**Peter Fern**](https://github.com/pdf):
+ Convert APT package resource to use `provides :package`, add timeout parameter.
+* [**Xabier de Zuazo**](https://github.com/zuazo):
+ Fix Chef::User#list API error when inflate=true. (CHEF-5328)
+* [**Raphaël Valyi**](https://github.com/rvalyi):
+ Use git resource status checking to reduce shell_out system calls.
+* [**Eric Krupnik**](https://github.com/ekrupnik):
+ Added .project to git ignore list.
+* [**Ryan Cragun**](https://github.com/ryancragun):
+ Support override_runlist CLI option in shef/chef-shell. (CHEF-5314)
+* [**Cam Cope**](https://github.com/ccope):
+ Fix updating user passwords on Solaris. (CHEF-5247)
+* [**Ben Somers**](https://github.com/bensomers):
+ Enable storage of roles in subdirectories for chef-solo. (CHEF-4193)
+* [**Robert Tarrall**](https://github.com/tarrall):
+ Fix Upstart provider with parameters. (CHEF-5265)
+* [**Klaas Jan Wierenga**](https://github.com/kjwierenga):
+ Don't pass on default HTTP port(80) in Host header. (CHEF-5355)
+* [**MarkGibbons**](https://github.com/MarkGibbons):
+ Allow for undefined solaris services in the service resource. (CHEF-5347)
+* [**Allan Espinosa**](https://github.com/aespinosa):
+ Properly knife bootstrap on ArchLinux. (CHEF-5366)
+* [**Matt Hoyle**](https://github.com/deployable):
+ Made windows service resource to handle transitory states. (CHEF-5319, CHEF-4791)
+* [**Brett cave**](https://github.com/brettcave):
+ Add Dir.pwd as fallback for default user_home if home directory is not set. (CHEF-5365)
+* [**Caleb Tennis**](https://github.com/ctennis):
+ Add support for automatically using the Systemd service provider when available. (CHEF-3637)
+* [**Matt Hoyle**](https://github.com/deployable):
+ Add timeout for Chef::Provider::Service::Windows. (CHEF-1165)
+* [**Jesse Hu**](https://github.com/jessehu):
+ knife[:attribute] in knife.rb should not override --attribute (CHEF-5158)
+* [**Vasiliy Tolstov**](https://github.com/vtolstov):
+ Added the initial exherbo linux support for Chef providers.
+
+* Fix knife cookbook site share on windows (CHEF-4994)
+* YAJL Allows Invalid JSON File Sending To The Server (CHEF-4899)
+* YAJL Silently Ingesting Invalid JSON and "Normalizing" Incorrectly (CHEF-4565)
+* Update rpm provider checking regex to allow for special characters (CHEF-4893)
+* Allow for spaces in selinux controlled directories (CHEF-5095)
+* Windows batch resource run action fails: " TypeError: can't convert nil into String" (CHEF-5287)
+* Log resource always triggers notifications (CHEF-4028)
+* Prevent tracing? from throwing an exception when first starting chef-shell.
+* Use Upstart provider on Ubuntu 13.10+. (CHEF-5276)
+* Cleaned up mount provider superclass
+* Added "knife serve" to bring up local mode as a server
+* Print nested LWRPs with indentation in doc formatter output
+* Make local mode stable enough to run chef-pedant
+* Wrap code in block context when syntax checking so `return` is valid
+ (CHEF-5199)
+* Quote git resource rev\_pattern to prevent glob matching files (CHEF-4940)
+* User resource now only prints the name during why-run runs. (CHEF-5180)
+* Set --run-lock-timeout to wait/bail if another client has the runlock (CHEF-5074)
+* remote\_file's source attribute does not support DelayedEvaluators (CHEF-5162)
+* `option` attribute of mount resource now supports lazy evaluation. (CHEF-5163)
+* `force_unlink` now only unlinks if the file already exists. (CHEF-5015)
+* `chef_gem` resource now uses omnibus gem binary. (CHEF-5092)
+* chef-full template gets knife options to override install script url, add wget/curl cli options, and custom install commands (CHEF-4697)
+* knife now bootstraps node with the latest current version of chef-client. (CHEF-4911)
+* Add config options for attribute whitelisting in node.save. (CHEF-3811)
+* Use user's .chef as a fallback cache path if /var/chef is not accessible. (CHEF-5259)
+* Fixed Ruby 2.0 Windows compatibility issues around ruby-wmi gem by replacing it with wmi-lite gem.
+* Set proxy environment variables if preset in config. (CHEF-4712)
+* Automatically enable verify_api_cert when running chef-client in local-mode. (Chef Issues 1464)
+* Add helper to warn for broken [windows] paths. (CHEF-5322)
+* Send md5 checksummed data for registry key if data type is binary, dword, or qword. (Chef-5323)
+* Add warning if host resembles winrm command and knife-windows is not present.
+* Use FFI binders to attach :SendMessageTimeout to avoid DL deprecation warning. (ChefDK Issues 69)
+* Use 'guest' user on AIX for RSpec tests. (OC-9954)
+* Added DelayedEvaluator support in LWRP using the `lazy {}` key
+* Fixed a bug where nested resources that inherited from Resource::LWRPBase
+ would not share the same actions/default_action as their parent
+* Raise error if a guard_interpreter is specified and a block is passed to a guard (conditional)
+* Allow specifying a guard_interpreter after a conditional on a resource (Fixes #1943)
+* Windows package type should be a symbol (Fixes #1997) \ No newline at end of file
diff --git a/MAINTAINERS.md b/MAINTAINERS.md
index 0023cb91bf..e9cfec0f94 100644
--- a/MAINTAINERS.md
+++ b/MAINTAINERS.md
@@ -7,7 +7,7 @@ file tells you who needs to review your patch - you need a simple majority of ma
for the relevant subsystems to provide a :+1: on your pull request. Additionally, you need
to not receive a veto from a Lieutenant or the Project Lead.
-Check out [How Chef is Maintained](https://github.com/opscode/chef-rfc/blob/master/rfc030-maintenance-policy.md#how-the-project-is-maintained) for details on the process, how to become
+Check out [How Chef is Maintained](https://github.com/chef/chef-rfc/blob/master/rfc030-maintenance-policy.md#how-the-project-is-maintained) for details on the process, how to become
a maintainer, lieutenant, or the project lead.
# Project Lead
@@ -18,9 +18,7 @@ a maintainer, lieutenant, or the project lead.
## Chef Core
-Handles the core parts of the Chef DSL, base resource and provider
-infrastructure, the Chef applications and [omnibus-chef](https://github.com/chef/omnibus-chef). Includes anything not covered by
-another component.
+Maintainers for the Chef client, Ohai, mixlibs, ChefDK, ChefSpec, Foodcritic, chefstyle, and sundry others.
To mention the team, use @chef/client-core
@@ -36,40 +34,36 @@ To mention the team, use @chef/client-core
* [AJ Christensen](https://github.com/fujin)
* [Phil Dibowitz](https://github.com/jaymzh)
* [Jay Mundrawala](https://github.com/jaym)
+* [John Keiser](https://github.com/jkeiser)
* [Jon Cowie](https://github.com/jonlives)
+* [Joshua Timberman](https://github.com/jtimberman)
* [Lamont Granquist](https://github.com/lamont-granquist)
* [Claire McQuin](https://github.com/mcquin)
+* [Matt Wrock](https://github.com/mwrock)
+* [Ranjib Dey](https://github.com/ranjib)
* [Steven Murawski](https://github.com/smurawski)
+* [Steven Danna](https://github.com/stevendanna)
+* [Tim Smith](https://github.com/tas50)
+* [Tom Duffield](https://github.com/tduffield)
* [Tyler Ball](https://github.com/tyler-ball)
-* [Ranjib Dey](https://github.com/ranjib)
-* [Matt Wrock](https://github.com/mwrock)
-
-## Dev Tools
-
-Chef Zero, Knife, Chef Apply and Chef Shell.
-To mention the team, use @chef/client-dev-tools
-
-### Maintainers
-* [Daniel DeLeo](https://github.com/danielsdeleo)
-* [Joshua Timberman](https://github.com/jtimberman)
-* [Lamont Granquist](https://github.com/lamont-granquist)
-* [Steven Danna](https://github.com/stevendanna)
+## Chef Provisioning
-## Test Tools
+Chef Provisioning and Drivers. Supported Drivers are listed in the [README](https://github.com/chef/chef-provisioning/blob/master/README.md#chef-provisioning).
-ChefSpec
-To mention the team, use @chef/client-test-tools
+To mention the team, use @chef/provisioning
### Lieutenant
-* [Seth Vargo](https://github.com/sethvargo)
+* [Tyler Ball](https://github.com/tyler-ball)
### Maintainers
-* [Joshua Timberman](https://github.com/jtimberman)
-* [Lamont Granquist](https://github.com/lamont-granquist)
-* [Ranjib Dey](https://github.com/ranjib)
+* [John Keiser](https://github.com/jkeiser)
+* [JJ Asghar](https://github.com/jjasghar)
+* [João Cravo](https://github.com/joaogbcravo)
+* [Stuart Preston](https://github.com/stuartpreston)
+* [Harley Alaniz](https://github.com/thehar)
## Platform Specific Components
@@ -99,6 +93,7 @@ To mention the team, use @chef/client-ubuntu
### Maintainers
* [Lamont Granquist](https://github.com/lamont-granquist)
+* [Tim Smith](https://github.com/tas50)
* [Thom May](https://github.com/thommay)
## Windows
@@ -160,6 +155,7 @@ To mention the team, use @chef/client-debian
### Maintainers
* [Lamont Granquist](https://github.com/lamont-granquist)
+* [Tim Smith](https://github.com/tas50)
## Fedora
@@ -176,6 +172,7 @@ To mention the team, use @chef/client-opensuse
### Maintainers
* [Lamont Granquist](https://github.com/lamont-granquist)
+* [Tim Smith](https://github.com/tas50)
## SUSE Enterprise Linux Server
@@ -197,7 +194,7 @@ To mention the team, use @chef/client-freebsd
* [Cory Stephenson](https://github.com/Aevin1387)
* [David Aronsohn](https://github.com/tbunnyman)
-* [Bryant Lippert](https://github.com/agentmeerkat)
+* [Bryant Lippert](https://github.com/AgentMeerkat)
## OpenBSD
diff --git a/MAINTAINERS.toml b/MAINTAINERS.toml
index 12eb536fa3..10e7655cd8 100644
--- a/MAINTAINERS.toml
+++ b/MAINTAINERS.toml
@@ -12,7 +12,7 @@ file tells you who needs to review your patch - you need a simple majority of ma
for the relevant subsystems to provide a :+1: on your pull request. Additionally, you need
to not receive a veto from a Lieutenant or the Project Lead.
-Check out [How Chef is Maintained](https://github.com/opscode/chef-rfc/blob/master/rfc030-maintenance-policy.md#how-the-project-is-maintained) for details on the process, how to become
+Check out [How Chef is Maintained](https://github.com/chef/chef-rfc/blob/master/rfc030-maintenance-policy.md#how-the-project-is-maintained) for details on the process, how to become
a maintainer, lieutenant, or the project lead.
"""
@@ -28,9 +28,7 @@ a maintainer, lieutenant, or the project lead.
title = "Chef Core"
team = "client-core"
text = """
-Handles the core parts of the Chef DSL, base resource and provider
-infrastructure, the Chef applications and [omnibus-chef](https://github.com/chef/omnibus-chef). Includes anything not covered by
-another component.
+Maintainers for the Chef client, Ohai, mixlibs, ChefDK, ChefSpec, Foodcritic, chefstyle, and sundry others.
"""
lieutenant = "thommay"
@@ -42,46 +40,35 @@ another component.
"fujin",
"jaymzh",
"jaym",
+ "jkeiser",
"jonlives",
+ "jtimberman",
"lamont-granquist",
"mcquin",
- "smurawski",
- "tyler-ball",
+ "mwrock",
"ranjib",
- "mwrock"
- ]
-
- [Org.Components.DevTools]
- title = "Dev Tools"
- team = "client-dev-tools"
- text = "Chef Zero, Knife, Chef Apply and Chef Shell."
-
- paths = [
- "lib/chef/knife.rb",
- "lib/chef/knife/",
- "spec/functional/knife/",
- "spec/integration/knife/",
- "spec/unit/knife/"
- ]
-
- maintainers = [
- "danielsdeleo",
- "jtimberman",
- "lamont-granquist",
- "stevendanna"
+ "smurawski",
+ "stevendanna",
+ "tas50",
+ "tduffield",
+ "tyler-ball"
]
- [Org.Components.TestTools]
- title = "Test Tools"
- team = "client-test-tools"
- text = "ChefSpec"
+ [Org.Components.Provisioning]
+ title = "Chef Provisioning"
+ team = "provisioning"
+ text = """
+Chef Provisioning and Drivers. Supported Drivers are listed in the [README](https://github.com/chef/chef-provisioning/blob/master/README.md#chef-provisioning).
+"""
- lieutenant = "sethvargo"
+ lieutenant = "tyler-ball"
maintainers = [
- "jtimberman",
- "lamont-granquist",
- "ranjib"
+ "jkeiser",
+ "jjasghar",
+ "joaogbcravo",
+ "stuartpreston",
+ "thehar"
]
[Org.Components.Subsystems]
@@ -109,6 +96,7 @@ The specific components of Chef related to a given platform - including (but not
maintainers = [
"lamont-granquist",
+ "tas50",
"thommay"
]
@@ -148,7 +136,8 @@ The specific components of Chef related to a given platform - including (but not
lieutenant = "jtimberman"
maintainers = [
- "tyler-ball"
+ "tyler-ball",
+ "mikedodge04"
]
[Org.Components.Subsystems.Debian]
@@ -158,7 +147,8 @@ The specific components of Chef related to a given platform - including (but not
lieutenant = "thommay"
maintainers = [
- "lamont-granquist"
+ "lamont-granquist",
+ "tas50"
]
[Org.Components.Subsystems.Fedora]
@@ -174,7 +164,8 @@ The specific components of Chef related to a given platform - including (but not
team = "client-opensuse"
maintainers = [
- "lamont-granquist"
+ "lamont-granquist",
+ "tas50"
]
[Org.Components.Subsystems."SUSE Enterprise Linux"]
@@ -194,7 +185,7 @@ The specific components of Chef related to a given platform - including (but not
maintainers = [
"Aevin1387",
"tBunnyMan",
- "agentmeerkat"
+ "AgentMeerkat"
]
[Org.Components.Subsystems.OpenBSD]
@@ -237,9 +228,9 @@ The specific components of Chef related to a given platform - including (but not
Name = "Cory Stephenson"
GitHub = "Aevin1387"
- [people.agentmeerkat]
+ [people.AgentMeerkat]
Name = "Bryant Lippert"
- GitHub = "agentmeerkat"
+ GitHub = "AgentMeerkat"
[people.btm]
Name = "Bryan McLellan"
@@ -336,3 +327,42 @@ The specific components of Chef related to a given platform - including (but not
[people.mwrock]
Name = "Matt Wrock"
GitHub = "mwrock"
+
+ [people.tas50]
+ Name = "Tim Smith"
+ GitHub = "tas50"
+ Twitter = "tas50"
+ IRC = "tas50"
+
+ [people.jkeiser]
+ Name = "John Keiser"
+ GitHub = "jkeiser"
+
+ [people.stuartpreston]
+ Name = "Stuart Preston"
+ GitHub = "stuartpreston"
+
+ [people.jjasghar]
+ Name = "JJ Asghar"
+ GitHub = "jjasghar"
+ Twitter = "jjasghar"
+ IRC = "j^2"
+
+ [people.joaogbcravo]
+ Name = "João Cravo"
+ GitHub = "joaogbcravo"
+ Twitter = "joaogbcravo"
+
+ [people.thehar]
+ Name = "Harley Alaniz"
+ GitHub = "thehar"
+
+ [people.tduffield]
+ Name = "Tom Duffield"
+ GitHub = "tduffield"
+
+ [people.mikedodge04]
+ Name = "mikedodge04"
+ GitHub = "mikedodge04"
+ Twitter = "mikedodge04"
+ IRC = "mikedodge04"
diff --git a/NOTICE b/NOTICE
index 5bca08f99f..932967f59c 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,21 +1,21 @@
Chef NOTICE
===========
-Developed at Opscode (http://www.opscode.com).
+Developed at Chef (https://www.chef.io).
Contributors and Copyright holders:
- * Copyright 2008, Adam Jacob <adam@opscode.com>
- * Copyright 2008, Arjuna Christensen <aj@hjksolutions.com>
- * Copyright 2008, Bryan McLellan <btm@loftninjas.org>
- * Copyright 2008, Ezra Zygmuntowicz <ezra@engineyard.com>
- * Copyright 2009, Sean Cribbs <seancribbs@gmail.com>
- * Copyright 2009, Christopher Brown <cb@opscode.com>
- * Copyright 2009, Thom May <thom@clearairturbulence.org>
- * Copyright 2009, Joe Williams <joe@joetify.com>
+ * Copyright 2008-2016, Adam Jacob <adam@chef.io>
+ * Copyright 2008-2016, Arjuna Christensen <aj@hjksolutions.com>
+ * Copyright 2008-2016, Bryan McLellan <btm@loftninjas.org>
+ * Copyright 2008-2016, Ezra Zygmuntowicz <ezra@engineyard.com>
+ * Copyright 2009-2016, Sean Cribbs <seancribbs@gmail.com>
+ * Copyright 2009-2016, Christopher Brown <cb@chef.io>
+ * Copyright 2009-2016, Thom May <thom@clearairturbulence.org>
+ * Copyright 2009-2016, Joe Williams <joe@joetify.com>
Chef incorporates code modified from Open4 (http://www.codeforpeople.com/lib/ruby/open4/), which was written by Ara T. Howard.
-Chef incorporates code modified from deep_merge (http://trac.misuse.org/science/wiki/DeepMerge), which is Copyright (c) 2008 Steve Midgley
+Chef incorporates code modified from deep_merge (http://trac.misuse.org/science/wiki/DeepMerge), which is Copyright 2008-2016, Steve Midgley
Chef incorporates code modified from diff-lcs (http://diff-lcs.rubyforge.org/), which is Copyright (c) 2004–2013 Austin Ziegler
diff --git a/README.md b/README.md
index 49409efe05..3152007551 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,16 @@
-# Chef
-[![Code Climate](https://codeclimate.com/github/chef/chef.png)](https://codeclimate.com/github/chef/chef)
+# Chef
+[![Code Climate](https://codeclimate.com/github/chef/chef.svg)](https://codeclimate.com/github/chef/chef)
[![Build Status Master](https://travis-ci.org/chef/chef.svg?branch=master)](https://travis-ci.org/chef/chef)
[![Build Status Master](https://ci.appveyor.com/api/projects/status/github/chef/chef?branch=master&svg=true&passingText=master%20-%20Ok&pendingText=master%20-%20Pending&failingText=master%20-%20Failing)](https://ci.appveyor.com/project/Chef/chef/branch/master)
+[![Gem Version](https://badge.fury.io/rb/chef.svg)](https://badge.fury.io/rb/chef)
Want to try Chef? Get started with [learnchef](https://learn.chef.io)
-* Documentation: [http://docs.chef.io](http://docs.chef.io)
-* Source: [http://github.com/chef/chef/tree/master](http://github.com/chef/chef/tree/master)
-* Tickets/Issues: [https://github.com/chef/chef/issues](https://github.com/chef/chef/issues)
-* IRC: `#chef` and `#chef-hacking` on Freenode
-* Mailing list: [https://discourse.chef.io](https://discourse.chef.io)
+- Documentation: <https://docs.chef.io>
+- Source: <https://github.com/chef/chef/tree/master>
+- Tickets/Issues: <https://github.com/chef/chef/issues>
+- Slack: [Chef Community Slack](https://community-slack.chef.io/)
+- Mailing list: <https://discourse.chef.io>
Chef is a configuration management tool designed to bring automation to your
entire infrastructure.
@@ -17,71 +18,72 @@ entire infrastructure.
This README focuses on developers who want to modify Chef source code.
If you just want to use Chef, check out these resources:
-* [learnchef](https://learn.chef.io): Getting started guide
-* [http://docs.chef.io](http://docs.chef.io): Comprehensive User Docs
-* [Installer Downloads](https://www.chef.io/download-chef-client/): Install Chef as a complete package
+- [learnchef](https://learn.chef.io): Getting started guide
+- [docs.chef.io](https://docs.chef.io): Comprehensive User Docs
+- [Installer Downloads](https://downloads.chef.io/chef/): Install Chef as a complete package
+- [chef/chef](https://hub.docker.com/r/chef/chef): Docker image for use with [kitchen-dokken](https://github.com/someara/kitchen-dokken)
## Installing From Git
**NOTE:** Unless you have a specific reason to install from source (to
try a new feature, contribute a patch, or run chef on an OS for which no
-package is available), you should head to the [installer page](https://www.chef.io/download-chef-client/)
+package is available), you should head to the [downloads page](https://downloads.chef.io/chef/)
to get a prebuilt package.
### Prerequisites
-Install these via your platform's preferred method (apt, yum, ports,
-emerge, etc.):
+Install these via your platform's preferred method (`apt`, `yum`, `ports`,
+`emerge`, etc.):
* git
* C compiler, header files, etc. On Ubuntu/Debian, use the
`build-essential` package.
-* ruby 2.0.0 or later
+* ruby 2.3.0 or later
* rubygems
-* bundler
+* bundler gem
### Chef Installation
Then get the source and install it:
- # Clone this repo
- git clone https://github.com/chef/chef.git
-
- # cd into the source tree
- cd chef
+```bash
+# Clone this repo
+git clone https://github.com/chef/chef.git
- # Install dependencies with bundler
- bundle install
+# cd into the source tree
+cd chef
- # Build a gem
- rake gem
+# Install dependencies with bundler
+bundle install
- # Install the gem you just built
- gem install pkg/chef-VERSION.gem
+# Build a gem
+bundle exec rake gem
+# Install the gem you just built
+gem install pkg/chef-VERSION.gem
+```
## Contributing/Development
Before working on the code, if you plan to contribute your changes, you need to
read the
-[Chef Contributions document](http://docs.chef.io/community_contributions.html).
+[Chef Contributions document](https://docs.chef.io/community_contributions.html).
The general development process is:
1. Fork this repo and clone it to your workstation.
2. Create a feature branch for your change.
3. Write code and tests.
-4. Push your feature branch to github and open a pull request against
- master.
+4. Push your feature branch to github and open a pull request against master.
-Once your repository is set up, you can start working on the code. We do use
-TDD with RSpec, so you'll need to get a development environment running.
-Follow the above procedure ("Installing from Git") to get your local
-copy of the source running.
+Once your repository is set up, you can start working on the code. We do utilize
+RSpec for test driven development, so you'll need to get a development
+environment running. Follow the above procedure ("Installing from Git") to get
+your local copy of the source running.
## Reporting Issues
-Issues can be reported by using [GitHub issues](https://github.com/chef/chef/issues).
+Issues can be reported by using [GitHub Issues](https://github.com/chef/chef/issues).
Full details on how to report issues can be found in the [CONTRIBUTING](https://github.com/chef/chef/blob/master/CONTRIBUTING.md#-chef-issue-tracking) doc.
@@ -89,7 +91,7 @@ Note that this repository is primarily for reporting chef-client issues.
For reporting issues against other Chef projects, please look up the appropriate repository
to report issues against in the Chef docs in the
[community contributions section](https://docs.chef.io/community_contributions.html#issues-and-bug-reports).
-If you can't detemine the appropriate place to report an issue, then please open it
+If you can't determine the appropriate place to report an issue, then please open it
against the repository you think best fits and it will be directed to the appropriate project.
## Testing
@@ -97,20 +99,191 @@ against the repository you think best fits and it will be directed to the approp
We use RSpec for unit/spec tests. It is not necessary to start the development
environment to run the specs--they are completely standalone.
- # Run All the Tests
- bundle exec rake spec
+```bash
+# Run All the Tests
+bundle exec rake spec
- # Run a Single Test File
- bundle exec rspec spec/PATH/TO/FILE_spec.rb
+# Run a Single Test File
+bundle exec rspec spec/PATH/TO/FILE_spec.rb
- # Run a Subset of Tests
- bundle exec rspec spec/PATH/TO/DIR
+# Run a Subset of Tests
+bundle exec rspec spec/PATH/TO/DIR
+```
When you submit a pull request, we will automatically run the functional and unit
tests in spec/functional/ and spec/unit/ respectively. These will be run on Ubuntu
through Travis CI, and on Windows through AppVeyor. The status of these runs will
be displayed with your pull request.
+## Building the Full Package
+
+To build chef as a standalone package (with ruby and all dependent libraries included in a .deb, .rpm, .pkg or .msi), we use the omnibus system. Go to the [omnibus README](omnibus/README.md) to find out how to build!
+
+## Updating Dependencies
+
+If you want to change our constraints (change which packages and versions we accept in the chef), there are several places to do so:
+
+* To add or remove a gem from chef, or update a gem version, edit [Gemfile](Gemfile).
+* To change the version of binary packages, edit [version_policy.rb](version_policy.rb).
+* To add new packages to chef, edit [omnibus/config/projects/chef.rb](omnibus/config/projects/chef.rb).
+
+Once you've made any changes you want, you have to update the lockfiles that actually drive the build:
+* To update chef's gem dependencies to the very latest versions available, run `rake bundle:update`.
+* To update chef's gem dependencies *conservatively* (changing as little as possible), run `rake bundle:install`.
+* To update specific gems only, run `rake bundle:update[gem1 gem2 ...]`
+* **`bundle update` and `bundle install` will *not* work, on purpose:** the rake task handles both the windows and non-windows lockfiles and updates them in sync.
+
+To perform a full update of all dependencies in chef (including binary packages, tests and build system dependencies), run `rake dependencies`. This will update the `Gemfile.lock`, `omnibus/Gemfile.lock`, `acceptance/Gemfile.lock`, `omnibus/Berksfile.lock`, and `omnibus_overrides.rb`. It will also show you any outdated dependencies due to conflicting constraints. Some outdated dependencies are to be expected; it will inform you if any new ones appear that we don't know about, and tell you how to proceed.
+
+# How Chef Builds and Versions
+
+Chef is an amalgam of many components. These components update all the time, necessitating new builds. This is an overview of the process of versioning, building and releasing Chef.
+
+## Chef Packages
+
+Chef is distributed as packages for debian, rhel, ubuntu, windows, solaris, aix, and os x. It includes a large number of components from various sources, and these are versioned and maintained separately from chef project, which bundles them all together conveniently for the user.
+
+These packages go through several milestones:
+- `master`: When code is checked in to master, the patch version of chef is bumped (e.g. 0.9.10 -> 0.9.11) and a build is kicked off automatically to create and test the packages in Chef's Jenkins cluster.
+- `unstable`: When a package is built, it enters the unstable channel. When all packages for all OS's have successfully built, the test phase is kicked off in Jenkins across all supported OS's. These builds are password-protected and generally only available to the test systems.
+- `current`: If the packages pass all the tests on all supported OS's, it is promoted as a unit to `current`, and is available via Chef's artifactory by running `curl https://www.chef.io/chef/install.sh | sudo bash -s -- -c current -P chef`
+- `stable`: Periodically, Chef will pick a release to "bless" for folks who would like a slower update schedule than "every time a build passes the tests." When this happens, it is manually promoted to stable and an announcement is sent to the list. It can be reached at https://downloads.chef.io or installed using the `curl` command without specifying `-c current`. Packages in `stable` are no longer available in `current`.
+
+Additionally, periodically Chef will update the desired versions of chef components and check that in to `master`, triggering a new build with the updated components in it.
+
+## Automated Version Bumping
+
+Whenever a change is checked in to `master`, the patch version of `chef` is bumped. To do this, the `lita-versioner` bot listens to github for merged PRs, and when it finds one, takes these actions:
+
+1. Bumps the patch version in `lib/chef/version.rb` (e.g. 0.9.14 -> 0.9.15).
+2. Runs `rake bundle:install` to update the `Gemfile.lock` to include the new version.
+3. Runs `rake changelog:update` to update the `CHANGELOG.md`.
+4. Pushes to `master` and submits a new build to Chef's Jenkins cluster.
+
+## Bumping the minor version of Chef
+
+After each "official" stable release we need to bump the minor version. To do this:
+
+1. Run `bundle exec rake version:bump_minor`
+
+Submit a PR with the changes made by the above.
+
+## Addressing a Regression
+
+Sometimes, regressions split through the cracks. Since new functionality is always being added and the minor version is bumped immediately after release, we can't simply roll forward. In this scenario, we'll need to perform a special regression release process. In the example that follows, the stable release with a regression is `1.10.60` while master is currently sitting at `1.11.30`. *Note:* To perform this process, you must be a Chef employee.
+
+1. If the regression has not already been addressed, open a Pull Request against master with the fix.
+2. Wait until that Pull Request has been merged and `1.11.31` has passed all the necessary tests and is available in the current channel.
+3. Inspect the Git history and find the `SHA` associated with the Merge Commit for the Pull Request above.
+4. Apply the fix for the regression via a cherry-pick:
+ 1. Check out the stable release tag: `git checkout v1.10.60`
+ 2. Cherry Pick the SHA with the fix: `git cherry-pick SHA`
+ 3. Address any conflicts (if necessary)
+ 4. Tag the sha with the appropriate version: `git tag -a v1.10.61 -m "Release v1.10.61"`
+ 5. Push the new tag to origin: `git push origin --tags`
+5. Log in to Jenkins and trigger a `chef-trigger-release` job specifying the new tag as the `GIT_REF`.
+
+## Component Versions
+
+Chef has two sorts of component: ruby components like `berkshelf` and `test-kitchen`, and binary components like `openssl` and even `ruby` itself.
+
+In general, you can find all chef desired versions in the [Gemfile](Gemfile) and [version_policy.rb](version_policy.rb) files. The [Gemfile.lock](Gemfile.lock) is the locked version of the Gemfile, and [omnibus_overrides](omnibus_overrides.rb) is the locked version of omnibus. [build](omnibus/Gemfile) and [test](acceptance/Gemfile) Gemfiles and [Berksfile](omnibus/Berksfile) version the toolset we use to build and test.
+
+### Binary Components
+
+The versions of binary components (as well as rubygems and bundler, which can't be versioned in a Gemfile) are stored in [version_policy.rb](version_policy.rb) (the `OMNIBUS_OVERRIDES` constant) and locked in [omnibus_overrides](omnibus_overrides.rb). `rake dependencies` will update the `bundler` version, and the rest are be updated manually by Chef every so often.
+
+These have software definitions either in [omnibus/config/software](omnibus/config/software) or, more often, in the [omnibus-software](https://github.com/chef/omnibus-software/tree/master/config/software) project.
+
+### Rubygems Components
+
+Most of the actual front-facing software in chef is composed of ruby projects. berkshelf, test-kitchen and even chef itself are made of ruby gems. Chef uses the typical ruby way of controlling rubygems versions, the `Gemfile`. Specifically, the `Gemfile` at the top of chef repository governs the version of every single gem we install into chef package. It's a one-stop shop.
+
+Our rubygems component versions are locked down with `Gemfile.lock`, and can be updated with `rake dependencies`.
+
+There are three gems versioned outside the `Gemfile`: `rubygems`, `bundler` and `chef`. `rubygems` and `bundler` are in the `RUBYGEMS_AT_LATEST_VERSION` constant in [version_policy.rb](version-policy.rb) and locked in [omnibus_overrides](omnibus_overrides.rb). They are kept up to date by `rake dependencies`.
+
+**Windows**: [Gemfile.lock](Gemfile.lock) is generated platform-agnostic, and then generated again for Windows. The one file has the solution for both Linux and Windows.
+
+The tool we use to generate Windows-specific lockfiles on non-Windows machines is [tasks/bin/bundle-platform](bundle-platform), which takes the first argument and sets `Gem.platforms`, and then calls `bundle` with the remaining arguments.
+
+### Build Tooling Versions
+
+Of special mention is the software we use to build omnibus itself. There are two distinct bits of code that control the versions of compilers, make, git, and other tools we use to build.
+
+First, the Jenkins machines that run the build are configured entirely by the [opscode-ci cookbook](https://github.com/chef-cookbooks/opscode-ci) cookbook. They install most of the tools we use via `build-essentials`, and standardize the build environment so we can tear down and bring up builders at will. These machines are kept alive long-running, are periodically updated by Chef to the latest opscode-ci, omnibus and build-essentials cookbooks.
+
+Second, the version of omnibus we use to build chef is governed by `omnibus/Gemfile`. When software definitions or the omnibus framework is updated, this is the file that drives whether we pick it up.
+
+The omnibus tooling versions are locked down with `omnibus/Gemfile.lock`, and can be updated by running `rake dependencies`.
+
+### Test Versions
+
+chef is tested by the [chef-acceptance framework](https://github.com/chef/chef-acceptance), which contains suites that are run on the Jenkins test machines. The definitions of the tests are in the `acceptance` directory. The version of chef-acceptance and test-kitchen, are governed by `acceptance/Gemfile`.
+
+The test tooling versions are locked down with `acceptance/Gemfile.lock`, which can be updated by running `rake dependencies`.
+
+## The Build Process
+
+The actual Chef build process is done with Omnibus, and has several general steps:
+
+1. `bundle install` from `chef/Gemfile.lock`
+2. Reinstall any gems that came from git or path using `rake install`
+3. appbundle chef, chef, test-kitchen and berkshelf
+4. Put miscellaneous powershell scripts and cleanup
+
+### Kicking Off The Build
+
+The build is kicked off in Jenkins by running this on the machine (which is already the correct OS and already has the correct dependencies, loaded by the `omnibus` cookbook):
+
+```
+load-omnibus-toolchain.bat
+cd chef/omnibus
+bundle install
+bundle exec omnibus build chef
+```
+
+This causes the [chef project definition](omnibus/config/projects/chef.rb) to load, which runs the [chef-complete](omnibus/config/software/chef-complete.rb) software definition, the primary software definition driving the whole build process. The reason we embed it all in a software definition instead of the project is to take advantage of omnibus caching: omnibus will invalidate the entire project (and recompile ruby, openssl, and everything else) if you change anything at all in the project file. Not so with a software definition.
+
+### Installing the Gems
+
+The primary build definition that installs the many Chef rubygems is [`software/chef.rb`](omnibus/software/chef.rb). This has dependencies on any binary libraries, ruby, rubygems and bundler. It has a lot of steps, so it uses a [library](omnibus/files/chef/build-chef.rb) to help reuse code and make it manageable to look at.
+
+What it does:
+
+1. Depends on software defs for pre-cached gems (see "Gems and Caching" below).
+2. Installs all gems from the bundle:
+ - Sets up a `.bundle/config` ([code](omnibus/files/chef/build-chef.rb#L17-L39)) with --retries=4, --jobs=1, --without=development,no_<platform>, and `build.config.nokogiri` to pass.
+ - Sets up a common environment, standardizing the compilers and flags we use, in [`env`](omnibus/files/chef-gem/build-chef-gem.rb#L32-L54).
+ - [Runs](omnibus/config/software/chef.rb#L68) `bundle install --verbose`
+3. Reinstalls any gems that were installed via path:
+ - [Runs](omnibus/files/chef/build-chef.rb#L80) `bundle list --paths` to get the installed directories of all gems.
+ - For each gem not installed in the main gem dir, [runs](omnibus/files/chef/build-chef.rb#L89) `rake install` from the installed gem directory.
+ - [Deletes](omnibus/files/chef/build-chef.rb#L139-L143) the bundler git cache and path- and git-installed gems from the build.
+4. [Creates](omnibus/files/chef/build-chef.rb#L102-L152) `/opt/chef/Gemfile` and `/opt/chef/Gemfile.lock` with the gems that were installed in the build.
+
+#### Gems and Caching
+
+Some gems take a super long time to install (particularly native-compiled ones such as nokogiri and dep-selector-libgecode) and do not change version very often. In order to avoid doing this work every time, we take advantage of omnibus caching by separating out these gems into their own software definitions. [chef-gem-dep-selector-libgecode](omnibus/config/software/chef-gem-dep-selector-libgecode.rb) for example.
+
+Each of these gems uses the `config/files/chef-gem/build-chef-gem` library to define itself. The name of the software definition itself indicates the .
+
+We only create software definitions for long-running gems. Everything else is just installed in the [chef](omnibus/config/software/chef.rb) software definition in a big `bundle install` catchall.
+
+Most gems we just install in the single `chef` software definition.
+
+The first thing
+
+### Appbundling
+
+After the gems are installed, we *appbundle* them in [chef-appbundle](omnibus/config/software/chef-appbundle.rb). This creates binstubs that use the bundle to pin the software .
+
+During the process of appbundling, we update the gem's `Gemfile` to include the locks in the top level `/opt/chef/Gemfile.lock`, so we can guarantee they will never pick up things outside the build. We then run `bundle lock` to update the gem's `Gemfile.lock`, and `bundle check` to ensure all the gems are actually installed. The appbundler then uses these pins.
+
+### Other Cleanup
+
+Finally, chef does several more steps including installing powershell scripts and shortcuts, and removing extra documentation to keep the build slim.
+
# License
Chef - A configuration management system
@@ -118,9 +291,10 @@ Chef - A configuration management system
| | |
|:---------------------|:-----------------------------------------|
| **Author:** | Adam Jacob (<adam@chef.io>)
-| **Copyright:** | Copyright (c) 2008-2015 Chef Software, Inc.
+| **Copyright:** | Copyright 2008-2016, Chef Software, Inc.
| **License:** | Apache License, Version 2.0
+```
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -132,3 +306,5 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+```
+
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index d95c416a41..7d990d9fe7 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,79 +1,150 @@
-# Chef Client Release Notes 12.5.0:
-* OSX 10.11 support (support for SIP and service changes)
-* Windows cookbook <= 1.38.1 contains a library file which does not compile with
-chef-client 12.5.0. This is resolved in version 1.38.2 of the Windows cookbook.
-Cookbooks depending on the Windows cookbook should update the dependency version
-to at least 1.38.2 to be compatible with chef-client 12.5.0.
+_This file holds "in progress" release notes for the current release under development and is intended for consumption by the Chef Documentation team. Please see <https://docs.chef.io/release_notes.html> for the official Chef release notes._
-## PSCredential support for the `dsc_script` resource
+# Chef Client Release Notes 12.19:
-The `dsc_script` resource now supports the use of the `ps_credential`
-helper method. This method generates a Ruby object which can be described
-as a Powershell PSCredential object. For example, if you wanted to created
-a user using DSC, previously you would have had to do something like:
+## Highlighted enhancements for this release:
+
+- Systemd unit files are now verified before being installed.
+- Added support for windows alternate user identity in execute resources.
+- Added ed25519 key support for for ssh connections.
+
+### Windows alternate user identity execute support
+
+The `execute` resource and similar resources such as `script`, `batch`, and `powershell_script` now support the specification of credentials on Windows so that the resulting process is created with the security identity that corresponds to those credentials.
+
+**Note**: When Chef is running as a service, this feature requires that the user that Chef runs as has 'SeAssignPrimaryTokenPrivilege' (aka 'SE_ASSIGNPRIMARYTOKEN_NAME') user right. By default only LocalSystem and NetworkService have this right when running as a service. This is necessary even if the user is an Administrator.
+
+This right bacn be added and checked in a recipe using this example:
```ruby
-dsc_script 'create-foo-user' do
- code <<-EOH
- $username = "placeholder"
- $password = "#{FooBarBaz1!}" | ConvertTo-SecureString -asPlainText -Force
- $cred = New-Object System.Management.Automation.PSCredential($username, $password)
- User FooUser00
- {
- Ensure = "Present"
- UserName = 'FooUser00'
- Password = $cred
- }
- EOH
- configuration_data_script "path/to/config/data.psd1"
-end
+# Add 'SeAssignPrimaryTokenPrivilege' for the user
+Chef::ReservedNames::Win32::Security.add_account_right('<user>', 'SeAssignPrimaryTokenPrivilege')
+
+# Check if the user has 'SeAssignPrimaryTokenPrivilege' rights
+Chef::ReservedNames::Win32::Security.get_account_right('<user>').include?('SeAssignPrimaryTokenPrivilege')
```
-This can now be replaced with
+#### Properties
+
+The following properties are new or updated for the `execute`, `script`, `batch`, and `powershell_script` resources and any resources derived from them:
+
+- `user`<br>
+ **Ruby types:** String<br>
+ The user name of the user identity with which to launch the new process. Default value: `nil`. The user name may optionally be specified with a domain, i.e. `domain\user` or `user@my.dns.domain.com` via Universal Principal Name (UPN) format. It can also be specified without a domain simply as `user` if the domain is instead specified using the `domain` attribute. On Windows only, if this property is specified, the `password` property **must** be specified.
+
+- `password`<br>
+ **Ruby types** String<br>
+ _Windows only:_ The password of the user specified by the `user` property. Default value: `nil`. This property is mandatory if `user` is specified on Windows and may only be specified if `user` is specified. The `sensitive` property for this resource will automatically be set to `true` if `password` is specified.
+
+- `domain`<br>
+ **Ruby types** String<br>
+ _Windows only:_ The domain of the user user specified by the `user` property. Default value: `nil`. If not specified, the user name and password specified by the `user` and `password` properties will be used to resolve that user against the domain in which the system running Chef client is joined, or if that system is not joined to a domain it will resolve the user as a local account on that system. An alternative way to specify the domain is to leave this property unspecified and specify the domain as part of the `user` property.
+
+#### Usage
+
+The following examples explain how alternate user identity properties can be used in the execute resources:
```ruby
-dsc_script 'create-foo-user' do
+powershell_script 'create powershell-test file' do
code <<-EOH
- User FooUser00
- {
- Ensure = "Present"
- UserName = 'FooUser00'
- Password = #{ps_credential("FooBarBaz1!")}
- }
+ $stream = [System.IO.StreamWriter] "#{Chef::Config[:file_cache_path]}/powershell-test.txt"
+ $stream.WriteLine("In #{Chef::Config[:file_cache_path]}...word.")
+ $stream.close()
EOH
- configuration_data_script "path/to/config/data.psd1"
+ user 'username'
+ password 'password'
+end
+
+execute 'mkdir test_dir' do
+ cwd Chef::Config[:file_cache_path]
+ domain "domain-name"
+ user "user"
+ password "password"
+end
+
+script 'create test_dir' do
+ interpreter "bash"
+ code "mkdir test_dir"
+ cwd Chef::Config[:file_cache_path]
+ user "domain-name\\username"
+ password "password"
+end
+
+batch 'create test_dir' do
+ code "mkdir test_dir"
+ cwd Chef::Config[:file_cache_path]
+ user "username@domain-name"
+ password "password"
end
```
-## New `knife rehash` for faster command loading
+## Highlighted bug fixes for this release:
-The new `knife rehash` command speeds up day-to-day knife usage by
-caching information about installed plugins and available commands.
-Initial testing has shown substantial improvements in `knife` startup
-times for users with a large number of Gems installed and Windows
-users.
+- Ensure that the Windows Administrator group can access the chef-solo nodes directory
+- When loading a cookbook in Chef Solo, use `metadata.json` in preference to `metadata.rb`
-To use this feature, simply run `knife rehash` and continue using
-`knife`. When you install or remove gems that provide knife plugins,
-run `knife rehash` again to keep the cache up to date.
+## Deprecation Notice
-## Support for `/usr/bin/yum-deprecated` in the yum provider
+- As of version 12.19, chef client will no longer be build or tested on the Cisco NX-OS and IOS XR platforms.
-In Fedora 22 yum has been deprecated in favor of DNF. Unfortunately, while DNF tries to be backwards
-compatible with yum, the yum provider in Chef is not compatible with DNF. Until a proper `dnf_package`
-resource and associated provider is written and merged into core, 12.5.0 has been patched so that the
-`yum_package` resource takes a property named `yum_binary` which can be set to point at the yum binary
-to run for all its commands. The `yum_binary` will also default to `yum-deprecated` if the
-`/usr/bin/yum-deprecated` command is found on the system. This means that Fedora 22 users can run
-something like this early in their chef-client run:
+# Ohai Release Notes 8.23:
-```ruby
-if File.exist?("/usr/bin/dnf")
- execute "dnf install -y yum" do
- not_if { File.exist?("/usr/bin/yum-deprecated") }
- end
-end
-```
+## Cumulus Linux Platform
+
+Cumulus Linux will now be detected as platform `cumulus` instead of `debian` and the `platform_version` will be properly set to the Cumulus Linux release.
+
+## Virtualization Detection
+
+Windows / Linux / BSD guests running on the Veertu hypervisors will now be detected
+
+Windows guests running on Xen and Hyper-V hypervisors will now be detected
+
+## New Sysconf Plugin
+
+A new plugin parses the output of the sysconf command to provide information on the underlying system.
+
+## AWS Account ID
+
+The EC2 plugin now fetches the AWS Account ID in addition to previous instance metadata
+
+## GCC Detection
+
+GCC detection has been improved to collect additional information, and to not prompt for the installation of Xcode on macOS systems
+
+## New deprecations introduced in this release:
+
+### Ohai::Config removed
+
+- **Deprecation ID**: OHAI-1
+- **Remediation Docs**: <https://docs.chef.io/deprecations_ohai_legacy_config.html>
+- **Expected Removal**: Ohai 13 (April 2017)
+
+### sigar gem based plugins removed
+
+- **Deprecation ID**: OHAI-2
+- **Remediation Docs**: <https://docs.chef.io/deprecations_ohai_sigar_plugins.html>
+- **Expected Removal**: Ohai 13 (April 2017)
+
+### run_command and popen4 helper methods removed
+
+- **Deprecation ID**: OHAI-3
+- **Remediation Docs**: <https://docs.chef.io/deprecations_ohai_run_command_helpers.html>
+- **Expected Removal**: Ohai 13 (April 2017)
+
+### libvirt plugin attributes moved
+
+- **Deprecation ID**: OHAI-4
+- **Remediation Docs**: <https://docs.chef.io/deprecations_ohai_libvirt_plugin.html>
+- **Expected Removal**: Ohai 13 (April 2017)
+
+### Windows CPU plugin attribute changes
+
+- **Deprecation ID**: OHAI-5
+- **Remediation Docs**: <https://docs.chef.io/deprecations_ohai_windows_cpu.html>
+- **Expected Removal**: Ohai 13 (April 2017)
+
+### DigitalOcean plugin attribute changes
-After which the yum-deprecated binary will exist, and the yum provider will find it and should operate
-normally and successfully.
+- **Deprecation ID**: OHAI-6
+- **Remediation Docs**: <https://docs.chef.io/deprecations_ohai_digitalocean.html>
+- **Expected Removal**: Ohai 13 (April 2017)
diff --git a/ROADMAP.md b/ROADMAP.md
index c726b4e7e5..eeec513a3f 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -4,13 +4,8 @@ This file provides direction for the project as set forth by [RFC030#Roadmap](ht
It is drafted by the Project Lead and the Lieutenants, with input from Maintainers and Contributors.
-## 2015 Q2
-* Core - URL support in package resources
- - For package managment tools where it is appropriate, allow passing a URL as a package source
-* Windows - dsc_resource
- - Adds the ability to use Microsoft Desired State Configuration (DSC) resources in Chef recipes.
-
-## 2015 Q3
-* Windows - Native 64bit support
- - Runs under a 64bit Ruby
-
+## 2016 Q1
+* Windows - core windows_feature
+ - Move windows_feature from Windows cookbook, add caching
+* Windows - knife windows bootstrap, knife windows winrm in core
+ - Migrate Windows bootstrapping functionality into core
diff --git a/Rakefile b/Rakefile
index 6b9a52f68d..311639230b 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,47 +19,86 @@
VERSION = IO.read(File.expand_path("../VERSION", __FILE__)).strip
-require 'rubygems'
-require 'chef-config/package_task'
-require 'rdoc/task'
-require_relative 'tasks/rspec'
-require_relative 'tasks/external_tests'
-require_relative 'tasks/maintainers'
+require "rubygems"
+require "chef/version"
+require "chef-config/package_task"
+require "rdoc/task"
+require_relative "tasks/rspec"
+require_relative "tasks/maintainers"
+require_relative "tasks/cbgb"
+require_relative "tasks/dependencies"
+require_relative "tasks/changelog"
+require_relative "tasks/announce"
-ChefConfig::PackageTask.new(File.expand_path('..', __FILE__), 'Chef') do |package|
- package.component_paths = ['chef-config']
+ChefConfig::PackageTask.new(File.expand_path("..", __FILE__), "Chef", "chef") do |package|
+ package.component_paths = ["chef-config"]
package.generate_version_class = true
end
+# Add conservative dependency update to version:bump (which was created by PackageTask)
+task "version:bump" => %w{version:bump_patch version:update}
+task "version:bump" => %w{version:bump_patch version:update}
-task :pedant do
- require File.expand_path('spec/support/pedant/run_pedant')
+task "version:bump_minor" do
+ Rake::Task["changelog:archive"].invoke
+ maj, min, _build = Chef::VERSION.split(".")
+ File.open("VERSION", "w+") { |f| f.write("#{maj}.#{min.to_i + 1}.0") }
+ Rake::Task["version"].invoke
+ Rake::Task["bundle:install"].invoke
end
+task "version:bump_major" do
+ Rake::Task["changelog:archive"].invoke
+ maj, _min, _build = Chef::VERSION.split(".")
+ File.open("VERSION", "w+") { |f| f.write("#{maj.to_i + 1}.0.0") }
+ Rake::Task["version"].invoke
+ Rake::Task["bundle:install"].invoke
+end
+
+task :pedant, :chef_zero_spec
+
task :build_eventlog do
- Dir.chdir 'ext/win32-eventlog/' do
- system 'rake build'
+ Dir.chdir "ext/win32-eventlog/" do
+ system "rake build"
end
end
task :register_eventlog do
- Dir.chdir 'ext/win32-eventlog/' do
- system 'rake register'
+ Dir.chdir "ext/win32-eventlog/" do
+ system "rake register"
end
end
+desc "Keep the Dockerfile up-to-date"
+task :update_dockerfile do
+ require "mixlib/install"
+ latest_stable_version = Mixlib::Install.available_versions("chef", "stable").last
+ text = File.read("Dockerfile")
+ new_text = text.gsub(/^ARG VERSION=[\d\.]+$/, "ARG VERSION=#{latest_stable_version}")
+ File.open("Dockerfile", "w+") { |f| f.write(new_text) }
+end
+
begin
- require 'yard'
+ require "chefstyle"
+ require "rubocop/rake_task"
+ RuboCop::RakeTask.new(:style) do |task|
+ task.options += ["--display-cop-names", "--no-color"]
+ end
+rescue LoadError
+ puts "chefstyle/rubocop is not available. gem install chefstyle to do style checking."
+end
+
+begin
+ require "yard"
DOC_FILES = [ "README.rdoc", "LICENSE", "spec/tiny_server.rb", "lib/**/*.rb" ]
namespace :yard do
desc "Create YARD documentation"
YARD::Rake::YardocTask.new(:html) do |t|
t.files = DOC_FILES
- t.options = ['--format', 'html']
+ t.options = ["--format", "html"]
end
end
rescue LoadError
puts "yard is not available. (sudo) gem install yard to generate yard documentation."
end
-
diff --git a/VERSION b/VERSION
index 2b4b4d7cb5..2c35ae5b76 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-12.5.1
+12.19.39 \ No newline at end of file
diff --git a/acceptance/.gitignore b/acceptance/.gitignore
new file mode 100644
index 0000000000..4b0b151d75
--- /dev/null
+++ b/acceptance/.gitignore
@@ -0,0 +1,3 @@
+.acceptance_logs
+.acceptance_data
+data-collector/Berksfile.lock
diff --git a/acceptance/.shared/kitchen_acceptance/.kitchen.digitalocean.yml b/acceptance/.shared/kitchen_acceptance/.kitchen.digitalocean.yml
new file mode 100644
index 0000000000..d49d4b9cf0
--- /dev/null
+++ b/acceptance/.shared/kitchen_acceptance/.kitchen.digitalocean.yml
@@ -0,0 +1,33 @@
+# Not quite ready yet
+
+driver:
+ name: digitalocean
+ digitalocean_access_token: <%= ENV['DIGITALOCEAN_API_TOKEN'] %>
+ region: <%= ENV['DIGITALOCEAN_REGION'] %>
+ size: 2gb
+ ssh_key_ids: <%= ENV['DIGITALOCEAN_SSH_KEYS'] %>
+ transport:
+ ssh_key: <%= ENV['DIGITALOCEAN_SSH_KEY_PATH'] %>
+
+provisioner:
+ name: chef_zero
+ product_name: chef
+ product_version: latest
+ channel: current
+
+# busser installation relies on this
+<% if ENV["KITCHEN_CHEF_PRODUCT"] %>
+verifier:
+ chef_omnibus_root: "/opt/<%= ENV["KITCHEN_CHEF_PRODUCT"] %>"
+<% end %>
+
+platforms:
+<% %w(centos-6.5 centos-7.0
+ fedora-21
+ debian-8.1
+ ubuntu-12.04 ubuntu-14.04 ubuntu-15.10
+).each do |platform| %>
+ - name: #{platform}
+ driver_config:
+ image: <%= "#{platform.gsub('.', '-')}-x64" %>
+<% end %>
diff --git a/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml b/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml
new file mode 100644
index 0000000000..caefef49ea
--- /dev/null
+++ b/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml
@@ -0,0 +1,282 @@
+# Not quite ready yet
+
+<%
+def file_if_exists(path)
+ path = File.expand_path(path)
+ File.exist?(path) ? path : nil
+end
+%>
+
+driver:
+ name: ec2
+ tags:
+ X-Dept: Eng
+ X-Contact: product-team
+ X-Application: chef-ci-acceptance
+ aws_ssh_key_id: <%= ENV['AWS_SSH_KEY_ID'] || ENV['USER'] || ENV['USERNAME'] %>
+ # test-specific stuff
+ region: us-west-2
+ subnet_id: subnet-19ac017c
+ security_group_ids: ["sg-e401eb83", "sg-96274af3"]
+ instance_type: m3.large
+# associate_public_ip: true # Don't enable public IP, as subnet specified is behind VPN
+
+# busser installation relies on this
+<% if ENV["KITCHEN_CHEF_PRODUCT"] %>
+verifier:
+ chef_omnibus_root: "/opt/<%= ENV["KITCHEN_CHEF_PRODUCT"] %>"
+<% end %>
+
+transport:
+ ssh_key: <%= file_if_exists("~/.ssh/#{ENV['AWS_SSH_KEY_ID'] || ENV['USER'] || ENV['USERNAME']}.pem") ||
+ file_if_exists("~/.ssh/#{ENV['AWS_SSH_KEY_ID'] || ENV['USER'] || ENV['USERNAME']}") ||
+ file_if_exists("~/.ssh/id_rsa") %>
+
+provisioner:
+ name: chef_zero
+ product_name: <%= ENV["KITCHEN_CHEF_PRODUCT"] %>
+ product_version: <%= ENV["KITCHEN_CHEF_VERSION"] %>
+ channel: <%= ENV["KITCHEN_CHEF_CHANNEL"] %>
+ client_rb:
+ audit_mode: :enabled
+ attributes:
+ chef_acceptance: "true"
+ use_system_chef: "true"
+
+platforms:
+ #
+ # AIX
+ #
+ # - name: aix-6.1
+ # - name: aix-7.1
+ #
+ # Debian
+ #
+ - name: debian-8
+ driver:
+ image_search:
+ name: debian-jessie-*
+ owner-id: "379101102735"
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: gp2
+ image-type: machine
+ transport:
+ username: admin
+ - name: debian-7
+ driver:
+ image_search:
+ name: debian-wheezy-*
+ owner-id: "379101102735"
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: standard
+ image-type: machine
+ transport:
+ username: admin
+ #
+ # Ubuntu
+ #
+ - name: ubuntu-15.10
+ driver:
+ image_search:
+ name: ubuntu/images/*/ubuntu-*-15.10-amd64-server-*
+ owner-id: "099720109477"
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: gp2
+ image-type: machine
+ transport:
+ username: ubuntu
+ - name: ubuntu-14.04
+ driver:
+ image_search:
+ name: ubuntu/images/*/ubuntu-*-14.04-*-server-*
+ owner-id: "099720109477"
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: gp2
+ image-type: machine
+ transport:
+ username: ubuntu
+ - name: ubuntu-12.04
+ driver:
+ image_search:
+ name: ubuntu/images/*/ubuntu-*-12.04-*-server-*
+ owner-id: "099720109477"
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: gp2
+ image-type: machine
+ transport:
+ username: ubuntu
+ #
+ # Red Hat Enterprise Linux
+ #
+ - name: el-7
+ driver:
+ image_search:
+ name: RHEL-7.*
+ owner-id: "309956199498"
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: gp2
+ image-type: machine
+ transport:
+ username: ec2-user
+ - name: el-6
+ driver:
+ image_search:
+ name: RHEL-6.*
+ owner-id: "309956199498"
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: gp2
+ image-type: machine
+ transport:
+ username: ec2-user
+ - name: el-5
+ driver:
+ image_search:
+ name: RHEL-5.*
+ owner-id: "309956199498"
+ architecture: x86_64
+ virtualization-type: paravirtual
+ block-device-mapping.volume-type: gp2
+ image-type: machine
+ transport:
+ username: ec2-user
+ #
+ # FreeBSD
+ #
+ - name: freebsd-10
+ driver:
+ image_search:
+ name: FreeBSD/EC2 10.*-RELEASE*
+ owner-id: "118940168514"
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: gp2
+ image-type: machine
+ transport:
+ username: ec2-user
+ - name: freebsd-9
+ driver:
+ image_search:
+ name: FreeBSD/EC2 9.*-RELEASE*
+ owner-id: "118940168514"
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: gp2
+ image-type: machine
+ transport:
+ username: ec2-user
+ - name: freebsd-8
+ driver:
+ image_search:
+ name: FreeBSD/EC2 8.*-RELEASE*
+ owner-id: "118940168514"
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: standard
+ image-type: machine
+ transport:
+ username: ec2-user
+ #
+ # OS/X
+ #
+ # - name: mac_os_x-10.11
+ # - name: mac_os_x-10.10
+ # - name: mac_os_x-10.9
+ # - name: mac_os_x-10.8
+ #
+ # Nexus???
+ #
+ # - name: nexus-7
+ #
+ # Solaris
+ #
+ # - name: solaris-11
+ # - name: solaris-10
+ #
+ # Windows
+ #
+ - name: windows-2012r2
+ provisioner:
+ architecture: <%= ENV["KITCHEN_CHEF_WIN_ARCHITECTURE"] %>
+ driver:
+ image_search:
+ name: Windows_Server-2012-R2*-English-*-Base-*
+ owner-alias: amazon
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: gp2
+ image-type: machine
+ user_data: |
+ <powershell>
+ & netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" profile=public protocol=tcp localport=5985 remoteip=localsubnet new remoteip=any
+ #Set script execution to unrestricted
+ & Set-ExecutionPolicy Unrestricted -Force
+ </powershell>
+ transport:
+ username: administrator
+
+ - name: windows-2012
+ driver:
+ image_search:
+ name: Windows_Server-2012-RTM*-English-*-Base-*
+ owner-alias: amazon
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: gp2
+ image-type: machine
+ transport:
+ username: administrator
+ - name: windows-2008r2
+ driver:
+ image_search:
+ name: Windows_Server-2008-R2*-English-*-Base-*
+ owner-alias: amazon
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: gp2
+ image-type: machine
+ transport:
+ username: administrator
+ #
+ # Centos
+ #
+ - name: centos-7
+ driver:
+ image_search:
+ name: CentOS Linux 7 *
+ owner-alias: aws-marketplace
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: standard
+ image-type: machine
+ transport:
+ username: root
+ - name: centos-6
+ driver:
+ image_search:
+ name: CentOS-6.5-GA-*
+ owner-alias: aws-marketplace
+ architecture: x86_64
+ virtualization-type: paravirtual
+ block-device-mapping.volume-type: standard
+ image-type: machine
+ transport:
+ username: root
+ #
+ # Fedora
+ #
+ - name: fedora-21
+ driver:
+ image_search:
+ name: Fedora-Cloud-Base-21-*
+ owner-id: "125523088429"
+ architecture: x86_64
+ virtualization-type: hvm
+ block-device-mapping.volume-type: gp2
+ image-type: machine
diff --git a/acceptance/.shared/kitchen_acceptance/.kitchen.vagrant.yml b/acceptance/.shared/kitchen_acceptance/.kitchen.vagrant.yml
new file mode 100644
index 0000000000..954f5e9eb1
--- /dev/null
+++ b/acceptance/.shared/kitchen_acceptance/.kitchen.vagrant.yml
@@ -0,0 +1,59 @@
+driver:
+ name: vagrant
+ forward_agent: yes
+ customize:
+ cpus: 2
+ memory: 1024
+
+provisioner:
+ name: chef_zero
+ product_name: <%= ENV["KITCHEN_CHEF_PRODUCT"] %>
+ product_version: <%= ENV["KITCHEN_CHEF_VERSION"] %>
+ channel: <%= ENV["KITCHEN_CHEF_CHANNEL"] %>
+ client_rb:
+ audit_mode: :enabled
+ attributes:
+ chef_acceptance: "true"
+ use_system_chef: "true"
+
+# busser installation relies on this
+<% if ENV["KITCHEN_CHEF_PRODUCT"] %>
+verifier:
+ chef_omnibus_root: "/opt/<%= ENV["KITCHEN_CHEF_PRODUCT"] %>"
+<% end %>
+
+platforms:
+<% %w(
+debian-8
+debian-7
+debian-6
+ubuntu-15.10
+ubuntu-14.04
+el-7
+el-6
+el-5
+freebsd-10
+freebsd-9
+fedora-21
+).each do |platform| %>
+ - name: <%= platform %>
+ driver:
+ box: opscode-<%= platform %>
+ box_url: http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_<%= platform %>_chef-provisionerless.box
+<% end %>
+# freebsd-8
+# ubuntu-12.04
+# centos-7
+ - name: centos-6
+ driver:
+ box: bento/centos-6.7
+<% %w(
+2012r2
+2012
+2008r2
+).each do |version| %>
+ - name: windows-<%= version %>
+ driver:
+ box: chef/windows-server-<%= version %>-standard
+# URL is atlas
+<% end %>
diff --git a/acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb b/acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb
new file mode 100644
index 0000000000..d5d2e1380b
--- /dev/null
+++ b/acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb
@@ -0,0 +1,68 @@
+require 'chef/mixin/shell_out'
+
+module KitchenAcceptance
+ class Kitchen < Chef::Resource
+ resource_name :kitchen
+
+ property :command, String, name_property: true
+ property :driver, %w(ec2 vagrant), coerce: proc { |v| v.to_s }, default: lazy { ENV["KITCHEN_DRIVER"] || :ec2 }
+ property :instances, String, default: lazy { ENV["KITCHEN_INSTANCES"] ? ENV["KITCHEN_INSTANCES"] : "" }
+ property :kitchen_dir, String, default: Chef.node['chef-acceptance']['suite-dir']
+ property :chef_product, String, default: lazy {
+ ENV["KITCHEN_CHEF_PRODUCT"] || begin
+ # Figure out if we're in chefdk or chef
+ if ::File.exist?(::File.expand_path("../../chef-dk.gemspec", node['chef-acceptance']['suite-dir']))
+ "chefdk"
+ else
+ "chef"
+ end
+ end
+ }
+ property :chef_channel, String, default: lazy {
+ ENV["KITCHEN_CHEF_CHANNEL"] ||
+ # Pick up current if we can't connect to artifactory
+ (ENV["ARTIFACTORY_USERNAME"] ? "unstable" : "current")
+ }
+ property :chef_version, String, default: lazy {
+ ENV["KITCHEN_CHEF_VERSION"] ||
+ # If we're running the chef or chefdk projects in jenkins, pick up the project name.
+ (ENV["PROJECT_NAME"] == chef_product ? ENV["OMNIBUS_BUILD_VERSION"] : nil) ||
+ "latest"
+ }
+ property :artifactory_username, String, default: lazy { ENV["ARTIFACTORY_USERNAME"] ? ENV["ARTIFACTORY_USERNAME"] : "" }
+ property :artifactory_password, String, default: lazy { ENV["ARTIFACTORY_PASSWORD"] ? ENV["ARTIFACTORY_PASSWORD"] : "" }
+ property :env, Hash, default: {}
+ property :kitchen_options, String, default: lazy { ENV["PROJECT_NAME"] ? "-c -l debug" : "-c" }
+
+ action :run do
+
+ ruby_block "copy_kitchen_logs_to_data_path" do
+ block do
+ cmd_env = {
+ "KITCHEN_DRIVER" => driver,
+ "KITCHEN_INSTANCES" => instances,
+ "KITCHEN_LOCAL_YAML" => ::File.expand_path("../../.kitchen.#{driver}.yml", __FILE__),
+ "KITCHEN_CHEF_PRODUCT" => chef_product,
+ "KITCHEN_CHEF_CHANNEL" => chef_channel,
+ "KITCHEN_CHEF_VERSION" => chef_version,
+ "ARTIFACTORY_USERNAME" => artifactory_username,
+ "ARTIFACTORY_PASSWORD" => artifactory_password
+ }.merge(new_resource.env)
+ suite = kitchen_dir.split("/").last
+ kitchen_log_path = ENV["WORKSPACE"] ? "#{ENV["WORKSPACE"]}/chef-acceptance-data/logs" : "#{kitchen_dir}/../.acceptance_data/logs/"
+
+ begin
+ shell_out!("bundle exec kitchen #{command}#{instances ? " #{instances}" : ""}#{kitchen_options ? " #{kitchen_options}" : ""}",
+ env: cmd_env,
+ timeout: 60 * 30,
+ live_stream: STDOUT,
+ cwd: kitchen_dir)
+ ensure
+ FileUtils.mkdir_p("#{kitchen_log_path}/#{suite}/#{command}")
+ FileUtils.cp_r("#{kitchen_dir}/.kitchen/logs/.", "#{kitchen_log_path}/#{suite}/#{command}")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/acceptance/.shared/kitchen_acceptance/metadata.rb b/acceptance/.shared/kitchen_acceptance/metadata.rb
new file mode 100644
index 0000000000..70dc342d09
--- /dev/null
+++ b/acceptance/.shared/kitchen_acceptance/metadata.rb
@@ -0,0 +1 @@
+name "kitchen_acceptance"
diff --git a/acceptance/Gemfile b/acceptance/Gemfile
new file mode 100644
index 0000000000..41a18c9914
--- /dev/null
+++ b/acceptance/Gemfile
@@ -0,0 +1,16 @@
+source "https://rubygems.org"
+
+gem "rake" # required to build some native extensions
+gem "chef-acceptance", github: "chef/chef-acceptance"
+gem "kitchen-ec2"
+gem "inspec"
+gem "kitchen-vagrant"
+gem "windows_chef_zero"
+gem "kitchen-inspec"
+gem "test-kitchen"
+gem "winrm-elevated"
+gem "berkshelf"
+
+# Pin to 1.2.3 because current mixlib-install has a problem where unstable
+# packages are not always immediately available via the omnitruck API.
+gem "mixlib-install", "1.2.3"
diff --git a/acceptance/Gemfile.lock b/acceptance/Gemfile.lock
new file mode 100644
index 0000000000..8dfb2ec217
--- /dev/null
+++ b/acceptance/Gemfile.lock
@@ -0,0 +1,258 @@
+GIT
+ remote: git://github.com/chef/chef-acceptance.git
+ revision: e92ddae46d2126864698b9c8e4fc4ec2dcc46c55
+ specs:
+ chef-acceptance (0.2.0)
+ mixlib-shellout (~> 2.0)
+ thor (~> 0.19)
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ addressable (2.5.0)
+ public_suffix (~> 2.0, >= 2.0.2)
+ artifactory (2.6.0)
+ aws-sdk (2.7.5)
+ aws-sdk-resources (= 2.7.5)
+ aws-sdk-core (2.7.5)
+ aws-sigv4 (~> 1.0)
+ jmespath (~> 1.0)
+ aws-sdk-resources (2.7.5)
+ aws-sdk-core (= 2.7.5)
+ aws-sigv4 (1.0.0)
+ berkshelf (5.6.2)
+ addressable (~> 2.3, >= 2.3.4)
+ berkshelf-api-client (>= 2.0.2, < 4.0)
+ buff-config (~> 2.0)
+ buff-extensions (~> 2.0)
+ buff-shell_out (~> 1.0)
+ cleanroom (~> 1.0)
+ faraday (~> 0.9)
+ httpclient (~> 2.7)
+ minitar (~> 0.5, >= 0.5.4)
+ mixlib-archive (~> 0.4)
+ octokit (~> 4.0)
+ retryable (~> 2.0)
+ ridley (~> 5.0)
+ solve (> 2.0, < 4.0)
+ thor (~> 0.19, < 0.19.2)
+ berkshelf-api-client (3.0.0)
+ faraday (~> 0.9)
+ httpclient (~> 2.7)
+ ridley (>= 4.5, < 6.0)
+ buff-config (2.0.0)
+ buff-extensions (~> 2.0)
+ varia_model (~> 0.6)
+ buff-extensions (2.0.0)
+ buff-ignore (1.2.0)
+ buff-ruby_engine (1.0.0)
+ buff-shell_out (1.1.0)
+ buff-ruby_engine (~> 1.0)
+ builder (3.2.3)
+ celluloid (0.16.0)
+ timers (~> 4.0.0)
+ celluloid-io (0.16.2)
+ celluloid (>= 0.16.0)
+ nio4r (>= 1.1.0)
+ chef-config (12.18.31)
+ addressable
+ fuzzyurl
+ mixlib-config (~> 2.0)
+ mixlib-shellout (~> 2.0)
+ cleanroom (1.0.0)
+ coderay (1.1.1)
+ diff-lcs (1.3)
+ docker-api (1.33.2)
+ excon (>= 0.38.0)
+ json
+ erubis (2.7.0)
+ excon (0.55.0)
+ faraday (0.9.2)
+ multipart-post (>= 1.2, < 3)
+ ffi (1.9.17)
+ fuzzyurl (0.9.0)
+ gssapi (1.2.0)
+ ffi (>= 1.0.1)
+ gyoku (1.3.1)
+ builder (>= 2.1.2)
+ hashie (3.5.1)
+ hitimes (1.2.4)
+ httpclient (2.8.3)
+ inspec (1.14.1)
+ faraday (>= 0.9.0)
+ hashie (~> 3.4)
+ json (>= 1.8, < 3.0)
+ method_source (~> 0.8)
+ mixlib-log
+ parallel (~> 1.9)
+ pry (~> 0)
+ rainbow (~> 2)
+ rspec (~> 3)
+ rspec-its (~> 1.2)
+ rspec_junit_formatter (~> 0.2.3)
+ rubyzip (~> 1.1)
+ sslshake (~> 1)
+ thor (~> 0.19)
+ train (>= 0.22.0, < 1.0)
+ jmespath (1.3.1)
+ json (2.0.3)
+ kitchen-ec2 (1.2.0)
+ aws-sdk (~> 2)
+ excon
+ multi_json
+ retryable (~> 2.0)
+ test-kitchen (~> 1.4, >= 1.4.1)
+ kitchen-inspec (0.17.0)
+ hashie (~> 3.4)
+ inspec (>= 0.34.0, < 2.0.0)
+ test-kitchen (~> 1.6)
+ kitchen-vagrant (1.0.0)
+ test-kitchen (~> 1.4)
+ little-plugger (1.1.4)
+ logging (2.1.0)
+ little-plugger (~> 1.1)
+ multi_json (~> 1.10)
+ method_source (0.8.2)
+ minitar (0.6.1)
+ mixlib-archive (0.4.1)
+ mixlib-log
+ mixlib-authentication (1.4.1)
+ mixlib-log
+ mixlib-config (2.2.4)
+ mixlib-install (1.2.3)
+ artifactory
+ mixlib-shellout
+ mixlib-versioning
+ mixlib-log (1.7.1)
+ mixlib-shellout (2.2.7)
+ mixlib-versioning (1.1.0)
+ molinillo (0.5.6)
+ multi_json (1.12.1)
+ multipart-post (2.0.0)
+ net-scp (1.2.1)
+ net-ssh (>= 2.6.5)
+ net-ssh (4.0.1)
+ net-ssh-gateway (1.3.0)
+ net-ssh (>= 2.6.5)
+ nio4r (2.0.0)
+ nori (2.6.0)
+ octokit (4.6.2)
+ sawyer (~> 0.8.0, >= 0.5.3)
+ parallel (1.10.0)
+ pry (0.10.4)
+ coderay (~> 1.1.0)
+ method_source (~> 0.8.1)
+ slop (~> 3.4)
+ public_suffix (2.0.5)
+ rainbow (2.2.1)
+ rake (12.0.0)
+ retryable (2.0.4)
+ ridley (5.1.0)
+ addressable
+ buff-config (~> 2.0)
+ buff-extensions (~> 2.0)
+ buff-ignore (~> 1.2)
+ buff-shell_out (~> 1.0)
+ celluloid (~> 0.16.0)
+ celluloid-io (~> 0.16.1)
+ chef-config (>= 12.5.0)
+ erubis
+ faraday (~> 0.9.0)
+ hashie (>= 2.0.2, < 4.0.0)
+ httpclient (~> 2.7)
+ json (>= 1.7.7)
+ mixlib-authentication (>= 1.3.0)
+ retryable (~> 2.0)
+ semverse (~> 2.0)
+ varia_model (~> 0.6)
+ rspec (3.5.0)
+ rspec-core (~> 3.5.0)
+ rspec-expectations (~> 3.5.0)
+ rspec-mocks (~> 3.5.0)
+ rspec-core (3.5.4)
+ rspec-support (~> 3.5.0)
+ rspec-expectations (3.5.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.5.0)
+ rspec-its (1.2.0)
+ rspec-core (>= 3.0.0)
+ rspec-expectations (>= 3.0.0)
+ rspec-mocks (3.5.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.5.0)
+ rspec-support (3.5.0)
+ rspec_junit_formatter (0.2.3)
+ builder (< 4)
+ rspec-core (>= 2, < 4, != 2.12.0)
+ rubyntlm (0.6.1)
+ rubyzip (1.2.1)
+ safe_yaml (1.0.4)
+ sawyer (0.8.1)
+ addressable (>= 2.3.5, < 2.6)
+ faraday (~> 0.8, < 1.0)
+ semverse (2.0.0)
+ slop (3.6.0)
+ solve (3.1.0)
+ molinillo (>= 0.5)
+ semverse (>= 1.1, < 3.0)
+ sslshake (1.0.13)
+ test-kitchen (1.15.0)
+ mixlib-install (>= 1.2, < 3.0)
+ mixlib-shellout (>= 1.2, < 3.0)
+ net-scp (~> 1.1)
+ net-ssh (>= 2.9, < 5.0)
+ net-ssh-gateway (~> 1.2)
+ safe_yaml (~> 1.0)
+ thor (~> 0.18)
+ thor (0.19.1)
+ timers (4.0.4)
+ hitimes
+ train (0.22.1)
+ docker-api (~> 1.26)
+ json (>= 1.8, < 3.0)
+ mixlib-shellout (~> 2.0)
+ net-scp (~> 1.2)
+ net-ssh (>= 2.9, < 5.0)
+ winrm (~> 2.0)
+ winrm-fs (~> 1.0)
+ varia_model (0.6.0)
+ buff-extensions (~> 2.0)
+ hashie (>= 2.0.2, < 4.0.0)
+ windows_chef_zero (2.0.0)
+ test-kitchen (>= 1.2.1)
+ winrm (2.1.2)
+ builder (>= 2.1.2)
+ erubis (~> 2.7)
+ gssapi (~> 1.2)
+ gyoku (~> 1.0)
+ httpclient (~> 2.2, >= 2.2.0.2)
+ logging (>= 1.6.1, < 3.0)
+ nori (~> 2.0)
+ rubyntlm (~> 0.6.0, >= 0.6.1)
+ winrm-elevated (1.1.0)
+ winrm (~> 2.0)
+ winrm-fs (~> 1.0)
+ winrm-fs (1.0.1)
+ erubis (~> 2.7)
+ logging (>= 1.6.1, < 3.0)
+ rubyzip (~> 1.1)
+ winrm (~> 2.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ berkshelf
+ chef-acceptance!
+ inspec
+ kitchen-ec2
+ kitchen-inspec
+ kitchen-vagrant
+ mixlib-install (= 1.2.3)
+ rake
+ test-kitchen
+ windows_chef_zero
+ winrm-elevated
+
+BUNDLED WITH
+ 1.12.5
diff --git a/acceptance/README.md b/acceptance/README.md
new file mode 100644
index 0000000000..992129bf2b
--- /dev/null
+++ b/acceptance/README.md
@@ -0,0 +1,137 @@
+# Acceptance Testing for Chef Client
+
+This folder contains acceptance tests that are required for Chef client release readiness.
+
+## Getting started
+
+The tests use the _chef-acceptance_ gem as the high level framework. All the gems needed to run these tests can be installed with Bundler from this directory.
+
+### Important Note!
+
+Before running chef-acceptance, you _MUST_ do the following on your current session:
+
+```shell
+export APPBUNDLER_ALLOW_RVM=true
+```
+
+## Pre-requisites / One time set up
+
+### Set up for local VM (Vagrant)
+
+If you intend to run the acceptance tests on a local VM, the supported solution is to use Vagrant. Ensure that Vagrant is installed on the machine that tests will run from, along with a virtualization driver (E.g.: VirtualBox).
+
+Set up the KITCHEN_DRIVER environment variable appropriately (value should be "vagrant"). E.g.:
+
+```shell
+export KITCHEN_DRIVER=vagrant
+```
+
+Add this to your shell profile or startup script as needed.
+
+### Set up for cloud VM (EC2)
+
+If you intend to run the acceptance tests on a cloud VM, the supported solution is to use EC2.
+
+The steps you will need to do are:
+
+1. Add your AWS credentials to the machine - e.g., to the ~/.aws/credentials directory.
+
+ - The easiest way to do this is to download the aws command line (`brew install awscli` on OS/X) and run `aws configure`.
+
+2. Create or import a SSH key to AWS. (If you already have one, you can skip the import/create)
+
+ - In the AWS console, click Key Pairs, then Create Key Pair or Import Key Pair.
+
+3. Copy or move the private key file (USERNAME.pem) to the SSH folder (e.g. `~/.ssh/USERNAME.pem`).
+
+ - If you Created a key pair in step 2, download the private key and move it to `~/.ssh`.
+ - If you Importd a key pair in step 2, just ensure your private key is in `~/.ssh` and has the same name as the key pair (`~/.ssh/USERNAME` or `~/.ssh/USERNAME.pem`).
+
+4. Set AWS_SSH_KEY_ID to the SSH key name.
+
+ - This is **optional** if your AWS SSH key name is your local username.
+ - You may want to set this in your shell `.profile`.
+
+ ```shell
+ export AWS_SSH_KEY_ID=name-of-private-key
+ ```
+
+5. Set the private key to only be readable by root
+
+ ```shell
+ chmod 0400 ~/.ssh/USERNAME.pem
+ ```
+
+6. Set up the KITCHEN_DRIVER environment variable appropriately (value should be "ec2"). (This is optional, as ec2 is the default.) E.g.:
+
+ ```shell
+ export KITCHEN_DRIVER=ec2
+ ```
+
+ Add this to your shell profile or startup script as needed.
+
+7. **Connect to Chef VPN**. The instances you create will not have public IPs!
+
+## Setting up and running a test suite
+
+To get started, do a bundle install from the acceptance directory:
+
+```shell
+chef/acceptance$ bundle install --binstubs
+```
+
+To get some basic info and ensure chef-acceptance can be run, do:
+
+```shell
+chef/acceptance$ bin/chef-acceptance info
+```
+
+To run a particular test suite, do the following:
+
+```shell
+chef/acceptance$ bin/chef-acceptance test TEST_SUITE
+```
+
+To restrict which OS's will run, use the KITCHEN_INSTANCES environment variable:
+
+```shell
+chef/acceptance$ export KITCHEN_INSTANCES=*-ubuntu-1404
+chef/acceptance$ bin/chef-acceptance test cookbook-git
+```
+
+If KITCHEN_INSTANCES is not specified, the default instances are default-ubuntu-1404 and default-windows-windows-2012r2\. All selected instances will be run in _parallel_ if the driver supports it (ec2 does, vagrant doesn't).
+
+## Optional Settings
+
+In addition to the environment settings above, there are a number of key values that are available to set for changing the way the acceptance tests are run.
+
+### KITCHEN_CHEF_CHANNEL
+
+Use this setting to specify which channel we will pull the chef build from. The default is to use the "current" channel, unless the ARTIFACTORY_USERNAME is set (which normally happens when running under Jenkins), in which case the default is changed to "unstable".
+
+```shell
+export KITCHEN_CHEF_CHANNEL=name-of-channel
+```
+
+### KITCHEN_CHEF_VERSION
+
+Use this setting to override the version of the Chef client that is installed. The default is to get the latest version in the desired channel.
+
+```shell
+export KITCHEN_CHEF_VERSION=version-of-chef-client
+```
+
+### ARTIFACTORY_USERNAME / ARTIFACTORY_PASSWORD
+
+If the desired channel to get the Chef client from is "unstable", the following settings need to be exported:
+
+```shell
+export ARTIFACTORY_USERNAME=username
+export ARTIFACTORY_PASSWORD=password
+```
+
+## Future Work
+
+Currently, there is no simple mechanism for chef-acceptance to build an Omnibus package of the developers local chef instance and run acceptance tests on it - the only packages that can be exercised are ones that come from one of the pipeline channels (unstable, current or stable).
+
+This is not an issue when adding acceptance tests for pre-existing functionality (as that functionality is presumed to already be in a build in one of the pipeline channels).
diff --git a/acceptance/basics/.acceptance/acceptance-cookbook/.gitignore b/acceptance/basics/.acceptance/acceptance-cookbook/.gitignore
new file mode 100644
index 0000000000..041413b040
--- /dev/null
+++ b/acceptance/basics/.acceptance/acceptance-cookbook/.gitignore
@@ -0,0 +1,2 @@
+nodes/
+tmp/
diff --git a/acceptance/basics/.acceptance/acceptance-cookbook/metadata.rb b/acceptance/basics/.acceptance/acceptance-cookbook/metadata.rb
new file mode 100644
index 0000000000..2b7547b70d
--- /dev/null
+++ b/acceptance/basics/.acceptance/acceptance-cookbook/metadata.rb
@@ -0,0 +1,3 @@
+name 'acceptance-cookbook'
+
+depends "kitchen_acceptance"
diff --git a/acceptance/basics/.acceptance/acceptance-cookbook/recipes/destroy.rb b/acceptance/basics/.acceptance/acceptance-cookbook/recipes/destroy.rb
new file mode 100644
index 0000000000..e2d663ac2f
--- /dev/null
+++ b/acceptance/basics/.acceptance/acceptance-cookbook/recipes/destroy.rb
@@ -0,0 +1 @@
+kitchen "destroy"
diff --git a/acceptance/basics/.acceptance/acceptance-cookbook/recipes/provision.rb b/acceptance/basics/.acceptance/acceptance-cookbook/recipes/provision.rb
new file mode 100644
index 0000000000..5726c0e7b5
--- /dev/null
+++ b/acceptance/basics/.acceptance/acceptance-cookbook/recipes/provision.rb
@@ -0,0 +1 @@
+kitchen "converge"
diff --git a/acceptance/basics/.acceptance/acceptance-cookbook/recipes/verify.rb b/acceptance/basics/.acceptance/acceptance-cookbook/recipes/verify.rb
new file mode 100644
index 0000000000..05ac94ce66
--- /dev/null
+++ b/acceptance/basics/.acceptance/acceptance-cookbook/recipes/verify.rb
@@ -0,0 +1 @@
+kitchen "verify"
diff --git a/acceptance/basics/.kitchen.yml b/acceptance/basics/.kitchen.yml
new file mode 100644
index 0000000000..4b7a516396
--- /dev/null
+++ b/acceptance/basics/.kitchen.yml
@@ -0,0 +1,4 @@
+suites:
+ - name: chef-current-install
+ includes: [ubuntu-14.04, windows-server-2012r2]
+ run_list:
diff --git a/acceptance/basics/test/integration/chef-current-install/serverspec/chef_client_spec.rb b/acceptance/basics/test/integration/chef-current-install/serverspec/chef_client_spec.rb
new file mode 100644
index 0000000000..dd0e0e4e34
--- /dev/null
+++ b/acceptance/basics/test/integration/chef-current-install/serverspec/chef_client_spec.rb
@@ -0,0 +1,19 @@
+
+require "spec_helper"
+
+gem_path = "/opt/chef/embedded/bin/gem"
+white_list = %w{chef-config json rake}
+
+describe "gem list" do
+ it "should not have non-whitelisted duplicate gems" do
+ gems = command("#{gem_path} list").stdout
+
+ duplicate_gems = gems.lines().select { |l| l.include?(",") }.collect { |l| l.split(" ").first }
+ puts "Duplicate gems found: #{duplicate_gems}" if duplicate_gems.length > 0
+
+ non_whitelisted_duplicates = duplicate_gems.select { |l| !white_list.include?(l) }
+ puts "Non white listed duplicates: #{non_whitelisted_duplicates}" if non_whitelisted_duplicates.length > 0
+
+ (non_whitelisted_duplicates.length).should be == 0
+ end
+end
diff --git a/acceptance/basics/test/integration/chef-current-install/serverspec/spec_helper.rb b/acceptance/basics/test/integration/chef-current-install/serverspec/spec_helper.rb
new file mode 100644
index 0000000000..7189ddb13b
--- /dev/null
+++ b/acceptance/basics/test/integration/chef-current-install/serverspec/spec_helper.rb
@@ -0,0 +1,6 @@
+require "serverspec"
+require "pathname"
+
+set :backend, :exec
+
+set :path, "/bin:/usr/local/bin:$PATH"
diff --git a/acceptance/basics/test/integration/helpers/serverspec/Gemfile b/acceptance/basics/test/integration/helpers/serverspec/Gemfile
new file mode 100644
index 0000000000..b56d1e1298
--- /dev/null
+++ b/acceptance/basics/test/integration/helpers/serverspec/Gemfile
@@ -0,0 +1,8 @@
+source "https://rubygems.org"
+
+# Until https://github.com/test-kitchen/busser-serverspec/pull/42 is merged and
+# released, we need to include rake and rspec-core in the Gemfile
+gem "rake"
+gem "rspec-core"
+gem "busser-serverspec"
+gem "serverspec"
diff --git a/acceptance/data-collector/.acceptance/acceptance-cookbook/.gitignore b/acceptance/data-collector/.acceptance/acceptance-cookbook/.gitignore
new file mode 100644
index 0000000000..041413b040
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/acceptance-cookbook/.gitignore
@@ -0,0 +1,2 @@
+nodes/
+tmp/
diff --git a/acceptance/data-collector/.acceptance/acceptance-cookbook/metadata.rb b/acceptance/data-collector/.acceptance/acceptance-cookbook/metadata.rb
new file mode 100644
index 0000000000..68fc3af2dd
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/acceptance-cookbook/metadata.rb
@@ -0,0 +1,3 @@
+name 'acceptance-cookbook'
+depends "kitchen_acceptance"
+depends "data-collector-test"
diff --git a/acceptance/data-collector/.acceptance/acceptance-cookbook/recipes/destroy.rb b/acceptance/data-collector/.acceptance/acceptance-cookbook/recipes/destroy.rb
new file mode 100644
index 0000000000..7f4be2c7f7
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/acceptance-cookbook/recipes/destroy.rb
@@ -0,0 +1,2 @@
+log "Running 'destroy' recipe from the acceptance-cookbook in directory '#{node['chef-acceptance']['suite-dir']}'"
+kitchen "destroy"
diff --git a/acceptance/data-collector/.acceptance/acceptance-cookbook/recipes/provision.rb b/acceptance/data-collector/.acceptance/acceptance-cookbook/recipes/provision.rb
new file mode 100644
index 0000000000..c707e874f0
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/acceptance-cookbook/recipes/provision.rb
@@ -0,0 +1,2 @@
+log "Running 'provision' recipe from the acceptance-cookbook in directory '#{node['chef-acceptance']['suite-dir']}'"
+kitchen "converge"
diff --git a/acceptance/data-collector/.acceptance/acceptance-cookbook/recipes/verify.rb b/acceptance/data-collector/.acceptance/acceptance-cookbook/recipes/verify.rb
new file mode 100644
index 0000000000..e4a547272b
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/acceptance-cookbook/recipes/verify.rb
@@ -0,0 +1,2 @@
+log "Running 'verify' recipe from the acceptance-cookbook in directory '#{node['chef-acceptance']['suite-dir']}'"
+kitchen "verify"
diff --git a/acceptance/data-collector/.acceptance/data-collector-test/.gitignore b/acceptance/data-collector/.acceptance/data-collector-test/.gitignore
new file mode 100644
index 0000000000..ec2a890bd3
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/data-collector-test/.gitignore
@@ -0,0 +1,16 @@
+.vagrant
+Berksfile.lock
+*~
+*#
+.#*
+\#*#
+.*.sw[a-z]
+*.un~
+
+# Bundler
+Gemfile.lock
+bin/*
+.bundle/*
+
+.kitchen/
+.kitchen.local.yml
diff --git a/acceptance/data-collector/.acceptance/data-collector-test/Berksfile b/acceptance/data-collector/.acceptance/data-collector-test/Berksfile
new file mode 100644
index 0000000000..34fea2166b
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/data-collector-test/Berksfile
@@ -0,0 +1,3 @@
+source 'https://supermarket.chef.io'
+
+metadata
diff --git a/acceptance/data-collector/.acceptance/data-collector-test/files/default/api.rb b/acceptance/data-collector/.acceptance/data-collector-test/files/default/api.rb
new file mode 100644
index 0000000000..3fb2c730b0
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/data-collector-test/files/default/api.rb
@@ -0,0 +1,85 @@
+require "json"
+require "sinatra"
+
+class Chef
+ class Node
+ # dummy class for JSON parsing
+ end
+end
+
+module ApiHelpers
+ def self.payload_type(payload)
+ message_type = payload["message_type"]
+ status = payload["status"]
+
+ message_type == "run_converge" ? "#{message_type}.#{status}" : message_type
+ end
+end
+
+class Counter
+ def self.reset
+ @@counters = Hash.new { |h, k| h[k] = 0 }
+ end
+
+ def self.increment(payload)
+ counter_name = ApiHelpers.payload_type(payload)
+ @@counters[counter_name] += 1
+ end
+
+ def self.to_json
+ @@counters.to_json
+ end
+end
+
+class MessageCache
+ include ApiHelpers
+
+ def self.reset
+ @@message_cache = {}
+ end
+
+ def self.store(payload)
+ cache_key = ApiHelpers.payload_type(payload)
+
+ @@message_cache[cache_key] = payload
+ end
+
+ def self.fetch(cache_key)
+ @@message_cache[cache_key].to_json
+ end
+end
+
+Counter.reset
+
+get "/" do
+ "Data Collector API server"
+end
+
+get "/reset-counters" do
+ Counter.reset
+ "counters reset"
+end
+
+get "/counters" do
+ Counter.to_json
+end
+
+get "/cache/:key" do |cache_key|
+ MessageCache.fetch(cache_key)
+end
+
+get "/reset-cache" do
+ MessageCache.reset
+ "cache reset"
+end
+
+post "/data-collector/v0" do
+ body = request.body.read
+ payload = JSON.load(body)
+
+ Counter.increment(payload)
+ MessageCache.store(payload)
+
+ status 201
+ "message received"
+end
diff --git a/acceptance/data-collector/.acceptance/data-collector-test/files/default/apigemfile b/acceptance/data-collector/.acceptance/data-collector-test/files/default/apigemfile
new file mode 100644
index 0000000000..94fc334d88
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/data-collector-test/files/default/apigemfile
@@ -0,0 +1,3 @@
+source "https://rubygems.org"
+
+gem "sinatra"
diff --git a/acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-both-mode.rb b/acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-both-mode.rb
new file mode 100644
index 0000000000..89f3555be1
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-both-mode.rb
@@ -0,0 +1,4 @@
+chef_server_url "http://localhost:8889"
+node_name "data-collector-test"
+data_collector.server_url "http://localhost:9292/data-collector/v0"
+data_collector.mode :both
diff --git a/acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-client-mode.rb b/acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-client-mode.rb
new file mode 100644
index 0000000000..8e3f0c4845
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-client-mode.rb
@@ -0,0 +1,4 @@
+chef_server_url "http://localhost:8889"
+node_name "data-collector-test"
+data_collector.server_url "http://localhost:9292/data-collector/v0"
+data_collector.mode :client
diff --git a/acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-no-endpoint.rb b/acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-no-endpoint.rb
new file mode 100644
index 0000000000..f8374107ea
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-no-endpoint.rb
@@ -0,0 +1,2 @@
+chef_server_url "http://localhost:8889"
+node_name "data-collector-test"
diff --git a/acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-solo-mode.rb b/acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-solo-mode.rb
new file mode 100644
index 0000000000..904e952e85
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/data-collector-test/files/default/client-rb-solo-mode.rb
@@ -0,0 +1,4 @@
+chef_server_url "http://localhost:8889"
+node_name "data-collector-test"
+data_collector.server_url "http://localhost:9292/data-collector/v0"
+data_collector.mode :solo
diff --git a/acceptance/data-collector/.acceptance/data-collector-test/files/default/config.ru b/acceptance/data-collector/.acceptance/data-collector-test/files/default/config.ru
new file mode 100644
index 0000000000..81cf29d9fb
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/data-collector-test/files/default/config.ru
@@ -0,0 +1,2 @@
+require_relative "./api"
+run Sinatra::Application
diff --git a/acceptance/data-collector/.acceptance/data-collector-test/metadata.rb b/acceptance/data-collector/.acceptance/data-collector-test/metadata.rb
new file mode 100644
index 0000000000..dbd376aa83
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/data-collector-test/metadata.rb
@@ -0,0 +1,7 @@
+name 'data-collector-test'
+maintainer 'Adam Leff'
+maintainer_email 'adamleff@chef.io'
+license 'Apache 2.0'
+description 'Installs/Configures data-collector-test'
+long_description 'Installs/Configures data-collector-test'
+version '0.1.0'
diff --git a/acceptance/data-collector/.acceptance/data-collector-test/recipes/default.rb b/acceptance/data-collector/.acceptance/data-collector-test/recipes/default.rb
new file mode 100644
index 0000000000..20b945db9b
--- /dev/null
+++ b/acceptance/data-collector/.acceptance/data-collector-test/recipes/default.rb
@@ -0,0 +1,38 @@
+api_root_dir = "/var/opt/data_collector_api"
+
+directory api_root_dir do
+ recursive true
+end
+
+cookbook_file ::File.join(api_root_dir, "Gemfile") do
+ source "apigemfile"
+end
+
+cookbook_file ::File.join(api_root_dir, "config.ru")
+
+cookbook_file ::File.join(api_root_dir, "api.rb")
+
+execute "bundle install --binstubs" do
+ cwd api_root_dir
+end
+
+pid_file = "/var/run/api.pid"
+running_pid = ::File.exist?(pid_file) ? ::File.read(pid_file).strip : nil
+
+execute "kill existing API process" do
+ command "kill #{running_pid}"
+ not_if { running_pid.nil? }
+end
+
+execute "start API" do
+ command "bin/rackup -D -P #{pid_file}"
+ cwd api_root_dir
+end
+
+directory "/etc/chef"
+
+["both-mode", "client-mode", "no-endpoint", "solo-mode"].each do |config_file|
+ cookbook_file "/etc/chef/#{config_file}.rb" do
+ source "client-rb-#{config_file}.rb"
+ end
+end
diff --git a/acceptance/data-collector/.kitchen.yml b/acceptance/data-collector/.kitchen.yml
new file mode 100644
index 0000000000..f719e3ea69
--- /dev/null
+++ b/acceptance/data-collector/.kitchen.yml
@@ -0,0 +1,9 @@
+verifier:
+ name: busser
+
+suites:
+ - name: default
+ includes:
+ - ubuntu-14.04
+ run_list:
+ - recipe[data-collector-test::default]
diff --git a/acceptance/data-collector/Berksfile b/acceptance/data-collector/Berksfile
new file mode 100644
index 0000000000..b8f003071b
--- /dev/null
+++ b/acceptance/data-collector/Berksfile
@@ -0,0 +1,3 @@
+source "https://supermarket.chef.io"
+
+cookbook "data-collector-test", path: File.join(File.expand_path(File.dirname(__FILE__)), ".acceptance", "data-collector-test")
diff --git a/acceptance/data-collector/test/integration/default/serverspec/default_spec.rb b/acceptance/data-collector/test/integration/default/serverspec/default_spec.rb
new file mode 100644
index 0000000000..59c1f8d21b
--- /dev/null
+++ b/acceptance/data-collector/test/integration/default/serverspec/default_spec.rb
@@ -0,0 +1,204 @@
+#
+# Author:: Adam Leff (<adamleff@chef.io)
+#
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "json"
+require "serverspec"
+
+set :backend, :exec
+
+class Chef
+ class Node
+ # dummy class for parsing JSON action messages
+ end
+end
+
+shared_examples_for "reset counters" do
+ it "resets the counters" do
+ expect(command("curl http://localhost:9292/reset-counters").exit_status).to eq(0)
+ end
+end
+
+shared_examples_for "reset cache" do
+ it "resets the message cache" do
+ expect(command("curl http://localhost:9292/reset-cache").exit_status).to eq(0)
+ end
+end
+
+shared_examples_for "successful chef run" do |cmd|
+ include_examples "reset counters"
+ include_examples "reset cache"
+
+ it "runs chef and expects a zero exit status" do
+ expect(command(cmd).exit_status).to eq(0)
+ end
+end
+
+shared_examples_for "unsuccessful chef run" do |cmd|
+ include_examples "reset counters"
+ include_examples "reset cache"
+
+ it "runs chef and expects a non-zero exit status" do
+ expect(command(cmd).exit_status).not_to eq(0)
+ end
+end
+
+shared_examples_for "counter checks" do |counters_to_check|
+ counters_to_check.each do |counter, value|
+ it "counter #{counter} should equal #{value.inspect}" do
+ counter_values = JSON.load(command("curl http://localhost:9292/counters").stdout)
+ expect(counter_values[counter]).to eq(value)
+ end
+ end
+end
+
+shared_examples_for "run_start payload check" do
+ describe "run_start message" do
+ let(:required_fields) do
+ %w{
+ chef_server_fqdn
+ entity_uuid
+ id
+ message_version
+ message_type
+ node_name
+ organization_name
+ run_id
+ source
+ start_time
+ }
+ end
+ let(:optional_fields) { [] }
+
+ it "is not missing any required fields" do
+ payload = JSON.load(command("curl http://localhost:9292/cache/run_start").stdout)
+ missing_fields = required_fields.select { |key| !payload.key?(key) }
+ expect(missing_fields).to eq([])
+ end
+
+ end
+end
+
+shared_examples_for "run_converge.success payload check" do
+ describe "run_converge success message" do
+ let(:required_fields) do
+ %w{
+ chef_server_fqdn
+ entity_uuid
+ id
+ end_time
+ expanded_run_list
+ message_type
+ message_version
+ node
+ node_name
+ organization_name
+ resources
+ run_id
+ run_list
+ source
+ start_time
+ status
+ total_resource_count
+ updated_resource_count
+ deprecations
+ }
+ end
+ let(:optional_fields) { [] }
+
+ it "is not missing any required fields" do
+ payload = JSON.load(command("curl http://localhost:9292/cache/run_converge.success").stdout)
+ missing_fields = required_fields.select { |key| !payload.key?(key) }
+ expect(missing_fields).to eq([])
+ end
+
+ end
+end
+
+shared_examples_for "run_converge.failure payload check" do
+ describe "run_converge failure message" do
+ let(:required_fields) do
+ %w{
+ chef_server_fqdn
+ entity_uuid
+ error
+ id
+ end_time
+ expanded_run_list
+ message_type
+ message_version
+ node
+ node_name
+ organization_name
+ resources
+ run_id
+ run_list
+ source
+ start_time
+ status
+ total_resource_count
+ updated_resource_count
+ deprecations
+ }
+ end
+ let(:optional_fields) { [] }
+
+ it "is not missing any required fields" do
+ payload = JSON.load(command("curl http://localhost:9292/cache/run_converge.failure").stdout)
+ missing_fields = required_fields.select { |key| !payload.key?(key) }
+ expect(missing_fields).to eq([])
+ end
+
+ it "does not have any extra fields" do
+ payload = JSON.load(command("curl http://localhost:9292/cache/run_converge.failure").stdout)
+ extra_fields = payload.keys.select { |key| !required_fields.include?(key) && !optional_fields.include?(key) }
+ expect(extra_fields).to eq([])
+ end
+ end
+end
+
+describe "CCR with no data collector URL configured" do
+ include_examples "successful chef run", "chef-client -z -c /etc/chef/no-endpoint.rb"
+ include_examples "counter checks", { "run_start" => nil, "run_converge.success" => nil, "run_converge.failure" => nil }
+end
+
+describe "CCR, local mode, config in solo mode" do
+ include_examples "successful chef run", "chef-client -z -c /etc/chef/solo-mode.rb"
+ include_examples "counter checks", { "run_start" => 1, "run_converge.success" => 1, "run_converge.failure" => nil }
+ include_examples "run_start payload check"
+ include_examples "run_converge.success payload check"
+end
+
+describe "CCR, local mode, config in client mode" do
+ include_examples "successful chef run", "chef-client -z -c /etc/chef/client-mode.rb"
+ include_examples "counter checks", { "run_start" => nil, "run_converge.success" => nil, "run_converge.failure" => nil }
+end
+
+describe "CCR, local mode, config in both mode" do
+ include_examples "successful chef run", "chef-client -z -c /etc/chef/both-mode.rb"
+ include_examples "counter checks", { "run_start" => 1, "run_converge.success" => 1, "run_converge.failure" => nil }
+ include_examples "run_start payload check"
+ include_examples "run_converge.success payload check"
+end
+
+describe "CCR, local mode, config in solo mode, failed run" do
+ include_examples "unsuccessful chef run", "chef-client -z -c /etc/chef/solo-mode.rb -r 'recipe[cookbook-that-does-not-exist::default]'"
+ include_examples "counter checks", { "run_start" => 1, "run_converge.success" => nil, "run_converge.failure" => 1 }
+ include_examples "run_start payload check"
+ include_examples "run_converge.failure payload check"
+end
diff --git a/acceptance/data-collector/test/integration/helpers/serverspec/Gemfile b/acceptance/data-collector/test/integration/helpers/serverspec/Gemfile
new file mode 100644
index 0000000000..b56d1e1298
--- /dev/null
+++ b/acceptance/data-collector/test/integration/helpers/serverspec/Gemfile
@@ -0,0 +1,8 @@
+source "https://rubygems.org"
+
+# Until https://github.com/test-kitchen/busser-serverspec/pull/42 is merged and
+# released, we need to include rake and rspec-core in the Gemfile
+gem "rake"
+gem "rspec-core"
+gem "busser-serverspec"
+gem "serverspec"
diff --git a/acceptance/fips/.acceptance/acceptance-cookbook/.gitignore b/acceptance/fips/.acceptance/acceptance-cookbook/.gitignore
new file mode 100644
index 0000000000..041413b040
--- /dev/null
+++ b/acceptance/fips/.acceptance/acceptance-cookbook/.gitignore
@@ -0,0 +1,2 @@
+nodes/
+tmp/
diff --git a/acceptance/fips/.acceptance/acceptance-cookbook/metadata.rb b/acceptance/fips/.acceptance/acceptance-cookbook/metadata.rb
new file mode 100644
index 0000000000..6c754560f0
--- /dev/null
+++ b/acceptance/fips/.acceptance/acceptance-cookbook/metadata.rb
@@ -0,0 +1,2 @@
+name "acceptance-cookbook"
+depends "kitchen_acceptance"
diff --git a/acceptance/fips/.acceptance/acceptance-cookbook/recipes/destroy.rb b/acceptance/fips/.acceptance/acceptance-cookbook/recipes/destroy.rb
new file mode 100644
index 0000000000..e2d663ac2f
--- /dev/null
+++ b/acceptance/fips/.acceptance/acceptance-cookbook/recipes/destroy.rb
@@ -0,0 +1 @@
+kitchen "destroy"
diff --git a/acceptance/fips/.acceptance/acceptance-cookbook/recipes/provision.rb b/acceptance/fips/.acceptance/acceptance-cookbook/recipes/provision.rb
new file mode 100644
index 0000000000..5726c0e7b5
--- /dev/null
+++ b/acceptance/fips/.acceptance/acceptance-cookbook/recipes/provision.rb
@@ -0,0 +1 @@
+kitchen "converge"
diff --git a/acceptance/fips/.acceptance/acceptance-cookbook/recipes/verify.rb b/acceptance/fips/.acceptance/acceptance-cookbook/recipes/verify.rb
new file mode 100644
index 0000000000..05ac94ce66
--- /dev/null
+++ b/acceptance/fips/.acceptance/acceptance-cookbook/recipes/verify.rb
@@ -0,0 +1 @@
+kitchen "verify"
diff --git a/acceptance/fips/.kitchen.yml b/acceptance/fips/.kitchen.yml
new file mode 100644
index 0000000000..e78a3289d1
--- /dev/null
+++ b/acceptance/fips/.kitchen.yml
@@ -0,0 +1,8 @@
+suites:
+ - name: fips-unit-functional
+ includes: [centos-6]
+ run_list:
+
+ - name: fips-integration
+ includes: [centos-6, windows-2012r2]
+ run_list:
diff --git a/acceptance/fips/test/integration/fips-integration/serverspec/Gemfile b/acceptance/fips/test/integration/fips-integration/serverspec/Gemfile
new file mode 100644
index 0000000000..d297c4314d
--- /dev/null
+++ b/acceptance/fips/test/integration/fips-integration/serverspec/Gemfile
@@ -0,0 +1,9 @@
+source "https://rubygems.org"
+
+# Until https://github.com/test-kitchen/busser-serverspec/pull/42 is merged and
+# released, we need to include rake and rspec-core in the Gemfile
+gem "rake"
+gem "rspec-core"
+gem "busser-serverspec"
+gem "serverspec"
+gem "mixlib-shellout"
diff --git a/acceptance/fips/test/integration/fips-integration/serverspec/fips-integration_spec.rb b/acceptance/fips/test/integration/fips-integration/serverspec/fips-integration_spec.rb
new file mode 100644
index 0000000000..2a087f8029
--- /dev/null
+++ b/acceptance/fips/test/integration/fips-integration/serverspec/fips-integration_spec.rb
@@ -0,0 +1,52 @@
+require "mixlib/shellout"
+require "bundler"
+
+describe "Chef Fips Integration Specs" do
+ def windows?
+ if RUBY_PLATFORM =~ /mswin|mingw|windows/
+ true
+ else
+ false
+ end
+ end
+
+ let(:omnibus_root) do
+ if windows?
+ "c:/opscode/chef"
+ else
+ "/opt/chef"
+ end
+ end
+
+ let(:env) do
+ {
+ "PATH" => [ "#{omnibus_root}/embedded/bin", ENV["PATH"] ].join(File::PATH_SEPARATOR),
+ "BUNDLE_GEMFILE" => "#{omnibus_root}/Gemfile",
+ "GEM_PATH" => nil, "GEM_CACHE" => nil, "GEM_HOME" => nil,
+ "BUNDLE_IGNORE_CONFIG" => "true",
+ "BUNDLE_FROZEN" => "1",
+ "CHEF_FIPS" => "1"
+ }
+ end
+
+ let(:chef_dir) do
+ cmd = Mixlib::ShellOut.new("bundle show chef", env: env).run_command
+ cmd.error!
+ cmd.stdout.chomp
+ end
+
+ def run_rspec_test(test)
+ Bundler.with_clean_env do
+ cmd = Mixlib::ShellOut.new(
+ "bundle exec rspec -f documentation -t ~requires_git #{test}",
+ env: env, cwd: chef_dir, timeout: 3600
+ )
+ cmd.run_command.error!
+ end
+ end
+
+ it "passes the integration specs" do
+ skip
+ #run_rspec_test("spec/integration")
+ end
+end
diff --git a/acceptance/fips/test/integration/fips-unit-functional/serverspec/Gemfile b/acceptance/fips/test/integration/fips-unit-functional/serverspec/Gemfile
new file mode 100644
index 0000000000..03c7a9e657
--- /dev/null
+++ b/acceptance/fips/test/integration/fips-unit-functional/serverspec/Gemfile
@@ -0,0 +1,7 @@
+source "https://rubygems.org"
+
+# Until https://github.com/test-kitchen/busser-serverspec/pull/42 is merged and
+# released, we need to include rake and rspec-core in the Gemfile
+gem "rake"
+gem "rspec-core"
+gem "mixlib-shellout"
diff --git a/acceptance/fips/test/integration/fips-unit-functional/serverspec/fips-unit-functional_spec.rb b/acceptance/fips/test/integration/fips-unit-functional/serverspec/fips-unit-functional_spec.rb
new file mode 100644
index 0000000000..446261f83f
--- /dev/null
+++ b/acceptance/fips/test/integration/fips-unit-functional/serverspec/fips-unit-functional_spec.rb
@@ -0,0 +1,56 @@
+require "mixlib/shellout"
+require "bundler"
+
+describe "Chef Fips Unit/Functional Specs" do
+ def windows?
+ if RUBY_PLATFORM =~ /mswin|mingw|windows/
+ true
+ else
+ false
+ end
+ end
+
+ let(:omnibus_root) do
+ if windows?
+ "c:/opscode/chef"
+ else
+ "/opt/chef"
+ end
+ end
+
+ let(:env) do
+ {
+ "PATH" => [ "#{omnibus_root}/embedded/bin", ENV["PATH"] ].join(File::PATH_SEPARATOR),
+ "BUNDLE_GEMFILE" => "#{omnibus_root}/Gemfile",
+ "GEM_PATH" => nil, "GEM_CACHE" => nil, "GEM_HOME" => nil,
+ "BUNDLE_IGNORE_CONFIG" => "true",
+ "BUNDLE_FROZEN" => "1",
+ "CHEF_FIPS" => "1"
+ }
+ end
+
+ let(:chef_dir) do
+ cmd = Mixlib::ShellOut.new("bundle show chef", env: env).run_command
+ cmd.error!
+ cmd.stdout.chomp
+ end
+
+ def run_rspec_test(test)
+ Bundler.with_clean_env do
+ cmd = Mixlib::ShellOut.new(
+ "bundle exec rspec -f documentation -t ~requires_git #{test}",
+ env: env, cwd: chef_dir, timeout: 3600
+ )
+ cmd.run_command.error!
+ end
+ end
+
+ it "passes the unit specs" do
+ run_rspec_test("spec/unit")
+ end
+
+ it "passes the functional specs" do
+ run_rspec_test("spec/functional")
+ end
+
+end
diff --git a/acceptance/omnitruck/.acceptance/acceptance-cookbook/.gitignore b/acceptance/omnitruck/.acceptance/acceptance-cookbook/.gitignore
new file mode 100644
index 0000000000..041413b040
--- /dev/null
+++ b/acceptance/omnitruck/.acceptance/acceptance-cookbook/.gitignore
@@ -0,0 +1,2 @@
+nodes/
+tmp/
diff --git a/acceptance/omnitruck/.acceptance/acceptance-cookbook/metadata.rb b/acceptance/omnitruck/.acceptance/acceptance-cookbook/metadata.rb
new file mode 100644
index 0000000000..4c7c42d9bd
--- /dev/null
+++ b/acceptance/omnitruck/.acceptance/acceptance-cookbook/metadata.rb
@@ -0,0 +1 @@
+name 'acceptance-cookbook'
diff --git a/acceptance/omnitruck/.acceptance/acceptance-cookbook/recipes/destroy.rb b/acceptance/omnitruck/.acceptance/acceptance-cookbook/recipes/destroy.rb
new file mode 100644
index 0000000000..f890b597fe
--- /dev/null
+++ b/acceptance/omnitruck/.acceptance/acceptance-cookbook/recipes/destroy.rb
@@ -0,0 +1 @@
+log "NOOP 'destroy' recipe from the acceptance-cookbook in directory '#{node['chef-acceptance']['suite-dir']}'"
diff --git a/acceptance/omnitruck/.acceptance/acceptance-cookbook/recipes/provision.rb b/acceptance/omnitruck/.acceptance/acceptance-cookbook/recipes/provision.rb
new file mode 100644
index 0000000000..64ef7581ac
--- /dev/null
+++ b/acceptance/omnitruck/.acceptance/acceptance-cookbook/recipes/provision.rb
@@ -0,0 +1 @@
+log "NOOP 'provision' recipe from the acceptance-cookbook in directory '#{node['chef-acceptance']['suite-dir']}'"
diff --git a/acceptance/omnitruck/.acceptance/acceptance-cookbook/recipes/verify.rb b/acceptance/omnitruck/.acceptance/acceptance-cookbook/recipes/verify.rb
new file mode 100644
index 0000000000..7db51450e1
--- /dev/null
+++ b/acceptance/omnitruck/.acceptance/acceptance-cookbook/recipes/verify.rb
@@ -0,0 +1,61 @@
+control_group "omnitruck" do
+ require 'chef/http'
+ require 'chef/json_compat'
+
+ # We do this to be able to reference 'rest' both inside and outside example
+ # blocks
+ rest = Chef::HTTP.new("https://omnitruck.chef.io/chef/metadata", headers: {"Accept" => "application/json"})
+ let(:rest) { rest }
+
+ def request(url)
+ Chef::JSONCompat.parse(rest.get(url))["sha256"]
+ end
+
+ shared_examples "32 matches 64" do |version|
+ it "only returns 32-bit packages" do
+ sha32 = request("?p=windows&pv=2012r2&v=#{version}&m=i386")
+ sha64 = request("?p=windows&pv=2012r2&v=#{version}&m=x86_64")
+ expect(sha32).to eq(sha64)
+ end
+ end
+
+ context "from the current channel" do
+ it "returns both 32-bit and 64-bit packages" do
+ # We cannot verify from the returned URL if the package is 64 or 32 bit because
+ # it is often lying, so we just make sure they are different.
+ # The current channel is often cleaned so only the latest builds are in
+ # it, so we just request the latest version instead of trying to check
+ # old versions
+ sha32 = request("?p=windows&pv=2012r2&m=i386&prerelease=true")
+ sha64 = request("?p=windows&pv=2012r2&m=x86_64&prerelease=true")
+ expect(sha32).to_not eq(sha64)
+ end
+ end
+
+ context "from the stable channel" do
+ %w{11 12.3 12.4.2 12.6.0 12.8.1}.each do |version|
+ describe "with version #{version}" do
+ include_examples "32 matches 64", version
+ end
+ end
+
+ begin
+ rest.get("?p=windows&pv=2012r2&v=12.9")
+ describe "with version 12.9" do
+ it "returns both 32-bit and 64-bit packages" do
+ sha32 = request("?p=windows&pv=2012r2&v=12.9&m=i386")
+ sha64 = request("?p=windows&pv=2012r2&v=12.9&m=x86_64")
+ expect(sha32).to_not eq(sha64)
+ end
+ end
+ rescue Net::HTTPServerException => e
+ # Once 12.9 is released this will stop 404ing and the example
+ # will be executed
+ unless e.response.code == "404"
+ raise
+ end
+ end
+
+ end
+
+end
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/.gitignore b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/.gitignore
new file mode 100644
index 0000000000..041413b040
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/.gitignore
@@ -0,0 +1,2 @@
+nodes/
+tmp/
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/cookbook_kitchen.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/cookbook_kitchen.rb
new file mode 100644
index 0000000000..5d851a6ac6
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/cookbook_kitchen.rb
@@ -0,0 +1,43 @@
+class CookbookKitchen < KitchenAcceptance::Kitchen
+ resource_name :cookbook_kitchen
+
+ property :command, default: lazy { name.split(" ")[0] }
+ property :kitchen_dir, default: lazy { ::File.join(repository_root, cookbook_relative_dir) }
+ property :test_cookbook, String, default: lazy { name.split(" ")[1] }
+ property :repository, String, default: lazy { "chef-cookbooks/#{test_cookbook}" },
+ coerce: proc { |v|
+ # chef-cookbooks/runit -> https://github.com/chef-cookbooks/runit.git
+ if !v.include?(':')
+ "https://github.com/#{v}.git"
+ else
+ v
+ end
+ }
+ property :repository_root, String, default: lazy { ::File.join(Chef.node["chef-acceptance"]["suite-dir"], "test_run", test_cookbook) }
+ property :branch, String, default: "master"
+ property :cookbook_relative_dir, String, default: ""
+ property :env, default: lazy {
+ {
+ "BUNDLE_GEMFILE" => ::File.expand_path("../Gemfile", Chef.node["chef-acceptance"]["suite-dir"]),
+# "KITCHEN_GLOBAL_YAML" => ::File.join(kitchen_dir, ".kitchen.yml"),
+ "KITCHEN_YAML" => ::File.join(node["chef-acceptance"]["suite-dir"], ".kitchen.#{test_cookbook}.yml")
+ }
+ }
+
+ action :run do
+ # Ensure the parent directory exists
+ directory ::File.expand_path("..", repository_root) do
+ recursive true
+ end
+
+ # Grab the cookbook
+ # TODO Grab the source URL from supermarket
+ # TODO get git to include its kitchen tests in the cookbook.
+ git repository_root do
+ repository new_resource.repository
+ branch new_resource.branch
+ end
+
+ super()
+ end
+end
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/top_cookbooks.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/top_cookbooks.rb
new file mode 100644
index 0000000000..73f5151bca
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/top_cookbooks.rb
@@ -0,0 +1,45 @@
+class TopCookbooks < Chef::Resource
+ resource_name :top_cookbooks
+
+ property :command, String, name_property: true
+
+ # Disabling all windows tests until winrm issue is properly settled.
+ #
+ action :run do
+ cookbook_kitchen "#{command} docker" do
+ end
+
+ cookbook_kitchen "#{command} git" do
+ end
+
+ cookbook_kitchen "#{command} learn-the-basics-ubuntu" do
+ repository "learn-chef/learn-chef-acceptance"
+ cookbook_relative_dir "cookbooks/learn-the-basics-ubuntu"
+ end
+
+ cookbook_kitchen "#{command} learn-the-basics-windows" do
+ repository "learn-chef/learn-chef-acceptance"
+ cookbook_relative_dir "cookbooks/learn-the-basics-windows"
+ end
+
+ cookbook_kitchen "#{command} powershell" do
+ end
+
+ cookbook_kitchen "#{command} iis" do
+ end
+
+ cookbook_kitchen "#{command} sql_server" do
+ end
+
+ cookbook_kitchen "#{command} winbox" do
+ repository "adamedx/winbox"
+ end
+
+ # cookbook_kitchen "#{command} windows" do
+ # end
+
+ # cookbook_kitchen "#{command} chocolatey" do
+ # repository "chocolatey/chocolatey-cookbook"
+ # end
+ end
+end
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/metadata.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/metadata.rb
new file mode 100644
index 0000000000..26cdab4e99
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/metadata.rb
@@ -0,0 +1,3 @@
+name "acceptance-cookbook"
+
+depends "kitchen_acceptance"
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/destroy.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/destroy.rb
new file mode 100644
index 0000000000..63d10e86e4
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/destroy.rb
@@ -0,0 +1 @@
+top_cookbooks "destroy"
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/provision.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/provision.rb
new file mode 100644
index 0000000000..7b16f8e66f
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/provision.rb
@@ -0,0 +1 @@
+top_cookbooks "converge"
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/verify.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/verify.rb
new file mode 100644
index 0000000000..8d00a2e301
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/verify.rb
@@ -0,0 +1 @@
+top_cookbooks "verify"
diff --git a/acceptance/top-cookbooks/.gitignore b/acceptance/top-cookbooks/.gitignore
new file mode 100644
index 0000000000..306f0cce57
--- /dev/null
+++ b/acceptance/top-cookbooks/.gitignore
@@ -0,0 +1 @@
+test_run/
diff --git a/acceptance/top-cookbooks/.kitchen.chocolatey.yml b/acceptance/top-cookbooks/.kitchen.chocolatey.yml
new file mode 100644
index 0000000000..7d7529d69f
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.chocolatey.yml
@@ -0,0 +1,6 @@
+suites:
+ - name: default
+ run_list:
+ - recipe[chocolatey::default]
+ - recipe[chocolatey_test::default]
+ includes: [windows-2012r2]
diff --git a/acceptance/top-cookbooks/.kitchen.docker.yml b/acceptance/top-cookbooks/.kitchen.docker.yml
new file mode 100644
index 0000000000..41864e3608
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.docker.yml
@@ -0,0 +1,9 @@
+suites:
+ - name: docker-default
+ attributes:
+ docker:
+ version: 1.10.0
+ run_list:
+ - recipe[apt]
+ - recipe[chef-apt-docker]
+ includes: [ubuntu-14.04]
diff --git a/acceptance/top-cookbooks/.kitchen.git.yml b/acceptance/top-cookbooks/.kitchen.git.yml
new file mode 100644
index 0000000000..302657dffc
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.git.yml
@@ -0,0 +1,11 @@
+suites:
+ - name: git-default
+ # Ubuntu images need to run apt update
+ run_list: ["recipe[apt]","recipe[git]"]
+ includes: [ubuntu-14.04]
+ - name: git-source
+ run_list: ["recipe[git::source]"]
+ includes: [nonexistent]
+ - name: git-default-windows
+ run_list: ["recipe[git]"]
+ includes: [windows-2012r2]
diff --git a/acceptance/top-cookbooks/.kitchen.iis.yml b/acceptance/top-cookbooks/.kitchen.iis.yml
new file mode 100644
index 0000000000..ffbc23caba
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.iis.yml
@@ -0,0 +1,4 @@
+suites:
+ - name: iis
+ run_list: ["recipe[iis::default]"]
+ includes: [windows-2012r2]
diff --git a/acceptance/top-cookbooks/.kitchen.learn-the-basics-rhel.yml b/acceptance/top-cookbooks/.kitchen.learn-the-basics-rhel.yml
new file mode 100644
index 0000000000..6cbf1b50fa
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.learn-the-basics-rhel.yml
@@ -0,0 +1,7 @@
+suites:
+ - name: learn-the-basics-rhel-default
+ run_list:
+ - recipe[learn-the-basics-rhel::setup]
+ - recipe[learn-the-basics-rhel::lesson1]
+ - recipe[learn-the-basics-rhel::lesson2]
+ includes: [el-6]
diff --git a/acceptance/top-cookbooks/.kitchen.learn-the-basics-ubuntu.yml b/acceptance/top-cookbooks/.kitchen.learn-the-basics-ubuntu.yml
new file mode 100644
index 0000000000..8d54ff94cb
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.learn-the-basics-ubuntu.yml
@@ -0,0 +1,7 @@
+suites:
+ - name: learn-the-basics-ubuntu-default
+ run_list:
+ - recipe[learn-the-basics-ubuntu::setup]
+ - recipe[learn-the-basics-ubuntu::lesson1]
+ - recipe[learn-the-basics-ubuntu::lesson2]
+ includes: [ubuntu-14.04]
diff --git a/acceptance/top-cookbooks/.kitchen.learn-the-basics-windows.yml b/acceptance/top-cookbooks/.kitchen.learn-the-basics-windows.yml
new file mode 100644
index 0000000000..2704577537
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.learn-the-basics-windows.yml
@@ -0,0 +1,7 @@
+suites:
+ - name: learn-the-basics-windows-default
+ run_list:
+ - recipe[learn-the-basics-windows::setup]
+ - recipe[learn-the-basics-windows::lesson1]
+ - recipe[learn-the-basics-windows::lesson2]
+ includes: [windows-2012r2]
diff --git a/acceptance/top-cookbooks/.kitchen.powershell.yml b/acceptance/top-cookbooks/.kitchen.powershell.yml
new file mode 100644
index 0000000000..6fad2364bb
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.powershell.yml
@@ -0,0 +1,4 @@
+suites:
+ - name: powershell
+ run_list: ["recipe[powershell::powershell2]"]
+ includes: [windows-2012r2]
diff --git a/acceptance/top-cookbooks/.kitchen.sql_server.yml b/acceptance/top-cookbooks/.kitchen.sql_server.yml
new file mode 100644
index 0000000000..51a6bd6616
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.sql_server.yml
@@ -0,0 +1,5 @@
+suites:
+ - name: sql_server
+ run_list: ["recipe[sql_server::default]"]
+ attributes: { sql_server: { accept_eula: true } }
+ includes: [windows-2012r2]
diff --git a/acceptance/top-cookbooks/.kitchen.winbox.yml b/acceptance/top-cookbooks/.kitchen.winbox.yml
new file mode 100644
index 0000000000..9cf39a0d5b
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.winbox.yml
@@ -0,0 +1,8 @@
+suites:
+ - name: default
+ run_list:
+ - recipe[winbox::default]
+ includes: [windows-2012r2]
+
+verifier:
+ name: dummy
diff --git a/acceptance/top-cookbooks/.kitchen.windows.yml b/acceptance/top-cookbooks/.kitchen.windows.yml
new file mode 100644
index 0000000000..38c86ff322
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.windows.yml
@@ -0,0 +1,38 @@
+suites:
+ # Waiting on https://github.com/chef-cookbooks/windows/pull/350
+ # - name: tasks
+ # run_list:
+ # - recipe[windows::default]
+ # - recipe[minimal::tasks]
+ # includes: [windows-2012r2]
+ - name: path
+ run_list:
+ - recipe[windows::default]
+ - recipe[minimal::path]
+ includes: [windows-2012r2]
+ - name: certificate
+ run_list:
+ - recipe[windows::default]
+ - recipe[minimal::certificate]
+ includes: [windows-2012r2]
+ # Package is deprecated
+ # - name: package
+ # run_list:
+ # - recipe[windows::default]
+ # - recipe[minimal::package]
+ # includes: [windows-2012r2]
+ - name: feature
+ run_list:
+ - recipe[windows::default]
+ - recipe[minimal::feature]
+ includes: [windows-2012r2]
+ - name: http_acl
+ run_list:
+ - recipe[windows::default]
+ - recipe[minimal::http_acl]
+ includes: [windows-2012r2]
+ - name: font
+ run_list:
+ - recipe[windows::default]
+ - recipe[minimal::font]
+ includes: [windows-2012r2]
diff --git a/acceptance/trivial/.acceptance/acceptance-cookbook/.gitignore b/acceptance/trivial/.acceptance/acceptance-cookbook/.gitignore
new file mode 100644
index 0000000000..041413b040
--- /dev/null
+++ b/acceptance/trivial/.acceptance/acceptance-cookbook/.gitignore
@@ -0,0 +1,2 @@
+nodes/
+tmp/
diff --git a/acceptance/trivial/.acceptance/acceptance-cookbook/metadata.rb b/acceptance/trivial/.acceptance/acceptance-cookbook/metadata.rb
new file mode 100644
index 0000000000..6c754560f0
--- /dev/null
+++ b/acceptance/trivial/.acceptance/acceptance-cookbook/metadata.rb
@@ -0,0 +1,2 @@
+name "acceptance-cookbook"
+depends "kitchen_acceptance"
diff --git a/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/destroy.rb b/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/destroy.rb
new file mode 100644
index 0000000000..e2d663ac2f
--- /dev/null
+++ b/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/destroy.rb
@@ -0,0 +1 @@
+kitchen "destroy"
diff --git a/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/provision.rb b/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/provision.rb
new file mode 100644
index 0000000000..a6f148f7ad
--- /dev/null
+++ b/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/provision.rb
@@ -0,0 +1 @@
+kitchen "setup"
diff --git a/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/verify.rb b/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/verify.rb
new file mode 100644
index 0000000000..05ac94ce66
--- /dev/null
+++ b/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/verify.rb
@@ -0,0 +1 @@
+kitchen "verify"
diff --git a/acceptance/trivial/.kitchen.yml b/acceptance/trivial/.kitchen.yml
new file mode 100644
index 0000000000..0db67c468f
--- /dev/null
+++ b/acceptance/trivial/.kitchen.yml
@@ -0,0 +1,7 @@
+verifier:
+ name: inspec
+
+suites:
+ - name: chef-current-install
+ includes: [ubuntu-14.04, windows-server-2012r2]
+ run_list:
diff --git a/acceptance/trivial/test/integration/chef-current-install/inspec/chef_client_spec.rb b/acceptance/trivial/test/integration/chef-current-install/inspec/chef_client_spec.rb
new file mode 100644
index 0000000000..05c1331744
--- /dev/null
+++ b/acceptance/trivial/test/integration/chef-current-install/inspec/chef_client_spec.rb
@@ -0,0 +1,5 @@
+chef_version = ENV["KITCHEN_CHEF_VERSION"].split("+")[0]
+describe command("chef-client -v") do
+ its("exit_status") { should eq 0 }
+ its(:stdout) { should match /Chef: #{chef_version}/ } if chef_version != "latest"
+end
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/.gitignore b/acceptance/windows-service/.acceptance/acceptance-cookbook/.gitignore
new file mode 100644
index 0000000000..041413b040
--- /dev/null
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/.gitignore
@@ -0,0 +1,2 @@
+nodes/
+tmp/
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/metadata.rb b/acceptance/windows-service/.acceptance/acceptance-cookbook/metadata.rb
new file mode 100644
index 0000000000..6c754560f0
--- /dev/null
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/metadata.rb
@@ -0,0 +1,2 @@
+name "acceptance-cookbook"
+depends "kitchen_acceptance"
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/destroy.rb b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/destroy.rb
new file mode 100644
index 0000000000..e12f938cf3
--- /dev/null
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/destroy.rb
@@ -0,0 +1 @@
+#kitchen "destroy"
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/provision.rb b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/provision.rb
new file mode 100644
index 0000000000..cec9de4e5d
--- /dev/null
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/provision.rb
@@ -0,0 +1 @@
+#kitchen "converge"
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/verify.rb b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/verify.rb
new file mode 100644
index 0000000000..52e3560cf6
--- /dev/null
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/verify.rb
@@ -0,0 +1 @@
+#kitchen "verify"
diff --git a/acceptance/windows-service/.kitchen.yml b/acceptance/windows-service/.kitchen.yml
new file mode 100644
index 0000000000..5270e81487
--- /dev/null
+++ b/acceptance/windows-service/.kitchen.yml
@@ -0,0 +1,7 @@
+verifier:
+ name: inspec
+
+suites:
+ - name: chef-windows-service
+ includes: [windows-2012r2]
+ run_list:
diff --git a/acceptance/windows-service/test/integration/chef-windows-service/inspec/chef_windows_service_spec.rb b/acceptance/windows-service/test/integration/chef-windows-service/inspec/chef_windows_service_spec.rb
new file mode 100644
index 0000000000..75383b69bf
--- /dev/null
+++ b/acceptance/windows-service/test/integration/chef-windows-service/inspec/chef_windows_service_spec.rb
@@ -0,0 +1,58 @@
+only_if do
+ os["family"] == "windows"
+end
+
+describe command("chef-service-manager") do
+ it { should exist }
+ its("exit_status") { should eq 0 }
+end
+
+describe service("chef-client") do
+ it { should_not be_enabled }
+ it { should_not be_installed }
+ it { should_not be_running }
+end
+
+describe command("/opscode/chef/bin/chef-service-manager.bat -a install") do
+ its("exit_status") { should eq 0 }
+ its(:stdout) { should match /Service 'chef-client' has successfully been installed./ }
+end
+
+describe service("chef-client") do
+ it { should be_enabled }
+ it { should be_installed }
+ it { should_not be_running }
+end
+
+describe command("/opscode/chef/bin/chef-service-manager.bat -a start") do
+ its("exit_status") { should eq 0 }
+ its(:stdout) { should match /Service 'chef-client' is now 'running'/ }
+end
+
+describe service("chef-client") do
+ it { should be_enabled }
+ it { should be_installed }
+ it { should be_running }
+end
+
+describe command("/opscode/chef/bin/chef-service-manager.bat -a stop") do
+ its("exit_status") { should eq 0 }
+ its(:stdout) { should match /Service 'chef-client' is now 'stopped'/ }
+end
+
+describe service("chef-client") do
+ it { should be_enabled }
+ it { should be_installed }
+ it { should_not be_running }
+end
+
+describe command("/opscode/chef/bin/chef-service-manager.bat -a uninstall") do
+ its("exit_status") { should eq 0 }
+ its(:stdout) { should match /Service chef-client deleted/ }
+end
+
+describe service("chef-client") do
+ it { should_not be_enabled }
+ it { should_not be_installed }
+ it { should_not be_running }
+end
diff --git a/appveyor.yml b/appveyor.yml
index 7cc8fb631d..7b3780896c 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -6,9 +6,8 @@ platform:
environment:
matrix:
- - ruby_version: "200"
- - ruby_version: "200-x64"
- - ruby_version: "21"
+ - ruby_version: "23-x64"
+ - ruby_version: "23"
clone_folder: c:\projects\chef
clone_depth: 1
@@ -21,13 +20,20 @@ install:
- systeminfo
- winrm quickconfig -q
- SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
+ - ps: $env:RUBYGEMS_VERSION=$(findstr rubygems omnibus_overrides.rb | %{ $_.split(" ")[3] })
+ - ps: $env:BUNDLER_VERSION=$(findstr bundler omnibus_overrides.rb | %{ $_.split(" ")[3] })
- echo %PATH%
- ruby --version
- - gem install bundler --quiet --no-ri --no-rdoc || gem install bundler --quiet --no-ri --no-rdoc || gem install bundler --quiet --no-ri --no-rdoc
- - gem install rubygems-pkg/rubygems-update-2.4.6.gem
- - update_rubygems
+ - gem uninstall bundler -a -x
+ - gem update --system %RUBYGEMS_VERSION% || gem update --system %RUBYGEMS_VERSION% || gem update --system %RUBYGEMS_VERSION%
+ - gem install bundler -v %BUNDLER_VERSION% --quiet --no-ri --no-rdoc || gem install bundler -v %BUNDLER_VERSION% --quiet --no-ri --no-rdoc || gem install bundler -v %BUNDLER_VERSION% --quiet --no-ri --no-rdoc
- gem --version
- bundler --version
+ - SET BUNDLE_IGNORE_CONFIG=true
+ - SET BUNDLE_FROZEN=1
+ - SET BUNDLE_WITHOUT=development:guard:maintenance:tools:integration:changelog:docgen:travis:style:omnibus_package:aix:bsd:linux:mac_os_x:solaris
+ - appveyor DownloadFile http://curl.haxx.se/ca/cacert.pem -FileName C:\cacert.pem
+ - set SSL_CERT_FILE=C:\cacert.pem
build_script:
- bundle install || bundle install || bundle install
diff --git a/bin/chef-apply b/bin/chef-apply
index c617129aa3..39c6682b78 100755
--- a/bin/chef-apply
+++ b/bin/chef-apply
@@ -3,7 +3,7 @@
# ./chef-apply - Run a single chef recipe
#
# Author:: Bryan W. Berry (<bryan.berry@gmail.com>)
-# Copyright:: Copyright (c) 2012 Bryan W. Berry
+# Copyright:: Copyright 2012-2016, Bryan W. Berry
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'rubygems'
+require "rubygems"
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
-require 'chef/application/apply'
+require "chef/application/apply"
Chef::Application::Apply.new.run
diff --git a/bin/chef-client b/bin/chef-client
index 5b2b058f91..207bb8941f 100755
--- a/bin/chef-client
+++ b/bin/chef-client
@@ -2,8 +2,8 @@
#
# ./chef-client - Run the chef client
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'rubygems'
+require "rubygems"
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
-require 'chef'
-require 'chef/application/client'
+require "chef"
+require "chef/application/client"
Chef::Application::Client.new.run
diff --git a/bin/chef-service-manager b/bin/chef-service-manager
index 5808a0be46..c894b10f4f 100755
--- a/bin/chef-service-manager
+++ b/bin/chef-service-manager
@@ -2,8 +2,8 @@
#
# ./chef-service-manager - Control chef-service on Windows platforms.
#
-# Author:: Serdar Sutay (serdar@opscode.com)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (serdar@chef.io)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,19 +18,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'rubygems'
+require "rubygems"
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
-require 'chef'
-require 'chef/application/windows_service_manager'
+require "chef"
+require "chef/application/windows_service_manager"
if Chef::Platform.windows?
chef_client_service = {
:service_name => "chef-client",
:service_display_name => "Chef Client Service",
:service_description => "Runs Chef Client on regular, configurable intervals.",
- :service_file_path => File.expand_path('../chef-windows-service', $PROGRAM_NAME),
+ :service_file_path => File.expand_path("../chef-windows-service", $PROGRAM_NAME),
:delayed_start => true,
- :dependencies => ['Winmgmt']
+ :dependencies => ["Winmgmt"],
}
Chef::Application::WindowsServiceManager.new(chef_client_service).run
else
diff --git a/bin/chef-shell b/bin/chef-shell
index f334635742..4d9300ebb7 100755
--- a/bin/chef-shell
+++ b/bin/chef-shell
@@ -25,13 +25,10 @@ end
require "irb"
require "irb/completion"
-require 'irb/ext/save-history'
+require "irb/ext/save-history"
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
require "chef/shell"
-# On Windows only, enable irb --noreadline because of input problems --
-# See CHEF-3284.
-IRB.conf[:USE_READLINE] = false if Chef::Platform::windows?
Shell.start
diff --git a/bin/chef-solo b/bin/chef-solo
index 958ab21a41..23def86a11 100755
--- a/bin/chef-solo
+++ b/bin/chef-solo
@@ -2,8 +2,8 @@
#
# ./chef-solo - Run the chef client, in stand-alone mode
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'rubygems'
+require "rubygems"
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
-require 'chef/application/solo'
+require "chef/application/solo"
Chef::Application::Solo.new.run
diff --git a/bin/chef-windows-service b/bin/chef-windows-service
index 292d5651fc..184c3d7cd6 100755
--- a/bin/chef-windows-service
+++ b/bin/chef-windows-service
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
#
-# Author:: Jay Mundrawala (<jdm@getchef.com>)
+# Author:: Jay Mundrawala (<jdm@chef.io>)
#
# Copyright:: 2014, Chef Software, Inc.
#
@@ -19,14 +19,14 @@
# Note:
# The file is used by appbundler to generate a ruby file that
-# we can execute using the correct gems. The batch file we
+# we can execute using the correct gems. The batch file we
# generate will call that file, and will be registered as
# a windows service.
-require 'rubygems'
+require "rubygems"
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
-require 'chef'
-require 'chef/application/windows_service'
+require "chef"
+require "chef/application/windows_service"
if Chef::Platform.windows?
Chef::Application::WindowsService.mainloop
diff --git a/bin/knife b/bin/knife
index 6173aadd86..b8983d6d5c 100755
--- a/bin/knife
+++ b/bin/knife
@@ -2,8 +2,8 @@
#
# ./knife - Chef CLI interface
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'rubygems'
+require "rubygems"
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
-require 'chef/application/knife'
+require "chef/application/knife"
Chef::Application::Knife.new.run
-
diff --git a/chef-config/Gemfile b/chef-config/Gemfile
index d39725ff87..96ab544690 100644
--- a/chef-config/Gemfile
+++ b/chef-config/Gemfile
@@ -1,4 +1,4 @@
-source 'https://rubygems.org'
+source "https://rubygems.org"
# Specify your gem's dependencies in chef-config.gemspec
gemspec
diff --git a/chef-config/Rakefile b/chef-config/Rakefile
index 36e7e2572d..fd6497a287 100644
--- a/chef-config/Rakefile
+++ b/chef-config/Rakefile
@@ -1,14 +1,17 @@
-require 'rspec/core/rake_task'
-require 'chef-config/package_task'
+require "chef-config/package_task"
-ChefConfig::PackageTask.new(File.expand_path('..', __FILE__), 'ChefConfig') do |package|
- package.module_path = 'chef-config'
+ChefConfig::PackageTask.new(File.expand_path("..", __FILE__), "ChefConfig", "chef-config") do |package|
+ package.module_path = "chef-config"
end
task :default => :spec
-desc "Run standard specs"
-RSpec::Core::RakeTask.new(:spec) do |t|
- t.pattern = FileList['spec/**/*_spec.rb']
+begin
+ require "rspec/core/rake_task"
+ desc "Run standard specs"
+ RSpec::Core::RakeTask.new(:spec) do |t|
+ t.pattern = FileList["spec/**/*_spec.rb"]
+ end
+rescue LoadError
+ STDERR.puts "\n*** RSpec not available. (sudo) gem install rspec to run unit tests. ***\n\n"
end
-
diff --git a/chef-config/VERSION b/chef-config/VERSION
deleted file mode 100644
index 2b4b4d7cb5..0000000000
--- a/chef-config/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-12.5.1
diff --git a/chef-config/chef-config.gemspec b/chef-config/chef-config.gemspec
index 6619f04169..9e40528fba 100644
--- a/chef-config/chef-config.gemspec
+++ b/chef-config/chef-config.gemspec
@@ -1,7 +1,7 @@
# coding: utf-8
-lib = File.expand_path('../lib', __FILE__)
+lib = File.expand_path("../lib", __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
-require 'chef-config/version'
+require "chef-config/version"
Gem::Specification.new do |spec|
spec.name = "chef-config"
@@ -17,15 +17,17 @@ Gem::Specification.new do |spec|
spec.add_dependency "mixlib-shellout", "~> 2.0"
spec.add_dependency "mixlib-config", "~> 2.0"
+ spec.add_dependency "fuzzyurl"
+ spec.add_dependency "addressable"
spec.add_development_dependency "rake", "~> 10.0"
- %w(rspec-core rspec-expectations rspec-mocks).each do |rspec|
+ %w{rspec-core rspec-expectations rspec-mocks}.each do |rspec|
spec.add_development_dependency(rspec, "~> 3.2")
end
- spec.files = %w(Rakefile LICENSE README.md) + Dir.glob("*.gemspec") +
- Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject {|f| File.directory?(f) }
+ spec.files = %w{Rakefile LICENSE README.md} + Dir.glob("*.gemspec") +
+ Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
spec.bindir = "bin"
spec.executables = []
diff --git a/chef-config/lib/chef-config.rb b/chef-config/lib/chef-config.rb
index 1f593c868f..3c52462ab6 100644
--- a/chef-config/lib/chef-config.rb
+++ b/chef-config/lib/chef-config.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/chef-config/lib/chef-config/config.rb b/chef-config/lib/chef-config/config.rb
index 069f0ed6c0..4f2516331d 100644
--- a/chef-config/lib/chef-config/config.rb
+++ b/chef-config/lib/chef-config/config.rb
@@ -1,10 +1,10 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Author:: Mark Mzyk (<mmzyk@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: AJ Christensen (<aj@chef.io>)
+# Author:: Mark Mzyk (<mmzyk@chef.io>)
# Author:: Kyle Goodwin (<kgoodwin@primerevenue.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,25 +19,33 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'mixlib/config'
-require 'pathname'
+require "mixlib/config"
+require "pathname"
-require 'chef-config/logger'
-require 'chef-config/windows'
-require 'chef-config/path_helper'
-require 'mixlib/shellout'
+require "chef-config/fips"
+require "chef-config/logger"
+require "chef-config/windows"
+require "chef-config/path_helper"
+require "chef-config/mixin/fuzzy_hostname_matcher"
+
+require "mixlib/shellout"
+require "uri"
+require "addressable/uri"
+require "openssl"
+require "yaml"
module ChefConfig
class Config
extend Mixlib::Config
+ extend ChefConfig::Mixin::FuzzyHostnameMatcher
# Evaluates the given string as config.
#
# +filename+ is used for context in stacktraces, but doesn't need to be the name of an actual file.
def self.from_string(string, filename)
- self.instance_eval(string, filename, 1)
+ instance_eval(string, filename, 1)
end
def self.inspect
@@ -48,14 +56,25 @@ module ChefConfig
path = PathHelper.cleanpath(path)
if ChefConfig.windows?
# turns \etc\chef\client.rb and \var\chef\client.rb into C:/chef/client.rb
- if env['SYSTEMDRIVE'] && path[0] == '\\' && path.split('\\')[2] == 'chef'
- path = PathHelper.join(env['SYSTEMDRIVE'], path.split('\\', 3)[2])
+ # Some installations will be on different drives so use the drive that
+ # the expanded path to __FILE__ is found.
+ drive = windows_installation_drive
+ if drive && path[0] == '\\' && path.split('\\')[2] == "chef"
+ path = PathHelper.join(drive, path.split('\\', 3)[2])
end
end
path
end
- def self.add_formatter(name, file_path=nil)
+ def self.windows_installation_drive
+ if ChefConfig.windows?
+ drive = File.expand_path(__FILE__).split("/", 2)[0]
+ drive = ENV["SYSTEMDRIVE"] if drive.to_s == ""
+ drive
+ end
+ end
+
+ def self.add_formatter(name, file_path = nil)
formatters << [name, file_path]
end
@@ -63,6 +82,25 @@ module ChefConfig
event_handlers << logger
end
+ def self.apply_extra_config_options(extra_config_options)
+ if extra_config_options
+ extra_parsed_options = extra_config_options.inject({}) do |memo, option|
+ # Sanity check value.
+ if option.empty? || !option.include?("=")
+ raise UnparsableConfigOption, "Unparsable config option #{option.inspect}"
+ end
+ # Split including whitespace if someone does truly odd like
+ # --config-option "foo = bar"
+ key, value = option.split(/\s*=\s*/, 2)
+ # Call to_sym because Chef::Config expects only symbol keys. Also
+ # runs a simple parse on the string for some common types.
+ memo[key.to_sym] = YAML.safe_load(value)
+ memo
+ end
+ merge!(extra_parsed_options)
+ end
+ end
+
# Config file to load (client.rb, knife.rb, etc. defaults set differently in knife, chef-client, etc.)
configurable(:config_file)
@@ -76,12 +114,21 @@ module ChefConfig
default :formatters, []
+ def self.is_valid_url?(uri)
+ url = uri.to_s.strip
+ /^http:\/\// =~ url || /^https:\/\// =~ url || /^chefzero:/ =~ url
+ end
# Override the config dispatch to set the value of multiple server options simultaneously
#
# === Parameters
# url<String>:: String to be set for all of the chef-server-api URL's
#
- configurable(:chef_server_url).writes_value { |url| url.to_s.strip }
+ configurable(:chef_server_url).writes_value do |uri|
+ unless is_valid_url? uri
+ raise ConfigurationError, "#{uri} is an invalid chef_server_url."
+ end
+ uri.to_s.strip
+ end
# When you are using ActiveSupport, they monkey-patch 'daemonize' into Kernel.
# So while this is basically identical to what method_missing would do, we pull
@@ -95,14 +142,16 @@ module ChefConfig
# that upload or download files (such as knife upload, knife role from file,
# etc.) work.
default :chef_repo_path do
- if self.configuration[:cookbook_path]
- if self.configuration[:cookbook_path].kind_of?(String)
- File.expand_path('..', self.configuration[:cookbook_path])
+ if configuration[:cookbook_path]
+ if configuration[:cookbook_path].kind_of?(String)
+ File.expand_path("..", configuration[:cookbook_path])
else
- self.configuration[:cookbook_path].map do |path|
- File.expand_path('..', path)
+ configuration[:cookbook_path].map do |path|
+ File.expand_path("..", path)
end
end
+ elsif configuration[:cookbook_artifact_path]
+ File.expand_path("..", configuration[:cookbook_artifact_path])
else
cache_path
end
@@ -112,11 +161,11 @@ module ChefConfig
# In local mode, we auto-discover the repo root by looking for a path with "cookbooks" under it.
# This allows us to run config-free.
path = cwd
- until File.directory?(PathHelper.join(path, "cookbooks"))
- new_path = File.expand_path('..', path)
+ until File.directory?(PathHelper.join(path, "cookbooks")) || File.directory?(PathHelper.join(path, "cookbook_artifacts"))
+ new_path = File.expand_path("..", path)
if new_path == path
- ChefConfig.logger.warn("No cookbooks directory found at or above current directory. Assuming #{Dir.pwd}.")
- return Dir.pwd
+ ChefConfig.logger.warn("No cookbooks directory found at or above current directory. Assuming #{cwd}.")
+ return cwd
end
path = new_path
end
@@ -128,65 +177,77 @@ module ChefConfig
if chef_repo_path.kind_of?(String)
PathHelper.join(chef_repo_path, child_path)
else
- chef_repo_path.uniq.map { |path| PathHelper.join(path, child_path)}
+ chef_repo_path.uniq.map { |path| PathHelper.join(path, child_path) }
end
end
# Location of acls on disk. String or array of strings.
# Defaults to <chef_repo_path>/acls.
- # Only applies to Enterprise Chef commands.
- default(:acl_path) { derive_path_from_chef_repo_path('acls') }
+ default(:acl_path) { derive_path_from_chef_repo_path("acls") }
# Location of clients on disk. String or array of strings.
- # Defaults to <chef_repo_path>/acls.
- default(:client_path) { derive_path_from_chef_repo_path('clients') }
+ # Defaults to <chef_repo_path>/clients.
+ default(:client_path) { derive_path_from_chef_repo_path("clients") }
+
+ # Location of client keys on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/client_keys.
+ default(:client_key_path) { derive_path_from_chef_repo_path("client_keys") }
+
+ # Location of containers on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/containers.
+ default(:container_path) { derive_path_from_chef_repo_path("containers") }
+
+ # Location of cookbook_artifacts on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/cookbook_artifacts.
+ default(:cookbook_artifact_path) { derive_path_from_chef_repo_path("cookbook_artifacts") }
# Location of cookbooks on disk. String or array of strings.
# Defaults to <chef_repo_path>/cookbooks. If chef_repo_path
# is not specified, this is set to [/var/chef/cookbooks, /var/chef/site-cookbooks]).
default(:cookbook_path) do
- if self.configuration[:chef_repo_path]
- derive_path_from_chef_repo_path('cookbooks')
+ if configuration[:chef_repo_path]
+ derive_path_from_chef_repo_path("cookbooks")
else
- Array(derive_path_from_chef_repo_path('cookbooks')).flatten +
- Array(derive_path_from_chef_repo_path('site-cookbooks')).flatten
+ Array(derive_path_from_chef_repo_path("cookbooks")).flatten +
+ Array(derive_path_from_chef_repo_path("site-cookbooks")).flatten
end
end
- # Location of containers on disk. String or array of strings.
- # Defaults to <chef_repo_path>/containers.
- # Only applies to Enterprise Chef commands.
- default(:container_path) { derive_path_from_chef_repo_path('containers') }
-
# Location of data bags on disk. String or array of strings.
# Defaults to <chef_repo_path>/data_bags.
- default(:data_bag_path) { derive_path_from_chef_repo_path('data_bags') }
+ default(:data_bag_path) { derive_path_from_chef_repo_path("data_bags") }
# Location of environments on disk. String or array of strings.
# Defaults to <chef_repo_path>/environments.
- default(:environment_path) { derive_path_from_chef_repo_path('environments') }
+ default(:environment_path) { derive_path_from_chef_repo_path("environments") }
# Location of groups on disk. String or array of strings.
# Defaults to <chef_repo_path>/groups.
- # Only applies to Enterprise Chef commands.
- default(:group_path) { derive_path_from_chef_repo_path('groups') }
+ default(:group_path) { derive_path_from_chef_repo_path("groups") }
# Location of nodes on disk. String or array of strings.
# Defaults to <chef_repo_path>/nodes.
- default(:node_path) { derive_path_from_chef_repo_path('nodes') }
+ default(:node_path) { derive_path_from_chef_repo_path("nodes") }
+
+ # Location of policies on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/policies.
+ default(:policy_path) { derive_path_from_chef_repo_path("policies") }
+
+ # Location of policy_groups on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/policy_groups.
+ default(:policy_group_path) { derive_path_from_chef_repo_path("policy_groups") }
# Location of roles on disk. String or array of strings.
# Defaults to <chef_repo_path>/roles.
- default(:role_path) { derive_path_from_chef_repo_path('roles') }
+ default(:role_path) { derive_path_from_chef_repo_path("roles") }
# Location of users on disk. String or array of strings.
# Defaults to <chef_repo_path>/users.
- # Does not apply to Enterprise Chef commands.
- default(:user_path) { derive_path_from_chef_repo_path('users') }
+ default(:user_path) { derive_path_from_chef_repo_path("users") }
# Location of policies on disk. String or array of strings.
# Defaults to <chef_repo_path>/policies.
- default(:policy_path) { derive_path_from_chef_repo_path('policies') }
+ default(:policy_path) { derive_path_from_chef_repo_path("policies") }
# Turn on "path sanity" by default. See also: http://wiki.opscode.com/display/chef/User+Environment+PATH+Sanity
default :enforce_path_sanity, true
@@ -204,7 +265,7 @@ module ChefConfig
# this is under the user's home directory.
default(:cache_path) do
if local_mode
- PathHelper.join(config_dir, 'local-mode-cache')
+ PathHelper.join(config_dir, "local-mode-cache")
else
primary_cache_root = platform_specific_path("/var")
primary_cache_path = platform_specific_path("/var/chef")
@@ -213,7 +274,7 @@ module ChefConfig
# Otherwise, we'll create .chef under the user's home directory and use that as
# the cache path.
unless path_accessible?(primary_cache_path) || path_accessible?(primary_cache_root)
- secondary_cache_path = PathHelper.join(user_home, '.chef')
+ secondary_cache_path = PathHelper.join(user_home, ".chef")
ChefConfig.logger.info("Unable to access cache at #{primary_cache_path}. Switching cache to #{secondary_cache_path}")
secondary_cache_path
else
@@ -271,6 +332,15 @@ module ChefConfig
# Using `force_logger` causes chef to default to logger output when STDOUT is a tty
default :force_logger, false
+ # Using 'stream_execute_output' will have Chef always stream the execute output
+ default :stream_execute_output, false
+
+ # Using `show_download_progress` will display the overall progress
+ # of a remote file download
+ default :show_download_progress, false
+ # How often to update the progress meter, in percent
+ default :download_progress_interval, 10
+
default :http_retry_count, 5
default :http_retry_delay, 5
default :interval, nil
@@ -284,6 +354,28 @@ module ChefConfig
default :diff_output_threshold, 1000000
default :local_mode, false
+ # Configures the mode of operation for ChefFS, which is applied to the
+ # ChefFS-based knife commands and chef-client's local mode. (ChefFS-based
+ # knife commands include: knife delete, knife deps, knife diff, knife down,
+ # knife edit, knife list, knife show, knife upload, and knife xargs.)
+ #
+ # Valid values are:
+ # * "static": ChefFS only manages objects that exist in a traditional Chef
+ # Repo as of Chef 11.
+ # * "everything": ChefFS manages all object types that existed on the OSS
+ # Chef 11 server.
+ # * "hosted_everything": ChefFS manages all object types as of the Chef 12
+ # Server, including RBAC objects and Policyfile objects (new to Chef 12).
+ default :repo_mode do
+ if local_mode && !chef_zero.osc_compat
+ "hosted_everything"
+ elsif chef_server_url =~ /\/+organizations\/.+/
+ "hosted_everything"
+ else
+ "everything"
+ end
+ end
+
default :pid_file, nil
# Whether Chef Zero local mode should bind to a port. All internal requests
@@ -297,18 +389,33 @@ module ChefConfig
config_context :chef_zero do
config_strict_mode true
default(:enabled) { ChefConfig::Config.local_mode }
- default :host, 'localhost'
+ default :host, "localhost"
default :port, 8889.upto(9999) # Will try ports from 8889-9999 until one works
+
+ # When set to a String, Chef Zero disables multitenant support. This is
+ # what you want when using Chef Zero to serve a single Chef Repo. Setting
+ # this to `false` enables multi-tenant.
+ default :single_org, "chef"
+
+ # Whether Chef Zero should operate in a mode analogous to OSS Chef Server
+ # 11 (true) or Chef Server 12 (false). Chef Zero can still serve
+ # policyfile objects in Chef 11 mode, as long as `repo_mode` is set to
+ # "hosted_everything". The primary differences are:
+ # * Chef 11 mode doesn't support multi-tennant, so there is no
+ # distinction between global and org-specific objects (since there are
+ # no orgs).
+ # * Chef 11 mode doesn't expose RBAC objects
+ default :osc_compat, false
end
- default :chef_server_url, "https://localhost:443"
+ default :chef_server_url, "https://localhost:443"
default(:chef_server_root) do
# if the chef_server_url is a path to an organization, aka
# 'some_url.../organizations/*' then remove the '/organization/*' by default
- if self.configuration[:chef_server_url] =~ /\/organizations\/\S*$/
- self.configuration[:chef_server_url].split('/')[0..-3].join('/')
- elsif self.configuration[:chef_server_url] # default to whatever chef_server_url is
- self.configuration[:chef_server_url]
+ if configuration[:chef_server_url] =~ /\/organizations\/\S*$/
+ configuration[:chef_server_url].split("/")[0..-3].join("/")
+ elsif configuration[:chef_server_url] # default to whatever chef_server_url is
+ configuration[:chef_server_url]
else
"https://localhost:443"
end
@@ -317,7 +424,11 @@ module ChefConfig
default :rest_timeout, 300
default :yum_timeout, 900
default :yum_lock_timeout, 30
- default :solo, false
+ default :solo, false
+
+ # Are we running in old Chef Solo legacy mode?
+ default :solo_legacy_mode, false
+
default :splay, nil
default :why_run, false
default :color, false
@@ -388,7 +499,6 @@ module ChefConfig
# effect if `policy_document_native_api` is set to `false`.
default :deployment_group, nil
-
# Set these to enable SSL authentication / mutual-authentication
# with the server
@@ -412,8 +522,8 @@ module ChefConfig
# Path to the default CA bundle files.
default :ssl_ca_path, nil
default(:ssl_ca_file) do
- if ChefConfig.windows? and embedded_path = embedded_dir
- cacert_path = File.join(embedded_path, "ssl/certs/cacert.pem")
+ if ChefConfig.windows? && embedded_dir
+ cacert_path = File.join(embedded_dir, "ssl/certs/cacert.pem")
cacert_path if File.exist?(cacert_path)
else
nil
@@ -426,24 +536,50 @@ module ChefConfig
# HTTP file servers.
default(:trusted_certs_dir) { PathHelper.join(config_dir, "trusted_certs") }
+ # A directory that contains additional configuration scripts to load for chef-client
+ default(:client_d_dir) { PathHelper.join(config_dir, "client.d") }
+
+ # A directory that contains additional configuration scripts to load for solo
+ default(:solo_d_dir) { PathHelper.join(config_dir, "solo.d") }
+
+ # A directory that contains additional configuration scripts to load for
+ # the workstation config
+ default(:config_d_dir) { PathHelper.join(config_dir, "config.d") }
+
# Where should chef-solo download recipes from?
default :recipe_url, nil
+ # Set to true if Chef is to set OpenSSL to run in FIPS mode
+ default(:fips) do
+ # CHEF_FIPS is used in testing to override checking for system level
+ # enablement. There are 3 possible values that this variable may have:
+ # nil - no override and the system will be checked
+ # empty - FIPS is NOT enabled
+ # a non empty value - FIPS is enabled
+ if ENV["CHEF_FIPS"] == ""
+ false
+ else
+ !ENV["CHEF_FIPS"].nil? || ChefConfig.fips?
+ end
+ end
+
+ # Initialize openssl
+ def self.init_openssl
+ if fips
+ enable_fips_mode
+ end
+ end
+
# Sets the version of the signed header authentication protocol to use (see
# the 'mixlib-authorization' project for more detail). Currently, versions
- # 1.0 and 1.1 are available; however, the chef-server must first be
- # upgraded to support version 1.1 before clients can begin using it.
- #
- # Version 1.1 of the protocol is required when using a `node_name` greater
- # than ~90 bytes (~90 ascii characters), so chef-client will automatically
- # switch to using version 1.1 when `node_name` is too large for the 1.0
- # protocol. If you intend to use large node names, ensure that your server
- # supports version 1.1. Automatic detection of large node names means that
- # users will generally not need to manually configure this.
- #
- # In the future, this configuration option may be replaced with an
- # automatic negotiation scheme.
- default :authentication_protocol_version, "1.0"
+ # 1.0, 1.1, and 1.3 are available.
+ default :authentication_protocol_version do
+ if fips
+ "1.3"
+ else
+ "1.1"
+ end
+ end
# This key will be used to sign requests to the Chef server. This location
# must be writable by Chef during initial setup when generating a client
@@ -554,8 +690,26 @@ module ChefConfig
ENV.key?("CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS")
end
+ # Whether the resource count should be updated for log resource
+ # on running chef-client
+ default :count_log_resource_updates, true
+
# knife configuration data
config_context :knife do
+ # XXX: none of these default values are applied to knife (and would create a backcompat
+ # break in knife if this bug was fixed since many of the defaults below are wrong). this appears
+ # to be the start of an attempt to be able to use config_strict_mode true? if so, this approach
+ # is fraught with peril because this namespace is used by every knife plugin in the wild and
+ # we would need to validate every cli option in every knife attribute out there and list them all here.
+ #
+ # based on the way that people may define `knife[:foobar] = "something"` for the knife-foobar
+ # gem plugin i'm pretty certain we can never turn on anything like config_string_mode since
+ # any config value may be a typo or it may be in some gem in some knife plugin we don't know about.
+ #
+ # we do still need to maintain at least one of these so that the knife config hash gets
+ # created.
+ #
+ # this whole situation is deeply unsatisfying.
default :ssh_port, nil
default :ssh_user, nil
default :ssh_attribute, nil
@@ -624,6 +778,9 @@ module ChefConfig
# Use atomic updates (i.e. move operation) while updating contents
# of the files resources. When set to false copy operation is
# used to update files.
+ #
+ # NOTE: CHANGING THIS SETTING MAY CAUSE CORRUPTION, DATA LOSS AND
+ # INSTABILITY.
default :file_atomic_update, true
# There are 3 possible values for this configuration setting.
@@ -684,6 +841,11 @@ module ChefConfig
default :normal_attribute_whitelist, nil
default :override_attribute_whitelist, nil
+ # Pull down all the rubygems versions from rubygems and cache them the first time we do a gem_package or
+ # chef_gem install. This is memory-expensive and will grow without bounds, but will reduce network
+ # round trips.
+ default :rubygems_cache_enabled, false
+
config_context :windows_service do
# Set `watchdog_timeout` to the number of seconds to wait for a chef-client run
# to finish
@@ -698,6 +860,134 @@ module ChefConfig
config_context :chefdk do
end
+ # Configuration options for Data Collector reporting. These settings allow
+ # the user to configure where to send their Data Collector data, what token
+ # to send, and whether Data Collector should report its findings in client
+ # mode vs. solo mode.
+ config_context :data_collector do
+ # Full URL to the endpoint that will receive our data. If nil, the
+ # data collector will not run.
+ # Ex: http://my-data-collector.mycompany.com/ingest
+ default(:server_url) do
+ if config_parent.solo || config_parent.local_mode
+ nil
+ else
+ File.join(config_parent.chef_server_url, "/data-collector")
+ end
+ end
+
+ # An optional pre-shared token to pass as an HTTP header (x-data-collector-token)
+ # that can be used to determine whether or not the poster of this
+ # run data should be trusted.
+ # Ex: some-uuid-here
+ default :token, nil
+
+ # The Chef mode during which Data Collector is allowed to function. This
+ # can be used to run Data Collector only when running as Chef Solo but
+ # not when using Chef Client.
+ # Options: :solo (for both Solo Legacy Mode and Client Local Mode), :client, :both
+ default :mode, :both
+
+ # When the Data Collector cannot send the "starting a run" message to
+ # the Data Collector server, the Data Collector will be disabled for that
+ # run. In some situations, such as highly-regulated environments, it
+ # may be more reasonable to prevent Chef from performing the actual run.
+ # In these situations, setting this value to true will cause the Chef
+ # run to raise an exception before starting any converge activities.
+ default :raise_on_failure, false
+
+ # A user-supplied Organization string that can be sent in payloads
+ # generated by the DataCollector when Chef is run in Solo mode. This
+ # allows users to associate their Solo nodes with faux organizations
+ # without the nodes being connected to an actual Chef Server.
+ default :organization, nil
+ end
+
+ configurable(:http_proxy)
+ configurable(:http_proxy_user)
+ configurable(:http_proxy_pass)
+ configurable(:https_proxy)
+ configurable(:https_proxy_user)
+ configurable(:https_proxy_pass)
+ configurable(:ftp_proxy)
+ configurable(:ftp_proxy_user)
+ configurable(:ftp_proxy_pass)
+ configurable(:no_proxy)
+
+ # Public method that users should call to export proxies to the appropriate
+ # environment variables. This method should be called after the config file is
+ # parsed and loaded.
+ # TODO add some post-file-parsing logic that automatically calls this so
+ # users don't have to
+ def self.export_proxies
+ export_proxy("http", http_proxy, http_proxy_user, http_proxy_pass) if http_proxy
+ export_proxy("https", https_proxy, https_proxy_user, https_proxy_pass) if https_proxy
+ export_proxy("ftp", ftp_proxy, ftp_proxy_user, ftp_proxy_pass) if ftp_proxy
+ export_no_proxy(no_proxy) if no_proxy
+ end
+
+ # Character classes for Addressable
+ # See https://www.ietf.org/rfc/rfc3986.txt 3.2.1
+ # The user part may not have a : in it
+ USER = Addressable::URI::CharacterClasses::UNRESERVED + Addressable::URI::CharacterClasses::SUB_DELIMS
+ # The password part may have any valid USERINFO characters
+ PASSWORD = USER + "\\:"
+
+ # Builds a proxy uri and exports it to the appropriate environment variables. Examples:
+ # http://username:password@hostname:port
+ # https://username@hostname:port
+ # ftp://hostname:port
+ # when
+ # scheme = "http", "https", or "ftp"
+ # hostport = hostname:port or scheme://hostname:port
+ # user = username
+ # pass = password
+ # @api private
+ def self.export_proxy(scheme, path, user, pass)
+ path = "#{scheme}://#{path}" unless path.include?("://")
+ # URI.split returns the following parts:
+ # [scheme, userinfo, host, port, registry, path, opaque, query, fragment]
+ uri = Addressable::URI.encode(path, Addressable::URI)
+
+ if user && !user.empty?
+ userinfo = Addressable::URI.encode_component(user, USER)
+ if pass
+ userinfo << ":#{Addressable::URI.encode_component(pass, PASSWORD)}"
+ end
+ uri.userinfo = userinfo
+ end
+
+ path = uri.to_s
+ ENV["#{scheme}_proxy".downcase] = path unless ENV["#{scheme}_proxy".downcase]
+ ENV["#{scheme}_proxy".upcase] = path unless ENV["#{scheme}_proxy".upcase]
+ end
+
+ # @api private
+ def self.export_no_proxy(value)
+ ENV["no_proxy"] = value unless ENV["no_proxy"]
+ ENV["NO_PROXY"] = value unless ENV["NO_PROXY"]
+ end
+
+ # Given a scheme, host, and port, return the correct proxy URI based on the
+ # set environment variables, unless exluded by no_proxy, in which case nil
+ # is returned
+ def self.proxy_uri(scheme, host, port)
+ proxy_env_var = ENV["#{scheme}_proxy"].to_s.strip
+
+ # Check if the proxy string contains a scheme. If not, add the url's scheme to the
+ # proxy before parsing. The regex /^.*:\/\// matches, for example, http://. Reusing proxy
+ # here since we are really just trying to get the string built correctly.
+ proxy = if !proxy_env_var.empty?
+ if proxy_env_var =~ /^.*:\/\//
+ URI.parse(proxy_env_var)
+ else
+ URI.parse("#{scheme}://#{proxy_env_var}")
+ end
+ end
+
+ return proxy unless fuzzy_hostname_match_any?(host, ENV["no_proxy"])
+ end
+
# Chef requires an English-language UTF-8 locale to function properly. We attempt
# to use the 'locale -a' command and search through a list of preferences until we
# find one that we can use. On Ubuntu systems we should find 'C.UTF-8' and be
@@ -713,7 +1003,7 @@ module ChefConfig
# If there is no 'locale -a' then we return 'en_US.UTF-8' since that is the most commonly
# available English UTF-8 locale. However, all modern POSIXen should support 'locale -a'.
def self.guess_internal_locale
- # https://github.com/opscode/chef/issues/2181
+ # https://github.com/chef/chef/issues/2181
# Some systems have the `locale -a` command, but the result has
# invalid characters for the default encoding.
#
@@ -723,12 +1013,12 @@ module ChefConfig
cmd.error!
locales = cmd.stdout.split
case
- when locales.include?('C.UTF-8')
- 'C.UTF-8'
- when locales.include?('en_US.UTF-8'), locales.include?('en_US.utf8')
- 'en_US.UTF-8'
- when locales.include?('en.UTF-8')
- 'en.UTF-8'
+ when locales.include?("C.UTF-8")
+ "C.UTF-8"
+ when locales.include?("en_US.UTF-8"), locales.include?("en_US.utf8")
+ "en_US.UTF-8"
+ when locales.include?("en.UTF-8")
+ "en.UTF-8"
else
# Will match en_ZZ.UTF-8, en_ZZ.utf-8, en_ZZ.UTF8, en_ZZ.utf8
guesses = locales.select { |l| l =~ /^en_.*UTF-?8$/i }
@@ -738,7 +1028,7 @@ module ChefConfig
guessed_locale.gsub(/UTF-?8$/i, "UTF-8")
else
ChefConfig.logger.warn "Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support."
- 'C'
+ "C"
end
end
rescue
@@ -747,7 +1037,7 @@ module ChefConfig
else
ChefConfig.logger.debug "No usable locale -a command found, assuming you have en_US.UTF-8 installed."
end
- 'en_US.UTF-8'
+ "en_US.UTF-8"
end
default :internal_locale, guess_internal_locale
@@ -761,6 +1051,14 @@ module ChefConfig
# break Chef community cookbooks and is very highly discouraged.
default :ruby_encoding, Encoding::UTF_8
+ default :rubygems_url, "https://rubygems.org"
+
+ # This controls the behavior of resource cloning (and CHEF-3694 warnings). For Chef < 12 the behavior
+ # has been that this is 'true', in Chef 13 this will change to false. Setting this to 'true' in Chef
+ # 13 is not a viable or supported migration strategy since Chef 13 community cookbooks will be expected
+ # to break with this setting set to 'true'.
+ default :resource_cloning, true
+
# If installed via an omnibus installer, this gives the path to the
# "embedded" directory which contains all of the software packaged with
# omnibus. This is used to locate the cacert.pem file on windows.
@@ -778,5 +1076,22 @@ module ChefConfig
def self._this_file
File.expand_path(__FILE__)
end
+
+ # Set fips mode in openssl. Do any patching necessary to make
+ # sure Chef runs do not crash.
+ # @api private
+ def self.enable_fips_mode
+ OpenSSL.fips_mode = true
+ require "digest"
+ require "digest/sha1"
+ require "digest/md5"
+ # Remove pre-existing constants if they do exist to reduce the
+ # amount of log spam and warnings.
+ Digest.send(:remove_const, "SHA1") if Digest.const_defined?("SHA1")
+ Digest.const_set("SHA1", OpenSSL::Digest::SHA1)
+ OpenSSL::Digest.send(:remove_const, "MD5") if OpenSSL::Digest.const_defined?("MD5")
+ OpenSSL::Digest.const_set("MD5", Digest::MD5)
+ ChefConfig.logger.debug "FIPS mode is enabled."
+ end
end
end
diff --git a/chef-config/lib/chef-config/exceptions.rb b/chef-config/lib/chef-config/exceptions.rb
index 1f80e505df..23fd28f9c8 100644
--- a/chef-config/lib/chef-config/exceptions.rb
+++ b/chef-config/lib/chef-config/exceptions.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,12 +15,13 @@
# limitations under the License.
#
-require 'chef-config/windows'
-require 'chef-config/logger'
+require "chef-config/windows"
+require "chef-config/logger"
module ChefConfig
class ConfigurationError < ArgumentError; end
class InvalidPath < StandardError; end
+ class UnparsableConfigOption < StandardError; end
end
diff --git a/chef-config/lib/chef-config/fips.rb b/chef-config/lib/chef-config/fips.rb
new file mode 100644
index 0000000000..623ce87686
--- /dev/null
+++ b/chef-config/lib/chef-config/fips.rb
@@ -0,0 +1,51 @@
+#
+# Author:: Matt Wrock (<matt@mattwrock.com>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+module ChefConfig
+
+ def self.fips?
+ if ChefConfig.windows?
+ begin
+ require "win32/registry"
+ rescue LoadError
+ return false
+ end
+
+ # from http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129(v=vs.85).aspx
+ reg_type =
+ case ::RbConfig::CONFIG["target_cpu"]
+ when "i386"
+ Win32::Registry::KEY_READ | 0x100
+ when "x86_64"
+ Win32::Registry::KEY_READ | 0x200
+ else
+ Win32::Registry::KEY_READ
+ end
+ begin
+ Win32::Registry::HKEY_LOCAL_MACHINE.open('System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy', reg_type) do |policy|
+ policy["Enabled"] != 0
+ end
+ rescue Win32::Registry::Error
+ false
+ end
+ else
+ fips_path = "/proc/sys/crypto/fips_enabled"
+ File.exist?(fips_path) && File.read(fips_path).chomp != "0"
+ end
+ end
+end
diff --git a/chef-config/lib/chef-config/logger.rb b/chef-config/lib/chef-config/logger.rb
index 57f18809ee..d239e85f43 100644
--- a/chef-config/lib/chef-config/logger.rb
+++ b/chef-config/lib/chef-config/logger.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,6 @@
# limitations under the License.
#
-
module ChefConfig
# Implements enough of Logger's API that we can use it in place of a real
@@ -58,5 +57,3 @@ module ChefConfig
@logger
end
end
-
-
diff --git a/chef-config/lib/chef-config/mixin/dot_d.rb b/chef-config/lib/chef-config/mixin/dot_d.rb
new file mode 100644
index 0000000000..778c25d7f9
--- /dev/null
+++ b/chef-config/lib/chef-config/mixin/dot_d.rb
@@ -0,0 +1,38 @@
+#
+# Copyright:: Copyright 2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "chef-config/path_helper"
+
+module ChefConfig
+ module Mixin
+ module DotD
+ def load_dot_d(path)
+ dot_d_files =
+ begin
+ entries = Array.new
+ entries << Dir.glob(File.join(
+ ChefConfig::PathHelper.escape_glob_dir(path), "*.rb"))
+ entries.flatten.select do |entry|
+ File.file?(entry)
+ end
+ end
+ dot_d_files.sort.map do |conf|
+ apply_config(IO.read(conf), conf)
+ end
+ end
+ end
+ end
+end
diff --git a/chef-config/lib/chef-config/mixin/fuzzy_hostname_matcher.rb b/chef-config/lib/chef-config/mixin/fuzzy_hostname_matcher.rb
new file mode 100644
index 0000000000..ca1bdb4c0b
--- /dev/null
+++ b/chef-config/lib/chef-config/mixin/fuzzy_hostname_matcher.rb
@@ -0,0 +1,41 @@
+#
+# Copyright:: Copyright 2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "fuzzyurl"
+
+module ChefConfig
+ module Mixin
+ module FuzzyHostnameMatcher
+
+ def fuzzy_hostname_match_any?(hostname, matches)
+ if (!hostname.nil?) && (!matches.nil?)
+ return matches.to_s.split(/\s*,\s*/).compact.any? do |m|
+ fuzzy_hostname_match?(hostname, m)
+ end
+ end
+
+ false
+ end
+
+ def fuzzy_hostname_match?(hostname, match)
+ # Do greedy matching by adding wildcard if it is not specified
+ match = "*" + match if !match.start_with?("*")
+ Fuzzyurl.matches?(Fuzzyurl.mask(hostname: match), hostname)
+ end
+
+ end
+ end
+end
diff --git a/chef-config/lib/chef-config/package_task.rb b/chef-config/lib/chef-config/package_task.rb
index 0aa063a2ff..de830c09d3 100644
--- a/chef-config/lib/chef-config/package_task.rb
+++ b/chef-config/lib/chef-config/package_task.rb
@@ -1,6 +1,6 @@
#
# Author:: Kartik Null Cating-Subramanian (<ksubramanian@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef, Inc.
+# Copyright:: Copyright 2015-2016, Chef, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'rake'
-require 'rubygems'
-require 'rubygems/package_task'
+require "rake"
+require "rubygems"
+require "rubygems/package_task"
module ChefConfig
class PackageTask < Rake::TaskLib
@@ -31,6 +31,10 @@ module ChefConfig
# the top level module which contains VERSION and MODULE_ROOT.
attr_accessor :module_name
+ # Name of the gem being built. This is used to find the lines to fix in
+ # Gemfile.lock.
+ attr_accessor :gem_name
+
# Should the generated version.rb be in a class or module? Default is false (module).
attr_accessor :generate_version_class
@@ -47,10 +51,6 @@ module ChefConfig
@module_path || module_name.downcase
end
- # Path to a VERSION file with a single string that contains the package version.
- # By default, this is root_path/VERSION
- attr_accessor :version_file_path
-
# Directory used to store package files and output that is generated.
# This has the same meaning (or lack thereof) as package_dir in
# rake/packagetask.
@@ -59,33 +59,45 @@ module ChefConfig
# Name of git remote used to push tags during a release. Default is origin.
attr_accessor :git_remote
- def initialize(root_path=nil, module_name=nil)
- init(root_path, module_name)
+ def initialize(root_path = nil, module_name = nil, gem_name = nil)
+ init(root_path, module_name, gem_name)
yield self if block_given?
define unless root_path.nil? || module_name.nil?
end
- def init(root_path, module_name)
+ def init(root_path, module_name, gem_name)
@root_path = root_path
@module_name = module_name
+ @gem_name = gem_name
@component_paths = []
@module_path = nil
- @version_file_path = 'VERSION'
- @package_dir = 'pkg'
- @git_remote = 'origin'
+ @package_dir = "pkg"
+ @git_remote = "origin"
@generate_version_class = false
end
def component_full_paths
- component_paths.map { |path| File.expand_path(path, root_path)}
+ component_paths.map { |path| File.expand_path(path, root_path) }
end
def version_rb_path
File.expand_path("lib/#{module_path}/version.rb", root_path)
end
+ def chef_root_path
+ module_name == "Chef" ? root_path : File.dirname(root_path)
+ end
+
+ def version_file_path
+ File.join(chef_root_path, "VERSION")
+ end
+
+ def gemfile_lock_path
+ File.join(root_path, "Gemfile.lock")
+ end
+
def version
- IO.read(File.expand_path(version_file_path, root_path)).strip
+ IO.read(version_file_path).strip
end
def full_package_dir
@@ -93,66 +105,87 @@ module ChefConfig
end
def class_or_module
- generate_version_class ? 'class' : 'module'
+ generate_version_class ? "class" : "module"
end
def with_clean_env(&block)
if defined?(Bundler)
Bundler.with_clean_env(&block)
else
- block.call
+ yield
end
end
def define
- fail 'Need to provide package root and module name' if root_path.nil? || module_name.nil?
+ raise "Need to provide package root and module name" if root_path.nil? || module_name.nil?
- desc 'Build Gems of component dependencies'
+ desc "Build Gems of component dependencies"
task :package_components do
component_full_paths.each do |component_path|
Dir.chdir(component_path) do
- sh 'rake package'
+ sh "rake package"
end
end
end
task :package => :package_components
- desc 'Build and install component dependencies'
+ desc "Build and install component dependencies"
task :install_components => :package_components do
component_full_paths.each do |component_path|
Dir.chdir(component_path) do
- sh 'rake install'
+ sh "rake install"
end
end
end
task :install => :install_components
- desc 'Clean up builds of component dependencies'
+ desc "Clean up builds of component dependencies"
task :clobber_component_packages do
component_full_paths.each do |component_path|
Dir.chdir(component_path) do
- sh 'rake clobber_package'
+ sh "rake clobber_package"
end
end
end
task :clobber_package => :clobber_component_packages
- desc 'Update the version number for component dependencies'
+ desc "Update the version number for component dependencies"
task :update_components_versions do
component_full_paths.each do |component_path|
Dir.chdir(component_path) do
- sh 'rake version'
+ sh "rake version"
end
end
end
- desc 'Regenerate lib/#{@module_path}/version.rb from VERSION file'
- task :version => :update_components_versions do
- contents = <<-VERSION_RB
-# Copyright:: Copyright (c) 2010-2015 Chef Software, Inc.
+ namespace :version do
+ desc 'Regenerate lib/#{@module_path}/version.rb from VERSION file'
+ task :update => :update_components_versions do
+ update_version_rb
+ update_gemfile_lock
+ end
+
+ task :bump => %w{version:bump_patch version:update}
+
+ task :show do
+ puts version
+ end
+
+ # Add 1 to the current patch version in the VERSION file, and write it back out.
+ task :bump_patch do
+ current_version = version
+ new_version = current_version.sub(/^(\d+\.\d+\.)(\d+)/) { "#{$1}#{$2.to_i + 1}" }
+ puts "Updating version in #{version_rb_path} from #{current_version.chomp} to #{new_version.chomp}"
+ IO.write(version_file_path, new_version)
+ end
+
+ def update_version_rb # rubocop:disable Lint/NestedMethodDefinition
+ puts "Updating #{version_rb_path} to include version #{version} ..."
+ contents = <<-VERSION_RB
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -174,8 +207,8 @@ module ChefConfig
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#{class_or_module} #{module_name}
- #{module_name.upcase}_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
- VERSION = '#{version}'
+ #{module_name.upcase}_ROOT = File.expand_path("../..", __FILE__)
+ VERSION = "#{version}"
end
#
@@ -186,22 +219,38 @@ end
# pre-release versions like "10.14.0.rc.2". Please use Rubygem's
# Gem::Version class instead.
#
- VERSION_RB
- IO.write(version_rb_path, contents)
+ VERSION_RB
+ IO.write(version_rb_path, contents)
+ end
+
+ def update_gemfile_lock # rubocop:disable Lint/NestedMethodDefinition
+ if File.exist?(gemfile_lock_path)
+ puts "Updating #{gemfile_lock_path} to include version #{version} ..."
+ contents = IO.read(gemfile_lock_path)
+ contents.gsub!(/^\s*(chef|chef-config)\s*\((= )?\S+\)\s*$/) do |line|
+ line.gsub(/\((= )?\d+(\.\d+)+/) { "(#{$1}#{version}" }
+ end
+ IO.write(gemfile_lock_path, contents)
+ end
+ end
end
- Dir[File.expand_path("*gemspec", root_path)].reverse.each do |gemspec_path|
+ task :version => "version:update"
+
+ gemspec_platform_to_install = ""
+ Dir[File.expand_path("*.gemspec", root_path)].reverse_each do |gemspec_path|
gemspec = eval(IO.read(gemspec_path))
Gem::PackageTask.new(gemspec) do |task|
task.package_dir = full_package_dir
end
+ gemspec_platform_to_install = "-#{gemspec.platform}" if gemspec.platform != Gem::Platform::RUBY && Gem::Platform.match(gemspec.platform)
end
desc "Build and install a #{module_path} gem"
task :install => [:package] do
with_clean_env do
full_module_path = File.join(full_package_dir, module_path)
- sh %{gem install #{full_module_path}-#{version}.gem --no-rdoc --no-ri}
+ sh %{gem install #{full_module_path}-#{version}#{gemspec_platform_to_install}.gem --no-rdoc --no-ri}
end
end
@@ -209,11 +258,11 @@ end
sh %{gem uninstall #{module_path} -x -v #{version} }
end
- desc 'Build it, tag it and ship it'
+ desc "Build it, tag it and ship it"
task :ship => [:clobber_package, :gem] do
sh("git tag #{version}")
sh("git push #{git_remote} --tags")
- Dir[File.expand_path('*.gem', full_package_dir)].reverse.each do |built_gem|
+ Dir[File.expand_path("*.gem", full_package_dir)].reverse_each do |built_gem|
sh("gem push #{built_gem}")
end
end
diff --git a/chef-config/lib/chef-config/path_helper.rb b/chef-config/lib/chef-config/path_helper.rb
index 45f451479a..e8a576c84f 100644
--- a/chef-config/lib/chef-config/path_helper.rb
+++ b/chef-config/lib/chef-config/path_helper.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef-config/windows'
-require 'chef-config/logger'
-require 'chef-config/exceptions'
+require "chef-config/windows"
+require "chef-config/logger"
+require "chef-config/exceptions"
module ChefConfig
class PathHelper
@@ -32,11 +32,11 @@ module ChefConfig
loop do
slash = path.rindex(/[#{Regexp.escape(File::SEPARATOR)}#{Regexp.escape(path_separator)}]/, end_slash - 1)
if !slash
- return end_slash == path.size ? '.' : path_separator
+ return end_slash == path.size ? "." : path_separator
elsif slash == end_slash - 1
end_slash = slash
else
- return path[0..slash-1]
+ return path[0..slash - 1]
end
end
else
@@ -64,9 +64,9 @@ module ChefConfig
leading_slashes = /^[#{path_separator_regex}]+/
args.flatten.inject() do |joined_path, component|
- joined_path = joined_path.sub(trailing_slashes, '')
- component = component.sub(leading_slashes, '')
- joined_path += "#{path_separator}#{component}"
+ joined_path = joined_path.sub(trailing_slashes, "")
+ component = component.sub(leading_slashes, "")
+ joined_path + "#{path_separator}#{component}"
end
end
@@ -110,7 +110,7 @@ module ChefConfig
end
# Produces a comparable path.
- def self.canonical_path(path, add_prefix=true)
+ def self.canonical_path(path, add_prefix = true)
# First remove extra separators and resolve any relative paths
abs_path = File.absolute_path(path)
@@ -128,6 +128,17 @@ module ChefConfig
abs_path
end
+ # This is the INVERSE of Pathname#cleanpath, it converts forward
+ # slashes to backwhacks for Windows. Since the Ruby API and the
+ # Windows APIs all consume forward slashes, this helper function
+ # should only be used for *DISPLAY* logic to send strings back
+ # to the user with backwhacks. Internally, filename paths should
+ # generally be stored with forward slashes for consistency. It is
+ # not necessary or desired to blindly convert pathnames to have
+ # backwhacks on Windows.
+ #
+ # Generally, if the user isn't going to be seeing it, you should be
+ # using Pathname#cleanpath intead of this function.
def self.cleanpath(path)
path = Pathname.new(path).cleanpath.to_s
# ensure all forward slashes are backslashes
@@ -141,12 +152,20 @@ module ChefConfig
canonical_path(path1) == canonical_path(path2)
end
+ # Note: this method is deprecated. Please use escape_glob_dirs
# Paths which may contain glob-reserved characters need
# to be escaped before globbing can be done.
# http://stackoverflow.com/questions/14127343
def self.escape_glob(*parts)
path = cleanpath(join(*parts))
- path.gsub(/[\\\{\}\[\]\*\?]/) { |x| "\\"+x }
+ path.gsub(/[\\\{\}\[\]\*\?]/) { |x| "\\" + x }
+ end
+
+ # This function does not switch to backslashes for windows
+ # This is because only forwardslashes should be used with dir (even for windows)
+ def self.escape_glob_dir(*parts)
+ path = Pathname.new(join(*parts)).cleanpath.to_s
+ path.gsub(/[\\\{\}\[\]\*\?]/) { |x| "\\" + x }
end
def self.relative_path_from(from, to)
@@ -168,7 +187,7 @@ module ChefConfig
#
# See self.all_homes.
def self.home(*args)
- @@home_dir ||= self.all_homes { |p| break p }
+ @@home_dir ||= all_homes { |p| break p }
if @@home_dir
path = File.join(@@home_dir, *args)
block_given? ? (yield path) : path
@@ -201,12 +220,12 @@ module ChefConfig
# HOMESHARE HOMEPATH
# USERPROFILE
- paths << ENV['HOME']
- paths << ENV['HOMEDRIVE'] + ENV['HOMEPATH'] if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
- paths << ENV['HOMESHARE'] + ENV['HOMEPATH'] if ENV['HOMESHARE'] && ENV['HOMEPATH']
- paths << ENV['USERPROFILE']
+ paths << ENV["HOME"]
+ paths << ENV["HOMEDRIVE"] + ENV["HOMEPATH"] if ENV["HOMEDRIVE"] && ENV["HOMEPATH"]
+ paths << ENV["HOMESHARE"] + ENV["HOMEPATH"] if ENV["HOMESHARE"] && ENV["HOMEPATH"]
+ paths << ENV["USERPROFILE"]
end
- paths << Dir.home if ENV['HOME']
+ paths << Dir.home if ENV["HOME"]
# Depending on what environment variables we're using, the slashes can go in any which way.
# Just change them all to / to keep things consistent.
@@ -216,7 +235,7 @@ module ChefConfig
paths = paths.map { |home_path| home_path.gsub(path_separator, ::File::SEPARATOR) if home_path }
# Filter out duplicate paths and paths that don't exist.
- valid_paths = paths.select { |home_path| home_path && Dir.exists?(home_path) }
+ valid_paths = paths.select { |home_path| home_path && Dir.exists?(home_path.force_encoding("utf-8")) }
valid_paths = valid_paths.uniq
# Join all optional path elements at the end.
@@ -231,27 +250,28 @@ module ChefConfig
# Determine if the given path is protected by OS X System Integrity Protection.
def self.is_sip_path?(path, node)
- if node['platform'] == 'mac_os_x' and Gem::Version.new(node['platform_version']) >= Gem::Version.new('10.11')
+ if node["platform"] == "mac_os_x" && Gem::Version.new(node["platform_version"]) >= Gem::Version.new("10.11")
# todo: parse rootless.conf for this?
- sip_paths= [
- '/System', '/bin', '/sbin', '/usr',
- ]
- sip_paths.each do |sip_path|
- ChefConfig.logger.info("This is a SIP path, checking if it in exceptions list.")
- return true if path.start_with?(sip_path)
- end
- false
+ sip_paths = [
+ "/System", "/bin", "/sbin", "/usr"
+ ]
+ sip_paths.each do |sip_path|
+ ChefConfig.logger.info("This is a SIP path, checking if it in exceptions list.")
+ return true if path.start_with?(sip_path)
+ end
+ false
else
false
end
end
+
# Determine if the given path is on the exception list for OS X System Integrity Protection.
def self.writable_sip_path?(path)
# todo: parse rootless.conf for this?
sip_exceptions = [
- '/System/Library/Caches', '/System/Library/Extensions',
- '/System/Library/Speech', '/System/Library/User Template',
- '/usr/libexec/cups', '/usr/local', '/usr/share/man'
+ "/System/Library/Caches", "/System/Library/Extensions",
+ "/System/Library/Speech", "/System/Library/User Template",
+ "/usr/libexec/cups", "/usr/local", "/usr/share/man"
]
sip_exceptions.each do |exception_path|
return true if path.start_with?(exception_path)
@@ -261,4 +281,3 @@ module ChefConfig
end
end
end
-
diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb
index 654a18eac1..c84ff4304e 100644
--- a/chef-config/lib/chef-config/version.rb
+++ b/chef-config/lib/chef-config/version.rb
@@ -1,4 +1,4 @@
-# Copyright:: Copyright (c) 2010-2015 Chef Software, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,8 +20,8 @@
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module ChefConfig
- CHEFCONFIG_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
- VERSION = '12.5.1'
+ CHEFCONFIG_ROOT = File.expand_path("../..", __FILE__)
+ VERSION = "12.19.39"
end
#
diff --git a/chef-config/lib/chef-config/windows.rb b/chef-config/lib/chef-config/windows.rb
index a2e90067df..9c606110a4 100644
--- a/chef-config/lib/chef-config/windows.rb
+++ b/chef-config/lib/chef-config/windows.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,4 +26,3 @@ module ChefConfig
end
end
-
diff --git a/chef-config/lib/chef-config/workstation_config_loader.rb b/chef-config/lib/chef-config/workstation_config_loader.rb
index 177cd776d4..babb78aeb8 100644
--- a/chef-config/lib/chef-config/workstation_config_loader.rb
+++ b/chef-config/lib/chef-config/workstation_config_loader.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,20 +16,22 @@
# limitations under the License.
#
-require 'chef-config/config'
-require 'chef-config/exceptions'
-require 'chef-config/logger'
-require 'chef-config/path_helper'
-require 'chef-config/windows'
+require "chef-config/config"
+require "chef-config/exceptions"
+require "chef-config/logger"
+require "chef-config/path_helper"
+require "chef-config/windows"
+require "chef-config/mixin/dot_d"
module ChefConfig
class WorkstationConfigLoader
+ include ChefConfig::Mixin::DotD
# Path to a config file requested by user, (e.g., via command line option). Can be nil
attr_accessor :explicit_config_file
# TODO: initialize this with a logger for Chef and Knife
- def initialize(explicit_config_file, logger=nil)
+ def initialize(explicit_config_file, logger = nil)
@explicit_config_file = explicit_config_file
@chef_config_dir = nil
@config_location = nil
@@ -62,15 +64,17 @@ module ChefConfig
def load
# Ignore it if there's no explicit_config_file and can't find one at a
# default path.
- return false if config_location.nil?
+ if !config_location.nil?
+ if explicit_config_file && !path_exists?(config_location)
+ raise ChefConfig::ConfigurationError, "Specified config file #{config_location} does not exist"
+ end
- if explicit_config_file && !path_exists?(config_location)
- raise ChefConfig::ConfigurationError, "Specified config file #{config_location} does not exist"
+ # Have to set Config.config_file b/c other config is derived from it.
+ Config.config_file = config_location
+ apply_config(IO.read(config_location), config_location)
end
- # Have to set Config.config_file b/c other config is derived from it.
- Config.config_file = config_location
- read_config(IO.read(config_location), config_location)
+ load_dot_d(Config[:config_d_dir]) if Config[:config_d_dir]
end
# (Private API, public for test purposes)
@@ -99,42 +103,42 @@ module ChefConfig
candidate_configs = []
# Look for $KNIFE_HOME/knife.rb (allow multiple knives config on same machine)
- if env['KNIFE_HOME']
- candidate_configs << File.join(env['KNIFE_HOME'], 'config.rb')
- candidate_configs << File.join(env['KNIFE_HOME'], 'knife.rb')
+ if env["KNIFE_HOME"]
+ candidate_configs << File.join(env["KNIFE_HOME"], "config.rb")
+ candidate_configs << File.join(env["KNIFE_HOME"], "knife.rb")
end
# Look for $PWD/knife.rb
if Dir.pwd
- candidate_configs << File.join(Dir.pwd, 'config.rb')
- candidate_configs << File.join(Dir.pwd, 'knife.rb')
+ candidate_configs << File.join(Dir.pwd, "config.rb")
+ candidate_configs << File.join(Dir.pwd, "knife.rb")
end
# Look for $UPWARD/.chef/knife.rb
if chef_config_dir
- candidate_configs << File.join(chef_config_dir, 'config.rb')
- candidate_configs << File.join(chef_config_dir, 'knife.rb')
+ candidate_configs << File.join(chef_config_dir, "config.rb")
+ candidate_configs << File.join(chef_config_dir, "knife.rb")
end
# Look for $HOME/.chef/knife.rb
- PathHelper.home('.chef') do |dot_chef_dir|
- candidate_configs << File.join(dot_chef_dir, 'config.rb')
- candidate_configs << File.join(dot_chef_dir, 'knife.rb')
+ PathHelper.home(".chef") do |dot_chef_dir|
+ candidate_configs << File.join(dot_chef_dir, "config.rb")
+ candidate_configs << File.join(dot_chef_dir, "knife.rb")
end
- candidate_configs.find do | candidate_config |
+ candidate_configs.find do |candidate_config|
have_config?(candidate_config)
end
end
def working_directory
a = if ChefConfig.windows?
- env['CD']
+ env["CD"]
else
- env['PWD']
+ env["PWD"]
end || Dir.pwd
a
end
- def read_config(config_content, config_file_path)
+ def apply_config(config_content, config_file_path)
Config.from_string(config_content, config_file_path)
rescue SignalException
raise
@@ -151,7 +155,7 @@ module ChefConfig
message = "You have an error in your config file #{config_file_path}\n\n"
message << "#{e.class.name}: #{e.message}\n"
filtered_trace = e.backtrace.grep(/#{Regexp.escape(config_file_path)}/)
- filtered_trace.each {|bt_line| message << " " << bt_line << "\n" }
+ filtered_trace.each { |bt_line| message << " " << bt_line << "\n" }
if !filtered_trace.empty?
line_nr = filtered_trace.first[/#{Regexp.escape(config_file_path)}:([\d]+)/, 1]
message << highlight_config_error(config_file_path, line_nr.to_i)
@@ -159,10 +163,9 @@ module ChefConfig
raise ChefConfig::ConfigurationError, message
end
-
def highlight_config_error(file, line)
config_file_lines = []
- IO.readlines(file).each_with_index {|l, i| config_file_lines << "#{(i + 1).to_s.rjust(3)}: #{l.chomp}"}
+ IO.readlines(file).each_with_index { |l, i| config_file_lines << "#{(i + 1).to_s.rjust(3)}: #{l.chomp}" }
if line == 1
lines = config_file_lines[0..3]
else
diff --git a/chef-config/spec/spec_helper.rb b/chef-config/spec/spec_helper.rb
index df9461cde9..107becb9eb 100644
--- a/chef-config/spec/spec_helper.rb
+++ b/chef-config/spec/spec_helper.rb
@@ -1,4 +1,4 @@
-require 'chef-config/windows'
+require "chef-config/windows"
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
@@ -53,7 +53,7 @@ RSpec.configure do |config|
# Use the documentation formatter for detailed output,
# unless a formatter has already been configured
# (e.g. via a command-line flag).
- config.default_formatter = 'doc'
+ config.default_formatter = "doc"
end
# Print the 10 slowest examples and example groups at the
diff --git a/chef-config/spec/unit/config_spec.rb b/chef-config/spec/unit/config_spec.rb
index d99ff428fb..f5e9a914c9 100644
--- a/chef-config/spec/unit/config_spec.rb
+++ b/chef-config/spec/unit/config_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Kyle Goodwin (<kgoodwin@primerevenue.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef-config/config'
+require "spec_helper"
+require "chef-config/config"
RSpec.describe ChefConfig::Config do
before(:each) do
@@ -28,7 +28,7 @@ RSpec.describe ChefConfig::Config do
ChefConfig::Config.treat_deprecation_warnings_as_errors(true)
# Set environment variable so the setting persists in child processes
- ENV['CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS'] = "1"
+ ENV["CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS"] = "1"
end
describe "config attribute writer: chef_server_url" do
@@ -60,6 +60,97 @@ RSpec.describe ChefConfig::Config do
expect(ChefConfig::Config.chef_server_url).to eq("https://junglist.gen.nz")
end
end
+
+ context "when the url is invalid" do
+ it "raises an exception" do
+ expect { ChefConfig::Config.chef_server_url = "127.0.0.1" }.to raise_error(ChefConfig::ConfigurationError)
+ end
+ end
+ end
+
+ describe "parsing arbitrary config from the CLI" do
+
+ def apply_config
+ described_class.apply_extra_config_options(extra_config_options)
+ end
+
+ context "when no arbitrary config is given" do
+
+ let(:extra_config_options) { nil }
+
+ it "succeeds" do
+ expect { apply_config }.to_not raise_error
+ end
+
+ end
+
+ context "when given a simple string option" do
+
+ let(:extra_config_options) { [ "node_name=bobotclown" ] }
+
+ it "applies the string option" do
+ apply_config
+ expect(described_class[:node_name]).to eq("bobotclown")
+ end
+
+ end
+
+ context "when given a blank value" do
+
+ let(:extra_config_options) { [ "http_retries=" ] }
+
+ it "sets the value to nil" do
+ # ensure the value is actually changed in the test
+ described_class[:http_retries] = 55
+ apply_config
+ expect(described_class[:http_retries]).to eq(nil)
+ end
+ end
+
+ context "when given spaces between `key = value`" do
+
+ let(:extra_config_options) { [ "node_name = bobo" ] }
+
+ it "handles the extra spaces and applies the config option" do
+ apply_config
+ expect(described_class[:node_name]).to eq("bobo")
+ end
+
+ end
+
+ context "when given an integer value" do
+
+ let(:extra_config_options) { [ "http_retries=9000" ] }
+
+ it "converts to a numeric type and applies the config option" do
+ apply_config
+ expect(described_class[:http_retries]).to eq(9000)
+ end
+
+ end
+
+ context "when given a boolean" do
+
+ let(:extra_config_options) { [ "boolean_thing=true" ] }
+
+ it "converts to a boolean type and applies the config option" do
+ apply_config
+ expect(described_class[:boolean_thing]).to eq(true)
+ end
+
+ end
+
+ context "when given input that is not in key=value form" do
+
+ let(:extra_config_options) { [ "http_retries:9000" ] }
+
+ it "raises UnparsableConfigOption" do
+ message = 'Unparsable config option "http_retries:9000"'
+ expect { apply_config }.to raise_error(ChefConfig::UnparsableConfigOption, message)
+ end
+
+ end
+
end
describe "when configuring formatters" do
@@ -112,16 +203,41 @@ RSpec.describe ChefConfig::Config do
before :each do
allow(ChefConfig).to receive(:windows?).and_return(is_windows)
end
-
+ describe "class method: windows_installation_drive" do
+ before do
+ allow(File).to receive(:expand_path).and_return("D:/Path/To/Executable")
+ end
+ if is_windows
+ it "should return D: on a windows system" do
+ expect(ChefConfig::Config.windows_installation_drive).to eq("D:")
+ end
+ else
+ it "should return nil on a non-windows system" do
+ expect(ChefConfig::Config.windows_installation_drive).to eq(nil)
+ end
+ end
+ end
describe "class method: platform_specific_path" do
+ before do
+ allow(ChefConfig::Config).to receive(:env).and_return({ "SYSTEMDRIVE" => "C:" })
+ end
if is_windows
- it "should return a windows path on windows systems" do
- path = "/etc/chef/cookbooks"
- allow(ChefConfig::Config).to receive(:env).and_return({ 'SYSTEMDRIVE' => 'C:' })
- # match on a regex that looks for the base path with an optional
- # system drive at the beginning (c:)
- # system drive is not hardcoded b/c it can change and b/c it is not present on linux systems
- expect(ChefConfig::Config.platform_specific_path(path)).to eq("C:\\chef\\cookbooks")
+ path = "/etc/chef/cookbooks"
+ context "a windows system with chef installed on C: drive" do
+ before do
+ allow(ChefConfig::Config).to receive(:windows_installation_drive).and_return("C:")
+ end
+ it "should return a windows path rooted in C:" do
+ expect(ChefConfig::Config.platform_specific_path(path)).to eq("C:\\chef\\cookbooks")
+ end
+ end
+ context "a windows system with chef installed on D: drive" do
+ before do
+ allow(ChefConfig::Config).to receive(:windows_installation_drive).and_return("D:")
+ end
+ it "should return a windows path rooted in D:" do
+ expect(ChefConfig::Config.platform_specific_path(path)).to eq("D:\\chef\\cookbooks")
+ end
end
else
it "should return given path on non-windows systems" do
@@ -150,15 +266,65 @@ RSpec.describe ChefConfig::Config do
before do
if is_windows
- allow(ChefConfig::Config).to receive(:env).and_return({ 'SYSTEMDRIVE' => 'C:' })
+ allow(ChefConfig::Config).to receive(:env).and_return({ "SYSTEMDRIVE" => "C:" })
ChefConfig::Config[:user_home] = 'C:\Users\charlie'
else
- ChefConfig::Config[:user_home] = '/Users/charlie'
+ ChefConfig::Config[:user_home] = "/Users/charlie"
end
allow(ChefConfig::Config).to receive(:path_accessible?).and_return(false)
end
+ describe "ChefConfig::Config[:fips]" do
+ let(:fips_enabled) { false }
+
+ before(:all) do
+ @original_env = ENV.to_hash
+ end
+
+ after(:all) do
+ ENV.clear
+ ENV.update(@original_env)
+ end
+
+ before(:each) do
+ ENV["CHEF_FIPS"] = nil
+ allow(ChefConfig).to receive(:fips?).and_return(fips_enabled)
+ end
+
+ it "returns false when no environment is set and not enabled on system" do
+ expect(ChefConfig::Config[:fips]).to eq(false)
+ end
+
+ context "when ENV['CHEF_FIPS'] is empty" do
+ before do
+ ENV["CHEF_FIPS"] = ""
+ end
+
+ it "returns false" do
+ expect(ChefConfig::Config[:fips]).to eq(false)
+ end
+ end
+
+ context "when ENV['CHEF_FIPS'] is set" do
+ before do
+ ENV["CHEF_FIPS"] = "1"
+ end
+
+ it "returns true" do
+ expect(ChefConfig::Config[:fips]).to eq(true)
+ end
+ end
+
+ context "when fips is enabled on system" do
+ let(:fips_enabled) { true }
+
+ it "returns true" do
+ expect(ChefConfig::Config[:fips]).to eq(true)
+ end
+ end
+ end
+
describe "ChefConfig::Config[:chef_server_root]" do
context "when chef_server_url isn't set manually" do
it "returns the default of 'https://localhost:443'" do
@@ -204,6 +370,11 @@ RSpec.describe ChefConfig::Config do
end
describe "ChefConfig::Config[:cache_path]" do
+ before do
+ if is_windows
+ allow(File).to receive(:expand_path).and_return("#{ChefConfig::Config.env["SYSTEMDRIVE"]}/Path/To/Executable")
+ end
+ end
context "when /var/chef exists and is accessible" do
it "defaults to /var/chef" do
allow(ChefConfig::Config).to receive(:path_accessible?).with(to_platform("/var/chef")).and_return(true)
@@ -244,26 +415,38 @@ RSpec.describe ChefConfig::Config do
context "and config_dir is /a/b/c" do
before do
- ChefConfig::Config.config_dir to_platform('/a/b/c')
+ ChefConfig::Config.config_dir to_platform("/a/b/c")
end
it "cache_path is /a/b/c/local-mode-cache" do
- expect(ChefConfig::Config.cache_path).to eq(to_platform('/a/b/c/local-mode-cache'))
+ expect(ChefConfig::Config.cache_path).to eq(to_platform("/a/b/c/local-mode-cache"))
end
end
context "and config_dir is /a/b/c/" do
before do
- ChefConfig::Config.config_dir to_platform('/a/b/c/')
+ ChefConfig::Config.config_dir to_platform("/a/b/c/")
end
it "cache_path is /a/b/c/local-mode-cache" do
- expect(ChefConfig::Config.cache_path).to eq(to_platform('/a/b/c/local-mode-cache'))
+ expect(ChefConfig::Config.cache_path).to eq(to_platform("/a/b/c/local-mode-cache"))
end
end
end
end
+ it "ChefConfig::Config[:stream_execute_output] defaults to false" do
+ expect(ChefConfig::Config[:stream_execute_output]).to eq(false)
+ end
+
+ it "ChefConfig::Config[:show_download_progress] defaults to false" do
+ expect(ChefConfig::Config[:show_download_progress]).to eq(false)
+ end
+
+ it "ChefConfig::Config[:download_progress_interval] defaults to every 10%" do
+ expect(ChefConfig::Config[:download_progress_interval]).to eq(10)
+ end
+
it "ChefConfig::Config[:file_backup_path] defaults to /var/chef/backup" do
allow(ChefConfig::Config).to receive(:cache_path).and_return(primary_cache_path)
backup_path = is_windows ? "#{primary_cache_path}\\backup" : "#{primary_cache_path}/backup"
@@ -278,6 +461,104 @@ RSpec.describe ChefConfig::Config do
expect(ChefConfig::Config[:ssl_ca_path]).to be_nil
end
+ describe "ChefConfig::Config[:repo_mode]" do
+
+ context "when local mode is enabled" do
+
+ before { ChefConfig::Config[:local_mode] = true }
+
+ it "defaults to 'hosted_everything'" do
+ expect(ChefConfig::Config[:repo_mode]).to eq("hosted_everything")
+ end
+
+ context "and osc_compat is enabled" do
+
+ before { ChefConfig::Config.chef_zero.osc_compat = true }
+
+ it "defaults to 'everything'" do
+ expect(ChefConfig::Config[:repo_mode]).to eq("everything")
+ end
+ end
+ end
+
+ context "when local mode is not enabled" do
+
+ context "and the chef_server_url is multi-tenant" do
+
+ before { ChefConfig::Config[:chef_server_url] = "https://chef.example/organizations/example" }
+
+ it "defaults to 'hosted_everything'" do
+ expect(ChefConfig::Config[:repo_mode]).to eq("hosted_everything")
+ end
+
+ end
+
+ context "and the chef_server_url is not multi-tenant" do
+
+ before { ChefConfig::Config[:chef_server_url] = "https://chef.example/" }
+
+ it "defaults to 'everything'" do
+ expect(ChefConfig::Config[:repo_mode]).to eq("everything")
+ end
+ end
+ end
+ end
+
+ describe "ChefConfig::Config[:chef_repo_path]" do
+
+ context "when cookbook_path is set to a single path" do
+
+ before { ChefConfig::Config[:cookbook_path] = "/home/anne/repo/cookbooks" }
+
+ it "is set to a path one directory up from the cookbook_path" do
+ expected = File.expand_path("/home/anne/repo")
+ expect(ChefConfig::Config[:chef_repo_path]).to eq(expected)
+ end
+
+ end
+
+ context "when cookbook_path is set to multiple paths" do
+
+ before do
+ ChefConfig::Config[:cookbook_path] = [
+ "/home/anne/repo/cookbooks",
+ "/home/anne/other_repo/cookbooks",
+ ]
+ end
+
+ it "is set to an Array of paths one directory up from the cookbook_paths" do
+ expected = [ "/home/anne/repo", "/home/anne/other_repo"].map { |p| File.expand_path(p) }
+ expect(ChefConfig::Config[:chef_repo_path]).to eq(expected)
+ end
+
+ end
+
+ context "when cookbook_path is not set but cookbook_artifact_path is set" do
+
+ before do
+ ChefConfig::Config[:cookbook_path] = nil
+ ChefConfig::Config[:cookbook_artifact_path] = "/home/roxie/repo/cookbook_artifacts"
+ end
+
+ it "is set to a path one directory up from the cookbook_artifact_path" do
+ expected = File.expand_path("/home/roxie/repo")
+ expect(ChefConfig::Config[:chef_repo_path]).to eq(expected)
+ end
+
+ end
+
+ context "when cookbook_path is not set" do
+
+ before { ChefConfig::Config[:cookbook_path] = nil }
+
+ it "is set to the cache_path" do
+ expect(ChefConfig::Config[:chef_repo_path]).to eq(ChefConfig::Config[:cache_path])
+ end
+
+ end
+
+ end
+
# On Windows, we'll detect an omnibus build and set this to the
# cacert.pem included in the package, but it's nil if you're on Windows
# w/o omnibus (e.g., doing development on Windows, custom build, etc.)
@@ -299,6 +580,12 @@ RSpec.describe ChefConfig::Config do
expect(ChefConfig::Config[:environment_path]).to eq(environment_path)
end
+ it "ChefConfig::Config[:cookbook_artifact_path] defaults to /var/chef/cookbook_artifacts" do
+ allow(ChefConfig::Config).to receive(:cache_path).and_return(primary_cache_path)
+ environment_path = is_windows ? "#{primary_cache_path}\\cookbook_artifacts" : "#{primary_cache_path}/cookbook_artifacts"
+ expect(ChefConfig::Config[:cookbook_artifact_path]).to eq(environment_path)
+ end
+
describe "setting the config dir" do
context "when the config file is given with a relative path" do
@@ -316,7 +603,7 @@ RSpec.describe ChefConfig::Config do
it "does not set derived paths at FS root" do
ChefConfig::Config.local_mode = true
- expect(ChefConfig::Config.cache_path.downcase).to eq(to_platform(File.join(Dir.pwd, 'local-mode-cache')).downcase)
+ expect(ChefConfig::Config.cache_path.downcase).to eq(to_platform(File.join(Dir.pwd, "local-mode-cache")).downcase)
end
end
@@ -361,7 +648,7 @@ RSpec.describe ChefConfig::Config do
end
it "config_dir is /home/charlie/.chef/" do
- expect(ChefConfig::Config.config_dir).to eq(ChefConfig::PathHelper.join(to_platform("/home/charlie/.chef"), ''))
+ expect(ChefConfig::Config.config_dir).to eq(ChefConfig::PathHelper.join(to_platform("/home/charlie/.chef"), ""))
end
context "and chef is running in local mode" do
@@ -370,7 +657,7 @@ RSpec.describe ChefConfig::Config do
end
it "config_dir is /home/charlie/.chef/" do
- expect(ChefConfig::Config.config_dir).to eq(ChefConfig::PathHelper.join(to_platform("/home/charlie/.chef"), ''))
+ expect(ChefConfig::Config.config_dir).to eq(ChefConfig::PathHelper.join(to_platform("/home/charlie/.chef"), ""))
end
end
end
@@ -423,7 +710,7 @@ RSpec.describe ChefConfig::Config do
end
describe "ChefConfig::Config[:encrypted_data_bag_secret]" do
- let(:db_secret_default_path){ to_platform("/etc/chef/encrypted_data_bag_secret") }
+ let(:db_secret_default_path) { to_platform("/etc/chef/encrypted_data_bag_secret") }
before do
allow(File).to receive(:exist?).with(db_secret_default_path).and_return(secret_exists)
@@ -458,7 +745,7 @@ RSpec.describe ChefConfig::Config do
describe "ChefConfig::Config[:user_valid_regex]" do
context "on a platform that is not Windows" do
it "allows one letter usernames" do
- any_match = ChefConfig::Config[:user_valid_regex].any? { |regex| regex.match('a') }
+ any_match = ChefConfig::Config[:user_valid_regex].any? { |regex| regex.match("a") }
expect(any_match).to be_truthy
end
end
@@ -533,7 +820,7 @@ RSpec.describe ChefConfig::Config do
it "should fall back to C locale" do
expect(ChefConfig.logger).to receive(:warn).with("Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.")
- expect(ChefConfig::Config.guess_internal_locale).to eq 'C'
+ expect(ChefConfig::Config.guess_internal_locale).to eq "C"
end
end
@@ -561,6 +848,269 @@ RSpec.describe ChefConfig::Config do
end
end
+ describe "export_proxies" do
+ before(:all) do
+ @original_env = ENV.to_hash
+ ENV["http_proxy"] = nil
+ ENV["https_proxy"] = nil
+ ENV["ftp_proxy"] = nil
+ ENV["no_proxy"] = nil
+ end
+
+ after(:all) do
+ ENV.clear
+ ENV.update(@original_env)
+ end
+
+ let(:http_proxy) { "http://localhost:7979" }
+ let(:https_proxy) { "https://localhost:7979" }
+ let(:ftp_proxy) { "ftp://localhost:7979" }
+ let(:proxy_user) { "http_user" }
+ let(:proxy_pass) { "http_pass" }
+
+ context "when http_proxy, proxy_pass and proxy_user are set" do
+ before do
+ ChefConfig::Config.http_proxy = http_proxy
+ ChefConfig::Config.http_proxy_user = proxy_user
+ ChefConfig::Config.http_proxy_pass = proxy_pass
+ end
+ it "exports ENV['http_proxy']" do
+ expect(ENV).to receive(:[]=).with("http_proxy", "http://http_user:http_pass@localhost:7979")
+ expect(ENV).to receive(:[]=).with("HTTP_PROXY", "http://http_user:http_pass@localhost:7979")
+ ChefConfig::Config.export_proxies
+ end
+ end
+
+ context "when https_proxy, proxy_pass and proxy_user are set" do
+ before do
+ ChefConfig::Config.https_proxy = https_proxy
+ ChefConfig::Config.https_proxy_user = proxy_user
+ ChefConfig::Config.https_proxy_pass = proxy_pass
+ end
+ it "exports ENV['https_proxy']" do
+ expect(ENV).to receive(:[]=).with("https_proxy", "https://http_user:http_pass@localhost:7979")
+ expect(ENV).to receive(:[]=).with("HTTPS_PROXY", "https://http_user:http_pass@localhost:7979")
+ ChefConfig::Config.export_proxies
+ end
+ end
+
+ context "when ftp_proxy, proxy_pass and proxy_user are set" do
+ before do
+ ChefConfig::Config.ftp_proxy = ftp_proxy
+ ChefConfig::Config.ftp_proxy_user = proxy_user
+ ChefConfig::Config.ftp_proxy_pass = proxy_pass
+ end
+ it "exports ENV['ftp_proxy']" do
+ expect(ENV).to receive(:[]=).with("ftp_proxy", "ftp://http_user:http_pass@localhost:7979")
+ expect(ENV).to receive(:[]=).with("FTP_PROXY", "ftp://http_user:http_pass@localhost:7979")
+ ChefConfig::Config.export_proxies
+ end
+ end
+
+ shared_examples "no user pass" do
+ it "does not populate the user or password" do
+ expect(ENV).to receive(:[]=).with("http_proxy", "http://localhost:7979")
+ expect(ENV).to receive(:[]=).with("HTTP_PROXY", "http://localhost:7979")
+ ChefConfig::Config.export_proxies
+ end
+ end
+
+ context "when proxy_pass and proxy_user are passed as empty strings" do
+ before do
+ ChefConfig::Config.http_proxy = http_proxy
+ ChefConfig::Config.http_proxy_user = ""
+ ChefConfig::Config.http_proxy_pass = proxy_pass
+ end
+ include_examples "no user pass"
+ end
+
+ context "when proxy_pass and proxy_user are not provided" do
+ before do
+ ChefConfig::Config.http_proxy = http_proxy
+ end
+ include_examples "no user pass"
+ end
+
+ context "when the proxy is provided without a scheme" do
+ before do
+ ChefConfig::Config.http_proxy = "localhost:1111"
+ end
+ it "automatically adds the scheme to the proxy url" do
+ expect(ENV).to receive(:[]=).with("http_proxy", "http://localhost:1111")
+ expect(ENV).to receive(:[]=).with("HTTP_PROXY", "http://localhost:1111")
+ ChefConfig::Config.export_proxies
+ end
+ end
+
+ shared_examples "no export" do
+ it "does not export any proxy settings" do
+ ChefConfig::Config.export_proxies
+ expect(ENV["http_proxy"]).to eq(nil)
+ expect(ENV["https_proxy"]).to eq(nil)
+ expect(ENV["ftp_proxy"]).to eq(nil)
+ expect(ENV["no_proxy"]).to eq(nil)
+ end
+ end
+
+ context "when nothing is set" do
+ include_examples "no export"
+ end
+
+ context "when all the users and passwords are set but no proxies are set" do
+ before do
+ ChefConfig::Config.http_proxy_user = proxy_user
+ ChefConfig::Config.http_proxy_pass = proxy_pass
+ ChefConfig::Config.https_proxy_user = proxy_user
+ ChefConfig::Config.https_proxy_pass = proxy_pass
+ ChefConfig::Config.ftp_proxy_user = proxy_user
+ ChefConfig::Config.ftp_proxy_pass = proxy_pass
+ end
+ include_examples "no export"
+ end
+
+ context "no_proxy is set" do
+ before do
+ ChefConfig::Config.no_proxy = "localhost"
+ end
+ it "exports ENV['no_proxy']" do
+ expect(ENV).to receive(:[]=).with("no_proxy", "localhost")
+ expect(ENV).to receive(:[]=).with("NO_PROXY", "localhost")
+ ChefConfig::Config.export_proxies
+ end
+ end
+ end
+
+ describe "proxy_uri" do
+ subject(:proxy_uri) { described_class.proxy_uri(scheme, host, port) }
+ let(:env) { {} }
+ let(:scheme) { "http" }
+ let(:host) { "test.example.com" }
+ let(:port) { 8080 }
+ let(:proxy) { "#{proxy_prefix}#{proxy_host}:#{proxy_port}" }
+ let(:proxy_prefix) { "http://" }
+ let(:proxy_host) { "proxy.mycorp.com" }
+ let(:proxy_port) { 8080 }
+
+ before do
+ stub_const("ENV", env)
+ end
+
+ shared_examples_for "a proxy uri" do
+ it "contains the host" do
+ expect(proxy_uri.host).to eq(proxy_host)
+ end
+
+ it "contains the port" do
+ expect(proxy_uri.port).to eq(proxy_port)
+ end
+ end
+
+ context "when the config setting is normalized (does not contain the scheme)" do
+ include_examples "a proxy uri" do
+
+ let(:proxy_prefix) { "" }
+
+ let(:env) do
+ {
+ "#{scheme}_proxy" => proxy,
+ "no_proxy" => nil,
+ }
+ end
+ end
+ end
+
+ context "when the proxy is set by the environment" do
+ include_examples "a proxy uri" do
+ let(:scheme) { "https" }
+ let(:env) do
+ {
+ "https_proxy" => "https://jane_username:opensesame@proxy.mycorp.com:8080",
+ }
+ end
+ end
+ end
+
+ context "when an empty proxy is set by the environment" do
+ let(:env) do
+ {
+ "https_proxy" => "",
+ }
+ end
+
+ it "does not fail with URI parse exception" do
+ expect { proxy_uri }.to_not raise_error
+ end
+ end
+
+ context "when no_proxy is set" do
+ context "when no_proxy is the exact host" do
+ let(:env) do
+ {
+ "http_proxy" => proxy,
+ "no_proxy" => host,
+ }
+ end
+
+ it { is_expected.to eq nil }
+ end
+
+ context "when no_proxy includes the same domain with a wildcard" do
+ let(:env) do
+ {
+ "http_proxy" => proxy,
+ "no_proxy" => "*.example.com",
+ }
+ end
+
+ it { is_expected.to eq nil }
+ end
+
+ context "when no_proxy is included on a list" do
+ let(:env) do
+ {
+ "http_proxy" => proxy,
+ "no_proxy" => "chef.io,getchef.com,opscode.com,test.example.com",
+ }
+ end
+
+ it { is_expected.to eq nil }
+ end
+
+ context "when no_proxy is included on a list with wildcards" do
+ let(:env) do
+ {
+ "http_proxy" => proxy,
+ "no_proxy" => "10.*,*.example.com",
+ }
+ end
+
+ it { is_expected.to eq nil }
+ end
+
+ context "when no_proxy is a domain with a dot prefix" do
+ let(:env) do
+ {
+ "http_proxy" => proxy,
+ "no_proxy" => ".example.com",
+ }
+ end
+
+ it { is_expected.to eq nil }
+ end
+
+ context "when no_proxy is a domain with no wildcard" do
+ let(:env) do
+ {
+ "http_proxy" => proxy,
+ "no_proxy" => "example.com",
+ }
+ end
+
+ it { is_expected.to eq nil }
+ end
+ end
+ end
+
describe "allowing chefdk configuration outside of chefdk" do
it "allows arbitrary settings in the chefdk config context" do
@@ -578,7 +1128,7 @@ RSpec.describe ChefConfig::Config do
end
it "sets CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS environment variable" do
- expect(ENV['CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS']).to eq("1")
+ expect(ENV["CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS"]).to eq("1")
end
it "treats deprecation warnings as errors in child processes when testing" do
@@ -596,7 +1146,7 @@ RSpec.describe ChefConfig::Config do
context "outside of our test environment" do
before do
- ENV.delete('CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS')
+ ENV.delete("CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS")
ChefConfig::Config.reset
end
@@ -605,6 +1155,35 @@ RSpec.describe ChefConfig::Config do
end
end
+ end
+
+ describe "data collector URL" do
+
+ context "when using default settings" do
+
+ context "for Chef Client" do
+
+ it "configures the data collector URL as a relative path to the Chef Server URL" do
+ ChefConfig::Config[:chef_server_url] = "https://chef.example/organizations/myorg"
+ expect(ChefConfig::Config[:data_collector][:server_url]).to eq("https://chef.example/organizations/myorg/data-collector")
+ end
+
+ end
+
+ context "for Chef Solo" do
+
+ before do
+ ChefConfig::Config[:solo] = true
+ end
+
+ it "sets the data collector server URL to nil" do
+ ChefConfig::Config[:chef_server_url] = "https://chef.example/organizations/myorg"
+ expect(ChefConfig::Config[:data_collector][:server_url]).to be_nil
+ end
+
+ end
+
+ end
end
diff --git a/chef-config/spec/unit/fips_spec.rb b/chef-config/spec/unit/fips_spec.rb
new file mode 100644
index 0000000000..cf5af22ef1
--- /dev/null
+++ b/chef-config/spec/unit/fips_spec.rb
@@ -0,0 +1,122 @@
+#
+# Author:: Matt Wrock (<matt@mattwrock.com>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef-config/fips"
+require "spec_helper"
+
+RSpec.describe "ChefConfig.fips?" do
+ let(:enabled) { "0" }
+
+ context "on *nix" do
+ let(:fips_path) { "/proc/sys/crypto/fips_enabled" }
+
+ before(:each) do
+ allow(ChefConfig).to receive(:windows?).and_return(false)
+ allow(::File).to receive(:exist?).with(fips_path).and_return(true)
+ allow(::File).to receive(:read).with(fips_path).and_return(enabled)
+ end
+
+ context "fips file is present and contains 1" do
+ let(:enabled) { "1" }
+
+ it "returns true" do
+ expect(ChefConfig.fips?).to be(true)
+ end
+ end
+
+ context "fips file does not contain 1" do
+ let(:enabled) { "0" }
+
+ it "returns false" do
+ expect(ChefConfig.fips?).to be(false)
+ end
+ end
+
+ context "fips file is not present" do
+ before do
+ allow(::File).to receive(:exist?).with(fips_path).and_return(false)
+ end
+
+ it "returns false" do
+ expect(ChefConfig.fips?).to be(false)
+ end
+ end
+ end
+
+ context "on windows", :windows_only do
+ let(:fips_key) { 'System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy' }
+ let(:win_reg_entry) { { "Enabled" => enabled } }
+
+ before(:each) do
+ allow(ChefConfig).to receive(:windows?).and_return(true)
+ allow(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).with(fips_key, arch).and_yield(win_reg_entry)
+ end
+
+ shared_examples "fips_detection" do
+ context "fips enabled key is set to 1" do
+ let(:enabled) { 1 }
+
+ it "returns true" do
+ expect(ChefConfig.fips?).to be(true)
+ end
+ end
+
+ context "fips enabled key is set to 0" do
+ let(:enabled) { 0 }
+
+ it "returns false" do
+ expect(ChefConfig.fips?).to be(false)
+ end
+ end
+
+ context "fips key does not exist" do
+ before do
+ allow(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).and_raise(Win32::Registry::Error, 50)
+ end
+
+ it "returns false" do
+ expect(ChefConfig.fips?).to be(false)
+ end
+ end
+ end
+
+ context "on 32 bit ruby" do
+ let(:arch) { Win32::Registry::KEY_READ | 0x100 }
+
+ before { stub_const("::RbConfig::CONFIG", { "target_cpu" => "i386" } ) }
+
+ it_behaves_like "fips_detection"
+ end
+
+ context "on 64 bit ruby" do
+ let(:arch) { Win32::Registry::KEY_READ | 0x200 }
+
+ before { stub_const("::RbConfig::CONFIG", { "target_cpu" => "x86_64" } ) }
+
+ it_behaves_like "fips_detection"
+ end
+
+ context "on unknown ruby" do
+ let(:arch) { Win32::Registry::KEY_READ }
+
+ before { stub_const("::RbConfig::CONFIG", { "target_cpu" => nil } ) }
+
+ it_behaves_like "fips_detection"
+ end
+ end
+end
diff --git a/chef-config/spec/unit/path_helper_spec.rb b/chef-config/spec/unit/path_helper_spec.rb
index 3e6213597a..399b3dc965 100644
--- a/chef-config/spec/unit/path_helper_spec.rb
+++ b/chef-config/spec/unit/path_helper_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef-config/path_helper'
-require 'spec_helper'
+require "chef-config/path_helper"
+require "spec_helper"
RSpec.describe ChefConfig::PathHelper do
@@ -27,30 +27,30 @@ RSpec.describe ChefConfig::PathHelper do
describe "join" do
it "joins starting with '' resolve to absolute paths" do
- expect(path_helper.join('', 'a', 'b')).to eq("#{path_helper.path_separator}a#{path_helper.path_separator}b")
+ expect(path_helper.join("", "a", "b")).to eq("#{path_helper.path_separator}a#{path_helper.path_separator}b")
end
it "joins ending with '' add a / to the end" do
- expect(path_helper.join('a', 'b', '')).to eq("a#{path_helper.path_separator}b#{path_helper.path_separator}")
+ expect(path_helper.join("a", "b", "")).to eq("a#{path_helper.path_separator}b#{path_helper.path_separator}")
end
end
describe "dirname" do
it "dirname('abc') is '.'" do
- expect(path_helper.dirname('abc')).to eq('.')
+ expect(path_helper.dirname("abc")).to eq(".")
end
it "dirname('/') is '/'" do
expect(path_helper.dirname(path_helper.path_separator)).to eq(path_helper.path_separator)
end
it "dirname('a/b/c') is 'a/b'" do
- expect(path_helper.dirname(path_helper.join('a', 'b', 'c'))).to eq(path_helper.join('a', 'b'))
+ expect(path_helper.dirname(path_helper.join("a", "b", "c"))).to eq(path_helper.join("a", "b"))
end
it "dirname('a/b/c/') is 'a/b'" do
- expect(path_helper.dirname(path_helper.join('a', 'b', 'c', ''))).to eq(path_helper.join('a', 'b'))
+ expect(path_helper.dirname(path_helper.join("a", "b", "c", ""))).to eq(path_helper.join("a", "b"))
end
it "dirname('/a/b/c') is '/a/b'" do
- expect(path_helper.dirname(path_helper.join('', 'a', 'b', 'c'))).to eq(path_helper.join('', 'a', 'b'))
+ expect(path_helper.dirname(path_helper.join("", "a", "b", "c"))).to eq(path_helper.join("", "a", "b"))
end
end
end
@@ -93,7 +93,6 @@ RSpec.describe ChefConfig::PathHelper do
end
-
it "cleanpath changes slashes into backslashes and leaves backslashes alone" do
expect(path_helper.cleanpath('/a/b\\c/d/')).to eq('\\a\\b\\c\\d')
end
@@ -113,11 +112,11 @@ RSpec.describe ChefConfig::PathHelper do
include_examples("common_functionality")
it "path_separator is /" do
- expect(path_helper.path_separator).to eq('/')
+ expect(path_helper.path_separator).to eq("/")
end
it "cleanpath removes extra slashes alone" do
- expect(path_helper.cleanpath('/a///b/c/d/')).to eq('/a/b/c/d')
+ expect(path_helper.cleanpath("/a///b/c/d/")).to eq("/a/b/c/d")
end
describe "platform-specific #join behavior" do
@@ -224,7 +223,7 @@ RSpec.describe ChefConfig::PathHelper do
end
end
- context "not on windows", :unix_only do
+ context "not on windows", :unix_only do
it "returns a canonical path" do
expect(path_helper.canonical_path("/etc//apache.d/sites-enabled/../sites-available/default")).to eq("/etc/apache.d/sites-available/default")
end
@@ -256,10 +255,10 @@ RSpec.describe ChefConfig::PathHelper do
it "joins, cleanpaths, and escapes characters reserved by glob" do
args = ["this/*path", "[needs]", "escaping?"]
escaped_path = if ChefConfig.windows?
- "this\\\\\\*path\\\\\\[needs\\]\\\\escaping\\?"
- else
- "this/\\*path/\\[needs\\]/escaping\\?"
- end
+ "this\\\\\\*path\\\\\\[needs\\]\\\\escaping\\?"
+ else
+ "this/\\*path/\\[needs\\]/escaping\\?"
+ end
expect(path_helper).to receive(:join).with(*args).and_call_original
expect(path_helper).to receive(:cleanpath).and_call_original
expect(path_helper.escape_glob(*args)).to eq(escaped_path)
@@ -267,9 +266,26 @@ RSpec.describe ChefConfig::PathHelper do
end
end
+ describe "escape_glob_dir" do
+ it "escapes characters reserved by glob without using backslashes for path separators" do
+ path = "C:/this/*path/[needs]/escaping?"
+ escaped_path = "C:/this/\\*path/\\[needs\\]/escaping\\?"
+ expect(path_helper.escape_glob_dir(path)).to eq(escaped_path)
+ end
+
+ context "when given more than one argument" do
+ it "joins, cleanpaths, and escapes characters reserved by glob" do
+ args = ["this/*path", "[needs]", "escaping?"]
+ escaped_path = "this/\\*path/\\[needs\\]/escaping\\?"
+ expect(path_helper).to receive(:join).with(*args).and_call_original
+ expect(path_helper.escape_glob_dir(*args)).to eq(escaped_path)
+ end
+ end
+ end
+
describe "all_homes" do
before do
- stub_const('ENV', env)
+ stub_const("ENV", env)
allow(ChefConfig).to receive(:windows?).and_return(is_windows)
end
diff --git a/chef-config/spec/unit/workstation_config_loader_spec.rb b/chef-config/spec/unit/workstation_config_loader_spec.rb
index 9f24a4f11b..087f249724 100644
--- a/chef-config/spec/unit/workstation_config_loader_spec.rb
+++ b/chef-config/spec/unit/workstation_config_loader_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tempfile'
+require "spec_helper"
+require "tempfile"
-require 'chef-config/exceptions'
-require 'chef-config/windows'
-require 'chef-config/workstation_config_loader'
+require "chef-config/exceptions"
+require "chef-config/windows"
+require "chef-config/workstation_config_loader"
RSpec.describe ChefConfig::WorkstationConfigLoader do
@@ -35,6 +35,12 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
end
end
+ before do
+ # We set this to nil so that a dev workstation will
+ # not interfere with the tests.
+ ChefConfig::Config[:config_d_dir] = nil
+ end
+
# Test methods that do I/O or reference external state which are stubbed out
# elsewhere.
describe "external dependencies" do
@@ -45,7 +51,7 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
end
it "tests a path's existence" do
- expect(config_loader.path_exists?('/nope/nope/nope/nope/frab/jab/nab')).to be(false)
+ expect(config_loader.path_exists?("/nope/nope/nope/nope/frab/jab/nab")).to be(false)
expect(config_loader.path_exists?(__FILE__)).to be(true)
end
@@ -68,7 +74,7 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
let(:home) { "/Users/example.user" }
before do
- allow(ChefConfig::PathHelper).to receive(:home).with('.chef').and_yield(File.join(home, '.chef'))
+ allow(ChefConfig::PathHelper).to receive(:home).with(".chef").and_yield(File.join(home, ".chef"))
allow(config_loader).to receive(:path_exists?).with("#{home}/.chef/knife.rb").and_return(true)
end
@@ -138,7 +144,6 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
expect(config_loader.config_location).to eq("#{cwd}/config.rb")
end
-
context "and/or KNIFE_HOME is set" do
let(:knife_home) { "/path/to/knife/home" }
@@ -206,7 +211,6 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
end
end
-
describe "loading the config file" do
context "when no explicit config is specifed and no implicit config is found" do
@@ -217,7 +221,8 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
it "skips loading" do
expect(config_loader.config_location).to be(nil)
- expect(config_loader.load).to be(false)
+ expect(config_loader).not_to receive(:apply_config)
+ config_loader.load
end
end
@@ -256,7 +261,8 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
let(:config_content) { "config_file_evaluated(true)" }
it "loads the config" do
- expect(config_loader.load).to be(true)
+ expect(config_loader).to receive(:apply_config).and_call_original
+ config_loader.load
expect(ChefConfig::Config.config_file_evaluated).to be(true)
end
@@ -288,4 +294,73 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
end
+ describe "when loading config.d" do
+ context "when the conf.d directory exists" do
+ let(:config_content) { "" }
+
+ let(:tempdir) { Dir.mktmpdir("chef-workstation-test") }
+
+ let!(:confd_file) do
+ Tempfile.new(["Chef-WorkstationConfigLoader-rspec-test", ".rb"], tempdir).tap do |t|
+ t.print(config_content)
+ t.close
+ end
+ end
+
+ before do
+ ChefConfig::Config[:config_d_dir] = tempdir
+ allow(config_loader).to receive(:path_exists?).with(
+ an_instance_of(String)).and_return(false)
+ end
+
+ after do
+ FileUtils.remove_entry_secure tempdir
+ end
+
+ context "and is valid" do
+ let(:config_content) { "config_d_file_evaluated(true)" }
+
+ it "loads the config" do
+ expect(config_loader).to receive(:apply_config).and_call_original
+ config_loader.load
+ expect(ChefConfig::Config.config_d_file_evaluated).to be(true)
+ end
+ end
+
+ context "and has a syntax error" do
+ let(:config_content) { "{{{{{:{{" }
+
+ it "raises a ConfigurationError" do
+ expect { config_loader.load }.to raise_error(ChefConfig::ConfigurationError)
+ end
+ end
+
+ context "has a non rb file" do
+ let(:sytax_error_content) { "{{{{{:{{" }
+ let(:config_content) { "config_d_file_evaluated(true)" }
+
+ let!(:not_confd_file) do
+ Tempfile.new(["Chef-WorkstationConfigLoader-rspec-test", ".foorb"], tempdir).tap do |t|
+ t.print(sytax_error_content)
+ t.close
+ end
+ end
+
+ it "does not load the non rb file" do
+ expect { config_loader.load }.not_to raise_error
+ expect(ChefConfig::Config.config_d_file_evaluated).to be(true)
+ end
+ end
+ end
+
+ context "when the conf.d directory does not exist" do
+ before do
+ ChefConfig::Config[:config_d_dir] = "/nope/nope/nope/nope/notdoingit"
+ end
+
+ it "does not load anything" do
+ expect(config_loader).not_to receive(:apply_config)
+ end
+ end
+ end
end
diff --git a/chef-windows.gemspec b/chef-universal-mingw32.gemspec
index 1c72d9102a..449f909bb2 100644
--- a/chef-windows.gemspec
+++ b/chef-universal-mingw32.gemspec
@@ -1,12 +1,14 @@
gemspec = eval(IO.read(File.expand_path("../chef.gemspec", __FILE__)))
-gemspec.platform = Gem::Platform.new(["universal", "mingw32"])
+gemspec.platform = Gem::Platform.new(%w{universal mingw32})
gemspec.add_dependency "ffi", "~> 1.9"
gemspec.add_dependency "win32-api", "~> 1.5.3"
gemspec.add_dependency "win32-dir", "~> 0.5.0"
gemspec.add_dependency "win32-event", "~> 0.6.1"
-gemspec.add_dependency "win32-eventlog", "~> 0.6.2"
+# TODO: Relax this pin and make the necessary updaets. The issue originally
+# leading to this pin has been fixed in 0.6.5.
+gemspec.add_dependency "win32-eventlog", "0.6.3"
gemspec.add_dependency "win32-mmap", "~> 0.4.1"
gemspec.add_dependency "win32-mutex", "~> 0.4.2"
gemspec.add_dependency "win32-process", "~> 0.8.2"
@@ -14,8 +16,8 @@ gemspec.add_dependency "win32-service", "~> 0.8.7"
gemspec.add_dependency "windows-api", "~> 0.4.4"
gemspec.add_dependency "wmi-lite", "~> 1.0"
gemspec.extensions << "ext/win32-eventlog/Rakefile"
-gemspec.files += %w(ext/win32-eventlog/Rakefile ext/win32-eventlog/chef-log.man)
+gemspec.files += %w{ext/win32-eventlog/Rakefile ext/win32-eventlog/chef-log.man}
-gemspec.executables += %w( chef-service-manager chef-windows-service )
+gemspec.executables += %w{ chef-service-manager chef-windows-service }
gemspec
diff --git a/chef.gemspec b/chef.gemspec
index 96673f391a..2b80d817b8 100644
--- a/chef.gemspec
+++ b/chef.gemspec
@@ -1,8 +1,8 @@
-$:.unshift(File.dirname(__FILE__) + '/lib')
-require 'chef/version'
+$:.unshift(File.dirname(__FILE__) + "/lib")
+require "chef/version"
Gem::Specification.new do |s|
- s.name = 'chef'
+ s.name = "chef"
s.version = Chef::VERSION
s.platform = Gem::Platform::RUBY
s.extra_rdoc_files = ["README.md", "CONTRIBUTING.md", "LICENSE" ]
@@ -11,46 +11,51 @@ Gem::Specification.new do |s|
s.license = "Apache-2.0"
s.author = "Adam Jacob"
s.email = "adam@chef.io"
- s.homepage = "http://www.chef.io"
+ s.homepage = "https://www.chef.io"
- s.required_ruby_version = ">= 2.0.0"
+ s.required_ruby_version = ">= 2.2.2"
s.add_dependency "chef-config", "= #{Chef::VERSION}"
- s.add_dependency "mixlib-cli", "~> 1.4"
+ s.add_dependency "mixlib-cli", "~> 1.7"
s.add_dependency "mixlib-log", "~> 1.3"
- s.add_dependency "mixlib-authentication", "~> 1.3"
+ s.add_dependency "mixlib-authentication", "~> 1.4"
s.add_dependency "mixlib-shellout", "~> 2.0"
- s.add_dependency "ohai", ">= 8.6.0.alpha.1", "< 9"
+ s.add_dependency "mixlib-archive", "~> 0.4"
+ s.add_dependency "ohai", ">= 8.6.0.alpha.1", "< 13"
s.add_dependency "ffi-yajl", "~> 2.2"
- s.add_dependency "net-ssh", "~> 2.6"
- s.add_dependency "net-ssh-multi", "~> 1.1"
+ s.add_dependency "net-ssh", ">= 2.9", "< 5.0"
+ s.add_dependency "net-ssh-multi", "~> 1.2", ">= 1.2.1"
+ s.add_dependency "net-sftp", "~> 2.1", ">= 2.1.2"
s.add_dependency "highline", "~> 1.6", ">= 1.6.9"
s.add_dependency "erubis", "~> 2.7"
s.add_dependency "diff-lcs", "~> 1.2", ">= 1.2.4"
- s.add_dependency "chef-zero", "~> 4.2", ">= 4.2.2"
- s.add_dependency "pry", "~> 0.9"
+ s.add_dependency "chef-zero", ">= 4.8"
- s.add_dependency 'plist', '~> 3.1.0'
+ s.add_dependency "plist", "~> 3.2"
+ s.add_dependency "iniparse", "~> 1.4"
+ s.add_dependency "addressable"
# Audit mode requires these, so they are non-developmental dependencies now
- %w(rspec-core rspec-expectations rspec-mocks).each { |gem| s.add_dependency gem, "~> 3.2" }
+ %w{rspec-core rspec-expectations rspec-mocks}.each { |gem| s.add_dependency gem, "~> 3.5" }
s.add_dependency "rspec_junit_formatter", "~> 0.2.0"
s.add_dependency "serverspec", "~> 2.7"
s.add_dependency "specinfra", "~> 2.10"
s.add_dependency "syslog-logger", "~> 1.6"
+ s.add_dependency "uuidtools", "~> 2.1.5"
- s.add_development_dependency "rack"
- s.add_development_dependency "cheffish", "~> 1.1"
+ s.add_dependency "proxifier", "~> 1.0"
- s.add_development_dependency "rake", "~> 10.1"
+ # v1.10 is needed as a runtime dep now for 'bundler/inline'
+ # very deliberately avoiding putting a ceiling on this to avoid depsolver conflicts.
+ s.add_dependency "bundler", ">= 1.10"
s.bindir = "bin"
- s.executables = %w( chef-client chef-solo knife chef-shell chef-apply )
+ s.executables = %w{ chef-client chef-solo knife chef-shell chef-apply }
- s.require_path = 'lib'
- s.files = %w(Gemfile Rakefile LICENSE README.md CONTRIBUTING.md) + Dir.glob("{distro,lib,tasks,spec}/**/*", File::FNM_DOTMATCH).reject {|f| File.directory?(f) } + Dir.glob("*.gemspec")
+ s.require_paths = %w{ lib lib-backcompat }
+ s.files = %w{Gemfile Rakefile LICENSE README.md CONTRIBUTING.md VERSION} + Dir.glob("{distro,lib,lib-backcompat,tasks,acceptance,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) } + Dir.glob("*.gemspec")
end
diff --git a/ci/bundle_install.sh b/ci/bundle_install.sh
new file mode 100755
index 0000000000..4eecec9f18
--- /dev/null
+++ b/ci/bundle_install.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+set -evx
+
+gem environment
+bundler_version=$(grep bundler omnibus_overrides.rb | cut -d'"' -f2)
+gem install bundler -v $bundler_version --user-install --conservative
+# WITH: changelog (for version bumping and changelog creation)
+export BUNDLE_WITHOUT=omnibus_package:test:pry:integration:docgen:maintenance:travis:aix:bsd:linux:mac_os_x:solaris:windows:development:travis
+bundle _${bundler_version}_ install
diff --git a/ci/dependency_update.sh b/ci/dependency_update.sh
new file mode 100755
index 0000000000..65b67be526
--- /dev/null
+++ b/ci/dependency_update.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+set -evx
+
+. ci/bundle_install.sh
+
+bundle exec rake dependencies_ci
+
+git checkout .bundle/config
diff --git a/ci/jenkins_run_tests.bat b/ci/jenkins_run_tests.bat
deleted file mode 100644
index ba9cedd5e2..0000000000
--- a/ci/jenkins_run_tests.bat
+++ /dev/null
@@ -1,14 +0,0 @@
-ruby -v
-
-call bundle check
-
-if %ERRORLEVEL% NEQ 0 (
- call rm Gemfile.lock
- call bundle install --without docgen --path vendor/bundle
-)
-
-bundle exec rspec -r rspec_junit_formatter -f RspecJunitFormatter -o test.xml -f documentation spec/functional spec/unit spec/stress spec/integration
-
-set RSPEC_ERRORLVL=%ERRORLEVEL%
-REM Return the error level from rspec
-exit /B %RSPEC_ERRORLVL%
diff --git a/ci/jenkins_run_tests.sh b/ci/jenkins_run_tests.sh
deleted file mode 100755
index 5bf7def062..0000000000
--- a/ci/jenkins_run_tests.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-export PATH=$PATH:/usr/local/bin
-
-ruby -v;
-# remove the Gemfile.lock and try again if bundler fails.
-# This should take care of Gemfile changes that result in "bad" bundles without forcing us to rebundle every time
-bundle install --without docgen --path vendor/bundle || ( rm Gemfile.lock && bundle install --path vendor/bundle )
-bundle exec rspec -r rspec_junit_formatter -f RspecJunitFormatter -o test.xml -f documentation spec;
-RSPEC_RETURNCODE=$?
-
-# exit with the result of running rspec
-exit $RSPEC_RETURNCODE
diff --git a/ci/verify-chef.bat b/ci/verify-chef.bat
new file mode 100755
index 0000000000..7ba0817938
--- /dev/null
+++ b/ci/verify-chef.bat
@@ -0,0 +1,67 @@
+
+@ECHO OFF
+
+REM ; %PROJECT_NAME% is set by Jenkins, this allows us to use the same script to verify
+REM ; Chef and Angry Chef
+cd C:\opscode\%PROJECT_NAME%\bin
+
+REM ; We don't want to add the embedded bin dir to the main PATH as this
+REM ; could mask issues in our binstub shebangs.
+SET EMBEDDED_BIN_DIR=C:\opscode\%PROJECT_NAME%\embedded\bin
+
+ECHO.
+
+REM ; Set the temporary directory to a custom location, and wipe it before
+REM ; and after the tests run.
+SET TEMP=%TEMP%\cheftest
+SET TMP=%TMP%\cheftest
+RMDIR /S /Q %TEMP%
+MKDIR %TEMP%
+
+FOR %%b IN (
+ chef-client
+ knife
+ chef-solo
+ ohai
+) DO (
+
+
+ ECHO Checking for existence of binfile `%%b`...
+
+ IF EXIST %%b (
+ ECHO ...FOUND IT!
+ ) ELSE (
+ GOTO :error
+ )
+ ECHO.
+)
+
+call chef-client --version
+
+REM ; Exercise various packaged tools to validate binstub shebangs
+call %EMBEDDED_BIN_DIR%\ruby --version
+call %EMBEDDED_BIN_DIR%\gem --version
+call %EMBEDDED_BIN_DIR%\bundle --version
+call %EMBEDDED_BIN_DIR%\rspec --version
+
+SET PATH=C:\opscode\%PROJECT_NAME%\bin;C:\opscode\%PROJECT_NAME%\embedded\bin;%PATH%
+
+REM ; Test against the vendored chef gem (cd into the output of "bundle show chef")
+for /f "delims=" %%a in ('bundle show chef') do cd %%a
+
+IF NOT EXIST "Gemfile.lock" (
+ ECHO "Chef gem does not contain a Gemfile.lock! This is needed to run any tests."
+ GOTO :error
+)
+
+IF "%PIPELINE_NAME%" == "chef-fips" (
+ set CHEF_FIPS=1
+)
+
+REM ; ffi-yajl must run in c-extension mode for perf, so force it so we don't accidentally fall back to ffi
+set FORCE_FFI_YAJL=ext
+
+set BUNDLE_GEMFILE=C:\opscode\%PROJECT_NAME%\Gemfile
+set BUNDLE_IGNORE_CONFIG=true
+set BUNDLE_FROZEN=1
+call bundle exec rspec -r rspec_junit_formatter -f RspecJunitFormatter -o %WORKSPACE%\test.xml -f documentation spec/functional
diff --git a/ci/verify-chef.sh b/ci/verify-chef.sh
new file mode 100755
index 0000000000..71d4afe0df
--- /dev/null
+++ b/ci/verify-chef.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+
+set -evx
+
+# Set up a custom tmpdir, and clean it up before and after the tests
+TMPDIR="${TMPDIR:-/tmp}/cheftest"
+export TMPDIR
+rm -rf $TMPDIR
+mkdir -p $TMPDIR
+
+# $PROJECT_NAME is set by Jenkins, this allows us to use the same script to verify
+# Chef and Angry Chef
+PATH=/opt/$PROJECT_NAME/bin:$PATH
+export PATH
+
+BIN_DIR=/opt/$PROJECT_NAME/bin
+export BIN_DIR
+
+# We don't want to add the embedded bin dir to the main PATH as this
+# could mask issues in our binstub shebangs.
+EMBEDDED_BIN_DIR=/opt/$PROJECT_NAME/embedded/bin
+export EMBEDDED_BIN_DIR
+
+# If we are on Mac our symlinks are located under /usr/local/bin
+# otherwise they are under /usr/bin
+if [ -f /usr/bin/sw_vers ]; then
+ USR_BIN_DIR="/usr/local/bin"
+else
+ USR_BIN_DIR="/usr/bin"
+fi
+export USR_BIN_DIR
+
+# sanity check that we're getting the correct symlinks from the pre-install script
+# solaris doesn't have readlink or test -e. ls -n is different on BSD. proceed with caution.
+if [ ! -L $USR_BIN_DIR/chef-client ] || [ `ls -l $USR_BIN_DIR/chef-client | awk '{print$NF}'` != "$BIN_DIR/chef-client" ]; then
+ echo "$USR_BIN_DIR/chef-client symlink to $BIN_DIR/chef-client was not correctly created by the pre-install script!"
+ exit 1
+fi
+
+if [ ! -L $USR_BIN_DIR/knife ] || [ `ls -l $USR_BIN_DIR/knife | awk '{print$NF}'` != "$BIN_DIR/knife" ]; then
+ echo "$USR_BIN_DIR/knife symlink to $BIN_DIR/knife was not correctly created by the pre-install script!"
+ exit 1
+fi
+
+if [ ! -L $USR_BIN_DIR/chef-solo ] || [ `ls -l $USR_BIN_DIR/chef-solo | awk '{print$NF}'` != "$BIN_DIR/chef-solo" ]; then
+ echo "$USR_BIN_DIR/chef-solo symlink to $BIN_DIR/chef-solo was not correctly created by the pre-install script!"
+ exit 1
+fi
+
+if [ ! -L $USR_BIN_DIR/ohai ] || [ `ls -l $USR_BIN_DIR/ohai | awk '{print$NF}'` != "$BIN_DIR/ohai" ]; then
+ echo "$USR_BIN_DIR/ohai symlink to $BIN_DIR/ohai was not correctly created by the pre-install script!"
+ exit 1
+fi
+
+# Ensure the calling environment (disapproval look Bundler) does not
+# infect our Ruby environment created by the `chef-client` cli.
+for ruby_env_var in _ORIGINAL_GEM_PATH \
+ BUNDLE_BIN_PATH \
+ BUNDLE_GEMFILE \
+ GEM_HOME \
+ GEM_PATH \
+ GEM_ROOT \
+ RUBYLIB \
+ RUBYOPT \
+ RUBY_ENGINE \
+ RUBY_ROOT \
+ RUBY_VERSION
+
+do
+ unset $ruby_env_var
+done
+
+chef-client --version
+
+# Exercise various packaged tools to validate binstub shebangs
+$EMBEDDED_BIN_DIR/ruby --version
+$EMBEDDED_BIN_DIR/gem --version
+$EMBEDDED_BIN_DIR/bundle --version
+$EMBEDDED_BIN_DIR/rspec --version
+
+# ffi-yajl must run in c-extension mode or we take perf hits, so we force it
+# before running rspec so that we don't wind up testing the ffi mode
+FORCE_FFI_YAJL=ext
+export FORCE_FFI_YAJL
+
+# ACCEPTANCE environment variable will be set on acceptance testers.
+# If is it set; we run the acceptance tests, otherwise run rspec tests.
+if [ "x$ACCEPTANCE" != "x" ]; then
+ # Find the Chef gem and cd there.
+ OLD_PATH=$PATH
+ PATH=/opt/$PROJECT_NAME/bin:/opt/$PROJECT_NAME/embedded/bin:$PATH
+ cd /opt/$PROJECT_NAME
+ CHEF_GEM=`bundle show chef`
+ PATH=$OLD_PATH
+
+ # On acceptance testers we have Chef DK. We will use its Ruby environment
+ # to cut down the gem installation time.
+ PATH=/opt/chefdk/bin:/opt/chefdk/embedded/bin:$PATH
+ export PATH
+
+ # copy acceptance suites into workspace
+ SUITE_PATH=$WORKSPACE/acceptance
+ mkdir -p $SUITE_PATH
+ cp -R $CHEF_GEM/acceptance/. $SUITE_PATH
+ sudo chown -R $USER:$USER $SUITE_PATH
+
+ cd $SUITE_PATH
+
+ env PATH=$PATH AWS_SSH_KEY_ID=$AWS_SSH_KEY_ID bundle install --deployment
+ env PATH=$PATH AWS_SSH_KEY_ID=$AWS_SSH_KEY_ID KITCHEN_DRIVER=ec2 KITCHEN_CHEF_CHANNEL=unstable bundle exec chef-acceptance test --force-destroy --data-path $WORKSPACE/chef-acceptance-data
+else
+ PATH=/opt/$PROJECT_NAME/bin:/opt/$PROJECT_NAME/embedded/bin:$PATH
+ export PATH
+
+ # Test against the installed Chef gem
+ cd /opt/$PROJECT_NAME
+ CHEF_GEM=`bundle show chef`
+ cd $CHEF_GEM
+ if [ ! -f "Gemfile.lock" ]; then
+ echo "Chef gem does not contain a Gemfile.lock! This is needed to run any tests."
+ exit 1
+ fi
+
+ sudo env BUNDLE_GEMFILE=/opt/$PROJECT_NAME/Gemfile BUNDLE_IGNORE_CONFIG=true BUNDLE_FROZEN=1 PATH=$PATH TERM=xterm bundle exec rspec -r rspec_junit_formatter -f RspecJunitFormatter -o $WORKSPACE/test.xml -f documentation spec/functional
+fi
diff --git a/ci/version_bump.sh b/ci/version_bump.sh
new file mode 100755
index 0000000000..ed2229ecc3
--- /dev/null
+++ b/ci/version_bump.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+set -evx
+
+export LANG=en_US.UTF-8
+
+. ci/bundle_install.sh
+
+bundle exec rake version:bump
+bundle exec rake changelog || true
+bundle exec rake update_dockerfile
+
+git checkout .bundle/config
diff --git a/ci/version_show.sh b/ci/version_show.sh
new file mode 100755
index 0000000000..5348f6f090
--- /dev/null
+++ b/ci/version_show.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+cat VERSION
diff --git a/distro/common/html/_static/basic.css b/distro/common/html/_static/basic.css
index 967e36ce05..a67b16ec88 100644
--- a/distro/common/html/_static/basic.css
+++ b/distro/common/html/_static/basic.css
@@ -4,7 +4,7 @@
*
* Sphinx stylesheet -- basic theme.
*
- * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ * :copyright: Copyright 2007-2016, by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
diff --git a/distro/common/html/_static/doctools.js b/distro/common/html/_static/doctools.js
index c5455c905d..e380d88303 100644
--- a/distro/common/html/_static/doctools.js
+++ b/distro/common/html/_static/doctools.js
@@ -4,7 +4,7 @@
*
* Sphinx JavaScript utilities for all documentation.
*
- * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ * :copyright: Copyright 2007-2016, by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
diff --git a/distro/common/html/_static/searchtools.js b/distro/common/html/_static/searchtools.js
index fec94539f9..f2377af09b 100644
--- a/distro/common/html/_static/searchtools.js
+++ b/distro/common/html/_static/searchtools.js
@@ -4,7 +4,7 @@
*
* Sphinx JavaScript utilties for the full-text search.
*
- * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ * :copyright: Copyright 2007-2016, by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
diff --git a/distro/common/html/_static/websupport.js b/distro/common/html/_static/websupport.js
index 71c0a1364a..9186bee898 100644
--- a/distro/common/html/_static/websupport.js
+++ b/distro/common/html/_static/websupport.js
@@ -4,7 +4,7 @@
*
* sphinx.websupport utilties for all documentation.
*
- * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ * :copyright: Copyright 2007-2016, by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
diff --git a/distro/common/html/knife_bootstrap.html b/distro/common/html/knife_bootstrap.html
index 5e3d70404f..7589dfbaba 100644
--- a/distro/common/html/knife_bootstrap.html
+++ b/distro/common/html/knife_bootstrap.html
@@ -173,7 +173,7 @@
<div class="highlight-bash"><div class="highlight"><pre><span class="nv">$ </span>knife bootstrap 192.168.1.100 -r <span class="s1">&#39;role[webserver]&#39;</span> -d ubuntu12.04-gems-mine
</pre></div>
</div>
-<p>Alternatively, an example bootstrap template can be found in the git source for the chef-repo: <a class="reference external" href="https://github.com/opscode/chef/tree/master/lib/chef/knife/bootstrap">https://github.com/opscode/chef/tree/master/lib/chef/knife/bootstrap</a>. Copy the template to <tt class="docutils literal"><span class="pre">~/.chef-repo/.chef/bootstrap/ubuntu12.04-apt.erb</span></tt> and modify the template appropriately.</p>
+<p>Alternatively, an example bootstrap template can be found in the git source for the chef-repo: <a class="reference external" href="https://github.com/chef/chef/tree/master/lib/chef/knife/bootstrap">https://github.com/chef/chef/tree/master/lib/chef/knife/bootstrap</a>. Copy the template to <tt class="docutils literal"><span class="pre">~/.chef-repo/.chef/bootstrap/ubuntu12.04-apt.erb</span></tt> and modify the template appropriately.</p>
</div>
<div class="section" id="debian-and-apt">
<h3>Debian and Apt<a class="headerlink" href="#debian-and-apt" title="Permalink to this headline">¶</a></h3>
diff --git a/distro/common/html/knife_environment.html b/distro/common/html/knife_environment.html
index 75ef69f8a0..ee4810c133 100644
--- a/distro/common/html/knife_environment.html
+++ b/distro/common/html/knife_environment.html
@@ -200,11 +200,11 @@ windows 1.0.0 4.1.2
</div>
<div class="section" id="from-file">
<h2>from file<a class="headerlink" href="#from-file" title="Permalink to this headline">¶</a></h2>
-<p>The <tt class="docutils literal"><span class="pre">from</span> <span class="pre">file</span></tt> argument is used to add or update an environment using a JSON or Ruby DSL description. It must be run with the <tt class="docutils literal"><span class="pre">create</span></tt> or <tt class="docutils literal"><span class="pre">edit</span></tt> arguments.</p>
+<p>The <tt class="docutils literal"><span class="pre">from</span> <span class="pre">file</span></tt> argument is used to add or update an environment using a JSON or Ruby DSL description.</p>
<div class="section" id="id7">
<h3>Syntax<a class="headerlink" href="#id7" title="Permalink to this headline">¶</a></h3>
<p>This argument has the following syntax:</p>
-<div class="highlight-bash"><div class="highlight"><pre><span class="nv">$ </span>knife environment <span class="o">[</span>create | edit<span class="o">]</span> from file FILE <span class="o">(</span>options<span class="o">)</span>
+<div class="highlight-bash"><div class="highlight"><pre><span class="nv">$ </span>knife environment from file FILE <span class="o">(</span>options<span class="o">)</span>
</pre></div>
</div>
</div>
@@ -221,11 +221,7 @@ windows 1.0.0 4.1.2
<p>The following examples show how to use this knife subcommand:</p>
<p><strong>Create an environment from a JSON file</strong></p>
<p>To add an environment using data contained in a JSON file:</p>
-<div class="highlight-bash"><div class="highlight"><pre><span class="nv">$ </span>knife environment create devops from file <span class="s2">&quot;path to JSON file&quot;</span>
-</pre></div>
-</div>
-<p>or:</p>
-<div class="highlight-bash"><div class="highlight"><pre><span class="nv">$ </span>knife environment edit devops from file <span class="s2">&quot;path to JSON file&quot;</span>
+<div class="highlight-bash"><div class="highlight"><pre><span class="nv">$ </span>knife environment from file <span class="s2">&quot;path to JSON file&quot;</span>
</pre></div>
</div>
</div>
@@ -323,4 +319,4 @@ override_attributes:
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/distro/common/man/man1/README.md b/distro/common/man/man1/README.md
index 9a915fb4cc..7af6aa8948 100644
--- a/distro/common/man/man1/README.md
+++ b/distro/common/man/man1/README.md
@@ -9,7 +9,7 @@ that are built into the chef-client are managed.
## Source Files
The source files are located in the chef-docs repository:
-https://github.com/opscode/chef-docs
+https://github.com/chef/chef-docs
Each Knife subcommand has its own source folder. The folder naming
pattern begins with man_.
@@ -55,4 +55,4 @@ at docs.opscode.com/knife_foo.html.
## Questions?
-Open an [Issue](https://github.com/opscode/chef-docs/issues) and ask.
+Open an [Issue](https://github.com/chef/chef-docs/issues) and ask.
diff --git a/distro/common/man/man1/knife-client.1 b/distro/common/man/man1/knife-client.1
index 9dbd174c71..24bd999d65 100644
--- a/distro/common/man/man1/knife-client.1
+++ b/distro/common/man/man1/knife-client.1
@@ -37,7 +37,7 @@ However, during the first chef\-client run, this private key does not exist. Ins
.sp
During the initial chef\-client run, the chef\-client will register with the Chef server using the private key assigned to the chef\-validator, after which the chef\-client will obtain a \fBclient.pem\fP private key for all future authentication requests to the Chef server\&.
.sp
-After the initial chef\-client run has completed successfully, the chef\-validator is no longer required and may be deleted from the node. Use the \fBdelete_validation\fP recipe found in the \fBchef\-client\fP cookbook (\fI\%https://github.com/opscode\-cookbooks/chef\-client\fP) to remove the chef\-validator\&.
+After the initial chef\-client run has completed successfully, the chef\-validator is no longer required and may be deleted from the node. Use the \fBdelete_validation\fP recipe found in the \fBchef\-client\fP cookbook (\fI\%https://github.com/chef\-cookbooks/chef\-client\fP) to remove the chef\-validator\&.
.sp
The \fBknife client\fP subcommand is used to manage an API client list and their associated RSA public key\-pairs. This allows authentication requests to be made to the Chef server by any entity that uses the Chef server API, such as the chef\-client and knife\&.
.SH COMMON OPTIONS
diff --git a/distro/common/man/man1/knife-environment.1 b/distro/common/man/man1/knife-environment.1
index d583abe7fa..7b8542170f 100644
--- a/distro/common/man/man1/knife-environment.1
+++ b/distro/common/man/man1/knife-environment.1
@@ -339,7 +339,7 @@ $ knife environment edit devops
.UNINDENT
.SH FROM FILE
.sp
-The \fBfrom file\fP argument is used to add or update an environment using a JSON or Ruby DSL description. It must be run with the \fBcreate\fP or \fBedit\fP arguments.
+The \fBfrom file\fP argument is used to add or update an environment using a JSON or Ruby DSL description.
.sp
\fBSyntax\fP
.sp
@@ -349,7 +349,7 @@ This argument has the following syntax:
.sp
.nf
.ft C
-$ knife environment [create | edit] from file FILE (options)
+$ knife environment from file FILE (options)
.ft P
.fi
.UNINDENT
@@ -366,25 +366,13 @@ Use to upload all environments found at the specified path.
.sp
\fBExamples\fP
.sp
-To add an environment using data contained in a JSON file:
+To add or update an environment using data contained in a JSON file:
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
-$ knife environment create devops from file "path to JSON file"
-.ft P
-.fi
-.UNINDENT
-.UNINDENT
-.sp
-or:
-.INDENT 0.0
-.INDENT 3.5
-.sp
-.nf
-.ft C
-$ knife environment edit devops from file "path to JSON file"
+$ knife environment from file "path to JSON file"
.ft P
.fi
.UNINDENT
diff --git a/distro/common/markdown/man1/knife-configure.mkd b/distro/common/markdown/man1/knife-configure.mkd
index f3a4ef02bb..b441dc5d8b 100644
--- a/distro/common/markdown/man1/knife-configure.mkd
+++ b/distro/common/markdown/man1/knife-configure.mkd
@@ -33,10 +33,11 @@ the specified _directory_.
* On a freshly installed Chef Server, use _knife configure -i_ to
create an administrator and knife configuration file. Leave the
field blank to accept the default value. On most systems, the
- default values are acceptable.
+ default values are acceptable (except for the chef server URL,
+ there you must add your organization name)
user@host$ knife configure -i
- Please enter the chef server URL: [http://localhost:4000]
+ Please enter the chef server URL: [http://localhost/organizations/myorg]
Please enter a clientname for the new client: [username]
Please enter the existing admin clientname: [chef-webui]
Please enter the location of the existing admin client's private key: [/etc/chef/webui.pem]
diff --git a/distro/common/markdown/man8/chef-client.mkd b/distro/common/markdown/man8/chef-client.mkd
index ffe444ecf2..7506e3b925 100644
--- a/distro/common/markdown/man8/chef-client.mkd
+++ b/distro/common/markdown/man8/chef-client.mkd
@@ -40,6 +40,8 @@ __chef-client__ _(options)_
Set the PID file location, defaults to /tmp/chef-client.pid
* `--once`:
Cancel any interval or splay options, run chef once and exit
+ * `--skip-cookbook-sync`:
+ Skip cookbook synchronization
* `-v`, `--version`:
Show chef version
* `-h`, `--help`:
diff --git a/distro/powershell/chef/chef.psm1 b/distro/powershell/chef/chef.psm1
index 6646226795..9196d62e6c 100644
--- a/distro/powershell/chef/chef.psm1
+++ b/distro/powershell/chef/chef.psm1
@@ -109,6 +109,12 @@ public enum StandardHandle : int
Error = -12
}
+public enum HandleFlags : int
+{
+ HANDLE_FLAG_INHERIT = 0x00000001,
+ HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002
+}
+
public static class Kernel32
{
[DllImport("kernel32.dll", SetLastError=true)]
@@ -128,11 +134,12 @@ public static class Kernel32
[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr GetStdHandle(
StandardHandle nStdHandle);
-
- [DllImport("kernel32", SetLastError=true)]
- public static extern int WaitForSingleObject(
- IntPtr hHandle,
- int dwMilliseconds);
+
+ [DllImport("kernel32.dll")]
+ public static extern bool SetHandleInformation(
+ IntPtr hObject,
+ int dwMask,
+ uint dwFlags);
[DllImport("kernel32", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
@@ -144,6 +151,32 @@ public static class Kernel32
public static extern bool GetExitCodeProcess(
IntPtr hProcess,
out int lpExitCode);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern bool CreatePipe(
+ out IntPtr phReadPipe,
+ out IntPtr phWritePipe,
+ IntPtr lpPipeAttributes,
+ uint nSize);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern bool ReadFile(
+ IntPtr hFile,
+ [Out] byte[] lpBuffer,
+ uint nNumberOfBytesToRead,
+ ref int lpNumberOfBytesRead,
+ IntPtr lpOverlapped);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern bool PeekNamedPipe(
+ IntPtr handle,
+ byte[] buffer,
+ uint nBufferSize,
+ ref uint bytesRead,
+ ref uint bytesAvail,
+ ref uint BytesLeftThisMessage);
+
+ public const int STILL_ACTIVE = 259;
}
}
"@
@@ -156,13 +189,6 @@ function Run-ExecutableAndWait($AppPath, $ArgumentString) {
$si = New-Object Chef.STARTUPINFO
$pi = New-Object Chef.PROCESS_INFORMATION
- $si.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($si)
- $si.wShowWindow = [Chef.ShowWindow]::SW_SHOW
- $si.dwFlags = [Chef.STARTF]::STARTF_USESTDHANDLES
- $si.hStdError = [Chef.Kernel32]::GetStdHandle([Chef.StandardHandle]::Error)
- $si.hStdOutput = [Chef.Kernel32]::GetStdHandle([Chef.StandardHandle]::Output)
- $si.hStdInput = [Chef.Kernel32]::GetStdHandle([Chef.StandardHandle]::Input)
-
$pSec = New-Object Chef.SECURITY_ATTRIBUTES
$pSec.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($pSec)
$pSec.bInheritHandle = $true
@@ -170,25 +196,103 @@ function Run-ExecutableAndWait($AppPath, $ArgumentString) {
$tSec.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($tSec)
$tSec.bInheritHandle = $true
- $success = [Chef.Kernel32]::CreateProcess($AppPath, $ArgumentString, [ref] $pSec, [ref] $tSec, $true, [Chef.CreationFlags]::NONE, [IntPtr]::Zero, $pwd, [ref] $si, [ref] $pi)
+ # Create pipe for process stdout
+ $ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([System.Runtime.InteropServices.Marshal]::SizeOf($si))
+ [System.Runtime.InteropServices.Marshal]::StructureToPtr($pSec, $ptr, $true)
+ $hReadOut = [IntPtr]::Zero
+ $hWriteOut = [IntPtr]::Zero
+ $success = [Chef.Kernel32]::CreatePipe([ref] $hReadOut, [ref] $hWriteOut, $ptr, 0)
if (-Not $success) {
$reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- throw "Unable to create process [$ArgumentString]. Error code $reason."
+ throw "Unable to create output pipe. Error code $reason."
}
- $waitReason = [Chef.Kernel32]::WaitForSingleObject($pi.hProcess, -1)
- if ($waitReason -ne 0) {
- if ($waitReason -eq -1) {
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- throw "Could not wait for process to terminate. Error code $reason."
- } else {
- throw "WaitForSingleObject failed with return code $waitReason - it's impossible!"
- }
+ $success = [Chef.Kernel32]::SetHandleInformation($hReadOut, [Chef.HandleFlags]::HANDLE_FLAG_INHERIT, 0)
+ if (-Not $success) {
+ $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+ throw "Unable to set output pipe handle information. Error code $reason."
}
- $success = [Chef.Kernel32]::GetExitCodeProcess($pi.hProcess, [ref] $global:LASTEXITCODE)
+
+ $si.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($si)
+ $si.wShowWindow = [Chef.ShowWindow]::SW_SHOW
+ $si.dwFlags = [Chef.STARTF]::STARTF_USESTDHANDLES
+ $si.hStdOutput = $hWriteOut
+ $si.hStdError = $hWriteOut
+ $si.hStdInput = [Chef.Kernel32]::GetStdHandle([Chef.StandardHandle]::Input)
+
+ $success = [Chef.Kernel32]::CreateProcess(
+ $AppPath,
+ $ArgumentString,
+ [ref] $pSec,
+ [ref] $tSec,
+ $true,
+ [Chef.CreationFlags]::NONE,
+ [IntPtr]::Zero,
+ $pwd,
+ [ref] $si,
+ [ref] $pi
+ )
if (-Not $success) {
$reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- throw "Process exit code unavailable. Error code $reason."
+ throw "Unable to create process [$ArgumentString]. Error code $reason."
}
+
+ $sb = New-Object System.Text.StringBuilder
+ $buffer = New-Object byte[] 1024
+
+ # Initialize reference variables
+ $bytesRead = 0
+ $bytesAvailable = 0
+ $bytesLeftThisMsg = 0
+ $global:LASTEXITCODE = [Chef.Kernel32]::STILL_ACTIVE
+
+ $isActive = $true
+ while ($isActive) {
+ $success = [Chef.Kernel32]::GetExitCodeProcess($pi.hProcess, [ref] $global:LASTEXITCODE)
+ if (-Not $success) {
+ $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+ throw "Process exit code unavailable. Error code $reason."
+ }
+
+ $success = [Chef.Kernel32]::PeekNamedPipe(
+ $hReadOut,
+ $null,
+ $buffer.Length,
+ [ref] $bytesRead,
+ [ref] $bytesAvailable,
+ [ref] $bytesLeftThisMsg
+ )
+ if (-Not $success) {
+ $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+ throw "Output pipe unavailable for peeking. Error code $reason."
+ }
+
+ if ($bytesRead -gt 0) {
+ while ([Chef.Kernel32]::ReadFile($hReadOut, $buffer, $buffer.Length, [ref] $bytesRead, 0)) {
+ $output = [Text.Encoding]::UTF8.GetString($buffer, 0, $bytesRead)
+ if ($output) {
+ [void]$sb.Append($output)
+ }
+ if ($bytesRead -lt $buffer.Length) {
+ # Partial buffer indicating the end of stream, break out of ReadFile loop
+ # ReadFile will block until:
+ # The number of bytes requested is read.
+ # A write operation completes on the write end of the pipe.
+ # An asynchronous handle is being used and the read is occurring asynchronously.
+ # An error occurs.
+ break
+ }
+ }
+ }
+
+ if ($global:LASTEXITCODE -ne [Chef.Kernel32]::STILL_ACTIVE) {
+ $isActive = $false
+ }
+ }
+
+ # Return output obtained from child process stdout/stderr
+ $sb.ToString()
+
+ # Cleanup handles
$success = [Chef.Kernel32]::CloseHandle($pi.hProcess)
if (-Not $success) {
$reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
@@ -199,6 +303,17 @@ function Run-ExecutableAndWait($AppPath, $ArgumentString) {
$reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
throw "Unable to release thread handle. Error code $reason."
}
+ $success = [Chef.Kernel32]::CloseHandle($hWriteOut)
+ if (-Not $success) {
+ $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+ throw "Unable to release output write handle. Error code $reason."
+ }
+ $success = [Chef.Kernel32]::CloseHandle($hReadOut)
+ if (-Not $success) {
+ $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+ throw "Unable to release output read handle. Error code $reason."
+ }
+ [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr)
}
function Get-ScriptDirectory {
diff --git a/ext/win32-eventlog/Rakefile b/ext/win32-eventlog/Rakefile
index 63fae1e73b..5b1186cf13 100644
--- a/ext/win32-eventlog/Rakefile
+++ b/ext/win32-eventlog/Rakefile
@@ -1,6 +1,6 @@
-require 'rubygems'
-require 'rake'
-require 'mkmf'
+require "rubygems"
+require "rake"
+require "mkmf"
desc "Building event log dll"
@@ -12,21 +12,20 @@ def ensure_present(commands)
end
end
-
-EVT_MC_FILE = 'chef-log.man'
-EVT_RC_FILE = 'chef-log.rc'
-EVT_RESOURCE_OBJECT = 'resource.o'
-EVT_SHARED_OBJECT = 'chef-log.dll'
-MC = 'windmc'
-RC = 'windres'
-CC = 'gcc'
+EVT_MC_FILE = "chef-log.man"
+EVT_RC_FILE = "chef-log.rc"
+EVT_RESOURCE_OBJECT = "resource.o"
+EVT_SHARED_OBJECT = "chef-log.dll"
+MC = "windmc"
+RC = "windres"
+CC = "gcc"
ensure_present [MC, RC, CC]
task :build => [EVT_RESOURCE_OBJECT, EVT_SHARED_OBJECT]
task :default => [:build, :register]
-file EVT_RC_FILE=> EVT_MC_FILE do
+file EVT_RC_FILE => EVT_MC_FILE do
sh "#{MC} #{EVT_MC_FILE}"
end
@@ -39,7 +38,7 @@ file EVT_SHARED_OBJECT => EVT_RESOURCE_OBJECT do
end
task :register => EVT_SHARED_OBJECT do
- require 'win32/eventlog'
+ require "win32/eventlog"
dll_file = File.expand_path(EVT_SHARED_OBJECT)
begin
Win32::EventLog.add_event_source(
diff --git a/habitat/default.toml b/habitat/default.toml
new file mode 100644
index 0000000000..04385fc371
--- /dev/null
+++ b/habitat/default.toml
@@ -0,0 +1,11 @@
+# The Chef run interval in seconds
+interval = 10
+
+# The splay
+splay = 10
+
+# The default log level
+log_level = "info"
+
+# The default run list
+run_list = ""
diff --git a/habitat/hooks/run b/habitat/hooks/run
new file mode 100644
index 0000000000..0f3844dd5f
--- /dev/null
+++ b/habitat/hooks/run
@@ -0,0 +1,8 @@
+#!/bin/sh
+export GEM_HOME="{{pkg.path}}/ruby/2.3.0"
+export GEM_PATH="$(hab pkg path core/ruby)/lib/ruby/gems/2.3.0:$(hab pkg path core/bundler):$GEM_HOME"
+export APPBUNDLER_ALLOW_RVM=true
+
+exec 2>&1
+exec chef-solo --fork -i {{cfg.interval}} -s {{cfg.splay}} -l {{cfg.log_level}} -o {{cfg.run_list}}
+
diff --git a/habitat/plan.sh b/habitat/plan.sh
new file mode 100644
index 0000000000..7a797842e2
--- /dev/null
+++ b/habitat/plan.sh
@@ -0,0 +1,100 @@
+pkg_name=chef-client
+pkg_origin=chef
+pkg_maintainer="The Chef Maintainers <humans@chef.io>"
+pkg_description="The Chef Client"
+pkg_version=$(cat ../VERSION)
+pkg_source=nosuchfile.tar.gz
+pkg_filename=${pkg_dirname}.tar.gz
+pkg_license=('Apache-2.0')
+pkg_bin_dirs=(bin)
+pkg_build_deps=(core/make core/gcc core/coreutils core/git)
+pkg_deps=(core/glibc core/ruby core/libxml2 core/libxslt core/libiconv core/xz core/zlib core/bundler core/openssl core/cacerts core/libffi)
+pkg_svc_user=root
+
+do_download() {
+ build_line "Fake download! Creating archive of latest repository commit."
+ # source is in this repo, so we're going to create an archive from the
+ # appropriate path within the repo and place the generated tarball in the
+ # location expected by do_unpack
+ cd $PLAN_CONTEXT/../
+ git archive --prefix=${pkg_name}-${pkg_version}/ --output=$HAB_CACHE_SRC_PATH/${pkg_filename} HEAD
+}
+
+do_verify() {
+ build_line "Skipping checksum verification on the archive we just created."
+ return 0
+}
+
+do_prepare() {
+ export OPENSSL_LIB_DIR=$(pkg_path_for openssl)/lib
+ export OPENSSL_INCLUDE_DIR=$(pkg_path_for openssl)/include
+ export SSL_CERT_FILE=$(pkg_path_for cacerts)/ssl/cert.pem
+
+ build_line "Setting link for /usr/bin/env to 'coreutils'"
+ [[ ! -f /usr/bin/env ]] && ln -s $(pkg_path_for coreutils)/bin/env /usr/bin/env
+
+ return 0
+}
+
+do_build() {
+ export CPPFLAGS="${CPPFLAGS} ${CFLAGS}"
+
+ local _bundler_dir=$(pkg_path_for bundler)
+ local _libxml2_dir=$(pkg_path_for libxml2)
+ local _libxslt_dir=$(pkg_path_for libxslt)
+ local _zlib_dir=$(pkg_path_for zlib)
+
+ export GEM_HOME=${pkg_prefix}
+ export GEM_PATH=${_bundler_dir}:${GEM_HOME}
+
+ export NOKOGIRI_CONFIG="--use-system-libraries --with-zlib-dir=${_zlib_dir} --with-xslt-dir=${_libxslt_dir} --with-xml2-include=${_libxml2_dir}/include/libxml2 --with-xml2-lib=${_libxml2_dir}/lib"
+ bundle config --local build.nokogiri '${NOKOGIRI_CONFIG}'
+
+ bundle config --local silence_root_warning 1
+
+ # We need to add tzinfo-data to the Gemfile since we're not in an
+ # environment that has this from the OS
+ if [[ -z "`grep 'gem .*tzinfo-data.*' Gemfile`" ]]; then
+ echo 'gem "tzinfo-data"' >> Gemfile
+ fi
+
+ bundle install --no-deployment --jobs 2 --retry 5 --path $pkg_prefix
+
+ bundle exec 'cd ./chef-config && rake package'
+ bundle exec 'rake package'
+ mkdir -p gems-suck/gems
+ cp pkg/chef-$pkg_version.gem gems-suck/gems
+ cp chef-config/pkg/chef-config-$pkg_version.gem gems-suck/gems
+ bundle exec gem generate_index -d gems-suck
+
+ sed -e "s#gem \"chef\".*#gem \"chef\", source: \"file://$HAB_CACHE_SRC_PATH/$pkg_dirname/gems-suck\"#" -i Gemfile
+ sed -e "s#gem \"chef-config\".*#gem \"chef-config\", source: \"file://$HAB_CACHE_SRC_PATH/$pkg_dirname/gems-suck\"#" -i Gemfile
+ #bundle config --local local.chef $HAB_CACHE_SRC_PATH/$pkg_dirname/gems-suck
+ #bundle config --local local.chef-config $HAB_CACHE_SRC_PATH/$pkg_dirname/gems-suck
+
+ bundle install --no-deployment --jobs 2 --retry 5 --path $pkg_prefix
+
+}
+
+do_install() {
+
+ mkdir -p $pkg_prefix/bin
+
+ bundle exec appbundler $HAB_CACHE_SRC_PATH/$pkg_dirname $pkg_prefix/bin chef
+ bundle exec appbundler $HAB_CACHE_SRC_PATH/$pkg_dirname $pkg_prefix/bin ohai
+
+ for binstub in ${pkg_prefix}/bin/*; do
+ build_line "Setting shebang for ${binstub} to 'ruby'"
+ [[ -f $binstub ]] && sed -e "s#/usr/bin/env ruby#$(pkg_path_for ruby)/bin/ruby#" -i $binstub
+ done
+
+ if [[ `readlink /usr/bin/env` = "$(pkg_path_for coreutils)/bin/env" ]]; then
+ build_line "Removing the symlink we created for '/usr/bin/env'"
+ rm /usr/bin/env
+ fi
+}
+
+# Stubs
+do_strip() {
+ return 0
+}
diff --git a/kitchen-tests/.kitchen.travis.yml b/kitchen-tests/.kitchen.travis.yml
index 2c3de60108..aae5202457 100644
--- a/kitchen-tests/.kitchen.travis.yml
+++ b/kitchen-tests/.kitchen.travis.yml
@@ -1,16 +1,16 @@
---
driver:
- name: ec2
- aws_access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
- aws_secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
- aws_ssh_key_id: <%= ENV['AWS_KEYPAIR_NAME'] %>
- region: "us-west-2"
- availability_zone: "us-west-2a"
- security_group_ids: ["travis-ci"]
- instance_type: "m3.medium"
+ name: dokken
+ privileged: true
+ chef_image: chef/chef
+ chef_version: current
+
+transport:
+ name: dokken
provisioner:
name: chef_github
+ root_path: /opt/kitchen
github_owner: "chef"
github_repo: "chef"
refname: <%= ENV['TRAVIS_COMMIT'] %>
@@ -20,23 +20,115 @@ provisioner:
client_rb:
diff_disabled: true
-transport:
- ssh_key: <%= ENV['EC2_SSH_KEY_PATH'] %>
+verifier:
+ name: inspec
+ format: progress
platforms:
- - name: ubuntu-12.04
- driver:
- # http://cloud-images.ubuntu.com/locator/ec2/
- # 12.04 amd64 us-west-2 hvm:ssd
- image_id: ami-f3635fc3
- - name: rhel-6
- driver:
- # https://github.com/chef/releng-chef-repo/blob/master/script/ci#L93-L96
- image_id: ami-7df0bd4d
+- name: debian-7
+ driver:
+ image: debian:7
+ pid_one_command: /sbin/init
+ intermediate_instructions:
+ - RUN /usr/bin/apt-get update
+ - RUN /usr/bin/apt-get -y install zlib1g-dev sudo net-tools wget ca-certificates
+ - RUN /bin/mkdir /var/run/sshd
+
+- name: debian-8
+ driver:
+ image: debian:8
+ pid_one_command: /bin/systemd
+ intermediate_instructions:
+ - RUN /usr/bin/apt-get update
+ - RUN /usr/bin/apt-get -y install zlib1g-dev sudo net-tools wget ca-certificates
+
+- name: centos-5
+ driver:
+ image: centos:5
+ platform: rhel
+ run_command: /sbin/init
+ intermediate_instructions:
+ - RUN yum clean all
+ - RUN yum install -y which initscripts net-tools sudo wget
+ - RUN sed -i -e "s/Defaults.*requiretty.*/Defaults !requiretty/g" /etc/sudoers
+
+- name: centos-6
+ driver:
+ image: centos:6
+ run_command: /sbin/init
+ intermediate_instructions:
+ - RUN yum clean all
+ - RUN yum -y install which initscripts net-tools sudo wget
+ - RUN sed -i -e "s/Defaults.*requiretty.*/Defaults !requiretty/g" /etc/sudoers
+ attributes:
+ chef_client:
+ init_style: init
+
+- name: centos-7
+ driver:
+ image: centos:7
+ pid_one_command: /usr/lib/systemd/systemd
+ intermediate_instructions:
+ - RUN yum clean all
+ - RUN yum -y install which initscripts net-tools sudo wget
+ - RUN sed -i -e "s/Defaults.*requiretty.*/Defaults !requiretty/g" /etc/sudoers
+
+- name: fedora-latest
+ driver:
+ image: fedora:latest
+ pid_one_command: /usr/lib/systemd/systemd
+ intermediate_instructions:
+ - RUN dnf -y install yum which initscripts rpm-build zlib-devel net-tools sudo wget
+ - RUN yum makecache
+ - RUN sed -i -e "s/Defaults.*requiretty.*/Defaults !requiretty/g" /etc/sudoers
+
+- name: ubuntu-12.04
+ driver:
+ image: ubuntu-upstart:12.04
+ pid_one_command: /sbin/init
+ intermediate_instructions:
+ - RUN /usr/bin/apt-get update
+ - RUN /usr/bin/apt-get -y install zlib1g-dev sudo net-tools wget ca-certificates
+
+- name: ubuntu-14.04
+ driver:
+ image: ubuntu-upstart:14.04
+ pid_one_command: /sbin/init
+ intermediate_instructions:
+ - RUN /usr/bin/apt-get update
+ - RUN /usr/bin/apt-get -y install zlib1g-dev sudo net-tools wget ca-certificates
+
+- name: ubuntu-16.04
+ driver:
+ image: ubuntu:16.04
+ pid_one_command: /bin/systemd
+ intermediate_instructions:
+ - RUN /usr/bin/apt-get update
+ - RUN /usr/bin/apt-get -y install zlib1g-dev sudo net-tools wget ca-certificates
+
+- name: opensuse-13.2
+ driver:
+ image: opensuse:13.2
+ pid_one_command: /bin/systemd
+ intermediate_instructions:
+ - RUN zypper refresh
+
+- name: amazonlinux
+ driver:
+ image: amazonlinux:latest
+ pid_one_command: /sbin/init
+ intermediate_instructions:
+ - RUN yum clean all
+ - RUN yum -y install which initscripts net-tools sudo wget
+ - RUN sed -i -e "s/Defaults.*requiretty.*/Defaults !requiretty/g" /etc/sudoers
suites:
- name: webapp
run_list:
- - recipe[apt::default]
- - recipe[webapp::default]
- attributes:
+ - recipe[base::default]
+ - name: awesome_customers_ubuntu
+ run_list:
+ - recipe[awesome_customers_ubuntu_wrapper::default]
+ - name: awesome_customers_rhel
+ run_list:
+ - recipe[awesome_customers_rhel_wrapper::default]
diff --git a/kitchen-tests/.kitchen.yml b/kitchen-tests/.kitchen.yml
index c853f51b8d..d6df77932a 100644
--- a/kitchen-tests/.kitchen.yml
+++ b/kitchen-tests/.kitchen.yml
@@ -5,8 +5,14 @@ driver:
cpus: 4
memory: 2048
+verifier:
+ name: inspec
+ format: progress
+
provisioner:
name: chef_github
+ chef_omnibus_url: "https://omnitruck.chef.io/install.sh"
+ chef_omnibus_install_options: "-c current"
github_owner: "chef"
github_repo: "chef"
refname: <%= %x(git rev-parse HEAD) %>
@@ -15,24 +21,21 @@ provisioner:
diff_disabled: true
platforms:
- # upstream community mysql cookbook broken on 10.04
- #- name: ubuntu-10.04
- # run_list: apt::default
- name: ubuntu-12.04
- run_list: apt::default
- name: ubuntu-14.04
- run_list: apt::default
- # upstream community mysql cookbook also broken on 14.10
- #- name: ubuntu-14.10
- # run_list: apt::default
- - name: centos-6.4
- run_list: yum-epel::default
- - name: centos-5.10
- run_list: yum-epel::default
+ - name: ubuntu-16.04
+ - name: centos-7.2
+ - name: centos-6.7
+ # needs fixing for 5.11
+ # - name: centos-5.11
suites:
- name: webapp
run_list:
- - recipe[apt::default]
- - recipe[webapp::default]
- attributes:
+ - recipe[base::default]
+ - name: awesome_customers_ubuntu
+ run_list:
+ - recipe[awesome_customers_ubuntu_wrapper::default]
+ - name: awesome_customers_rhel
+ run_list:
+ - recipe[awesome_customers_rhel_wrapper::default]
diff --git a/kitchen-tests/Berksfile b/kitchen-tests/Berksfile
index 66569ed97f..5319e45a19 100644
--- a/kitchen-tests/Berksfile
+++ b/kitchen-tests/Berksfile
@@ -1,3 +1,13 @@
-source "https://supermarket.getchef.com"
+source "https://supermarket.chef.io"
-cookbook "webapp", :path => "cookbooks/webapp"
+#cookbook "webapp", path: "cookbooks/webapp"
+cookbook "base", path: "cookbooks/base"
+
+cookbook "php", "~> 1.5.0"
+
+cookbook "resolver", github: "chef-cookbooks/resolver"
+
+cookbook "awesome_customers_ubuntu_wrapper", path: "cookbooks/awesome_customers_ubuntu_wrapper"
+cookbook "awesome_customers_ubuntu", github: "learn-chef/awesome_customers_ubuntu"
+cookbook "awesome_customers_rhel_wrapper", path: "cookbooks/awesome_customers_rhel_wrapper"
+cookbook "awesome_customers_rhel", github: "learn-chef/awesome_customers_rhel"
diff --git a/kitchen-tests/Berksfile.lock b/kitchen-tests/Berksfile.lock
new file mode 100644
index 0000000000..6d8f40436a
--- /dev/null
+++ b/kitchen-tests/Berksfile.lock
@@ -0,0 +1,134 @@
+DEPENDENCIES
+ awesome_customers_rhel
+ git: https://github.com/learn-chef/awesome_customers_rhel.git
+ revision: b576fcf2988e2cdf156e7ba6ff59a94d556e16f1
+ awesome_customers_rhel_wrapper
+ path: cookbooks/awesome_customers_rhel_wrapper
+ awesome_customers_ubuntu
+ git: https://github.com/learn-chef/awesome_customers_ubuntu.git
+ revision: fea174c5855266f28218f76f00f6eff69e850244
+ awesome_customers_ubuntu_wrapper
+ path: cookbooks/awesome_customers_ubuntu_wrapper
+ base
+ path: cookbooks/base
+ php (~> 1.5.0)
+ resolver
+ git: https://github.com/chef-cookbooks/resolver.git
+ revision: 8bf9034dabc47d29a07870e4059c32114f2c820a
+
+GRAPH
+ apt (4.0.2)
+ compat_resource (>= 12.10)
+ awesome_customers_rhel (0.1.0)
+ database (~> 6.0)
+ firewall (~> 2.5)
+ httpd (~> 0.4)
+ mysql (~> 7.0)
+ mysql2_chef_gem (~> 1.1)
+ selinux (~> 0.9)
+ awesome_customers_rhel_wrapper (0.1.0)
+ awesome_customers_rhel (>= 0.0.0)
+ awesome_customers_ubuntu (0.1.0)
+ apt (~> 4.0)
+ database (~> 6.0)
+ firewall (~> 2.5)
+ httpd (~> 0.4)
+ mysql (~> 7.0)
+ mysql2_chef_gem (~> 1.1)
+ awesome_customers_ubuntu_wrapper (0.1.0)
+ awesome_customers_ubuntu (>= 0.0.0)
+ base (0.1.0)
+ apt (>= 0.0.0)
+ build-essential (>= 0.0.0)
+ chef-client (>= 0.0.0)
+ chef_hostname (>= 0.0.0)
+ logrotate (>= 0.0.0)
+ multipackage (>= 0.0.0)
+ nscd (>= 0.0.0)
+ ntp (>= 0.0.0)
+ openssh (>= 0.0.0)
+ resolver (>= 0.0.0)
+ selinux (>= 0.0.0)
+ sudo (>= 0.0.0)
+ ubuntu (>= 0.0.0)
+ users (>= 0.0.0)
+ build-essential (7.0.3)
+ compat_resource (>= 12.16.3)
+ mingw (>= 1.1)
+ seven_zip (>= 0.0.0)
+ chef-client (7.1.0)
+ cron (>= 1.7.0)
+ logrotate (>= 1.9.0)
+ windows (>= 1.42.0)
+ chef-sugar (3.4.0)
+ chef_hostname (0.4.2)
+ compat_resource (>= 0.0.0)
+ compat_resource (12.16.3)
+ cron (3.0.0)
+ database (6.1.1)
+ postgresql (>= 1.0.0)
+ firewall (2.5.3)
+ chef-sugar (>= 0.0.0)
+ httpd (0.4.4)
+ compat_resource (>= 12.14.6)
+ iis (5.0.5)
+ windows (>= 1.34.6)
+ iptables (3.1.0)
+ compat_resource (>= 12.14.3)
+ logrotate (2.1.0)
+ compat_resource (>= 0.0.0)
+ mariadb (1.0.1)
+ apt (>= 0.0.0)
+ yum (>= 0.0.0)
+ yum-epel (>= 0.0.0)
+ mingw (1.2.5)
+ compat_resource (>= 12.16.3)
+ seven_zip (>= 0.0.0)
+ multipackage (4.0.0)
+ compat_resource (>= 0.0.0)
+ mysql (7.2.0)
+ smf (>= 0.0.0)
+ yum-mysql-community (>= 0.0.0)
+ mysql2_chef_gem (1.1.0)
+ build-essential (>= 0.0.0)
+ mariadb (>= 0.0.0)
+ mysql (>= 6.0)
+ nscd (4.1.0)
+ compat_resource (>= 0.0.0)
+ ntp (3.3.1)
+ ohai (4.2.3)
+ compat_resource (>= 12.14.7)
+ openssh (2.1.1)
+ iptables (>= 1.0)
+ openssl (6.1.1)
+ php (1.5.0)
+ build-essential (>= 0.0.0)
+ iis (>= 0.0.0)
+ mysql (>= 0.0.0)
+ windows (>= 0.0.0)
+ xml (>= 0.0.0)
+ yum-epel (>= 0.0.0)
+ postgresql (6.0.1)
+ build-essential (>= 2.0.0)
+ compat_resource (>= 12.16.3)
+ openssl (>= 4.0)
+ rbac (1.0.3)
+ resolver (1.3.1)
+ selinux (0.9.0)
+ seven_zip (2.0.2)
+ windows (>= 1.2.2)
+ smf (2.2.8)
+ rbac (>= 1.0.1)
+ sudo (3.3.1)
+ ubuntu (2.0.0)
+ apt (>= 0.0.0)
+ users (4.0.3)
+ windows (2.1.1)
+ ohai (>= 4.0.0)
+ xml (3.1.1)
+ build-essential (>= 0.0.0)
+ yum (4.1.0)
+ yum-epel (2.1.1)
+ compat_resource (>= 12.16.3)
+ yum-mysql-community (2.0.3)
+ compat_resource (>= 12.16.3)
diff --git a/kitchen-tests/Gemfile b/kitchen-tests/Gemfile
index 5e1907ba1f..707a38a7f6 100644
--- a/kitchen-tests/Gemfile
+++ b/kitchen-tests/Gemfile
@@ -1,10 +1,12 @@
source "https://rubygems.org"
-group :end_to_end do
- gem 'berkshelf'
- gem 'test-kitchen', '~> 1.4.0'
- gem 'kitchen-appbundle-updater', '~> 0.0.1'
- gem "kitchen-vagrant", '~> 0.17.0'
- gem 'kitchen-ec2', github: 'test-kitchen/kitchen-ec2'
- gem 'vagrant-wrapper'
-end
+gem "rake" # required to build some native extensions
+gem "berkshelf"
+gem "kitchen-appbundle-updater"
+gem "kitchen-dokken", "< 2.0" # 2.x fails atm: https://travis-ci.org/chef/chef/jobs/199125787
+gem "kitchen-ec2"
+gem "kitchen-inspec"
+gem "kitchen-vagrant"
+gem "ridley"
+gem "test-kitchen"
+gem "vagrant-wrapper"
diff --git a/kitchen-tests/Gemfile.lock b/kitchen-tests/Gemfile.lock
new file mode 100644
index 0000000000..b9d14397f1
--- /dev/null
+++ b/kitchen-tests/Gemfile.lock
@@ -0,0 +1,259 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ addressable (2.5.0)
+ public_suffix (~> 2.0, >= 2.0.2)
+ artifactory (2.6.0)
+ aws-sdk (2.7.5)
+ aws-sdk-resources (= 2.7.5)
+ aws-sdk-core (2.7.5)
+ aws-sigv4 (~> 1.0)
+ jmespath (~> 1.0)
+ aws-sdk-resources (2.7.5)
+ aws-sdk-core (= 2.7.5)
+ aws-sigv4 (1.0.0)
+ berkshelf (5.6.2)
+ addressable (~> 2.3, >= 2.3.4)
+ berkshelf-api-client (>= 2.0.2, < 4.0)
+ buff-config (~> 2.0)
+ buff-extensions (~> 2.0)
+ buff-shell_out (~> 1.0)
+ cleanroom (~> 1.0)
+ faraday (~> 0.9)
+ httpclient (~> 2.7)
+ minitar (~> 0.5, >= 0.5.4)
+ mixlib-archive (~> 0.4)
+ octokit (~> 4.0)
+ retryable (~> 2.0)
+ ridley (~> 5.0)
+ solve (> 2.0, < 4.0)
+ thor (~> 0.19, < 0.19.2)
+ berkshelf-api-client (3.0.0)
+ faraday (~> 0.9)
+ httpclient (~> 2.7)
+ ridley (>= 4.5, < 6.0)
+ buff-config (2.0.0)
+ buff-extensions (~> 2.0)
+ varia_model (~> 0.6)
+ buff-extensions (2.0.0)
+ buff-ignore (1.2.0)
+ buff-ruby_engine (1.0.0)
+ buff-shell_out (1.1.0)
+ buff-ruby_engine (~> 1.0)
+ builder (3.2.3)
+ celluloid (0.16.0)
+ timers (~> 4.0.0)
+ celluloid-io (0.16.2)
+ celluloid (>= 0.16.0)
+ nio4r (>= 1.1.0)
+ chef-config (12.18.31)
+ addressable
+ fuzzyurl
+ mixlib-config (~> 2.0)
+ mixlib-shellout (~> 2.0)
+ cleanroom (1.0.0)
+ coderay (1.1.1)
+ diff-lcs (1.3)
+ docker-api (1.33.2)
+ excon (>= 0.38.0)
+ json
+ erubis (2.7.0)
+ excon (0.55.0)
+ faraday (0.9.2)
+ multipart-post (>= 1.2, < 3)
+ ffi (1.9.17)
+ ffi (1.9.17-x86-mingw32)
+ fuzzyurl (0.9.0)
+ gssapi (1.2.0)
+ ffi (>= 1.0.1)
+ gyoku (1.3.1)
+ builder (>= 2.1.2)
+ hashie (3.5.1)
+ hitimes (1.2.4)
+ hitimes (1.2.4-x86-mingw32)
+ httpclient (2.8.3)
+ inspec (1.14.1)
+ faraday (>= 0.9.0)
+ hashie (~> 3.4)
+ json (>= 1.8, < 3.0)
+ method_source (~> 0.8)
+ mixlib-log
+ parallel (~> 1.9)
+ pry (~> 0)
+ rainbow (~> 2)
+ rspec (~> 3)
+ rspec-its (~> 1.2)
+ rspec_junit_formatter (~> 0.2.3)
+ rubyzip (~> 1.1)
+ sslshake (~> 1)
+ thor (~> 0.19)
+ train (>= 0.22.0, < 1.0)
+ jmespath (1.3.1)
+ json (2.0.3)
+ kitchen-appbundle-updater (0.1.2)
+ kitchen-dokken (1.1.0)
+ docker-api (~> 1.33)
+ test-kitchen (~> 1.13)
+ kitchen-ec2 (1.2.0)
+ aws-sdk (~> 2)
+ excon
+ multi_json
+ retryable (~> 2.0)
+ test-kitchen (~> 1.4, >= 1.4.1)
+ kitchen-inspec (0.17.0)
+ hashie (~> 3.4)
+ inspec (>= 0.34.0, < 2.0.0)
+ test-kitchen (~> 1.6)
+ kitchen-vagrant (1.0.0)
+ test-kitchen (~> 1.4)
+ little-plugger (1.1.4)
+ logging (2.1.0)
+ little-plugger (~> 1.1)
+ multi_json (~> 1.10)
+ method_source (0.8.2)
+ minitar (0.6.1)
+ mixlib-archive (0.4.1)
+ mixlib-log
+ mixlib-authentication (1.4.1)
+ mixlib-log
+ mixlib-config (2.2.4)
+ mixlib-install (2.1.12)
+ artifactory
+ mixlib-shellout
+ mixlib-versioning
+ thor
+ mixlib-log (1.7.1)
+ mixlib-shellout (2.2.7)
+ mixlib-shellout (2.2.7-universal-mingw32)
+ win32-process (~> 0.8.2)
+ wmi-lite (~> 1.0)
+ mixlib-versioning (1.1.0)
+ molinillo (0.5.6)
+ multi_json (1.12.1)
+ multipart-post (2.0.0)
+ net-scp (1.2.1)
+ net-ssh (>= 2.6.5)
+ net-ssh (4.0.1)
+ net-ssh-gateway (1.3.0)
+ net-ssh (>= 2.6.5)
+ nio4r (2.0.0)
+ nori (2.6.0)
+ octokit (4.6.2)
+ sawyer (~> 0.8.0, >= 0.5.3)
+ parallel (1.10.0)
+ pry (0.10.4)
+ coderay (~> 1.1.0)
+ method_source (~> 0.8.1)
+ slop (~> 3.4)
+ public_suffix (2.0.5)
+ rainbow (2.2.1)
+ rake (12.0.0)
+ retryable (2.0.4)
+ ridley (5.1.0)
+ addressable
+ buff-config (~> 2.0)
+ buff-extensions (~> 2.0)
+ buff-ignore (~> 1.2)
+ buff-shell_out (~> 1.0)
+ celluloid (~> 0.16.0)
+ celluloid-io (~> 0.16.1)
+ chef-config (>= 12.5.0)
+ erubis
+ faraday (~> 0.9.0)
+ hashie (>= 2.0.2, < 4.0.0)
+ httpclient (~> 2.7)
+ json (>= 1.7.7)
+ mixlib-authentication (>= 1.3.0)
+ retryable (~> 2.0)
+ semverse (~> 2.0)
+ varia_model (~> 0.6)
+ rspec (3.5.0)
+ rspec-core (~> 3.5.0)
+ rspec-expectations (~> 3.5.0)
+ rspec-mocks (~> 3.5.0)
+ rspec-core (3.5.4)
+ rspec-support (~> 3.5.0)
+ rspec-expectations (3.5.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.5.0)
+ rspec-its (1.2.0)
+ rspec-core (>= 3.0.0)
+ rspec-expectations (>= 3.0.0)
+ rspec-mocks (3.5.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.5.0)
+ rspec-support (3.5.0)
+ rspec_junit_formatter (0.2.3)
+ builder (< 4)
+ rspec-core (>= 2, < 4, != 2.12.0)
+ rubyntlm (0.6.1)
+ rubyzip (1.2.1)
+ safe_yaml (1.0.4)
+ sawyer (0.8.1)
+ addressable (>= 2.3.5, < 2.6)
+ faraday (~> 0.8, < 1.0)
+ semverse (2.0.0)
+ slop (3.6.0)
+ solve (3.1.0)
+ molinillo (>= 0.5)
+ semverse (>= 1.1, < 3.0)
+ sslshake (1.0.13)
+ test-kitchen (1.15.0)
+ mixlib-install (>= 1.2, < 3.0)
+ mixlib-shellout (>= 1.2, < 3.0)
+ net-scp (~> 1.1)
+ net-ssh (>= 2.9, < 5.0)
+ net-ssh-gateway (~> 1.2)
+ safe_yaml (~> 1.0)
+ thor (~> 0.18)
+ thor (0.19.1)
+ timers (4.0.4)
+ hitimes
+ train (0.22.1)
+ docker-api (~> 1.26)
+ json (>= 1.8, < 3.0)
+ mixlib-shellout (~> 2.0)
+ net-scp (~> 1.2)
+ net-ssh (>= 2.9, < 5.0)
+ winrm (~> 2.0)
+ winrm-fs (~> 1.0)
+ vagrant-wrapper (2.0.3)
+ varia_model (0.6.0)
+ buff-extensions (~> 2.0)
+ hashie (>= 2.0.2, < 4.0.0)
+ win32-process (0.8.3)
+ ffi (>= 1.0.0)
+ winrm (2.1.2)
+ builder (>= 2.1.2)
+ erubis (~> 2.7)
+ gssapi (~> 1.2)
+ gyoku (~> 1.0)
+ httpclient (~> 2.2, >= 2.2.0.2)
+ logging (>= 1.6.1, < 3.0)
+ nori (~> 2.0)
+ rubyntlm (~> 0.6.0, >= 0.6.1)
+ winrm-fs (1.0.1)
+ erubis (~> 2.7)
+ logging (>= 1.6.1, < 3.0)
+ rubyzip (~> 1.1)
+ winrm (~> 2.0)
+ wmi-lite (1.0.0)
+
+PLATFORMS
+ ruby
+ x86-mingw32
+
+DEPENDENCIES
+ berkshelf
+ kitchen-appbundle-updater
+ kitchen-dokken (< 2.0)
+ kitchen-ec2
+ kitchen-inspec
+ kitchen-vagrant
+ rake
+ ridley
+ test-kitchen
+ vagrant-wrapper
+
+BUNDLED WITH
+ 1.12.5
diff --git a/kitchen-tests/cookbooks/audit_test/.gitignore b/kitchen-tests/cookbooks/audit_test/.gitignore
index ec2a890bd3..1e074046f0 100644
--- a/kitchen-tests/cookbooks/audit_test/.gitignore
+++ b/kitchen-tests/cookbooks/audit_test/.gitignore
@@ -1,5 +1,4 @@
.vagrant
-Berksfile.lock
*~
*#
.#*
diff --git a/kitchen-tests/cookbooks/audit_test/Berksfile b/kitchen-tests/cookbooks/audit_test/Berksfile
index 0ac9b78cf7..967b9a78b6 100644
--- a/kitchen-tests/cookbooks/audit_test/Berksfile
+++ b/kitchen-tests/cookbooks/audit_test/Berksfile
@@ -1,3 +1,3 @@
-source "https://supermarket.getchef.com"
+source "https://supermarket.chef.io"
metadata
diff --git a/kitchen-tests/cookbooks/audit_test/Berksfile.lock b/kitchen-tests/cookbooks/audit_test/Berksfile.lock
new file mode 100644
index 0000000000..ef9f28a3be
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/Berksfile.lock
@@ -0,0 +1,7 @@
+DEPENDENCIES
+ audit_test
+ path: .
+ metadata: true
+
+GRAPH
+ audit_test (0.1.0)
diff --git a/kitchen-tests/cookbooks/audit_test/metadata.rb b/kitchen-tests/cookbooks/audit_test/metadata.rb
index 4a60104e92..3fbda5dbe1 100644
--- a/kitchen-tests/cookbooks/audit_test/metadata.rb
+++ b/kitchen-tests/cookbooks/audit_test/metadata.rb
@@ -1,8 +1,7 @@
-name 'audit_test'
-maintainer 'The Authors'
-maintainer_email 'you@example.com'
-license 'all_rights'
-description 'Installs/Configures audit_test'
-long_description 'Installs/Configures audit_test'
-version '0.1.0'
-
+name "audit_test"
+maintainer "The Authors"
+maintainer_email "you@example.com"
+license "all_rights"
+description "Installs/Configures audit_test"
+long_description "Installs/Configures audit_test"
+version "0.1.0"
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/default.rb b/kitchen-tests/cookbooks/audit_test/recipes/default.rb
index 833c12064a..886c2cd0ac 100644
--- a/kitchen-tests/cookbooks/audit_test/recipes/default.rb
+++ b/kitchen-tests/cookbooks/audit_test/recipes/default.rb
@@ -2,7 +2,7 @@
# Cookbook Name:: audit_test
# Recipe:: default
#
-# Copyright (c) 2014 The Authors, All Rights Reserved.
+# Copyright 2014-2016, The Authors, All Rights Reserved.
control_group "basic control group" do
control "basic math" do
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/error_duplicate_control_groups.rb b/kitchen-tests/cookbooks/audit_test/recipes/error_duplicate_control_groups.rb
index 82b358d4be..2b5b8b5d22 100644
--- a/kitchen-tests/cookbooks/audit_test/recipes/error_duplicate_control_groups.rb
+++ b/kitchen-tests/cookbooks/audit_test/recipes/error_duplicate_control_groups.rb
@@ -2,7 +2,7 @@
# Cookbook Name:: audit_test
# Recipe:: error_duplicate_control_groups
#
-# Copyright (c) 2014 The Authors, All Rights Reserved.
+# Copyright 2014-2016, The Authors, All Rights Reserved.
control_group "basic control group" do
it "should pass" do
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/error_no_block.rb b/kitchen-tests/cookbooks/audit_test/recipes/error_no_block.rb
index 42da81aa4f..e4c444e8bc 100644
--- a/kitchen-tests/cookbooks/audit_test/recipes/error_no_block.rb
+++ b/kitchen-tests/cookbooks/audit_test/recipes/error_no_block.rb
@@ -2,6 +2,6 @@
# Cookbook Name:: audit_test
# Recipe:: error_no_block
#
-# Copyright (c) 2014 The Authors, All Rights Reserved.
+# Copyright 2014-2016, The Authors, All Rights Reserved.
control_group "empty control group without block"
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/error_orphan_control.rb b/kitchen-tests/cookbooks/audit_test/recipes/error_orphan_control.rb
index 4f2a8e6c55..61d809a7c0 100644
--- a/kitchen-tests/cookbooks/audit_test/recipes/error_orphan_control.rb
+++ b/kitchen-tests/cookbooks/audit_test/recipes/error_orphan_control.rb
@@ -2,7 +2,7 @@
# Cookbook Name:: audit_test
# Recipe:: error_orphan_control
#
-# Copyright (c) 2014 The Authors, All Rights Reserved.
+# Copyright 2014-2016, The Authors, All Rights Reserved.
control_group "basic control group" do
it "should pass" do
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/failed_specs.rb b/kitchen-tests/cookbooks/audit_test/recipes/failed_specs.rb
index c5c2c32f0a..9e6adfe2e9 100644
--- a/kitchen-tests/cookbooks/audit_test/recipes/failed_specs.rb
+++ b/kitchen-tests/cookbooks/audit_test/recipes/failed_specs.rb
@@ -2,7 +2,7 @@
# Cookbook Name:: audit_test
# Recipe:: failed_specs
#
-# Copyright (c) 2014 The Authors, All Rights Reserved.
+# Copyright 2014-2016, The Authors, All Rights Reserved.
control_group "basic control group" do
control "basic math" do
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/serverspec_collision.rb b/kitchen-tests/cookbooks/audit_test/recipes/serverspec_collision.rb
index c433bd1a90..36dd714cef 100644
--- a/kitchen-tests/cookbooks/audit_test/recipes/serverspec_collision.rb
+++ b/kitchen-tests/cookbooks/audit_test/recipes/serverspec_collision.rb
@@ -2,7 +2,7 @@
# Cookbook Name:: audit_test
# Recipe:: serverspec_collision
#
-# Copyright (c) 2014 The Authors, All Rights Reserved.
+# Copyright 2014-2016, The Authors, All Rights Reserved.
file "/tmp/audit_test_file" do
action :create
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/serverspec_support.rb b/kitchen-tests/cookbooks/audit_test/recipes/serverspec_support.rb
index 8b3c35a6bd..fc44fb334e 100644
--- a/kitchen-tests/cookbooks/audit_test/recipes/serverspec_support.rb
+++ b/kitchen-tests/cookbooks/audit_test/recipes/serverspec_support.rb
@@ -2,7 +2,7 @@
# Cookbook Name:: audit_test
# Recipe:: serverspec_support
#
-# Copyright (c) 2014 The Authors, All Rights Reserved.
+# Copyright 2014-2016, The Authors, All Rights Reserved.
file "/tmp/audit_test_file" do
action :create
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/with_include_recipe.rb b/kitchen-tests/cookbooks/audit_test/recipes/with_include_recipe.rb
index f795f7786a..7727c573c7 100644
--- a/kitchen-tests/cookbooks/audit_test/recipes/with_include_recipe.rb
+++ b/kitchen-tests/cookbooks/audit_test/recipes/with_include_recipe.rb
@@ -2,7 +2,7 @@
# Cookbook Name:: audit_test
# Recipe:: with_include_recipe
#
-# Copyright (c) 2014 The Authors, All Rights Reserved.
+# Copyright 2014-2016, The Authors, All Rights Reserved.
include_recipe "audit_test::serverspec_collision"
diff --git a/kitchen-tests/cookbooks/awesome_customers_rhel_wrapper/metadata.rb b/kitchen-tests/cookbooks/awesome_customers_rhel_wrapper/metadata.rb
new file mode 100644
index 0000000000..641f2f91e3
--- /dev/null
+++ b/kitchen-tests/cookbooks/awesome_customers_rhel_wrapper/metadata.rb
@@ -0,0 +1,9 @@
+name "awesome_customers_rhel_wrapper"
+maintainer "The Authors"
+maintainer_email "you@example.com"
+license "all_rights"
+description "Installs/Configures awesome_customers_rhel"
+long_description "Installs/Configures awesome_customers_rhel"
+version "0.1.0"
+
+depends "awesome_customers_rhel"
diff --git a/kitchen-tests/cookbooks/awesome_customers_rhel_wrapper/recipes/default.rb b/kitchen-tests/cookbooks/awesome_customers_rhel_wrapper/recipes/default.rb
new file mode 100644
index 0000000000..058ee61617
--- /dev/null
+++ b/kitchen-tests/cookbooks/awesome_customers_rhel_wrapper/recipes/default.rb
@@ -0,0 +1,6 @@
+#
+# Cookbook Name:: awesome_customers_rhel
+# Recipe:: default
+#
+# Copyright (c) 2016 The Authors, All Rights Reserved.
+include_recipe "awesome_customers_rhel::default"
diff --git a/kitchen-tests/cookbooks/awesome_customers_ubuntu_wrapper/metadata.rb b/kitchen-tests/cookbooks/awesome_customers_ubuntu_wrapper/metadata.rb
new file mode 100644
index 0000000000..429fce2f64
--- /dev/null
+++ b/kitchen-tests/cookbooks/awesome_customers_ubuntu_wrapper/metadata.rb
@@ -0,0 +1,9 @@
+name "awesome_customers_ubuntu_wrapper"
+maintainer "The Authors"
+maintainer_email "you@example.com"
+license "all_rights"
+description "Installs/Configures awesome_customers_ubuntu"
+long_description "Installs/Configures awesome_customers_ubuntu"
+version "0.1.0"
+
+depends "awesome_customers_ubuntu"
diff --git a/kitchen-tests/cookbooks/awesome_customers_ubuntu_wrapper/recipes/default.rb b/kitchen-tests/cookbooks/awesome_customers_ubuntu_wrapper/recipes/default.rb
new file mode 100644
index 0000000000..93012d295f
--- /dev/null
+++ b/kitchen-tests/cookbooks/awesome_customers_ubuntu_wrapper/recipes/default.rb
@@ -0,0 +1,6 @@
+#
+# Cookbook Name:: awesome_customers_ubuntu
+# Recipe:: default
+#
+# Copyright (c) 2016 The Authors, All Rights Reserved.
+include_recipe "awesome_customers_ubuntu::default"
diff --git a/kitchen-tests/cookbooks/base/Berksfile b/kitchen-tests/cookbooks/base/Berksfile
new file mode 100644
index 0000000000..ba11c46c1d
--- /dev/null
+++ b/kitchen-tests/cookbooks/base/Berksfile
@@ -0,0 +1,5 @@
+source "https://supermarket.chef.io"
+
+metadata
+
+cookbook "apt"
diff --git a/kitchen-tests/cookbooks/base/README.md b/kitchen-tests/cookbooks/base/README.md
new file mode 100644
index 0000000000..f19ab46735
--- /dev/null
+++ b/kitchen-tests/cookbooks/base/README.md
@@ -0,0 +1,3 @@
+# webapp
+
+TODO: Enter the cookbook description here.
diff --git a/kitchen-tests/cookbooks/base/attributes/default.rb b/kitchen-tests/cookbooks/base/attributes/default.rb
new file mode 100644
index 0000000000..75e57cb27b
--- /dev/null
+++ b/kitchen-tests/cookbooks/base/attributes/default.rb
@@ -0,0 +1,84 @@
+puts "CHEF SUGAR THINKS WE ARE ON UBUNTU" if ubuntu?
+puts "CHEF SUGAR THINKS WE ARE ON RHEL" if rhel?
+
+#
+# ubuntu cookbook overrides
+#
+
+default["ubuntu"]["include_source_packages"] = true
+default["ubuntu"]["components"] = "main restricted universe multiverse"
+
+#
+# openssh cookbook overrides
+#
+
+# turn off old protocols client-side
+default["openssh"]["client"]["host_based_authentication"] = "no"
+# allow typical ssh v2 rsa/dsa/ecdsa key auth client-side
+default["openssh"]["client"]["pubkey_authentication"] = "yes"
+# allow password auth client-side (we can ssh 'to' hosts that require passwords)
+default["openssh"]["client"]["password_authentication"] = "yes"
+# turn off kerberos client-side
+default["openssh"]["client"]["gssapi_authentication"] = "no"
+default["openssh"]["client"]["check_host_ip"] = "no"
+# everone turns strict host key checking off anyway
+default["openssh"]["client"]["strict_host_key_checking"] = "no"
+# force protocol 2
+default["openssh"]["client"]["protocol"] = "2"
+
+# it is mostly important that the aes*-ctr ciphers appear first in this list, the cbc ciphers are for compatibility
+default["openssh"]["server"]["ciphers"] = "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,blowfish-cbc,3des-cbc,cast128-cbc"
+# DNS causes long timeouts when connecting clients have busted DNS
+default["openssh"]["server"]["use_dns"] = "no"
+default["openssh"]["server"]["syslog_facility"] = "AUTH"
+# only allow access via ssh pubkeys, all other mechanisms including passwords are turned off for all users
+default["openssh"]["server"]["pubkey_authentication"] = "yes"
+default["openssh"]["server"]["password_authentication"] = "no"
+default["openssh"]["server"]["host_based_authentication"] = "no"
+default["openssh"]["server"]["gssapi_authentication"] = "no"
+default["openssh"]["server"]["permit_root_login"] = "without-password"
+default["openssh"]["server"]["ignore_rhosts"] = "yes"
+default["openssh"]["server"]["permit_empty_passwords"] = "no"
+default["openssh"]["server"]["challenge_response_authentication"] = "no"
+default["openssh"]["server"]["kerberos_authentication"] = "no"
+# tcp keepalives are useful to keep connections up through VPNs and firewalls
+default["openssh"]["server"]["tcp_keepalive"] = "yes"
+default["openssh"]["server"]["use_privilege_separation"] = "yes"
+default["openssh"]["server"]["max_start_ups"] = "10"
+# PAM (i think) already prints the motd on login
+default["openssh"]["server"]["print_motd"] = "no"
+# force only protocol 2 connections
+default["openssh"]["server"]["protocol"] = "2"
+# allow tunnelling x-applications back to the client
+default["openssh"]["server"]["x11_forwarding"] = "yes"
+
+#
+# chef-client cookbook overrides
+#
+
+# always wait at least 30 mins (1800 secs) between daemonized chef-client runs
+default["chef_client"]["interval"] = 1800
+# wait an additional random interval of up to 30 mins (1800 secs) between daemonized runs
+default["chef_client"]["splay"] = 1800
+# only log what we change
+default["chef_client"]["config"]["verbose_logging"] = false
+
+#
+# resolver cookbook overrides
+#
+
+default["resolver"]["nameservers"] = [ "8.8.8.8", "8.8.4.4" ]
+default["resolver"]["search"] = "chef.io"
+
+#
+# sudo cookbook overrides
+#
+
+default["authorization"]["sudo"]["passwordless"] = true
+default["authorization"]["sudo"]["users"] = %w{vagrant centos ubuntu}
+
+#
+# nscd cookbook overrides
+#
+
+default["nscd"]["server_user"] = "nobody"
diff --git a/kitchen-tests/cookbooks/base/libraries/chef-sugar.rb b/kitchen-tests/cookbooks/base/libraries/chef-sugar.rb
new file mode 100644
index 0000000000..90d02a361f
--- /dev/null
+++ b/kitchen-tests/cookbooks/base/libraries/chef-sugar.rb
@@ -0,0 +1,4 @@
+require "chef/sugar"
+
+# hack until this gets baked into chef-sugar so we can use chef-sugar in attributes files
+Chef::Node.send(:include, Chef::Sugar::DSL)
diff --git a/kitchen-tests/cookbooks/base/metadata.rb b/kitchen-tests/cookbooks/base/metadata.rb
new file mode 100644
index 0000000000..32ea03916f
--- /dev/null
+++ b/kitchen-tests/cookbooks/base/metadata.rb
@@ -0,0 +1,24 @@
+name "base"
+maintainer ""
+maintainer_email ""
+license ""
+description "Installs/Configures base"
+long_description "Installs/Configures base"
+version "0.1.0"
+
+gem "chef-sugar"
+
+depends "apt"
+depends "build-essential"
+depends "chef-client"
+depends "chef_hostname"
+depends "logrotate"
+depends "multipackage"
+depends "nscd"
+depends "ntp"
+depends "openssh"
+depends "resolver"
+depends "selinux"
+depends "sudo"
+depends "ubuntu"
+depends "users"
diff --git a/kitchen-tests/cookbooks/base/recipes/default.rb b/kitchen-tests/cookbooks/base/recipes/default.rb
new file mode 100644
index 0000000000..c25673bef5
--- /dev/null
+++ b/kitchen-tests/cookbooks/base/recipes/default.rb
@@ -0,0 +1,54 @@
+#
+# Cookbook Name:: webapp
+# Recipe:: default
+#
+# Copyright (C) 2014
+#
+
+hostname "chef-travis-ci.chef.io"
+
+if node["platform_family"] == "debian"
+ include_recipe "ubuntu"
+ apt_update "packages"
+end
+
+if %w{rhel fedora}.include?(node["platform_family"])
+ include_recipe "selinux::disabled"
+end
+
+yum_repository "epel" do
+ enabled true
+ description "Extra Packages for Enterprise Linux #{node['platform_version'].to_i} - $basearch"
+ failovermethod "priority"
+ gpgkey "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-#{node['platform_version'].to_i}"
+ gpgcheck true
+ mirrorlist "https://mirrors.fedoraproject.org/metalink?repo=epel-#{node['platform_version'].to_i}&arch=$basearch"
+ only_if { node["platform_family"] == "rhel" && node["platform"] != "amazon" }
+end
+
+include_recipe "build-essential"
+
+include_recipe "::packages"
+
+include_recipe "ntp"
+
+include_recipe "resolver"
+
+include_recipe "users::sysadmins"
+
+include_recipe "sudo"
+
+include_recipe "chef-client::delete_validation"
+include_recipe "chef-client::config"
+include_recipe "chef-client"
+
+# hack needed for debian-7 on docker
+directory "/var/run/sshd"
+
+include_recipe "openssh"
+
+include_recipe "nscd"
+
+include_recipe "logrotate"
+
+include_recipe "::tests"
diff --git a/kitchen-tests/cookbooks/base/recipes/packages.rb b/kitchen-tests/cookbooks/base/recipes/packages.rb
new file mode 100644
index 0000000000..c4457e5945
--- /dev/null
+++ b/kitchen-tests/cookbooks/base/recipes/packages.rb
@@ -0,0 +1,18 @@
+
+# this is just a list of package that exist on every O/S we test, and often aren't installed by default. you don't
+# have to get too clever here, you can delete packages if they don't exist everywhere we test.
+pkgs = %w{lsof tcpdump strace zsh dmidecode ltrace bc curl wget telnet subversion git traceroute htop tmux }
+
+# this deliberately calls the multipackage API N times in order to do one package installation in order to exercise the
+# multipackage cookbook.
+pkgs.each do |pkg|
+ multipackage pkgs
+end
+
+gems = %w{fpm aws-sdk}
+
+gems.each do |gem|
+ chef_gem gem do
+ compile_time false
+ end
+end
diff --git a/kitchen-tests/cookbooks/base/recipes/tests.rb b/kitchen-tests/cookbooks/base/recipes/tests.rb
new file mode 100644
index 0000000000..9d9d813865
--- /dev/null
+++ b/kitchen-tests/cookbooks/base/recipes/tests.rb
@@ -0,0 +1,21 @@
+#
+# Cookbook Name:: webapp
+# Recipe:: default
+#
+# Copyright (C) 2014
+#
+
+#
+# this file is for random tests to check specific chef-client internal functionality
+#
+
+file "/tmp/chef-test-ümlauts" do
+ content "testing UTF-8 char in the filename"
+end
+
+# this caught a regression in 12.14.70 before it was released when i
+# ran it in lamont-ci, so added the test here so everyone else other than
+# me gets coverage for this as well.
+file "/tmp/chef-test-\xFDmlaut" do
+ content "testing illegal UTF-8 char in the filename"
+end
diff --git a/kitchen-tests/cookbooks/webapp/Berksfile b/kitchen-tests/cookbooks/webapp/Berksfile
index 4b6079016e..ba11c46c1d 100644
--- a/kitchen-tests/cookbooks/webapp/Berksfile
+++ b/kitchen-tests/cookbooks/webapp/Berksfile
@@ -1,4 +1,4 @@
-source "https://api.berkshelf.com"
+source "https://supermarket.chef.io"
metadata
diff --git a/kitchen-tests/cookbooks/webapp/attributes/default.rb b/kitchen-tests/cookbooks/webapp/attributes/default.rb
index fb33efa49e..2ff7a6c5ff 100644
--- a/kitchen-tests/cookbooks/webapp/attributes/default.rb
+++ b/kitchen-tests/cookbooks/webapp/attributes/default.rb
@@ -1,14 +1,14 @@
-default['apache']['remote_host_ip'] = '127.0.0.1'
+default["apache"]["remote_host_ip"] = "127.0.0.1"
-default['webapp']['database'] = 'webapp'
-default['webapp']['db_username'] = 'webapp'
-default['webapp']['path'] = '/srv/webapp'
+default["webapp"]["database"] = "webapp"
+default["webapp"]["db_username"] = "webapp"
+default["webapp"]["path"] = "/srv/webapp"
# XXX: apache2 cookbook 2.0.0 has bugs around changing the mpm and then attempting a graceful restart
# which fails and leaves the service down.
-case node['platform']
+case node["platform"]
when "ubuntu"
- if node['platform_version'].to_f >= 14.04
- default[:apache][:mpm] = 'event'
+ if node["platform_version"].to_f >= 14.04
+ default[:apache][:mpm] = "event"
end
end
diff --git a/kitchen-tests/cookbooks/webapp/metadata.rb b/kitchen-tests/cookbooks/webapp/metadata.rb
index c26ad23979..5124aa4f6f 100644
--- a/kitchen-tests/cookbooks/webapp/metadata.rb
+++ b/kitchen-tests/cookbooks/webapp/metadata.rb
@@ -1,12 +1,12 @@
-name 'webapp'
-maintainer ''
-maintainer_email ''
-license ''
-description 'Installs/Configures webapp'
-long_description 'Installs/Configures webapp'
-version '0.1.0'
+name "webapp"
+maintainer ""
+maintainer_email ""
+license ""
+description "Installs/Configures webapp"
+long_description "Installs/Configures webapp"
+version "0.1.0"
-depends 'apache2'
-depends 'database', '~> 2.3.1'
-depends 'mysql'
-depends 'php'
+depends "apache2", "~> 3.2.2"
+depends "database", "~> 2.3.1"
+depends "mysql", "~> 5.6.3"
+depends "php", "~> 1.5.0"
diff --git a/kitchen-tests/cookbooks/webapp/recipes/default.rb b/kitchen-tests/cookbooks/webapp/recipes/default.rb
index 839b0ad8d8..2b3459b794 100644
--- a/kitchen-tests/cookbooks/webapp/recipes/default.rb
+++ b/kitchen-tests/cookbooks/webapp/recipes/default.rb
@@ -10,44 +10,44 @@ include_recipe "database::mysql"
include_recipe "php"
creds = Hash.new
-%w(mysql webapp).each do |item_name|
- creds[item_name] = data_bag_item('passwords', item_name)
+%w{mysql webapp}.each do |item_name|
+ creds[item_name] = data_bag_item("passwords", item_name)
end
web_app "webapp" do
- server_name 'localhost'
- server_aliases [node['fqdn'], node['hostname'], 'localhost.localdomain']
- docroot node['webapp']['path']
- cookbook 'apache2'
+ server_name "localhost"
+ server_aliases [node["fqdn"], node["hostname"], "localhost.localdomain"]
+ docroot node["webapp"]["path"]
+ cookbook "apache2"
end
mysql_service "default" do
- server_root_password creds['mysql']['server_root_password']
- server_repl_password creds['mysql']['server_repl_password']
+ server_root_password creds["mysql"]["server_root_password"]
+ server_repl_password creds["mysql"]["server_repl_password"]
end
-mysql_database node['webapp']['database'] do
+mysql_database node["webapp"]["database"] do
connection ({
- :host => 'localhost',
- :username => 'root',
- :password => creds['mysql']['server_root_password']
+ :host => "localhost",
+ :username => "root",
+ :password => creds["mysql"]["server_root_password"],
})
action :create
end
-mysql_database_user node['webapp']['db_username'] do
+mysql_database_user node["webapp"]["db_username"] do
connection ({
- :host => 'localhost',
- :username => 'root',
- :password => creds['mysql']['server_root_password']
+ :host => "localhost",
+ :username => "root",
+ :password => creds["mysql"]["server_root_password"],
})
- password creds['webapp']['db_password']
- database_name node['webapp']['database']
+ password creds["webapp"]["db_password"]
+ database_name node["webapp"]["database"]
privileges [:select, :update, :insert, :create, :delete]
action :grant
end
-directory node['webapp']['path'] do
+directory node["webapp"]["path"] do
owner "root"
group "root"
mode "0755"
@@ -56,9 +56,9 @@ directory node['webapp']['path'] do
end
template "#{node['webapp']['path']}/index.html" do
- source 'index.html.erb'
+ source "index.html.erb"
end
template "#{node['webapp']['path']}/index.php" do
- source 'index.php.erb'
+ source "index.php.erb"
end
diff --git a/kitchen-tests/data_bags/users/adam.json b/kitchen-tests/data_bags/users/adam.json
new file mode 100644
index 0000000000..f96d7c213f
--- /dev/null
+++ b/kitchen-tests/data_bags/users/adam.json
@@ -0,0 +1,9 @@
+{
+ "id": "adam",
+ "uid": 666, // yes? i figure adam likes metal, shout out to iron maiden...
+ "gid": 666,
+ "shell": "/bin/zsh",
+ "groups": [ "sysadmin" ],
+ "comment": "Adam Jacob",
+ "password": "*"
+}
diff --git a/kitchen-tests/test/fixtures/serverspec_helper.rb b/kitchen-tests/test/fixtures/serverspec_helper.rb
index ad1f866775..feb4c21200 100644
--- a/kitchen-tests/test/fixtures/serverspec_helper.rb
+++ b/kitchen-tests/test/fixtures/serverspec_helper.rb
@@ -2,24 +2,24 @@
# The commented-out platforms in the osmapping hash can be added once we have added them into
# our .kitchen.yml and .kitchen.travis.yml and added the appropriate JSON under test/fixtures/platforms.
-require 'serverspec'
-require 'json'
-require 'ffi_yajl'
+require "serverspec"
+require "json"
+require "ffi_yajl"
set :backend, :exec
include Specinfra::Helper::Properties
-require 'pp'
+require "pp"
pp os
def load_nodestub
case os[:family]
- when 'ubuntu', 'debian'
+ when "ubuntu", "debian"
platform = os[:family]
platform_version = os[:release]
- when 'redhat'
- platform = 'centos'
+ when "redhat"
+ platform = "centos"
platform_version = os[:release].to_i
end
FFI_Yajl::Parser.parse(IO.read("#{ENV['BUSSER_ROOT']}/../kitchen/data/platforms/#{platform}/#{platform_version}.json"), :symbolize_names => true)
@@ -27,6 +27,6 @@ end
# centos-59 doesn't have /sbin in the default path,
# so we must ensure it's on serverspec's path
-set :path, '$PATH:/sbin'
+set :path, "$PATH:/sbin"
set_property load_nodestub
diff --git a/kitchen-tests/test/integration/webapp/default_spec.rb b/kitchen-tests/test/integration/webapp/default_spec.rb
new file mode 100644
index 0000000000..cf148218b7
--- /dev/null
+++ b/kitchen-tests/test/integration/webapp/default_spec.rb
@@ -0,0 +1,118 @@
+#describe port(80) do
+# it { should be_listening }
+# its('processes') {should include 'http'}
+#end
+#
+#describe command("curl http://localhost/index.html") do
+# its("stdout") { should match /Hello, World!/ }
+#end
+
+case os[:family]
+when "debian", "ubuntu"
+ ssh_package = "openssh-client"
+ ssh_service = "ssh"
+ ntp_service = "ntp"
+when "centos", "redhat", "fedora", "amazon"
+ ssh_package = "openssh-clients"
+ ssh_service = "sshd"
+ ntp_service = "ntpd"
+else
+ raise "i don't know the family #{os[:family]}"
+end
+
+describe package("nscd") do
+ it { should be_installed }
+end
+
+describe service("nscd") do
+ # broken?
+ # it { should be_enabled }
+ it { should be_installed }
+ it { should be_running }
+end
+
+describe package(ssh_package) do
+ it { should be_installed }
+end
+
+describe service(ssh_service) do
+ it { should be_enabled }
+ it { should be_installed }
+ it { should be_running }
+end
+
+describe sshd_config do
+ its("Protocol") { should cmp 2 }
+ its("GssapiAuthentication") { should cmp "no" }
+ its("UseDns") { should cmp "no" }
+end
+
+describe ssh_config do
+ its("StrictHostKeyChecking") { should cmp "no" }
+ its("GssapiAuthentication") { should cmp "no" }
+end
+
+describe package("ntp") do
+ it { should be_installed }
+end
+
+describe service(ntp_service) do
+ # broken?
+ # it { should be_enabled }
+ it { should be_installed }
+ it { should be_running }
+end
+
+describe service("chef-client") do
+ it { should be_enabled }
+ it { should be_installed }
+ it { should be_running }
+end
+
+describe file("/etc/resolv.conf") do
+ its("content") { should match /search\s+chef.io/ }
+ its("content") { should match /nameserver\s+8.8.8.8/ }
+ its("content") { should match /nameserver\s+8.8.4.4/ }
+end
+
+describe package("gcc") do
+ it { should be_installed }
+end
+
+describe package("flex") do
+ it { should be_installed }
+end
+
+describe package("bison") do
+ it { should be_installed }
+end
+
+describe package("autoconf") do
+ it { should be_installed }
+end
+
+%w{lsof tcpdump strace zsh dmidecode ltrace bc curl wget telnet subversion git traceroute htop tmux }.each do |pkg|
+ describe package pkg do
+ it { should be_installed }
+ end
+end
+
+describe etc_group.where(group_name: "sysadmin") do
+ its("users") { should include "adam" }
+ its("gids") { should eq [2300] }
+end
+
+describe passwd.users("adam") do
+ its("uids") { should eq ["666"] }
+end
+
+describe ntp_conf do
+ its("server") { should_not eq nil }
+end
+
+# busted inside of docker containers?
+describe port(22) do
+ it { should be_listening }
+ its("protocols") { should include "tcp" }
+ its("processes") { should eq ["sshd"] }
+end
diff --git a/kitchen-tests/test/integration/webapp/serverspec/Gemfile b/kitchen-tests/test/integration/webapp/serverspec/Gemfile
deleted file mode 100644
index 0cb00ce354..0000000000
--- a/kitchen-tests/test/integration/webapp/serverspec/Gemfile
+++ /dev/null
@@ -1,4 +0,0 @@
-# This Gemfile is only needed so that busser will install gems it needs for serverspec_helper.rb to work
-source "https://rubygems.org"
-
-gem 'ffi-yajl', '~> 1.1' # Go away, JSON gem
diff --git a/kitchen-tests/test/integration/webapp/serverspec/localhost/default_spec.rb b/kitchen-tests/test/integration/webapp/serverspec/localhost/default_spec.rb
deleted file mode 100644
index 64c9121a6f..0000000000
--- a/kitchen-tests/test/integration/webapp/serverspec/localhost/default_spec.rb
+++ /dev/null
@@ -1,127 +0,0 @@
-
-require "net/http"
-require "uri"
-
-require "#{ENV['BUSSER_ROOT']}/../kitchen/data/serverspec_helper"
-
-describe "webapp::default", :end_to_end => true do
-
- describe "installed packages" do
- shared_examples_for "a package" do
- it "is installed" do
- expect(package(package_name)).to be_installed
- end
- end
-
- describe "#{property[:apache][:package]} package" do
- include_examples "a package" do
- let(:package_name) { property[:apache][:package] }
- end
- end
-
- describe "#{property[:mysql][:server_package]} package" do
- include_examples "a package" do
- let(:package_name) { property[:mysql][:server_package] }
- end
- end
-
- describe "#{property[:mysql][:client_package]} package" do
- include_examples "a package" do
- let(:package_name) { property[:mysql][:client_package] }
- end
- end
-
- describe "php package" do
- include_examples "a package" do
- let(:package_name) { property[:php][:package] }
- end
- end
- end
-
- describe "enabled/running services" do
- shared_examples_for "a service" do
- it "is enabled" do
- expect(service(service_name)).to be_enabled
- end
-
- it "is running" do
- expect(service(service_name)).to be_enabled
- end
- end
-
- describe "#{property[:apache][:service_name]} service" do
- include_examples "a service" do
- let(:service_name) { property[:apache][:service_name] }
- end
- end
-
- describe "mysql service" do
- include_examples "a service" do
- let(:service_name) { property[:mysql][:service_name] }
- end
- end
-
- end
-
- describe "mysql database" do
- let(:db_query) { "mysql -u root -pilikerandompasswordstoo -e \"#{statement}\"" }
- let(:statement) { "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='webapp'" }
- it "creates a database called 'webapp'" do
- expect(command(db_query).stdout).to match /webapp/
- end
-
- describe "mysql database user 'webapp'" do
- let(:statement) { "SELECT Host, Db FROM mysql.db WHERE User='webapp'\\G" }
- it "adds user 'webapp' to database 'webapp@localhost'" do
- expect(command(db_query).stdout).to match /Host: localhost\n Db: webapp/
- end
-
- describe "grants" do
- shared_examples_for "a privilege" do |priv|
- let(:statement) {
- "SELECT #{priv_query}" \
- " FROM mysql.db" \
- " WHERE Host='localhost' AND Db='webapp' AND User='webapp'\\G"
- }
- let(:priv_query) { "#{priv.capitalize}_priv" }
-
- it "has privilege #{priv} on 'webapp@localhost'" do
- expect(command(db_query).stdout).to match /#{priv_query}: Y/
- end
- end
-
- %w(select update insert delete create).each do |priv|
- include_examples "a privilege", priv do
- end
- end
- end
- end
- end
-
- describe "generated webpages" do
- let(:get_response) { Net::HTTP.get_response(uri) }
- shared_examples_for "a webpage" do
- it "exists" do
- expect(get_response).to be_kind_of(Net::HTTPSuccess)
- end
-
- it "displays content" do
- expect(get_response.body).to include(content)
- end
- end
-
- describe "http://localhost/index.html" do
- include_examples "a webpage" do
- let(:uri) { URI.parse("http://localhost/index.html") }
- let(:content) { "Hello, World!" }
- end
- end
-
- describe "http://localhost/index.php" do
- include_examples "a webpage" do
- let(:uri) { URI.parse("http://localhost/index.php") }
- let(:content) { "Hello, World!" }
- end
- end
- end
-end
diff --git a/lib-backcompat/chef/chef_fs/file_system/acl_entry.rb b/lib-backcompat/chef/chef_fs/file_system/acl_entry.rb
new file mode 100644
index 0000000000..f28b9f86e3
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/acl_entry.rb
@@ -0,0 +1,5 @@
+require "chef/chef_fs/file_system/chef_server/acl_entry"
+
+module Chef::ChefFS::FileSystem
+ AclEntry = ChefServer::AclEntry
+end
diff --git a/lib-backcompat/chef/chef_fs/file_system/already_exists_error.rb b/lib-backcompat/chef/chef_fs/file_system/already_exists_error.rb
new file mode 100644
index 0000000000..75cebe5497
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/already_exists_error.rb
@@ -0,0 +1,20 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/exceptions"
+Chef.deprecated :internal_api, "Individual ChefFS error files are deprecated. Please require 'chef/chef_fs/file_system/exceptions' rather than 'chef/chef_fs/file_system/#{File.basename(__FILE__, ".rb")}'."
diff --git a/lib-backcompat/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb b/lib-backcompat/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
new file mode 100644
index 0000000000..123fb9ee9a
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
@@ -0,0 +1,5 @@
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir"
+
+module Chef::ChefFS::FileSystem
+ ChefRepositoryFileSystemRootDir = Repository::ChefRepositoryFileSystemRootDir
+end
diff --git a/lib-backcompat/chef/chef_fs/file_system/chef_server_root_dir.rb b/lib-backcompat/chef/chef_fs/file_system/chef_server_root_dir.rb
new file mode 100644
index 0000000000..acb81dd08a
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/chef_server_root_dir.rb
@@ -0,0 +1,5 @@
+require "chef/chef_fs/file_system/chef_server/chef_server_root_dir"
+
+module Chef::ChefFS::FileSystem
+ ChefServerRootDir = ChefServer::ChefServerRootDir
+end
diff --git a/lib-backcompat/chef/chef_fs/file_system/cookbook_frozen_error.rb b/lib-backcompat/chef/chef_fs/file_system/cookbook_frozen_error.rb
new file mode 100644
index 0000000000..75cebe5497
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/cookbook_frozen_error.rb
@@ -0,0 +1,20 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/exceptions"
+Chef.deprecated :internal_api, "Individual ChefFS error files are deprecated. Please require 'chef/chef_fs/file_system/exceptions' rather than 'chef/chef_fs/file_system/#{File.basename(__FILE__, ".rb")}'."
diff --git a/lib-backcompat/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb b/lib-backcompat/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb
new file mode 100644
index 0000000000..75cebe5497
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb
@@ -0,0 +1,20 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/exceptions"
+Chef.deprecated :internal_api, "Individual ChefFS error files are deprecated. Please require 'chef/chef_fs/file_system/exceptions' rather than 'chef/chef_fs/file_system/#{File.basename(__FILE__, ".rb")}'."
diff --git a/lib-backcompat/chef/chef_fs/file_system/file_system_error.rb b/lib-backcompat/chef/chef_fs/file_system/file_system_error.rb
new file mode 100644
index 0000000000..75cebe5497
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/file_system_error.rb
@@ -0,0 +1,20 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/exceptions"
+Chef.deprecated :internal_api, "Individual ChefFS error files are deprecated. Please require 'chef/chef_fs/file_system/exceptions' rather than 'chef/chef_fs/file_system/#{File.basename(__FILE__, ".rb")}'."
diff --git a/lib-backcompat/chef/chef_fs/file_system/must_delete_recursively_error.rb b/lib-backcompat/chef/chef_fs/file_system/must_delete_recursively_error.rb
new file mode 100644
index 0000000000..75cebe5497
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/must_delete_recursively_error.rb
@@ -0,0 +1,20 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/exceptions"
+Chef.deprecated :internal_api, "Individual ChefFS error files are deprecated. Please require 'chef/chef_fs/file_system/exceptions' rather than 'chef/chef_fs/file_system/#{File.basename(__FILE__, ".rb")}'."
diff --git a/lib-backcompat/chef/chef_fs/file_system/not_found_error.rb b/lib-backcompat/chef/chef_fs/file_system/not_found_error.rb
new file mode 100644
index 0000000000..75cebe5497
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/not_found_error.rb
@@ -0,0 +1,20 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/exceptions"
+Chef.deprecated :internal_api, "Individual ChefFS error files are deprecated. Please require 'chef/chef_fs/file_system/exceptions' rather than 'chef/chef_fs/file_system/#{File.basename(__FILE__, ".rb")}'."
diff --git a/lib-backcompat/chef/chef_fs/file_system/operation_failed_error.rb b/lib-backcompat/chef/chef_fs/file_system/operation_failed_error.rb
new file mode 100644
index 0000000000..75cebe5497
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/operation_failed_error.rb
@@ -0,0 +1,20 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/exceptions"
+Chef.deprecated :internal_api, "Individual ChefFS error files are deprecated. Please require 'chef/chef_fs/file_system/exceptions' rather than 'chef/chef_fs/file_system/#{File.basename(__FILE__, ".rb")}'."
diff --git a/lib-backcompat/chef/chef_fs/file_system/operation_not_allowed_error.rb b/lib-backcompat/chef/chef_fs/file_system/operation_not_allowed_error.rb
new file mode 100644
index 0000000000..75cebe5497
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/operation_not_allowed_error.rb
@@ -0,0 +1,20 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/exceptions"
+Chef.deprecated :internal_api, "Individual ChefFS error files are deprecated. Please require 'chef/chef_fs/file_system/exceptions' rather than 'chef/chef_fs/file_system/#{File.basename(__FILE__, ".rb")}'."
diff --git a/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir.rb b/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir.rb
new file mode 100644
index 0000000000..d9bdbc104c
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir.rb
@@ -0,0 +1,5 @@
+require "chef/chef_fs/file_system/repository/acls_dir"
+
+module Chef::ChefFS::FileSystem::Repository
+ ChefRepositoryFileSystemAclsDir = AclsDir
+end
diff --git a/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_client_keys_dir.rb b/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_client_keys_dir.rb
new file mode 100644
index 0000000000..4ebcb5f010
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_client_keys_dir.rb
@@ -0,0 +1,5 @@
+require "chef/chef_fs/file_system/repository/client_keys_dir"
+
+module Chef::ChefFS::FileSystem::Repository
+ ChefRepositoryFileSystemClientKeysDir = ClientKeysDir
+end
diff --git a/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb b/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb
new file mode 100644
index 0000000000..7668c6b174
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb
@@ -0,0 +1,6 @@
+require "chef/chef_fs/file_system/repository/file_system_entry"
+
+module Chef::ChefFS::FileSystem::Repository
+ Chef.deprecated :internal_api, "Chef::ChefFS::FileSystem::Repository::ChefRepositoryFileSystemEntry is deprecated. Please use FileSystemEntry directly"
+ ChefRepositoryFileSystemEntry = FileSystemEntry
+end
diff --git a/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir.rb b/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir.rb
new file mode 100644
index 0000000000..393e4aa85d
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir.rb
@@ -0,0 +1,5 @@
+require "chef/chef_fs/file_system/repository/policies_dir"
+
+module Chef::ChefFS::FileSystem::Repository
+ ChefRepositoryFileSystemPoliciesDir = PoliciesDir
+end
diff --git a/lib-backcompat/chef/chef_fs/file_system/repository/file_system_root_dir.rb b/lib-backcompat/chef/chef_fs/file_system/repository/file_system_root_dir.rb
new file mode 100644
index 0000000000..1c8bb87d72
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/repository/file_system_root_dir.rb
@@ -0,0 +1,34 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/file_system_entry"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class FileSystemRootDir < FileSystemEntry
+ def initialize(file_path)
+ Chef.deprecated :internal_api, "Chef::ChefFS::FileSystem::Repository::FileSystemRootDir is deprecated."
+ super("", nil, file_path)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef.rb b/lib/chef.rb
index 1a0b802adb..3e161dc365 100644
--- a/lib/chef.rb
+++ b/lib/chef.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,20 +16,20 @@
# limitations under the License.
#
-require 'chef/version'
-require 'chef/nil_argument'
-require 'chef/mash'
-require 'chef/exceptions'
-require 'chef/log'
-require 'chef/config'
-require 'chef/providers'
-require 'chef/resources'
-require 'chef/shell_out'
+require "chef/version"
+require "chef/nil_argument"
+require "chef/mash"
+require "chef/exceptions"
+require "chef/log"
+require "chef/config"
+require "chef/providers"
+require "chef/resources"
+require "chef/shell_out"
-require 'chef/daemon'
+require "chef/daemon"
-require 'chef/run_status'
-require 'chef/handler'
-require 'chef/handler/json_file'
-require 'chef/event_dispatch/dsl'
-require 'chef/chef_class'
+require "chef/run_status"
+require "chef/handler"
+require "chef/handler/json_file"
+require "chef/event_dispatch/dsl"
+require "chef/chef_class"
diff --git a/lib/chef/api_client.rb b/lib/chef/api_client.rb
index b7b9f7dc43..6999a4f52d 100644
--- a/lib/chef/api_client.rb
+++ b/lib/chef/api_client.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,13 +17,13 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/mash'
-require 'chef/json_compat'
-require 'chef/search/query'
-require 'chef/server_api'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/search/query"
+require "chef/server_api"
# DEPRECATION NOTE
#
@@ -38,7 +38,7 @@ class Chef
# Create a new Chef::ApiClient object.
def initialize
- @name = ''
+ @name = ""
@public_key = nil
@private_key = nil
@admin = false
@@ -49,7 +49,7 @@ class Chef
#
# @params [Optional String] The name must be alpha-numeric plus - and _.
# @return [String] The current value of the name.
- def name(arg=nil)
+ def name(arg = nil)
set_or_return(
:name,
arg,
@@ -61,7 +61,7 @@ class Chef
#
# @params [Optional True/False] Should be true or false - default is false.
# @return [True/False] The current value
- def admin(arg=nil)
+ def admin(arg = nil)
set_or_return(
:admin,
arg,
@@ -73,7 +73,7 @@ class Chef
#
# @params [Optional String] The string representation of the public key.
# @return [String] The current value.
- def public_key(arg=nil)
+ def public_key(arg = nil)
set_or_return(
:public_key,
arg,
@@ -86,7 +86,7 @@ class Chef
# @params [Boolean] whether or not the client is a validator. If
# `nil`, retrieves the already-set value.
# @return [Boolean] The current value
- def validator(arg=nil)
+ def validator(arg = nil)
set_or_return(
:validator,
arg,
@@ -98,7 +98,7 @@ class Chef
#
# @params [Optional String] The string representation of the private key.
# @return [String] The current value.
- def private_key(arg=nil)
+ def private_key(arg = nil)
set_or_return(
:private_key,
arg,
@@ -116,8 +116,8 @@ class Chef
"public_key" => @public_key,
"validator" => @validator,
"admin" => @admin,
- 'json_class' => self.class.name,
- "chef_type" => "client"
+ "json_class" => self.class.name,
+ "chef_type" => "client",
}
result["private_key"] = @private_key if @private_key
result
@@ -141,6 +141,7 @@ class Chef
end
def self.json_create(data)
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::ApiClient#from_hash")
from_hash(data)
end
@@ -149,7 +150,7 @@ class Chef
end
def self.http_api
- Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0"})
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" })
end
def self.reregister(name)
@@ -157,11 +158,11 @@ class Chef
api_client.reregister
end
- def self.list(inflate=false)
+ def self.list(inflate = false)
if inflate
response = Hash.new
Chef::Search::Query.new.search(:client) do |n|
- n = self.json_create(n) if n.instance_of?(Hash)
+ n = json_create(n) if n.instance_of?(Hash)
response[n.name] = n
end
response
@@ -176,7 +177,7 @@ class Chef
if response.kind_of?(Chef::ApiClient)
response
else
- json_create(response)
+ from_hash(response)
end
end
@@ -187,15 +188,13 @@ class Chef
# Save this client via the REST API, returns a hash including the private key
def save
- begin
- http_api.put("clients/#{name}", { :name => self.name, :admin => self.admin, :validator => self.validator})
- rescue Net::HTTPServerException => e
- # If that fails, go ahead and try and update it
- if e.response.code == "404"
- http_api.post("clients", {:name => self.name, :admin => self.admin, :validator => self.validator })
- else
- raise e
- end
+ http_api.put("clients/#{name}", { :name => name, :admin => admin, :validator => validator })
+ rescue Net::HTTPServerException => e
+ # If that fails, go ahead and try and update it
+ if e.response.code == "404"
+ http_api.post("clients", { :name => name, :admin => admin, :validator => validator })
+ else
+ raise e
end
end
@@ -221,11 +220,11 @@ class Chef
def inspect
"Chef::ApiClient name:'#{name}' admin:'#{admin.inspect}' validator:'#{validator}' " +
- "public_key:'#{public_key}' private_key:'#{private_key}'"
+ "public_key:'#{public_key}' private_key:'#{private_key}'"
end
def http_api
- @http_api ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0"})
+ @http_api ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" })
end
end
diff --git a/lib/chef/api_client/registration.rb b/lib/chef/api_client/registration.rb
index 4882323293..e8ab0149e8 100644
--- a/lib/chef/api_client/registration.rb
+++ b/lib/chef/api_client/registration.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/rest'
-require 'chef/exceptions'
+require "chef/config"
+require "chef/server_api"
+require "chef/exceptions"
class Chef
class ApiClient
@@ -45,7 +45,7 @@ class Chef
#--
# If client creation fails with a 5xx, it is retried up to 5 times. These
# retries are on top of the retries with randomized exponential backoff
- # built in to Chef::REST. The retries here are a workaround for failures
+ # built in to Chef::ServerAPI. The retries here are a workaround for failures
# caused by resource contention in Hosted Chef when creating a very large
# number of clients simultaneously, (e.g., spinning up 100s of ec2 nodes
# at once). Future improvements to the affected component should make
@@ -53,8 +53,9 @@ class Chef
def run
assert_destination_writable!
retries = Config[:client_registration_retries] || 5
+ client = nil
begin
- create_or_update
+ client = api_client(create_or_update)
rescue Net::HTTPFatalError => e
# HTTPFatalError implies 5xx.
raise if retries <= 0
@@ -64,10 +65,11 @@ class Chef
retry
end
write_key
+ client
end
def assert_destination_writable!
- if (File.exists?(destination) && !File.writable?(destination)) or !File.writable?(File.dirname(destination))
+ if (File.exists?(destination) && !File.writable?(destination)) || !File.writable?(File.dirname(destination))
abs_path = File.expand_path(destination)
raise Chef::Exceptions::CannotWritePrivateKey, "I can't write your private key to #{abs_path} - check permissions?"
end
@@ -106,6 +108,28 @@ class Chef
response
end
+ def api_client(response)
+ return response if response.is_a?(Chef::ApiClient)
+
+ client = Chef::ApiClient.new
+ client.name(name)
+ client.public_key(api_client_key(response, "public_key"))
+ client.private_key(api_client_key(response, "private_key"))
+ client
+ end
+
+ def api_client_key(response, key_name)
+ if response[key_name]
+ if response[key_name].respond_to?(:to_pem)
+ response[key_name].to_pem
+ else
+ response[key_name]
+ end
+ elsif response["chef_key"]
+ response["chef_key"][key_name]
+ end
+ end
+
def put_data
base_put_data = { :name => name, :admin => false }
if self_generate_keys?
@@ -123,9 +147,13 @@ class Chef
end
def http_api
- @http_api ||= Chef::REST.new(Chef::Config[:chef_server_url],
- Chef::Config[:validation_client_name],
- Chef::Config[:validation_key])
+ @http_api ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url],
+ {
+ :api_version => "0",
+ :client_name => Chef::Config[:validation_client_name],
+ :signing_key_filename => Chef::Config[:validation_key],
+ }
+ )
end
# Whether or not to generate keys locally and post the public key to the
@@ -152,7 +180,7 @@ class Chef
end
def file_flags
- base_flags = File::CREAT|File::TRUNC|File::RDWR
+ base_flags = File::CREAT | File::TRUNC | File::RDWR
# Windows doesn't have symlinks, so it doesn't have NOFOLLOW
if defined?(File::NOFOLLOW) && !Chef::Config[:follow_client_key_symlink]
base_flags |= File::NOFOLLOW
diff --git a/lib/chef/api_client_v1.rb b/lib/chef/api_client_v1.rb
index 80f0d2517c..a1b9b8317e 100644
--- a/lib/chef/api_client_v1.rb
+++ b/lib/chef/api_client_v1.rb
@@ -1,7 +1,7 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Nuo Yan (<nuo@chef.io>)
-# Copyright:: Copyright (c) 2008, 2015 Chef Software, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,16 +17,16 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/mash'
-require 'chef/json_compat'
-require 'chef/search/query'
-require 'chef/exceptions'
-require 'chef/mixin/api_version_request_handling'
-require 'chef/server_api'
-require 'chef/api_client'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/search/query"
+require "chef/exceptions"
+require "chef/mixin/api_version_request_handling"
+require "chef/server_api"
+require "chef/api_client"
# COMPATIBILITY NOTE
#
@@ -44,11 +44,11 @@ class Chef
include Chef::Mixin::ParamsValidate
include Chef::Mixin::ApiVersionRequestHandling
- SUPPORTED_API_VERSIONS = [0,1]
+ SUPPORTED_API_VERSIONS = [0, 1]
# Create a new Chef::ApiClientV1 object.
def initialize
- @name = ''
+ @name = ""
@public_key = nil
@private_key = nil
@admin = false
@@ -57,22 +57,22 @@ class Chef
end
def chef_rest_v0
- @chef_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0", :inflate_json_class => false})
+ @chef_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0", :inflate_json_class => false })
end
def chef_rest_v1
- @chef_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "1", :inflate_json_class => false})
+ @chef_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "1", :inflate_json_class => false })
end
def self.http_api
- Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "1", :inflate_json_class => false})
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "1", :inflate_json_class => false })
end
# Gets or sets the client name.
#
# @params [Optional String] The name must be alpha-numeric plus - and _.
# @return [String] The current value of the name.
- def name(arg=nil)
+ def name(arg = nil)
set_or_return(
:name,
arg,
@@ -84,7 +84,7 @@ class Chef
#
# @params [Optional True/False] Should be true or false - default is false.
# @return [True/False] The current value
- def admin(arg=nil)
+ def admin(arg = nil)
set_or_return(
:admin,
arg,
@@ -96,7 +96,7 @@ class Chef
#
# @params [Optional String] The string representation of the public key.
# @return [String] The current value.
- def public_key(arg=nil)
+ def public_key(arg = nil)
set_or_return(
:public_key,
arg,
@@ -109,7 +109,7 @@ class Chef
# @params [Boolean] whether or not the client is a validator. If
# `nil`, retrieves the already-set value.
# @return [Boolean] The current value
- def validator(arg=nil)
+ def validator(arg = nil)
set_or_return(
:validator,
arg,
@@ -122,7 +122,7 @@ class Chef
#
# @params [Optional String] The string representation of the private key.
# @return [String] The current value.
- def private_key(arg=nil)
+ def private_key(arg = nil)
set_or_return(
:private_key,
arg,
@@ -134,7 +134,7 @@ class Chef
#
# @params [Optional True/False] Should be true or false - default is false.
# @return [True/False] The current value
- def create_key(arg=nil)
+ def create_key(arg = nil)
set_or_return(
:create_key,
arg,
@@ -151,7 +151,7 @@ class Chef
"name" => @name,
"validator" => @validator,
"admin" => @admin,
- "chef_type" => "client"
+ "chef_type" => "client",
}
result["private_key"] = @private_key unless @private_key.nil?
result["public_key"] = @public_key unless @public_key.nil?
@@ -186,11 +186,11 @@ class Chef
api_client.reregister
end
- def self.list(inflate=false)
+ def self.list(inflate = false)
if inflate
response = Hash.new
Chef::Search::Query.new.search(:client) do |n|
- n = self.from_hash(n) if n.instance_of?(Hash)
+ n = from_hash(n) if n.instance_of?(Hash)
response[n.name] = n
end
response
@@ -212,15 +212,13 @@ class Chef
# Save this client via the REST API, returns a hash including the private key
def save
- begin
- update
- rescue Net::HTTPServerException => e
- # If that fails, go ahead and try and update it
- if e.response.code == "404"
- create
- else
- raise e
- end
+ update
+ rescue Net::HTTPServerException => e
+ # If that fails, go ahead and try and update it
+ if e.response.code == "404"
+ create
+ else
+ raise e
end
end
@@ -282,7 +280,7 @@ class Chef
:validator => validator,
# this field is ignored in API V1, but left for backwards-compat,
# can remove after OSC 11 support is finished?
- :admin => admin
+ :admin => admin,
}
begin
# try API V1
@@ -294,12 +292,12 @@ class Chef
new_client = chef_rest_v1.post("clients", payload)
# get the private_key out of the chef_key hash if it exists
- if new_client['chef_key']
- if new_client['chef_key']['private_key']
- new_client['private_key'] = new_client['chef_key']['private_key']
+ if new_client["chef_key"]
+ if new_client["chef_key"]["private_key"]
+ new_client["private_key"] = new_client["chef_key"]["private_key"]
end
- new_client['public_key'] = new_client['chef_key']['public_key']
- new_client.delete('chef_key')
+ new_client["public_key"] = new_client["chef_key"]["public_key"]
+ new_client.delete("chef_key")
end
rescue Net::HTTPServerException => e
@@ -313,7 +311,7 @@ class Chef
new_client = chef_rest_v0.post("clients", payload)
end
- Chef::ApiClientV1.from_hash(self.to_hash.merge(new_client))
+ Chef::ApiClientV1.from_hash(to_hash.merge(new_client))
end
# As a string
diff --git a/lib/chef/application.rb b/lib/chef/application.rb
index 970544c068..ab19e6571e 100644
--- a/lib/chef/application.rb
+++ b/lib/chef/application.rb
@@ -1,7 +1,7 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Author:: Mark Mzyk (mmzyk@opscode.com)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Author:: Mark Mzyk (mmzyk@chef.io)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'pp'
-require 'uri'
-require 'socket'
-require 'chef/config'
-require 'chef/config_fetcher'
-require 'chef/exceptions'
-require 'chef/local_mode'
-require 'chef/log'
-require 'chef/platform'
-require 'mixlib/cli'
-require 'tmpdir'
-require 'rbconfig'
+require "pp"
+require "socket"
+require "chef/config"
+require "chef/config_fetcher"
+require "chef/exceptions"
+require "chef/local_mode"
+require "chef/log"
+require "chef/platform"
+require "mixlib/cli"
+require "tmpdir"
+require "rbconfig"
+require "chef/application/exit_code"
class Chef
class Application
@@ -47,7 +47,6 @@ class Chef
def reconfigure
configure_chef
configure_logging
- configure_proxy_environment_variables
configure_encoding
emit_warnings
end
@@ -62,11 +61,11 @@ class Chef
def setup_signal_handlers
trap("INT") do
- Chef::Application.fatal!("SIGINT received, stopping", 2)
+ Chef::Application.fatal!("SIGINT received, stopping", Chef::Exceptions::SigInt.new)
end
trap("TERM") do
- Chef::Application.fatal!("SIGTERM received, stopping", 3)
+ Chef::Application.fatal!("SIGTERM received, stopping", Chef::Exceptions::SigTerm.new)
end
unless Chef::Platform.windows?
@@ -85,11 +84,20 @@ class Chef
def configure_chef
parse_options
load_config_file
+ Chef::Config.export_proxies
+ Chef::Config.init_openssl
end
# Parse the config file
def load_config_file
config_fetcher = Chef::ConfigFetcher.new(config[:config_file])
+
+ # Some config settings are derived relative to the config file path; if
+ # given as a relative path, this is computed relative to cwd, but
+ # chef-client will later chdir to root, so we need to get the absolute path
+ # here.
+ config[:config_file] = config_fetcher.expanded_path
+
if config[:config_file].nil?
Chef::Log.warn("No config file found or specified on command line, using command line options.")
elsif config_fetcher.config_missing?
@@ -100,13 +108,22 @@ class Chef
config_content = config_fetcher.read_config
apply_config(config_content, config[:config_file])
end
+ extra_config_options = config.delete(:config_option)
Chef::Config.merge!(config)
+ apply_extra_config_options(extra_config_options)
+ end
+
+ def apply_extra_config_options(extra_config_options)
+ Chef::Config.apply_extra_config_options(extra_config_options)
+ rescue ChefConfig::UnparsableConfigOption => e
+ Chef::Application.fatal!(e.message)
end
def set_specific_recipes
- Chef::Config[:specific_recipes] =
- cli_arguments.map { |file| File.expand_path(file) } if
- cli_arguments.respond_to?(:map)
+ if cli_arguments.respond_to?(:map)
+ Chef::Config[:specific_recipes] =
+ cli_arguments.map { |file| File.expand_path(file) }
+ end
end
# Initialize and configure the logger.
@@ -134,6 +151,7 @@ class Chef
# that a user has configured a log_location in client.rb, but is running
# chef-client by hand to troubleshoot a problem.
def configure_logging
+ configure_log_location
Chef::Log.init(MonoLogger.new(Chef::Config[:log_location]))
if want_additional_logger?
configure_stdout_logger
@@ -141,13 +159,27 @@ class Chef
Chef::Log.level = resolve_log_level
rescue StandardError => error
Chef::Log.fatal("Failed to open or create log file at #{Chef::Config[:log_location]}: #{error.class} (#{error.message})")
- Chef::Application.fatal!("Aborting due to invalid 'log_location' configuration", 2)
+ Chef::Application.fatal!("Aborting due to invalid 'log_location' configuration", error)
+ end
+
+ # Turn `log_location :syslog` and `log_location :win_evt` into the
+ # appropriate loggers.
+ def configure_log_location
+ log_location = Chef::Config[:log_location]
+ return unless log_location.respond_to?(:to_sym)
+
+ Chef::Config[:log_location] =
+ case log_location.to_sym
+ when :syslog then Chef::Log::Syslog.new
+ when :win_evt then Chef::Log::WinEvt.new
+ else log_location # Probably a path; let MonoLogger sort it out
+ end
end
def configure_stdout_logger
stdout_logger = MonoLogger.new(STDOUT)
stdout_logger.formatter = Chef::Log.logger.formatter
- Chef::Log.loggers << stdout_logger
+ Chef::Log.loggers << stdout_logger
end
# Based on config and whether or not STDOUT is a tty, should we setup a
@@ -180,14 +212,6 @@ class Chef
end
end
- # Configure and set any proxy environment variables according to the config.
- def configure_proxy_environment_variables
- configure_http_proxy
- configure_https_proxy
- configure_ftp_proxy
- configure_no_proxy
- end
-
# Sets the default external encoding to UTF-8 (users can change this, but they shouldn't)
def configure_encoding
Encoding.default_external = Chef::Config[:ruby_encoding]
@@ -195,18 +219,18 @@ class Chef
# Called prior to starting the application, by the run method
def setup_application
- raise Chef::Exceptions::Application, "#{self.to_s}: you must override setup_application"
+ raise Chef::Exceptions::Application, "#{self}: you must override setup_application"
end
# Actually run the application
def run_application
- raise Chef::Exceptions::Application, "#{self.to_s}: you must override run_application"
+ raise Chef::Exceptions::Application, "#{self}: you must override run_application"
end
# Initializes Chef::Client instance and runs it
def run_chef_client(specific_recipes = [])
unless specific_recipes.respond_to?(:size)
- raise ArgumentError, 'received non-Array like specific_recipes argument'
+ raise ArgumentError, "received non-Array like specific_recipes argument"
end
Chef::LocalMode.with_server_connectivity do
@@ -233,6 +257,7 @@ class Chef
end
private
+
def can_fork?
# win32-process gem exposes some form of :fork for Process
# class. So we are separately ensuring that the platform we're
@@ -244,7 +269,7 @@ class Chef
# signal to finish the converge and exists.
def run_with_graceful_exit_option
# Override the TERM signal.
- trap('TERM') do
+ trap("TERM") do
Chef::Log.debug("SIGTERM received during converge," +
" finishing converge to exit normally (send SIGINT to terminate immediately)")
end
@@ -258,7 +283,7 @@ class Chef
pid = fork do
# Want to allow forked processes to finish converging when
# TERM singal is received (exit gracefully)
- trap('TERM') do
+ trap("TERM") do
Chef::Log.debug("SIGTERM received during converge," +
" finishing converge to exit normally (send SIGINT to terminate immediately)")
end
@@ -270,7 +295,7 @@ class Chef
@chef_client.run
rescue Exception => e
Chef::Log.error(e.to_s)
- exit 1
+ exit Chef::Application.normalize_exit_code(e)
else
exit 0
end
@@ -298,81 +323,8 @@ class Chef
rescue Exception => error
Chef::Log.fatal("Configuration error #{error.class}: #{error.message}")
filtered_trace = error.backtrace.grep(/#{Regexp.escape(config_file_path)}/)
- filtered_trace.each {|line| Chef::Log.fatal(" " + line )}
- Chef::Application.fatal!("Aborting due to error in '#{config_file_path}'", 2)
- end
-
- # Set ENV['http_proxy']
- def configure_http_proxy
- if http_proxy = Chef::Config[:http_proxy]
- http_proxy_string = configure_proxy("http", http_proxy,
- Chef::Config[:http_proxy_user], Chef::Config[:http_proxy_pass])
- env['http_proxy'] = http_proxy_string unless env['http_proxy']
- env['HTTP_PROXY'] = http_proxy_string unless env['HTTP_PROXY']
- end
- end
-
- # Set ENV['https_proxy']
- def configure_https_proxy
- if https_proxy = Chef::Config[:https_proxy]
- https_proxy_string = configure_proxy("https", https_proxy,
- Chef::Config[:https_proxy_user], Chef::Config[:https_proxy_pass])
- env['https_proxy'] = https_proxy_string unless env['https_proxy']
- env['HTTPS_PROXY'] = https_proxy_string unless env['HTTPS_PROXY']
- end
- end
-
- # Set ENV['ftp_proxy']
- def configure_ftp_proxy
- if ftp_proxy = Chef::Config[:ftp_proxy]
- ftp_proxy_string = configure_proxy("ftp", ftp_proxy,
- Chef::Config[:ftp_proxy_user], Chef::Config[:ftp_proxy_pass])
- env['ftp_proxy'] = ftp_proxy_string unless env['ftp_proxy']
- env['FTP_PROXY'] = ftp_proxy_string unless env['FTP_PROXY']
- end
- end
-
- # Set ENV['no_proxy']
- def configure_no_proxy
- if Chef::Config[:no_proxy]
- env['no_proxy'] = Chef::Config[:no_proxy] unless env['no_proxy']
- env['NO_PROXY'] = Chef::Config[:no_proxy] unless env['NO_PROXY']
- end
- end
-
- # Builds a proxy uri. Examples:
- # http://username:password@hostname:port
- # https://username@hostname:port
- # ftp://hostname:port
- # when
- # scheme = "http", "https", or "ftp"
- # hostport = hostname:port
- # user = username
- # pass = password
- def configure_proxy(scheme, path, user, pass)
- begin
- path = "#{scheme}://#{path}" unless path.include?('://')
- # URI.split returns the following parts:
- # [scheme, userinfo, host, port, registry, path, opaque, query, fragment]
- parts = URI.split(URI.encode(path))
- # URI::Generic.build requires an integer for the port, but URI::split gives
- # returns a string for the port.
- parts[3] = parts[3].to_i if parts[3]
- if user
- userinfo = URI.encode(URI.encode(user), '@:')
- if pass
- userinfo << ":#{URI.encode(URI.encode(pass), '@:')}"
- end
- parts[1] = userinfo
- end
-
- return URI::Generic.build(parts).to_s
- rescue URI::Error => e
- # URI::Error messages generally include the offending string. Including a message
- # for which proxy config item has the issue should help deduce the issue when
- # the URI::Error message is vague.
- raise Chef::Exceptions::BadProxyURI, "Cannot configure #{scheme} proxy. Does not comply with URI scheme. #{e.message}"
- end
+ filtered_trace.each { |line| Chef::Log.fatal(" " + line ) }
+ Chef::Application.fatal!("Aborting due to error in '#{config_file_path}'", error)
end
# This is a hook for testing
@@ -382,31 +334,43 @@ class Chef
def emit_warnings
if Chef::Config[:chef_gem_compile_time]
- Chef.log_deprecation "setting chef_gem_compile_time to true is deprecated"
+ Chef.deprecated :chef_gem_compile_time, "setting chef_gem_compile_time to true is deprecated"
end
end
class << self
def debug_stacktrace(e)
message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
- chef_stacktrace_out = "Generated at #{Time.now.to_s}\n"
+
+ cause = e.cause if e.respond_to?(:cause)
+ until cause.nil?
+ message << "\n\n>>>> Caused by #{cause.class}: #{cause}\n#{cause.backtrace.join("\n")}"
+ cause = cause.respond_to?(:cause) ? cause.cause : nil
+ end
+
+ chef_stacktrace_out = "Generated at #{Time.now}\n"
chef_stacktrace_out += message
Chef::FileCache.store("chef-stacktrace.out", chef_stacktrace_out)
Chef::Log.fatal("Stacktrace dumped to #{Chef::FileCache.load("chef-stacktrace.out", false)}")
+ Chef::Log.fatal("Please provide the contents of the stacktrace.out file if you file a bug report")
Chef::Log.debug(message)
true
end
+ def normalize_exit_code(exit_code)
+ Chef::Application::ExitCode.normalize_exit_code(exit_code)
+ end
+
# Log a fatal error message to both STDERR and the Logger, exit the application
- def fatal!(msg, err = -1)
+ def fatal!(msg, err = nil)
Chef::Log.fatal(msg)
- Process.exit err
+ Process.exit(normalize_exit_code(err))
end
- def exit!(msg, err = -1)
+ def exit!(msg, err = nil)
Chef::Log.debug(msg)
- Process.exit err
+ Process.exit(normalize_exit_code(err))
end
end
diff --git a/lib/chef/application/apply.rb b/lib/chef/application/apply.rb
index 4c559542f1..d7f2359b02 100644
--- a/lib/chef/application/apply.rb
+++ b/lib/chef/application/apply.rb
@@ -1,8 +1,8 @@
#
# Author:: Bryan W. Berry (<bryan.berry@gmail.com>)
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2012 Bryan W. Berry
-# Copyright:: Copyright (c) 2012 Daniel DeLeo
+# Copyright:: Copyright 2012-2016, Bryan W. Berry
+# Copyright:: Copyright 2012-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef'
-require 'chef/application'
-require 'chef/client'
-require 'chef/config'
-require 'chef/log'
-require 'fileutils'
-require 'tempfile'
-require 'chef/providers'
-require 'chef/resources'
+require "chef"
+require "chef/application"
+require "chef/client"
+require "chef/config"
+require "chef/log"
+require "fileutils"
+require "tempfile"
+require "chef/providers"
+require "chef/resources"
class Chef::Application::Apply < Chef::Application
@@ -82,19 +82,18 @@ class Chef::Application::Apply < Chef::Application
:show_options => true,
:exit => 0
-
option :version,
:short => "-v",
:long => "--version",
:description => "Show chef version",
:boolean => true,
- :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+ :proc => lambda { |v| puts "Chef: #{::Chef::VERSION}" },
:exit => 0
option :why_run,
- :short => '-W',
- :long => '--why-run',
- :description => 'Enable whyrun mode',
+ :short => "-W",
+ :long => "--why-run",
+ :description => "Enable whyrun mode",
:boolean => true
option :profile_ruby,
@@ -104,7 +103,7 @@ class Chef::Application::Apply < Chef::Application
:default => false
option :color,
- :long => '--[no-]color',
+ :long => "--[no-]color",
:boolean => true,
:default => true,
:description => "Use colored output, defaults to enabled"
@@ -124,7 +123,8 @@ class Chef::Application::Apply < Chef::Application
parse_options
Chef::Config.merge!(config)
configure_logging
- configure_proxy_environment_variables
+ Chef::Config.export_proxies
+ Chef::Config.init_openssl
parse_json
end
@@ -137,11 +137,11 @@ class Chef::Application::Apply < Chef::Application
def read_recipe_file(file_name)
if file_name.nil?
- Chef::Application.fatal!("No recipe file was provided", 1)
+ Chef::Application.fatal!("No recipe file was provided", Chef::Exceptions::RecipeNotFound.new)
else
recipe_path = File.expand_path(file_name)
unless File.exist?(recipe_path)
- Chef::Application.fatal!("No file exists at #{recipe_path}", 1)
+ Chef::Application.fatal!("No file exists at #{recipe_path}", Chef::Exceptions::RecipeNotFound.new)
end
recipe_fh = open(recipe_path)
recipe_text = recipe_fh.read
@@ -150,7 +150,7 @@ class Chef::Application::Apply < Chef::Application
end
def get_recipe_and_run_context
- Chef::Config[:solo] = true
+ Chef::Config[:solo_legacy_mode] = true
@chef_client = Chef::Client.new(@json_attribs)
@chef_client.run_ohai
@chef_client.load_node
@@ -167,7 +167,7 @@ class Chef::Application::Apply < Chef::Application
# write recipe to temp file, so in case of error,
# user gets error w/ context
def temp_recipe_file
- @recipe_fh = Tempfile.open('recipe-temporary-file')
+ @recipe_fh = Tempfile.open("recipe-temporary-file")
@recipe_fh.write(@recipe_text)
@recipe_fh.rewind
@recipe_filename = @recipe_fh.path
@@ -183,12 +183,12 @@ class Chef::Application::Apply < Chef::Application
else
if !ARGV[0]
puts opt_parser
- Chef::Application.exit! "No recipe file provided", 1
+ Chef::Application.exit! "No recipe file provided", Chef::Exceptions::RecipeNotFound.new
end
@recipe_filename = ARGV[0]
- @recipe_text,@recipe_fh = read_recipe_file @recipe_filename
+ @recipe_text, @recipe_fh = read_recipe_file @recipe_filename
end
- recipe,run_context = get_recipe_and_run_context
+ recipe, run_context = get_recipe_and_run_context
recipe.instance_eval(@recipe_text, @recipe_filename, 1)
runner = Chef::Runner.new(run_context)
begin
@@ -200,16 +200,14 @@ class Chef::Application::Apply < Chef::Application
end
def run_application
- begin
- parse_options
- run_chef_recipe
- Chef::Application.exit! "Exiting", 0
- rescue SystemExit => e
- raise
- rescue Exception => e
- Chef::Application.debug_stacktrace(e)
- Chef::Application.fatal!("#{e.class}: #{e.message}", 1)
- end
+ parse_options
+ run_chef_recipe
+ Chef::Application.exit! "Exiting", 0
+ rescue SystemExit
+ raise
+ rescue Exception => e
+ Chef::Application.debug_stacktrace(e)
+ Chef::Application.fatal!("#{e.class}: #{e.message}", e)
end
# Get this party started
diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb
index 5fac34196d..c8dbd76019 100644
--- a/lib/chef/application/client.rb
+++ b/lib/chef/application/client.rb
@@ -1,8 +1,8 @@
#
-# Author:: AJ Christensen (<aj@opscode.com)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Mark Mzyk (mmzyk@opscode.com)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: AJ Christensen (<aj@chef.io)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Mark Mzyk (mmzyk@chef.io)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,17 +17,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/application'
-require 'chef/client'
-require 'chef/config'
-require 'chef/daemon'
-require 'chef/log'
-require 'chef/config_fetcher'
-require 'chef/handler/error_report'
-require 'chef/workstation_config_loader'
+require "chef/application"
+require "chef/client"
+require "chef/config"
+require "chef/daemon"
+require "chef/log"
+require "chef/config_fetcher"
+require "chef/handler/error_report"
+require "chef/workstation_config_loader"
+require "chef/mixin/shell_out"
+require "chef-config/mixin/dot_d"
+require "mixlib/archive"
class Chef::Application::Client < Chef::Application
include Chef::Mixin::ShellOut
+ include ChefConfig::Mixin::DotD
# Mimic self_pipe sleep from Unicorn to capture signals safely
SELF_PIPE = []
@@ -37,6 +41,14 @@ class Chef::Application::Client < Chef::Application
:long => "--config CONFIG",
:description => "The configuration file to use"
+ option :config_option,
+ :long => "--config-option OPTION=VALUE",
+ :description => "Override a single configuration option",
+ :proc => lambda { |option, existing|
+ (existing ||= []) << option
+ existing
+ }
+
option :formatter,
:short => "-F FORMATTER",
:long => "--format FORMATTER",
@@ -62,7 +74,7 @@ class Chef::Application::Client < Chef::Application
:default => false
option :color,
- :long => '--[no-]color',
+ :long => "--[no-]color",
:boolean => true,
:default => true,
:description => "Use colored output, defaults to enabled"
@@ -102,10 +114,12 @@ class Chef::Application::Client < Chef::Application
unless Chef::Platform.windows?
option :daemonize,
- :short => "-d",
- :long => "--daemonize",
- :description => "Daemonize the process",
- :proc => lambda { |p| true }
+ :short => "-d [WAIT]",
+ :long => "--daemonize [WAIT]",
+ :description =>
+ "Daemonize the process. Accepts an optional integer which is the " \
+ "number of seconds to wait before the first daemonized run.",
+ :proc => lambda { |wait| wait =~ /^\d+$/ ? wait.to_i : true }
end
option :pid_file,
@@ -169,47 +183,46 @@ class Chef::Application::Client < Chef::Application
option :named_run_list,
:short => "-n NAMED_RUN_LIST",
:long => "--named-run-list NAMED_RUN_LIST",
- :description => "Use a policyfile's named run list instead of the default run list",
- :default => nil
+ :description => "Use a policyfile's named run list instead of the default run list"
option :environment,
- :short => '-E ENVIRONMENT',
- :long => '--environment ENVIRONMENT',
- :description => 'Set the Chef Environment on the node'
+ :short => "-E ENVIRONMENT",
+ :long => "--environment ENVIRONMENT",
+ :description => "Set the Chef Environment on the node"
option :version,
:short => "-v",
:long => "--version",
:description => "Show chef version",
:boolean => true,
- :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+ :proc => lambda { |v| puts "Chef: #{::Chef::VERSION}" },
:exit => 0
option :override_runlist,
:short => "-o RunlistItem,RunlistItem...",
:long => "--override-runlist RunlistItem,RunlistItem...",
:description => "Replace current run list with specified items for a single run",
- :proc => lambda{|items|
- items = items.split(',')
- items.compact.map{|item|
+ :proc => lambda { |items|
+ items = items.split(",")
+ items.compact.map do |item|
Chef::RunList::RunListItem.new(item)
- }
+ end
}
option :runlist,
:short => "-r RunlistItem,RunlistItem...",
:long => "--runlist RunlistItem,RunlistItem...",
:description => "Permanently replace current run list with specified items",
- :proc => lambda{|items|
- items = items.split(',')
- items.compact.map{|item|
+ :proc => lambda { |items|
+ items = items.split(",")
+ items.compact.map do |item|
Chef::RunList::RunListItem.new(item)
- }
+ end
}
option :why_run,
- :short => '-W',
- :long => '--why-run',
- :description => 'Enable whyrun mode',
+ :short => "-W",
+ :long => "--why-run",
+ :description => "Enable whyrun mode",
:boolean => true
option :client_fork,
@@ -263,7 +276,7 @@ class Chef::Application::Client < Chef::Application
option :audit_mode,
:long => "--audit-mode MODE",
:description => "Enable audit-mode with `enabled`. Disable audit-mode with `disabled`. Skip converge and only perform audits with `audit-only`",
- :proc => lambda { |mo| mo.gsub("-", "_").to_sym }
+ :proc => lambda { |mo| mo.tr("-", "_").to_sym }
option :minimal_ohai,
:long => "--minimal-ohai",
@@ -275,6 +288,21 @@ class Chef::Application::Client < Chef::Application
:description => "Whether a local mode (-z) server binds to a port",
:boolean => true
+ option :fips,
+ :long => "--[no-]fips",
+ :description => "Enable fips mode",
+ :boolean => true
+
+ option :delete_entire_chef_repo,
+ :long => "--delete-entire-chef-repo",
+ :description => "DANGEROUS: does what it says, only useful with --recipe-url",
+ :boolean => true
+
+ option :skip_cookbook_sync,
+ :long => "--[no-]skip-cookbook-sync",
+ :description => "Use cached cookbooks without overwriting local differences from the server",
+ :boolean => false
+
IMMEDIATE_RUN_SIGNAL = "1".freeze
attr_reader :chef_client_json
@@ -284,10 +312,12 @@ class Chef::Application::Client < Chef::Application
def reconfigure
super
- raise Chef::Exceptions::PIDFileLockfileMatch if Chef::Util::PathHelper.paths_eql? (Chef::Config[:pid_file] || '' ), (Chef::Config[:lockfile] || '')
+ raise Chef::Exceptions::PIDFileLockfileMatch if Chef::Util::PathHelper.paths_eql? (Chef::Config[:pid_file] || "" ), (Chef::Config[:lockfile] || "")
set_specific_recipes
+ Chef::Config[:fips] = config[:fips] if config.has_key? :fips
+
Chef::Config[:chef_server_url] = config[:chef_server_url] if config.has_key? :chef_server_url
Chef::Config.local_mode = config[:local_mode] if config.has_key?(:local_mode)
@@ -301,15 +331,20 @@ class Chef::Application::Client < Chef::Application
Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Dir.pwd)
end
- if !Chef::Config.local_mode && Chef::Config.has_key?(:recipe_url)
- Chef::Application.fatal!("chef-client recipe-url can be used only in local-mode", 1)
- elsif Chef::Config.local_mode && Chef::Config.has_key?(:recipe_url)
- Chef::Log.debug "Creating path #{Chef::Config.chef_repo_path} to extract recipes into"
- FileUtils.mkdir_p(Chef::Config.chef_repo_path)
- tarball_path = File.join(Chef::Config.chef_repo_path, 'recipes.tgz')
- fetch_recipe_tarball(Chef::Config[:recipe_url], tarball_path)
- result = shell_out!("tar zxvf #{tarball_path} -C #{Chef::Config.chef_repo_path}")
- Chef::Log.debug "#{result.stdout}"
+ if Chef::Config[:recipe_url]
+ if !Chef::Config.local_mode
+ Chef::Application.fatal!("chef-client recipe-url can be used only in local-mode")
+ else
+ if Chef::Config[:delete_entire_chef_repo]
+ Chef::Log.debug "Cleanup path #{Chef::Config.chef_repo_path} before extract recipes into it"
+ FileUtils.rm_rf(recipes_path, :secure => true)
+ end
+ Chef::Log.debug "Creating path #{Chef::Config.chef_repo_path} to extract recipes into"
+ FileUtils.mkdir_p(Chef::Config.chef_repo_path)
+ tarball_path = File.join(Chef::Config.chef_repo_path, "recipes.tgz")
+ fetch_recipe_tarball(Chef::Config[:recipe_url], tarball_path)
+ Mixlib::Archive.new(tarball_path).extract(Chef::Config.chef_repo_path, perms: false, ignore: /^\.$/)
+ end
end
Chef::Config.chef_zero.host = config[:chef_zero_host] if config[:chef_zero_host]
@@ -349,7 +384,12 @@ class Chef::Application::Client < Chef::Application
config[:config_file] = Chef::Config.platform_specific_path("/etc/chef/client.rb")
end
end
+
+ # Load the client.rb configuration
super
+
+ # Load all config files in client.d
+ load_dot_d(Chef::Config[:client_d_dir]) if Chef::Config[:client_d_dir]
end
def configure_logging
@@ -388,7 +428,7 @@ class Chef::Application::Client < Chef::Application
rescue SystemExit
raise
rescue Exception => e
- Chef::Application.fatal!("#{e.class}: #{e.message}", 1)
+ Chef::Application.fatal!("#{e.class}: #{e.message}", e)
end
else
interval_run_chef_client
@@ -396,36 +436,42 @@ class Chef::Application::Client < Chef::Application
end
private
+
def interval_run_chef_client
if Chef::Config[:daemonize]
Chef::Daemon.daemonize("chef-client")
+
+ # Start first daemonized run after configured number of seconds
+ if Chef::Config[:daemonize].is_a?(Integer)
+ sleep_then_run_chef_client(Chef::Config[:daemonize])
+ end
end
loop do
- begin
- @signal = test_signal
- if @signal != IMMEDIATE_RUN_SIGNAL
- sleep_sec = time_to_sleep
- Chef::Log.debug("Sleeping for #{sleep_sec} seconds")
- interval_sleep(sleep_sec)
- end
-
- @signal = nil
- run_chef_client(Chef::Config[:specific_recipes])
+ sleep_then_run_chef_client(time_to_sleep)
+ Chef::Application.exit!("Exiting", 0) if !Chef::Config[:interval]
+ end
+ end
- Chef::Application.exit!("Exiting", 0) if !Chef::Config[:interval]
- rescue SystemExit => e
- raise
- rescue Exception => e
- if Chef::Config[:interval]
- Chef::Log.error("#{e.class}: #{e}")
- Chef::Log.debug("#{e.class}: #{e}\n#{e.backtrace.join("\n")}")
- retry
- else
- Chef::Application.fatal!("#{e.class}: #{e.message}", 1)
- end
- end
+ def sleep_then_run_chef_client(sleep_sec)
+ @signal = test_signal
+ unless @signal == IMMEDIATE_RUN_SIGNAL
+ Chef::Log.debug("Sleeping for #{sleep_sec} seconds")
+ interval_sleep(sleep_sec)
+ end
+ @signal = nil
+
+ run_chef_client(Chef::Config[:specific_recipes])
+ rescue SystemExit => e
+ raise
+ rescue Exception => e
+ if Chef::Config[:interval]
+ Chef::Log.error("#{e.class}: #{e}")
+ Chef::Log.debug("#{e.class}: #{e}\n#{e.backtrace.join("\n")}")
+ retry
end
+
+ Chef::Application.fatal!("#{e.class}: #{e.message}", e)
end
def test_signal
@@ -449,22 +495,22 @@ class Chef::Application::Client < Chef::Application
end
def client_sleep(sec)
- IO.select([ SELF_PIPE[0] ], nil, nil, sec) or return
+ return unless IO.select([ SELF_PIPE[0] ], nil, nil, sec)
@signal = SELF_PIPE[0].getc.chr
end
def unforked_interval_error_message
"Unforked chef-client interval runs are disabled in Chef 12." +
- "\nConfiguration settings:" +
- "#{"\n interval = #{Chef::Config[:interval]} seconds" if Chef::Config[:interval]}" +
- "\nEnable chef-client interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options."
+ "\nConfiguration settings:" +
+ "#{"\n interval = #{Chef::Config[:interval]} seconds" if Chef::Config[:interval]}" +
+ "\nEnable chef-client interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options."
end
def audit_mode_settings_explanation
"\n* To enable audit mode after converge, use command line option `--audit-mode enabled` or set `audit_mode :enabled` in your config file." +
- "\n* To disable audit mode, use command line option `--audit-mode disabled` or set `audit_mode :disabled` in your config file." +
- "\n* To only run audit mode, use command line option `--audit-mode audit-only` or set `audit_mode :audit_only` in your config file." +
- "\nAudit mode is disabled by default."
+ "\n* To disable audit mode, use command line option `--audit-mode disabled` or set `audit_mode :disabled` in your config file." +
+ "\n* To only run audit mode, use command line option `--audit-mode audit-only` or set `audit_mode :audit_only` in your config file." +
+ "\nAudit mode is disabled by default."
end
def unrecognized_audit_mode(mode)
@@ -473,7 +519,7 @@ class Chef::Application::Client < Chef::Application
def fetch_recipe_tarball(url, path)
Chef::Log.debug("Download recipes tarball from #{url} to #{path}")
- File.open(path, 'wb') do |f|
+ File.open(path, "wb") do |f|
open(url) do |r|
f.write(r.read)
end
diff --git a/lib/chef/application/exit_code.rb b/lib/chef/application/exit_code.rb
new file mode 100644
index 0000000000..610a356a7c
--- /dev/null
+++ b/lib/chef/application/exit_code.rb
@@ -0,0 +1,233 @@
+#
+# Author:: Steven Murawski (<smurawski@chef.io>)
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Application
+
+ # These are the exit codes defined in Chef RFC 062
+ # https://github.com/chef/chef-rfc/blob/master/rfc062-exit-status.md
+ class ExitCode
+
+ # -1 is defined as DEPRECATED_FAILURE in RFC 062, so it is
+ # not enumerated in an active constant.
+ #
+ VALID_RFC_062_EXIT_CODES = {
+ SUCCESS: 0,
+ GENERIC_FAILURE: 1,
+ SIGINT_RECEIVED: 2,
+ SIGTERM_RECEIVED: 3,
+ REBOOT_SCHEDULED: 35,
+ REBOOT_NEEDED: 37,
+ REBOOT_FAILED: 41,
+ AUDIT_MODE_FAILURE: 42,
+ CLIENT_UPGRADED: 213,
+ }
+
+ DEPRECATED_RFC_062_EXIT_CODES = {
+ DEPRECATED_FAILURE: -1,
+ }
+
+ class << self
+
+ def normalize_exit_code(exit_code = nil)
+ if normalization_not_configured?
+ normalize_legacy_exit_code_with_warning(exit_code)
+ elsif normalization_disabled?
+ normalize_legacy_exit_code(exit_code)
+ else
+ normalize_exit_code_to_rfc(exit_code)
+ end
+ end
+
+ def enforce_rfc_062_exit_codes?
+ !normalization_disabled? && !normalization_not_configured?
+ end
+
+ def notify_reboot_exit_code_deprecation
+ return if normalization_disabled?
+ notify_on_deprecation(reboot_deprecation_warning)
+ end
+
+ def notify_deprecated_exit_code
+ return if normalization_disabled?
+ notify_on_deprecation(deprecation_warning)
+ end
+
+ private
+
+ def normalization_disabled?
+ Chef::Config[:exit_status] == :disabled
+ end
+
+ def normalization_not_configured?
+ Chef::Config[:exit_status].nil?
+ end
+
+ def normalize_legacy_exit_code_with_warning(exit_code)
+ normalized_exit_code = normalize_legacy_exit_code(exit_code)
+ unless valid_exit_codes.include? normalized_exit_code
+ notify_on_deprecation(deprecation_warning)
+ end
+ normalized_exit_code
+ end
+
+ def normalize_legacy_exit_code(exit_code)
+ case exit_code
+ when Integer
+ exit_code
+ when Exception
+ lookup_exit_code_by_exception(exit_code)
+ else
+ default_exit_code
+ end
+ end
+
+ def normalize_exit_code_to_rfc(exit_code)
+ normalized_exit_code = normalize_legacy_exit_code_with_warning(exit_code)
+ if valid_exit_codes.include? normalized_exit_code
+ normalized_exit_code
+ else
+ VALID_RFC_062_EXIT_CODES[:GENERIC_FAILURE]
+ end
+ end
+
+ def lookup_exit_code_by_exception(exception)
+ if sigint_received?(exception)
+ VALID_RFC_062_EXIT_CODES[:SIGINT_RECEIVED]
+ elsif sigterm_received?(exception)
+ VALID_RFC_062_EXIT_CODES[:SIGTERM_RECEIVED]
+ elsif normalization_disabled? || normalization_not_configured?
+ if legacy_exit_code?(exception)
+ # We have lots of "Chef::Application.fatal!('', 2)
+ # This maintains that behavior at initial introduction
+ # and when the RFC exit_status compliance is disabled.
+ VALID_RFC_062_EXIT_CODES[:SIGINT_RECEIVED]
+ else
+ VALID_RFC_062_EXIT_CODES[:GENERIC_FAILURE]
+ end
+ elsif reboot_scheduled?(exception)
+ VALID_RFC_062_EXIT_CODES[:REBOOT_SCHEDULED]
+ elsif reboot_needed?(exception)
+ VALID_RFC_062_EXIT_CODES[:REBOOT_NEEDED]
+ elsif reboot_failed?(exception)
+ VALID_RFC_062_EXIT_CODES[:REBOOT_FAILED]
+ elsif audit_failure?(exception)
+ VALID_RFC_062_EXIT_CODES[:AUDIT_MODE_FAILURE]
+ elsif client_upgraded?(exception)
+ VALID_RFC_062_EXIT_CODES[:CLIENT_UPGRADED]
+ else
+ VALID_RFC_062_EXIT_CODES[:GENERIC_FAILURE]
+ end
+ end
+
+ def legacy_exit_code?(exception)
+ resolve_exception_array(exception).any? do |e|
+ e.is_a? Chef::Exceptions::DeprecatedExitCode
+ end
+ end
+
+ def reboot_scheduled?(exception)
+ resolve_exception_array(exception).any? do |e|
+ e.is_a? Chef::Exceptions::Reboot
+ end
+ end
+
+ def reboot_needed?(exception)
+ resolve_exception_array(exception).any? do |e|
+ e.is_a? Chef::Exceptions::RebootPending
+ end
+ end
+
+ def reboot_failed?(exception)
+ resolve_exception_array(exception).any? do |e|
+ e.is_a? Chef::Exceptions::RebootFailed
+ end
+ end
+
+ def audit_failure?(exception)
+ resolve_exception_array(exception).any? do |e|
+ e.is_a? Chef::Exceptions::AuditError
+ end
+ end
+
+ def client_upgraded?(exception)
+ resolve_exception_array(exception).any? do |e|
+ e.is_a? Chef::Exceptions::ClientUpgraded
+ end
+ end
+
+ def sigint_received?(exception)
+ resolve_exception_array(exception).any? do |e|
+ e.is_a? Chef::Exceptions::SigInt
+ end
+ end
+
+ def sigterm_received?(exception)
+ resolve_exception_array(exception).any? do |e|
+ e.is_a? Chef::Exceptions::SigTerm
+ end
+ end
+
+ def resolve_exception_array(exception)
+ exception_array = [exception]
+ if exception.respond_to?(:wrapped_errors)
+ exception.wrapped_errors.each do |e|
+ exception_array.push e
+ end
+ end
+ exception_array
+ end
+
+ def valid_exit_codes
+ VALID_RFC_062_EXIT_CODES.values
+ end
+
+ def notify_on_deprecation(message)
+ Chef.deprecated(:exit_code, message)
+ rescue Chef::Exceptions::DeprecatedFeatureError
+ # Have to rescue this, otherwise this unhandled error preempts
+ # the current exit code assignment.
+ end
+
+ def deprecation_warning
+ "Chef RFC 062 (https://github.com/chef/chef-rfc/blob/master/rfc062-exit-status.md) defines the" \
+ " exit codes that should be used with Chef. Chef::Application::ExitCode defines valid exit codes" \
+ " In a future release, non-standard exit codes will be redefined as" \
+ " GENERIC_FAILURE unless `exit_status` is set to `:disabled` in your client.rb."
+ end
+
+ def reboot_deprecation_warning
+ "Per RFC 062 (https://github.com/chef/chef-rfc/blob/master/rfc062-exit-status.md)" \
+ ", when a reboot is requested Chef Client will exit with an exit code of 35, REBOOT_SCHEDULED." \
+ " To maintain the current behavior (an exit code of 0), you will need to set `exit_status` to" \
+ " `:disabled` in your client.rb"
+ end
+
+ def default_exit_code
+ if normalization_disabled? || normalization_not_configured?
+ DEPRECATED_RFC_062_EXIT_CODES[:DEPRECATED_FAILURE]
+ else
+ VALID_RFC_062_EXIT_CODES[:GENERIC_FAILURE]
+ end
+ end
+
+ end
+ end
+
+ end
+end
diff --git a/lib/chef/application/knife.rb b/lib/chef/application/knife.rb
index d169a5dab5..521011348f 100644
--- a/lib/chef/application/knife.rb
+++ b/lib/chef/application/knife.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,11 +15,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/knife'
-require 'chef/application'
-require 'mixlib/log'
-require 'ohai/config'
-require 'chef/monkey_patches/net_http.rb'
+require "chef/knife"
+require "chef/application"
+require "mixlib/log"
+require "ohai/config"
+require "chef/monkey_patches/net_http.rb"
class Chef::Application::Knife < Chef::Application
@@ -33,16 +33,24 @@ class Chef::Application::Knife < Chef::Application
:description => "The configuration file to use",
:proc => lambda { |path| File.expand_path(path, Dir.pwd) }
+ option :config_option,
+ :long => "--config-option OPTION=VALUE",
+ :description => "Override a single configuration option",
+ :proc => lambda { |option, existing|
+ (existing ||= []) << option
+ existing
+ }
+
verbosity_level = 0
option :verbosity,
- :short => '-V',
- :long => '--verbose',
+ :short => "-V",
+ :long => "--verbose",
:description => "More verbose output. Use twice for max verbosity",
- :proc => Proc.new { verbosity_level += 1},
+ :proc => Proc.new { verbosity_level += 1 },
:default => 0
option :color,
- :long => '--[no-]color',
+ :long => "--[no-]color",
:boolean => true,
:default => true,
:description => "Use colored output, defaults to enabled"
@@ -56,14 +64,14 @@ class Chef::Application::Knife < Chef::Application
:short => "-e EDITOR",
:long => "--editor EDITOR",
:description => "Set the editor to use for interactive commands",
- :default => ENV['EDITOR']
+ :default => ENV["EDITOR"]
option :disable_editing,
:short => "-d",
:long => "--disable-editing",
:description => "Do not open EDITOR, just accept the data as is",
:boolean => true,
- :default => false
+ :default => false
option :help,
:short => "-h",
@@ -131,9 +139,15 @@ class Chef::Application::Knife < Chef::Application
:long => "--version",
:description => "Show chef version",
:boolean => true,
- :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+ :proc => lambda { |v| puts "Chef: #{::Chef::VERSION}" },
:exit => 0
+ option :fips,
+ :long => "--[no-]fips",
+ :description => "Enable fips mode",
+ :boolean => true,
+ :default => nil
+
# Run knife
def run
Mixlib::Log::Formatter.show_time = false
@@ -161,8 +175,8 @@ class Chef::Application::Knife < Chef::Application
if no_command_given?
print_help_and_exit(1, NO_COMMAND_GIVEN)
elsif no_subcommand_given?
- if (want_help? || want_version?)
- print_help_and_exit
+ if want_help? || want_version?
+ print_help_and_exit(0)
else
print_help_and_exit(2, NO_COMMAND_GIVEN)
end
@@ -185,15 +199,15 @@ class Chef::Application::Knife < Chef::Application
ARGV[0] =~ /^(--version|-v)$/
end
- def print_help_and_exit(exitcode=1, fatal_message=nil)
+ def print_help_and_exit(exitcode = 1, fatal_message = nil)
Chef::Log.error(fatal_message) if fatal_message
begin
- self.parse_options
+ parse_options
rescue OptionParser::InvalidOption => e
puts "#{e}\n"
end
- puts self.opt_parser
+ puts opt_parser
puts
Chef::Knife.list_commands
exit exitcode
diff --git a/lib/chef/application/solo.rb b/lib/chef/application/solo.rb
index 4b472e9662..1481338a9c 100644
--- a/lib/chef/application/solo.rb
+++ b/lib/chef/application/solo.rb
@@ -1,7 +1,7 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Author:: Mark Mzyk (mmzyk@opscode.com)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Author:: Mark Mzyk (mmzyk@chef.io)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,24 +16,39 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef'
-require 'chef/application'
-require 'chef/client'
-require 'chef/config'
-require 'chef/daemon'
-require 'chef/log'
-require 'chef/rest'
-require 'chef/config_fetcher'
-require 'fileutils'
+require "chef"
+require "chef/application"
+require "chef/application/client"
+require "chef/client"
+require "chef/config"
+require "chef/daemon"
+require "chef/log"
+require "chef/rest"
+require "chef/config_fetcher"
+require "fileutils"
+require "chef/mixin/shell_out"
+require "pathname"
+require "chef-config/mixin/dot_d"
+require "mixlib/archive"
class Chef::Application::Solo < Chef::Application
+ include Chef::Mixin::ShellOut
+ include ChefConfig::Mixin::DotD
option :config_file,
:short => "-c CONFIG",
:long => "--config CONFIG",
- :default => Chef::Config.platform_specific_path('/etc/chef/solo.rb'),
+ :default => Chef::Config.platform_specific_path("/etc/chef/solo.rb"),
:description => "The configuration file to use"
+ option :config_option,
+ :long => "--config-option OPTION=VALUE",
+ :description => "Override a single configuration option",
+ :proc => lambda { |option, existing|
+ (existing ||= []) << option
+ existing
+ }
+
option :formatter,
:short => "-F FORMATTER",
:long => "--format FORMATTER",
@@ -59,7 +74,7 @@ class Chef::Application::Solo < Chef::Application
:default => false
option :color,
- :long => '--[no-]color',
+ :long => "--[no-]color",
:boolean => true,
:default => !Chef::Platform.windows?,
:description => "Use colored output, defaults to enabled"
@@ -135,28 +150,27 @@ class Chef::Application::Solo < Chef::Application
:proc => lambda { |s| s.to_i }
option :recipe_url,
- :short => "-r RECIPE_URL",
- :long => "--recipe-url RECIPE_URL",
- :description => "Pull down a remote gzipped tarball of recipes and untar it to the cookbook cache.",
- :proc => nil
+ :short => "-r RECIPE_URL",
+ :long => "--recipe-url RECIPE_URL",
+ :description => "Pull down a remote gzipped tarball of recipes and untar it to the cookbook cache."
option :version,
:short => "-v",
:long => "--version",
:description => "Show chef version",
:boolean => true,
- :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+ :proc => lambda { |v| puts "Chef: #{::Chef::VERSION}" },
:exit => 0
option :override_runlist,
:short => "-o RunlistItem,RunlistItem...",
:long => "--override-runlist RunlistItem,RunlistItem...",
:description => "Replace current run list with specified items",
- :proc => lambda{|items|
- items = items.split(',')
- items.compact.map{|item|
+ :proc => lambda { |items|
+ items = items.split(",")
+ items.compact.map do |item|
Chef::RunList::RunListItem.new(item)
- }
+ end
}
option :client_fork,
@@ -166,20 +180,20 @@ class Chef::Application::Solo < Chef::Application
:boolean => true
option :why_run,
- :short => '-W',
- :long => '--why-run',
- :description => 'Enable whyrun mode',
+ :short => "-W",
+ :long => "--why-run",
+ :description => "Enable whyrun mode",
:boolean => true
option :ez,
- :long => '--ez',
- :description => 'A memorial for Ezra Zygmuntowicz',
+ :long => "--ez",
+ :description => "A memorial for Ezra Zygmuntowicz",
:boolean => true
option :environment,
- :short => '-E ENVIRONMENT',
- :long => '--environment ENVIRONMENT',
- :description => 'Set the Chef Environment on the node'
+ :short => "-E ENVIRONMENT",
+ :long => "--environment ENVIRONMENT",
+ :description => "Set the Chef Environment on the node"
option :run_lock_timeout,
:long => "--run-lock-timeout SECONDS",
@@ -191,19 +205,65 @@ class Chef::Application::Solo < Chef::Application
:description => "Only run the bare minimum ohai plugins chef needs to function",
:boolean => true
+ option :delete_entire_chef_repo,
+ :long => "--delete-entire-chef-repo",
+ :description => "DANGEROUS: does what it says, only useful with --recipe-url",
+ :boolean => true
+
+ option :solo_legacy_mode,
+ :long => "--legacy-mode",
+ :description => "Run chef-solo in legacy mode",
+ :boolean => true
+
attr_reader :chef_client_json
- def initialize
- super
+ # Get this party started
+ def run
+ setup_signal_handlers
+ reconfigure
+ for_ezra if Chef::Config[:ez]
+ if !Chef::Config[:solo_legacy_mode]
+ Chef::Application::Client.new.run
+ else
+ setup_application
+ run_application
+ end
end
def reconfigure
super
+ load_dot_d(Chef::Config[:solo_d_dir]) if Chef::Config[:solo_d_dir]
+
set_specific_recipes
Chef::Config[:solo] = true
+ Chef::Log.deprecation("-r MUST be changed to --recipe-url, the -r option will be changed in Chef 13.0") if ARGV.include?("-r")
+
+ if !Chef::Config[:solo_legacy_mode]
+ # Because we re-parse ARGV when we move to chef-client, we need to tidy up some options first.
+ ARGV.delete("--ez")
+
+ # -r means something entirely different in chef-client land, so let's replace it with a "safe" value
+ if dash_r = ARGV.index("-r")
+ ARGV[dash_r] = "--recipe-url"
+ end
+
+ # For back compat reasons, we need to ensure that we try and use the cache_path as a repo first
+ Chef::Log.debug "Current chef_repo_path is #{Chef::Config.chef_repo_path}"
+
+ if !Chef::Config.has_key?(:cookbook_path) && !Chef::Config.has_key?(:chef_repo_path)
+ Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Chef::Config[:cache_path])
+ end
+
+ Chef::Config[:local_mode] = true
+ else
+ configure_legacy_mode!
+ end
+ end
+
+ def configure_legacy_mode!
if Chef::Config[:daemonize]
Chef::Config[:interval] ||= 1800
end
@@ -211,16 +271,18 @@ class Chef::Application::Solo < Chef::Application
Chef::Application.fatal!(unforked_interval_error_message) if !Chef::Config[:client_fork] && Chef::Config[:interval]
if Chef::Config[:recipe_url]
- cookbooks_path = Array(Chef::Config[:cookbook_path]).detect{|e| e =~ /\/cookbooks\/*$/ }
- recipes_path = File.expand_path(File.join(cookbooks_path, '..'))
+ cookbooks_path = Array(Chef::Config[:cookbook_path]).detect { |e| Pathname.new(e).cleanpath.to_s =~ /\/cookbooks\/*$/ }
+ recipes_path = File.expand_path(File.join(cookbooks_path, ".."))
- Chef::Log.debug "Cleanup path #{recipes_path} before extract recipes into it"
- FileUtils.rm_rf(recipes_path, :secure => true)
+ if Chef::Config[:delete_entire_chef_repo]
+ Chef::Log.debug "Cleanup path #{recipes_path} before extract recipes into it"
+ FileUtils.rm_rf(recipes_path, :secure => true)
+ end
Chef::Log.debug "Creating path #{recipes_path} to extract recipes into"
FileUtils.mkdir_p(recipes_path)
- tarball_path = File.join(recipes_path, 'recipes.tgz')
+ tarball_path = File.join(recipes_path, "recipes.tgz")
fetch_recipe_tarball(Chef::Config[:recipe_url], tarball_path)
- Mixlib::ShellOut.new("tar zxvf #{tarball_path} -C #{recipes_path}").run_command
+ Mixlib::Archive.new(tarball_path).extract(Chef::Config.chef_repo_path, perms: false, ignore: /^\.$/)
end
# json_attribs shuld be fetched after recipe_url tarball is unpacked.
@@ -239,7 +301,6 @@ class Chef::Application::Solo < Chef::Application
end
def run_application
- for_ezra if Chef::Config[:ez]
if !Chef::Config[:client_fork] || Chef::Config[:once]
# Run immediately without interval sleep or splay
begin
@@ -247,14 +308,13 @@ class Chef::Application::Solo < Chef::Application
rescue SystemExit
raise
rescue Exception => e
- Chef::Application.fatal!("#{e.class}: #{e.message}", 1)
+ Chef::Application.fatal!("#{e.class}: #{e.message}", e)
end
else
interval_run_chef_client
end
end
-
private
def for_ezra
@@ -295,7 +355,7 @@ EOH
Chef::Log.debug("#{e.class}: #{e}\n#{e.backtrace.join("\n")}")
retry
else
- Chef::Application.fatal!("#{e.class}: #{e.message}", 1)
+ Chef::Application.fatal!("#{e.class}: #{e.message}", e)
end
end
end
@@ -303,7 +363,7 @@ EOH
def fetch_recipe_tarball(url, path)
Chef::Log.debug("Download recipes tarball from #{url} to #{path}")
- File.open(path, 'wb') do |f|
+ File.open(path, "wb") do |f|
open(url) do |r|
f.write(r.read)
end
@@ -312,8 +372,8 @@ EOH
def unforked_interval_error_message
"Unforked chef-client interval runs are disabled in Chef 12." +
- "\nConfiguration settings:" +
- "#{"\n interval = #{Chef::Config[:interval]} seconds" if Chef::Config[:interval]}" +
- "\nEnable chef-client interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options."
+ "\nConfiguration settings:" +
+ "#{"\n interval = #{Chef::Config[:interval]} seconds" if Chef::Config[:interval]}" +
+ "\nEnable chef-client interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options."
end
end
diff --git a/lib/chef/application/windows_service.rb b/lib/chef/application/windows_service.rb
index 2551582c3a..7bc68a586d 100644
--- a/lib/chef/application/windows_service.rb
+++ b/lib/chef/application/windows_service.rb
@@ -1,6 +1,6 @@
#
# Author:: Christopher Maier (<maier@lambda.local>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,19 @@
# limitations under the License.
#
-require 'chef'
-require 'chef/monologger'
-require 'chef/application'
-require 'chef/client'
-require 'chef/config'
-require 'chef/handler/error_report'
-require 'chef/log'
-require 'chef/rest'
-require 'mixlib/cli'
-require 'socket'
-require 'uri'
-require 'win32/daemon'
-require 'chef/mixin/shell_out'
+require "chef"
+require "chef/monologger"
+require "chef/application"
+require "chef/client"
+require "chef/config"
+require "chef/handler/error_report"
+require "chef/log"
+require "chef/http"
+require "mixlib/cli"
+require "socket"
+require "uri"
+require "win32/daemon"
+require "chef/mixin/shell_out"
class Chef
class Application
@@ -45,8 +45,7 @@ class Chef
option :log_location,
:short => "-L LOGLOCATION",
:long => "--logfile LOGLOCATION",
- :description => "Set the log file location",
- :default => "#{ENV['SYSTEMDRIVE']}/chef/client.log"
+ :description => "Set the log file location"
option :splay,
:short => "-s SECONDS",
@@ -60,6 +59,8 @@ class Chef
:description => "Set the number of seconds to wait between chef-client runs",
:proc => lambda { |s| s.to_i }
+ DEFAULT_LOG_LOCATION ||= "#{ENV['SYSTEMDRIVE']}/chef/client.log"
+
def service_init
@service_action_mutex = Mutex.new
@service_signal = ConditionVariable.new
@@ -73,7 +74,7 @@ class Chef
# Set the initial timeout to splay sleep time
timeout = rand Chef::Config[:splay]
- while running? do
+ while running?
# Grab the service_action_mutex to make a chef-client run
@service_action_mutex.synchronize do
begin
@@ -182,34 +183,38 @@ class Chef
# The chef client will be started in a new process. We have used shell_out to start the chef-client.
# The log_location and config_file of the parent process is passed to the new chef-client process.
# We need to add the --no-fork, as by default it is set to fork=true.
- begin
- Chef::Log.info "Starting chef-client in a new process"
- # Pass config params to the new process
- config_params = " --no-fork"
- config_params += " -c #{Chef::Config[:config_file]}" unless Chef::Config[:config_file].nil?
- config_params += " -L #{Chef::Config[:log_location]}" unless Chef::Config[:log_location] == STDOUT
- # Starts a new process and waits till the process exits
- result = shell_out(
- "chef-client #{config_params}",
- :timeout => Chef::Config[:windows_service][:watchdog_timeout],
- :logger => Chef::Log
- )
- Chef::Log.debug "#{result.stdout}"
- Chef::Log.debug "#{result.stderr}"
- rescue Mixlib::ShellOut::CommandTimeout => e
- Chef::Log.error "chef-client timed out\n(#{e})"
- Chef::Log.error(<<-EOF)
- Your chef-client run timed out. You can increase the time chef-client is given
+
+ Chef::Log.info "Starting chef-client in a new process"
+ # Pass config params to the new process
+ config_params = " --no-fork"
+ config_params += " -c #{Chef::Config[:config_file]}" unless Chef::Config[:config_file].nil?
+ # log_location might be an event logger and if so we cannot pass as a command argument
+ # but shed no tears! If the logger is an event logger, it must have been configured
+ # as such in the config file and chef-client will use that when no arg is passed here
+ config_params += " -L #{resolve_log_location}" if resolve_log_location.is_a?(String)
+
+ # Starts a new process and waits till the process exits
+
+ result = shell_out(
+ "chef-client.bat #{config_params}",
+ :timeout => Chef::Config[:windows_service][:watchdog_timeout],
+ :logger => Chef::Log
+ )
+ Chef::Log.debug "#{result.stdout}"
+ Chef::Log.debug "#{result.stderr}"
+ rescue Mixlib::ShellOut::CommandTimeout => e
+ Chef::Log.error "chef-client timed out\n(#{e})"
+ Chef::Log.error(<<-EOF)
+ Your chef-client run timed out. You can increase the time chef-client is given
to complete by configuring windows_service.watchdog_timeout in your client.rb.
EOF
- rescue Mixlib::ShellOut::ShellCommandFailed => e
- Chef::Log.warn "Not able to start chef-client in new process (#{e})"
- rescue => e
- Chef::Log.error e
- ensure
- # Once process exits, we log the current process' pid
- Chef::Log.info "Child process exited (pid: #{Process.pid})"
- end
+ rescue Mixlib::ShellOut::ShellCommandFailed => e
+ Chef::Log.warn "Not able to start chef-client in new process (#{e})"
+ rescue => e
+ Chef::Log.error e
+ ensure
+ # Once process exits, we log the current process' pid
+ Chef::Log.info "Child process exited (pid: #{Process.pid})"
end
def apply_config(config_file_path)
@@ -219,12 +224,12 @@ class Chef
# Lifted from Chef::Application, with addition of optional startup parameters
# for playing nicely with Windows Services
- def reconfigure(startup_parameters=[])
+ def reconfigure(startup_parameters = [])
configure_chef startup_parameters
configure_logging
Chef::Config[:chef_server_url] = config[:chef_server_url] if config.has_key? :chef_server_url
- unless Chef::Config[:exception_handlers].any? {|h| Chef::Handler::ErrorReport === h}
+ unless Chef::Config[:exception_handlers].any? { |h| Chef::Handler::ErrorReport === h }
Chef::Config[:exception_handlers] << Chef::Handler::ErrorReport.new
end
@@ -235,7 +240,7 @@ class Chef
# See application.rb for related comments.
def configure_logging
- Chef::Log.init(MonoLogger.new(Chef::Config[:log_location]))
+ Chef::Log.init(MonoLogger.new(resolve_log_location))
if want_additional_logger?
configure_stdout_logger
end
@@ -245,7 +250,7 @@ class Chef
def configure_stdout_logger
stdout_logger = MonoLogger.new(STDOUT)
stdout_logger.formatter = Chef::Log.logger.formatter
- Chef::Log.loggers << stdout_logger
+ Chef::Log.loggers << stdout_logger
end
# Based on config and whether or not STDOUT is a tty, should we setup a
@@ -264,6 +269,11 @@ class Chef
Chef::Config[:log_level] == :auto
end
+ def resolve_log_location
+ # STDOUT is the default log location, but makes no sense for a windows service
+ Chef::Config[:log_location] == STDOUT ? DEFAULT_LOG_LOCATION : Chef::Config[:log_location]
+ end
+
# if log_level is `:auto`, convert it to :warn (when using output formatter)
# or :info (no output formatter). See also +using_output_formatter?+
def resolve_log_level
@@ -297,22 +307,22 @@ class Chef
begin
case config[:config_file]
when /^(http|https):\/\//
- Chef::REST.new("", nil, nil).fetch(config[:config_file]) { |f| apply_config(f.path) }
+ Chef::HTTP.new("").streaming_request(config[:config_file]) { |f| apply_config(f.path) }
else
- ::File::open(config[:config_file]) { |f| apply_config(f.path) }
+ ::File.open(config[:config_file]) { |f| apply_config(f.path) }
end
- rescue Errno::ENOENT => error
+ rescue Errno::ENOENT
Chef::Log.warn("*****************************************")
Chef::Log.warn("Did not find config file: #{config[:config_file]}, using command line options.")
Chef::Log.warn("*****************************************")
Chef::Config.merge!(config)
- rescue SocketError => error
- Chef::Application.fatal!("Error getting config file #{Chef::Config[:config_file]}", 2)
+ rescue SocketError
+ Chef::Application.fatal!("Error getting config file #{Chef::Config[:config_file]}", Chef::Exceptions::DeprecatedExitCode.new)
rescue Chef::Exceptions::ConfigurationError => error
- Chef::Application.fatal!("Error processing config file #{Chef::Config[:config_file]} with error #{error.message}", 2)
+ Chef::Application.fatal!("Error processing config file #{Chef::Config[:config_file]} with error #{error.message}", Chef::Exceptions::DeprecatedExitCode.new)
rescue Exception => error
- Chef::Application.fatal!("Unknown error processing config file #{Chef::Config[:config_file]} with error #{error.message}", 2)
+ Chef::Application.fatal!("Unknown error processing config file #{Chef::Config[:config_file]} with error #{error.message}", Chef::Exceptions::DeprecatedExitCode.new)
end
end
@@ -323,5 +333,5 @@ end
# To run this file as a service, it must be called as a script from within
# the Windows Service framework. In that case, kick off the main loop!
if __FILE__ == $0
- Chef::Application::WindowsService.mainloop
+ Chef::Application::WindowsService.mainloop
end
diff --git a/lib/chef/application/windows_service_manager.rb b/lib/chef/application/windows_service_manager.rb
index 44526c1720..5c572bc260 100644
--- a/lib/chef/application/windows_service_manager.rb
+++ b/lib/chef/application/windows_service_manager.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
#
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
- require 'win32/service'
+ require "win32/service"
end
-require 'chef/config'
-require 'mixlib/cli'
+require "chef/config"
+require "mixlib/cli"
class Chef
class Application
@@ -51,8 +51,7 @@ class Chef
option :log_location,
:short => "-L LOGLOCATION",
:long => "--logfile LOGLOCATION",
- :description => "Set the log file location for chef-service",
- :default => "#{ENV['SYSTEMDRIVE']}/chef/client.log"
+ :description => "Set the log file location for chef-service"
option :help,
:short => "-h",
@@ -68,7 +67,7 @@ class Chef
:long => "--version",
:description => "Show chef version",
:boolean => true,
- :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+ :proc => lambda { |v| puts "Chef: #{::Chef::VERSION}" },
:exit => 0
def initialize(service_options)
@@ -100,11 +99,11 @@ class Chef
parse_options(params)
case config[:action]
- when 'install'
+ when "install"
if service_exists?
puts "Service #{@service_name} already exists on the system."
else
- ruby = File.join(RbConfig::CONFIG['bindir'], 'ruby')
+ ruby = File.join(RbConfig::CONFIG["bindir"], "ruby")
opts = ""
opts << " -c #{config[:config_file]}" if config[:config_file]
@@ -127,35 +126,37 @@ class Chef
:password => @password,
:dependencies => @dependencies
)
- ::Win32::Service.configure(
- :service_name => @service_name,
- :delayed_start => @delayed_start
- ) unless @delayed_start.nil?
+ unless @delayed_start.nil?
+ ::Win32::Service.configure(
+ :service_name => @service_name,
+ :delayed_start => @delayed_start
+ )
+ end
puts "Service '#{@service_name}' has successfully been installed."
end
- when 'status'
+ when "status"
if !service_exists?
puts "Service #{@service_name} doesn't exist on the system."
else
puts "State of #{@service_name} service is: #{current_state}"
end
- when 'start'
+ when "start"
# TODO: allow override of startup parameters here?
- take_action('start', RUNNING)
- when 'stop'
- take_action('stop', STOPPED)
- when 'uninstall', 'delete'
- take_action('stop', STOPPED)
+ take_action("start", RUNNING)
+ when "stop"
+ take_action("stop", STOPPED)
+ when "uninstall", "delete"
+ take_action("stop", STOPPED)
unless service_exists?
puts "Service #{@service_name} doesn't exist on the system."
else
::Win32::Service.delete(@service_name)
puts "Service #{@service_name} deleted"
end
- when 'pause'
- take_action('pause', PAUSED)
- when 'resume'
- take_action('resume', RUNNING)
+ when "pause"
+ take_action("pause", PAUSED)
+ when "resume"
+ take_action("resume", RUNNING)
end
end
@@ -167,10 +168,10 @@ class Chef
PAUSED = "paused"
def service_exists?
- return ::Win32::Service.exists?(@service_name)
+ ::Win32::Service.exists?(@service_name)
end
- def take_action(action=nil, desired_state=nil)
+ def take_action(action = nil, desired_state = nil)
if service_exists?
if current_state != desired_state
::Win32::Service.send(action, @service_name)
diff --git a/lib/chef/applications.rb b/lib/chef/applications.rb
index 6a1a2e8a92..97c896e12e 100644
--- a/lib/chef/applications.rb
+++ b/lib/chef/applications.rb
@@ -1,4 +1,4 @@
-require 'chef/application/client'
-require 'chef/application/knife'
-require 'chef/application/solo'
-require 'chef/application/apply'
+require "chef/application/client"
+require "chef/application/knife"
+require "chef/application/solo"
+require "chef/application/apply"
diff --git a/lib/chef/audit/audit_event_proxy.rb b/lib/chef/audit/audit_event_proxy.rb
index b9ca39e5dc..25ff31ecb1 100644
--- a/lib/chef/audit/audit_event_proxy.rb
+++ b/lib/chef/audit/audit_event_proxy.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -60,7 +60,7 @@ class Chef
def build_control_from(example)
described_class = example.metadata[:described_class]
if described_class
- resource_type = described_class.class.name.split(':')[-1]
+ resource_type = described_class.class.name.split(":")[-1]
resource_name = described_class.name
end
@@ -70,7 +70,7 @@ class Chef
# If the innermost block has a resource instead of a string, don't include it in context
describe_groups.unshift(group[:description]) if described_class.nil?
group = group[:parent_example_group]
- while !group.nil?
+ until group.nil?
describe_groups.unshift(group[:description])
group = group[:parent_example_group]
end
@@ -78,14 +78,14 @@ class Chef
# We know all of our examples each live in a top-level `control_group` block - get this name now
outermost_group_desc = describe_groups.shift
- return outermost_group_desc, {
+ [outermost_group_desc, {
:name => example.description,
:desc => example.full_description,
:resource_type => resource_type,
:resource_name => resource_name,
:context => describe_groups,
- :line_number => example.metadata[:line_number]
- }
+ :line_number => example.metadata[:line_number],
+ }]
end
end
diff --git a/lib/chef/audit/audit_reporter.rb b/lib/chef/audit/audit_reporter.rb
index d952d8a249..8546a21bb4 100644
--- a/lib/chef/audit/audit_reporter.rb
+++ b/lib/chef/audit/audit_reporter.rb
@@ -1,7 +1,7 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
# limitations under the License.
#
-require 'chef/event_dispatch/base'
-require 'chef/audit/control_group_data'
-require 'time'
+require "chef/event_dispatch/base"
+require "chef/audit/control_group_data"
+require "time"
class Chef
class Audit
@@ -28,7 +28,7 @@ class Chef
attr_reader :rest_client, :audit_data, :ordered_control_groups, :run_status
private :rest_client, :audit_data, :ordered_control_groups, :run_status
- PROTOCOL_VERSION = '0.1.1'
+ PROTOCOL_VERSION = "0.1.1"
def initialize(rest_client)
@rest_client = rest_client
@@ -127,10 +127,8 @@ class Chef
end
Chef::Log.debug "Audit Report:\n#{Chef::JSONCompat.to_json_pretty(run_data)}"
- # Since we're posting compressed data we can not directly call post_rest which expects JSON
begin
- audit_url = rest_client.create_url(audit_history_url)
- rest_client.post(audit_url, run_data, headers)
+ rest_client.post(audit_history_url, run_data, headers)
rescue StandardError => e
if e.respond_to? :response
# 404 error code is OK. This means the version of server we're running against doesn't support
@@ -142,7 +140,11 @@ class Chef
# Save the audit report to local disk
error_file = "failed-audit-data.json"
Chef::FileCache.store(error_file, Chef::JSONCompat.to_json_pretty(run_data), 0640)
- Chef::Log.error("Failed to post audit report to server. Saving report to #{Chef::FileCache.load(error_file, false)}")
+ if Chef::Config.chef_zero.enabled
+ Chef::Log.debug("Saving audit report to #{Chef::FileCache.load(error_file, false)}")
+ else
+ Chef::Log.error("Failed to post audit report to server. Saving report to #{Chef::FileCache.load(error_file, false)}")
+ end
end
else
Chef::Log.error("Failed to post audit report to server (#{e})")
@@ -156,13 +158,13 @@ class Chef
end
def headers(additional_headers = {})
- options = {'X-Ops-Audit-Report-Protocol-Version' => PROTOCOL_VERSION}
+ options = { "X-Ops-Audit-Report-Protocol-Version" => PROTOCOL_VERSION }
options.merge(additional_headers)
end
def encode_gzip(data)
"".tap do |out|
- Zlib::GzipWriter.wrap(StringIO.new(out)){|gz| gz << data }
+ Zlib::GzipWriter.wrap(StringIO.new(out)) { |gz| gz << data }
end
end
diff --git a/lib/chef/audit/control_group_data.rb b/lib/chef/audit/control_group_data.rb
index 204d7f8070..476ebe95e9 100644
--- a/lib/chef/audit/control_group_data.rb
+++ b/lib/chef/audit/control_group_data.rb
@@ -1,7 +1,7 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'securerandom'
+require "securerandom"
class Chef
class Audit
@@ -41,7 +41,7 @@ class Chef
:run_id => run_id,
:start_time => start_time,
:end_time => end_time,
- :control_groups => control_groups.collect { |c| c.to_hash }
+ :control_groups => control_groups.collect { |c| c.to_hash },
}
end
end
@@ -49,7 +49,7 @@ class Chef
class ControlGroupData
attr_reader :name, :status, :number_succeeded, :number_failed, :controls, :metadata
- def initialize(name, metadata={})
+ def initialize(name, metadata = {})
@status = "success"
@controls = []
@number_succeeded = 0
@@ -58,7 +58,6 @@ class Chef
@metadata = metadata
end
-
def example_success(control_data)
@number_succeeded += 1
control = create_control(control_data)
@@ -80,13 +79,13 @@ class Chef
def to_hash
# We sort it so the examples appear in the output in the same order
# they appeared in the recipe
- controls.sort! {|x,y| x.line_number <=> y.line_number}
+ controls.sort! { |x, y| x.line_number <=> y.line_number }
h = {
:name => name,
:status => status,
:number_succeeded => number_succeeded,
:number_failed => number_failed,
- :controls => controls.collect { |c| c.to_hash }
+ :controls => controls.collect { |c| c.to_hash },
}
# If there is a duplicate key, metadata will overwrite it
add_display_only_data(h).merge(metadata)
@@ -105,7 +104,7 @@ class Chef
group[:id] = SecureRandom.uuid
group[:controls].collect!.with_index do |c, i|
# i is zero-indexed, and we want the display one-indexed
- c[:sequence_number] = i+1
+ c[:sequence_number] = i + 1
c
end
group
@@ -117,9 +116,9 @@ class Chef
attr_reader :name, :resource_type, :resource_name, :context, :line_number
attr_accessor :status, :details
- def initialize(control_data={})
+ def initialize(control_data = {})
control_data.each do |k, v|
- self.instance_variable_set("@#{k}", v)
+ instance_variable_set("@#{k}", v)
end
end
@@ -129,7 +128,7 @@ class Chef
:status => status,
:details => details,
:resource_type => resource_type,
- :resource_name => resource_name
+ :resource_name => resource_name,
}
h[:context] = context || []
h
diff --git a/lib/chef/audit/logger.rb b/lib/chef/audit/logger.rb
index e46f54e582..759683ccc8 100644
--- a/lib/chef/audit/logger.rb
+++ b/lib/chef/audit/logger.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,12 +15,12 @@
# limitations under the License.
#
-require 'stringio'
+require "stringio"
class Chef
class Audit
class Logger
- def self.puts(message="")
+ def self.puts(message = "")
@buffer ||= StringIO.new
@buffer.puts(message)
diff --git a/lib/chef/audit/rspec_formatter.rb b/lib/chef/audit/rspec_formatter.rb
index 074a11bed3..234202b684 100644
--- a/lib/chef/audit/rspec_formatter.rb
+++ b/lib/chef/audit/rspec_formatter.rb
@@ -1,6 +1,6 @@
#
# Author:: Serdar Sutay (<serdar@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'rspec/core'
+require "rspec/core"
class Chef
class Audit
diff --git a/lib/chef/audit/runner.rb b/lib/chef/audit/runner.rb
index 234d83ab8f..837346381c 100644
--- a/lib/chef/audit/runner.rb
+++ b/lib/chef/audit/runner.rb
@@ -1,6 +1,6 @@
#
-# Author:: Claire McQuin (<claire@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Claire McQuin (<claire@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/audit/logger'
+require "chef/audit/logger"
class Chef
class Audit
@@ -52,6 +52,7 @@ class Chef
end
private
+
# Prepare to run audits:
# - Require files
# - Configure RSpec
@@ -78,16 +79,16 @@ class Chef
# prevents Specinfra and Serverspec from modifying the RSpec configuration
# used by our spec tests.
def require_deps
- require 'rspec'
- require 'rspec/its'
- require 'specinfra'
- require 'specinfra/helper'
- require 'specinfra/helper/set'
- require 'serverspec/helper'
- require 'serverspec/matcher'
- require 'serverspec/subject'
- require 'chef/audit/audit_event_proxy'
- require 'chef/audit/rspec_formatter'
+ require "rspec"
+ require "rspec/its"
+ require "specinfra"
+ require "specinfra/helper"
+ require "specinfra/helper/set"
+ require "serverspec/helper"
+ require "serverspec/matcher"
+ require "serverspec/subject"
+ require "chef/audit/audit_event_proxy"
+ require "chef/audit/rspec_formatter"
Specinfra::Backend::Cmd.send(:include, Specinfra::Helper::Set)
end
@@ -106,6 +107,7 @@ class Chef
RSpec.configure do |c|
c.color = Chef::Config[:color]
c.expose_dsl_globally = false
+ c.project_source_dirs = Array(Chef::Config[:cookbook_path])
c.backtrace_exclusion_patterns << exclusion_pattern
end
end
@@ -146,7 +148,7 @@ class Chef
def configure_specinfra
if Chef::Platform.windows?
Specinfra.configuration.backend = :cmd
- Specinfra.configuration.os = { :family => 'windows' }
+ Specinfra.configuration.os = { :family => "windows" }
else
Specinfra.configuration.backend = :exec
end
@@ -163,7 +165,7 @@ class Chef
add_example_group_methods
run_context.audits.each do |name, group|
ctl_grp = RSpec::Core::ExampleGroup.__control_group__(*group.args, &group.block)
- RSpec.world.register(ctl_grp)
+ RSpec.world.record(ctl_grp)
end
end
diff --git a/lib/chef/chef_class.rb b/lib/chef/chef_class.rb
index 6a0d09ec96..e61fd5e1d2 100644
--- a/lib/chef/chef_class.rb
+++ b/lib/chef/chef_class.rb
@@ -1,6 +1,6 @@
#
# Author:: Lamont Granquist (<lamont@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,10 +26,13 @@
# injected" into this class by other objects and do not reference the class symbols in those files
# directly and we do not need to require those files here.
-require 'chef/platform/provider_priority_map'
-require 'chef/platform/resource_priority_map'
-require 'chef/platform/provider_handler_map'
-require 'chef/platform/resource_handler_map'
+require "chef/platform/provider_priority_map"
+require "chef/platform/resource_priority_map"
+require "chef/platform/provider_handler_map"
+require "chef/platform/resource_handler_map"
+require "chef/deprecated"
+require "chef/event_dispatch/dsl"
+require "chef/deprecated"
class Chef
class << self
@@ -56,7 +59,7 @@ class Chef
#
# @return[Chef::EventDispatch::Base] handler object
def event_handler(&block)
- dsl = Chef::EventDispatch::DSL.new('Chef client DSL')
+ dsl = Chef::EventDispatch::DSL.new("Chef client DSL")
dsl.instance_eval(&block)
end
@@ -178,14 +181,17 @@ class Chef
# these slurp in the resource+provider world, so be exceedingly lazy about requiring them
@provider_priority_map ||= Chef::Platform::ProviderPriorityMap.instance
end
+
# @api private
def resource_priority_map
@resource_priority_map ||= Chef::Platform::ResourcePriorityMap.instance
end
+
# @api private
def provider_handler_map
@provider_handler_map ||= Chef::Platform::ProviderHandlerMap.instance
end
+
# @api private
def resource_handler_map
@resource_handler_map ||= Chef::Platform::ResourceHandlerMap.instance
@@ -194,36 +200,35 @@ class Chef
#
# Emit a deprecation message.
#
- # @param message The message to send.
+ # @param type The message to send. This should be a symbol, referring to
+ # a class defined in Chef::Deprecated
+ # @param message An explicit message to display, rather than the generic one
+ # associated with the deprecation.
# @param location The location. Defaults to the caller who called you (since
# generally the person who triggered the check is the one that needs to be
# fixed).
#
# @example
- # Chef.deprecation("Deprecated!")
+ # Chef.deprecated(:my_deprecation, message: "This is deprecated!")
#
# @api private this will likely be removed in favor of an as-yet unwritten
# `Chef.log`
- def log_deprecation(message, location=nil)
- if !location
- # Pick the first caller that is *not* part of the Chef gem, that's the
- # thing the user wrote.
- chef_gem_path = File.expand_path("../..", __FILE__)
- caller(0..10).each do |c|
- if !c.start_with?(chef_gem_path)
- location = c
- break
- end
- end
- end
+ def deprecated(type, message, location = nil)
+ location ||= Chef::Log.caller_location
+ deprecation = Chef::Deprecated.create(type, message, location)
# `run_context.events` is the primary deprecation target if we're in a
# run. If we are not yet in a run, print to `Chef::Log`.
if run_context && run_context.events
- run_context.events.deprecation(message, location)
+ run_context.events.deprecation(deprecation, location)
else
- Chef::Log.deprecation(message, location)
+ Chef::Log.deprecation(deprecation, location)
end
end
+
+ def log_deprecation(message, location = nil)
+ location ||= Chef::Log.caller_location
+ Chef.deprecated(:generic, message, location)
+ end
end
# @api private Only for test dependency injection; not evenly implemented as yet.
diff --git a/lib/chef/chef_fs.rb b/lib/chef/chef_fs.rb
index bc445e53ad..43a9efd5e2 100644
--- a/lib/chef/chef_fs.rb
+++ b/lib/chef/chef_fs.rb
@@ -1,4 +1,54 @@
-require 'chef/platform'
+require "chef/platform"
+
+#
+# ChefFS was designed to be a near-1:1 translation between Chef server endpoints
+# and local data, so that it could be used for:
+#
+# 1. User editing, diffing and viewing of server content locally
+# 2. knife download, upload and diff (supporting the above scenario)
+# 3. chef-client -z (serving user repository directly)
+#
+# This is the translation between chef-zero data stores (which correspond
+# closely to server endpoints) and the ChefFS repository format.
+#
+# |-----------------------------------|-----------------------------------|
+# | chef-zero DataStore | ChefFS (repository) |
+# |-----------------------------------|-----------------------------------|
+# | <root> | org.json |
+# | association_requests/NAME | invitations.json |
+# | clients/NAME | clients/NAME.json |
+# | cookbooks/NAME/VERSION | cookbooks/NAME/metadata.rb |
+# | containers/NAME | containers/NAME.json |
+# | data/BAG/ITEM | data_bags/BAG/ITEM.json |
+# | environments/NAME | environments/NAME.json |
+# | groups/NAME | groups/NAME.json |
+# | nodes/NAME | nodes/NAME.json |
+# | policies/NAME/REVISION | policies/NAME-REVISION.json |
+# | policy_groups/NAME/policies/PNAME | policy_groups/NAME.json |
+# | roles/NAME | roles/NAME.json |
+# | sandboxes/ID | <not stored on disk, just memory> |
+# | users/NAME | members.json |
+# | file_store/COOKBOOK/VERSION/PATH | cookbooks/COOKBOOK/PATH |
+# | **/_acl | acls/**.json |
+# |-----------------------------------|-----------------------------------|
+#
+#
+# ## The Code
+#
+# There are two main entry points to ChefFS:
+#
+# - ChefServerRootDir represents the chef server (under an org) and surfaces a
+# filesystem-like interface (FSBaseObject / FSBaseDir) that maps the REST API
+# to the same format as you would have on disk.
+# - ChefRepositoryFileSystemRootDir represents the local repository where you
+# put your cookbooks, roles, policies, etc.
+#
+# Because these two map to a common directory structure, diff, upload, download,
+# and other filesystem operations, can easily be done in a generic manner.
+#
+# These are instantiated by Chef::ChefFS::Config's `chef_fs` and `local_fs`
+# methods.
+#
class Chef
module ChefFS
diff --git a/lib/chef/chef_fs/chef_fs_data_store.rb b/lib/chef/chef_fs/chef_fs_data_store.rb
index 4084fb80d3..46fe5c4dd3 100644
--- a/lib/chef/chef_fs/chef_fs_data_store.rb
+++ b/lib/chef/chef_fs/chef_fs_data_store.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/cookbook_manifest'
-require 'chef_zero/data_store/memory_store'
-require 'chef_zero/data_store/data_already_exists_error'
-require 'chef_zero/data_store/data_not_found_error'
-require 'chef/chef_fs/file_pattern'
-require 'chef/chef_fs/file_system'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/file_system/memory_root'
-require 'fileutils'
+require "chef/cookbook_manifest"
+require "chef_zero/data_store/memory_store"
+require "chef_zero/data_store/data_already_exists_error"
+require "chef_zero/data_store/data_not_found_error"
+require "chef/chef_fs/file_pattern"
+require "chef/chef_fs/file_system"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/chef_fs/file_system/memory/memory_root"
+require "fileutils"
class Chef
module ChefFS
@@ -66,13 +66,84 @@ class Chef
# - ChefFSDataStore lets cookbooks be uploaded into a temporary memory
# storage, and when the cookbook is committed, copies the files onto the
# disk in the correct place (/cookbooks/apache2/recipes/default.rb).
+ #
# 3. Data bags:
# - The Chef server expects data bags in /data/BAG/ITEM
# - The repository stores data bags in /data_bags/BAG/ITEM
#
# 4. JSON filenames are generally NAME.json in the repository (e.g. /nodes/foo.json).
#
+ # 5. Org membership:
+ # chef-zero stores user membership in an org as a series of empty files.
+ # If an org has jkeiser and cdoherty as members, chef-zero expects these
+ # files to exist:
+ #
+ # - `users/jkeiser` (content: '{}')
+ # - `users/cdoherty` (content: '{}')
+ #
+ # ChefFS, on the other hand, stores user membership in an org as a single
+ # file, `members.json`, with content:
+ #
+ # ```json
+ # [
+ # { "user": { "username": "jkeiser" } },
+ # { "user": { "username": "cdoherty" } }
+ # ]
+ # ```
+ #
+ # To translate between the two, we need to intercept requests to `users`
+ # like so:
+ #
+ # - `list(users)` -> `get(/members.json)`
+ # - `get(users/NAME)` -> `get(/members.json)`, see if it's in there
+ # - `create(users/NAME)` -> `get(/members.json)`, add name, `set(/members.json)`
+ # - `delete(users/NAME)` -> `get(/members.json)`, remove name, `set(/members.json)`
+ #
+ # 6. Org invitations:
+ # chef-zero stores org membership invitations as a series of empty files.
+ # If an org has invited jkeiser and cdoherty (and they have not yet accepted
+ # the invite), chef-zero expects these files to exist:
+ #
+ # - `association_requests/jkeiser` (content: '{}')
+ # - `association_requests/cdoherty` (content: '{}')
+ #
+ # ChefFS, on the other hand, stores invitations as a single file,
+ # `invitations.json`, with content:
+ #
+ # ```json
+ # [
+ # { "id" => "jkeiser-chef", 'username' => 'jkeiser' },
+ # { "id" => "cdoherty-chef", 'username' => 'cdoherty' }
+ # ]
+ # ```
+ #
+ # To translate between the two, we need to intercept requests to `users`
+ # like so:
+ #
+ # - `list(association_requests)` -> `get(/invitations.json)`
+ # - `get(association_requests/NAME)` -> `get(/invitations.json)`, see if it's in there
+ # - `create(association_requests/NAME)` -> `get(/invitations.json)`, add name, `set(/invitations.json)`
+ # - `delete(association_requests/NAME)` -> `get(/invitations.json)`, remove name, `set(/invitations.json)`
+ #
class ChefFSDataStore
+
+ # The base directories in a Chef Repo; even when these don't exist, a
+ # matching GET for these objects will return an empty list instead of a
+ # 404.
+ BASE_DIRNAMES = %w{
+ clients
+ cookbooks
+ data
+ environments
+ nodes
+ roles
+ users
+ containers
+ groups
+ policy_groups
+ policies
+ }.freeze
+
#
# Create a new ChefFSDataStore
#
@@ -83,9 +154,10 @@ class Chef
# Generally will be a +ChefFS::FileSystem::ChefRepositoryFileSystemRoot+
# object, created from +ChefFS::Config.local_fs+.
#
- def initialize(chef_fs)
+ def initialize(chef_fs, chef_config = Chef::Config)
@chef_fs = chef_fs
@memory_store = ChefZero::DataStore::MemoryStore.new
+ @repo_mode = chef_config[:repo_mode]
end
def publish_description
@@ -93,14 +165,15 @@ class Chef
end
attr_reader :chef_fs
+ attr_reader :repo_mode
def create_dir(path, name, *options)
if use_memory_store?(path)
@memory_store.create_dir(path, name, *options)
else
- with_dir(path) do |parent|
+ with_parent_dir(path + [name], *options) do |parent, name|
begin
- parent.create_child(chef_fs_filename(path + [name]), nil)
+ parent.create_child(name, nil)
rescue Chef::ChefFS::FileSystem::AlreadyExistsError => e
raise ChefZero::DataStore::DataAlreadyExistsError.new(to_zero_path(e.entry), e)
end
@@ -108,21 +181,78 @@ class Chef
end
end
+ #
+ # If you want to get the contents of /data/x/y from the server,
+ # you say chef_fs.child('data').child('x').child('y').read.
+ # It will make exactly one network request: GET /data/x/y
+ # And that will return 404 if it doesn't exist.
+ #
+ # ChefFS objects do not go to the network until you ask them for data.
+ # This means you can construct a /data/x/y ChefFS entry early.
+ #
+ # Alternative:
+ # chef_fs.child('data') could have done a GET /data preemptively,
+ # allowing it to know whether child('x') was valid (GET /data gives you
+ # a list of data bags). Then child('x') could have done a GET /data/x,
+ # allowing it to know whether child('y') (the item) existed. Finally,
+ # we would do the GET /data/x/y to read the contents. Three network
+ # requests instead of 1.
+ #
+
def create(path, name, data, *options)
if use_memory_store?(path)
@memory_store.create(path, name, data, *options)
- elsif path[0] == 'cookbooks' && path.length == 2
+ elsif path[0] == "cookbooks" && path.length == 2
# Do nothing. The entry gets created when the cookbook is created.
+ # /policy_groups/GROUP/policies/NAME
+ elsif path[0] == "policy_groups" && path[2] == "policies"
+ # Just set or create the proper entry in the hash
+ update_json(to_chef_fs_path(path[0..1]), {}, *options) do |group|
+ if policies.has_key?(path[3])
+ raise ChefZero::DataStore::DataAlreadyExistsError.new(path, group)
+ end
+
+ group["policies"] ||= {}
+ group["policies"][path[3]] = { "revision_id" => Chef::JSONCompat.parse(data) }
+ group
+ end
+
+ # create [/organizations/ORG]/users/NAME (with content '{}')
+ # Manipulate the `members.json` file that contains a list of all users
+ elsif is_org? && path == [ "users" ]
+ update_json("members.json", [], *options) do |members|
+ # Format of each entry: { "user": { "username": "jkeiser" } }
+ if members.any? { |member| member["user"]["username"] == name }
+ raise ChefZero::DataStore::DataAlreadyExistsError.new(path, entry)
+ end
+
+ # Actually add the user
+ members << { "user" => { "username" => name } }
+ end
+
+ # create [/organizations/ORG]/association_requests/NAME (with content '{}')
+ # Manipulate the `invitations.json` file that contains a list of all users
+ elsif is_org? && path == [ "association_requests" ]
+ update_json("invitations.json", [], *options) do |invitations|
+ # Format of each entry: { "id" => "jkeiser-chef", 'username' => 'jkeiser' }
+ if invitations.any? { |member| member["username"] == name }
+ raise ChefZero::DataStore::DataAlreadyExistsError.new(path)
+ end
+
+ # Actually add the user (TODO insert org name??)
+ invitations << { "username" => name }
+ end
+
else
if !data.is_a?(String)
raise "set only works with strings"
end
- with_dir(path) do |parent|
+ with_parent_dir(path + [name], *options) do |parent, name|
begin
- parent.create_child(chef_fs_filename(path + [name]), data)
+ parent.create_child(name, data)
rescue Chef::ChefFS::FileSystem::AlreadyExistsError => e
raise ChefZero::DataStore::DataAlreadyExistsError.new(to_zero_path(e.entry), e)
end
@@ -130,54 +260,99 @@ class Chef
end
end
- def get(path, request=nil)
+ def get(path, request = nil)
if use_memory_store?(path)
@memory_store.get(path)
- elsif path[0] == 'file_store' && path[1] == 'repo'
- entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[2..-1].join('/'))
+ elsif path[0] == "file_store" && path[1] == "repo"
+ entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[2..-1].join("/"))
begin
entry.read
rescue Chef::ChefFS::FileSystem::NotFoundError => e
raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
end
- else
+ # /policy_groups/NAME/policies/POLICYNAME: return the revision of the given policy
+ elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
+ # Just set or create the proper entry in the hash
+ policy_group = get_json(to_chef_fs_path(path[0..1]), {})
+ if !policy_group["policies"] || !policy_group["policies"][path[3]]
+ raise ChefZero::DataStore::DataNotFoundError.new(path, entry)
+ end
+ # The policy group looks like:
+ # {
+ # "policies": {
+ # "x": { "revision_id": "10" }
+ # }
+ # }
+ Chef::JSONCompat.to_json_pretty(policy_group["policies"][path[3]]["revision_id"])
+
+ # GET [/organizations/ORG]/users/NAME -> /users/NAME
+ # Manipulates members.json
+ elsif is_org? && path[0] == "users" && path.length == 2
+ if get_json("members.json", []).any? { |member| member["user"]["username"] == path[1] }
+ "{}"
+ else
+ raise ChefZero::DataStore::DataNotFoundError.new(path)
+ end
+
+ # GET [/organizations/ORG]/association_requests/NAME -> /users/NAME
+ # Manipulates invites.json
+ elsif is_org? && path[0] == "association_requests" && path.length == 2
+ if get_json("invites.json", []).any? { |member| member["user"]["username"] == path[1] }
+ "{}"
+ else
+ raise ChefZero::DataStore::DataNotFoundError.new(path)
+ end
+
+ # GET /cookbooks/NAME/VERSION or /cookbook_artifacts/NAME/IDENTIFIER
+ elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 3
with_entry(path) do |entry|
- if path[0] == 'cookbooks' && path.length == 3
- # get /cookbooks/NAME/version
- result = nil
- begin
- result = Chef::CookbookManifest.new(entry.chef_object).to_hash
- rescue Chef::ChefFS::FileSystem::NotFoundError => e
- raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
- end
+ cookbook_type = path[0]
+ result = nil
+ begin
+ result = Chef::CookbookManifest.new(entry.chef_object, policy_mode: cookbook_type == "cookbook_artifacts").to_hash
+ rescue Chef::ChefFS::FileSystem::NotFoundError => e
+ raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
+ end
- result.each_pair do |key, value|
- if value.is_a?(Array)
- value.each do |file|
- if file.is_a?(Hash) && file.has_key?('checksum')
- relative = ['file_store', 'repo', 'cookbooks']
- if chef_fs.versioned_cookbooks
- relative << "#{path[1]}-#{path[2]}"
- else
- relative << path[1]
- end
- relative = relative + file[:path].split('/')
- file['url'] = ChefZero::RestBase::build_uri(request.base_uri, relative)
+ result.each_pair do |key, value|
+ if value.is_a?(Array)
+ value.each do |file|
+ if file.is_a?(Hash) && file.has_key?("checksum")
+ relative = ["file_store", "repo", cookbook_type]
+ if chef_fs.versioned_cookbooks || cookbook_type == "cookbook_artifacts"
+ relative << "#{path[1]}-#{path[2]}"
+ else
+ relative << path[1]
end
+ relative += file[:path].split("/")
+ file["url"] = ChefZero::RestBase.build_uri(request.base_uri, relative)
end
end
end
- Chef::JSONCompat.to_json_pretty(result)
+ end
- else
- begin
- entry.read
- rescue Chef::ChefFS::FileSystem::NotFoundError => e
- raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
+ if cookbook_type == "cookbook_artifacts"
+ result["metadata"] = result["metadata"].to_hash
+ result["metadata"].delete_if do |key, value|
+ value == [] ||
+ (value == {} && !%w{dependencies attributes recipes}.include?(key)) ||
+ (value == "" && %w{source_url issues_url}.include?(key)) ||
+ (value == false && key == "privacy")
end
end
+
+ Chef::JSONCompat.to_json_pretty(result)
+ end
+
+ else
+ with_entry(path) do |entry|
+ begin
+ entry.read
+ rescue Chef::ChefFS::FileSystem::NotFoundError => e
+ raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
+ end
end
end
end
@@ -191,15 +366,25 @@ class Chef
end
# Write out the files!
- if path[0] == 'cookbooks' && path.length == 3
+ if %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 3
write_cookbook(path, data, *options)
+
+ # Handle /policy_groups/some_policy_group/policies/some_policy_name
+ elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
+ # Just set or create the proper entry in the hash
+ update_json(to_chef_fs_path(path[0..1]), {}, *options) do |group|
+ group["policies"] ||= {}
+ group["policies"][path[3]] = { "revision_id" => Chef::JSONCompat.parse(data) }
+ group
+ end
+
else
- with_dir(path[0..-2]) do |parent|
- child = parent.child(chef_fs_filename(path))
+ with_parent_dir(path, *options) do |parent, name|
+ child = parent.child(name)
if child.exists?
child.write(data)
else
- parent.create_child(chef_fs_filename(path), data)
+ parent.create_child(name, data)
end
end
end
@@ -209,10 +394,43 @@ class Chef
def delete(path)
if use_memory_store?(path)
@memory_store.delete(path)
+
+ # DELETE /policy_groups/GROUP/policies/POLICY
+ elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
+ update_json(to_chef_fs_path(path[0..1]), {}) do |group|
+ unless group["policies"] && group["policies"].has_key?(path[3])
+ raise ChefZero::DataStore::DataNotFoundError.new(path)
+ end
+ group["policies"].delete(path[3])
+ group
+ end
+
+ # DELETE [/organizations/ORG]/users/NAME
+ # Manipulates members.json
+ elsif is_org? && path[0] == "users" && path.length == 2
+ update_json("members.json", []) do |members|
+ result = members.reject { |member| member["user"]["username"] == path[1] }
+ if result.size == members.size
+ raise ChefZero::DataStore::DataNotFoundError.new(path)
+ end
+ result
+ end
+
+ # DELETE [/organizations/ORG]/users/NAME
+ # Manipulates members.json
+ elsif is_org? && path[0] == "association_requests" && path.length == 2
+ update_json("invitations.json", []) do |invitations|
+ result = invitations.reject { |invitation| invitation["username"] == path[1] }
+ if result.size == invitations.size
+ raise ChefZero::DataStore::DataNotFoundError.new(path)
+ end
+ result
+ end
+
else
with_entry(path) do |entry|
begin
- if path[0] == 'cookbooks' && path.length >= 3
+ if %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length >= 3
entry.delete(true)
else
entry.delete(false)
@@ -227,6 +445,25 @@ class Chef
def delete_dir(path, *options)
if use_memory_store?(path)
@memory_store.delete_dir(path, *options)
+
+ # DELETE /policies/POLICY
+ elsif path[0] == "policies" && path.length == 2
+ with_entry(path[0..0]) do |policies|
+ # /policies:
+ # - a-1.0.0.json
+ # - a-1.0.1.json
+ # - b-2.0.0.json
+ found_policy = false
+ policies.children.each do |policy|
+ # We want to delete just the ones that == POLICY
+ next unless policy.name.rpartition("-")[0] == path[1]
+ policy.delete(false)
+ FileSystemCache.instance.delete!(policy.file_path)
+ found_policy = true
+ end
+ raise ChefZero::DataStore::DataNotFoundError.new(path) if !found_policy
+ end
+
else
with_entry(path) do |entry|
begin
@@ -242,10 +479,49 @@ class Chef
if use_memory_store?(path)
@memory_store.list(path)
- elsif path[0] == 'cookbooks' && path.length == 1
+ # LIST /policies
+ elsif path == [ "policies" ]
+ with_entry([ path[0] ]) do |policies|
+ begin
+ policies.children.map { |policy| policy.name[0..-6].rpartition("-")[0] }.uniq
+ rescue Chef::ChefFS::FileSystem::NotFoundError
+ []
+ end
+ end
+
+ # LIST /policies/POLICY/revisions
+ elsif path[0] == "policies" && path[2] == "revisions" && path.length == 3
+ with_entry([ path[0] ]) do |policies|
+ # /policies:
+ # - a-1.0.0.json
+ # - a-1.0.1.json
+ # - b-2.0.0.json
+ revisions = []
+ policies.children.each do |policy|
+ name, dash, revision = policy.name[0..-6].rpartition("-")
+ revisions << revision if name == path[1]
+ end
+ raise ChefZero::DataStore::DataNotFoundError.new(path) if revisions.empty?
+ revisions
+ end
+
+ elsif path[0] == "policy_groups" && path.length == 2
+ with_entry(path) do |entry|
+ [ "policies" ]
+ end
+
+ elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 3
+ with_entry(path[0..1]) do |entry|
+ policies = Chef::JSONCompat.parse(entry.read)["policies"] || {}
+ policies.keys
+ end
+
+ elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 1
with_entry(path) do |entry|
begin
- if chef_fs.versioned_cookbooks
+ if path[0] == "cookbook_artifacts"
+ entry.children.map { |child| child.name.rpartition("-")[0] }.uniq
+ elsif chef_fs.versioned_cookbooks
# /cookbooks/name-version -> /cookbooks/name
entry.children.map { |child| split_name_version(child.name)[0] }.uniq
else
@@ -257,13 +533,13 @@ class Chef
end
end
- elsif path[0] == 'cookbooks' && path.length == 2
- if chef_fs.versioned_cookbooks
- result = with_entry([ 'cookbooks' ]) do |entry|
+ elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 2
+ if chef_fs.versioned_cookbooks || path[0] == "cookbook_artifacts"
+ result = with_entry([ path[0] ]) do |entry|
# list /cookbooks/name = filter /cookbooks/name-version down to name
entry.children.map { |child| split_name_version(child.name) }.
- select { |name, version| name == path[1] }.
- map { |name, version| version }
+ select { |name, version| name == path[1] }.
+ map { |name, version| version }
end
if result.empty?
raise ChefZero::DataStore::DataNotFoundError.new(path)
@@ -276,7 +552,7 @@ class Chef
end
else
- with_entry(path) do |entry|
+ result = with_entry(path) do |entry|
begin
entry.children.map { |c| zero_filename(c) }.sort
rescue Chef::ChefFS::FileSystem::NotFoundError => e
@@ -288,12 +564,25 @@ class Chef
end
end
end
+
+ # Older versions of chef-zero do not understand policies and cookbook_artifacts,
+ # don't give that stuff to them
+ if path == [] && ChefZero::VERSION.to_f < 4.4
+ result.reject! { |child| %w{policies policy_data cookbook_artifacts}.include?(child) }
+ end
+ result
end
end
def exists?(path)
if use_memory_store?(path)
@memory_store.exists?(path)
+
+ # /policy_groups/NAME/policies/POLICYNAME
+ elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
+ group = get_json(to_chef_fs_path(path[0..1]), {})
+ group["policies"] && group["policies"].has_key?(path[3])
+
else
path_always_exists?(path) || Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists?
end
@@ -302,8 +591,18 @@ class Chef
def exists_dir?(path)
if use_memory_store?(path)
@memory_store.exists_dir?(path)
- elsif path[0] == 'cookbooks' && path.length == 2
+
+ elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 2
+ list([ path[0] ]).include?(path[1])
+
+ # /policies/NAME
+ elsif path[0] == "policies" && path.length == 2
list([ path[0] ]).include?(path[1])
+
+ # /policy_groups/NAME/policies
+ elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 3
+ exists_dir?(path[0..1])
+
else
Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists?
end
@@ -312,34 +611,35 @@ class Chef
private
def use_memory_store?(path)
- return path[0] == 'sandboxes' || path[0] == 'file_store' && path[1] == 'checksums' || path == [ 'environments', '_default' ]
+ path[0] == "sandboxes" || path[0] == "file_store" && path[1] == "checksums" || path == %w{environments _default}
end
def write_cookbook(path, data, *options)
+ cookbook_type = path[0]
if chef_fs.versioned_cookbooks
- cookbook_path = File.join('cookbooks', "#{path[1]}-#{path[2]}")
+ cookbook_path = File.join(cookbook_type, "#{path[1]}-#{path[2]}")
else
- cookbook_path = File.join('cookbooks', path[1])
+ cookbook_path = File.join(cookbook_type, path[1])
end
# Create a little Chef::ChefFS memory filesystem with the data
- cookbook_fs = Chef::ChefFS::FileSystem::MemoryRoot.new('uploading')
+ cookbook_fs = Chef::ChefFS::FileSystem::Memory::MemoryRoot.new("uploading")
cookbook = Chef::JSONCompat.parse(data)
cookbook.each_pair do |key, value|
if value.is_a?(Array)
value.each do |file|
- if file.is_a?(Hash) && file.has_key?('checksum')
- file_data = @memory_store.get(['file_store', 'checksums', file['checksum']])
- cookbook_fs.add_file(File.join(cookbook_path, file['path']), file_data)
+ if file.is_a?(Hash) && file.has_key?("checksum")
+ file_data = @memory_store.get(["file_store", "checksums", file["checksum"]])
+ cookbook_fs.add_file(File.join(cookbook_path, file["path"]), file_data)
end
end
end
end
# Create the .uploaded-cookbook-version.json
- cookbooks = chef_fs.child('cookbooks')
+ cookbooks = chef_fs.child(cookbook_type)
if !cookbooks.exists?
- cookbooks = chef_fs.create_child('cookbooks')
+ cookbooks = chef_fs.create_child(cookbook_type)
end
# We are calling a cookbooks-specific API, so get multiplexed_dirs out of the way if it is there
if cookbooks.respond_to?(:multiplexed_dirs)
@@ -349,14 +649,14 @@ class Chef
end
def split_name_version(entry_name)
- name_version = entry_name.split('-')
- name = name_version[0..-2].join('-')
+ name_version = entry_name.split("-")
+ name = name_version[0..-2].join("-")
version = name_version[-1]
- [name,version]
+ [name, version]
end
def to_chef_fs_path(path)
- _to_chef_fs_path(path).join('/')
+ _to_chef_fs_path(path).join("/")
end
def chef_fs_filename(path)
@@ -364,27 +664,37 @@ class Chef
end
def _to_chef_fs_path(path)
- if path[0] == 'data'
- path = path.dup
- path[0] = 'data_bags'
+ path = path.dup
+
+ # /data -> /data_bags
+ # /data/BAG -> /data_bags/BAG
+ # /data/BAG/ITEM -> /data_bags/BAG/ITEM.json
+ if path[0] == "data"
+ path[0] = "data_bags"
if path.length >= 3
path[2] = "#{path[2]}.json"
end
- elsif path[0] == 'policies'
- path = path.dup
+
+ # /client_keys/CLIENT/keys -> /client_keys/CLIENT
+ # /client_keys/CLIENT/keys/KEYNAME -> /client_keys/CLIENT/KEYNAME.json
+ elsif path[0] == "client_keys"
+ path.delete_at(2)
if path.length >= 3
- path[2] = "#{path[2]}.json"
+ path[-1] += ".json"
end
- elsif path[0] == 'cookbooks'
+
+ # /policies/POLICY/revisions/REVISION -> /policies/POLICY-REVISION.json
+ elsif path[0] == "policies" && path[2] == "revisions" && path.length >= 4
+ path = [ "policies", "#{path[1]}-#{path[3]}.json" ]
+
+ elsif %w{cookbooks cookbook_artifacts}.include?(path[0])
if path.length == 2
raise ChefZero::DataStore::DataNotFoundError.new(path)
- elsif chef_fs.versioned_cookbooks
- if path.length >= 3
+ elsif path.length >= 3
+ if chef_fs.versioned_cookbooks || path[0] == "cookbook_artifacts"
# cookbooks/name/version -> cookbooks/name-version
path = [ path[0], "#{path[1]}-#{path[2]}" ] + path[3..-1]
- end
- else
- if path.length >= 3
+ else
# cookbooks/name/version/... -> /cookbooks/name/... iff metadata says so
version = get_single_cookbook_version(path)
if path[2] == version
@@ -394,24 +704,49 @@ class Chef
end
end
end
+
+ elsif path[0] == "acls"
+ # /acls/data -> /acls/data_bags
+ if path[1] == "data"
+ path[1] = "data_bags"
+ end
+
+ # /acls/containers|nodes|.../x.json
+ # /acls/organization.json
+ if path.length == 3 || path == %w{acls organization}
+ path[-1] = "#{path[-1]}.json"
+ end
+
+ # /acls/containers|nodes|... do NOT drop into the next elsif, and do
+ # not get .json appended
+
+ # /nodes|clients|.../x.json
elsif path.length == 2
- path = path.dup
- path[1] = "#{path[1]}.json"
+ path[-1] = "#{path[-1]}.json"
end
path
end
def to_zero_path(entry)
- path = entry.path.split('/')[1..-1]
- if path[0] == 'data_bags'
- path = path.dup
- path[0] = 'data'
+ path = entry.path.split("/")[1..-1]
+
+ if path[0] == "data_bags"
+ path[0] = "data"
if path.length >= 3
path[2] = path[2][0..-6]
end
- elsif path[0] == 'cookbooks'
- if chef_fs.versioned_cookbooks
+ # /client_keys/CLIENT -> /client_keys/CLIENT/keys
+ # /client_keys/CLIENT/KEYNAME.json -> /client_keys/CLIENT/keys/KEYNAME
+ elsif path[0] == "client_keys"
+ if path.size == 2
+ path << "keys"
+ elsif path.size > 2
+ path[2..-1] = [ "keys", path[-1][0..-6] ]
+ end
+
+ elsif %w{cookbooks cookbook_artifacts}.include?(path[0])
+ if chef_fs.versioned_cookbooks || path[0] == "cookbook_artifacts"
# cookbooks/name-version/... -> cookbooks/name/version/...
if path.length >= 2
name, version = split_name_version(path[1])
@@ -425,10 +760,17 @@ class Chef
end
end
- elsif path.length == 2 && path[0] != 'cookbooks'
- path = path.dup
+ # /policies/NAME-REVISION.json -> /policies/NAME/revisions/REVISION
+ elsif path[0] == "policies"
+ if path.length >= 2
+ name, dash, revision = path[1][0..-6].rpartition("-")
+ path = [ "policies", name, "revisions", revision ]
+ end
+
+ elsif path.length == 2 && path[0] != "cookbooks"
path[1] = path[1][0..-6]
end
+
path
end
@@ -437,20 +779,29 @@ class Chef
end
def path_always_exists?(path)
- return path.length == 1 && %w(clients cookbooks data environments nodes roles users).include?(path[0])
+ path.length == 1 && BASE_DIRNAMES.include?(path[0])
end
def with_entry(path)
+ yield Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path))
+ rescue Chef::ChefFS::FileSystem::NotFoundError => e
+ raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
+ end
+
+ def with_parent_dir(path, *options)
+ path = _to_chef_fs_path(path)
begin
- yield Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path))
+ yield get_dir(path[0..-2], options.include?(:create_dir)), path[-1]
rescue Chef::ChefFS::FileSystem::NotFoundError => e
- raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
+ err = ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
+ err.set_backtrace(e.backtrace)
+ raise err
end
end
def with_dir(path)
# Do not automatically create data bags
- create = !(path[0] == 'data' && path.size >= 2)
+ create = !(path[0] == "data" && path.size >= 2)
begin
yield get_dir(_to_chef_fs_path(path), create)
@@ -461,11 +812,11 @@ class Chef
end
end
- def get_dir(path, create=false)
- result = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path.join('/'))
+ def get_dir(path, create = false)
+ result = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path.join("/"))
if result.exists?
result
- elsif create
+ elsif create || path.size == 1
get_dir(path[0..-2], create).create_child(result.name, nil)
else
raise ChefZero::DataStore::DataNotFoundError.new(path)
@@ -473,9 +824,46 @@ class Chef
end
def get_single_cookbook_version(path)
- dir = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[0..1].join('/'))
+ dir = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[0..1].join("/"))
metadata = ChefZero::CookbookData.metadata_from(dir, path[1], nil, [])
- metadata[:version] || '0.0.0'
+ metadata[:version] || "0.0.0"
+ end
+
+ def update_json(path, default_value, *options)
+ entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path)
+ begin
+ input = Chef::JSONCompat.parse(entry.read)
+ output = yield input
+ entry.write(Chef::JSONCompat.to_json_pretty(output)) if output != Chef::JSONCompat.parse(entry.read)
+ rescue Chef::ChefFS::FileSystem::NotFoundError
+ # Send the default value to the caller, and create the entry if the caller updates it
+ output = yield default_value
+ parent = entry.parent
+ parent = ensure_dir(parent) if options.include?(:create_dir)
+ parent.create_child(entry.name, Chef::JSONCompat.to_json_pretty(output)) if output != []
+ end
+ end
+
+ def ensure_dir(entry)
+ return entry if entry.exists?
+ parent = entry.parent
+ if parent
+ ensure_dir(parent)
+ parent.create_child(entry.name)
+ end
+ end
+
+ def get_json(path, default_value)
+ entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path)
+ begin
+ Chef::JSONCompat.parse(entry.read)
+ rescue Chef::ChefFS::FileSystem::NotFoundError
+ default_value
+ end
+ end
+
+ def is_org?
+ repo_mode == "hosted_everything"
end
end
end
diff --git a/lib/chef/chef_fs/command_line.rb b/lib/chef/chef_fs/command_line.rb
index 8a205eef78..2aefe2fa88 100644
--- a/lib/chef/chef_fs/command_line.rb
+++ b/lib/chef/chef_fs/command_line.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,9 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system'
-require 'chef/chef_fs/file_system/operation_failed_error'
-require 'chef/chef_fs/file_system/operation_not_allowed_error'
-require 'chef/util/diff'
+require "chef/chef_fs/file_system"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/util/diff"
class Chef
module ChefFS
@@ -64,6 +63,13 @@ class Chef
end
when :deleted
+ # This is kind of a kludge - because the "new" entry isn't there, we can't predict
+ # it's true file name, because we've not got enough information. So because we know
+ # the two entries really ought to have the same extension, we'll just grab the old one
+ # and use it. (This doesn't affect cookbook files, since they'll always have extensions)
+ if File.extname(old_path) != File.extname(new_path)
+ new_path += File.extname(old_path)
+ end
next if diff_filter && diff_filter !~ /D/
if output_mode == :name_only
yield "#{new_path}\n"
@@ -72,7 +78,7 @@ class Chef
elsif old_value
result = "diff --knife #{old_path} #{new_path}\n"
result << "deleted file\n"
- result << diff_text(old_path, '/dev/null', old_value, '')
+ result << diff_text(old_path, "/dev/null", old_value, "")
yield result
else
yield "Only in #{format_path.call(old_entry.parent)}: #{old_entry.name}\n"
@@ -87,7 +93,7 @@ class Chef
elsif new_value
result = "diff --knife #{old_path} #{new_path}\n"
result << "new file\n"
- result << diff_text('/dev/null', new_path, '', new_value)
+ result << diff_text("/dev/null", new_path, "", new_value)
yield result
else
yield "Only in #{format_path.call(new_entry.parent)}: #{new_entry.name}\n"
@@ -223,7 +229,7 @@ class Chef
end
end
- if old_value == :none || (old_value == nil && !old_entry.exists?)
+ if old_value == :none || (old_value.nil? && !old_entry.exists?)
return [ [ :added, old_entry, new_entry, old_value, new_value ] ]
elsif new_value == :none
return [ [ :deleted, old_entry, new_entry, old_value, new_value ] ]
@@ -236,30 +242,31 @@ class Chef
return [ [ :error, old_entry, new_entry, nil, nil, e ] ]
end
- private
+ class << self
+ private
- def self.sort_keys(json_object)
- if json_object.is_a?(Array)
- json_object.map { |o| sort_keys(o) }
- elsif json_object.is_a?(Hash)
- new_hash = {}
- json_object.keys.sort.each { |key| new_hash[key] = sort_keys(json_object[key]) }
- new_hash
- else
- json_object
+ def sort_keys(json_object)
+ if json_object.is_a?(Array)
+ json_object.map { |o| sort_keys(o) }
+ elsif json_object.is_a?(Hash)
+ new_hash = {}
+ json_object.keys.sort.each { |key| new_hash[key] = sort_keys(json_object[key]) }
+ new_hash
+ else
+ json_object
+ end
end
- end
- def self.canonicalize_json(json_text)
- parsed_json = Chef::JSONCompat.parse(json_text)
- sorted_json = sort_keys(parsed_json)
- Chef::JSONCompat.to_json_pretty(sorted_json)
- end
+ def canonicalize_json(json_text)
+ parsed_json = Chef::JSONCompat.parse(json_text)
+ sorted_json = sort_keys(parsed_json)
+ Chef::JSONCompat.to_json_pretty(sorted_json)
+ end
+
+ def diff_text(old_path, new_path, old_value, new_value)
+ # Copy to tempfiles before diffing
+ # TODO don't copy things that are already in files! Or find an in-memory diff algorithm
- def self.diff_text(old_path, new_path, old_value, new_value)
- # Copy to tempfiles before diffing
- # TODO don't copy things that are already in files! Or find an in-memory diff algorithm
- begin
new_tempfile = Tempfile.new("new")
new_tempfile.write(new_value)
new_tempfile.close
diff --git a/lib/chef/chef_fs/config.rb b/lib/chef/chef_fs/config.rb
index 40cbb36530..63a1363724 100644
--- a/lib/chef/chef_fs/config.rb
+++ b/lib/chef/chef_fs/config.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/chef_fs/path_utils'
+require "chef/log"
+require "chef/chef_fs/path_utils"
class Chef
module ChefFS
@@ -31,8 +31,10 @@ class Chef
# out here:
INFLECTIONS = {
"acls" => "acl",
+ "client_keys" => "client_key",
"clients" => "client",
"cookbooks" => "cookbook",
+ "cookbook_artifacts" => "cookbook_artifact",
"containers" => "container",
"data_bags" => "data_bag",
"environments" => "environment",
@@ -40,11 +42,39 @@ class Chef
"nodes" => "node",
"roles" => "role",
"users" => "user",
- "policies" => "policy"
+ "policies" => "policy",
+ "policy_groups" => "policy_group",
}
- INFLECTIONS.each { |k,v| k.freeze; v.freeze }
+ INFLECTIONS.each { |k, v| k.freeze; v.freeze }
INFLECTIONS.freeze
+ # ChefFS supports three modes of operation: "static", "everything", and
+ # "hosted_everything". These names are antiquated since Chef 12 moved
+ # multi-tenant and RBAC to the open source product. In practice, they
+ # mean:
+ #
+ # * static: just static objects that are included in a traditional
+ # chef-repo, with no support for anything introduced in Chef 12 or
+ # later.
+ # * everything: all of the objects supported by the open source Chef
+ # Server 11.x
+ # * hosted_everything: (the name comes from Hosted Chef) supports
+ # everything in Chef Server 12 and later, including RBAC objects and
+ # Policyfile objects.
+ #
+ # The "static" and "everything" modes are used for backup and
+ # upgrade/migration of older Chef Servers, so they should be considered
+ # frozen in time.
+
+ CHEF_11_OSS_STATIC_OBJECTS = %w{cookbooks cookbook_artifacts data_bags environments roles}.freeze
+ CHEF_11_OSS_DYNAMIC_OBJECTS = %w{clients nodes users}.freeze
+ RBAC_OBJECT_NAMES = %w{acls containers groups }.freeze
+ CHEF_12_OBJECTS = %w{ cookbook_artifacts policies policy_groups client_keys }.freeze
+
+ STATIC_MODE_OBJECT_NAMES = CHEF_11_OSS_STATIC_OBJECTS
+ EVERYTHING_MODE_OBJECT_NAMES = (CHEF_11_OSS_STATIC_OBJECTS + CHEF_11_OSS_DYNAMIC_OBJECTS).freeze
+ HOSTED_EVERYTHING_MODE_OBJECT_NAMES = (EVERYTHING_MODE_OBJECT_NAMES + RBAC_OBJECT_NAMES + CHEF_12_OBJECTS).freeze
+
#
# Create a new Config object which can produce a chef_fs and local_fs.
#
@@ -114,7 +144,7 @@ class Chef
@cwd = File.expand_path(cwd)
@cookbook_version = options[:cookbook_version]
- if @chef_config[:repo_mode] == 'everything' && is_hosted? && !ui.nil?
+ if @chef_config[:repo_mode] == "everything" && is_hosted? && !ui.nil?
ui.warn %Q{You have repo_mode set to 'everything', but your chef_server_url
looks like it might be a hosted setup. If this is the case please use
hosted_everything or allow repo_mode to default}
@@ -122,9 +152,9 @@ class Chef
# Default to getting *everything* from the server.
if !@chef_config[:repo_mode]
if is_hosted?
- @chef_config[:repo_mode] = 'hosted_everything'
+ @chef_config[:repo_mode] = "hosted_everything"
else
- @chef_config[:repo_mode] = 'everything'
+ @chef_config[:repo_mode] = "everything"
end
end
end
@@ -142,8 +172,8 @@ class Chef
end
def create_chef_fs
- require 'chef/chef_fs/file_system/chef_server_root_dir'
- Chef::ChefFS::FileSystem::ChefServerRootDir.new("remote", @chef_config, :cookbook_version => @cookbook_version)
+ require "chef/chef_fs/file_system/chef_server/chef_server_root_dir"
+ Chef::ChefFS::FileSystem::ChefServer::ChefServerRootDir.new("remote", @chef_config, :cookbook_version => @cookbook_version)
end
def local_fs
@@ -151,8 +181,8 @@ class Chef
end
def create_local_fs
- require 'chef/chef_fs/file_system/chef_repository_file_system_root_dir'
- Chef::ChefFS::FileSystem::ChefRepositoryFileSystemRootDir.new(object_paths, Array(chef_config[:chef_repo_path]).flatten, @chef_config)
+ require "chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir"
+ Chef::ChefFS::FileSystem::Repository::ChefRepositoryFileSystemRootDir.new(object_paths, Array(chef_config[:chef_repo_path]).flatten, @chef_config)
end
# Returns the given real path's location relative to the server root.
@@ -197,7 +227,7 @@ class Chef
# path and use realpath because a repo_path if provided *must* exist.
realest_chef_repo_path = Chef::ChefFS::PathUtils.realest_path(chef_repo_path, @cwd)
if Chef::ChefFS::PathUtils.os_path_eq?(target_path, realest_chef_repo_path)
- return '/'
+ return "/"
end
end
@@ -212,13 +242,13 @@ class Chef
# Print the given server path, relative to the current directory
def format_path(entry)
- server_path = entry.path
- if base_path && server_path[0,base_path.length] == base_path
+ server_path = entry.respond_to?(:display_path) ? entry.display_path : entry.path
+ if base_path && server_path[0, base_path.length] == base_path
if server_path == base_path
- return '.'
- elsif server_path[base_path.length,1] == '/'
+ return "."
+ elsif server_path[base_path.length, 1] == "/"
return server_path[base_path.length + 1, server_path.length - base_path.length - 1]
- elsif base_path == '/' && server_path[0,1] == '/'
+ elsif base_path == "/" && server_path[0, 1] == "/"
return server_path[1, server_path.length - 1]
end
end
@@ -231,16 +261,17 @@ class Chef
@object_paths ||= begin
result = {}
case @chef_config[:repo_mode]
- when 'static'
- object_names = %w(cookbooks data_bags environments roles policies)
- when 'hosted_everything'
- object_names = %w(acls clients cookbooks containers data_bags environments groups nodes roles policies)
+ when "static"
+ object_names = STATIC_MODE_OBJECT_NAMES
+ when "hosted_everything"
+ object_names = HOSTED_EVERYTHING_MODE_OBJECT_NAMES
else
- object_names = %w(clients cookbooks data_bags environments nodes roles users policies)
+ object_names = EVERYTHING_MODE_OBJECT_NAMES
end
object_names.each do |object_name|
# cookbooks -> cookbook_path
- singular_name = INFLECTIONS[object_name] or raise "Unknown object name #{object_name}"
+ singular_name = INFLECTIONS[object_name]
+ raise "Unknown object name #{object_name}" unless singular_name
variable_name = "#{singular_name}_path"
paths = Array(@chef_config[variable_name]).flatten
result[object_name] = paths.map { |path| File.expand_path(path) }
diff --git a/lib/chef/chef_fs/data_handler/acl_data_handler.rb b/lib/chef/chef_fs/data_handler/acl_data_handler.rb
index 8def8a543d..6c8833004a 100644
--- a/lib/chef/chef_fs/data_handler/acl_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/acl_data_handler.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
class Chef
module ChefFS
@@ -7,16 +7,16 @@ class Chef
def normalize(acl, entry)
# Normalize the order of the keys for easier reading
result = normalize_hash(acl, {
- 'create' => {},
- 'read' => {},
- 'update' => {},
- 'delete' => {},
- 'grant' => {}
+ "create" => {},
+ "read" => {},
+ "update" => {},
+ "delete" => {},
+ "grant" => {},
})
result.keys.each do |key|
- result[key] = normalize_hash(result[key], { 'actors' => [], 'groups' => [] })
- result[key]['actors'] = result[key]['actors'].sort
- result[key]['groups'] = result[key]['groups'].sort
+ result[key] = normalize_hash(result[key], { "actors" => [], "groups" => [] })
+ result[key]["actors"] = result[key]["actors"].sort
+ result[key]["groups"] = result[key]["groups"].sort
end
result
end
diff --git a/lib/chef/chef_fs/data_handler/client_data_handler.rb b/lib/chef/chef_fs/data_handler/client_data_handler.rb
index 5bcbd4e373..6c01d8d54c 100644
--- a/lib/chef/chef_fs/data_handler/client_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/client_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/api_client'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/api_client"
class Chef
module ChefFS
@@ -7,25 +7,25 @@ class Chef
class ClientDataHandler < DataHandlerBase
def normalize(client, entry)
defaults = {
- 'name' => remove_dot_json(entry.name),
- 'clientname' => remove_dot_json(entry.name),
- 'admin' => false,
- 'validator' => false,
- 'chef_type' => 'client'
+ "name" => remove_dot_json(entry.name),
+ "clientname" => remove_dot_json(entry.name),
+ "admin" => false,
+ "validator" => false,
+ "chef_type" => "client",
}
# Handle the fact that admin/validator have changed type from string -> boolean
- client['admin'] = (client['admin'] == 'true') if client['admin'].is_a?(String)
- client['validator'] = (client['validator'] == 'true') if client['validator'].is_a?(String)
+ client["admin"] = (client["admin"] == "true") if client["admin"].is_a?(String)
+ client["validator"] = (client["validator"] == "true") if client["validator"].is_a?(String)
if entry.respond_to?(:org) && entry.org
- defaults['orgname'] = entry.org
+ defaults["orgname"] = entry.org
end
result = normalize_hash(client, defaults)
- result.delete('json_class')
+ result.delete("json_class")
result
end
def preserve_key?(key)
- return key == 'name'
+ key == "name"
end
def chef_class
diff --git a/lib/chef/chef_fs/data_handler/client_key_data_handler.rb b/lib/chef/chef_fs/data_handler/client_key_data_handler.rb
new file mode 100644
index 0000000000..6276413bcf
--- /dev/null
+++ b/lib/chef/chef_fs/data_handler/client_key_data_handler.rb
@@ -0,0 +1,11 @@
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/api_client"
+
+class Chef
+ module ChefFS
+ module DataHandler
+ class ClientKeyDataHandler < DataHandlerBase
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/data_handler/container_data_handler.rb b/lib/chef/chef_fs/data_handler/container_data_handler.rb
index 980453cbab..a8bd5f084c 100644
--- a/lib/chef/chef_fs/data_handler/container_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/container_data_handler.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
class Chef
module ChefFS
@@ -6,19 +6,25 @@ class Chef
class ContainerDataHandler < DataHandlerBase
def normalize(container, entry)
normalize_hash(container, {
- 'containername' => remove_dot_json(entry.name),
- 'containerpath' => remove_dot_json(entry.name)
+ "containername" => remove_dot_json(entry.name),
+ "containerpath" => remove_dot_json(entry.name),
})
end
def preserve_key?(key)
- return key == 'containername'
+ key == "containername"
end
- def verify_integrity(object, entry, &on_error)
+ # Verify that the JSON hash for this type has a key that matches its name.
+ #
+ # @param object [Object] JSON hash of the object
+ # @param entry [Chef::ChefFS::FileSystem::BaseFSObject] filesystem object we are verifying
+ # @yield [s] callback to handle errors
+ # @yieldparam [s<string>] error message
+ def verify_integrity(object, entry)
base_name = remove_dot_json(entry.name)
- if object['containername'] != base_name
- on_error.call("Name in #{entry.path_for_printing} must be '#{base_name}' (is '#{object['name']}')")
+ if object["containername"] != base_name
+ yield("Name in #{entry.path_for_printing} must be '#{base_name}' (is '#{object['containername']}')")
end
end
diff --git a/lib/chef/chef_fs/data_handler/cookbook_data_handler.rb b/lib/chef/chef_fs/data_handler/cookbook_data_handler.rb
index 56b7e0b765..2861c5d3eb 100644
--- a/lib/chef/chef_fs/data_handler/cookbook_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/cookbook_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/cookbook/metadata'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/cookbook/metadata"
class Chef
module ChefFS
@@ -9,22 +9,22 @@ class Chef
version = entry.name
name = entry.parent.name
result = normalize_hash(cookbook, {
- 'name' => "#{name}-#{version}",
- 'version' => version,
- 'cookbook_name' => name,
- 'json_class' => 'Chef::CookbookVersion',
- 'chef_type' => 'cookbook_version',
- 'frozen?' => false,
- 'metadata' => {}
+ "name" => "#{name}-#{version}",
+ "version" => version,
+ "cookbook_name" => name,
+ "json_class" => "Chef::CookbookVersion",
+ "chef_type" => "cookbook_version",
+ "frozen?" => false,
+ "metadata" => {},
})
- result['metadata'] = normalize_hash(result['metadata'], {
- 'version' => version,
- 'name' => name
+ result["metadata"] = normalize_hash(result["metadata"], {
+ "version" => version,
+ "name" => name,
})
end
def preserve_key?(key)
- return key == 'cookbook_name' || key == 'version'
+ key == "cookbook_name" || key == "version"
end
def chef_class
diff --git a/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb b/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb
index 1306922081..e799e72e36 100644
--- a/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/data_bag_item'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/data_bag_item"
class Chef
module ChefFS
@@ -7,26 +7,26 @@ class Chef
class DataBagItemDataHandler < DataHandlerBase
def normalize(data_bag_item, entry)
# If it's wrapped with raw_data, unwrap it.
- if data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data']
- data_bag_item = data_bag_item['raw_data']
+ if data_bag_item["json_class"] == "Chef::DataBagItem" && data_bag_item["raw_data"]
+ data_bag_item = data_bag_item["raw_data"]
end
# chef_type and data_bag come back in PUT and POST results, but we don't
# use those in knife-essentials.
normalize_hash(data_bag_item, {
- 'id' => remove_dot_json(entry.name)
+ "id" => remove_dot_json(entry.name),
})
end
def normalize_for_post(data_bag_item, entry)
- if data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data']
- data_bag_item = data_bag_item['raw_data']
+ if data_bag_item["json_class"] == "Chef::DataBagItem" && data_bag_item["raw_data"]
+ data_bag_item = data_bag_item["raw_data"]
end
{
"name" => "data_bag_item_#{entry.parent.name}_#{remove_dot_json(entry.name)}",
"json_class" => "Chef::DataBagItem",
"chef_type" => "data_bag_item",
"data_bag" => entry.parent.name,
- "raw_data" => normalize(data_bag_item, entry)
+ "raw_data" => normalize(data_bag_item, entry),
}
end
@@ -35,17 +35,23 @@ class Chef
end
def preserve_key?(key)
- return key == 'id'
+ key == "id"
end
def chef_class
Chef::DataBagItem
end
- def verify_integrity(object, entry, &on_error)
+ # Verify that the JSON hash for this type has a key that matches its name.
+ #
+ # @param object [Object] JSON hash of the object
+ # @param entry [Chef::ChefFS::FileSystem::BaseFSObject] filesystem object we are verifying
+ # @yield [s] callback to handle errors
+ # @yieldparam [s<string>] error message
+ def verify_integrity(object, entry)
base_name = remove_dot_json(entry.name)
- if object['raw_data']['id'] != base_name
- on_error.call("ID in #{entry.path_for_printing} must be '#{base_name}' (is '#{object['raw_data']['id']}')")
+ if object["raw_data"]["id"] != base_name
+ yield("ID in #{entry.path_for_printing} must be '#{base_name}' (is '#{object['raw_data']['id']}')")
end
end
diff --git a/lib/chef/chef_fs/data_handler/data_handler_base.rb b/lib/chef/chef_fs/data_handler/data_handler_base.rb
index a3dc92405c..3668f77dd5 100644
--- a/lib/chef/chef_fs/data_handler/data_handler_base.rb
+++ b/lib/chef/chef_fs/data_handler/data_handler_base.rb
@@ -24,15 +24,14 @@ class Chef
object
end
- #
- # Takes a name like blah.json and removes the .json from it.
- #
- def remove_dot_json(name)
- if name.length < 5 || name[-5,5] != ".json"
- raise "Invalid name #{path}: must end in .json"
+ def remove_file_extension(name, ext = ".*")
+ if %w{ .rb .json }.include?(File.extname(name))
+ File.basename(name, ext)
+ else
+ name
end
- name[0,name.length-5]
end
+ alias_method :remove_dot_json, :remove_file_extension
#
# Return true if minimize() should preserve a key even if it is the same
@@ -94,7 +93,7 @@ class Chef
# name to recipe[name]. Then calls uniq on the result.
#
def normalize_run_list(run_list)
- run_list.map{|item|
+ run_list.map do |item|
case item.to_s
when /^recipe\[.*\]$/
item # explicit recipe
@@ -103,21 +102,23 @@ class Chef
else
"recipe[#{item}]"
end
- }.uniq
+ end.uniq
end
#
# Bring in an instance of this object from Ruby. (Like roles/x.rb)
#
- def from_ruby(ruby)
- chef_class.from_file(ruby).to_hash
+ def from_ruby(path)
+ r = chef_class.new
+ r.from_file(path)
+ r.to_hash
end
#
# Turn a JSON hash into a bona fide Chef object (like Chef::Node).
#
def chef_object(object)
- chef_class.json_create(object)
+ chef_class.from_hash(object)
end
#
@@ -147,18 +148,18 @@ class Chef
# environment "desert"'
#
def to_ruby_keys(object, keys)
- result = ''
+ result = ""
keys.each do |key|
if object[key]
if object[key].is_a?(Hash)
if object[key].size > 0
result << key
first = true
- object[key].each_pair do |k,v|
+ object[key].each_pair do |k, v|
if first
first = false
else
- result << ' '*key.length
+ result << " " * key.length
end
result << " #{k.inspect} => #{v.inspect}\n"
end
@@ -185,14 +186,16 @@ class Chef
result
end
- #
# Verify that the JSON hash for this type has a key that matches its name.
- # Calls the on_error block with the error, if there is one.
#
- def verify_integrity(object, entry, &on_error)
- base_name = remove_dot_json(entry.name)
- if object['name'] != base_name
- on_error.call("Name must be '#{base_name}' (is '#{object['name']}')")
+ # @param object [Object] JSON hash of the object
+ # @param entry [Chef::ChefFS::FileSystem::BaseFSObject] filesystem object we are verifying
+ # @yield [s] callback to handle errors
+ # @yieldparam [s<string>] error message
+ def verify_integrity(object, entry)
+ base_name = remove_file_extension(entry.name)
+ if object["name"] != base_name
+ yield("Name must be '#{base_name}' (is '#{object['name']}')")
end
end
diff --git a/lib/chef/chef_fs/data_handler/environment_data_handler.rb b/lib/chef/chef_fs/data_handler/environment_data_handler.rb
index 5105f2ac49..ab8104b483 100644
--- a/lib/chef/chef_fs/data_handler/environment_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/environment_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/environment'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/environment"
class Chef
module ChefFS
@@ -7,18 +7,18 @@ class Chef
class EnvironmentDataHandler < DataHandlerBase
def normalize(environment, entry)
normalize_hash(environment, {
- 'name' => remove_dot_json(entry.name),
- 'description' => '',
- 'cookbook_versions' => {},
- 'default_attributes' => {},
- 'override_attributes' => {},
- 'json_class' => 'Chef::Environment',
- 'chef_type' => 'environment'
+ "name" => remove_file_extension(entry.name),
+ "description" => "",
+ "cookbook_versions" => {},
+ "default_attributes" => {},
+ "override_attributes" => {},
+ "json_class" => "Chef::Environment",
+ "chef_type" => "environment",
})
end
def preserve_key?(key)
- return key == 'name'
+ key == "name"
end
def chef_class
@@ -26,9 +26,9 @@ class Chef
end
def to_ruby(object)
- result = to_ruby_keys(object, %w(name description default_attributes override_attributes))
- if object['cookbook_versions']
- object['cookbook_versions'].each_pair do |name, version|
+ result = to_ruby_keys(object, %w{name description default_attributes override_attributes})
+ if object["cookbook_versions"]
+ object["cookbook_versions"].each_pair do |name, version|
result << "cookbook #{name.inspect}, #{version.inspect}"
end
end
diff --git a/lib/chef/chef_fs/data_handler/group_data_handler.rb b/lib/chef/chef_fs/data_handler/group_data_handler.rb
index 1a36c66eb8..8daced2e2e 100644
--- a/lib/chef/chef_fs/data_handler/group_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/group_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/api_client'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/api_client"
class Chef
module ChefFS
@@ -7,32 +7,32 @@ class Chef
class GroupDataHandler < DataHandlerBase
def normalize(group, entry)
defaults = {
- 'name' => remove_dot_json(entry.name),
- 'groupname' => remove_dot_json(entry.name),
- 'users' => [],
- 'clients' => [],
- 'groups' => [],
+ "name" => remove_dot_json(entry.name),
+ "groupname" => remove_dot_json(entry.name),
+ "users" => [],
+ "clients" => [],
+ "groups" => [],
}
if entry.org
- defaults['orgname'] = entry.org
+ defaults["orgname"] = entry.org
end
result = normalize_hash(group, defaults)
- if result['actors'] && result['actors'].sort.uniq == (result['users'] + result['clients']).sort.uniq
- result.delete('actors')
+ if result["actors"] && result["actors"].sort.uniq == (result["users"] + result["clients"]).sort.uniq
+ result.delete("actors")
end
result
end
def normalize_for_put(group, entry)
result = super(group, entry)
- result['actors'] = {
- 'users' => result['users'],
- 'clients' => result['clients'],
- 'groups' => result['groups']
+ result["actors"] = {
+ "users" => result["users"],
+ "clients" => result["clients"],
+ "groups" => result["groups"],
}
- result.delete('users')
- result.delete('clients')
- result.delete('groups')
+ result.delete("users")
+ result.delete("clients")
+ result.delete("groups")
result
end
@@ -41,7 +41,7 @@ class Chef
end
def preserve_key?(key)
- return key == 'name'
+ key == "name"
end
def chef_class
diff --git a/lib/chef/chef_fs/data_handler/node_data_handler.rb b/lib/chef/chef_fs/data_handler/node_data_handler.rb
index 04faa527f0..a0087ec5d6 100644
--- a/lib/chef/chef_fs/data_handler/node_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/node_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/node'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/node"
class Chef
module ChefFS
@@ -7,22 +7,22 @@ class Chef
class NodeDataHandler < DataHandlerBase
def normalize(node, entry)
result = normalize_hash(node, {
- 'name' => remove_dot_json(entry.name),
- 'json_class' => 'Chef::Node',
- 'chef_type' => 'node',
- 'chef_environment' => '_default',
- 'override' => {},
- 'normal' => {},
- 'default' => {},
- 'automatic' => {},
- 'run_list' => []
+ "name" => remove_dot_json(entry.name),
+ "json_class" => "Chef::Node",
+ "chef_type" => "node",
+ "chef_environment" => "_default",
+ "override" => {},
+ "normal" => {},
+ "default" => {},
+ "automatic" => {},
+ "run_list" => [],
})
- result['run_list'] = normalize_run_list(result['run_list'])
+ result["run_list"] = normalize_run_list(result["run_list"])
result
end
def preserve_key?(key)
- return key == 'name'
+ key == "name"
end
def chef_class
diff --git a/lib/chef/chef_fs/data_handler/organization_data_handler.rb b/lib/chef/chef_fs/data_handler/organization_data_handler.rb
index da911c08f0..0a697ab69a 100644
--- a/lib/chef/chef_fs/data_handler/organization_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/organization_data_handler.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
class Chef
module ChefFS
@@ -6,22 +6,28 @@ class Chef
class OrganizationDataHandler < DataHandlerBase
def normalize(organization, entry)
result = normalize_hash(organization, {
- 'name' => entry.org,
- 'full_name' => entry.org,
- 'org_type' => 'Business',
- 'clientname' => "#{entry.org}-validator",
- 'billing_plan' => 'platform-free',
+ "name" => entry.org,
+ "full_name" => entry.org,
+ "org_type" => "Business",
+ "clientname" => "#{entry.org}-validator",
+ "billing_plan" => "platform-free",
})
result
end
def preserve_key?(key)
- return key == 'name'
+ key == "name"
end
- def verify_integrity(object, entry, &on_error)
- if entry.org != object['name']
- on_error.call("Name must be '#{entry.org}' (is '#{object['name']}')")
+ # Verify that the JSON hash for this type has a key that matches its name.
+ #
+ # @param object [Object] JSON hash of the object
+ # @param entry [Chef::ChefFS::FileSystem::BaseFSObject] filesystem object we are verifying
+ # @yield [s] callback to handle errors
+ # @yieldparam [s<string>] error message
+ def verify_integrity(object, entry)
+ if entry.org != object["name"]
+ yield("Name must be '#{entry.org}' (is '#{object['name']}')")
end
end
end
diff --git a/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb b/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb
index db56ecc504..c5a5f873c5 100644
--- a/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb
@@ -1,11 +1,11 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
class Chef
module ChefFS
module DataHandler
class OrganizationInvitesDataHandler < DataHandlerBase
def normalize(invites, entry)
- invites.map { |invite| invite.is_a?(Hash) ? invite['username'] : invite }.sort.uniq
+ invites.map { |invite| invite.is_a?(Hash) ? invite["username"] : invite }.sort.uniq
end
def minimize(invites, entry)
diff --git a/lib/chef/chef_fs/data_handler/organization_members_data_handler.rb b/lib/chef/chef_fs/data_handler/organization_members_data_handler.rb
index afa331775c..8e452a413c 100644
--- a/lib/chef/chef_fs/data_handler/organization_members_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/organization_members_data_handler.rb
@@ -1,11 +1,11 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
class Chef
module ChefFS
module DataHandler
class OrganizationMembersDataHandler < DataHandlerBase
def normalize(members, entry)
- members.map { |member| member.is_a?(Hash) ? member['user']['username'] : member }.sort.uniq
+ members.map { |member| member.is_a?(Hash) ? member["user"]["username"] : member }.sort.uniq
end
def minimize(members, entry)
diff --git a/lib/chef/chef_fs/data_handler/policy_data_handler.rb b/lib/chef/chef_fs/data_handler/policy_data_handler.rb
index 769c13c364..fa7bbe9101 100644
--- a/lib/chef/chef_fs/data_handler/policy_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/policy_data_handler.rb
@@ -1,15 +1,48 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
class Chef
module ChefFS
module DataHandler
class PolicyDataHandler < DataHandlerBase
+ def name_and_revision(name)
+ # foo-1.0.0 = foo, 1.0.0
+ name = remove_dot_json(name)
+ if name =~ /^(.*)-([^-]*)$/
+ name, revision_id = $1, $2
+ end
+ revision_id ||= "0.0.0"
+ [ name, revision_id ]
+ end
def normalize(policy, entry)
- policy
+ # foo-1.0.0 = foo, 1.0.0
+ name, revision_id = name_and_revision(entry.name)
+ defaults = {
+ "name" => name,
+ "revision_id" => revision_id,
+ "run_list" => [],
+ "cookbook_locks" => {},
+ }
+ normalize_hash(policy, defaults)
+ end
+
+ # Verify that the JSON hash for this type has a key that matches its name.
+ #
+ # @param object [Object] JSON hash of the object
+ # @param entry [Chef::ChefFS::FileSystem::BaseFSObject] filesystem object we are verifying
+ # @yield [s] callback to handle errors
+ # @yieldparam [s<string>] error message
+ def verify_integrity(object_data, entry)
+ name, revision = name_and_revision(entry.name)
+ if object_data["name"] != name
+ yield("Object name '#{object_data['name']}' doesn't match entry '#{name}'.")
+ end
+
+ if object_data["revision_id"] != revision
+ yield("Object revision ID '#{object_data['revision_id']}' doesn't match entry '#{revision}'.")
+ end
end
end
end
end
end
-
diff --git a/lib/chef/chef_fs/data_handler/policy_group_data_handler.rb b/lib/chef/chef_fs/data_handler/policy_group_data_handler.rb
new file mode 100644
index 0000000000..f7aa92373c
--- /dev/null
+++ b/lib/chef/chef_fs/data_handler/policy_group_data_handler.rb
@@ -0,0 +1,33 @@
+require "chef/chef_fs/data_handler/data_handler_base"
+
+class Chef
+ module ChefFS
+ module DataHandler
+ class PolicyGroupDataHandler < DataHandlerBase
+
+ def normalize(policy_group, entry)
+ defaults = {
+ "name" => remove_dot_json(entry.name),
+ "policies" => {},
+ }
+ result = normalize_hash(policy_group, defaults)
+ result.delete("uri") # not useful data
+ result
+ end
+
+ # Verify that the JSON hash for this type has a key that matches its name.
+ #
+ # @param object [Object] JSON hash of the object
+ # @param entry [Chef::ChefFS::FileSystem::BaseFSObject] filesystem object we are verifying
+ # @yield [s] callback to handle errors
+ # @yieldparam [s<string>] error message
+ def verify_integrity(object_data, entry)
+ if object_data["policies"].empty?
+ yield("Policy group #{object_data["name"]} does not have any policies in it.")
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/data_handler/role_data_handler.rb b/lib/chef/chef_fs/data_handler/role_data_handler.rb
index 21c3013e9f..b26271f3e8 100644
--- a/lib/chef/chef_fs/data_handler/role_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/role_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/role'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/role"
class Chef
module ChefFS
@@ -7,24 +7,24 @@ class Chef
class RoleDataHandler < DataHandlerBase
def normalize(role, entry)
result = normalize_hash(role, {
- 'name' => remove_dot_json(entry.name),
- 'description' => '',
- 'json_class' => 'Chef::Role',
- 'chef_type' => 'role',
- 'default_attributes' => {},
- 'override_attributes' => {},
- 'run_list' => [],
- 'env_run_lists' => {}
+ "name" => remove_file_extension(entry.name),
+ "description" => "",
+ "json_class" => "Chef::Role",
+ "chef_type" => "role",
+ "default_attributes" => {},
+ "override_attributes" => {},
+ "run_list" => [],
+ "env_run_lists" => {},
})
- result['run_list'] = normalize_run_list(result['run_list'])
- result['env_run_lists'].each_pair do |env, run_list|
- result['env_run_lists'][env] = normalize_run_list(run_list)
+ result["run_list"] = normalize_run_list(result["run_list"])
+ result["env_run_lists"].each_pair do |env, run_list|
+ result["env_run_lists"][env] = normalize_run_list(run_list)
end
result
end
def preserve_key?(key)
- return key == 'name'
+ key == "name"
end
def chef_class
@@ -32,7 +32,7 @@ class Chef
end
def to_ruby(object)
- to_ruby_keys(object, %w(name description default_attributes override_attributes run_list env_run_lists))
+ to_ruby_keys(object, %w{name description default_attributes override_attributes run_list env_run_lists})
end
end
end
diff --git a/lib/chef/chef_fs/data_handler/user_data_handler.rb b/lib/chef/chef_fs/data_handler/user_data_handler.rb
index f6859faccd..4da2f8225d 100644
--- a/lib/chef/chef_fs/data_handler/user_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/user_data_handler.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
class Chef
module ChefFS
@@ -6,20 +6,20 @@ class Chef
class UserDataHandler < DataHandlerBase
def normalize(user, entry)
normalize_hash(user, {
- 'name' => remove_dot_json(entry.name),
- 'username' => remove_dot_json(entry.name),
- 'display_name' => remove_dot_json(entry.name),
- 'admin' => false,
- 'json_class' => 'Chef::WebUIUser',
- 'chef_type' => 'webui_user',
- 'salt' => nil,
- 'password' => nil,
- 'openid' => nil
+ "name" => remove_dot_json(entry.name),
+ "username" => remove_dot_json(entry.name),
+ "display_name" => remove_dot_json(entry.name),
+ "admin" => false,
+ "json_class" => "Chef::WebUIUser",
+ "chef_type" => "webui_user",
+ "salt" => nil,
+ "password" => nil,
+ "openid" => nil,
})
end
def preserve_key?(key)
- return key == 'name'
+ key == "name"
end
# There is no chef_class for users, nor does to_ruby work.
diff --git a/lib/chef/chef_fs/file_pattern.rb b/lib/chef/chef_fs/file_pattern.rb
index b2351dac68..835e06eab7 100644
--- a/lib/chef/chef_fs/file_pattern.rb
+++ b/lib/chef/chef_fs/file_pattern.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/chef_fs'
-require 'chef/chef_fs/path_utils'
+require "chef/chef_fs"
+require "chef/chef_fs/path_utils"
class Chef
module ChefFS
@@ -70,21 +70,21 @@ class Chef
# abc/def.could_match_children?('x') == false
# a**z.could_match_children?('ab/cd') == true
def could_match_children?(path)
- return false if path == '' # Empty string is not a path
+ return false if path == "" # Empty string is not a path
- argument_is_absolute = Chef::ChefFS::PathUtils::is_absolute?(path)
+ argument_is_absolute = Chef::ChefFS::PathUtils.is_absolute?(path)
return false if is_absolute != argument_is_absolute
- path = path[1,path.length-1] if argument_is_absolute
+ path = path[1, path.length - 1] if argument_is_absolute
- path_parts = Chef::ChefFS::PathUtils::split(path)
+ path_parts = Chef::ChefFS::PathUtils.split(path)
# If the pattern is shorter than the path (or same size), children will be larger than the pattern, and will not match.
return false if regexp_parts.length <= path_parts.length && !has_double_star
# If the path doesn't match up to this point, children won't match either.
- return false if path_parts.zip(regexp_parts).any? { |part,regexp| !regexp.nil? && !regexp.match(part) }
+ return false if path_parts.zip(regexp_parts).any? { |part, regexp| !regexp.nil? && !regexp.match(part) }
# Otherwise, it's possible we could match: the path matches to this point, and the pattern is longer than the path.
# TODO There is one edge case where the double star comes after some characters like abc**def--we could check whether the next
# bit of path starts with abc in that case.
- return true
+ true
end
# Returns the immediate child of a path that would be matched
@@ -111,10 +111,10 @@ class Chef
#
# This method assumes +could_match_children?(path)+ is +true+.
def exact_child_name_under(path)
- path = path[1,path.length-1] if Chef::ChefFS::PathUtils::is_absolute?(path)
- dirs_in_path = Chef::ChefFS::PathUtils::split(path).length
+ path = path[1, path.length - 1] if Chef::ChefFS::PathUtils.is_absolute?(path)
+ dirs_in_path = Chef::ChefFS::PathUtils.split(path).length
return nil if exact_parts.length <= dirs_in_path
- return exact_parts[dirs_in_path]
+ exact_parts[dirs_in_path]
end
# If this pattern represents an exact path, returns the exact path.
@@ -124,8 +124,8 @@ class Chef
# abc/x\\yz.exact_path == 'abc/xyz'
def exact_path
return nil if has_double_star || exact_parts.any? { |part| part.nil? }
- result = Chef::ChefFS::PathUtils::join(*exact_parts)
- is_absolute ? Chef::ChefFS::PathUtils::join('', result) : result
+ result = Chef::ChefFS::PathUtils.join(*exact_parts)
+ is_absolute ? Chef::ChefFS::PathUtils.join("", result) : result
end
# Returns the normalized version of the pattern, with / as the directory
@@ -149,9 +149,9 @@ class Chef
# abc/*/def.match?('abc/foo/def') == true
# abc/*/def.match?('abc/foo') == false
def match?(path)
- argument_is_absolute = Chef::ChefFS::PathUtils::is_absolute?(path)
+ argument_is_absolute = Chef::ChefFS::PathUtils.is_absolute?(path)
return false if is_absolute != argument_is_absolute
- path = path[1,path.length-1] if argument_is_absolute
+ path = path[1, path.length - 1] if argument_is_absolute
!!regexp.match(path)
end
@@ -160,7 +160,7 @@ class Chef
pattern
end
- private
+ private
def regexp
calculate
@@ -184,7 +184,7 @@ class Chef
def calculate
if !@regexp
- @is_absolute = Chef::ChefFS::PathUtils::is_absolute?(@pattern)
+ @is_absolute = Chef::ChefFS::PathUtils.is_absolute?(@pattern)
full_regexp_parts = []
normalized_parts = []
@@ -192,19 +192,19 @@ class Chef
@exact_parts = []
@has_double_star = false
- Chef::ChefFS::PathUtils::split(pattern).each do |part|
- regexp, exact, has_double_star = FilePattern::pattern_to_regexp(part)
+ Chef::ChefFS::PathUtils.split(pattern).each do |part|
+ regexp, exact, has_double_star = FilePattern.pattern_to_regexp(part)
if has_double_star
@has_double_star = true
end
# Skip // and /./ (pretend it's not there)
- if exact == '' || exact == '.'
+ if exact == "" || exact == "."
next
end
# Back up when you see .. (unless the prior part has ** in it, in which case .. must be preserved)
- if exact == '..'
+ if exact == ".."
if @is_absolute && normalized_parts.length == 0
# If we are at the root, just pretend the .. isn't there
next
@@ -232,14 +232,14 @@ class Chef
end
end
- @regexp = Regexp.new("^#{full_regexp_parts.join(Chef::ChefFS::PathUtils::regexp_path_separator)}$")
+ @regexp = Regexp.new("^#{full_regexp_parts.join(Chef::ChefFS::PathUtils.regexp_path_separator)}$")
@normalized_pattern = Chef::ChefFS::PathUtils.join(*normalized_parts)
- @normalized_pattern = Chef::ChefFS::PathUtils.join('', @normalized_pattern) if @is_absolute
+ @normalized_pattern = Chef::ChefFS::PathUtils.join("", @normalized_pattern) if @is_absolute
end
end
def self.pattern_special_characters
- if Chef::ChefFS::windows?
+ if Chef::ChefFS.windows?
@pattern_special_characters ||= /(\*\*|\*|\?|[\*\?\.\|\(\)\[\]\{\}\+\\\\\^\$])/
else
# Unix also supports character regexes and backslashes
@@ -249,7 +249,7 @@ class Chef
end
def self.regexp_escape_characters
- [ '[', '\\', '^', '$', '.', '|', '?', '*', '+', '(', ')', '{', '}' ]
+ [ "[", '\\', "^", "$", ".", "|", "?", "*", "+", "(", ")", "{", "}" ]
end
def self.pattern_to_regexp(pattern)
@@ -258,32 +258,32 @@ class Chef
has_double_star = false
pattern.split(pattern_special_characters).each_with_index do |part, index|
# Odd indexes from the split are symbols. Even are normal bits.
- if index % 2 == 0
+ if index.even?
exact << part if !exact.nil?
regexp << part
else
case part
# **, * and ? happen on both platforms.
- when '**'
+ when "**"
exact = nil
has_double_star = true
- regexp << '.*'
- when '*'
+ regexp << ".*"
+ when "*"
exact = nil
regexp << '[^\/]*'
- when '?'
+ when "?"
exact = nil
- regexp << '.'
+ regexp << "."
else
- if part[0,1] == '\\' && part.length == 2
+ if part[0, 1] == '\\' && part.length == 2
# backslash escapes are only supported on Unix, and are handled here by leaving the escape on (it means the same thing in a regex)
- exact << part[1,1] if !exact.nil?
- if regexp_escape_characters.include?(part[1,1])
+ exact << part[1, 1] if !exact.nil?
+ if regexp_escape_characters.include?(part[1, 1])
regexp << part
else
- regexp << part[1,1]
+ regexp << part[1, 1]
end
- elsif part[0,1] == '[' && part.length > 1
+ elsif part[0, 1] == "[" && part.length > 1
# [...] happens only on Unix, and is handled here by *not* backslashing (it means the same thing in and out of regex)
exact = nil
regexp << part
diff --git a/lib/chef/chef_fs/file_system.rb b/lib/chef/chef_fs/file_system.rb
index 3ab59046cc..cbd8aa71d9 100644
--- a/lib/chef/chef_fs/file_system.rb
+++ b/lib/chef/chef_fs/file_system.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,9 @@
# limitations under the License.
#
-require 'chef/chef_fs/path_utils'
-require 'chef/chef_fs/file_system/default_environment_cannot_be_modified_error'
-require 'chef/chef_fs/file_system/operation_failed_error'
-require 'chef/chef_fs/file_system/operation_not_allowed_error'
-require 'chef/chef_fs/parallelizer'
+require "chef/chef_fs/path_utils"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/chef_fs/parallelizer"
class Chef
module ChefFS
@@ -54,13 +52,13 @@ class Chef
def list_from(entry, &block)
# Include self in results if it matches
- if pattern.match?(entry.path)
- block.call(entry)
+ if pattern.match?(entry.display_path)
+ yield(entry)
end
- if pattern.could_match_children?(entry.path)
+ if pattern.could_match_children?(entry.display_path)
# If it's possible that our children could match, descend in and add matches.
- exact_child_name = pattern.exact_child_name_under(entry.path)
+ exact_child_name = pattern.exact_child_name_under(entry.display_path)
# If we've got an exact name, don't bother listing children; just grab the
# child with the given name.
@@ -70,9 +68,9 @@ class Chef
list_from(exact_child, &block)
end
- # Otherwise, go through all children and find any matches
+ # Otherwise, go through all children and find any matches
elsif entry.dir?
- results = Parallelizer::parallelize(entry.children) { |child| Chef::ChefFS::FileSystem.list(child, pattern) }
+ results = Parallelizer.parallelize(entry.children) { |child| Chef::ChefFS::FileSystem.list(child, pattern) }
results.flatten(1).each(&block)
end
end
@@ -95,13 +93,13 @@ class Chef
#
def self.resolve_path(entry, path)
return entry if path.length == 0
- return resolve_path(entry.root, path) if path[0,1] == "/" && entry.root != entry
- if path[0,1] == "/"
- path = path[1,path.length-1]
+ return resolve_path(entry.root, path) if path[0, 1] == "/" && entry.root != entry
+ if path[0, 1] == "/"
+ path = path[1, path.length - 1]
end
result = entry
- Chef::ChefFS::PathUtils::split(path).each do |part|
+ Chef::ChefFS::PathUtils.split(path).each do |part|
result = result.child(part)
end
result
@@ -188,16 +186,16 @@ class Chef
# Make sure everything on the server is also on the filesystem, and diff
found_paths = Set.new
Chef::ChefFS::FileSystem.list(a_root, pattern).each do |a|
- found_paths << a.path
- b = Chef::ChefFS::FileSystem.resolve_path(b_root, a.path)
+ found_paths << a.display_path
+ b = Chef::ChefFS::FileSystem.resolve_path(b_root, a.display_path)
yield [ a, b ]
end
# Check the outer regex pattern to see if it matches anything on the
# filesystem that isn't on the server
Chef::ChefFS::FileSystem.list(b_root, pattern).each do |b|
- if !found_paths.include?(b.path)
- a = Chef::ChefFS::FileSystem.resolve_path(a_root, b.path)
+ if !found_paths.include?(b.display_path)
+ a = Chef::ChefFS::FileSystem.resolve_path(a_root, b.display_path)
yield [ a, b ]
end
end
@@ -224,14 +222,14 @@ class Chef
result = []
a_children_names = Set.new
a.children.each do |a_child|
- a_children_names << a_child.name
- result << [ a_child, b.child(a_child.name) ]
+ a_children_names << a_child.bare_name
+ result << [ a_child, b.child(a_child.bare_name) ]
end
# Check b for children that aren't in a
b.children.each do |b_child|
- if !a_children_names.include?(b_child.name)
- result << [ a.child(b_child.name), b_child ]
+ if !a_children_names.include?(b_child.bare_name)
+ result << [ a.child(b_child.bare_name), b_child ]
end
end
result
@@ -259,170 +257,174 @@ class Chef
[ are_same, a_value, b_value ]
end
- private
-
- # Copy two entries (could be files or dirs)
- def self.copy_entries(src_entry, dest_entry, new_dest_parent, recurse_depth, options, ui, format_path)
- # A NOTE about this algorithm:
- # There are cases where this algorithm does too many network requests.
- # knife upload with a specific filename will first check if the file
- # exists (a "dir" in the parent) before deciding whether to POST or
- # PUT it. If we just tried PUT (or POST) and then tried the other if
- # the conflict failed, we wouldn't need to check existence.
- # On the other hand, we may already have DONE the request, in which
- # case we shouldn't waste time trying PUT if we know the file doesn't
- # exist.
- # Will need to decide how that works with checksums, though.
- error = false
- begin
- dest_path = format_path.call(dest_entry) if ui
- src_path = format_path.call(src_entry) if ui
- if !src_entry.exists?
- if options[:purge]
- # If we would not have uploaded it, we will not purge it.
- if src_entry.parent.can_have_child?(dest_entry.name, dest_entry.dir?)
- if options[:dry_run]
- ui.output "Would delete #{dest_path}" if ui
- else
- begin
- dest_entry.delete(true)
- ui.output "Deleted extra entry #{dest_path} (purge is on)" if ui
- rescue Chef::ChefFS::FileSystem::NotFoundError
- ui.output "Entry #{dest_path} does not exist. Nothing to do. (purge is on)" if ui
+ class << self
+ private
+
+ # Copy two entries (could be files or dirs)
+ def copy_entries(src_entry, dest_entry, new_dest_parent, recurse_depth, options, ui, format_path)
+ # A NOTE about this algorithm:
+ # There are cases where this algorithm does too many network requests.
+ # knife upload with a specific filename will first check if the file
+ # exists (a "dir" in the parent) before deciding whether to POST or
+ # PUT it. If we just tried PUT (or POST) and then tried the other if
+ # the conflict failed, we wouldn't need to check existence.
+ # On the other hand, we may already have DONE the request, in which
+ # case we shouldn't waste time trying PUT if we know the file doesn't
+ # exist.
+ # Will need to decide how that works with checksums, though.
+ error = false
+ begin
+ dest_path = format_path.call(dest_entry) if ui
+ src_path = format_path.call(src_entry) if ui
+ if !src_entry.exists?
+ if options[:purge]
+ # If we would not have uploaded it, we will not purge it.
+ if src_entry.parent.can_have_child?(dest_entry.name, dest_entry.dir?)
+ if options[:dry_run]
+ ui.output "Would delete #{dest_path}" if ui
+ else
+ begin
+ dest_entry.delete(true)
+ ui.output "Deleted extra entry #{dest_path} (purge is on)" if ui
+ rescue Chef::ChefFS::FileSystem::NotFoundError
+ ui.output "Entry #{dest_path} does not exist. Nothing to do. (purge is on)" if ui
+ end
end
- end
- else
- ui.output ("Not deleting extra entry #{dest_path} (purge is off)") if ui
- end
- end
-
- elsif !dest_entry.exists?
- if new_dest_parent.can_have_child?(src_entry.name, src_entry.dir?)
- # If the entry can do a copy directly from filesystem, do that.
- if new_dest_parent.respond_to?(:create_child_from)
- if options[:dry_run]
- ui.output "Would create #{dest_path}" if ui
else
- new_dest_parent.create_child_from(src_entry)
- ui.output "Created #{dest_path}" if ui
+ ui.output ("Not deleting extra entry #{dest_path} (purge is off)") if ui
end
- return
end
- if src_entry.dir?
- if options[:dry_run]
- ui.output "Would create #{dest_path}" if ui
- new_dest_dir = new_dest_parent.child(src_entry.name)
- else
- new_dest_dir = new_dest_parent.create_child(src_entry.name, nil)
- ui.output "Created #{dest_path}" if ui
- end
- # Directory creation is recursive.
- if recurse_depth != 0
- parallel_do(src_entry.children) do |src_child|
- new_dest_child = new_dest_dir.child(src_child.name)
- child_error = copy_entries(src_child, new_dest_child, new_dest_dir, recurse_depth ? recurse_depth - 1 : recurse_depth, options, ui, format_path)
- error ||= child_error
+ elsif !dest_entry.exists?
+ if new_dest_parent.can_have_child?(src_entry.name, src_entry.dir?)
+ # If the entry can do a copy directly from filesystem, do that.
+ if new_dest_parent.respond_to?(:create_child_from)
+ if options[:dry_run]
+ ui.output "Would create #{dest_path}" if ui
+ else
+ new_dest_parent.create_child_from(src_entry)
+ ui.output "Created #{dest_path}" if ui
end
+ return
end
- else
- if options[:dry_run]
- ui.output "Would create #{dest_path}" if ui
- else
- new_dest_parent.create_child(src_entry.name, src_entry.read)
- ui.output "Created #{dest_path}" if ui
- end
- end
- end
-
- else
- # Both exist.
- # If the entry can do a copy directly, do that.
- if dest_entry.respond_to?(:copy_from)
- if options[:force] || compare(src_entry, dest_entry)[0] == false
- if options[:dry_run]
- ui.output "Would update #{dest_path}" if ui
+ if src_entry.dir?
+ if options[:dry_run]
+ ui.output "Would create #{dest_path}" if ui
+ new_dest_dir = new_dest_parent.child(src_entry.name)
+ else
+ new_dest_dir = new_dest_parent.create_child(src_entry.name, nil)
+ ui.output "Created #{dest_path}" if ui
+ end
+ # Directory creation is recursive.
+ if recurse_depth != 0
+ parallel_do(src_entry.children) do |src_child|
+ new_dest_child = new_dest_dir.child(src_child.name)
+ child_error = copy_entries(src_child, new_dest_child, new_dest_dir, recurse_depth ? recurse_depth - 1 : recurse_depth, options, ui, format_path)
+ error ||= child_error
+ end
+ end
else
- dest_entry.copy_from(src_entry, options)
- ui.output "Updated #{dest_path}" if ui
+ if options[:dry_run]
+ ui.output "Would create #{dest_path}" if ui
+ else
+ child = new_dest_parent.create_child(src_entry.name, src_entry.read)
+ ui.output "Created #{format_path.call(child)}" if ui
+ end
end
end
- return
- end
- # If they are different types, log an error.
- if src_entry.dir?
- if dest_entry.dir?
- # If both are directories, recurse into their children
- if recurse_depth != 0
- parallel_do(child_pairs(src_entry, dest_entry)) do |src_child, dest_child|
- child_error = copy_entries(src_child, dest_child, dest_entry, recurse_depth ? recurse_depth - 1 : recurse_depth, options, ui, format_path)
- error ||= child_error
+ else
+ # Both exist.
+
+ # If the entry can do a copy directly, do that.
+ if dest_entry.respond_to?(:copy_from)
+ if options[:force] || compare(src_entry, dest_entry)[0] == false
+ if options[:dry_run]
+ ui.output "Would update #{dest_path}" if ui
+ else
+ dest_entry.copy_from(src_entry, options)
+ ui.output "Updated #{dest_path}" if ui
end
end
- else
- # If they are different types.
- ui.error("File #{src_path} is a directory while file #{dest_path} is a regular file\n") if ui
return
end
- else
- if dest_entry.dir?
- ui.error("File #{src_path} is a regular file while file #{dest_path} is a directory\n") if ui
- return
- else
- # Both are files! Copy them unless we're sure they are the same.'
- if options[:diff] == false
- should_copy = false
- elsif options[:force]
- should_copy = true
- src_value = nil
+ # If they are different types, log an error.
+ if src_entry.dir?
+ if dest_entry.dir?
+ # If both are directories, recurse into their children
+ if recurse_depth != 0
+ parallel_do(child_pairs(src_entry, dest_entry)) do |src_child, dest_child|
+ child_error = copy_entries(src_child, dest_child, dest_entry, recurse_depth ? recurse_depth - 1 : recurse_depth, options, ui, format_path)
+ error ||= child_error
+ end
+ end
else
- are_same, src_value, _dest_value = compare(src_entry, dest_entry)
- should_copy = !are_same
+ # If they are different types.
+ ui.error("File #{src_path} is a directory while file #{dest_path} is a regular file\n") if ui
+ return
end
- if should_copy
- if options[:dry_run]
- ui.output "Would update #{dest_path}" if ui
+ else
+ if dest_entry.dir?
+ ui.error("File #{src_path} is a regular file while file #{dest_path} is a directory\n") if ui
+ return
+ else
+
+ # Both are files! Copy them unless we're sure they are the same.'
+ if options[:diff] == false
+ should_copy = false
+ elsif options[:force]
+ should_copy = true
+ src_value = nil
else
- src_value = src_entry.read if src_value.nil?
- dest_entry.write(src_value)
- ui.output "Updated #{dest_path}" if ui
+ are_same, src_value, _dest_value = compare(src_entry, dest_entry)
+ should_copy = !are_same
+ end
+ if should_copy
+ if options[:dry_run]
+ ui.output "Would update #{dest_path}" if ui
+ else
+ src_value = src_entry.read if src_value.nil?
+ dest_entry.write(src_value)
+ ui.output "Updated #{dest_path}" if ui
+ end
end
end
end
end
+ rescue RubyFileError => e
+ ui.warn "#{format_path.call(e.entry)} #{e.reason}." if ui
+ rescue DefaultEnvironmentCannotBeModifiedError => e
+ ui.warn "#{format_path.call(e.entry)} #{e.reason}." if ui
+ rescue OperationFailedError => e
+ ui.error "#{format_path.call(e.entry)} failed to #{e.operation}: #{e.message}" if ui
+ error = true
+ rescue OperationNotAllowedError => e
+ ui.error "#{format_path.call(e.entry)} #{e.reason}." if ui
+ error = true
end
- rescue DefaultEnvironmentCannotBeModifiedError => e
- ui.warn "#{format_path.call(e.entry)} #{e.reason}." if ui
- rescue OperationFailedError => e
- ui.error "#{format_path.call(e.entry)} failed to #{e.operation}: #{e.message}" if ui
- error = true
- rescue OperationNotAllowedError => e
- ui.error "#{format_path.call(e.entry)} #{e.reason}." if ui
- error = true
+ error
end
- error
- end
- def self.get_or_create_parent(entry, options, ui, format_path)
- parent = entry.parent
- if parent && !parent.exists?
- parent_path = format_path.call(parent) if ui
- parent_parent = get_or_create_parent(parent, options, ui, format_path)
- if options[:dry_run]
- ui.output "Would create #{parent_path}" if ui
- else
- parent = parent_parent.create_child(parent.name, nil)
- ui.output "Created #{parent_path}" if ui
+ def get_or_create_parent(entry, options, ui, format_path)
+ parent = entry.parent
+ if parent && !parent.exists?
+ parent_path = format_path.call(parent) if ui
+ parent_parent = get_or_create_parent(parent, options, ui, format_path)
+ if options[:dry_run]
+ ui.output "Would create #{parent_path}" if ui
+ else
+ parent = parent_parent.create_child(parent.name, nil)
+ ui.output "Created #{parent_path}" if ui
+ end
end
+ parent
end
- return parent
- end
- def self.parallel_do(enum, options = {}, &block)
- Chef::ChefFS::Parallelizer.parallel_do(enum, options, &block)
+ def parallel_do(enum, options = {}, &block)
+ Chef::ChefFS::Parallelizer.parallel_do(enum, options, &block)
+ end
end
end
end
diff --git a/lib/chef/chef_fs/file_system/acl_dir.rb b/lib/chef/chef_fs/file_system/acl_dir.rb
deleted file mode 100644
index 9f68d7cda7..0000000000
--- a/lib/chef/chef_fs/file_system/acl_dir.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/acl_entry'
-require 'chef/chef_fs/file_system/operation_not_allowed_error'
-
-class Chef
- module ChefFS
- module FileSystem
- class AclDir < BaseFSDir
- def api_path
- parent.parent.child(name).api_path
- end
-
- def make_child_entry(name, exists = nil)
- result = @children.select { |child| child.name == name }.first if @children
- result || AclEntry.new(name, self, exists)
- end
-
- def can_have_child?(name, is_dir)
- name =~ /\.json$/ && !is_dir
- end
-
- def children
- if @children.nil?
- # Grab the ACTUAL children (/nodes, /containers, etc.) and get their names
- names = parent.parent.child(name).children.map { |child| child.dir? ? "#{child.name}.json" : child.name }
- @children = names.map { |name| make_child_entry(name, true) }
- end
- @children
- end
-
- def create_child(name, file_contents)
- raise OperationNotAllowedError.new(:create_child, self), "ACLs can only be updated, and can only be created when the corresponding object is created."
- end
-
- def data_handler
- parent.data_handler
- end
-
- def rest
- parent.rest
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/acl_entry.rb b/lib/chef/chef_fs/file_system/acl_entry.rb
deleted file mode 100644
index b2545af5ae..0000000000
--- a/lib/chef/chef_fs/file_system/acl_entry.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/file_system/operation_not_allowed_error'
-require 'chef/chef_fs/file_system/operation_failed_error'
-
-class Chef
- module ChefFS
- module FileSystem
- class AclEntry < RestListEntry
- PERMISSIONS = %w(create read update delete grant)
-
- def api_path
- "#{super}/_acl"
- end
-
- def delete(recurse)
- raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self), "ACLs cannot be deleted."
- end
-
- def write(file_contents)
- # ACL writes are fun.
- acls = data_handler.normalize(Chef::JSONCompat.parse(file_contents), self)
- PERMISSIONS.each do |permission|
- begin
- rest.put("#{api_path}/#{permission}", { permission => acls[permission] })
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}"
- rescue Net::HTTPServerException => e
- if e.response.code == "404"
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "HTTP error writing: #{e}"
- end
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/acls_dir.rb b/lib/chef/chef_fs/file_system/acls_dir.rb
deleted file mode 100644
index a8c63726b7..0000000000
--- a/lib/chef/chef_fs/file_system/acls_dir.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/acl_dir'
-require 'chef/chef_fs/file_system/cookbooks_acl_dir'
-require 'chef/chef_fs/file_system/acl_entry'
-require 'chef/chef_fs/data_handler/acl_data_handler'
-
-class Chef
- module ChefFS
- module FileSystem
- class AclsDir < BaseFSDir
- ENTITY_TYPES = %w(clients containers cookbooks data_bags environments groups nodes roles) # we don't read sandboxes, so we don't read their acls
-
- def initialize(parent)
- super('acls', parent)
- end
-
- def data_handler
- @data_handler ||= Chef::ChefFS::DataHandler::AclDataHandler.new
- end
-
- def api_path
- parent.api_path
- end
-
- def make_child_entry(name)
- children.select { |child| child.name == name }.first
- end
-
- def can_have_child?(name, is_dir)
- is_dir ? ENTITY_TYPES.include?(name) : name == 'organization.json'
- end
-
- def children
- if @children.nil?
- @children = ENTITY_TYPES.map do |entity_type|
- case entity_type
- when 'cookbooks'
- CookbooksAclDir.new(entity_type, self)
- else
- AclDir.new(entity_type, self)
- end
- end
- @children << AclEntry.new('organization.json', self, true) # the org acl is retrieved as GET /organizations/ORGNAME/ANYTHINGATALL/_acl
- end
- @children
- end
-
- def rest
- parent.rest
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/base_fs_dir.rb b/lib/chef/chef_fs/file_system/base_fs_dir.rb
index 47e33f961a..2827e5b384 100644
--- a/lib/chef/chef_fs/file_system/base_fs_dir.rb
+++ b/lib/chef/chef_fs/file_system/base_fs_dir.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/base_fs_object'
-require 'chef/chef_fs/file_system/nonexistent_fs_object'
+require "chef/chef_fs/file_system/base_fs_object"
+require "chef/chef_fs/file_system/nonexistent_fs_object"
class Chef
module ChefFS
diff --git a/lib/chef/chef_fs/file_system/base_fs_object.rb b/lib/chef/chef_fs/file_system/base_fs_object.rb
index 916ab8297d..9767b5b1ba 100644
--- a/lib/chef/chef_fs/file_system/base_fs_object.rb
+++ b/lib/chef/chef_fs/file_system/base_fs_object.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/chef_fs/path_utils'
-require 'chef/chef_fs/file_system/operation_not_allowed_error'
+require "chef/chef_fs/path_utils"
+require "chef/chef_fs/file_system/exceptions"
class Chef
module ChefFS
@@ -27,12 +27,12 @@ class Chef
@parent = parent
@name = name
if parent
- @path = Chef::ChefFS::PathUtils::join(parent.path, name)
+ @path = Chef::ChefFS::PathUtils.join(parent.path, name)
else
- if name != ''
+ if name != ""
raise ArgumentError, "Name of root object must be empty string: was '#{name}' instead"
end
- @path = '/'
+ @path = "/"
end
end
@@ -40,6 +40,10 @@ class Chef
attr_reader :parent
attr_reader :path
+ alias_method :display_path, :path
+ alias_method :display_name, :name
+ alias_method :bare_name, :name
+
# Override this if you have a special comparison algorithm that can tell
# you whether this entry is the same as another--either a quicker or a
# more reliable one. Callers will use this to decide whether to upload,
@@ -146,10 +150,10 @@ class Chef
def path_for_printing
if parent
parent_path = parent.path_for_printing
- if parent_path == '.'
+ if parent_path == "."
name
else
- Chef::ChefFS::PathUtils::join(parent.path_for_printing, name)
+ Chef::ChefFS::PathUtils.join(parent.path_for_printing, name)
end
else
name
@@ -180,4 +184,4 @@ class Chef
end
end
-require 'chef/chef_fs/file_system/nonexistent_fs_object'
+require "chef/chef_fs/file_system/nonexistent_fs_object"
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb
deleted file mode 100644
index 7d2a930633..0000000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
-require 'chef/chef_fs/file_system/acls_dir'
-require 'chef/chef_fs/data_handler/acl_data_handler'
-
-class Chef
- module ChefFS
- module FileSystem
- class ChefRepositoryFileSystemAclsDir < ChefRepositoryFileSystemEntry
- def initialize(name, parent, path = nil)
- super(name, parent, path, Chef::ChefFS::DataHandler::AclDataHandler.new)
- end
-
- def can_have_child?(name, is_dir)
- is_dir ? Chef::ChefFS::FileSystem::AclsDir::ENTITY_TYPES.include?(name) : name == 'organization.json'
- end
- end
- end
- end
-end \ No newline at end of file
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb
deleted file mode 100644
index 4391bdbfcd..0000000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry'
-require 'chef/chef_fs/file_system/cookbook_dir'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/cookbook/chefignore'
-require 'chef/cookbook/cookbook_version_loader'
-
-class Chef
- module ChefFS
- module FileSystem
- class ChefRepositoryFileSystemCookbookDir < ChefRepositoryFileSystemCookbookEntry
- def initialize(name, parent, file_path = nil)
- super(name, parent, file_path)
- end
-
- def chef_object
- begin
- loader = Chef::Cookbook::CookbookVersionLoader.new(file_path, parent.chefignore)
- # We need the canonical cookbook name if we are using versioned cookbooks, but we don't
- # want to spend a lot of time adding code to the main Chef libraries
- if root.versioned_cookbooks
- canonical_name = canonical_cookbook_name(File.basename(file_path))
- fail "When versioned_cookbooks mode is on, cookbook #{file_path} must match format <cookbook_name>-x.y.z" unless canonical_name
-
- # KLUDGE: We shouldn't have to use instance_variable_set
- loader.instance_variable_set(:@cookbook_name, canonical_name)
- end
-
- loader.load_cookbooks
- cb = loader.cookbook_version
- if !cb
- Chef::Log.error("Cookbook #{file_path} empty.")
- raise "Cookbook #{file_path} empty."
- end
- cb
- rescue => e
- Chef::Log.error("Could not read #{path_for_printing} into a Chef object: #{e}")
- Chef::Log.error(e.backtrace.join("\n"))
- raise
- end
- end
-
- def children
- super.select { |entry| !(entry.dir? && entry.children.size == 0 ) }
- end
-
- def can_have_child?(name, is_dir)
- if is_dir
- # Only the given directories will be uploaded.
- return CookbookDir::COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) && name != 'root_files'
- elsif name == Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE
- return false
- end
- super(name, is_dir)
- end
-
- # Exposed as a class method so that it can be used elsewhere
- def self.canonical_cookbook_name(entry_name)
- name_match = Chef::ChefFS::FileSystem::CookbookDir::VALID_VERSIONED_COOKBOOK_NAME.match(entry_name)
- return nil if name_match.nil?
- return name_match[1]
- end
-
- def canonical_cookbook_name(entry_name)
- self.class.canonical_cookbook_name(entry_name)
- end
-
- def uploaded_cookbook_version_path
- File.join(file_path, Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE)
- end
-
- def can_upload?
- File.exists?(uploaded_cookbook_version_path) || children.size > 0
- end
-
- protected
-
- def make_child_entry(child_name)
- segment_info = CookbookDir::COOKBOOK_SEGMENT_INFO[child_name.to_sym] || {}
- ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, segment_info[:ruby_only], segment_info[:recursive])
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb
deleted file mode 100644
index 914412f839..0000000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
-require 'chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir'
-require 'chef/chef_fs/file_system/not_found_error'
-
-class Chef
- module ChefFS
- module FileSystem
- class ChefRepositoryFileSystemCookbookEntry < ChefRepositoryFileSystemEntry
- def initialize(name, parent, file_path = nil, ruby_only = false, recursive = false)
- super(name, parent, file_path)
- @ruby_only = ruby_only
- @recursive = recursive
- end
-
- attr_reader :ruby_only
- attr_reader :recursive
-
- def children
- super.select { |entry| !(entry.dir? && entry.children.size == 0 ) }
- end
-
- def can_have_child?(name, is_dir)
- if is_dir
- return recursive && name != '.' && name != '..'
- elsif ruby_only
- return false if name[-3..-1] != '.rb'
- end
-
- # Check chefignore
- ignorer = parent
- loop do
- if ignorer.is_a?(ChefRepositoryFileSystemCookbooksDir)
- # Grab the path from entry to child
- path_to_child = name
- child = self
- while child.parent != ignorer
- path_to_child = PathUtils.join(child.name, path_to_child)
- child = child.parent
- end
- # Check whether that relative path is ignored
- return !ignorer.chefignore || !ignorer.chefignore.ignored?(path_to_child)
- end
- ignorer = ignorer.parent
- break unless ignorer
- end
-
- true
- end
-
- def write_pretty_json
- false
- end
-
- protected
-
- def make_child_entry(child_name)
- ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, ruby_only, recursive)
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb
deleted file mode 100644
index 5b495666c3..0000000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
-require 'chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir'
-require 'chef/cookbook/chefignore'
-
-class Chef
- module ChefFS
- module FileSystem
- class ChefRepositoryFileSystemCookbooksDir < ChefRepositoryFileSystemEntry
- def initialize(name, parent, file_path)
- super(name, parent, file_path)
- begin
- @chefignore = Chef::Cookbook::Chefignore.new(self.file_path)
- rescue Errno::EISDIR
- rescue Errno::EACCES
- # Work around a bug in Chefignore when chefignore is a directory
- end
- end
-
- attr_reader :chefignore
-
- def children
- super.select do |entry|
- # empty cookbooks and cookbook directories are ignored
- if !entry.can_upload?
- Chef::Log.warn("Cookbook '#{entry.name}' is empty or entirely chefignored at #{entry.path_for_printing}")
- false
- else
- true
- end
- end
- end
-
- def can_have_child?(name, is_dir)
- is_dir && !name.start_with?('.')
- end
-
- def write_cookbook(cookbook_path, cookbook_version_json, from_fs)
- cookbook_name = File.basename(cookbook_path)
- child = make_child_entry(cookbook_name)
-
- # Use the copy/diff algorithm to copy it down so we don't destroy
- # chefignored data. This is terribly un-thread-safe.
- Chef::ChefFS::FileSystem.copy_to(Chef::ChefFS::FilePattern.new("/#{cookbook_path}"), from_fs, child, nil, {:purge => true})
-
- # Write out .uploaded-cookbook-version.json
- cookbook_file_path = File.join(file_path, cookbook_name)
- if !File.exists?(cookbook_file_path)
- FileUtils.mkdir_p(cookbook_file_path)
- end
- uploaded_cookbook_version_path = File.join(cookbook_file_path, Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE)
- File.open(uploaded_cookbook_version_path, 'w') do |file|
- file.write(cookbook_version_json)
- end
- end
-
- protected
-
- def make_child_entry(child_name)
- ChefRepositoryFileSystemCookbookDir.new(child_name, self)
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb
deleted file mode 100644
index 39172e7ab9..0000000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Author:: Ho-Sheng Hsiao (<hosh@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/file_system_entry'
-require 'chef/chef_fs/file_system/not_found_error'
-
-class Chef
- module ChefFS
- module FileSystem
- # ChefRepositoryFileSystemEntry works just like FileSystemEntry,
- # except can inflate Chef objects
- class ChefRepositoryFileSystemEntry < FileSystemEntry
- def initialize(name, parent, file_path = nil, data_handler = nil)
- super(name, parent, file_path)
- @data_handler = data_handler
- end
-
- def write_pretty_json=(value)
- @write_pretty_json = value
- end
-
- def write_pretty_json
- @write_pretty_json.nil? ? root.write_pretty_json : @write_pretty_json
- end
-
- def data_handler
- @data_handler || parent.data_handler
- end
-
- def chef_object
- begin
- return data_handler.chef_object(Chef::JSONCompat.parse(read))
- rescue
- Chef::Log.error("Could not read #{path_for_printing} into a Chef object: #{$!}")
- end
- nil
- end
-
- def can_have_child?(name, is_dir)
- !is_dir && name[-5..-1] == '.json'
- end
-
- def write(file_contents)
- if file_contents && write_pretty_json && name[-5..-1] == '.json'
- file_contents = minimize(file_contents, self)
- end
- super(file_contents)
- end
-
- def minimize(file_contents, entry)
- object = Chef::JSONCompat.parse(file_contents)
- object = data_handler.normalize(object, entry)
- object = data_handler.minimize(object, entry)
- Chef::JSONCompat.to_json_pretty(object)
- end
-
- protected
-
- def make_child_entry(child_name)
- ChefRepositoryFileSystemEntry.new(child_name, self)
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
deleted file mode 100644
index 267fe30456..0000000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
+++ /dev/null
@@ -1,196 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
-require 'chef/chef_fs/file_system/chef_repository_file_system_acls_dir'
-require 'chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir'
-require 'chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir'
-require 'chef/chef_fs/file_system/chef_repository_file_system_policies_dir'
-require 'chef/chef_fs/file_system/multiplexed_dir'
-require 'chef/chef_fs/data_handler/client_data_handler'
-require 'chef/chef_fs/data_handler/environment_data_handler'
-require 'chef/chef_fs/data_handler/node_data_handler'
-require 'chef/chef_fs/data_handler/role_data_handler'
-require 'chef/chef_fs/data_handler/user_data_handler'
-require 'chef/chef_fs/data_handler/group_data_handler'
-require 'chef/chef_fs/data_handler/container_data_handler'
-
-class Chef
- module ChefFS
- module FileSystem
-
- #
- # Represents the root of a local Chef repository, with directories for
- # nodes, cookbooks, roles, etc. under it.
- #
- class ChefRepositoryFileSystemRootDir < BaseFSDir
- #
- # Create a new Chef Repository File System root.
- #
- # == Parameters
- # [child_paths]
- # A hash of child paths, e.g.:
- # "nodes" => [ '/var/nodes', '/home/jkeiser/nodes' ],
- # "roles" => [ '/var/roles' ],
- # ...
- # [root_paths]
- # An array of paths representing the top level, where
- # +org.json+, +members.json+, and +invites.json+ will be stored.
- # [chef_config] - a hash of options that looks suspiciously like the ones
- # stored in Chef::Config, containing at least these keys:
- # :versioned_cookbooks:: whether to include versions in cookbook names
- def initialize(child_paths, root_paths=[], chef_config=Chef::Config)
- super("", nil)
- @child_paths = child_paths
- @root_paths = root_paths
- @versioned_cookbooks = chef_config[:versioned_cookbooks]
- end
-
- attr_accessor :write_pretty_json
-
- attr_reader :root_paths
- attr_reader :child_paths
- attr_reader :versioned_cookbooks
-
- CHILDREN = %w(org.json invitations.json members.json)
-
- def children
- @children ||= begin
- result = child_paths.keys.sort.map { |name| make_child_entry(name) }
- result += CHILDREN.map { |name| make_child_entry(name) }
- result.select { |c| c && c.exists? }.sort_by { |c| c.name }
- end
- end
-
- def can_have_child?(name, is_dir)
- if is_dir
- child_paths.has_key?(name)
- elsif root_dir
- CHILDREN.include?(name)
- else
- false
- end
- end
-
- def create_child(name, file_contents = nil)
- if file_contents
- child = root_dir.create_child(name, file_contents)
- else
- child_paths[name].each do |path|
- begin
- Dir.mkdir(path)
- rescue Errno::EEXIST
- end
- end
- child = make_child_entry(name)
- end
- @children = nil
- child
- end
-
- def json_class
- nil
- end
-
- # Used to print out a human-readable file system description
- def fs_description
- repo_paths = root_paths || [ File.dirname(child_paths['cookbooks'][0]) ]
- result = "repository at #{repo_paths.join(', ')}\n"
- if versioned_cookbooks
- result << " Multiple versions per cookbook\n"
- else
- result << " One version per cookbook\n"
- end
- child_paths.each_pair do |name, paths|
- if paths.any? { |path| !repo_paths.include?(File.dirname(path)) }
- result << " #{name} at #{paths.join(', ')}\n"
- end
- end
- result
- end
-
- private
-
- #
- # A FileSystemEntry representing the root path where invites.json,
- # members.json and org.json may be found.
- #
- def root_dir
- existing_paths = root_paths.select { |path| File.exists?(path) }
- if existing_paths.size > 0
- MultiplexedDir.new(existing_paths.map do |path|
- dir = ChefRepositoryFileSystemEntry.new(name, parent, path)
- dir.write_pretty_json = !!write_pretty_json
- dir
- end)
- end
- end
-
- #
- # Create a child entry of the appropriate type:
- # cookbooks, data_bags, acls, etc. All will be multiplexed (i.e. if
- # you have multiple paths for cookbooks, the multiplexed dir will grab
- # cookbooks from all of them when you list or grab them).
- #
- def make_child_entry(name)
- if CHILDREN.include?(name)
- return nil if !root_dir
- return root_dir.child(name)
- end
-
- paths = (child_paths[name] || []).select { |path| File.exists?(path) }
- if paths.size == 0
- return NonexistentFSObject.new(name, self)
- end
- case name
- when 'cookbooks'
- dirs = paths.map { |path| ChefRepositoryFileSystemCookbooksDir.new(name, self, path) }
- when 'data_bags'
- dirs = paths.map { |path| ChefRepositoryFileSystemDataBagsDir.new(name, self, path) }
- when 'policies'
- dirs = paths.map { |path| ChefRepositoryFileSystemPoliciesDir.new(name, self, path) }
- when 'acls'
- dirs = paths.map { |path| ChefRepositoryFileSystemAclsDir.new(name, self, path) }
- else
- data_handler = case name
- when 'clients'
- Chef::ChefFS::DataHandler::ClientDataHandler.new
- when 'environments'
- Chef::ChefFS::DataHandler::EnvironmentDataHandler.new
- when 'nodes'
- Chef::ChefFS::DataHandler::NodeDataHandler.new
- when 'roles'
- Chef::ChefFS::DataHandler::RoleDataHandler.new
- when 'users'
- Chef::ChefFS::DataHandler::UserDataHandler.new
- when 'groups'
- Chef::ChefFS::DataHandler::GroupDataHandler.new
- when 'containers'
- Chef::ChefFS::DataHandler::ContainerDataHandler.new
- else
- raise "Unknown top level path #{name}"
- end
- dirs = paths.map { |path| ChefRepositoryFileSystemEntry.new(name, self, path, data_handler) }
- end
- MultiplexedDir.new(dirs)
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/chef_server/acl_dir.rb b/lib/chef/chef_fs/file_system/chef_server/acl_dir.rb
new file mode 100644
index 0000000000..006098a0c9
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/acl_dir.rb
@@ -0,0 +1,65 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/acl_entry"
+require "chef/chef_fs/file_system/exceptions"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class AclDir < BaseFSDir
+ def api_path
+ parent.parent.child(name).api_path
+ end
+
+ def make_child_entry(name, exists = nil)
+ result = @children.find { |child| child.name == name } if @children
+ result || AclEntry.new(name, self, exists)
+ end
+
+ def can_have_child?(name, is_dir)
+ !is_dir
+ end
+
+ def children
+ if @children.nil?
+ # Grab the ACTUAL children (/nodes, /containers, etc.) and get their names
+ names = parent.parent.child(name).children.map { |child| child.dir? ? "#{child.name}.json" : child.name }
+ @children = names.map { |name| make_child_entry(name, true) }
+ end
+ @children
+ end
+
+ def create_child(name, file_contents)
+ raise OperationNotAllowedError.new(:create_child, self, nil, "ACLs can only be updated, and can only be created when the corresponding object is created.")
+ end
+
+ def data_handler
+ parent.data_handler
+ end
+
+ def rest
+ parent.rest
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/acl_entry.rb b/lib/chef/chef_fs/file_system/chef_server/acl_entry.rb
new file mode 100644
index 0000000000..f4655412fa
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/acl_entry.rb
@@ -0,0 +1,67 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/file_system/exceptions"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class AclEntry < RestListEntry
+ PERMISSIONS = %w{create read update delete grant}
+
+ def api_path
+ "#{super}/_acl"
+ end
+
+ def display_path
+ pth = if parent.name == "acls"
+ "/acls/#{name}"
+ else
+ "/acls/#{parent.name}/#{name}"
+ end
+ File.extname(pth).empty? ? pth + ".json" : pth
+ end
+
+ def delete(recurse)
+ raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self, nil, "ACLs cannot be deleted")
+ end
+
+ def write(file_contents)
+ # ACL writes are fun.
+ acls = data_handler.normalize(Chef::JSONCompat.parse(file_contents), self)
+ PERMISSIONS.each do |permission|
+ begin
+ rest.put("#{api_path}/#{permission}", { permission => acls[permission] })
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "Timeout writing: #{e}")
+ rescue Net::HTTPServerException => e
+ if e.response.code == "404"
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "HTTP error writing: #{e}")
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/acls_dir.rb b/lib/chef/chef_fs/file_system/chef_server/acls_dir.rb
new file mode 100644
index 0000000000..b9af486203
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/acls_dir.rb
@@ -0,0 +1,75 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/acl_dir"
+require "chef/chef_fs/file_system/chef_server/cookbooks_acl_dir"
+require "chef/chef_fs/file_system/chef_server/policies_acl_dir"
+require "chef/chef_fs/file_system/chef_server/acl_entry"
+require "chef/chef_fs/data_handler/acl_data_handler"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class AclsDir < BaseFSDir
+ ENTITY_TYPES = %w{clients containers cookbook_artifacts cookbooks data_bags environments groups nodes policies policy_groups roles} # we don't read sandboxes, so we don't read their acls
+
+ def data_handler
+ @data_handler ||= Chef::ChefFS::DataHandler::AclDataHandler.new
+ end
+
+ def api_path
+ parent.api_path
+ end
+
+ def make_child_entry(name)
+ children.find { |child| child.name == name }
+ end
+
+ def can_have_child?(name, is_dir)
+ is_dir ? ENTITY_TYPES.include?(name) : name == "organization.json"
+ end
+
+ def children
+ if @children.nil?
+ @children = ENTITY_TYPES.map do |entity_type|
+ # All three of these can be versioned (NAME-VERSION), but only have
+ # one ACL that covers them all (NAME.json).
+ case entity_type
+ when "cookbooks", "cookbook_artifacts"
+ CookbooksAclDir.new(entity_type, self)
+ when "policies"
+ PoliciesAclDir.new(entity_type, self)
+ else
+ AclDir.new(entity_type, self)
+ end
+ end
+ @children << AclEntry.new("organization.json", self, true) # the org acl is retrieved as GET /organizations/ORGNAME/ANYTHINGATALL/_acl
+ end
+ @children
+ end
+
+ def rest
+ parent.rest
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/chef_server_root_dir.rb b/lib/chef/chef_fs/file_system/chef_server/chef_server_root_dir.rb
new file mode 100644
index 0000000000..5030a0733f
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/chef_server_root_dir.rb
@@ -0,0 +1,196 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/server_api"
+require "chef/chef_fs/file_system/chef_server/acls_dir"
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/chef_server/cookbooks_dir"
+require "chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir"
+require "chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir"
+require "chef/chef_fs/file_system/chef_server/data_bags_dir"
+require "chef/chef_fs/file_system/chef_server/nodes_dir"
+require "chef/chef_fs/file_system/chef_server/org_entry"
+require "chef/chef_fs/file_system/chef_server/organization_invites_entry"
+require "chef/chef_fs/file_system/chef_server/organization_members_entry"
+require "chef/chef_fs/file_system/chef_server/policies_dir"
+require "chef/chef_fs/file_system/chef_server/policy_groups_dir"
+require "chef/chef_fs/file_system/chef_server/environments_dir"
+require "chef/chef_fs/data_handler/acl_data_handler"
+require "chef/chef_fs/data_handler/client_data_handler"
+require "chef/chef_fs/data_handler/environment_data_handler"
+require "chef/chef_fs/data_handler/node_data_handler"
+require "chef/chef_fs/data_handler/role_data_handler"
+require "chef/chef_fs/data_handler/user_data_handler"
+require "chef/chef_fs/data_handler/group_data_handler"
+require "chef/chef_fs/data_handler/container_data_handler"
+require "chef/chef_fs/data_handler/policy_group_data_handler"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ #
+ # Represents the root of a Chef server (or organization), under which
+ # nodes, roles, cookbooks, etc. can be found.
+ #
+ class ChefServerRootDir < BaseFSDir
+ #
+ # Create a new Chef server root.
+ #
+ # == Parameters
+ #
+ # [root_name]
+ # A friendly name for the root, for printing--like "remote" or "chef_central".
+ # [chef_config]
+ # A hash with options that look suspiciously like Chef::Config, including the
+ # following keys:
+ # :chef_server_url:: The URL to the Chef server or top of the organization
+ # :node_name:: The username to authenticate to the Chef server with
+ # :client_key:: The private key for the user for authentication
+ # :environment:: The environment in which you are presently working
+ # :repo_mode::
+ # The repository mode, :hosted_everything, :everything or :static.
+ # This determines the set of subdirectories the Chef server will
+ # offer up.
+ # :versioned_cookbooks:: whether or not to include versions in cookbook names
+ # [options]
+ # Other options:
+ # :cookbook_version:: when cookbooks are retrieved, grab this version for them.
+ # :freeze:: freeze cookbooks on upload
+ #
+ def initialize(root_name, chef_config, options = {})
+ super("", nil)
+ @chef_server_url = chef_config[:chef_server_url]
+ @chef_username = chef_config[:node_name]
+ @chef_private_key = chef_config[:client_key]
+ @environment = chef_config[:environment]
+ @repo_mode = chef_config[:repo_mode]
+ @versioned_cookbooks = chef_config[:versioned_cookbooks]
+ @root_name = root_name
+ @cookbook_version = options[:cookbook_version] # Used in knife diff and download for server cookbook version
+ end
+
+ attr_reader :chef_server_url
+ attr_reader :chef_username
+ attr_reader :chef_private_key
+ attr_reader :environment
+ attr_reader :repo_mode
+ attr_reader :cookbook_version
+ attr_reader :versioned_cookbooks
+
+ def fs_description
+ "Chef server at #{chef_server_url} (user #{chef_username}), repo_mode = #{repo_mode}"
+ end
+
+ def rest
+ Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :raw_output => true, :api_version => "0")
+ end
+
+ def get_json(path)
+ Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :api_version => "0").get(path)
+ end
+
+ def chef_rest
+ Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key)
+ end
+
+ def api_path
+ ""
+ end
+
+ def path_for_printing
+ "#{@root_name}/"
+ end
+
+ def can_have_child?(name, is_dir)
+ result = children.find { |child| child.name == name }
+ result && !!result.dir? == !!is_dir
+ end
+
+ def org
+ @org ||= begin
+ path = Pathname.new(URI.parse(chef_server_url).path).cleanpath
+ if File.dirname(path) == "/organizations"
+ File.basename(path)
+ else
+ # In Chef 12, everything is in an org.
+ "chef"
+ end
+ end
+ end
+
+ def make_child_entry(name)
+ children.find { |child| child.name == name }
+ end
+
+ def children
+ @children ||= begin
+ result = [
+ # /cookbooks
+ versioned_cookbooks ? VersionedCookbooksDir.new("cookbooks", self) : CookbooksDir.new("cookbooks", self),
+ # /data_bags
+ DataBagsDir.new("data_bags", self, "data"),
+ # /environments
+ EnvironmentsDir.new("environments", self, nil, Chef::ChefFS::DataHandler::EnvironmentDataHandler.new),
+ # /roles
+ RestListDir.new("roles", self, nil, Chef::ChefFS::DataHandler::RoleDataHandler.new),
+ ]
+ if repo_mode == "hosted_everything"
+ result += [
+ # /acls
+ AclsDir.new("acls", self),
+ # /clients
+ RestListDir.new("clients", self, nil, Chef::ChefFS::DataHandler::ClientDataHandler.new),
+ # /containers
+ RestListDir.new("containers", self, nil, Chef::ChefFS::DataHandler::ContainerDataHandler.new),
+ # /cookbook_artifacts
+ CookbookArtifactsDir.new("cookbook_artifacts", self),
+ # /groups
+ RestListDir.new("groups", self, nil, Chef::ChefFS::DataHandler::GroupDataHandler.new),
+ # /nodes
+ NodesDir.new("nodes", self, nil, Chef::ChefFS::DataHandler::NodeDataHandler.new),
+ # /org.json
+ OrgEntry.new("org.json", self),
+ # /members.json
+ OrganizationMembersEntry.new("members.json", self),
+ # /invitations.json
+ OrganizationInvitesEntry.new("invitations.json", self),
+ # /policies
+ PoliciesDir.new("policies", self, nil, Chef::ChefFS::DataHandler::PolicyDataHandler.new),
+ # /policy_groups
+ PolicyGroupsDir.new("policy_groups", self, nil, Chef::ChefFS::DataHandler::PolicyGroupDataHandler.new),
+ ]
+ elsif repo_mode != "static"
+ result += [
+ # /clients
+ RestListDir.new("clients", self, nil, Chef::ChefFS::DataHandler::ClientDataHandler.new),
+ # /nodes
+ NodesDir.new("nodes", self, nil, Chef::ChefFS::DataHandler::NodeDataHandler.new),
+ # /users
+ RestListDir.new("users", self, nil, Chef::ChefFS::DataHandler::UserDataHandler.new),
+ ]
+ end
+ result.sort_by { |child| child.name }
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/platform/handler_map.rb b/lib/chef/chef_fs/file_system/chef_server/cookbook_artifact_dir.rb
index a9551a344b..faea96e944 100644
--- a/lib/chef/platform/handler_map.rb
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbook_artifact_dir.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser (<jkeiser@chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,24 +16,22 @@
# limitations under the License.
#
-require 'chef/node_map'
+require "chef/chef_fs/file_system/chef_server/cookbook_dir"
class Chef
- class Platform
- class HandlerMap < Chef::NodeMap
- #
- # "provides" lines with identical filters sort by class name (ascending).
- #
- def compare_matchers(key, new_matcher, matcher)
- cmp = super
- if cmp == 0
- # Sort by class name (ascending) as well, if all other properties
- # are exactly equal
- if new_matcher[:value].is_a?(Class) && !new_matcher[:override]
- cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:value].name }
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class CookbookArtifactDir < CookbookDir
+ def initialize(name, parent, options = {})
+ super(name, parent)
+ @cookbook_name, dash, @version = name.rpartition("-")
+ end
+
+ def copy_from(other, options = {})
+ raise OperationNotAllowedError.new(:write, self, nil, "cannot be updated: cookbook artifacts are immutable once uploaded")
end
end
- cmp
end
end
end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir.rb
new file mode 100644
index 0000000000..0b82a64a0a
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir.rb
@@ -0,0 +1,102 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/cookbooks_dir"
+require "chef/chef_fs/file_system/chef_server/cookbook_artifact_dir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ #
+ # /cookbook_artifacts
+ #
+ # Example children of /cookbook_artifacts:
+ #
+ # - apache2-ab234098245908ddf324a
+ # - apache2-295387a9823745feff239
+ # - mysql-1a2b9e1298734dfe90444
+ #
+ class CookbookArtifactsDir < CookbooksDir
+
+ def make_child_entry(name)
+ result = @children.find { |child| child.name == name } if @children
+ result || CookbookArtifactDir.new(name, self)
+ end
+
+ def children
+ @children ||= begin
+ result = []
+ root.get_json("#{api_path}/?num_versions=all").each_pair do |cookbook_name, cookbooks|
+ cookbooks["versions"].each do |cookbook_version|
+ result << CookbookArtifactDir.new("#{cookbook_name}-#{cookbook_version['identifier']}", self)
+ end
+ end
+ result.sort_by(&:name)
+ end
+ end
+
+ # Knife currently does not understand versioned cookbooks
+ # Cookbook Version uploader also requires a lot of refactoring
+ # to make this work. So instead, we make a temporary cookbook
+ # symlinking back to real cookbook, and upload the proxy.
+ def upload_cookbook(other, options)
+ cookbook_name, dash, identifier = other.name.rpartition("-")
+
+ Dir.mktmpdir do |temp_cookbooks_path|
+ proxy_cookbook_path = "#{temp_cookbooks_path}/#{cookbook_name}"
+
+ # Make a symlink
+ file_class.symlink other.file_path, proxy_cookbook_path
+
+ # Instantiate a proxy loader using the temporary symlink
+ proxy_loader = Chef::Cookbook::CookbookVersionLoader.new(proxy_cookbook_path, other.parent.chefignore)
+ proxy_loader.load_cookbooks
+
+ cookbook_to_upload = proxy_loader.cookbook_version
+ cookbook_to_upload.identifier = identifier
+ cookbook_to_upload.freeze_version if options[:freeze]
+
+ # Instantiate a new uploader based on the proxy loader
+ uploader = Chef::CookbookUploader.new(cookbook_to_upload, force: options[:force], rest: root.chef_rest, policy_mode: true)
+
+ with_actual_cookbooks_dir(temp_cookbooks_path) do
+ uploader.upload_cookbooks
+ end
+
+ #
+ # When the temporary directory is being deleted on
+ # windows, the contents of the symlink under that
+ # directory is also deleted. So explicitly remove
+ # the symlink without removing the original contents if we
+ # are running on windows
+ #
+ if Chef::Platform.windows?
+ Dir.rmdir proxy_cookbook_path
+ end
+ end
+ end
+
+ def can_have_child?(name, is_dir)
+ is_dir && name.include?("-")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb
new file mode 100644
index 0000000000..8f5faf2183
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb
@@ -0,0 +1,221 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/command_line"
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/chef_server/cookbook_subdir"
+require "chef/chef_fs/file_system/chef_server/cookbook_file"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/cookbook_version"
+require "chef/cookbook_uploader"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ # Unversioned cookbook.
+ #
+ # /cookbooks/NAME
+ #
+ # Children look like:
+ #
+ # - metadata.rb
+ # - attributes/
+ # - libraries/
+ # - recipes/
+ #
+ class CookbookDir < BaseFSDir
+ def initialize(name, parent, options = {})
+ super(name, parent)
+ @exists = options[:exists]
+ @cookbook_name = name
+ @version = root.cookbook_version # nil unless --cookbook-version specified in download/diff
+ end
+
+ attr_reader :cookbook_name, :version
+
+ COOKBOOK_SEGMENT_INFO = {
+ :attributes => { :ruby_only => true },
+ :definitions => { :ruby_only => true },
+ :recipes => { :ruby_only => true },
+ :libraries => { :recursive => true },
+ :templates => { :recursive => true },
+ :files => { :recursive => true },
+ :resources => { :ruby_only => true, :recursive => true },
+ :providers => { :ruby_only => true, :recursive => true },
+ :root_files => {},
+ }
+
+ def add_child(child)
+ @children << child
+ end
+
+ def api_path
+ "#{parent.api_path}/#{cookbook_name}/#{version || "_latest"}"
+ end
+
+ def make_child_entry(name)
+ # Since we're ignoring the rules and doing a network request here,
+ # we need to make sure we don't rethrow the exception. (child(name)
+ # is not supposed to fail.)
+
+ children.find { |child| child.name == name }
+ rescue Chef::ChefFS::FileSystem::NotFoundError
+ nil
+ end
+
+ def can_have_child?(name, is_dir)
+ # A cookbook's root may not have directories unless they are segment directories
+ return name != "root_files" && COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) if is_dir
+ true
+ end
+
+ def children
+ if @children.nil?
+ @children = []
+ manifest = chef_object.manifest
+ COOKBOOK_SEGMENT_INFO.each do |segment, segment_info|
+ next unless manifest.has_key?(segment)
+
+ # Go through each file in the manifest for the segment, and
+ # add cookbook subdirs and files for it.
+ manifest[segment].each do |segment_file|
+ parts = segment_file[:path].split("/")
+ # Get or create the path to the file
+ container = self
+ parts[0, parts.length - 1].each do |part|
+ old_container = container
+ container = old_container.children.find { |child| part == child.name }
+ if !container
+ container = CookbookSubdir.new(part, old_container, segment_info[:ruby_only], segment_info[:recursive])
+ old_container.add_child(container)
+ end
+ end
+ # Create the file itself
+ container.add_child(CookbookFile.new(parts[parts.length - 1], container, segment_file))
+ end
+ end
+ @children = @children.sort_by { |c| c.name }
+ end
+ @children
+ end
+
+ def dir?
+ exists?
+ end
+
+ def delete(recurse)
+ if recurse
+ begin
+ rest.delete(api_path)
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e, "Timeout deleting: #{e}")
+ rescue Net::HTTPServerException
+ if $!.response.code == "404"
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e, "HTTP error deleting: #{e}")
+ end
+ end
+ else
+ raise NotFoundError.new(self) if !exists?
+ raise MustDeleteRecursivelyError.new(self, "#{path_for_printing} must be deleted recursively")
+ end
+ end
+
+ # In versioned cookbook mode, actually check if the version exists
+ # Probably want to cache this.
+ def exists?
+ if @exists.nil?
+ @exists = parent.children.any? { |child| child.name == name }
+ end
+ @exists
+ end
+
+ def compare_to(other)
+ if !other.dir?
+ return [ !exists?, nil, nil ]
+ end
+ are_same = true
+ Chef::ChefFS::CommandLine.diff_entries(self, other, nil, :name_only).each do |type, old_entry, new_entry|
+ if [ :directory_to_file, :file_to_directory, :deleted, :added, :modified ].include?(type)
+ are_same = false
+ end
+ end
+ [ are_same, nil, nil ]
+ end
+
+ def copy_from(other, options = {})
+ parent.upload_cookbook_from(other, options)
+ end
+
+ def rest
+ parent.rest
+ end
+
+ def chef_object
+ # We cheat and cache here, because it seems like a good idea to keep
+ # the cookbook view consistent with the directory structure.
+ return @chef_object if @chef_object
+
+ # The negative (not found) response is cached
+ if @could_not_get_chef_object
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
+ end
+
+ begin
+ # We want to fail fast, for now, because of the 500 issue :/
+ # This will make things worse for parallelism, a little, because
+ # Chef::Config is global and this could affect other requests while
+ # this request is going on. (We're not parallel yet, but we will be.)
+ # Chef bug http://tickets.opscode.com/browse/CHEF-3066
+ old_retry_count = Chef::Config[:http_retry_count]
+ begin
+ Chef::Config[:http_retry_count] = 0
+ @chef_object ||= Chef::CookbookVersion.from_hash(root.get_json(api_path))
+ ensure
+ Chef::Config[:http_retry_count] = old_retry_count
+ end
+
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "Timeout reading: #{e}")
+
+ rescue Net::HTTPServerException => e
+ if e.response.code == "404"
+ @could_not_get_chef_object = e
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "HTTP error reading: #{e}")
+ end
+
+ # Chef bug http://tickets.opscode.com/browse/CHEF-3066 ... instead of 404 we get 500 right now.
+ # Remove this when that bug is fixed.
+ rescue Net::HTTPFatalError => e
+ if e.response.code == "500"
+ @could_not_get_chef_object = e
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "HTTP error reading: #{e}")
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbook_file.rb b/lib/chef/chef_fs/file_system/chef_server/cookbook_file.rb
new file mode 100644
index 0000000000..6b4657ae6a
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbook_file.rb
@@ -0,0 +1,78 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_object"
+require "chef/http/simple"
+require "openssl"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class CookbookFile < BaseFSObject
+ def initialize(name, parent, file)
+ super(name, parent)
+ @file = file
+ end
+
+ attr_reader :file
+
+ def checksum
+ file[:checksum]
+ end
+
+ def read
+ tmpfile = rest.streaming_request(file[:url])
+ File.open(tmpfile, "rb") { |f| f.read }
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "Timeout reading #{file[:url]}: #{e}")
+ rescue Net::HTTPServerException => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "#{e.message} retrieving #{file[:url]}")
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+
+ def rest
+ parent.rest
+ end
+
+ def compare_to(other)
+ other_value = nil
+ if other.respond_to?(:checksum)
+ other_checksum = other.checksum
+ else
+ begin
+ other_value = other.read
+ rescue Chef::ChefFS::FileSystem::NotFoundError
+ return [ false, nil, :none ]
+ end
+ other_checksum = calc_checksum(other_value)
+ end
+ [ checksum == other_checksum, nil, other_value ]
+ end
+
+ private
+
+ def calc_checksum(value)
+ OpenSSL::Digest::MD5.hexdigest(value)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbook_subdir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbook_subdir.rb
new file mode 100644
index 0000000000..01297a39ba
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbook_subdir.rb
@@ -0,0 +1,61 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class CookbookSubdir < BaseFSDir
+ def initialize(name, parent, ruby_only, recursive)
+ super(name, parent)
+ @children = []
+ @ruby_only = ruby_only
+ @recursive = recursive
+ end
+
+ attr_reader :versions
+ attr_reader :children
+
+ def add_child(child)
+ @children << child
+ end
+
+ def can_have_child?(name, is_dir)
+ if is_dir
+ return false if !@recursive
+ else
+ return false if @ruby_only && name !~ /\.rb$/
+ end
+ true
+ end
+
+ def make_child_entry(name)
+ result = @children.find { |child| child.name == name } if @children
+ result || NonexistentFSObject.new(name, self)
+ end
+
+ def rest
+ parent.rest
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbooks_acl_dir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbooks_acl_dir.rb
new file mode 100644
index 0000000000..e020d0fb34
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbooks_acl_dir.rb
@@ -0,0 +1,42 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/acl_dir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class CookbooksAclDir < AclDir
+ # If versioned_cookbooks is on, the list of cookbooks will have versions
+ # in them. But all versions of a cookbook have the same acl, so even if
+ # we have cookbooks/apache2-1.0.0 and cookbooks/apache2-1.1.2, we will
+ # only have one acl: acls/cookbooks/apache2.json. Thus, the list of
+ # children of acls/cookbooks is a unique list of cookbook *names*.
+ def children
+ if @children.nil?
+ names = parent.parent.child(name).children.map { |child| "#{child.cookbook_name}.json" }
+ @children = names.uniq.map { |name| make_child_entry(name, true) }
+ end
+ @children
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb
new file mode 100644
index 0000000000..631562d7ef
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb
@@ -0,0 +1,101 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/chef_server/cookbook_dir"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir"
+require "chef/mixin/file_class"
+
+require "tmpdir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ #
+ # /cookbooks
+ #
+ # Example children:
+ # apache2/
+ # mysql/
+ #
+ class CookbooksDir < RestListDir
+
+ include Chef::Mixin::FileClass
+
+ def make_child_entry(name)
+ result = @children.find { |child| child.name == name } if @children
+ result || CookbookDir.new(name, self)
+ end
+
+ def children
+ @children ||= begin
+ result = root.get_json(api_path).keys.map { |cookbook_name| CookbookDir.new(cookbook_name, self, exists: true) }
+ result.sort_by(&:name)
+ end
+ end
+
+ def create_child_from(other, options = {})
+ @children = nil
+ upload_cookbook_from(other, options)
+ end
+
+ def upload_cookbook_from(other, options = {})
+ upload_cookbook(other, options)
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "Timeout writing: #{e}")
+ rescue Net::HTTPServerException => e
+ case e.response.code
+ when "409"
+ raise Chef::ChefFS::FileSystem::CookbookFrozenError.new(:write, self, e, "Cookbook #{other.name} is frozen")
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "HTTP error writing: #{e}")
+ end
+ rescue Chef::Exceptions::CookbookFrozen => e
+ raise Chef::ChefFS::FileSystem::CookbookFrozenError.new(:write, self, e, "Cookbook #{other.name} is frozen")
+ end
+
+ def upload_cookbook(other, options)
+ cookbook_to_upload = other.chef_object
+ cookbook_to_upload.freeze_version if options[:freeze]
+ uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
+
+ with_actual_cookbooks_dir(other.parent.file_path) do
+ uploader.upload_cookbooks
+ end
+ end
+
+ # Work around the fact that CookbookUploader doesn't understand chef_repo_path (yet)
+ def with_actual_cookbooks_dir(actual_cookbook_path)
+ old_cookbook_path = Chef::Config.cookbook_path
+ Chef::Config.cookbook_path = actual_cookbook_path if !Chef::Config.cookbook_path
+
+ yield
+ ensure
+ Chef::Config.cookbook_path = old_cookbook_path
+ end
+
+ def can_have_child?(name, is_dir)
+ is_dir
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/data_bag_dir.rb b/lib/chef/chef_fs/file_system/chef_server/data_bag_dir.rb
new file mode 100644
index 0000000000..ee0ecd3b40
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/data_bag_dir.rb
@@ -0,0 +1,76 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/chef_server/data_bag_entry"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/chef_fs/data_handler/data_bag_item_data_handler"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class DataBagDir < RestListDir
+ def initialize(name, parent, exists = nil)
+ super(name, parent, nil, Chef::ChefFS::DataHandler::DataBagItemDataHandler.new)
+ @exists = nil
+ end
+
+ def dir?
+ exists?
+ end
+
+ def read
+ # This will only be called if dir? is false, which means exists? is false.
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self)
+ end
+
+ def exists?
+ if @exists.nil?
+ @exists = parent.children.any? { |child| child.name == name }
+ end
+ @exists
+ end
+
+ def delete(recurse)
+ if !recurse
+ raise NotFoundError.new(self) if !exists?
+ raise MustDeleteRecursivelyError.new(self, "#{path_for_printing} must be deleted recursively")
+ end
+ begin
+ rest.delete(api_path)
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e, "Timeout deleting: #{e}")
+ rescue Net::HTTPServerException => e
+ if e.response.code == "404"
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e, "HTTP error deleting: #{e}")
+ end
+ end
+ end
+
+ def make_child_entry(name, exists = nil)
+ @children.find { |child| child.name == name } if @children
+ DataBagEntry.new(name, self, exists)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/data_bag_entry.rb b/lib/chef/chef_fs/file_system/chef_server/data_bag_entry.rb
new file mode 100644
index 0000000000..c0093058b7
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/data_bag_entry.rb
@@ -0,0 +1,19 @@
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/data_handler/data_bag_item_data_handler"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ # /policies/NAME-REVISION.json
+ # Represents the actual data at /organizations/ORG/policies/NAME/revisions/REVISION
+ class DataBagEntry < RestListEntry
+ def display_path
+ pth = "/data_bags/#{parent.name}/#{name}"
+ File.extname(pth).empty? ? pth + ".json" : pth
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/data_bags_dir.rb b/lib/chef/chef_fs/file_system/chef_server/data_bags_dir.rb
new file mode 100644
index 0000000000..205aa9fd86
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/data_bags_dir.rb
@@ -0,0 +1,67 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/chef_server/data_bag_dir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class DataBagsDir < RestListDir
+ def make_child_entry(name, exists = false)
+ result = @children.find { |child| child.name == name } if @children
+ result || DataBagDir.new(name, self, exists)
+ end
+
+ def children
+ @children ||= root.get_json(api_path).keys.sort.map { |entry| make_child_entry(entry, true) }
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "Timeout getting children: #{e}")
+ rescue Net::HTTPServerException => e
+ if e.response.code == "404"
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "HTTP error getting children: #{e}")
+ end
+ end
+
+ def can_have_child?(name, is_dir)
+ is_dir
+ end
+
+ def create_child(name, file_contents)
+ begin
+ rest.post(api_path, { "name" => name })
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Timeout creating child '#{name}': #{e}")
+ rescue Net::HTTPServerException => e
+ if e.response.code == "409"
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e, "Cannot create #{name} under #{path}: already exists")
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "HTTP error creating child '#{name}': #{e}")
+ end
+ end
+ @children = nil
+ DataBagDir.new(name, self, true)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/environments_dir.rb b/lib/chef/chef_fs/file_system/chef_server/environments_dir.rb
new file mode 100644
index 0000000000..e4714cf089
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/environments_dir.rb
@@ -0,0 +1,56 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/file_system/exceptions"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class EnvironmentsDir < RestListDir
+ def make_child_entry(name, exists = nil)
+ if File.basename(name, ".*") == "_default"
+ DefaultEnvironmentEntry.new(name, self, exists)
+ else
+ super
+ end
+ end
+
+ class DefaultEnvironmentEntry < RestListEntry
+ def initialize(name, parent, exists = nil)
+ super(name, parent)
+ @exists = exists
+ end
+
+ def delete(recurse)
+ raise NotFoundError.new(self) if !exists?
+ raise DefaultEnvironmentCannotBeModifiedError.new(:delete, self)
+ end
+
+ def write(file_contents)
+ raise NotFoundError.new(self) if !exists?
+ raise DefaultEnvironmentCannotBeModifiedError.new(:write, self)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/nodes_dir.rb b/lib/chef/chef_fs/file_system/chef_server/nodes_dir.rb
index 2610b06a82..c81e880744 100644
--- a/lib/chef/chef_fs/file_system/nodes_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_server/nodes_dir.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,38 +16,34 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/data_handler/node_data_handler'
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/chef_fs/data_handler/node_data_handler"
class Chef
module ChefFS
module FileSystem
- class NodesDir < RestListDir
- def initialize(parent)
- super("nodes", parent, nil, Chef::ChefFS::DataHandler::NodeDataHandler.new)
- end
-
- # Identical to RestListDir.children, except supports environments
- def children
- begin
+ module ChefServer
+ class NodesDir < RestListDir
+ # Identical to RestListDir.children, except supports environments
+ def children
@children ||= root.get_json(env_api_path).keys.sort.map do |key|
- make_child_entry("#{key}.json", true)
+ make_child_entry(key, true)
end
rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "Timeout retrieving children: #{e}"
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "Timeout retrieving children: #{e}")
rescue Net::HTTPServerException => e
if $!.response.code == "404"
raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "HTTP error retrieving children: #{e}"
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "HTTP error retrieving children: #{e}")
end
end
- end
- def env_api_path
- environment ? "environments/#{environment}/#{api_path}" : api_path
+ def env_api_path
+ environment ? "environments/#{environment}/#{api_path}" : api_path
+ end
end
end
end
diff --git a/lib/chef/chef_fs/file_system/chef_server/org_entry.rb b/lib/chef/chef_fs/file_system/chef_server/org_entry.rb
new file mode 100644
index 0000000000..7253de3449
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/org_entry.rb
@@ -0,0 +1,35 @@
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/data_handler/organization_data_handler"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ # /organizations/NAME/org.json
+ # Represents the actual data at /organizations/NAME (the full name, etc.)
+ class OrgEntry < RestListEntry
+ def data_handler
+ Chef::ChefFS::DataHandler::OrganizationDataHandler.new
+ end
+
+ # /organizations/foo/org.json -> GET /organizations/foo
+ def api_path
+ parent.api_path
+ end
+
+ def display_path
+ "/org.json"
+ end
+
+ def exists?
+ parent.exists?
+ end
+
+ def delete(recurse)
+ raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/organization_invites_entry.rb b/lib/chef/chef_fs/file_system/chef_server/organization_invites_entry.rb
new file mode 100644
index 0000000000..adaffb99a7
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/organization_invites_entry.rb
@@ -0,0 +1,65 @@
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/data_handler/organization_invites_data_handler"
+require "chef/json_compat"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ # /organizations/NAME/invitations.json
+ # read data from:
+ # - GET /organizations/NAME/association_requests
+ # write data to:
+ # - remove from list: DELETE /organizations/NAME/association_requests/id
+ # - add to list: POST /organizations/NAME/association_requests
+ class OrganizationInvitesEntry < RestListEntry
+ def initialize(name, parent, exists = nil)
+ super(name, parent)
+ @exists = exists
+ end
+
+ def data_handler
+ Chef::ChefFS::DataHandler::OrganizationInvitesDataHandler.new
+ end
+
+ # /organizations/foo/invites.json -> /organizations/foo/association_requests
+ def api_path
+ File.join(parent.api_path, "association_requests")
+ end
+
+ def display_path
+ "/invitations.json"
+ end
+
+ def exists?
+ parent.exists?
+ end
+
+ def delete(recurse)
+ raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self)
+ end
+
+ def write(contents)
+ desired_invites = minimize_value(Chef::JSONCompat.parse(contents, :create_additions => false))
+ actual_invites = _read_json.inject({}) { |h, val| h[val["username"]] = val["id"]; h }
+ invites = actual_invites.keys
+ (desired_invites - invites).each do |invite|
+ begin
+ rest.post(api_path, { "user" => invite })
+ rescue Net::HTTPServerException => e
+ if e.response.code == "409"
+ Chef::Log.warn("Could not invite #{invite} to organization #{org}: #{api_error_text(e.response)}")
+ else
+ raise
+ end
+ end
+ end
+ (invites - desired_invites).each do |invite|
+ rest.delete(File.join(api_path, actual_invites[invite]))
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/organization_members_entry.rb b/lib/chef/chef_fs/file_system/chef_server/organization_members_entry.rb
new file mode 100644
index 0000000000..7e9c7141c4
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/organization_members_entry.rb
@@ -0,0 +1,64 @@
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/data_handler/organization_members_data_handler"
+require "chef/json_compat"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ # /organizations/NAME/members.json
+ # reads data from:
+ # - GET /organizations/NAME/users
+ # writes data to:
+ # - remove from list: DELETE /organizations/NAME/users/name
+ # - add to list: POST /organizations/NAME/users/name
+ class OrganizationMembersEntry < RestListEntry
+ def initialize(name, parent, exists = nil)
+ super(name, parent)
+ @exists = exists
+ end
+
+ def data_handler
+ Chef::ChefFS::DataHandler::OrganizationMembersDataHandler.new
+ end
+
+ # /organizations/foo/members.json -> /organizations/foo/users
+ def api_path
+ File.join(parent.api_path, "users")
+ end
+
+ def display_path
+ "/members.json"
+ end
+
+ def exists?
+ parent.exists?
+ end
+
+ def delete(recurse)
+ raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self)
+ end
+
+ def write(contents)
+ desired_members = minimize_value(Chef::JSONCompat.parse(contents, :create_additions => false))
+ members = minimize_value(_read_json)
+ (desired_members - members).each do |member|
+ begin
+ rest.post(api_path, "username" => member)
+ rescue Net::HTTPServerException => e
+ if %w{404 405}.include?(e.response.code)
+ raise "Chef server at #{api_path} does not allow you to directly add members. Please either upgrade your Chef server or move the users you want into invitations.json instead of members.json."
+ else
+ raise
+ end
+ end
+ end
+ (members - desired_members).each do |member|
+ rest.delete(File.join(api_path, member))
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/policies_acl_dir.rb b/lib/chef/chef_fs/file_system/chef_server/policies_acl_dir.rb
new file mode 100644
index 0000000000..fa1d184b7d
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/policies_acl_dir.rb
@@ -0,0 +1,41 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/acl_dir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class PoliciesAclDir < AclDir
+ # Policies are presented like /NAME-VERSION.json. But there is only
+ # one ACL for a given NAME. So we find out the unique policy names,
+ # and make one acls/policies/NAME.json for each one.
+ def children
+ if @children.nil?
+ # /acls/policies -> List ../../policies
+ names = parent.parent.child(name).children.map { |child| "#{child.policy_name}.json" }
+ @children = names.uniq.map { |name| make_child_entry(name, true) }
+ end
+ @children
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/policies_dir.rb b/lib/chef/chef_fs/file_system/chef_server/policies_dir.rb
new file mode 100644
index 0000000000..a4add1378d
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/policies_dir.rb
@@ -0,0 +1,158 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/chef_server/policy_revision_entry"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ #
+ # Server API:
+ # /policies - list of policies by name
+ # - /policies/NAME - represents a policy with all revisions
+ # - /policies/NAME/revisions - list of revisions for that policy
+ # - /policies/NAME/revisions/REVISION - actual policy-revision document
+ #
+ # Local Repository and ChefFS:
+ # /policies - PoliciesDir - maps to server API /policies
+ # - /policies/NAME-REVISION.json - PolicyRevision - maps to /policies/NAME/revisions/REVISION
+ #
+ class PoliciesDir < RestListDir
+ # Children: NAME-REVISION.json for all revisions of all policies
+ #
+ # /nodes: {
+ # "node1": "https://api.opscode.com/organizations/myorg/nodes/node1",
+ # "node2": "https://api.opscode.com/organizations/myorg/nodes/node2",
+ # }
+ #
+ # /policies: {
+ # "foo": {}
+ # }
+
+ def make_child_entry(name, exists = nil)
+ @children.find { |child| child.name == name } if @children
+ PolicyRevisionEntry.new(name, self, exists)
+ end
+
+ # Children come from /policies in this format:
+ # {
+ # "foo": {
+ # "uri": "https://api.opscode.com/organizations/essentials/policies/foo",
+ # "revisions": {
+ # "1.0.0": {
+ #
+ # },
+ # "1.0.1": {
+ #
+ # }
+ # }
+ # }
+ # }
+ def children
+ # Grab the names of the children, append json, and make child entries
+ @children ||= begin
+ result = []
+ data = root.get_json(api_path)
+ data.keys.sort.each do |policy_name|
+ data[policy_name]["revisions"].keys.each do |policy_revision|
+ filename = "#{policy_name}-#{policy_revision}.json"
+ result << make_child_entry(filename, true)
+ end
+ end
+ result
+ end
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "Timeout retrieving children: #{e}")
+ rescue Net::HTTPServerException => e
+ # 404 = NotFoundError
+ if $!.response.code == "404"
+ # GET /organizations/ORG/policies returned 404, but that just might be because
+ # we are talking to an older version of the server that doesn't support policies.
+ # Do GET /orgqanizations/ORG to find out if the org exists at all.
+ # TODO use server API version instead of a second network request.
+ begin
+ root.get_json(parent.api_path)
+ # Return empty list if the organization exists but /policies didn't work
+ []
+ rescue Net::HTTPServerException => e
+ if e.response.code == "404"
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "HTTP error retrieving children: #{e}")
+ end
+ # Anything else is unexpected (OperationFailedError)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "HTTP error retrieving children: #{e}")
+ end
+ end
+
+ #
+ # Does POST <api_path> with file_contents
+ #
+ def create_child(name, file_contents)
+ # Parse the contents to ensure they are valid JSON
+ begin
+ object = Chef::JSONCompat.parse(file_contents)
+ rescue Chef::Exceptions::JSON::ParseError => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Parse error reading JSON creating child '#{name}': #{e}")
+ end
+
+ # Create the child entry that will be returned
+ result = make_child_entry(name, true)
+
+ # Normalize the file_contents before post (add defaults, etc.)
+ if data_handler
+ object = data_handler.normalize_for_post(object, result)
+ data_handler.verify_integrity(object, result) do |error|
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, nil, "Error creating '#{name}': #{error}")
+ end
+ end
+
+ # POST /api_path with the normalized file_contents
+ begin
+ policy_name, policy_revision = data_handler.name_and_revision(name)
+ rest.post("#{api_path}/#{policy_name}/revisions", object)
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Timeout creating '#{name}': #{e}")
+ rescue Net::HTTPServerException => e
+ # 404 = NotFoundError
+ if e.response.code == "404"
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+ # 409 = AlreadyExistsError
+ elsif $!.response.code == "409"
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e, "Failure creating '#{name}': #{path}/#{name} already exists")
+ # Anything else is unexpected (OperationFailedError)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Failure creating '#{name}': #{e.message}")
+ end
+ end
+
+ # Clear the cache of children so that if someone asks for children
+ # again, we will get it again
+ @children = nil
+
+ result
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/policy_group_entry.rb b/lib/chef/chef_fs/file_system/chef_server/policy_group_entry.rb
new file mode 100644
index 0000000000..df3d393d35
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/policy_group_entry.rb
@@ -0,0 +1,135 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/exceptions"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ # Represents an entire policy group.
+ # Server path: /organizations/ORG/policy_groups/GROUP
+ # Repository path: policy_groups\GROUP.json
+ # Format:
+ # {
+ # "policies": {
+ # "a": { "revision_id": "1.0.0" }
+ # }
+ # }
+ class PolicyGroupEntry < RestListEntry
+ # delete is handled normally:
+ # DELETE /organizations/ORG/policy_groups/GROUP
+
+ # read is handled normally:
+ # GET /organizations/ORG/policy_groups/GROUP
+
+ # write is different.
+ # For each policy:
+ # - PUT /organizations/ORG/policy_groups/GROUP/policies/POLICY
+ # For each policy on the server but not the client:
+ # - DELETE /organizations/ORG/policy_groups/GROUP/policies/POLICY
+ # If the server has associations for a, b and c,
+ # And the client wants associations for a, x and y,
+ # We must PUT a, x and y
+ # And DELETE b and c
+ def write(file_contents)
+ # Parse the contents to ensure they are valid JSON
+ begin
+ object = Chef::JSONCompat.parse(file_contents)
+ rescue Chef::Exceptions::JSON::ParseError => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Parse error reading JSON creating child '#{name}': #{e}")
+ end
+
+ if data_handler
+ object = data_handler.normalize_for_put(object, self)
+ data_handler.verify_integrity(object, self) do |error|
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, nil, "Error creating '#{name}': #{error}")
+ end
+ end
+
+ begin
+
+ # this should all get carted to PolicyGroupEntry#write.
+
+ # the server demands the full policy data, but we want users' local policy_group documents to just
+ # have the data you'd get from GET /policy_groups/POLICY_GROUP. so we try to fetch that.
+
+ # ordinarily this would be POST to the normal URL, but we do PUT to
+ # /organizations/{organization}/policy_groups/{policy_group}/policies/{policy_name} with the full
+ # policy data, for each individual policy.
+ policy_datas = {}
+
+ object["policies"].each do |policy_name, policy_data|
+ policy_path = "/policies/#{policy_name}/revisions/#{policy_data["revision_id"]}"
+
+ get_data = begin
+ rest.get(policy_path)
+ rescue Net::HTTPServerException => e
+ raise "Could not find policy '#{policy_name}'' with revision '#{policy_data["revision_id"]}'' on the server"
+ end
+
+ # GET policy data
+ server_policy_data = Chef::JSONCompat.parse(get_data)
+
+ # if it comes back 404, raise an Exception with "Policy file X does not exist with revision Y on the server"
+
+ # otherwise, add it to the list of policyfile datas.
+ policy_datas[policy_name] = server_policy_data
+ end
+
+ begin
+ existing_group = Chef::JSONCompat.parse(read)
+ rescue NotFoundError
+ # It's OK if the group doesn't already exist, just means no existing policies
+ end
+
+ # now we have the fullpolicy data for each policies, which is what the PUT endpoint demands.
+ policy_datas.each do |policy_name, policy_data|
+ # PUT /organizations/ORG/policy_groups/GROUP/policies/NAME
+ rest.put("#{api_path}/policies/#{policy_name}", policy_data)
+ end
+
+ # Now we need to remove any policies that are *not* in our current group.
+ if existing_group && existing_group["policies"]
+ (existing_group["policies"].keys - policy_datas.keys).each do |policy_name|
+ rest.delete("#{api_path}/policies/#{policy_name}")
+ end
+ end
+
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Timeout creating '#{name}': #{e}")
+ rescue Net::HTTPServerException => e
+ # 404 = NotFoundError
+ if e.response.code == "404"
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+ # 409 = AlreadyExistsError
+ elsif $!.response.code == "409"
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e, "Failure creating '#{name}': #{path}/#{name} already exists")
+ # Anything else is unexpected (OperationFailedError)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Failure creating '#{name}': #{e.message}")
+ end
+ end
+
+ self
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/operation_not_allowed_error.rb b/lib/chef/chef_fs/file_system/chef_server/policy_groups_dir.rb
index 4b4f9742a8..0452fa4573 100644
--- a/lib/chef/chef_fs/file_system/operation_not_allowed_error.rb
+++ b/lib/chef/chef_fs/file_system/chef_server/policy_groups_dir.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,30 +16,25 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/file_system_error'
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/chef_fs/file_system/chef_server/policy_group_entry"
class Chef
module ChefFS
module FileSystem
- class OperationNotAllowedError < FileSystemError
- def initialize(operation, entry, cause = nil)
- super(entry, cause)
- @operation = operation
- end
-
- attr_reader :operation
- attr_reader :entry
+ module ChefServer
+ class PolicyGroupsDir < RestListDir
+ def make_child_entry(name, exists = nil)
+ PolicyGroupEntry.new(name, self, exists)
+ end
- def reason
- case operation
- when :delete
- "cannot be deleted"
- when :write
- "cannot be updated"
- when :create_child
- "cannot have a child created under it"
- when :read
- "cannot be read"
+ def create_child(name, file_contents)
+ entry = make_child_entry(name, true)
+ entry.write(file_contents)
+ @children = nil
+ entry
end
end
end
diff --git a/lib/chef/chef_fs/file_system/chef_server/policy_revision_entry.rb b/lib/chef/chef_fs/file_system/chef_server/policy_revision_entry.rb
new file mode 100644
index 0000000000..325b18e429
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/policy_revision_entry.rb
@@ -0,0 +1,38 @@
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/data_handler/policy_data_handler"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ # /policies/NAME-REVISION.json
+ # Represents the actual data at /organizations/ORG/policies/NAME/revisions/REVISION
+ class PolicyRevisionEntry < RestListEntry
+
+ # /policies/foo-1.0.0.json -> /policies/foo/revisions/1.0.0
+ def api_path(options = {})
+ "#{parent.api_path}/#{policy_name}/revisions/#{revision_id}"
+ end
+
+ def display_path
+ "/policies/#{policy_name}-#{revision_id}.json"
+ end
+
+ def write(file_contents)
+ raise OperationNotAllowedError.new(:write, self, nil, "cannot be updated: policy revisions are immutable once uploaded. If you want to change the policy, create a new revision with your changes")
+ end
+
+ def policy_name
+ policy_name, revision_id = data_handler.name_and_revision(name)
+ policy_name
+ end
+
+ def revision_id
+ policy_name, revision_id = data_handler.name_and_revision(name)
+ revision_id
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/rest_list_dir.rb b/lib/chef/chef_fs/file_system/chef_server/rest_list_dir.rb
new file mode 100644
index 0000000000..6ba53fab4b
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/rest_list_dir.rb
@@ -0,0 +1,176 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/file_system/exceptions"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class RestListDir < BaseFSDir
+ def initialize(name, parent, api_path = nil, data_handler = nil)
+ super(name, parent)
+ @api_path = api_path || (parent.api_path == "" ? name : "#{parent.api_path}/#{name}")
+ @data_handler = data_handler
+ end
+
+ attr_reader :api_path
+ attr_reader :data_handler
+
+ def can_have_child?(name, is_dir)
+ !is_dir
+ end
+
+ #
+ # When talking to a modern (12.0+) Chef server
+ # knife list /
+ # -> /nodes
+ # -> /policies
+ # -> /policy_groups
+ # -> /roles
+ #
+ # 12.0 or 12.1 will fail when you do this:
+ # knife list / --recursive
+ # Because it thinks /policies exists, and when it tries to list its children
+ # it gets a 404 (indicating it actually doesn't exist).
+ #
+ # With this change, knife list / --recursive will list /policies as a real, empty directory.
+ #
+ # Alternately, we could have done some sort of detection when we listed the top level
+ # and determined which endpoints the server would support, and returned only those.
+ # So you wouldn't see /policies in that case at all.
+ # The issue with that is there's no efficient way to do it because we can't find out
+ # the server version directly, and can't ask the server for a list of the endpoints it supports.
+ #
+
+ #
+ # Does GET /<api_path>, assumes the result is of the format:
+ #
+ # {
+ # "foo": "<api_path>/foo",
+ # "bar": "<api_path>/bar",
+ # }
+ #
+ # Children are foo.json and bar.json in this case.
+ #
+ def children
+ # Grab the names of the children, append json, and make child entries
+ @children ||= root.get_json(api_path).keys.sort.map do |key|
+ make_child_entry(key, true)
+ end
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "Timeout retrieving children: #{e}")
+ rescue Net::HTTPServerException => e
+ # 404 = NotFoundError
+ if $!.response.code == "404"
+
+ if parent.is_a?(ChefServerRootDir)
+ # GET /organizations/ORG/<container> returned 404, but that just might be because
+ # we are talking to an older version of the server that doesn't support policies.
+ # Do GET /organizations/ORG to find out if the org exists at all.
+ # TODO use server API version instead of a second network request.
+ begin
+ root.get_json(parent.api_path)
+ # Return empty list if the organization exists but /policies didn't work
+ []
+ rescue Net::HTTPServerException => e
+ if e.response.code == "404"
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "HTTP error retrieving children: #{e}")
+ end
+ else
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+
+ # Anything else is unexpected (OperationFailedError)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "HTTP error retrieving children: #{e}")
+ end
+ end
+
+ #
+ # Does POST <api_path> with file_contents
+ #
+ def create_child(name, file_contents)
+ # Parse the contents to ensure they are valid JSON
+ begin
+ object = Chef::JSONCompat.parse(file_contents)
+ rescue Chef::Exceptions::JSON::ParseError => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Parse error reading JSON creating child '#{name}': #{e}")
+ end
+
+ # Create the child entry that will be returned
+ result = make_child_entry(name, true)
+
+ # Normalize the file_contents before post (add defaults, etc.)
+ if data_handler
+ object = data_handler.normalize_for_post(object, result)
+ data_handler.verify_integrity(object, result) do |error|
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, nil, "Error creating '#{name}': #{error}")
+ end
+ end
+
+ # POST /api_path with the normalized file_contents
+ begin
+ rest.post(api_path, object)
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Timeout creating '#{name}': #{e}")
+ rescue Net::HTTPServerException => e
+ # 404 = NotFoundError
+ if e.response.code == "404"
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+ # 409 = AlreadyExistsError
+ elsif $!.response.code == "409"
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e, "Failure creating '#{name}': #{path}/#{name} already exists")
+ # Anything else is unexpected (OperationFailedError)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Failure creating '#{name}': #{e.message}")
+ end
+ end
+
+ # Clear the cache of children so that if someone asks for children
+ # again, we will get it again
+ @children = nil
+
+ result
+ end
+
+ def org
+ parent.org
+ end
+
+ def environment
+ parent.environment
+ end
+
+ def rest
+ parent.rest
+ end
+
+ def make_child_entry(name, exists = nil)
+ @children.find { |child| child.name == name } if @children
+ RestListEntry.new(name, self, exists)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/rest_list_entry.rb b/lib/chef/chef_fs/file_system/chef_server/rest_list_entry.rb
new file mode 100644
index 0000000000..8f9e554526
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/rest_list_entry.rb
@@ -0,0 +1,198 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_object"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/role"
+require "chef/node"
+require "chef/json_compat"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class RestListEntry < BaseFSObject
+ def initialize(name, parent, exists = nil)
+ super(name, parent)
+ @exists = exists
+ end
+
+ def data_handler
+ parent.data_handler
+ end
+
+ def api_child_name
+ if %w{ .rb .json }.include? File.extname(name)
+ File.basename(name, ".*")
+ else
+ name
+ end
+ end
+
+ def api_path
+ "#{parent.api_path}/#{api_child_name}"
+ end
+
+ def display_path
+ pth = api_path.start_with?("/") ? api_path : "/#{api_path}"
+ File.extname(pth).empty? ? pth + ".json" : pth
+ end
+ alias_method :path_for_printing, :display_path
+
+ def display_name
+ File.basename(display_path)
+ end
+
+ def org
+ parent.org
+ end
+
+ def environment
+ parent.environment
+ end
+
+ def exists?
+ if @exists.nil?
+ begin
+ rest.get(api_path)
+ @exists = true
+ rescue Net::HTTPServerException => e
+ if e.response.code == "404"
+ @exists = false
+ else
+ raise
+ end
+ rescue Chef::ChefFS::FileSystem::NotFoundError
+ @exists = false
+ end
+ end
+ @exists
+ end
+
+ def delete(recurse)
+ rest.delete(api_path)
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e, "Timeout deleting: #{e}")
+ rescue Net::HTTPServerException => e
+ if e.response.code == "404"
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e, "Timeout deleting: #{e}")
+ end
+ end
+
+ def read
+ Chef::JSONCompat.to_json_pretty(minimize_value(_read_json))
+ end
+
+ def _read_json
+ # Minimize the value (get rid of defaults) so the results don't look terrible
+ root.get_json(api_path)
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "Timeout reading: #{e}")
+ rescue Net::HTTPServerException => e
+ if $!.response.code == "404"
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "HTTP error reading: #{e}")
+ end
+ end
+
+ def chef_object
+ # REST will inflate the Chef object using json_class
+ data_handler.json_class.from_hash(read)
+ end
+
+ def minimize_value(value)
+ data_handler.minimize(data_handler.normalize(value, self), self)
+ end
+
+ def compare_to(other)
+ # TODO this pair of reads can be parallelized
+
+ # Grab the other value
+ begin
+ other_value_json = other.read
+ rescue Chef::ChefFS::FileSystem::NotFoundError
+ return [ nil, nil, :none ]
+ end
+
+ # Grab this value
+ begin
+ value = _read_json
+ rescue Chef::ChefFS::FileSystem::NotFoundError
+ return [ false, :none, other_value_json ]
+ end
+
+ # Minimize (and normalize) both values for easy and beautiful diffs
+ value = minimize_value(value)
+ value_json = Chef::JSONCompat.to_json_pretty(value)
+ begin
+ other_value = Chef::JSONCompat.parse(other_value_json)
+ rescue Chef::Exceptions::JSON::ParseError => e
+ Chef::Log.warn("Parse error reading #{other.path_for_printing} as JSON: #{e}")
+ return [ nil, value_json, other_value_json ]
+ end
+ other_value = minimize_value(other_value)
+ other_value_json = Chef::JSONCompat.to_json_pretty(other_value)
+
+ [ value == other_value, value_json, other_value_json ]
+ end
+
+ def rest
+ parent.rest
+ end
+
+ def write(file_contents)
+ begin
+ object = Chef::JSONCompat.parse(file_contents)
+ rescue Chef::Exceptions::JSON::ParseError => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "Parse error reading JSON: #{e}")
+ end
+
+ if data_handler
+ object = data_handler.normalize_for_put(object, self)
+ data_handler.verify_integrity(object, self) do |error|
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, nil, "#{error}")
+ end
+ end
+
+ begin
+ rest.put(api_path, object)
+ rescue Timeout::Error => e
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "Timeout writing: #{e}")
+ rescue Net::HTTPServerException => e
+ if e.response.code == "404"
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+ else
+ raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "HTTP error writing: #{e}")
+ end
+ end
+ end
+
+ def api_error_text(response)
+ Chef::JSONCompat.parse(response.body)["error"].join("\n")
+ rescue
+ response.body
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb b/lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb
new file mode 100644
index 0000000000..b7c96c42e1
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb
@@ -0,0 +1,45 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/cookbook_dir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ class VersionedCookbookDir < CookbookDir
+ # See Erchef code
+ # https://github.com/chef/chef_objects/blob/968a63344d38fd507f6ace05f73d53e9cd7fb043/src/chef_regex.erl#L94
+ VALID_VERSIONED_COOKBOOK_NAME = /^([.a-zA-Z0-9_-]+)-(\d+\.\d+\.\d+)$/
+
+ def initialize(name, parent, options = {})
+ super(name, parent)
+ # If the name is apache2-1.0.0 and versioned_cookbooks is on, we know
+ # the actual cookbook_name and version.
+ if name =~ VALID_VERSIONED_COOKBOOK_NAME
+ @cookbook_name = $1
+ @version = $2
+ else
+ @exists = false
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir.rb b/lib/chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir.rb
new file mode 100644
index 0000000000..172405763a
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir.rb
@@ -0,0 +1,107 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/cookbooks_dir"
+require "chef/chef_fs/file_system/chef_server/versioned_cookbook_dir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module ChefServer
+ #
+ # /cookbooks or /cookbook_artifacts
+ #
+ # Example children of /cookbooks:
+ #
+ # - apache2-1.0.0
+ # - apache2-1.0.1
+ # - mysql-2.0.5
+ #
+ # Example children of /cookbook_artifacts:
+ #
+ # - apache2-ab234098245908ddf324a
+ # - apache2-295387a9823745feff239
+ # - mysql-1a2b9e1298734dfe90444
+ #
+ class VersionedCookbooksDir < CookbooksDir
+
+ def make_child_entry(name)
+ result = @children.find { |child| child.name == name } if @children
+ result || VersionedCookbookDir.new(name, self)
+ end
+
+ def children
+ @children ||= begin
+ result = []
+ root.get_json("#{api_path}/?num_versions=all").each_pair do |cookbook_name, cookbooks|
+ cookbooks["versions"].each do |cookbook_version|
+ result << VersionedCookbookDir.new("#{cookbook_name}-#{cookbook_version['version']}", self)
+ end
+ end
+ result.sort_by(&:name)
+ end
+ end
+
+ # Knife currently does not understand versioned cookbooks
+ # Cookbook Version uploader also requires a lot of refactoring
+ # to make this work. So instead, we make a temporary cookbook
+ # symlinking back to real cookbook, and upload the proxy.
+ def upload_cookbook(other, options)
+ cookbook_name = Chef::ChefFS::FileSystem::Repository::ChefRepositoryFileSystemCookbookDir.canonical_cookbook_name(other.name)
+
+ Dir.mktmpdir do |temp_cookbooks_path|
+ proxy_cookbook_path = "#{temp_cookbooks_path}/#{cookbook_name}"
+
+ # Make a symlink
+ file_class.symlink other.file_path, proxy_cookbook_path
+
+ # Instantiate a proxy loader using the temporary symlink
+ proxy_loader = Chef::Cookbook::CookbookVersionLoader.new(proxy_cookbook_path, other.parent.chefignore)
+ proxy_loader.load_cookbooks
+
+ cookbook_to_upload = proxy_loader.cookbook_version
+ cookbook_to_upload.freeze_version if options[:freeze]
+
+ # Instantiate a new uploader based on the proxy loader
+ uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
+
+ with_actual_cookbooks_dir(temp_cookbooks_path) do
+ uploader.upload_cookbooks
+ end
+
+ #
+ # When the temporary directory is being deleted on
+ # windows, the contents of the symlink under that
+ # directory is also deleted. So explicitly remove
+ # the symlink without removing the original contents if we
+ # are running on windows
+ #
+ if Chef::Platform.windows?
+ Dir.rmdir proxy_cookbook_path
+ end
+ end
+ end
+
+ def can_have_child?(name, is_dir)
+ is_dir && name =~ Chef::ChefFS::FileSystem::ChefServer::VersionedCookbookDir::VALID_VERSIONED_COOKBOOK_NAME
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server_root_dir.rb b/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
deleted file mode 100644
index a243e0ae6b..0000000000
--- a/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
+++ /dev/null
@@ -1,165 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/server_api'
-require 'chef/chef_fs/file_system/acls_dir'
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/rest_list_dir'
-require 'chef/chef_fs/file_system/cookbooks_dir'
-require 'chef/chef_fs/file_system/data_bags_dir'
-require 'chef/chef_fs/file_system/nodes_dir'
-require 'chef/chef_fs/file_system/org_entry'
-require 'chef/chef_fs/file_system/organization_invites_entry'
-require 'chef/chef_fs/file_system/organization_members_entry'
-require 'chef/chef_fs/file_system/environments_dir'
-require 'chef/chef_fs/data_handler/client_data_handler'
-require 'chef/chef_fs/data_handler/role_data_handler'
-require 'chef/chef_fs/data_handler/user_data_handler'
-require 'chef/chef_fs/data_handler/group_data_handler'
-require 'chef/chef_fs/data_handler/container_data_handler'
-
-class Chef
- module ChefFS
- module FileSystem
- #
- # Represents the root of a Chef server (or organization), under which
- # nodes, roles, cookbooks, etc. can be found.
- #
- class ChefServerRootDir < BaseFSDir
- #
- # Create a new Chef server root.
- #
- # == Parameters
- #
- # [root_name]
- # A friendly name for the root, for printing--like "remote" or "chef_central".
- # [chef_config]
- # A hash with options that look suspiciously like Chef::Config, including the
- # following keys:
- # :chef_server_url:: The URL to the Chef server or top of the organization
- # :node_name:: The username to authenticate to the Chef server with
- # :client_key:: The private key for the user for authentication
- # :environment:: The environment in which you are presently working
- # :repo_mode::
- # The repository mode, :hosted_everything, :everything or :static.
- # This determines the set of subdirectories the Chef server will
- # offer up.
- # :versioned_cookbooks:: whether or not to include versions in cookbook names
- # [options]
- # Other options:
- # :cookbook_version:: when cookbooks are retrieved, grab this version for them.
- # :freeze:: freeze cookbooks on upload
- #
- def initialize(root_name, chef_config, options = {})
- super("", nil)
- @chef_server_url = chef_config[:chef_server_url]
- @chef_username = chef_config[:node_name]
- @chef_private_key = chef_config[:client_key]
- @environment = chef_config[:environment]
- @repo_mode = chef_config[:repo_mode]
- @versioned_cookbooks = chef_config[:versioned_cookbooks]
- @root_name = root_name
- @cookbook_version = options[:cookbook_version] # Used in knife diff and download for server cookbook version
- end
-
- attr_reader :chef_server_url
- attr_reader :chef_username
- attr_reader :chef_private_key
- attr_reader :environment
- attr_reader :repo_mode
- attr_reader :cookbook_version
- attr_reader :versioned_cookbooks
-
- def fs_description
- "Chef server at #{chef_server_url} (user #{chef_username}), repo_mode = #{repo_mode}"
- end
-
- def rest
- Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :raw_output => true, :api_version => "0")
- end
-
- def get_json(path)
- Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :api_version => "0").get(path)
- end
-
- def chef_rest
- Chef::REST.new(chef_server_url, chef_username, chef_private_key)
- end
-
- def api_path
- ""
- end
-
- def path_for_printing
- "#{@root_name}/"
- end
-
- def can_have_child?(name, is_dir)
- result = children.select { |child| child.name == name }.first
- result && !!result.dir? == !!is_dir
- end
-
- def org
- @org ||= begin
- path = Pathname.new(URI.parse(chef_server_url).path).cleanpath
- if File.dirname(path) == '/organizations'
- File.basename(path)
- else
- # In Chef 12, everything is in an org.
- 'chef'
- end
- end
- end
-
- def make_child_entry(name)
- children.select { |child| child.name == name }.first
- end
-
- def children
- @children ||= begin
- result = [
- CookbooksDir.new(self),
- DataBagsDir.new(self),
- EnvironmentsDir.new(self),
- RestListDir.new("roles", self, nil, Chef::ChefFS::DataHandler::RoleDataHandler.new)
- ]
- if repo_mode == 'hosted_everything'
- result += [
- AclsDir.new(self),
- RestListDir.new("clients", self, nil, Chef::ChefFS::DataHandler::ClientDataHandler.new),
- RestListDir.new("containers", self, nil, Chef::ChefFS::DataHandler::ContainerDataHandler.new),
- RestListDir.new("groups", self, nil, Chef::ChefFS::DataHandler::GroupDataHandler.new),
- NodesDir.new(self),
- OrgEntry.new("org.json", self),
- OrganizationMembersEntry.new("members.json", self),
- OrganizationInvitesEntry.new("invitations.json", self)
- ]
- elsif repo_mode != 'static'
- result += [
- RestListDir.new("clients", self, nil, Chef::ChefFS::DataHandler::ClientDataHandler.new),
- NodesDir.new(self),
- RestListDir.new("users", self, nil, Chef::ChefFS::DataHandler::UserDataHandler.new)
- ]
- end
- result.sort_by { |child| child.name }
- end
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/cookbook_dir.rb b/lib/chef/chef_fs/file_system/cookbook_dir.rb
deleted file mode 100644
index c0f0390e98..0000000000
--- a/lib/chef/chef_fs/file_system/cookbook_dir.rb
+++ /dev/null
@@ -1,224 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/command_line'
-require 'chef/chef_fs/file_system/rest_list_dir'
-require 'chef/chef_fs/file_system/cookbook_subdir'
-require 'chef/chef_fs/file_system/cookbook_file'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/cookbook_version'
-require 'chef/cookbook_uploader'
-
-class Chef
- module ChefFS
- module FileSystem
- class CookbookDir < BaseFSDir
- def initialize(name, parent, options = {})
- super(name, parent)
- @exists = options[:exists]
- # If the name is apache2-1.0.0 and versioned_cookbooks is on, we know
- # the actual cookbook_name and version.
- if root.versioned_cookbooks
- if name =~ VALID_VERSIONED_COOKBOOK_NAME
- @cookbook_name = $1
- @version = $2
- else
- @exists = false
- end
- else
- @cookbook_name = name
- @version = root.cookbook_version # nil unless --cookbook-version specified in download/diff
- end
- end
-
- attr_reader :cookbook_name, :version
-
- COOKBOOK_SEGMENT_INFO = {
- :attributes => { :ruby_only => true },
- :definitions => { :ruby_only => true },
- :recipes => { :ruby_only => true },
- :libraries => { :ruby_only => true },
- :templates => { :recursive => true },
- :files => { :recursive => true },
- :resources => { :ruby_only => true, :recursive => true },
- :providers => { :ruby_only => true, :recursive => true },
- :root_files => { }
- }
-
- # See Erchef code
- # https://github.com/opscode/chef_objects/blob/968a63344d38fd507f6ace05f73d53e9cd7fb043/src/chef_regex.erl#L94
- VALID_VERSIONED_COOKBOOK_NAME = /^([.a-zA-Z0-9_-]+)-(\d+\.\d+\.\d+)$/
-
- def add_child(child)
- @children << child
- end
-
- def api_path
- "#{parent.api_path}/#{cookbook_name}/#{version || "_latest"}"
- end
-
- def make_child_entry(name)
- # Since we're ignoring the rules and doing a network request here,
- # we need to make sure we don't rethrow the exception. (child(name)
- # is not supposed to fail.)
- begin
- children.select { |child| child.name == name }.first
- rescue Chef::ChefFS::FileSystem::NotFoundError
- nil
- end
- end
-
- def can_have_child?(name, is_dir)
- # A cookbook's root may not have directories unless they are segment directories
- return name != 'root_files' && COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) if is_dir
- return true
- end
-
- def children
- if @children.nil?
- @children = []
- manifest = chef_object.manifest
- COOKBOOK_SEGMENT_INFO.each do |segment, segment_info|
- next unless manifest.has_key?(segment)
-
- # Go through each file in the manifest for the segment, and
- # add cookbook subdirs and files for it.
- manifest[segment].each do |segment_file|
- parts = segment_file[:path].split('/')
- # Get or create the path to the file
- container = self
- parts[0,parts.length-1].each do |part|
- old_container = container
- container = old_container.children.select { |child| part == child.name }.first
- if !container
- container = CookbookSubdir.new(part, old_container, segment_info[:ruby_only], segment_info[:recursive])
- old_container.add_child(container)
- end
- end
- # Create the file itself
- container.add_child(CookbookFile.new(parts[parts.length-1], container, segment_file))
- end
- end
- @children = @children.sort_by { |c| c.name }
- end
- @children
- end
-
- def dir?
- exists?
- end
-
- def delete(recurse)
- if recurse
- begin
- rest.delete(api_path)
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
- rescue Net::HTTPServerException
- if $!.response.code == "404"
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "HTTP error deleting: #{e}"
- end
- end
- else
- raise NotFoundError.new(self) if !exists?
- raise MustDeleteRecursivelyError.new(self), "#{path_for_printing} must be deleted recursively"
- end
- end
-
- # In versioned cookbook mode, actually check if the version exists
- # Probably want to cache this.
- def exists?
- if @exists.nil?
- @exists = parent.children.any? { |child| child.name == name }
- end
- @exists
- end
-
- def compare_to(other)
- if !other.dir?
- return [ !exists?, nil, nil ]
- end
- are_same = true
- Chef::ChefFS::CommandLine::diff_entries(self, other, nil, :name_only).each do |type, old_entry, new_entry|
- if [ :directory_to_file, :file_to_directory, :deleted, :added, :modified ].include?(type)
- are_same = false
- end
- end
- [ are_same, nil, nil ]
- end
-
- def copy_from(other, options = {})
- parent.upload_cookbook_from(other, options)
- end
-
- def rest
- parent.rest
- end
-
- def chef_object
- # We cheat and cache here, because it seems like a good idea to keep
- # the cookbook view consistent with the directory structure.
- return @chef_object if @chef_object
-
- # The negative (not found) response is cached
- if @could_not_get_chef_object
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
- end
-
- begin
- # We want to fail fast, for now, because of the 500 issue :/
- # This will make things worse for parallelism, a little, because
- # Chef::Config is global and this could affect other requests while
- # this request is going on. (We're not parallel yet, but we will be.)
- # Chef bug http://tickets.opscode.com/browse/CHEF-3066
- old_retry_count = Chef::Config[:http_retry_count]
- begin
- Chef::Config[:http_retry_count] = 0
- @chef_object ||= Chef::CookbookVersion.json_create(root.get_json(api_path))
- ensure
- Chef::Config[:http_retry_count] = old_retry_count
- end
-
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading: #{e}"
-
- rescue Net::HTTPServerException => e
- if e.response.code == "404"
- @could_not_get_chef_object = e
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}"
- end
-
- # Chef bug http://tickets.opscode.com/browse/CHEF-3066 ... instead of 404 we get 500 right now.
- # Remove this when that bug is fixed.
- rescue Net::HTTPFatalError => e
- if e.response.code == "500"
- @could_not_get_chef_object = e
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}"
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/cookbook_file.rb b/lib/chef/chef_fs/file_system/cookbook_file.rb
deleted file mode 100644
index 16203b727c..0000000000
--- a/lib/chef/chef_fs/file_system/cookbook_file.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_object'
-require 'chef/http/simple'
-require 'openssl'
-
-class Chef
- module ChefFS
- module FileSystem
- class CookbookFile < BaseFSObject
- def initialize(name, parent, file)
- super(name, parent)
- @file = file
- end
-
- attr_reader :file
-
- def checksum
- file[:checksum]
- end
-
- def read
- begin
- tmpfile = rest.streaming_request(file[:url])
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading #{file[:url]}: #{e}"
- rescue Net::HTTPServerException => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "#{e.message} retrieving #{file[:url]}"
- end
-
- begin
- tmpfile.open
- tmpfile.read
- ensure
- tmpfile.close!
- end
- end
-
- def rest
- parent.rest
- end
-
- def compare_to(other)
- other_value = nil
- if other.respond_to?(:checksum)
- other_checksum = other.checksum
- else
- begin
- other_value = other.read
- rescue Chef::ChefFS::FileSystem::NotFoundError
- return [ false, nil, :none ]
- end
- other_checksum = calc_checksum(other_value)
- end
- [ checksum == other_checksum, nil, other_value ]
- end
-
- private
-
- def calc_checksum(value)
- OpenSSL::Digest::MD5.hexdigest(value)
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/cookbook_subdir.rb b/lib/chef/chef_fs/file_system/cookbook_subdir.rb
deleted file mode 100644
index 73c709e01e..0000000000
--- a/lib/chef/chef_fs/file_system/cookbook_subdir.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-
-class Chef
- module ChefFS
- module FileSystem
- class CookbookSubdir < BaseFSDir
- def initialize(name, parent, ruby_only, recursive)
- super(name, parent)
- @children = []
- @ruby_only = ruby_only
- @recursive = recursive
- end
-
- attr_reader :versions
- attr_reader :children
-
- def add_child(child)
- @children << child
- end
-
- def can_have_child?(name, is_dir)
- if is_dir
- return false if !@recursive
- else
- return false if @ruby_only && name !~ /\.rb$/
- end
- true
- end
-
- def rest
- parent.rest
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/cookbooks_acl_dir.rb b/lib/chef/chef_fs/file_system/cookbooks_acl_dir.rb
deleted file mode 100644
index 560ceb4886..0000000000
--- a/lib/chef/chef_fs/file_system/cookbooks_acl_dir.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/acl_dir'
-require 'chef/chef_fs/file_system/acl_entry'
-
-class Chef
- module ChefFS
- module FileSystem
- class CookbooksAclDir < AclDir
- # If versioned_cookbooks is on, the list of cookbooks will have versions
- # in them. But all versions of a cookbook have the same acl, so even if
- # we have cookbooks/apache2-1.0.0 and cookbooks/apache2-1.1.2, we will
- # only have one acl: acls/cookbooks/apache2.json. Thus, the list of
- # children of acls/cookbooks is a unique list of cookbook *names*.
- def children
- if @children.nil?
- names = parent.parent.child(name).children.map { |child| "#{child.cookbook_name}.json" }
- @children = names.uniq.map { |name| make_child_entry(name, true) }
- end
- @children
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/cookbooks_dir.rb b/lib/chef/chef_fs/file_system/cookbooks_dir.rb
deleted file mode 100644
index 6f49c28996..0000000000
--- a/lib/chef/chef_fs/file_system/cookbooks_dir.rb
+++ /dev/null
@@ -1,156 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/rest_list_dir'
-require 'chef/chef_fs/file_system/cookbook_dir'
-require 'chef/chef_fs/file_system/operation_failed_error'
-require 'chef/chef_fs/file_system/cookbook_frozen_error'
-require 'chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir'
-require 'chef/mixin/file_class'
-
-require 'tmpdir'
-
-class Chef
- module ChefFS
- module FileSystem
- class CookbooksDir < RestListDir
-
- include Chef::Mixin::FileClass
-
- def initialize(parent)
- super("cookbooks", parent)
- end
-
- def make_child_entry(name)
- result = @children.select { |child| child.name == name }.first if @children
- result || CookbookDir.new(name, self)
- end
-
- def children
- @children ||= begin
- if root.versioned_cookbooks
- result = []
- root.get_json("#{api_path}/?num_versions=all").each_pair do |cookbook_name, cookbooks|
- cookbooks['versions'].each do |cookbook_version|
- result << CookbookDir.new("#{cookbook_name}-#{cookbook_version['version']}", self, :exists => true)
- end
- end
- else
- result = root.get_json(api_path).keys.map { |cookbook_name| CookbookDir.new(cookbook_name, self, :exists => true) }
- end
- result.sort_by(&:name)
- end
- end
-
- def create_child_from(other, options = {})
- @children = nil
- upload_cookbook_from(other, options)
- end
-
- def upload_cookbook_from(other, options = {})
- root.versioned_cookbooks ? upload_versioned_cookbook(other, options) : upload_unversioned_cookbook(other, options)
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}"
- rescue Net::HTTPServerException => e
- case e.response.code
- when "409"
- raise Chef::ChefFS::FileSystem::CookbookFrozenError.new(:write, self, e), "Cookbook #{other.name} is frozen"
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "HTTP error writing: #{e}"
- end
- rescue Chef::Exceptions::CookbookFrozen => e
- raise Chef::ChefFS::FileSystem::CookbookFrozenError.new(:write, self, e), "Cookbook #{other.name} is frozen"
- end
-
- # Knife currently does not understand versioned cookbooks
- # Cookbook Version uploader also requires a lot of refactoring
- # to make this work. So instead, we make a temporary cookbook
- # symlinking back to real cookbook, and upload the proxy.
- def upload_versioned_cookbook(other, options)
- cookbook_name = Chef::ChefFS::FileSystem::ChefRepositoryFileSystemCookbookDir.canonical_cookbook_name(other.name)
-
- Dir.mktmpdir do |temp_cookbooks_path|
- proxy_cookbook_path = "#{temp_cookbooks_path}/#{cookbook_name}"
-
- # Make a symlink
- file_class.symlink other.file_path, proxy_cookbook_path
-
- # Instantiate a proxy loader using the temporary symlink
- proxy_loader = Chef::Cookbook::CookbookVersionLoader.new(proxy_cookbook_path, other.parent.chefignore)
- proxy_loader.load_cookbooks
-
- cookbook_to_upload = proxy_loader.cookbook_version
- cookbook_to_upload.freeze_version if options[:freeze]
-
- # Instantiate a new uploader based on the proxy loader
- uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
-
- with_actual_cookbooks_dir(temp_cookbooks_path) do
- upload_cookbook!(uploader)
- end
-
- #
- # When the temporary directory is being deleted on
- # windows, the contents of the symlink under that
- # directory is also deleted. So explicitly remove
- # the symlink without removing the original contents if we
- # are running on windows
- #
- if Chef::Platform.windows?
- Dir.rmdir proxy_cookbook_path
- end
- end
- end
-
- def upload_unversioned_cookbook(other, options)
- cookbook_to_upload = other.chef_object
- cookbook_to_upload.freeze_version if options[:freeze]
- uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
-
- with_actual_cookbooks_dir(other.parent.file_path) do
- upload_cookbook!(uploader)
- end
- end
-
- # Work around the fact that CookbookUploader doesn't understand chef_repo_path (yet)
- def with_actual_cookbooks_dir(actual_cookbook_path)
- old_cookbook_path = Chef::Config.cookbook_path
- Chef::Config.cookbook_path = actual_cookbook_path if !Chef::Config.cookbook_path
-
- yield
- ensure
- Chef::Config.cookbook_path = old_cookbook_path
- end
-
- def upload_cookbook!(uploader, options = {})
- if uploader.respond_to?(:upload_cookbook)
- uploader.upload_cookbook
- else
- uploader.upload_cookbooks
- end
- end
-
- def can_have_child?(name, is_dir)
- return false if !is_dir
- return false if root.versioned_cookbooks && name !~ Chef::ChefFS::FileSystem::CookbookDir::VALID_VERSIONED_COOKBOOK_NAME
- return true
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/data_bag_dir.rb b/lib/chef/chef_fs/file_system/data_bag_dir.rb
deleted file mode 100644
index 212f76fdb9..0000000000
--- a/lib/chef/chef_fs/file_system/data_bag_dir.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/rest_list_dir'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/file_system/must_delete_recursively_error'
-require 'chef/chef_fs/data_handler/data_bag_item_data_handler'
-
-class Chef
- module ChefFS
- module FileSystem
- class DataBagDir < RestListDir
- def initialize(name, parent, exists = nil)
- super(name, parent, nil, Chef::ChefFS::DataHandler::DataBagItemDataHandler.new)
- @exists = nil
- end
-
- def dir?
- exists?
- end
-
- def read
- # This will only be called if dir? is false, which means exists? is false.
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self)
- end
-
- def exists?
- if @exists.nil?
- @exists = parent.children.any? { |child| child.name == name }
- end
- @exists
- end
-
- def delete(recurse)
- if !recurse
- raise NotFoundError.new(self) if !exists?
- raise MustDeleteRecursivelyError.new(self), "#{path_for_printing} must be deleted recursively"
- end
- begin
- rest.delete(api_path)
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
- rescue Net::HTTPServerException => e
- if e.response.code == "404"
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "HTTP error deleting: #{e}"
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/data_bags_dir.rb b/lib/chef/chef_fs/file_system/data_bags_dir.rb
deleted file mode 100644
index 1cb61bbd1a..0000000000
--- a/lib/chef/chef_fs/file_system/data_bags_dir.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/rest_list_dir'
-require 'chef/chef_fs/file_system/data_bag_dir'
-
-class Chef
- module ChefFS
- module FileSystem
- class DataBagsDir < RestListDir
- def initialize(parent)
- super("data_bags", parent, "data")
- end
-
- def make_child_entry(name, exists = false)
- result = @children.select { |child| child.name == name }.first if @children
- result || DataBagDir.new(name, self, exists)
- end
-
- def children
- begin
- @children ||= root.get_json(api_path).keys.sort.map { |entry| make_child_entry(entry, true) }
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "Timeout getting children: #{e}"
- rescue Net::HTTPServerException => e
- if e.response.code == "404"
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "HTTP error getting children: #{e}"
- end
- end
- end
-
- def can_have_child?(name, is_dir)
- is_dir
- end
-
- def create_child(name, file_contents)
- begin
- rest.post(api_path, { 'name' => name })
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Timeout creating child '#{name}': #{e}"
- rescue Net::HTTPServerException => e
- if e.response.code == "409"
- raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e), "Cannot create #{name} under #{path}: already exists"
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "HTTP error creating child '#{name}': #{e}"
- end
- end
- @children = nil
- DataBagDir.new(name, self, true)
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/environments_dir.rb b/lib/chef/chef_fs/file_system/environments_dir.rb
deleted file mode 100644
index 3aee3ee5af..0000000000
--- a/lib/chef/chef_fs/file_system/environments_dir.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/file_system/default_environment_cannot_be_modified_error'
-require 'chef/chef_fs/data_handler/environment_data_handler'
-
-class Chef
- module ChefFS
- module FileSystem
- class EnvironmentsDir < RestListDir
- def initialize(parent)
- super("environments", parent, nil, Chef::ChefFS::DataHandler::EnvironmentDataHandler.new)
- end
-
- def make_child_entry(name, exists = nil)
- if name == '_default.json'
- DefaultEnvironmentEntry.new(name, self, exists)
- else
- super
- end
- end
-
- class DefaultEnvironmentEntry < RestListEntry
- def initialize(name, parent, exists = nil)
- super(name, parent)
- @exists = exists
- end
-
- def delete(recurse)
- raise NotFoundError.new(self) if !exists?
- raise DefaultEnvironmentCannotBeModifiedError.new(:delete, self), "#{path_for_printing} cannot be deleted."
- end
-
- def write(file_contents)
- raise NotFoundError.new(self) if !exists?
- raise DefaultEnvironmentCannotBeModifiedError.new(:write, self), "#{path_for_printing} cannot be updated."
- end
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/exceptions.rb b/lib/chef/chef_fs/file_system/exceptions.rb
new file mode 100644
index 0000000000..2a1baba8f5
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/exceptions.rb
@@ -0,0 +1,105 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ module ChefFS
+ module FileSystem
+ class FileSystemError < StandardError
+ # @param entry The entry which had an issue.
+ # @param cause The wrapped exception (if any).
+ # @param reason A string describing why this exception happened.
+ def initialize(entry, cause = nil, reason = nil)
+ super(reason)
+ @entry = entry
+ @cause = cause
+ @reason = reason
+ end
+
+ # The entry which had an issue.
+ attr_reader :entry
+
+ # The wrapped exception (if any).
+ attr_reader :cause
+
+ # A string describing why this exception happened.
+ attr_reader :reason
+ end
+
+ class MustDeleteRecursivelyError < FileSystemError; end
+
+ class NotFoundError < FileSystemError; end
+
+ class OperationFailedError < FileSystemError
+ def initialize(operation, entry, cause = nil, reason = nil)
+ super(entry, cause, reason)
+ @operation = operation
+ end
+
+ def message
+ if cause && cause.is_a?(Net::HTTPExceptions) && cause.response.code == "400"
+ "#{super} cause: #{cause.response.body}"
+ else
+ super
+ end
+ end
+
+ attr_reader :operation
+ end
+
+ class OperationNotAllowedError < FileSystemError
+ def initialize(operation, entry, cause = nil, reason = nil)
+ reason ||=
+ case operation
+ when :delete
+ "cannot be deleted"
+ when :write
+ "cannot be updated"
+ when :create_child
+ "cannot have a child created under it"
+ when :read
+ "cannot be read"
+ end
+ super(entry, cause, reason)
+ @operation = operation
+ end
+
+ attr_reader :operation
+ attr_reader :entry
+ end
+
+ class AlreadyExistsError < OperationFailedError; end
+
+ class CookbookFrozenError < AlreadyExistsError; end
+
+ class RubyFileError < OperationNotAllowedError
+ def reason
+ result = super
+ result + " (can't safely update ruby files)"
+ end
+ end
+
+ class DefaultEnvironmentCannotBeModifiedError < OperationNotAllowedError
+ def reason
+ result = super
+ result + " (default environment cannot be modified)"
+ end
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/file_system_entry.rb b/lib/chef/chef_fs/file_system/file_system_entry.rb
deleted file mode 100644
index 478631eac2..0000000000
--- a/lib/chef/chef_fs/file_system/file_system_entry.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/rest_list_dir'
-require 'chef/chef_fs/file_system/already_exists_error'
-require 'chef/chef_fs/file_system/must_delete_recursively_error'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/path_utils'
-require 'fileutils'
-
-class Chef
- module ChefFS
- module FileSystem
- class FileSystemEntry < BaseFSDir
- def initialize(name, parent, file_path = nil)
- super(name, parent)
- @file_path = file_path || "#{parent.file_path}/#{name}"
- end
-
- attr_reader :file_path
-
- def path_for_printing
- file_path
- end
-
- def children
- # Except cookbooks and data bag dirs, all things must be json files
- begin
- Dir.entries(file_path).sort.
- map { |child_name| make_child_entry(child_name) }.
- select { |child| child && can_have_child?(child.name, child.dir?) }
- rescue Errno::ENOENT
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
- end
- end
-
- def create_child(child_name, file_contents=nil)
- child = make_child_entry(child_name)
- if child.exists?
- raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
- end
- if file_contents
- child.write(file_contents)
- else
- begin
- Dir.mkdir(child.file_path)
- rescue Errno::EEXIST
- raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
- end
- end
- child
- end
-
- def dir?
- File.directory?(file_path)
- end
-
- def delete(recurse)
- if dir?
- if !recurse
- raise MustDeleteRecursivelyError.new(self, $!)
- end
- FileUtils.rm_rf(file_path)
- else
- File.delete(file_path)
- end
- end
-
- def exists?
- File.exists?(file_path) && (parent.nil? || parent.can_have_child?(name, dir?))
- end
-
- def read
- begin
- File.open(file_path, "rb") {|f| f.read}
- rescue Errno::ENOENT
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
- end
- end
-
- def write(content)
- File.open(file_path, 'wb') do |file|
- file.write(content)
- end
- end
-
- protected
-
- def make_child_entry(child_name)
- FileSystemEntry.new(child_name, self)
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/memory/memory_dir.rb b/lib/chef/chef_fs/file_system/memory/memory_dir.rb
new file mode 100644
index 0000000000..6049f404b1
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/memory/memory_dir.rb
@@ -0,0 +1,53 @@
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/memory/memory_file"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Memory
+ class MemoryDir < Chef::ChefFS::FileSystem::BaseFSDir
+ def initialize(name, parent)
+ super(name, parent)
+ @children = []
+ end
+
+ attr_reader :children
+
+ def make_child_entry(name)
+ @children.find { |child| child.name == name }
+ end
+
+ def add_child(child)
+ @children.push(child)
+ end
+
+ def can_have_child?(name, is_dir)
+ root.cannot_be_in_regex ? (name !~ root.cannot_be_in_regex) : true
+ end
+
+ def add_file(path, value)
+ path_parts = path.split("/")
+ dir = add_dir(path_parts[0..-2].join("/"))
+ file = MemoryFile.new(path_parts[-1], dir, value)
+ dir.add_child(file)
+ file
+ end
+
+ def add_dir(path)
+ path_parts = path.split("/")
+ dir = self
+ path_parts.each do |path_part|
+ subdir = dir.child(path_part)
+ if !subdir.exists?
+ subdir = MemoryDir.new(path_part, dir)
+ dir.add_child(subdir)
+ end
+ dir = subdir
+ end
+ dir
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/memory/memory_file.rb b/lib/chef/chef_fs/file_system/memory/memory_file.rb
new file mode 100644
index 0000000000..6dcefc72eb
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/memory/memory_file.rb
@@ -0,0 +1,20 @@
+require "chef/chef_fs/file_system/base_fs_object"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Memory
+ class MemoryFile < Chef::ChefFS::FileSystem::BaseFSObject
+ def initialize(name, parent, value)
+ super(name, parent)
+ @value = value
+ end
+
+ def read
+ @value
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/memory/memory_root.rb b/lib/chef/chef_fs/file_system/memory/memory_root.rb
new file mode 100644
index 0000000000..4881b3d951
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/memory/memory_root.rb
@@ -0,0 +1,23 @@
+require "chef/chef_fs/file_system/memory/memory_dir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Memory
+ class MemoryRoot < MemoryDir
+ def initialize(pretty_name, cannot_be_in_regex = nil)
+ super("", nil)
+ @pretty_name = pretty_name
+ @cannot_be_in_regex = cannot_be_in_regex
+ end
+
+ attr_reader :cannot_be_in_regex
+
+ def path_for_printing
+ @pretty_name
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/memory_dir.rb b/lib/chef/chef_fs/file_system/memory_dir.rb
deleted file mode 100644
index 260a91693c..0000000000
--- a/lib/chef/chef_fs/file_system/memory_dir.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/memory_file'
-
-class Chef
- module ChefFS
- module FileSystem
- class MemoryDir < Chef::ChefFS::FileSystem::BaseFSDir
- def initialize(name, parent)
- super(name, parent)
- @children = []
- end
-
- attr_reader :children
-
- def make_child_entry(name)
- @children.select { |child| child.name == name }.first
- end
-
- def add_child(child)
- @children.push(child)
- end
-
- def can_have_child?(name, is_dir)
- root.cannot_be_in_regex ? (name !~ root.cannot_be_in_regex) : true
- end
-
- def add_file(path, value)
- path_parts = path.split('/')
- dir = add_dir(path_parts[0..-2].join('/'))
- file = MemoryFile.new(path_parts[-1], dir, value)
- dir.add_child(file)
- file
- end
-
- def add_dir(path)
- path_parts = path.split('/')
- dir = self
- path_parts.each do |path_part|
- subdir = dir.child(path_part)
- if !subdir.exists?
- subdir = MemoryDir.new(path_part, dir)
- dir.add_child(subdir)
- end
- dir = subdir
- end
- dir
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/memory_file.rb b/lib/chef/chef_fs/file_system/memory_file.rb
deleted file mode 100644
index 0c44e703f1..0000000000
--- a/lib/chef/chef_fs/file_system/memory_file.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require 'chef/chef_fs/file_system/base_fs_object'
-
-class Chef
- module ChefFS
- module FileSystem
- class MemoryFile < Chef::ChefFS::FileSystem::BaseFSObject
- def initialize(name, parent, value)
- super(name, parent)
- @value = value
- end
- def read
- return @value
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/memory_root.rb b/lib/chef/chef_fs/file_system/memory_root.rb
deleted file mode 100644
index 4a83830946..0000000000
--- a/lib/chef/chef_fs/file_system/memory_root.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require 'chef/chef_fs/file_system/memory_dir'
-
-class Chef
- module ChefFS
- module FileSystem
- class MemoryRoot < MemoryDir
- def initialize(pretty_name, cannot_be_in_regex = nil)
- super('', nil)
- @pretty_name = pretty_name
- @cannot_be_in_regex = cannot_be_in_regex
- end
-
- attr_reader :cannot_be_in_regex
-
- def path_for_printing
- @pretty_name
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/multiplexed_dir.rb b/lib/chef/chef_fs/file_system/multiplexed_dir.rb
index 70b827f85f..cf1fb34345 100644
--- a/lib/chef/chef_fs/file_system/multiplexed_dir.rb
+++ b/lib/chef/chef_fs/file_system/multiplexed_dir.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/file_system/base_fs_object'
-require 'chef/chef_fs/file_system/nonexistent_fs_object'
+require "chef/chef_fs/file_system/base_fs_object"
+require "chef/chef_fs/file_system/nonexistent_fs_object"
class Chef
module ChefFS
@@ -17,22 +17,20 @@ class Chef
end
def children
- begin
- result = []
- seen = {}
+ result = []
+ seen = {}
# If multiple things have the same name, the first one wins.
- multiplexed_dirs.each do |dir|
- dir.children.each do |child|
- if seen[child.name]
- Chef::Log.warn("Child with name '#{child.name}' found in multiple directories: #{seen[child.name].path_for_printing} and #{child.path_for_printing}")
- else
- result << child
- seen[child.name] = child
- end
+ multiplexed_dirs.each do |dir|
+ dir.children.each do |child|
+ if seen[child.name]
+ Chef::Log.warn("Child with name '#{child.name}' found in multiple directories: #{seen[child.name].path_for_printing} and #{child.path_for_printing}") unless seen[child.name].path_for_printing == child.path_for_printing
+ else
+ result << child
+ seen[child.name] = child
end
end
- result
end
+ result
end
def make_child_entry(name)
@@ -41,7 +39,7 @@ class Chef
child_entry = dir.child(name)
if child_entry.exists?
if result
- Chef::Log.warn("Child with name '#{child_entry.name}' found in multiple directories: #{result.parent.path_for_printing} and #{child_entry.parent.path_for_printing}")
+ Chef::Log.debug("Child with name '#{child_entry.name}' found in multiple directories: #{result.parent.path_for_printing} and #{child_entry.parent.path_for_printing}")
else
result = child_entry
end
diff --git a/lib/chef/chef_fs/file_system/nonexistent_fs_object.rb b/lib/chef/chef_fs/file_system/nonexistent_fs_object.rb
index a587ab47a4..1a48d23047 100644
--- a/lib/chef/chef_fs/file_system/nonexistent_fs_object.rb
+++ b/lib/chef/chef_fs/file_system/nonexistent_fs_object.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,13 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/base_fs_object'
-require 'chef/chef_fs/file_system/not_found_error'
+require "chef/chef_fs/file_system/base_fs_object"
+require "chef/chef_fs/file_system/exceptions"
class Chef
module ChefFS
module FileSystem
class NonexistentFSObject < BaseFSObject
- def initialize(name, parent)
- super
- end
-
def exists?
false
end
diff --git a/lib/chef/chef_fs/file_system/org_entry.rb b/lib/chef/chef_fs/file_system/org_entry.rb
deleted file mode 100644
index 852956e1e5..0000000000
--- a/lib/chef/chef_fs/file_system/org_entry.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/data_handler/organization_data_handler'
-
-class Chef
- module ChefFS
- module FileSystem
- # /organizations/NAME/org.json
- # Represents the actual data at /organizations/NAME (the full name, etc.)
- class OrgEntry < RestListEntry
- def initialize(name, parent, exists = nil)
- super(name, parent)
- @exists = exists
- end
-
- def data_handler
- Chef::ChefFS::DataHandler::OrganizationDataHandler.new
- end
-
- # /organizations/foo/org.json -> GET /organizations/foo
- def api_path
- parent.api_path
- end
-
- def exists?
- parent.exists?
- end
-
- def delete(recurse)
- raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self)
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/organization_invites_entry.rb b/lib/chef/chef_fs/file_system/organization_invites_entry.rb
deleted file mode 100644
index 5df37085cb..0000000000
--- a/lib/chef/chef_fs/file_system/organization_invites_entry.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/data_handler/organization_invites_data_handler'
-require 'chef/json_compat'
-
-class Chef
- module ChefFS
- module FileSystem
- # /organizations/NAME/invitations.json
- # read data from:
- # - GET /organizations/NAME/association_requests
- # write data to:
- # - remove from list: DELETE /organizations/NAME/association_requests/id
- # - add to list: POST /organizations/NAME/association_requests
- class OrganizationInvitesEntry < RestListEntry
- def initialize(name, parent, exists = nil)
- super(name, parent)
- @exists = exists
- end
-
- def data_handler
- Chef::ChefFS::DataHandler::OrganizationInvitesDataHandler.new
- end
-
- # /organizations/foo/invites.json -> /organizations/foo/association_requests
- def api_path
- File.join(parent.api_path, 'association_requests')
- end
-
- def exists?
- parent.exists?
- end
-
- def delete(recurse)
- raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self)
- end
-
- def write(contents)
- desired_invites = minimize_value(Chef::JSONCompat.parse(contents, :create_additions => false))
- actual_invites = _read_json.inject({}) { |h,val| h[val['username']] = val['id']; h }
- invites = actual_invites.keys
- (desired_invites - invites).each do |invite|
- begin
- rest.post(api_path, { 'user' => invite })
- rescue Net::HTTPServerException => e
- if e.response.code == '409'
- Chef::Log.warn("Could not invite #{invite} to organization #{org}: #{api_error_text(e.response)}")
- else
- raise
- end
- end
- end
- (invites - desired_invites).each do |invite|
- rest.delete(File.join(api_path, actual_invites[invite]))
- end
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/organization_members_entry.rb b/lib/chef/chef_fs/file_system/organization_members_entry.rb
deleted file mode 100644
index 40042a9cbc..0000000000
--- a/lib/chef/chef_fs/file_system/organization_members_entry.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/data_handler/organization_members_data_handler'
-require 'chef/json_compat'
-
-class Chef
- module ChefFS
- module FileSystem
- # /organizations/NAME/members.json
- # reads data from:
- # - GET /organizations/NAME/users
- # writes data to:
- # - remove from list: DELETE /organizations/NAME/users/name
- # - add to list: POST /organizations/NAME/users/name
- class OrganizationMembersEntry < RestListEntry
- def initialize(name, parent, exists = nil)
- super(name, parent)
- @exists = exists
- end
-
- def data_handler
- Chef::ChefFS::DataHandler::OrganizationMembersDataHandler.new
- end
-
- # /organizations/foo/members.json -> /organizations/foo/users
- def api_path
- File.join(parent.api_path, 'users')
- end
-
- def exists?
- parent.exists?
- end
-
- def delete(recurse)
- raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self)
- end
-
- def write(contents)
- desired_members = minimize_value(Chef::JSONCompat.parse(contents, :create_additions => false))
- members = minimize_value(_read_json)
- (desired_members - members).each do |member|
- begin
- rest.post(api_path, 'username' => member)
- rescue Net::HTTPServerException => e
- if %w(404 405).include?(e.response.code)
- raise "Chef server at #{api_path} does not allow you to directly add members. Please either upgrade your Chef server or move the users you want into invitations.json instead of members.json."
- else
- raise
- end
- end
- end
- (members - desired_members).each do |member|
- rest.delete(File.join(api_path, member))
- end
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/operation_failed_error.rb b/lib/chef/chef_fs/file_system/repository/acl.rb
index 28d170d628..023ae11379 100644
--- a/lib/chef/chef_fs/file_system/operation_failed_error.rb
+++ b/lib/chef/chef_fs/file_system/repository/acl.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,26 +16,29 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/file_system_error'
+require "chef/chef_fs/data_handler/acl_data_handler"
+require "chef/chef_fs/file_system/repository/base_file"
class Chef
module ChefFS
module FileSystem
- class OperationFailedError < FileSystemError
- def initialize(operation, entry, cause = nil)
- super(entry, cause)
- @operation = operation
- end
+ module Repository
+
+ class Acl < BaseFile
- def message
- if cause && cause.is_a?(Net::HTTPExceptions) && cause.response.code == "400"
- "#{super} cause: #{cause.response.body}"
- else
+ def initialize(name, parent)
+ @data_handler = Chef::ChefFS::DataHandler::AclDataHandler.new
super
end
- end
- attr_reader :operation
+ def bare_name
+ if name == "organization" && parent.kind_of?(AclDir)
+ "organization.json"
+ else
+ name
+ end
+ end
+ end
end
end
end
diff --git a/lib/chef/chef_fs/file_system/repository/acls_dir.rb b/lib/chef/chef_fs/file_system/repository/acls_dir.rb
new file mode 100644
index 0000000000..110befdf22
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/acls_dir.rb
@@ -0,0 +1,50 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/acl"
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/repository/acls_sub_dir"
+require "chef/chef_fs/file_system/chef_server/acls_dir"
+require "chef/chef_fs/data_handler/acl_data_handler"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class AclsDir < Repository::Directory
+
+ BARE_FILES = %w{ organization.json root }
+
+ def can_have_child?(name, is_dir)
+ is_dir ? Chef::ChefFS::FileSystem::ChefServer::AclsDir::ENTITY_TYPES.include?(name) : BARE_FILES.include?(name)
+ end
+
+ protected
+
+ def make_child_entry(child_name)
+ if BARE_FILES.include? child_name
+ Acl.new(child_name, self)
+ else
+ AclsSubDir.new(child_name, self)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/acls_sub_dir.rb b/lib/chef/chef_fs/file_system/repository/acls_sub_dir.rb
new file mode 100644
index 0000000000..70c7d77480
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/acls_sub_dir.rb
@@ -0,0 +1,38 @@
+#
+# Author:: Jordan Running (<jr@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/acl"
+require "chef/chef_fs/data_handler/acl_data_handler"
+require "chef/chef_fs/file_system/repository/directory"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class AclsSubDir < Repository::Directory
+
+ protected
+
+ def make_child_entry(child_name)
+ Acl.new(child_name, self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/base_file.rb b/lib/chef/chef_fs/file_system/repository/base_file.rb
new file mode 100644
index 0000000000..3e1edc8d62
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/base_file.rb
@@ -0,0 +1,155 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system_cache"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ class BaseFile
+
+ attr_reader :name
+ attr_reader :parent
+ attr_reader :path
+ attr_reader :file_path
+ attr_reader :data_handler
+
+ alias_method :display_path, :path
+ alias_method :display_name, :name
+
+ def initialize(name, parent)
+ @parent = parent
+
+ if %w{ .rb .json }.include? File.extname(name)
+ name = File.basename(name, ".*")
+ end
+
+ file_path = "#{parent.file_path}/#{name}"
+
+ Chef::Log.debug "BaseFile: Detecting file extension for #{name}"
+ ext = File.exist?(file_path + ".rb") ? ".rb" : ".json"
+ name += ext
+ file_path += ext
+
+ Chef::Log.debug "BaseFile: got a file path of #{file_path} for #{name}"
+ @name = name
+ @path = Chef::ChefFS::PathUtils.join(parent.path, name)
+ @file_path = file_path
+ end
+
+ def dir?
+ false
+ end
+
+ # Used to compare names on disk to the API, for diffing.
+ def bare_name
+ File.basename(name, ".*")
+ end
+
+ def is_json_file?
+ File.extname(file_path) == ".json"
+ end
+
+ def is_ruby_file?
+ File.extname(file_path) == ".rb"
+ end
+
+ def name_valid?
+ !name.start_with?(".") && (is_json_file? || is_ruby_file?)
+ end
+
+ def fs_entry_valid?
+ name_valid? && exists?
+ end
+
+ def create(file_contents)
+ if exists?
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self)
+ else
+ write(file_contents)
+ end
+ end
+
+ def can_have_child?(name, is_dir)
+ false
+ end
+
+ attr_writer :write_pretty_json
+ def write_pretty_json
+ @write_pretty_json.nil? ? root.write_pretty_json : @write_pretty_json
+ end
+
+ def path_for_printing
+ file_path
+ end
+
+ def delete(_)
+ FileSystemCache.instance.delete!(file_path)
+ File.delete(file_path)
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+
+ def exists?
+ File.file?(file_path)
+ end
+
+ def minimize(content, entry)
+ object = Chef::JSONCompat.parse(content)
+ object = data_handler.normalize(object, entry)
+ object = data_handler.minimize(object, entry)
+ Chef::JSONCompat.to_json_pretty(object)
+ end
+
+ def read
+ if is_ruby_file?
+ data_handler.from_ruby(file_path).to_json
+ else
+ File.open(file_path, "rb") { |f| f.read }
+ end
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+
+ def write(content)
+ if is_ruby_file?
+ raise Chef::ChefFS::FileSystem::RubyFileError.new(:write, self)
+ end
+ if content && write_pretty_json && is_json_file?
+ content = minimize(content, self)
+ end
+ File.open(file_path, "wb") do |file|
+ file.write(content)
+ end
+ end
+
+ def root
+ parent.root
+ end
+
+ def compare_to(other)
+ nil
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifact_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifact_dir.rb
new file mode 100644
index 0000000000..83c13e5e20
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifact_dir.rb
@@ -0,0 +1,41 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class ChefRepositoryFileSystemCookbookArtifactDir < ChefRepositoryFileSystemCookbookDir
+ # Override from parent
+ def cookbook_version
+ loader = Chef::Cookbook::CookbookVersionLoader.new(file_path, parent.chefignore)
+ cookbook_name, _dash, identifier = name.rpartition("-")
+ # KLUDGE: We shouldn't have to use instance_variable_set
+ loader.instance_variable_set(:@cookbook_name, cookbook_name)
+ loader.load_cookbooks
+ cookbook_version = loader.cookbook_version
+ cookbook_version.identifier = identifier
+ cookbook_version
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb
new file mode 100644
index 0000000000..31b538b9ce
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb
@@ -0,0 +1,144 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry"
+require "chef/chef_fs/file_system/chef_server/cookbook_dir"
+require "chef/chef_fs/file_system/chef_server/versioned_cookbook_dir"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/cookbook/cookbook_version_loader"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ # Represents ROOT/cookbooks/:cookbook
+ class ChefRepositoryFileSystemCookbookDir < ChefRepositoryFileSystemCookbookEntry
+
+ # API Required by Respository::Directory
+
+ def fs_entry_valid?
+ return false unless File.directory?(file_path) && name_valid?
+ if can_upload?
+ true
+ else
+ Chef::Log.warn("Cookbook '#{name}' is empty or entirely chefignored at #{path_for_printing}")
+ false
+ end
+ end
+
+ def name_valid?
+ !name.start_with?(".")
+ end
+
+ def dir?
+ true
+ end
+
+ def create(file_contents = nil)
+ if exists?
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self)
+ end
+ begin
+ Dir.mkdir(file_path)
+ rescue Errno::EEXIST
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self)
+ end
+ end
+
+ def write(cookbook_path, cookbook_version_json, from_fs)
+ # Use the copy/diff algorithm to copy it down so we don't destroy
+ # chefignored data. This is terribly un-thread-safe.
+ Chef::ChefFS::FileSystem.copy_to(Chef::ChefFS::FilePattern.new("/#{cookbook_path}"), from_fs, self, nil, { :purge => true })
+
+ # Write out .uploaded-cookbook-version.json
+ # cookbook_file_path = File.join(file_path, cookbook_name) <- this should be the same as self.file_path
+ if !File.exists?(file_path)
+ FileUtils.mkdir_p(file_path)
+ end
+ uploaded_cookbook_version_path = File.join(file_path, Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE)
+ File.open(uploaded_cookbook_version_path, "w") do |file|
+ file.write(cookbook_version_json)
+ end
+ end
+
+ # Customizations of base class
+
+ def chef_object
+ cb = cookbook_version
+ if !cb
+ Chef::Log.error("Cookbook #{file_path} empty.")
+ raise "Cookbook #{file_path} empty."
+ end
+ cb
+ rescue => e
+ Chef::Log.error("Could not read #{path_for_printing} into a Chef object: #{e}")
+ Chef::Log.error(e.backtrace.join("\n"))
+ raise
+ end
+
+ def children
+ super.select { |entry| !(entry.dir? && entry.children.size == 0 ) }
+ end
+
+ def can_have_child?(name, is_dir)
+ if is_dir
+ # Only the given directories will be uploaded.
+ return Chef::ChefFS::FileSystem::ChefServer::CookbookDir::COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) && name != "root_files"
+ elsif name == Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE
+ return false
+ end
+ super(name, is_dir)
+ end
+
+ # Exposed as a class method so that it can be used elsewhere
+ def self.canonical_cookbook_name(entry_name)
+ name_match = Chef::ChefFS::FileSystem::ChefServer::VersionedCookbookDir::VALID_VERSIONED_COOKBOOK_NAME.match(entry_name)
+ return nil if name_match.nil?
+ name_match[1]
+ end
+
+ def canonical_cookbook_name(entry_name)
+ self.class.canonical_cookbook_name(entry_name)
+ end
+
+ def uploaded_cookbook_version_path
+ File.join(file_path, Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE)
+ end
+
+ def can_upload?
+ File.exists?(uploaded_cookbook_version_path) || children.size > 0
+ end
+
+ protected
+
+ def make_child_entry(child_name)
+ segment_info = Chef::ChefFS::FileSystem::ChefServer::CookbookDir::COOKBOOK_SEGMENT_INFO[child_name.to_sym] || {}
+ ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, segment_info[:ruby_only], segment_info[:recursive])
+ end
+
+ def cookbook_version
+ loader = Chef::Cookbook::CookbookVersionLoader.new(file_path, parent.chefignore)
+ loader.load_cookbooks
+ loader.cookbook_version
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb
new file mode 100644
index 0000000000..90b8c88cff
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb
@@ -0,0 +1,177 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/file_system_entry"
+require "chef/chef_fs/file_system/repository/cookbooks_dir"
+require "chef/chef_fs/file_system/exceptions"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ # NB: unlike most other things in chef_fs/file_system/repository, this
+ # class represents both files and directories, so it needs to have the
+ # methods/if branches for each.
+ class ChefRepositoryFileSystemCookbookEntry
+
+ attr_reader :name
+ attr_reader :parent
+ attr_reader :path
+ attr_reader :ruby_only
+ attr_reader :recursive
+ attr_reader :file_path
+
+ alias_method :display_path, :path
+ alias_method :display_name, :name
+ alias_method :bare_name, :name
+
+ def initialize(name, parent, file_path = nil, ruby_only = false, recursive = false)
+ @parent = parent
+ @name = name
+ @path = Chef::ChefFS::PathUtils.join(parent.path, name)
+ @ruby_only = ruby_only
+ @recursive = recursive
+ @data_handler = nil
+ @file_path = file_path || "#{parent.file_path}/#{name}"
+ end
+
+ def children
+ entries = Dir.entries(file_path).sort.
+ map { |child_name| make_child_entry(child_name) }.
+ select { |child| child && can_have_child?(child.name, child.dir?) }
+ entries.select { |entry| !(entry.dir? && entry.children.size == 0 ) }
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+
+ def can_have_child?(name, is_dir)
+ if is_dir
+ return recursive && name != "." && name != ".."
+ elsif ruby_only
+ return false if name[-3..-1] != ".rb"
+ end
+
+ # Check chefignore
+ ignorer = parent
+ loop do
+ if ignorer.is_a?(CookbooksDir)
+ # Grab the path from entry to child
+ path_to_child = name
+ child = self
+ while child.parent != ignorer
+ path_to_child = PathUtils.join(child.name, path_to_child)
+ child = child.parent
+ end
+ # Check whether that relative path is ignored
+ return !ignorer.chefignore || !ignorer.chefignore.ignored?(path_to_child)
+ end
+ ignorer = ignorer.parent
+ break unless ignorer
+ end
+
+ true
+ end
+
+ def write_pretty_json
+ false
+ end
+
+ def path_for_printing
+ file_path
+ end
+
+ def create_child(child_name, file_contents = nil)
+ child = make_child_entry(child_name)
+ if child.exists?
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
+ end
+ if file_contents
+ child.write(file_contents)
+ else
+ begin
+ Dir.mkdir(child.file_path)
+ rescue Errno::EEXIST
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
+ end
+ end
+ child
+ end
+
+ def dir?
+ File.directory?(file_path)
+ end
+
+ def delete(recurse)
+ FileSystemCache.instance.delete!(file_path)
+ begin
+ if dir?
+ if !recurse
+ raise MustDeleteRecursivelyError.new(self, $!)
+ end
+ FileUtils.rm_r(file_path)
+ else
+ File.delete(file_path)
+ end
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+ end
+
+ def exists?
+ File.exists?(file_path) && (parent.nil? || parent.can_have_child?(name, dir?))
+ end
+
+ def read
+ File.open(file_path, "rb") { |f| f.read }
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+
+ def write(content)
+ File.open(file_path, "wb") do |file|
+ file.write(content)
+ end
+ end
+
+ def child(name)
+ if can_have_child?(name, true) || can_have_child?(name, false)
+ result = make_child_entry(name)
+ end
+ result || NonexistentFSObject.new(name, self)
+ end
+
+ def root
+ parent.root
+ end
+
+ def compare_to(other)
+ nil
+ end
+
+ protected
+
+ def make_child_entry(child_name)
+ ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, ruby_only, recursive)
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb
new file mode 100644
index 0000000000..9ea9268ab1
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb
@@ -0,0 +1,231 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/repository/acls_dir"
+require "chef/chef_fs/file_system/repository/clients_dir"
+require "chef/chef_fs/file_system/repository/cookbooks_dir"
+require "chef/chef_fs/file_system/repository/cookbook_artifacts_dir"
+require "chef/chef_fs/file_system/repository/containers_dir"
+require "chef/chef_fs/file_system/repository/data_bags_dir"
+require "chef/chef_fs/file_system/repository/environments_dir"
+require "chef/chef_fs/file_system/repository/groups_dir"
+require "chef/chef_fs/file_system/repository/nodes_dir"
+require "chef/chef_fs/file_system/repository/policy_groups_dir"
+require "chef/chef_fs/file_system/repository/roles_dir"
+require "chef/chef_fs/file_system/repository/users_dir"
+require "chef/chef_fs/file_system/repository/client_keys_dir"
+require "chef/chef_fs/file_system/repository/file_system_entry"
+require "chef/chef_fs/file_system/repository/policies_dir"
+require "chef/chef_fs/file_system/repository/versioned_cookbooks_dir"
+require "chef/chef_fs/file_system/multiplexed_dir"
+require "chef/chef_fs/data_handler/client_data_handler"
+require "chef/chef_fs/data_handler/client_key_data_handler"
+require "chef/chef_fs/data_handler/environment_data_handler"
+require "chef/chef_fs/data_handler/node_data_handler"
+require "chef/chef_fs/data_handler/policy_data_handler"
+require "chef/chef_fs/data_handler/policy_group_data_handler"
+require "chef/chef_fs/data_handler/role_data_handler"
+require "chef/chef_fs/data_handler/user_data_handler"
+require "chef/chef_fs/data_handler/group_data_handler"
+require "chef/chef_fs/data_handler/container_data_handler"
+require "chef/win32/security" if Chef::Platform.windows?
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ #
+ # Represents the root of a local Chef repository, with directories for
+ # nodes, cookbooks, roles, etc. under it.
+ #
+ class ChefRepositoryFileSystemRootDir < BaseFSDir
+ #
+ # Create a new Chef Repository File System root.
+ #
+ # == Parameters
+ # [child_paths]
+ # A hash of child paths, e.g.:
+ # "nodes" => [ '/var/nodes', '/home/jkeiser/nodes' ],
+ # "roles" => [ '/var/roles' ],
+ # ...
+ # [root_paths]
+ # An array of paths representing the top level, where
+ # +org.json+, +members.json+, and +invites.json+ will be stored.
+ # [chef_config] - a hash of options that looks suspiciously like the ones
+ # stored in Chef::Config, containing at least these keys:
+ # :versioned_cookbooks:: whether to include versions in cookbook names
+ def initialize(child_paths, root_paths = [], chef_config = Chef::Config)
+ super("", nil)
+ @child_paths = child_paths
+ @root_paths = root_paths
+ @versioned_cookbooks = chef_config[:versioned_cookbooks]
+ end
+
+ attr_accessor :write_pretty_json
+
+ attr_reader :root_paths
+ attr_reader :child_paths
+ attr_reader :versioned_cookbooks
+
+ CHILDREN = %w{org.json invitations.json members.json}
+
+ def children
+ @children ||= begin
+ result = child_paths.keys.sort.map { |name| make_child_entry(name) }
+ result += CHILDREN.map { |name| make_child_entry(name) }
+ result.select { |c| c && c.exists? }.sort_by { |c| c.name }
+ end
+ end
+
+ def can_have_child?(name, is_dir)
+ if is_dir
+ child_paths.has_key?(name)
+ elsif root_dir
+ CHILDREN.include?(name)
+ else
+ false
+ end
+ end
+
+ def create_child(name, file_contents = nil)
+ if file_contents
+ child = root_dir.create_child(name, file_contents)
+ else
+ child_paths[name].each do |path|
+ begin
+ Dir.mkdir(path, 0700)
+ if Chef::Platform.windows?
+ all_mask = Chef::ReservedNames::Win32::API::Security::GENERIC_ALL
+ administrators = Chef::ReservedNames::Win32::Security::SID.Administrators
+ owner = Chef::ReservedNames::Win32::Security::SID.default_security_object_owner
+ dacl = Chef::ReservedNames::Win32::Security::ACL.create([
+ Chef::ReservedNames::Win32::Security::ACE.access_allowed(owner, all_mask),
+ Chef::ReservedNames::Win32::Security::ACE.access_allowed(administrators, all_mask),
+ ])
+ so = Chef::ReservedNames::Win32::Security::SecurableObject.new(path)
+ so.owner = owner
+ so.set_dacl(dacl, false)
+ end
+ rescue Errno::EEXIST
+ end
+ end
+ child = make_child_entry(name)
+ end
+ @children = nil
+ child
+ end
+
+ def json_class
+ nil
+ end
+
+ # Used to print out a human-readable file system description
+ def fs_description
+ repo_paths = root_paths || [ File.dirname(child_paths["cookbooks"][0]) ]
+ result = "repository at #{repo_paths.join(', ')}\n"
+ if versioned_cookbooks
+ result << " Multiple versions per cookbook\n"
+ else
+ result << " One version per cookbook\n"
+ end
+ child_paths.each_pair do |name, paths|
+ if paths.any? { |path| !repo_paths.include?(File.dirname(path)) }
+ result << " #{name} at #{paths.join(', ')}\n"
+ end
+ end
+ result
+ end
+
+ private
+
+ #
+ # A FileSystemEntry representing the root path where invites.json,
+ # members.json and org.json may be found.
+ #
+ def root_dir
+ existing_paths = root_paths.select { |path| File.exists?(path) }
+ if existing_paths.size > 0
+ MultiplexedDir.new(existing_paths.map do |path|
+ dir = FileSystemEntry.new(name, parent, path)
+ dir.write_pretty_json = !!write_pretty_json
+ dir
+ end)
+ end
+ end
+
+ #
+ # Create a child entry of the appropriate type:
+ # cookbooks, data_bags, acls, etc. All will be multiplexed (i.e. if
+ # you have multiple paths for cookbooks, the multiplexed dir will grab
+ # cookbooks from all of them when you list or grab them).
+ #
+ def make_child_entry(name)
+ if CHILDREN.include?(name)
+ return nil if !root_dir
+ return root_dir.child(name)
+ end
+
+ paths = (child_paths[name] || []).select { |path| File.exists?(path) }
+ if paths.size == 0
+ return NonexistentFSObject.new(name, self)
+ end
+ case name
+ when "acls"
+ dirs = paths.map { |path| AclsDir.new(name, self, path) }
+ when "client_keys"
+ dirs = paths.map { |path| ClientKeysDir.new(name, self, path) }
+ when "clients"
+ dirs = paths.map { |path| ClientsDir.new(name, self, path) }
+ when "containers"
+ dirs = paths.map { |path| ContainersDir.new(name, self, path) }
+ when "cookbooks"
+ if versioned_cookbooks
+ dirs = paths.map { |path| VersionedCookbooksDir.new(name, self, path) }
+ else
+ dirs = paths.map { |path| CookbooksDir.new(name, self, path) }
+ end
+ when "cookbook_artifacts"
+ dirs = paths.map { |path| CookbookArtifactsDir.new(name, self, path) }
+ when "data_bags"
+ dirs = paths.map { |path| DataBagsDir.new(name, self, path) }
+ when "environments"
+ dirs = paths.map { |path| EnvironmentsDir.new(name, self, path) }
+ when "groups"
+ dirs = paths.map { |path| GroupsDir.new(name, self, path) }
+ when "nodes"
+ dirs = paths.map { |path| NodesDir.new(name, self, path) }
+ when "policy_groups"
+ dirs = paths.map { |path| PolicyGroupsDir.new(name, self, path) }
+ when "policies"
+ dirs = paths.map { |path| PoliciesDir.new(name, self, path) }
+ when "roles"
+ dirs = paths.map { |path| RolesDir.new(name, self, path) }
+ when "users"
+ dirs = paths.map { |path| UsersDir.new(name, self, path) }
+ else
+ raise "Unknown top level path #{name}"
+ end
+ MultiplexedDir.new(dirs)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbook_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbook_dir.rb
new file mode 100644
index 0000000000..5dc74d85da
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbook_dir.rb
@@ -0,0 +1,42 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class ChefRepositoryFileSystemVersionedCookbookDir < ChefRepositoryFileSystemCookbookDir
+ # Override from parent
+ def cookbook_version
+ loader = Chef::Cookbook::CookbookVersionLoader.new(file_path, parent.chefignore)
+ # We need the canonical cookbook name if we are using versioned cookbooks, but we don't
+ # want to spend a lot of time adding code to the main Chef libraries
+ canonical_name = canonical_cookbook_name(File.basename(file_path))
+ raise "When versioned_cookbooks mode is on, cookbook #{file_path} must match format <cookbook_name>-x.y.z" unless canonical_name
+ # KLUDGE: We shouldn't have to use instance_variable_set
+ loader.instance_variable_set(:@cookbook_name, canonical_name)
+ loader.load_cookbooks
+ loader.cookbook_version
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/client.rb b/lib/chef/chef_fs/file_system/repository/client.rb
new file mode 100644
index 0000000000..6a99b7f005
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/client.rb
@@ -0,0 +1,38 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/data_handler/client_data_handler"
+require "chef/chef_fs/file_system/repository/base_file"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ class Client < BaseFile
+
+ def initialize(name, parent)
+ @data_handler = Chef::ChefFS::DataHandler::ClientDataHandler.new
+ super
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/client_key.rb b/lib/chef/chef_fs/file_system/repository/client_key.rb
new file mode 100644
index 0000000000..8ca4f85d2f
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/client_key.rb
@@ -0,0 +1,38 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/data_handler/client_key_data_handler"
+require "chef/chef_fs/file_system/repository/base_file"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ class ClientKey < BaseFile
+
+ def initialize(name, parent)
+ @data_handler = Chef::ChefFS::DataHandler::ClientKeyDataHandler.new
+ super
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir.rb b/lib/chef/chef_fs/file_system/repository/client_keys_dir.rb
index 73556b2c0b..9e7e7b3d5c 100644
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir.rb
+++ b/lib/chef/chef_fs/file_system/repository/client_keys_dir.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Jordan Running (<jr@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,25 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
-require 'chef/chef_fs/data_handler/data_bag_item_data_handler'
+require "chef/chef_fs/file_system/repository/client_keys_sub_dir"
+require "chef/chef_fs/data_handler/client_key_data_handler"
+require "chef/chef_fs/file_system/repository/directory"
class Chef
module ChefFS
module FileSystem
- class ChefRepositoryFileSystemDataBagsDir < ChefRepositoryFileSystemEntry
- def initialize(name, parent, path = nil)
- super(name, parent, path, Chef::ChefFS::DataHandler::DataBagItemDataHandler.new)
- end
+ module Repository
+ class ClientKeysDir < Repository::Directory
+
+ def can_have_child?(name, is_dir)
+ is_dir && !name.start_with?(".")
+ end
+
+ protected
- def can_have_child?(name, is_dir)
- is_dir && !name.start_with?('.')
+ def make_child_entry(child_name)
+ ClientKeysSubDir.new(child_name, self)
+ end
end
end
end
diff --git a/lib/chef/chef_fs/file_system/repository/client_keys_sub_dir.rb b/lib/chef/chef_fs/file_system/repository/client_keys_sub_dir.rb
new file mode 100644
index 0000000000..6aafcfe294
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/client_keys_sub_dir.rb
@@ -0,0 +1,38 @@
+#
+# Author:: Jordan Running (<jr@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/client_key"
+require "chef/chef_fs/data_handler/client_key_data_handler"
+require "chef/chef_fs/file_system/repository/directory"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class ClientKeysSubDir < Repository::Directory
+
+ protected
+
+ def make_child_entry(child_name)
+ ClientKey.new(child_name, self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/clients_dir.rb b/lib/chef/chef_fs/file_system/repository/clients_dir.rb
new file mode 100644
index 0000000000..01027f83ac
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/clients_dir.rb
@@ -0,0 +1,37 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/client"
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/exceptions"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class ClientsDir < Repository::Directory
+
+ def make_child_entry(child_name)
+ Client.new(child_name, self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/container.rb b/lib/chef/chef_fs/file_system/repository/container.rb
new file mode 100644
index 0000000000..e14a2ded73
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/container.rb
@@ -0,0 +1,38 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/data_handler/container_data_handler"
+require "chef/chef_fs/file_system/repository/base_file"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ class Container < BaseFile
+
+ def initialize(name, parent)
+ @data_handler = Chef::ChefFS::DataHandler::ContainerDataHandler.new
+ super
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/containers_dir.rb b/lib/chef/chef_fs/file_system/repository/containers_dir.rb
new file mode 100644
index 0000000000..2af496f418
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/containers_dir.rb
@@ -0,0 +1,37 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/container"
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/exceptions"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class ContainersDir < Repository::Directory
+
+ def make_child_entry(child_name)
+ Container.new(child_name, self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/cookbook_artifacts_dir.rb b/lib/chef/chef_fs/file_system/repository/cookbook_artifacts_dir.rb
new file mode 100644
index 0000000000..773d9a5e5a
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/cookbook_artifacts_dir.rb
@@ -0,0 +1,36 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/cookbooks_dir"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifact_dir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ # Represents ROOT/cookbook_artifacts
+ class CookbookArtifactsDir < CookbooksDir
+ def make_child_entry(child_name)
+ ChefRepositoryFileSystemCookbookArtifactDir.new(child_name, self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/cookbooks_dir.rb b/lib/chef/chef_fs/file_system/repository/cookbooks_dir.rb
new file mode 100644
index 0000000000..86eca95ba8
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/cookbooks_dir.rb
@@ -0,0 +1,51 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir"
+require "chef/cookbook/chefignore"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ class CookbooksDir < Repository::Directory
+
+ def chefignore
+ @chefignore ||= Chef::Cookbook::Chefignore.new(file_path)
+ rescue Errno::EISDIR, Errno::EACCES
+ # Work around a bug in Chefignore when chefignore is a directory
+ end
+
+ def write_cookbook(cookbook_path, cookbook_version_json, from_fs)
+ cookbook_name = File.basename(cookbook_path)
+ make_child_entry(cookbook_name).write(cookbook_path, cookbook_version_json, from_fs)
+ end
+
+ protected
+
+ def make_child_entry(child_name)
+ ChefRepositoryFileSystemCookbookDir.new(child_name, self)
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/data_bag.rb b/lib/chef/chef_fs/file_system/repository/data_bag.rb
new file mode 100644
index 0000000000..fb3ad9da77
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/data_bag.rb
@@ -0,0 +1,39 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/repository/data_bag_item"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ # Represents REPO_ROOT/data_bags/data_bag Children of this are data bag
+ # items.
+ class DataBag < Repository::Directory
+
+ def make_child_entry(child_name)
+ DataBagItem.new(child_name, self)
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/data_bag_item.rb b/lib/chef/chef_fs/file_system/repository/data_bag_item.rb
new file mode 100644
index 0000000000..2e3fb39606
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/data_bag_item.rb
@@ -0,0 +1,38 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/data_handler/data_bag_item_data_handler"
+require "chef/chef_fs/file_system/repository/base_file"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ class DataBagItem < BaseFile
+
+ def initialize(name, parent)
+ @data_handler = Chef::ChefFS::DataHandler::DataBagItemDataHandler.new
+ super
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/data_bags_dir.rb b/lib/chef/chef_fs/file_system/repository/data_bags_dir.rb
new file mode 100644
index 0000000000..666fede62b
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/data_bags_dir.rb
@@ -0,0 +1,39 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/repository/data_bag"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ # Represents the REPO_ROOT/data_bags directory. Children of this are
+ # data bags.
+ class DataBagsDir < Repository::Directory
+
+ def make_child_entry(child_name)
+ DataBag.new(child_name, self)
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/directory.rb b/lib/chef/chef_fs/file_system/repository/directory.rb
new file mode 100644
index 0000000000..328cf92b03
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/directory.rb
@@ -0,0 +1,167 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system_cache"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ class Directory
+
+ attr_reader :name
+ attr_reader :parent
+ attr_reader :path
+ attr_reader :file_path
+
+ alias_method :display_path, :path
+ alias_method :display_name, :name
+ alias_method :bare_name, :name
+
+ def initialize(name, parent, file_path = nil)
+ @parent = parent
+ @name = name
+ @path = Chef::ChefFS::PathUtils.join(parent.path, name)
+ @file_path = file_path || "#{parent.file_path}/#{name}"
+ end
+
+ def name_valid?
+ !name.start_with?(".")
+ end
+
+ # Whether or not the file system entry this object represents is
+ # valid. Mainly used to trim dotfiles/dotdirs and non directories
+ # from the list of children when enumerating items on the filesystem
+ def fs_entry_valid?
+ name_valid? && File.directory?(file_path)
+ end
+
+ # ChefFS API:
+
+ # Public API called by multiplexed_dir
+ def can_have_child?(name, is_dir)
+ possible_child = make_child_entry(name)
+ possible_child.dir? == is_dir && possible_child.name_valid?
+ end
+
+ # Public API called by chef_fs/file_system
+ def dir?
+ true
+ end
+
+ def path_for_printing
+ file_path
+ end
+
+ def children
+ return FileSystemCache.instance.children(file_path) if FileSystemCache.instance.exist?(file_path)
+ children = dir_ls.sort.
+ map { |child_name| make_child_entry(child_name) }.
+ select { |new_child| new_child.fs_entry_valid? && can_have_child?(new_child.name, new_child.dir?) }
+ FileSystemCache.instance.set_children(file_path, children)
+ rescue Errno::ENOENT => e
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+ end
+
+ def create_child(child_name, file_contents = nil)
+ child = make_child_entry(child_name)
+ if child.exists?
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
+ end
+ FileSystemCache.instance.delete!(child.file_path)
+ if file_contents
+ child.write(file_contents)
+ else
+ begin
+ Dir.mkdir(child.file_path)
+ rescue Errno::EEXIST
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
+ end
+ end
+ child
+ end
+
+ # An empty children array is an empty dir
+ def empty?
+ children.empty?
+ end
+
+ # Public API callied by chef_fs/file_system
+ def child(name)
+ possible_child = make_child_entry(name)
+ if possible_child.name_valid?
+ possible_child
+ else
+ NonexistentFSObject.new(name, self)
+ end
+ end
+
+ def root
+ parent.root
+ end
+
+ # File system wrappers
+
+ def create(file_contents = nil)
+ if exists?
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self)
+ end
+ begin
+ FileSystemCache.instance.delete!(file_path)
+ Dir.mkdir(file_path)
+ rescue Errno::EEXIST
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self)
+ end
+ end
+
+ def dir_ls
+ Dir.entries(file_path).select { |p| !p.start_with?(".") }
+ end
+
+ def delete(recurse)
+ if exists?
+ if !recurse
+ raise MustDeleteRecursivelyError.new(self, $!)
+ end
+ FileUtils.rm_r(file_path)
+ FileSystemCache.instance.delete!(file_path)
+ else
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+ end
+
+ def exists?
+ File.exists?(file_path)
+ end
+
+ protected
+
+ def write(data)
+ raise FileSystemError.new(self, nil, "attempted to write to a directory entry")
+ end
+
+ def make_child_entry(child_name)
+ raise "Not Implemented"
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/environment.rb b/lib/chef/chef_fs/file_system/repository/environment.rb
new file mode 100644
index 0000000000..9ef9741308
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/environment.rb
@@ -0,0 +1,38 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/data_handler/environment_data_handler"
+require "chef/chef_fs/file_system/repository/base_file"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ class Environment < BaseFile
+
+ def initialize(name, parent)
+ @data_handler = Chef::ChefFS::DataHandler::EnvironmentDataHandler.new
+ super
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/environments_dir.rb b/lib/chef/chef_fs/file_system/repository/environments_dir.rb
new file mode 100644
index 0000000000..4d04348d6e
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/environments_dir.rb
@@ -0,0 +1,37 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/environment"
+require "chef/chef_fs/data_handler/environment_data_handler"
+require "chef/chef_fs/file_system/repository/directory"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class EnvironmentsDir < Repository::Directory
+
+ def make_child_entry(child_name)
+ Environment.new(child_name, self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/file_system_entry.rb b/lib/chef/chef_fs/file_system/repository/file_system_entry.rb
new file mode 100644
index 0000000000..45ae002521
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/file_system_entry.rb
@@ -0,0 +1,151 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/chef_fs/path_utils"
+require "fileutils"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class FileSystemEntry < BaseFSDir
+ def initialize(name, parent, file_path = nil, data_handler = nil)
+ super(name, parent)
+ @file_path = file_path || "#{parent.file_path}/#{name}"
+ @data_handler = data_handler
+ end
+
+ attr_reader :file_path
+
+ def write_pretty_json=(value)
+ @write_pretty_json = value
+ end
+
+ def write_pretty_json
+ @write_pretty_json.nil? ? root.write_pretty_json : @write_pretty_json
+ end
+
+ def data_handler
+ @data_handler || parent.data_handler
+ end
+
+ def path_for_printing
+ file_path
+ end
+
+ def chef_object
+ data_handler.chef_object(Chef::JSONCompat.parse(read))
+ rescue
+ Chef::Log.error("Could not read #{path_for_printing} into a Chef object: #{$!}")
+ nil
+ end
+
+ def can_have_child?(name, is_dir)
+ !is_dir && File.extname(name) == ".json"
+ end
+
+ def name_valid?
+ !name.start_with?(".")
+ end
+
+ # basic implementation to support Repository::Directory API
+ def fs_entry_valid?
+ name_valid? && File.exist?(file_path)
+ end
+
+ def minimize(file_contents, entry)
+ object = Chef::JSONCompat.parse(file_contents)
+ object = data_handler.normalize(object, entry)
+ object = data_handler.minimize(object, entry)
+ Chef::JSONCompat.to_json_pretty(object)
+ end
+
+ def children
+ # Except cookbooks and data bag dirs, all things must be json files
+ Dir.entries(file_path).sort.
+ map { |child_name| make_child_entry(child_name) }.
+ select { |new_child| new_child.fs_entry_valid? && can_have_child?(new_child.name, new_child.dir?) }
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+
+ def create_child(child_name, file_contents = nil)
+ child = make_child_entry(child_name)
+ if child.exists?
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
+ end
+ if file_contents
+ child.write(file_contents)
+ else
+ Dir.mkdir(child.file_path)
+ end
+ child
+ rescue Errno::EEXIST
+ raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
+ end
+
+ def dir?
+ File.directory?(file_path)
+ end
+
+ def delete(recurse)
+ if dir?
+ if !recurse
+ raise MustDeleteRecursivelyError.new(self, $!)
+ end
+ FileUtils.rm_r(file_path)
+ else
+ File.delete(file_path)
+ end
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+
+ def exists?
+ File.exists?(file_path) && (parent.nil? || parent.can_have_child?(name, dir?))
+ end
+
+ def read
+ File.open(file_path, "rb") { |f| f.read }
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
+
+ def write(file_contents)
+ if file_contents && write_pretty_json && File.extname(name) == ".json"
+ file_contents = minimize(file_contents, self)
+ end
+ File.open(file_path, "wb") do |file|
+ file.write(file_contents)
+ end
+ end
+ alias :create :write
+
+ protected
+
+ def make_child_entry(child_name)
+ FileSystemEntry.new(child_name, self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/group.rb b/lib/chef/chef_fs/file_system/repository/group.rb
new file mode 100644
index 0000000000..302e72739b
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/group.rb
@@ -0,0 +1,38 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/data_handler/group_data_handler"
+require "chef/chef_fs/file_system/repository/base_file"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ class Group < BaseFile
+
+ def initialize(name, parent)
+ @data_handler = Chef::ChefFS::DataHandler::GroupDataHandler.new
+ super
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/groups_dir.rb b/lib/chef/chef_fs/file_system/repository/groups_dir.rb
new file mode 100644
index 0000000000..20728d1248
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/groups_dir.rb
@@ -0,0 +1,37 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/group"
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/exceptions"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class GroupsDir < Repository::Directory
+
+ def make_child_entry(child_name)
+ Group.new(child_name, self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/already_exists_error.rb b/lib/chef/chef_fs/file_system/repository/node.rb
index bf8994fdf3..d8f0dec7c4 100644
--- a/lib/chef/chef_fs/file_system/already_exists_error.rb
+++ b/lib/chef/chef_fs/file_system/repository/node.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,21 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/operation_failed_error'
+require "chef/chef_fs/data_handler/node_data_handler"
+require "chef/chef_fs/file_system/repository/base_file"
class Chef
module ChefFS
module FileSystem
- class AlreadyExistsError < OperationFailedError
- def initialize(operation, entry, cause = nil)
- super(operation, entry, cause)
+ module Repository
+
+ class Node < BaseFile
+
+ def initialize(name, parent)
+ @data_handler = Chef::ChefFS::DataHandler::NodeDataHandler.new
+ super
+ end
+
end
end
end
diff --git a/lib/chef/chef_fs/file_system/repository/nodes_dir.rb b/lib/chef/chef_fs/file_system/repository/nodes_dir.rb
new file mode 100644
index 0000000000..a0dd0c9e51
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/nodes_dir.rb
@@ -0,0 +1,59 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/node"
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/win32/security" if Chef::Platform.windows?
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class NodesDir < Repository::Directory
+
+ def make_child_entry(child_name)
+ Node.new(child_name, self)
+ end
+
+ def create_child(child_name, file_contents = nil)
+ child = super
+ File.chmod(0600, child.file_path)
+ if Chef::Platform.windows?
+ read_mask = Chef::ReservedNames::Win32::API::Security::GENERIC_READ
+ write_mask = Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE
+ administrators = Chef::ReservedNames::Win32::Security::SID.Administrators
+ owner = Chef::ReservedNames::Win32::Security::SID.default_security_object_owner
+ dacl = Chef::ReservedNames::Win32::Security::ACL.create([
+ Chef::ReservedNames::Win32::Security::ACE.access_allowed(owner, read_mask),
+ Chef::ReservedNames::Win32::Security::ACE.access_allowed(owner, write_mask),
+ Chef::ReservedNames::Win32::Security::ACE.access_allowed(administrators, read_mask),
+ Chef::ReservedNames::Win32::Security::ACE.access_allowed(administrators, write_mask),
+ ])
+ so = Chef::ReservedNames::Win32::Security::SecurableObject.new(child.file_path)
+ so.owner = owner
+ so.set_dacl(dacl, false)
+ end
+ child
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_policies_dir.rb b/lib/chef/chef_fs/file_system/repository/policies_dir.rb
index 42768f10b7..c74ea5469b 100644
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_policies_dir.rb
+++ b/lib/chef/chef_fs/file_system/repository/policies_dir.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,23 +16,27 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
-require 'chef/chef_fs/data_handler/policy_data_handler'
+require "chef/chef_fs/file_system/repository/policy"
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/data_handler/policy_data_handler"
class Chef
module ChefFS
module FileSystem
+ module Repository
+ class PoliciesDir < Repository::Directory
- class ChefRepositoryFileSystemPoliciesDir < ChefRepositoryFileSystemEntry
- def initialize(name, parent, path = nil)
- super(name, parent, path, Chef::ChefFS::DataHandler::PolicyDataHandler.new)
- end
+ def can_have_child?(name, is_dir)
+ !is_dir && name.include?("-")
+ end
+
+ protected
- def can_have_child?(name, is_dir)
- is_dir && !name.start_with?('.')
+ def make_child_entry(child_name)
+ Policy.new(child_name, self)
+ end
end
end
end
end
end
-
diff --git a/lib/chef/chef_fs/file_system/repository/policy.rb b/lib/chef/chef_fs/file_system/repository/policy.rb
new file mode 100644
index 0000000000..695bf17e83
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/policy.rb
@@ -0,0 +1,38 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/data_handler/policy_data_handler"
+require "chef/chef_fs/file_system/repository/base_file"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ class Policy < BaseFile
+
+ def initialize(name, parent)
+ @data_handler = Chef::ChefFS::DataHandler::PolicyDataHandler.new
+ super
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/policy_group.rb b/lib/chef/chef_fs/file_system/repository/policy_group.rb
new file mode 100644
index 0000000000..e4182847b6
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/policy_group.rb
@@ -0,0 +1,38 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/data_handler/policy_group_data_handler"
+require "chef/chef_fs/file_system/repository/base_file"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ class PolicyGroup < BaseFile
+
+ def initialize(name, parent)
+ @data_handler = Chef::ChefFS::DataHandler::PolicyGroupDataHandler.new
+ super
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/policy_groups_dir.rb b/lib/chef/chef_fs/file_system/repository/policy_groups_dir.rb
new file mode 100644
index 0000000000..4db85a93f7
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/policy_groups_dir.rb
@@ -0,0 +1,37 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/policy_group"
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/exceptions"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class PolicyGroupsDir < Repository::Directory
+
+ def make_child_entry(child_name)
+ PolicyGroup.new(child_name, self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/cookbook_frozen_error.rb b/lib/chef/chef_fs/file_system/repository/role.rb
index 705673384d..d97ae0e7a1 100644
--- a/lib/chef/chef_fs/file_system/cookbook_frozen_error.rb
+++ b/lib/chef/chef_fs/file_system/repository/role.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,21 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/already_exists_error'
+require "chef/chef_fs/data_handler/role_data_handler"
+require "chef/chef_fs/file_system/repository/base_file"
class Chef
module ChefFS
module FileSystem
- class CookbookFrozenError < AlreadyExistsError
- def initialize(operation, entry, cause = nil)
- super(operation, entry, cause)
+ module Repository
+
+ class Role < BaseFile
+
+ def initialize(name, parent)
+ @data_handler = Chef::ChefFS::DataHandler::RoleDataHandler.new
+ super
+ end
+
end
end
end
diff --git a/lib/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb b/lib/chef/chef_fs/file_system/repository/roles_dir.rb
index 8ca3b917ca..42f4376e71 100644
--- a/lib/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb
+++ b/lib/chef/chef_fs/file_system/repository/roles_dir.rb
@@ -1,6 +1,7 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +17,19 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/operation_not_allowed_error'
+require "chef/chef_fs/file_system/repository/role"
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/exceptions"
class Chef
module ChefFS
module FileSystem
- class DefaultEnvironmentCannotBeModifiedError < OperationNotAllowedError
- def initialize(operation, entry, cause = nil)
- super(operation, entry, cause)
- end
+ module Repository
+ class RolesDir < Repository::Directory
- def reason
- result = super
- result + " (default environment cannot be modified)"
+ def make_child_entry(child_name)
+ Role.new(child_name, self)
+ end
end
end
end
diff --git a/lib/chef/chef_fs/file_system/repository/user.rb b/lib/chef/chef_fs/file_system/repository/user.rb
new file mode 100644
index 0000000000..59355cc303
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/user.rb
@@ -0,0 +1,38 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/data_handler/user_data_handler"
+require "chef/chef_fs/file_system/repository/base_file"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+
+ class User < BaseFile
+
+ def initialize(name, parent)
+ @data_handler = Chef::ChefFS::DataHandler::UserDataHandler.new
+ super
+ end
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/users_dir.rb b/lib/chef/chef_fs/file_system/repository/users_dir.rb
new file mode 100644
index 0000000000..9e8621575b
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/users_dir.rb
@@ -0,0 +1,37 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/user"
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/exceptions"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class UsersDir < Repository::Directory
+
+ def make_child_entry(child_name)
+ User.new(child_name, self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/versioned_cookbooks_dir.rb b/lib/chef/chef_fs/file_system/repository/versioned_cookbooks_dir.rb
new file mode 100644
index 0000000000..80f77d02be
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/versioned_cookbooks_dir.rb
@@ -0,0 +1,34 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/cookbooks_dir"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbook_dir"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class VersionedCookbooksDir < CookbooksDir
+ def make_child_entry(child_name)
+ ChefRepositoryFileSystemVersionedCookbookDir.new(child_name, self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/rest_list_dir.rb b/lib/chef/chef_fs/file_system/rest_list_dir.rb
deleted file mode 100644
index 0ac735a2c4..0000000000
--- a/lib/chef/chef_fs/file_system/rest_list_dir.rb
+++ /dev/null
@@ -1,110 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/file_system/not_found_error'
-
-class Chef
- module ChefFS
- module FileSystem
- class RestListDir < BaseFSDir
- def initialize(name, parent, api_path = nil, data_handler = nil)
- super(name, parent)
- @api_path = api_path || (parent.api_path == "" ? name : "#{parent.api_path}/#{name}")
- @data_handler = data_handler
- end
-
- attr_reader :api_path
- attr_reader :data_handler
-
- def can_have_child?(name, is_dir)
- name =~ /\.json$/ && !is_dir
- end
-
- def children
- begin
- @children ||= root.get_json(api_path).keys.sort.map do |key|
- make_child_entry("#{key}.json", true)
- end
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "Timeout retrieving children: #{e}"
- rescue Net::HTTPServerException => e
- if $!.response.code == "404"
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "HTTP error retrieving children: #{e}"
- end
- end
- end
-
- def create_child(name, file_contents)
- begin
- object = Chef::JSONCompat.parse(file_contents)
- rescue Chef::Exceptions::JSON::ParseError => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Parse error reading JSON creating child '#{name}': #{e}"
- end
-
- result = make_child_entry(name, true)
-
- if data_handler
- object = data_handler.normalize_for_post(object, result)
- data_handler.verify_integrity(object, result) do |error|
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self), "Error creating '#{name}': #{error}"
- end
- end
-
- begin
- rest.post(api_path, object)
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Timeout creating '#{name}': #{e}"
- rescue Net::HTTPServerException => e
- if e.response.code == "404"
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
- elsif $!.response.code == "409"
- raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e), "Failure creating '#{name}': #{path}/#{name} already exists"
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Failure creating '#{name}': #{e.message}"
- end
- end
-
- @children = nil
-
- result
- end
-
- def org
- parent.org
- end
-
- def environment
- parent.environment
- end
-
- def rest
- parent.rest
- end
-
- def make_child_entry(name, exists = nil)
- @children.select { |child| child.name == name }.first if @children
- RestListEntry.new(name, self, exists)
- end
- end
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system/rest_list_entry.rb b/lib/chef/chef_fs/file_system/rest_list_entry.rb
deleted file mode 100644
index f68794cb0d..0000000000
--- a/lib/chef/chef_fs/file_system/rest_list_entry.rb
+++ /dev/null
@@ -1,185 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_object'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/file_system/operation_failed_error'
-require 'chef/role'
-require 'chef/node'
-require 'chef/json_compat'
-
-class Chef
- module ChefFS
- module FileSystem
- class RestListEntry < BaseFSObject
- def initialize(name, parent, exists = nil)
- super(name, parent)
- @exists = exists
- end
-
- def data_handler
- parent.data_handler
- end
-
- def api_child_name
- if name.length < 5 || name[-5,5] != ".json"
- raise "Invalid name #{path}: must end in .json"
- end
- name[0,name.length-5]
- end
-
- def api_path
- "#{parent.api_path}/#{api_child_name}"
- end
-
- def org
- parent.org
- end
-
- def environment
- parent.environment
- end
-
- def exists?
- if @exists.nil?
- begin
- @exists = parent.children.any? { |child| child.name == name }
- rescue Chef::ChefFS::FileSystem::NotFoundError
- @exists = false
- end
- end
- @exists
- end
-
- def delete(recurse)
- begin
- rest.delete(api_path)
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
- rescue Net::HTTPServerException => e
- if e.response.code == "404"
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
- end
- end
- end
-
- def read
- Chef::JSONCompat.to_json_pretty(minimize_value(_read_json))
- end
-
- def _read_json
- begin
- # Minimize the value (get rid of defaults) so the results don't look terrible
- root.get_json(api_path)
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading: #{e}"
- rescue Net::HTTPServerException => e
- if $!.response.code == "404"
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}"
- end
- end
- end
-
- def chef_object
- # REST will inflate the Chef object using json_class
- data_handler.json_class.json_create(read)
- end
-
- def minimize_value(value)
- data_handler.minimize(data_handler.normalize(value, self), self)
- end
-
- def compare_to(other)
- # TODO this pair of reads can be parallelized
-
- # Grab the other value
- begin
- other_value_json = other.read
- rescue Chef::ChefFS::FileSystem::NotFoundError
- return [ nil, nil, :none ]
- end
-
- # Grab this value
- begin
- value = _read_json
- rescue Chef::ChefFS::FileSystem::NotFoundError
- return [ false, :none, other_value_json ]
- end
-
- # Minimize (and normalize) both values for easy and beautiful diffs
- value = minimize_value(value)
- value_json = Chef::JSONCompat.to_json_pretty(value)
- begin
- other_value = Chef::JSONCompat.parse(other_value_json)
- rescue Chef::Exceptions::JSON::ParseError => e
- Chef::Log.warn("Parse error reading #{other.path_for_printing} as JSON: #{e}")
- return [ nil, value_json, other_value_json ]
- end
- other_value = minimize_value(other_value)
- other_value_json = Chef::JSONCompat.to_json_pretty(other_value)
-
- [ value == other_value, value_json, other_value_json ]
- end
-
- def rest
- parent.rest
- end
-
- def write(file_contents)
- begin
- object = Chef::JSONCompat.parse(file_contents)
- rescue Chef::Exceptions::JSON::ParseError => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Parse error reading JSON: #{e}"
- end
-
- if data_handler
- object = data_handler.normalize_for_put(object, self)
- data_handler.verify_integrity(object, self) do |error|
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self), "#{error}"
- end
- end
-
- begin
- rest.put(api_path, object)
- rescue Timeout::Error => e
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}"
- rescue Net::HTTPServerException => e
- if e.response.code == "404"
- raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
- else
- raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "HTTP error writing: #{e}"
- end
- end
- end
-
- def api_error_text(response)
- begin
- Chef::JSONCompat.parse(response.body)['error'].join("\n")
- rescue
- response.body
- end
- end
- end
-
- end
- end
-end
diff --git a/lib/chef/chef_fs/file_system_cache.rb b/lib/chef/chef_fs/file_system_cache.rb
new file mode 100644
index 0000000000..a9d8d8bfe4
--- /dev/null
+++ b/lib/chef/chef_fs/file_system_cache.rb
@@ -0,0 +1,80 @@
+#
+# Copyright:: Copyright 2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "singleton"
+require "chef/client"
+
+class Chef
+ module ChefFS
+ class FileSystemCache
+ include Singleton
+
+ def initialize
+ @cache = {}
+
+ Chef::Client.when_run_starts do
+ FileSystemCache.instance.reset!
+ end
+ end
+
+ def reset!
+ @cache = {}
+ end
+
+ def exist?(path)
+ @cache.key?(path)
+ end
+
+ def children(path)
+ @cache[path]["children"]
+ end
+
+ def set_children(path, val)
+ @cache[path] ||= { "children" => [] }
+ @cache[path]["children"] = val
+ val
+ end
+
+ def delete!(path)
+ parent = _get_parent(path)
+ Chef::Log.debug("Deleting parent #{parent} and #{path} from FileSystemCache")
+ if @cache.key?(path)
+ @cache.delete(path)
+ end
+ if !parent.nil? && @cache.key?(parent)
+ @cache.delete(parent)
+ end
+ end
+
+ def fetch(path)
+ if @cache.key?(path)
+ @cache[path]
+ else
+ false
+ end
+ end
+
+ private
+
+ def _get_parent(path)
+ parts = ChefFS::PathUtils.split(path)
+ return nil if parts.nil? || parts.length < 2
+ ChefFS::PathUtils.join(*parts[0..-2])
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/knife.rb b/lib/chef/chef_fs/knife.rb
index 9101e455f8..1731e19ce1 100644
--- a/lib/chef/chef_fs/knife.rb
+++ b/lib/chef/chef_fs/knife.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'pathname'
+require "chef/knife"
+require "pathname"
class Chef
module ChefFS
@@ -25,11 +25,11 @@ class Chef
# Workaround for CHEF-3932
def self.deps
super do
- require 'chef/config'
- require 'chef/chef_fs/parallelizer'
- require 'chef/chef_fs/config'
- require 'chef/chef_fs/file_pattern'
- require 'chef/chef_fs/path_utils'
+ require "chef/config"
+ require "chef/chef_fs/parallelizer"
+ require "chef/chef_fs/config"
+ require "chef/chef_fs/file_pattern"
+ require "chef/chef_fs/path_utils"
yield
end
end
@@ -45,16 +45,16 @@ class Chef
end
option :repo_mode,
- :long => '--repo-mode MODE',
+ :long => "--repo-mode MODE",
:description => "Specifies the local repository layout. Values: static, everything, hosted_everything. Default: everything/hosted_everything"
option :chef_repo_path,
- :long => '--chef-repo-path PATH',
- :description => 'Overrides the location of chef repo. Default is specified by chef_repo_path in the config'
+ :long => "--chef-repo-path PATH",
+ :description => "Overrides the location of chef repo. Default is specified by chef_repo_path in the config"
option :concurrency,
- :long => '--concurrency THREADS',
- :description => 'Maximum number of simultaneous requests to send (default: 10)'
+ :long => "--concurrency THREADS",
+ :description => "Maximum number of simultaneous requests to send (default: 10)"
def configure_chef
super
@@ -111,7 +111,7 @@ class Chef
end
# Use the original path because we can't be sure.
inferred_path = arg
- elsif arg[0,1] == '~'
+ elsif arg[0, 1] == "~"
# Let's be nice and fix it if possible - but warn the user.
ui.warn("A path relative to a user home directory has been provided: #{arg}")
ui.warn("Paths provided need to be rooted at the chef-repo being considered or be relative paths.")
@@ -131,7 +131,7 @@ class Chef
ui.error("Current working directory is '#{@chef_fs_config.cwd}'.")
exit(1)
else
- inferred_path = Chef::ChefFS::PathUtils::join(@chef_fs_config.base_path, arg)
+ inferred_path = Chef::ChefFS::PathUtils.join(@chef_fs_config.base_path, arg)
end
Chef::ChefFS::FilePattern.new(inferred_path)
end
@@ -145,7 +145,7 @@ class Chef
end
def discover_repo_dir(dir)
- %w(.chef cookbooks data_bags environments roles).each do |subdir|
+ %w{.chef cookbooks data_bags environments roles}.each do |subdir|
return dir if File.directory?(File.join(dir, subdir))
end
# If this isn't it, check the parent
diff --git a/lib/chef/chef_fs/parallelizer.rb b/lib/chef/chef_fs/parallelizer.rb
index 116a626869..32de61e048 100644
--- a/lib/chef/chef_fs/parallelizer.rb
+++ b/lib/chef/chef_fs/parallelizer.rb
@@ -1,5 +1,5 @@
-require 'thread'
-require 'chef/chef_fs/parallelizer/parallel_enumerable'
+require "thread"
+require "chef/chef_fs/parallelizer/parallel_enumerable"
class Chef
module ChefFS
@@ -54,7 +54,7 @@ class Chef
def resize(to_threads, wait = true, timeout = nil)
if to_threads < num_threads
- threads_to_stop = @threads[to_threads..num_threads-1]
+ threads_to_stop = @threads[to_threads..num_threads - 1]
@threads = @threads.slice(0, to_threads)
threads_to_stop.each do |thread|
@stop_thread[thread] = true
@@ -86,19 +86,17 @@ class Chef
private
def worker_loop
- begin
- while !@stop_thread[Thread.current]
- begin
- task = @tasks.pop
- task.call
- rescue
- puts "ERROR #{$!}"
- puts $!.backtrace
- end
+ until @stop_thread[Thread.current]
+ begin
+ task = @tasks.pop
+ task.call
+ rescue
+ puts "ERROR #{$!}"
+ puts $!.backtrace
end
- ensure
- @stop_thread.delete(Thread.current)
end
+ ensure
+ @stop_thread.delete(Thread.current)
end
end
end
diff --git a/lib/chef/chef_fs/parallelizer/flatten_enumerable.rb b/lib/chef/chef_fs/parallelizer/flatten_enumerable.rb
index 7321aa0664..84db2c2053 100644
--- a/lib/chef/chef_fs/parallelizer/flatten_enumerable.rb
+++ b/lib/chef/chef_fs/parallelizer/flatten_enumerable.rb
@@ -23,10 +23,10 @@ class Chef
def flatten(value, levels, &block)
if levels != 0 && value.respond_to?(:each) && !value.is_a?(String)
value.each do |child|
- flatten(child, levels.nil? ? levels : levels-1, &block)
+ flatten(child, levels.nil? ? levels : levels - 1, &block)
end
else
- block.call(value)
+ yield(value)
end
end
end
diff --git a/lib/chef/chef_fs/parallelizer/parallel_enumerable.rb b/lib/chef/chef_fs/parallelizer/parallel_enumerable.rb
index 8845b6926a..ab578bdb7f 100644
--- a/lib/chef/chef_fs/parallelizer/parallel_enumerable.rb
+++ b/lib/chef/chef_fs/parallelizer/parallel_enumerable.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/parallelizer/flatten_enumerable'
+require "chef/chef_fs/parallelizer/flatten_enumerable"
class Chef
module ChefFS
@@ -92,7 +92,7 @@ class Chef
end
end
- def first(n=nil)
+ def first(n = nil)
if n
restricted_copy(@input_enumerable.first(n)).to_a
else
@@ -157,7 +157,7 @@ class Chef
@parent_task_queue.push(method(:process_one))
stop_processing_input = false
- while !@unconsumed_output.empty?
+ until @unconsumed_output.empty?
output, index, input, type = @unconsumed_output.pop
yield output, index, input, type
if type == :exception && @options[:stop_on_exception]
@@ -178,15 +178,13 @@ class Chef
end
end
- while !finished?
+ until finished?
# yield thread to others (for 1.8.7)
if @unconsumed_output.empty?
sleep(0.01)
end
- while !@unconsumed_output.empty?
- yield @unconsumed_output.pop
- end
+ yield @unconsumed_output.pop until @unconsumed_output.empty?
# If no one is working on our tasks and we're allowed to
# work on them in the main thread, process an input to
@@ -227,9 +225,7 @@ class Chef
def stop
@unconsumed_input.clear
- while @in_process.size > 0
- sleep(0.05)
- end
+ sleep(0.05) while @in_process.size > 0
@unconsumed_output.clear
end
@@ -266,7 +262,7 @@ class Chef
begin
output = @block.call(input)
@unconsumed_output.push([ output, index, input, :result ])
- rescue
+ rescue StandardError, ScriptError
if @options[:stop_on_exception]
@unconsumed_input.clear
end
diff --git a/lib/chef/chef_fs/path_utils.rb b/lib/chef/chef_fs/path_utils.rb
index 595f966378..7b2de5e3e0 100644
--- a/lib/chef/chef_fs/path_utils.rb
+++ b/lib/chef/chef_fs/path_utils.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/chef_fs'
-require 'pathname'
+require "chef/chef_fs"
+require "pathname"
class Chef
module ChefFS
@@ -45,9 +45,9 @@ class Chef
# Determine if it started with a slash
absolute = parts[0].length == 0 || parts[0].length > 0 && parts[0] =~ /^#{regexp_path_separator}/
# Remove leading and trailing slashes from each part so that the join will work (and the slash at the end will go away)
- parts = parts.map { |part| part.gsub(/^#{regexp_path_separator}+|#{regexp_path_separator}+$/, '') }
+ parts = parts.map { |part| part.gsub(/^#{regexp_path_separator}+|#{regexp_path_separator}+$/, "") }
# Don't join empty bits
- result = parts.select { |part| part != '' }.join('/')
+ result = parts.select { |part| part != "" }.join("/")
# Put the / back on
absolute ? "/#{result}" : result
end
@@ -57,13 +57,14 @@ class Chef
end
def self.regexp_path_separator
- Chef::ChefFS::windows? ? '[\/\\\\]' : '/'
+ Chef::ChefFS.windows? ? '[\/\\\\]' : "/"
end
# Given a server path, determines if it is absolute.
def self.is_absolute?(path)
!!(path =~ /^#{regexp_path_separator}/)
end
+
# Given a path which may only be partly real (i.e. /x/y/z when only /x exists,
# or /x/y/*/blah when /x/y/z/blah exists), call File.realpath on the biggest
# part that actually exists. The paths operated on here are not Chef-FS paths.
@@ -82,7 +83,7 @@ class Chef
# File.dirname happens to return the path as its own dirname if you're
# at the root (such as at \\foo\bar, C:\ or /)
- until parent_path == path do
+ until parent_path == path
# This can occur if a path such as "C:" is given. Ruby gives the parent as "C:."
# for reasons only it knows.
raise ArgumentError "Invalid path segment #{path}" if parent_path.length > path.length
@@ -100,7 +101,7 @@ class Chef
# Compares two path fragments according to the case-sentitivity of the host platform.
def self.os_path_eq?(left, right)
- Chef::ChefFS::windows? ? left.casecmp(right) == 0 : left == right
+ Chef::ChefFS.windows? ? left.casecmp(right) == 0 : left == right
end
# Given two general OS-dependent file paths, determines the relative path of the
@@ -113,9 +114,9 @@ class Chef
candidate_fragment = path[0, ancestor.length]
return nil unless PathUtils.os_path_eq?(candidate_fragment, ancestor)
if ancestor.length == path.length
- ''
- elsif path[ancestor.length,1] =~ /#{PathUtils.regexp_path_separator}/
- path[ancestor.length+1..-1]
+ ""
+ elsif path[ancestor.length, 1] =~ /#{PathUtils.regexp_path_separator}/
+ path[ancestor.length + 1..-1]
else
nil
end
diff --git a/lib/chef/client.rb b/lib/chef/client.rb
index b2a00a7d01..c064d33209 100644
--- a/lib/chef/client.rb
+++ b/lib/chef/client.rb
@@ -1,9 +1,9 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,41 +18,43 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/path_sanity'
-require 'chef/log'
-require 'chef/rest'
-require 'chef/api_client'
-require 'chef/api_client/registration'
-require 'chef/audit/runner'
-require 'chef/node'
-require 'chef/role'
-require 'chef/file_cache'
-require 'chef/run_context'
-require 'chef/runner'
-require 'chef/run_status'
-require 'chef/cookbook/cookbook_collection'
-require 'chef/cookbook/file_vendor'
-require 'chef/cookbook/file_system_file_vendor'
-require 'chef/cookbook/remote_file_vendor'
-require 'chef/event_dispatch/dispatcher'
-require 'chef/event_loggers/base'
-require 'chef/event_loggers/windows_eventlog'
-require 'chef/exceptions'
-require 'chef/formatters/base'
-require 'chef/formatters/doc'
-require 'chef/formatters/minimal'
-require 'chef/version'
-require 'chef/resource_reporter'
-require 'chef/audit/audit_reporter'
-require 'chef/run_lock'
-require 'chef/policy_builder'
-require 'chef/request_id'
-require 'chef/platform/rebooter'
-require 'chef/mixin/deprecation'
-require 'ohai'
-require 'rbconfig'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/path_sanity"
+require "chef/log"
+require "chef/deprecated"
+require "chef/server_api"
+require "chef/api_client"
+require "chef/api_client/registration"
+require "chef/audit/runner"
+require "chef/node"
+require "chef/role"
+require "chef/file_cache"
+require "chef/run_context"
+require "chef/runner"
+require "chef/run_status"
+require "chef/cookbook/cookbook_collection"
+require "chef/cookbook/file_vendor"
+require "chef/cookbook/file_system_file_vendor"
+require "chef/cookbook/remote_file_vendor"
+require "chef/event_dispatch/dispatcher"
+require "chef/event_loggers/base"
+require "chef/event_loggers/windows_eventlog"
+require "chef/exceptions"
+require "chef/formatters/base"
+require "chef/formatters/doc"
+require "chef/formatters/minimal"
+require "chef/version"
+require "chef/resource_reporter"
+require "chef/data_collector"
+require "chef/audit/audit_reporter"
+require "chef/run_lock"
+require "chef/policy_builder"
+require "chef/request_id"
+require "chef/platform/rebooter"
+require "chef/mixin/deprecation"
+require "ohai"
+require "rbconfig"
class Chef
# == Chef::Client
@@ -78,6 +80,7 @@ class Chef
def node
run_status.node
end
+
def node=(value)
run_status.node = value
end
@@ -92,11 +95,19 @@ class Chef
#
# The rest object used to communicate with the Chef server.
#
- # @return [Chef::REST]
+ # @return [Chef::ServerAPI]
#
attr_reader :rest
#
+ # A rest object with validate_utf8 set to false. This will not throw exceptions
+ # on non-UTF8 strings in JSON but will sanitize them so that e.g. POSTs will
+ # never fail. Cannot be configured on a request-by-request basis, so we carry
+ # around another rest object for it.
+ #
+ attr_reader :rest_clean
+
+ #
# The runner used to converge.
#
# @return [Chef::Runner]
@@ -143,7 +154,7 @@ class Chef
# @option args [Array<String>] :specific_recipes A list of recipe file paths
# to load after the run list has been loaded.
#
- def initialize(json_attribs=nil, args={})
+ def initialize(json_attribs = nil, args = {})
@json_attribs = json_attribs || {}
@ohai = Ohai::System.new
@@ -247,12 +258,14 @@ class Chef
run_context = nil
events.run_start(Chef::VERSION)
Chef::Log.info("*** Chef #{Chef::VERSION} ***")
+ Chef::Log.info("Platform: #{RUBY_PLATFORM}")
Chef::Log.info "Chef-client pid: #{Process.pid}"
Chef::Log.debug("Chef-client request_id: #{request_id}")
enforce_path_sanity
run_ohai
- register unless Chef::Config[:solo]
+ register unless Chef::Config[:solo_legacy_mode]
+ register_data_collector_reporter
load_node
@@ -303,9 +316,7 @@ class Chef
events.run_failed(run_error)
ensure
Chef::RequestID.instance.reset_request_id
- request_id = nil
@run_status = nil
- run_context = nil
runlock.release
end
@@ -317,10 +328,10 @@ class Chef
run_error || converge_error
else
e = if run_error == converge_error
- Chef::Exceptions::RunFailedWrappingError.new(converge_error, audit_error)
- else
- Chef::Exceptions::RunFailedWrappingError.new(run_error, converge_error, audit_error)
- end
+ Chef::Exceptions::RunFailedWrappingError.new(converge_error, audit_error)
+ else
+ Chef::Exceptions::RunFailedWrappingError.new(run_error, converge_error, audit_error)
+ end
e.fill_backtrace
e
end
@@ -385,13 +396,23 @@ class Chef
end
end
+ # Rest client for use by API reporters. This rest client will not fail with an exception if
+ # it is fed non-UTF8 data.
+ #
+ # @api private
+ def rest_clean(client_name = node_name, config = Chef::Config)
+ @rest_clean ||=
+ Chef::ServerAPI.new(config[:chef_server_url], client_name: client_name,
+ signing_key_filename: config[:client_key], validate_utf8: false)
+ end
+
# Resource reporters send event information back to the chef server for
# processing. Can only be called after we have a @rest object
# @api private
def register_reporters
[
- Chef::ResourceReporter.new(rest),
- Chef::Audit::AuditReporter.new(rest)
+ Chef::ResourceReporter.new(rest_clean),
+ Chef::Audit::AuditReporter.new(rest_clean),
].each do |r|
events.register(r)
end
@@ -515,7 +536,7 @@ class Chef
# @api private
#
def save_updated_node
- if Chef::Config[:solo]
+ if Chef::Config[:solo_legacy_mode]
# nothing to do
elsif policy_builder.temporary_policy?
Chef::Log.warn("Skipping final node save because override_runlist was given")
@@ -536,7 +557,7 @@ class Chef
# @api private
#
def run_ohai
- filter = Chef::Config[:minimal_ohai] ? %w[fqdn machinename hostname platform platform_version os os_version] : nil
+ filter = Chef::Config[:minimal_ohai] ? %w{fqdn machinename hostname platform platform_version os os_version} : nil
ohai.all_plugins(filter)
events.ohai_completed(node)
end
@@ -550,14 +571,10 @@ class Chef
# - ohai[:machinename]
# - ohai[:hostname]
#
- # If we are running against a server with authentication protocol < 1.0, we
- # *require* authentication protocol version 1.1.
- #
# @raise [Chef::Exceptions::CannotDetermineNodeName] If the node name is not
# set and cannot be determined via ohai.
#
# @see Chef::Config#node_name
- # @see Chef::Config#authentication_protocol_version
#
# @api private
#
@@ -567,14 +584,6 @@ class Chef
raise Chef::Exceptions::CannotDetermineNodeName unless name
- # node names > 90 bytes only work with authentication protocol >= 1.1
- # see discussion in config.rb.
- # TODO use a computed default in Chef::Config to determine this instead of
- # setting it.
- if name.bytesize > 90
- Chef::Config[:authentication_protocol_version] = "1.1"
- end
-
name
end
@@ -587,7 +596,7 @@ class Chef
# If Chef::Config.client_key does not exist, we register the client with the
# Chef server and fire the registration_start and registration_completed events.
#
- # @return [Chef::REST] The server connection object.
+ # @return [Chef::ServerAPI] The server connection object.
#
# @see Chef::Config#chef_server_url
# @see Chef::Config#client_key
@@ -599,7 +608,7 @@ class Chef
#
# @api private
#
- def register(client_name=node_name, config=Chef::Config)
+ def register(client_name = node_name, config = Chef::Config)
if !config[:client_key]
events.skipping_registration(client_name, config)
Chef::Log.debug("Client key is unspecified - skipping registration")
@@ -613,7 +622,10 @@ class Chef
events.registration_completed
end
# We now have the client key, and should use it from now on.
- @rest = Chef::REST.new(config[:chef_server_url], client_name, config[:client_key])
+ @rest = Chef::ServerAPI.new(config[:chef_server_url], client_name: client_name,
+ signing_key_filename: config[:client_key])
+ # force initialization of the rest_clean API object
+ rest_clean(client_name, config)
register_reporters
rescue Exception => e
# TODO this should probably only ever fire if we *started* registration.
@@ -897,7 +909,7 @@ class Chef
attr_reader :specific_recipes
def profiling_prereqs!
- require 'ruby-prof'
+ require "ruby-prof"
rescue LoadError
raise "You must have the ruby-prof gem installed in order to use --profile-ruby"
end
@@ -927,13 +939,13 @@ class Chef
end
def assert_cookbook_path_not_empty(run_context)
- if Chef::Config[:solo]
+ if Chef::Config[:solo_legacy_mode]
# Check for cookbooks in the path given
# Chef::Config[:cookbook_path] can be a string or an array
# if it's an array, go through it and check each one, raise error at the last one if no files are found
cookbook_paths = Array(Chef::Config[:cookbook_path])
Chef::Log.debug "Loading from cookbook_path: #{cookbook_paths.map { |path| File.expand_path(path) }.join(', ')}"
- if cookbook_paths.all? {|path| empty_directory?(path) }
+ if cookbook_paths.all? { |path| empty_directory?(path) }
msg = "None of the cookbook paths set in Chef::Config[:cookbook_path], #{cookbook_paths.inspect}, contain any cookbooks"
Chef::Log.fatal(msg)
raise Chef::Exceptions::CookbookNotFound, msg
@@ -941,18 +953,23 @@ class Chef
else
Chef::Log.warn("Node #{node_name} has an empty run list.") if run_context.node.run_list.empty?
end
-
end
def has_admin_privileges?
- require 'chef/win32/security'
+ require "chef/win32/security"
Chef::ReservedNames::Win32::Security.has_admin_privileges?
end
+
+ # Register the data collector reporter to send event information to the
+ # data collector server
+ def register_data_collector_reporter
+ events.register(Chef::DataCollector::Reporter.new) if Chef::DataCollector.register_reporter?
+ end
end
end
# HACK cannot load this first, but it must be loaded.
-require 'chef/cookbook_loader'
-require 'chef/cookbook_version'
-require 'chef/cookbook/synchronizer'
+require "chef/cookbook_loader"
+require "chef/cookbook_version"
+require "chef/cookbook/synchronizer"
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index a43985f691..549872bfd7 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -1,10 +1,10 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Author:: Mark Mzyk (<mmzyk@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: AJ Christensen (<aj@chef.io>)
+# Author:: Mark Mzyk (<mmzyk@chef.io>)
# Author:: Kyle Goodwin (<kgoodwin@primerevenue.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,16 +19,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/log'
-require 'chef-config/logger'
+require "chef/log"
+require "chef-config/logger"
# DI our logger into ChefConfig before we load the config. Some defaults are
# auto-detected, and this emits log messages on some systems, all of which will
# occur at require-time. So we need to set the logger first.
ChefConfig.logger = Chef::Log
-require 'chef-config/config'
-require 'chef/platform/query_helpers'
+require "chef-config/config"
+require "chef/platform/query_helpers"
# Ohai::Config defines its own log_level and log_location. When loaded, it will
# override the default ChefConfig::Config values. We save them here before
@@ -41,7 +41,7 @@ LOG_LOCATION = ChefConfig::Config[:log_location] unless defined? LOG_LOCATION
# Load the ohai config into the chef config. We can't have an empty ohai
# configuration context because `ohai.plugins_path << some_path` won't work,
# and providing default ohai config values here isn't DRY.
-require 'ohai/config'
+require "ohai/config"
class Chef
Config = ChefConfig::Config
diff --git a/lib/chef/config_fetcher.rb b/lib/chef/config_fetcher.rb
index a8aad0740d..ee1b64956a 100644
--- a/lib/chef/config_fetcher.rb
+++ b/lib/chef/config_fetcher.rb
@@ -1,7 +1,7 @@
-require 'chef/application'
-require 'chef/chef_fs/path_utils'
-require 'chef/http/simple'
-require 'chef/json_compat'
+require "chef/application"
+require "chef/chef_fs/path_utils"
+require "chef/http/simple"
+require "chef/json_compat"
class Chef
class ConfigFetcher
@@ -12,12 +12,20 @@ class Chef
@config_location = config_location
end
+ def expanded_path
+ if config_location.nil? || remote_config?
+ config_location
+ else
+ File.expand_path(config_location)
+ end
+ end
+
def fetch_json
config_data = read_config
begin
Chef::JSONCompat.from_json(config_data)
rescue Chef::Exceptions::JSON::ParseError => error
- Chef::Application.fatal!("Could not parse the provided JSON file (#{config_location}): " + error.message, 2)
+ Chef::Application.fatal!("Could not parse the provided JSON file (#{config_location}): " + error.message, Chef::Exceptions::DeprecatedExitCode.new)
end
end
@@ -32,15 +40,15 @@ class Chef
def fetch_remote_config
http.get("")
rescue SocketError, SystemCallError, Net::HTTPServerException => error
- Chef::Application.fatal!("Cannot fetch config '#{config_location}': '#{error.class}: #{error.message}", 2)
+ Chef::Application.fatal!("Cannot fetch config '#{config_location}': '#{error.class}: #{error.message}", Chef::Exceptions::DeprecatedExitCode.new)
end
def read_local_config
::File.read(config_location)
- rescue Errno::ENOENT => error
- Chef::Application.fatal!("Cannot load configuration from #{config_location}", 2)
- rescue Errno::EACCES => error
- Chef::Application.fatal!("Permissions are incorrect on #{config_location}. Please chmod a+r #{config_location}", 2)
+ rescue Errno::ENOENT
+ Chef::Application.fatal!("Cannot load configuration from #{config_location}", Chef::Exceptions::DeprecatedExitCode.new)
+ rescue Errno::EACCES
+ Chef::Application.fatal!("Permissions are incorrect on #{config_location}. Please chmod a+r #{config_location}", Chef::Exceptions::DeprecatedExitCode.new)
end
def config_missing?
diff --git a/lib/chef/constants.rb b/lib/chef/constants.rb
index d39ce4c68d..f32c3e6654 100644
--- a/lib/chef/constants.rb
+++ b/lib/chef/constants.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser <jkeiser@chef.io>
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,6 +20,7 @@ class Chef
def NOT_PASSED.to_s
"NOT_PASSED"
end
+
def NOT_PASSED.inspect
to_s
end
diff --git a/lib/chef/cookbook/chefignore.rb b/lib/chef/cookbook/chefignore.rb
index aa9345e64e..dce58ecdb8 100644
--- a/lib/chef/cookbook/chefignore.rb
+++ b/lib/chef/cookbook/chefignore.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -40,7 +40,7 @@ class Chef
end
def ignored?(file_name)
- @ignores.any? {|glob| File.fnmatch?(glob, file_name)}
+ @ignores.any? { |glob| File.fnmatch?(glob, file_name) }
end
private
@@ -52,7 +52,7 @@ class Chef
ignore_globs << line.strip unless line =~ COMMENTS_AND_WHITESPACE
end
else
- Chef::Log.debug("No chefignore file found at #@ignore_file no files will be ignored")
+ Chef::Log.debug("No chefignore file found at #{@ignore_file} no files will be ignored")
end
ignore_globs
end
@@ -61,7 +61,7 @@ class Chef
if File.basename(path) =~ /chefignore/
path
else
- File.join(path, 'chefignore')
+ File.join(path, "chefignore")
end
end
@@ -72,4 +72,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/cookbook/cookbook_collection.rb b/lib/chef/cookbook/cookbook_collection.rb
index ae63abfc93..d06b8fd042 100644
--- a/lib/chef/cookbook/cookbook_collection.rb
+++ b/lib/chef/cookbook/cookbook_collection.rb
@@ -1,7 +1,7 @@
#--
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2010-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,8 @@
# limitations under the License.
#
-require 'chef/mash'
+require "chef/mash"
+require "chef/cookbook/gem_installer"
class Chef
# == Chef::CookbookCollection
@@ -33,13 +34,30 @@ class Chef
# The input is a mapping of cookbook name to CookbookVersion objects. We
# simply extract them
- def initialize(cookbook_versions={})
+ def initialize(cookbook_versions = {})
super() do |hash, key|
raise Chef::Exceptions::CookbookNotFound, "Cookbook #{key} not found. " <<
"If you're loading #{key} from another cookbook, make sure you configure the dependency in your metadata"
end
- cookbook_versions.each{ |cookbook_name, cookbook_version| self[cookbook_name] = cookbook_version }
+ cookbook_versions.each { |cookbook_name, cookbook_version| self[cookbook_name] = cookbook_version }
end
+ # Validates that the cookbook metadata allows it to run on this instance.
+ #
+ # Currently checks chef_version and ohai_version in the cookbook metadata
+ # against the running Chef::VERSION and Ohai::VERSION.
+ #
+ # @raises [Chef::Exceptions::CookbookChefVersionMismatch] if the Chef::VERSION fails validation
+ # @raises [Chef::Exceptions::CookbookOhaiVersionMismatch] if the Ohai::VERSION fails validation
+ def validate!
+ each do |cookbook_name, cookbook_version|
+ cookbook_version.metadata.validate_chef_version!
+ cookbook_version.metadata.validate_ohai_version!
+ end
+ end
+
+ def install_gems(events)
+ Cookbook::GemInstaller.new(self, events).install
+ end
end
end
diff --git a/lib/chef/cookbook/cookbook_version_loader.rb b/lib/chef/cookbook/cookbook_version_loader.rb
index dbccdbc0a8..b9de9a7482 100644
--- a/lib/chef/cookbook/cookbook_version_loader.rb
+++ b/lib/chef/cookbook/cookbook_version_loader.rb
@@ -1,8 +1,9 @@
-require 'chef/cookbook_version'
-require 'chef/cookbook/chefignore'
-require 'chef/cookbook/metadata'
-require 'chef/util/path_helper'
+require "chef/cookbook_version"
+require "chef/cookbook/chefignore"
+require "chef/cookbook/metadata"
+require "chef/util/path_helper"
+require "find"
class Chef
class Cookbook
@@ -32,7 +33,7 @@ class Chef
attr_reader :metadata_error
- def initialize(path, chefignore=nil)
+ def initialize(path, chefignore = nil)
@cookbook_path = File.expand_path( path ) # cookbook_path from which this was loaded
# We keep a list of all cookbook paths that have been merged in
@cookbook_paths = [ cookbook_path ]
@@ -43,6 +44,7 @@ class Chef
@relative_path = /#{Regexp.escape(@cookbook_path)}\/(.+)$/
@metadata_loaded = false
@cookbook_settings = {
+ :all_files => {},
:attribute_filenames => {},
:definition_filenames => {},
:recipe_filenames => {},
@@ -51,7 +53,7 @@ class Chef
:library_filenames => {},
:resource_filenames => {},
:provider_filenames => {},
- :root_filenames => {}
+ :root_filenames => {},
}
@metadata_filenames = []
@@ -78,18 +80,20 @@ class Chef
# re-raise any exception that occurred when reading the metadata
raise_metadata_error!
- load_as(:attribute_filenames, 'attributes', '*.rb')
- load_as(:definition_filenames, 'definitions', '*.rb')
- load_as(:recipe_filenames, 'recipes', '*.rb')
- load_recursively_as(:library_filenames, 'libraries', '*.rb')
+ load_all_files
+
+ remove_ignored_files
+
+ load_as(:attribute_filenames, "attributes", "*.rb")
+ load_as(:definition_filenames, "definitions", "*.rb")
+ load_as(:recipe_filenames, "recipes", "*.rb")
+ load_recursively_as(:library_filenames, "libraries", "*")
load_recursively_as(:template_filenames, "templates", "*")
load_recursively_as(:file_filenames, "files", "*")
load_recursively_as(:resource_filenames, "resources", "*.rb")
load_recursively_as(:provider_filenames, "providers", "*.rb")
load_root_files
- remove_ignored_files
-
if empty?
Chef::Log.warn "Found a directory #{cookbook_name} in the cookbook path, but it contains no cookbook files. skipping."
end
@@ -104,10 +108,10 @@ class Chef
@uploaded_cookbook_version_file = File.join(cookbook_path, UPLOADED_COOKBOOK_VERSION_FILE)
end
- if File.exists?(File.join(cookbook_path, "metadata.rb"))
- @metadata_filenames << File.join(cookbook_path, "metadata.rb")
- elsif File.exists?(File.join(cookbook_path, "metadata.json"))
+ if File.exists?(File.join(cookbook_path, "metadata.json"))
@metadata_filenames << File.join(cookbook_path, "metadata.json")
+ elsif File.exists?(File.join(cookbook_path, "metadata.rb"))
+ @metadata_filenames << File.join(cookbook_path, "metadata.rb")
elsif @uploaded_cookbook_version_file
@metadata_filenames << @uploaded_cookbook_version_file
end
@@ -121,6 +125,7 @@ class Chef
return nil if empty?
Chef::CookbookVersion.new(cookbook_name, *cookbook_paths).tap do |c|
+ c.all_files = cookbook_settings[:all_files].values
c.attribute_filenames = cookbook_settings[:attribute_filenames].values
c.definition_filenames = cookbook_settings[:definition_filenames].values
c.recipe_filenames = cookbook_settings[:recipe_filenames].values
@@ -164,7 +169,7 @@ class Chef
when /\.json$/
apply_json_metadata(metadata_file)
else
- raise RuntimeError, "Invalid metadata file: #{metadata_file} for cookbook: #{cookbook_version}"
+ raise "Invalid metadata file: #{metadata_file} for cookbook: #{cookbook_version}"
end
end
@@ -212,8 +217,44 @@ class Chef
@chefignore ||= Chefignore.new(File.basename(cookbook_path))
end
+ # Enumerate all the files in a cookbook and assign the resulting list to
+ # `cookbook_settings[:all_files]`. In order to behave in a compatible way
+ # with previous implementations, directories at the cookbook's root that
+ # begin with a dot are ignored. dotfiles are generally not ignored,
+ # however if the file is named ".uploaded-cookbook-version.json" it is
+ # assumed to be managed by chef-zero and not part of the cookbook.
+ def load_all_files
+ return unless File.exist?(cookbook_path)
+
+ # If cookbook_path is a symlink, Find on Windows Ruby 2.3 will not traverse it.
+ # Dir.entries will do so on all platforms, so we iterate the top level using
+ # Dir.entries. Since we have different behavior at the top anyway (hidden
+ # directories at the top level are not included for backcompat), this
+ # actually keeps things a bit cleaner.
+ Dir.entries(cookbook_path).each do |top_filename|
+ # Skip top-level directories starting with "."
+ top_path = File.join(cookbook_path, top_filename)
+ next if File.directory?(top_path) && top_filename.start_with?(".")
+
+ # Use Find.find because it:
+ # (a) returns any children, recursively
+ # (b) includes top_path as well
+ # (c) skips symlinks, which is backcompat (no judgement on whether it was *right*)
+ Find.find(top_path) do |path|
+ # Only add files, not directories
+ next unless File.file?(path)
+ # Don't add .uploaded-cookbook-version.json
+ next if File.basename(path) == UPLOADED_COOKBOOK_VERSION_FILE
+
+ relative_path = Chef::Util::PathHelper.relative_path_from(cookbook_path, path)
+ path = Pathname.new(path).cleanpath.to_s
+ cookbook_settings[:all_files][relative_path] = path
+ end
+ end
+ end
+
def load_root_files
- Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(cookbook_path), '*'), File::FNM_DOTMATCH).each do |file|
+ select_files_by_glob(File.join(Chef::Util::PathHelper.escape_glob_dir(cookbook_path), "*"), File::FNM_DOTMATCH).each do |file|
file = Chef::Util::PathHelper.cleanpath(file)
next if File.directory?(file)
next if File.basename(file) == UPLOADED_COOKBOOK_VERSION_FILE
@@ -223,75 +264,84 @@ class Chef
end
def load_recursively_as(category, category_dir, glob)
- file_spec = File.join(Chef::Util::PathHelper.escape_glob(cookbook_path, category_dir), '**', glob)
- Dir.glob(file_spec, File::FNM_DOTMATCH).each do |file|
+ glob_pattern = File.join(Chef::Util::PathHelper.escape_glob_dir(cookbook_path, category_dir), "**", glob)
+ select_files_by_glob(glob_pattern, File::FNM_DOTMATCH).each do |file|
file = Chef::Util::PathHelper.cleanpath(file)
- next if File.directory?(file)
name = Chef::Util::PathHelper.relative_path_from(@cookbook_path, file)
cookbook_settings[category][name] = file
end
end
def load_as(category, *path_glob)
- Dir[File.join(Chef::Util::PathHelper.escape_glob(cookbook_path), *path_glob)].each do |file|
+ glob_pattern = File.join(Chef::Util::PathHelper.escape_glob_dir(cookbook_path), *path_glob)
+ select_files_by_glob(glob_pattern).each do |file|
file = Chef::Util::PathHelper.cleanpath(file)
name = Chef::Util::PathHelper.relative_path_from(@cookbook_path, file)
cookbook_settings[category][name] = file
end
end
+ # Mimic Dir.glob inside a cookbook by running `File.fnmatch?` against
+ # `cookbook_settings[:all_files]`.
+ #
+ # @param pattern [String] a glob string passed to `File.fnmatch?`
+ # @param option [Integer] Option flag to control globbing behavior. These
+ # are constants defined on `File`, such as `File::FNM_DOTMATCH`.
+ # `File.fnmatch?` and `Dir.glob` only take one option argument, if you
+ # need to combine options, you must `|` the constants together. To make
+ # `File.fnmatch?` behave like `Dir.glob`, `File::FNM_PATHNAME` is
+ # always enabled.
+ def select_files_by_glob(pattern, option = 0)
+ combined_opts = option | File::FNM_PATHNAME
+ cookbook_settings[:all_files].values.select do |path|
+ File.fnmatch?(pattern, path, combined_opts)
+ end
+ end
+
def remove_ignored_files
- cookbook_settings.each_value do |file_list|
- file_list.reject! do |relative_path, full_path|
- chefignore.ignored?(relative_path)
- end
+ cookbook_settings[:all_files].reject! do |relative_path, full_path|
+ chefignore.ignored?(relative_path)
end
end
def apply_ruby_metadata(file)
- begin
- @metadata.from_file(file)
- rescue Chef::Exceptions::JSON::ParseError
- Chef::Log.error("Error evaluating metadata.rb for #@inferred_cookbook_name in " + file)
- raise
- end
+ @metadata.from_file(file)
+ rescue Chef::Exceptions::JSON::ParseError
+ Chef::Log.error("Error evaluating metadata.rb for #{@inferred_cookbook_name} in " + file)
+ raise
end
def apply_json_metadata(file)
- begin
- @metadata.from_json(IO.read(file))
- rescue Chef::Exceptions::JSON::ParseError
- Chef::Log.error("Couldn't parse cookbook metadata JSON for #@inferred_cookbook_name in " + file)
- raise
- end
+ @metadata.from_json(IO.read(file))
+ rescue Chef::Exceptions::JSON::ParseError
+ Chef::Log.error("Couldn't parse cookbook metadata JSON for #{@inferred_cookbook_name} in " + file)
+ raise
end
def apply_json_cookbook_version_metadata(file)
- begin
- data = Chef::JSONCompat.parse(IO.read(file))
- @metadata.from_hash(data['metadata'])
- # the JSON cookbok metadata file is only used by chef-zero.
- # The Chef Server API currently does not enforce that the metadata
- # have a `name` field, but that will cause an error when attempting
- # to load the cookbook. To keep compatibility, we fake it by setting
- # the metadata name from the cookbook version object's name.
- #
- # This behavior can be removed if/when Chef Server enforces that the
- # metadata contains a name key.
- @metadata.name(data['cookbook_name']) unless data['metadata'].key?('name')
- rescue Chef::Exceptions::JSON::ParseError
- Chef::Log.error("Couldn't parse cookbook metadata JSON for #@inferred_cookbook_name in " + file)
- raise
- end
+ data = Chef::JSONCompat.parse(IO.read(file))
+ @metadata.from_hash(data["metadata"])
+ # the JSON cookbok metadata file is only used by chef-zero.
+ # The Chef Server API currently does not enforce that the metadata
+ # have a `name` field, but that will cause an error when attempting
+ # to load the cookbook. To keep compatibility, we fake it by setting
+ # the metadata name from the cookbook version object's name.
+ #
+ # This behavior can be removed if/when Chef Server enforces that the
+ # metadata contains a name key.
+ @metadata.name(data["cookbook_name"]) unless data["metadata"].key?("name")
+ rescue Chef::Exceptions::JSON::ParseError
+ Chef::Log.error("Couldn't parse cookbook metadata JSON for #{@inferred_cookbook_name} in " + file)
+ raise
end
def set_frozen
if uploaded_cookbook_version_file
begin
data = Chef::JSONCompat.parse(IO.read(uploaded_cookbook_version_file))
- @frozen = data['frozen?']
+ @frozen = data["frozen?"]
rescue Chef::Exceptions::JSON::ParseError
- Chef::Log.error("Couldn't parse cookbook metadata JSON for #@inferred_cookbook_name in #{uploaded_cookbook_version_file}")
+ Chef::Log.error("Couldn't parse cookbook metadata JSON for #{@inferred_cookbook_name} in #{uploaded_cookbook_version_file}")
raise
end
end
diff --git a/lib/chef/cookbook/file_system_file_vendor.rb b/lib/chef/cookbook/file_system_file_vendor.rb
index e351ec4702..8088ed00cd 100644
--- a/lib/chef/cookbook/file_system_file_vendor.rb
+++ b/lib/chef/cookbook/file_system_file_vendor.rb
@@ -1,7 +1,7 @@
#--
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'chef/cookbook/file_vendor'
+require "chef/cookbook/file_vendor"
class Chef
class Cookbook
@@ -37,20 +37,19 @@ class Chef
def initialize(manifest, *repo_paths)
@cookbook_name = manifest[:cookbook_name]
@repo_paths = repo_paths.flatten
- raise ArgumentError, "You must specify at least one repo path" if @repo_paths.empty?
+ raise ArgumentError, "You must specify at least one repo path" if repo_paths.empty?
+ end
+
+ def cookbooks
+ @cookbooks ||= Chef::CookbookLoader.new(repo_paths).load_cookbooks
end
# Implements abstract base's requirement. It looks in the
# Chef::Config.cookbook_path file hierarchy for the requested
# file.
def get_filename(filename)
- location = @repo_paths.inject(nil) do |memo, basepath|
- candidate_location = File.join(basepath, @cookbook_name, filename)
- memo = candidate_location if File.exist?(candidate_location)
- memo
- end
- raise "File #{filename} does not exist for cookbook #{@cookbook_name}" unless location
-
+ location = File.join(cookbooks[cookbook_name].root_dir, filename) if cookbooks.has_key?(cookbook_name)
+ raise "File #{filename} does not exist for cookbook #{cookbook_name}" unless location && File.exist?(location)
location
end
diff --git a/lib/chef/cookbook/file_vendor.rb b/lib/chef/cookbook/file_vendor.rb
index b82b52f90c..f849f79296 100644
--- a/lib/chef/cookbook/file_vendor.rb
+++ b/lib/chef/cookbook/file_vendor.rb
@@ -1,7 +1,7 @@
#
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,6 @@
# limitations under the License.
#
-
class Chef
class Cookbook
# == Chef::Cookbook::FileVendor
diff --git a/lib/chef/cookbook/gem_installer.rb b/lib/chef/cookbook/gem_installer.rb
new file mode 100644
index 0000000000..df73ce3ee4
--- /dev/null
+++ b/lib/chef/cookbook/gem_installer.rb
@@ -0,0 +1,84 @@
+#--
+# Copyright:: Copyright (c) 2010-2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "tmpdir"
+require "chef/mixin/shell_out"
+
+class Chef
+ class Cookbook
+ class GemInstaller
+ include Chef::Mixin::ShellOut
+
+ # @return [Chef::EventDispatch::Dispatcher] the client event dispatcher
+ attr_accessor :events
+ # @return [Chef::CookbookCollection] the cookbook collection
+ attr_accessor :cookbook_collection
+
+ def initialize(cookbook_collection, events)
+ @cookbook_collection = cookbook_collection
+ @events = events
+ end
+
+ # Installs the gems into the omnibus gemset.
+ #
+ def install
+ cookbook_gems = []
+
+ cookbook_collection.each do |cookbook_name, cookbook_version|
+ cookbook_gems += cookbook_version.metadata.gems
+ end
+
+ events.cookbook_gem_start(cookbook_gems)
+
+ unless cookbook_gems.empty?
+ begin
+ Dir.mktmpdir("chef-gem-bundle") do |dir|
+ File.open("#{dir}/Gemfile", "w+") do |tf|
+ tf.puts "source '#{Chef::Config[:rubygems_url]}'"
+ cookbook_gems.each do |args|
+ tf.puts "gem(*#{args.inspect})"
+ end
+ tf.close
+ Chef::Log.debug("generated Gemfile contents:")
+ Chef::Log.debug(IO.read(tf.path))
+ so = shell_out!("bundle install", cwd: dir, env: { "PATH" => path_with_prepended_ruby_bin })
+ Chef::Log.info(so.stdout)
+ end
+ end
+ Gem.clear_paths
+ rescue Exception => e
+ events.cookbook_gem_failed(e)
+ raise
+ end
+ end
+
+ events.cookbook_gem_finished
+ end
+
+ private
+
+ # path_sanity appends the ruby_bin, but I want the ruby_bin prepended
+ def path_with_prepended_ruby_bin
+ env_path = ENV["PATH"].dup || ""
+ existing_paths = env_path.split(File::PATH_SEPARATOR)
+ existing_paths.unshift(RbConfig::CONFIG["bindir"])
+ env_path = existing_paths.join(File::PATH_SEPARATOR)
+ env_path.encode("utf-8", invalid: :replace, undef: :replace)
+ end
+ end
+ end
+end
diff --git a/lib/chef/cookbook/metadata.rb b/lib/chef/cookbook/metadata.rb
index 9822920a7d..3f23bc2056 100644
--- a/lib/chef/cookbook/metadata.rb
+++ b/lib/chef/cookbook/metadata.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2008-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: AJ Christensen (<aj@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,15 @@
# limitations under the License.
#
-require 'chef/exceptions'
-require 'chef/mash'
-require 'chef/mixin/from_file'
-require 'chef/mixin/params_validate'
-require 'chef/log'
-require 'chef/version_class'
-require 'chef/version_constraint'
-require 'chef/json_compat'
+require "chef/exceptions"
+require "chef/mash"
+require "chef/mixin/from_file"
+require "chef/mixin/params_validate"
+require "chef/log"
+require "chef/version_class"
+require "chef/version_constraint"
+require "chef/version_constraint/platform"
+require "chef/json_compat"
class Chef
class Cookbook
@@ -35,39 +36,45 @@ class Chef
# about Chef Cookbooks.
class Metadata
- NAME = 'name'.freeze
- DESCRIPTION = 'description'.freeze
- LONG_DESCRIPTION = 'long_description'.freeze
- MAINTAINER = 'maintainer'.freeze
- MAINTAINER_EMAIL = 'maintainer_email'.freeze
- LICENSE = 'license'.freeze
- PLATFORMS = 'platforms'.freeze
- DEPENDENCIES = 'dependencies'.freeze
- RECOMMENDATIONS = 'recommendations'.freeze
- SUGGESTIONS = 'suggestions'.freeze
- CONFLICTING = 'conflicting'.freeze
- PROVIDING = 'providing'.freeze
- REPLACING = 'replacing'.freeze
- ATTRIBUTES = 'attributes'.freeze
- GROUPINGS = 'groupings'.freeze
- RECIPES = 'recipes'.freeze
- VERSION = 'version'.freeze
- SOURCE_URL = 'source_url'.freeze
- ISSUES_URL = 'issues_url'.freeze
- PRIVACY = 'privacy'.freeze
+ NAME = "name".freeze
+ DESCRIPTION = "description".freeze
+ LONG_DESCRIPTION = "long_description".freeze
+ MAINTAINER = "maintainer".freeze
+ MAINTAINER_EMAIL = "maintainer_email".freeze
+ LICENSE = "license".freeze
+ PLATFORMS = "platforms".freeze
+ DEPENDENCIES = "dependencies".freeze
+ RECOMMENDATIONS = "recommendations".freeze
+ SUGGESTIONS = "suggestions".freeze
+ CONFLICTING = "conflicting".freeze
+ PROVIDING = "providing".freeze
+ REPLACING = "replacing".freeze
+ ATTRIBUTES = "attributes".freeze
+ GROUPINGS = "groupings".freeze
+ RECIPES = "recipes".freeze
+ VERSION = "version".freeze
+ SOURCE_URL = "source_url".freeze
+ ISSUES_URL = "issues_url".freeze
+ PRIVACY = "privacy".freeze
+ CHEF_VERSIONS = "chef_versions".freeze
+ OHAI_VERSIONS = "ohai_versions".freeze
+ GEMS = "gems".freeze
COMPARISON_FIELDS = [ :name, :description, :long_description, :maintainer,
:maintainer_email, :license, :platforms, :dependencies,
:recommendations, :suggestions, :conflicting, :providing,
:replacing, :attributes, :groupings, :recipes, :version,
- :source_url, :issues_url, :privacy ]
-
- VERSION_CONSTRAINTS = {:depends => DEPENDENCIES,
- :recommends => RECOMMENDATIONS,
- :suggests => SUGGESTIONS,
- :conflicts => CONFLICTING,
- :provides => PROVIDING,
- :replaces => REPLACING }
+ :source_url, :issues_url, :privacy, :chef_versions, :ohai_versions,
+ :gems ]
+
+ VERSION_CONSTRAINTS = { :depends => DEPENDENCIES,
+ :recommends => RECOMMENDATIONS,
+ :suggests => SUGGESTIONS,
+ :conflicts => CONFLICTING,
+ :provides => PROVIDING,
+ :replaces => REPLACING,
+ :chef_version => CHEF_VERSIONS,
+ :ohai_version => OHAI_VERSIONS }
include Chef::Mixin::ParamsValidate
include Chef::Mixin::FromFile
@@ -84,6 +91,13 @@ class Chef
attr_reader :recipes
attr_reader :version
+ # @return [Array<Gem::Dependency>] Array of supported Chef versions
+ attr_reader :chef_versions
+ # @return [Array<Gem::Dependency>] Array of supported Ohai versions
+ attr_reader :ohai_versions
+ # @return [Array<Array>] Array of gems to install with *args as an Array
+ attr_reader :gems
+
# Builds a new Chef::Cookbook::Metadata object.
#
# === Parameters
@@ -95,11 +109,11 @@ class Chef
# === Returns
# metadata<Chef::Cookbook::Metadata>
def initialize
- @name = nil
+ @name = nil
- @description = ''
- @long_description = ''
- @license = 'All rights reserved'
+ @description = ""
+ @long_description = ""
+ @license = "All rights reserved"
@maintainer = nil
@maintainer_email = nil
@@ -115,9 +129,12 @@ class Chef
@groupings = Mash.new
@recipes = Mash.new
@version = Version.new("0.0.0")
- @source_url = ''
- @issues_url = ''
+ @source_url = ""
+ @issues_url = ""
@privacy = false
+ @chef_versions = []
+ @ohai_versions = []
+ @gems = []
@errors = []
end
@@ -161,7 +178,7 @@ class Chef
#
# === Returns
# maintainer<String>:: Returns the current maintainer.
- def maintainer(arg=nil)
+ def maintainer(arg = nil)
set_or_return(
:maintainer,
arg,
@@ -176,7 +193,7 @@ class Chef
#
# === Returns
# maintainer_email<String>:: Returns the current maintainer email.
- def maintainer_email(arg=nil)
+ def maintainer_email(arg = nil)
set_or_return(
:maintainer_email,
arg,
@@ -191,7 +208,7 @@ class Chef
#
# === Returns
# license<String>:: Returns the current license
- def license(arg=nil)
+ def license(arg = nil)
set_or_return(
:license,
arg,
@@ -206,7 +223,7 @@ class Chef
#
# === Returns
# description<String>:: Returns the description
- def description(arg=nil)
+ def description(arg = nil)
set_or_return(
:description,
arg,
@@ -221,7 +238,7 @@ class Chef
#
# === Returns
# long_description<String>:: Returns the long description
- def long_description(arg=nil)
+ def long_description(arg = nil)
set_or_return(
:long_description,
arg,
@@ -237,7 +254,7 @@ class Chef
#
# === Returns
# version<String>:: Returns the current version
- def version(arg=nil)
+ def version(arg = nil)
if arg
@version = Chef::Version.new(arg)
end
@@ -252,7 +269,7 @@ class Chef
#
# === Returns
# name<String>:: Returns the current cookbook name.
- def name(arg=nil)
+ def name(arg = nil)
set_or_return(
:name,
arg,
@@ -309,7 +326,7 @@ class Chef
# === Returns
# versions<Array>:: Returns the list of versions for the platform
def recommends(cookbook, *version_args)
- version = new_args_format(:recommends, cookbook, version_args)
+ version = new_args_format(:recommends, cookbook, version_args)
constraint = validate_version_constraint(:recommends, cookbook, version)
@recommendations[cookbook] = constraint.to_s
@recommendations[cookbook]
@@ -386,6 +403,39 @@ class Chef
@replacing[cookbook]
end
+ # Metadata DSL to set a valid chef_version. May be declared multiple times
+ # with the result being 'OR'd such that if any statements match, the version
+ # is considered supported. Uses Gem::Requirement for its implementation.
+ #
+ # @param version_args [Array<String>] Version constraint in String form
+ # @return [Array<Gem::Dependency>] Current chef_versions array
+ def chef_version(*version_args)
+ @chef_versions << Gem::Dependency.new("chef", *version_args) unless version_args.empty?
+ @chef_versions
+ end
+
+ # Metadata DSL to set a valid ohai_version. May be declared multiple times
+ # with the result being 'OR'd such that if any statements match, the version
+ # is considered supported. Uses Gem::Requirement for its implementation.
+ #
+ # @param version_args [Array<String>] Version constraint in String form
+ # @return [Array<Gem::Dependency>] Current ohai_versions array
+ def ohai_version(*version_args)
+ @ohai_versions << Gem::Dependency.new("ohai", *version_args) unless version_args.empty?
+ @ohai_versions
+ end
+
+ # Metadata DSL to set a gem to install from the cookbook metadata. May be declared
+ # multiple times. All the gems from all the cookbooks are combined into one Gemfile
+ # and depsolved together. Uses Bundler's DSL for its implementation.
+ #
+ # @param args [Array<String>] Gem name and options to pass to Bundler's DSL
+ # @return [Array<Array>] Array of gem statements as args
+ def gem(*args)
+ @gems << args unless args.empty?
+ @gems
+ end
+
# Adds a description for a recipe.
#
# === Parameters
@@ -412,7 +462,7 @@ class Chef
cookbook.fully_qualified_recipe_names.map do |recipe_name|
unqualified_name =
if recipe_name =~ /::default$/
- self.name.to_s
+ name.to_s
else
recipe_name
end
@@ -451,13 +501,13 @@ class Chef
:description => { :kind_of => String },
:choice => { :kind_of => [ Array ], :default => [] },
:calculated => { :equal_to => [ true, false ], :default => false },
- :type => { :equal_to => [ "string", "array", "hash", "symbol", "boolean", "numeric" ], :default => "string" },
+ :type => { :equal_to => %w{string array hash symbol boolean numeric}, :default => "string" },
:required => { :equal_to => [ "required", "recommended", "optional", true, false ], :default => "optional" },
:recipes => { :kind_of => [ Array ], :default => [] },
:default => { :kind_of => [ String, Array, Hash, Symbol, Numeric, TrueClass, FalseClass ] },
:source_url => { :kind_of => String },
:issues_url => { :kind_of => String },
- :privacy => { :kind_of => [ TrueClass, FalseClass ] }
+ :privacy => { :kind_of => [ TrueClass, FalseClass ] },
}
)
options[:required] = remap_required_attribute(options[:required]) unless options[:required].nil?
@@ -474,35 +524,72 @@ class Chef
options,
{
:title => { :kind_of => String },
- :description => { :kind_of => String }
+ :description => { :kind_of => String },
}
)
@groupings[name] = options
@groupings[name]
end
+ # Convert an Array of Gem::Dependency objects (chef_version/ohai_version) to an Array.
+ #
+ # Gem::Dependencey#to_s is not useful, and there is no #to_json defined on it or its component
+ # objets, so we have to write our own rendering method.
+ #
+ # [ Gem::Dependency.new(">= 12.5"), Gem::Dependency.new(">= 11.18.0", "< 12.0") ]
+ #
+ # results in:
+ #
+ # [ [ ">= 12.5" ], [ ">= 11.18.0", "< 12.0" ] ]
+ #
+ # @param deps [Array<Gem::Dependency>] Multiple Gem-style version constraints
+ # @return [Array<Array<String>]] Simple object representation of version constraints (for json)
+ def gem_requirements_to_array(*deps)
+ deps.map do |dep|
+ dep.requirement.requirements.map do |op, version|
+ "#{op} #{version}"
+ end.sort
+ end
+ end
+
+ # Convert an Array of Gem::Dependency objects (chef_version/ohai_version) to a hash.
+ #
+ # This is the inverse of #gem_requirements_to_array
+ #
+ # @param what [String] What version constraint we are constructing ('chef' or 'ohai' presently)
+ # @param array [Array<Array<String>]] Simple object representation of version constraints (from json)
+ # @return [Array<Gem::Dependency>] Multiple Gem-style version constraints
+ def gem_requirements_from_array(what, array)
+ array.map do |dep|
+ Gem::Dependency.new(what, *dep)
+ end
+ end
+
def to_hash
{
- NAME => self.name,
- DESCRIPTION => self.description,
- LONG_DESCRIPTION => self.long_description,
- MAINTAINER => self.maintainer,
- MAINTAINER_EMAIL => self.maintainer_email,
- LICENSE => self.license,
- PLATFORMS => self.platforms,
- DEPENDENCIES => self.dependencies,
- RECOMMENDATIONS => self.recommendations,
- SUGGESTIONS => self.suggestions,
- CONFLICTING => self.conflicting,
- PROVIDING => self.providing,
- REPLACING => self.replacing,
- ATTRIBUTES => self.attributes,
- GROUPINGS => self.groupings,
- RECIPES => self.recipes,
- VERSION => self.version,
- SOURCE_URL => self.source_url,
- ISSUES_URL => self.issues_url,
- PRIVACY => self.privacy
+ NAME => name,
+ DESCRIPTION => description,
+ LONG_DESCRIPTION => long_description,
+ MAINTAINER => maintainer,
+ MAINTAINER_EMAIL => maintainer_email,
+ LICENSE => license,
+ PLATFORMS => platforms,
+ DEPENDENCIES => dependencies,
+ RECOMMENDATIONS => recommendations,
+ SUGGESTIONS => suggestions,
+ CONFLICTING => conflicting,
+ PROVIDING => providing,
+ REPLACING => replacing,
+ ATTRIBUTES => attributes,
+ GROUPINGS => groupings,
+ RECIPES => recipes,
+ VERSION => version,
+ SOURCE_URL => source_url,
+ ISSUES_URL => issues_url,
+ PRIVACY => privacy,
+ CHEF_VERSIONS => gem_requirements_to_array(*chef_versions),
+ OHAI_VERSIONS => gem_requirements_to_array(*ohai_versions),
+ GEMS => gems,
}
end
@@ -511,7 +598,7 @@ class Chef
end
def self.from_hash(o)
- cm = self.new()
+ cm = new()
cm.from_hash(o)
cm
end
@@ -537,12 +624,15 @@ class Chef
@source_url = o[SOURCE_URL] if o.has_key?(SOURCE_URL)
@issues_url = o[ISSUES_URL] if o.has_key?(ISSUES_URL)
@privacy = o[PRIVACY] if o.has_key?(PRIVACY)
+ @chef_versions = gem_requirements_from_array("chef", o[CHEF_VERSIONS]) if o.has_key?(CHEF_VERSIONS)
+ @ohai_versions = gem_requirements_from_array("ohai", o[OHAI_VERSIONS]) if o.has_key?(OHAI_VERSIONS)
+ @gems = o[GEMS] if o.has_key?(GEMS)
self
end
def self.from_json(string)
o = Chef::JSONCompat.from_json(string)
- self.from_hash(o)
+ from_hash(o)
end
def self.validate_json(json_str)
@@ -550,11 +640,11 @@ class Chef
metadata = new()
VERSION_CONSTRAINTS.each do |dependency_type, hash_key|
if dependency_group = o[hash_key]
- dependency_group.each do |cb_name, constraints|
- if metadata.respond_to?(method_name)
- metadata.public_send(method_name, cb_name, *Array(constraints))
- end
- end
+ dependency_group.each do |cb_name, constraints|
+ if metadata.respond_to?(dependency_type)
+ metadata.public_send(dependency_type, cb_name, *Array(constraints))
+ end
+ end
end
end
true
@@ -572,7 +662,7 @@ class Chef
#
# === Returns
# source_url<String>:: Returns the current source URL.
- def source_url(arg=nil)
+ def source_url(arg = nil)
set_or_return(
:source_url,
arg,
@@ -587,7 +677,7 @@ class Chef
#
# === Returns
# issues_url<String>:: Returns the current issues URL.
- def issues_url(arg=nil)
+ def issues_url(arg = nil)
set_or_return(
:issues_url,
arg,
@@ -604,7 +694,7 @@ class Chef
# === Returns
# privacy<TrueClass,FalseClass>:: Whether this cookbook is private or not
#
- def privacy(arg=nil)
+ def privacy(arg = nil)
set_or_return(
:privacy,
arg,
@@ -612,7 +702,50 @@ class Chef
)
end
- private
+ # Validates that the Ohai::VERSION of the running chef-client matches one of the
+ # configured ohai_version statements in this cookbooks metadata.
+ #
+ # @raises [Chef::Exceptions::CookbookOhaiVersionMismatch] if the cookbook fails validation
+ def validate_ohai_version!
+ unless gem_dep_matches?("ohai", Gem::Version.new(Ohai::VERSION), *ohai_versions)
+ raise Exceptions::CookbookOhaiVersionMismatch.new(Ohai::VERSION, name, version, *ohai_versions)
+ end
+ end
+
+ # Validates that the Chef::VERSION of the running chef-client matches one of the
+ # configured chef_version statements in this cookbooks metadata.
+ #
+ # @raises [Chef::Exceptions::CookbookChefVersionMismatch] if the cookbook fails validation
+ def validate_chef_version!
+ unless gem_dep_matches?("chef", Gem::Version.new(Chef::VERSION), *chef_versions)
+ raise Exceptions::CookbookChefVersionMismatch.new(Chef::VERSION, name, version, *chef_versions)
+ end
+ end
+
+ def method_missing(method, *args, &block)
+ if block_given?
+ super
+ else
+ Chef::Log.debug "ignoring method #{method} on cookbook with name #{name}, possible typo or future metadata?"
+ end
+ end
+
+ private
+
+ # Helper to match a gem style version (ohai_version/chef_version) against a set of
+ # Gem::Dependency version constraints. If none are present, it always matches. if
+ # multiple are present, one must match. Returns false if none matches.
+ #
+ # @param what [String] the name of the constraint (e.g. 'chef' or 'ohai')
+ # @param version [String] the version to compare against the constraints
+ # @param deps [Array<Gem::Dependency>] Multiple Gem-style version constraints
+ # @return [Boolean] true if no constraints or a match, false if no match
+ def gem_dep_matches?(what, version, *deps)
+ # always match if we have no chef_version at all
+ return true unless deps.length > 0
+ # match if we match any of the chef_version lines
+ deps.any? { |dep| dep.match?(what, version) }
+ end
def run_validation
if name.nil?
@@ -626,25 +759,25 @@ class Chef
elsif version_constraints.size == 1
version_constraints.first
else
- msg=<<-OBSOLETED
+ msg = <<-OBSOLETED
The dependency specification syntax you are using is no longer valid. You may not
specify more than one version constraint for a particular cookbook.
Consult https://docs.chef.io/config_rb_metadata.html for the updated syntax.
-Called by: #{caller_name} '#{dep_name}', #{version_constraints.map {|vc| vc.inspect}.join(", ")}
+Called by: #{caller_name} '#{dep_name}', #{version_constraints.map { |vc| vc.inspect }.join(", ")}
Called from:
-#{caller[0...5].map {|line| " " + line}.join("\n")}
+#{caller[0...5].map { |line| " " + line }.join("\n")}
OBSOLETED
raise Exceptions::ObsoleteDependencySyntax, msg
end
end
def validate_version_constraint(caller_name, dep_name, constraint_str)
- Chef::VersionConstraint.new(constraint_str)
+ Chef::VersionConstraint::Platform.new(constraint_str)
rescue Chef::Exceptions::InvalidVersionConstraint => e
Log.debug(e)
- msg=<<-INVALID
+ msg = <<-INVALID
The version constraint syntax you are using is not valid. If you recently
upgraded to Chef 0.10.0, be aware that you no may longer use "<<" and ">>" for
'less than' and 'greater than'; use '<' and '>' instead.
@@ -652,7 +785,7 @@ Consult https://docs.chef.io/config_rb_metadata.html for more information.
Called by: #{caller_name} '#{dep_name}', '#{constraint_str}'
Called from:
-#{caller[0...5].map {|line| " " + line}.join("\n")}
+#{caller[0...5].map { |line| " " + line }.join("\n")}
INVALID
raise Exceptions::InvalidVersionConstraint, msg
end
@@ -666,7 +799,7 @@ INVALID
def validate_string_array(arry)
if arry.kind_of?(Array)
arry.each do |choice|
- validate( {:choice => choice}, {:choice => {:kind_of => String}} )
+ validate( { :choice => choice }, { :choice => { :kind_of => String } } )
end
end
end
@@ -676,28 +809,28 @@ INVALID
# Raise an exception if the members of the array do not match the defaults
# === Parameters
# opts<Hash>:: The options hash
- def validate_choice_array(opts)
- if opts[:choice].kind_of?(Array)
- case opts[:type]
- when "string"
- validator = [ String ]
- when "array"
- validator = [ Array ]
- when "hash"
- validator = [ Hash ]
- when "symbol"
- validator = [ Symbol ]
- when "boolean"
- validator = [ TrueClass, FalseClass ]
- when "numeric"
- validator = [ Numeric ]
- end
+ def validate_choice_array(opts)
+ if opts[:choice].kind_of?(Array)
+ case opts[:type]
+ when "string"
+ validator = [ String ]
+ when "array"
+ validator = [ Array ]
+ when "hash"
+ validator = [ Hash ]
+ when "symbol"
+ validator = [ Symbol ]
+ when "boolean"
+ validator = [ TrueClass, FalseClass ]
+ when "numeric"
+ validator = [ Numeric ]
+ end
- opts[:choice].each do |choice|
- validate( {:choice => choice}, {:choice => {:kind_of => validator}} )
- end
+ opts[:choice].each do |choice|
+ validate( { :choice => choice }, { :choice => { :kind_of => validator } } )
end
end
+ end
# For backwards compatibility, remap Boolean values to String
# true is mapped to "required"
@@ -721,7 +854,7 @@ INVALID
def validate_calculated_default_rule(options)
calculated_conflict = ((options[:default].is_a?(Array) && !options[:default].empty?) ||
(options[:default].is_a?(String) && !options[:default] != "")) &&
- options[:calculated] == true
+ options[:calculated] == true
raise ArgumentError, "Default cannot be specified if calculated is true!" if calculated_conflict
end
@@ -729,12 +862,12 @@ INVALID
return if !options[:choice].is_a?(Array) || options[:choice].empty?
if options[:default].is_a?(String) && options[:default] != ""
- raise ArgumentError, "Default must be one of your choice values!" if options[:choice].index(options[:default]) == nil
+ raise ArgumentError, "Default must be one of your choice values!" if options[:choice].index(options[:default]).nil?
end
if options[:default].is_a?(Array) && !options[:default].empty?
options[:default].each do |val|
- raise ArgumentError, "Default values must be a subset of your choice values!" if options[:choice].index(val) == nil
+ raise ArgumentError, "Default values must be a subset of your choice values!" if options[:choice].index(val).nil?
end
end
end
@@ -753,7 +886,7 @@ INVALID
def handle_deprecated_constraints(specification)
specification.inject(Mash.new) do |acc, (cb, constraints)|
constraints = Array(constraints)
- acc[cb] = (constraints.empty? || constraints.size > 1) ? [] : constraints.first.gsub(/>>/, '>').gsub(/<</, '<')
+ acc[cb] = (constraints.empty? || constraints.size > 1) ? [] : constraints.first.gsub(/>>/, ">").gsub(/<</, "<")
acc
end
end
diff --git a/lib/chef/cookbook/remote_file_vendor.rb b/lib/chef/cookbook/remote_file_vendor.rb
index 7868430227..e63d094dc4 100644
--- a/lib/chef/cookbook/remote_file_vendor.rb
+++ b/lib/chef/cookbook/remote_file_vendor.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/cookbook/file_vendor'
+require "chef/cookbook/file_vendor"
class Chef
class Cookbook
@@ -45,10 +45,10 @@ class Chef
end
raise "No such segment #{segment} in cookbook #{@cookbook_name}" unless @manifest[segment]
- found_manifest_record = @manifest[segment].find {|manifest_record| manifest_record[:path] == filename }
+ found_manifest_record = @manifest[segment].find { |manifest_record| manifest_record[:path] == filename }
raise "No such file #{filename} in #{@cookbook_name}" unless found_manifest_record
- cache_filename = File.join("cookbooks", @cookbook_name, found_manifest_record['path'])
+ cache_filename = File.join("cookbooks", @cookbook_name, found_manifest_record["path"])
# update valid_cache_entries so the upstream cache cleaner knows what
# we've used.
@@ -62,8 +62,8 @@ class Chef
# If the checksums are different between on-disk (current) and on-server
# (remote, per manifest), do the update. This will also execute if there
# is no current checksum.
- if current_checksum != found_manifest_record['checksum']
- raw_file = @rest.get_rest(found_manifest_record[:url], true)
+ if current_checksum != found_manifest_record["checksum"]
+ raw_file = @rest.streaming_request(found_manifest_record[:url])
Chef::Log.debug("Storing updated #{cache_filename} in the cache.")
Chef::FileCache.move_to(raw_file.path, cache_filename)
diff --git a/lib/chef/cookbook/synchronizer.rb b/lib/chef/cookbook/synchronizer.rb
index fc8e739d73..bb44bc3d5c 100644
--- a/lib/chef/cookbook/synchronizer.rb
+++ b/lib/chef/cookbook/synchronizer.rb
@@ -1,6 +1,7 @@
-require 'chef/client'
-require 'chef/util/threaded_job_queue'
-require 'singleton'
+require "chef/client"
+require "chef/util/threaded_job_queue"
+require "chef/server_api"
+require "singleton"
class Chef
@@ -42,7 +43,7 @@ class Chef
end
def cleanup_file_cache
- unless Chef::Config[:solo] || skip_removal
+ unless Chef::Config[:solo_legacy_mode] || skip_removal
# Delete each file in the cache that we didn't encounter in the
# manifest.
cache.find(File.join(%w{cookbooks ** {*,.*}})).each do |cache_filename|
@@ -140,7 +141,7 @@ class Chef
# === Returns
# true:: Always returns true
def sync_cookbooks
- Chef::Log.info("Loading cookbooks [#{cookbooks.map {|ckbk| ckbk.name + '@' + ckbk.version}.join(', ')}]")
+ Chef::Log.info("Loading cookbooks [#{cookbooks.map { |ckbk| ckbk.name + '@' + ckbk.version }.join(', ')}]")
Chef::Log.debug("Cookbooks detail: #{cookbooks.inspect}")
clear_obsoleted_cookbooks
@@ -151,11 +152,11 @@ class Chef
queue << lambda do |lock|
full_file_path = sync_file(file)
- lock.synchronize {
+ lock.synchronize do
# Save the full_path of the downloaded file to be restored in the manifest later
save_full_file_path(file, full_file_path)
mark_file_synced(file)
- }
+ end
end
end
@@ -175,7 +176,7 @@ class Chef
# Saves the full_path to the file of the cookbook to be updated
# in the manifest later
def save_full_file_path(file, full_path)
- @cookbook_full_file_paths[file.cookbook] ||= { }
+ @cookbook_full_file_paths[file.cookbook] ||= {}
@cookbook_full_file_paths[file.cookbook][file.segment] ||= [ ]
@cookbook_full_file_paths[file.cookbook][file.segment] << full_path
end
@@ -244,14 +245,14 @@ class Chef
# === Returns
# Full path to the cached file as a String
def sync_file(file)
- cache_filename = File.join("cookbooks", file.cookbook.name, file.manifest_record['path'])
+ cache_filename = File.join("cookbooks", file.cookbook.name, file.manifest_record["path"])
mark_cached_file_valid(cache_filename)
# If the checksums are different between on-disk (current) and on-server
# (remote, per manifest), do the update. This will also execute if there
# is no current checksum.
- if !cached_copy_up_to_date?(cache_filename, file.manifest_record['checksum'])
- download_file(file.manifest_record['url'], cache_filename)
+ if !cached_copy_up_to_date?(cache_filename, file.manifest_record["checksum"])
+ download_file(file.manifest_record["url"], cache_filename)
@events.updated_cookbook_file(file.cookbook.name, cache_filename)
else
Chef::Log.debug("Not storing #{cache_filename}, as the cache is up to date.")
@@ -262,6 +263,10 @@ class Chef
end
def cached_copy_up_to_date?(local_path, expected_checksum)
+ if Chef::Config[:skip_cookbook_sync]
+ Chef::Log.warn "skipping cookbook synchronization! DO NOT LEAVE THIS ENABLED IN PRODUCTION!!!"
+ return true
+ end
if cache.has_key?(local_path)
current_checksum = CookbookVersion.checksum_cookbook_file(cache.load(local_path, false))
expected_checksum == current_checksum
@@ -274,7 +279,7 @@ class Chef
# downloaded to the path +destination+ which is relative to the Chef file
# cache root.
def download_file(url, destination)
- raw_file = server_api.get_rest(url, true)
+ raw_file = server_api.streaming_request(url)
Chef::Log.info("Storing updated #{destination} in the cache.")
cache.move_to(raw_file.path, destination)
@@ -286,7 +291,7 @@ class Chef
end
def server_api
- Chef::REST.new(Chef::Config[:chef_server_url])
+ Thread.current[:server_api] ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], keepalives: true)
end
end
diff --git a/lib/chef/cookbook/syntax_check.rb b/lib/chef/cookbook/syntax_check.rb
index 96fc7e7b84..8d0d636bd2 100644
--- a/lib/chef/cookbook/syntax_check.rb
+++ b/lib/chef/cookbook/syntax_check.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'pathname'
-require 'stringio'
-require 'erubis'
-require 'chef/mixin/shell_out'
-require 'chef/mixin/checksum'
-require 'chef/util/path_helper'
+require "pathname"
+require "stringio"
+require "erubis"
+require "chef/mixin/shell_out"
+require "chef/mixin/checksum"
+require "chef/util/path_helper"
class Chef
class Cookbook
@@ -43,7 +43,7 @@ class Chef
# Create a new PersistentSet. Values in the set are persisted by
# creating a file in the +cache_path+ directory.
- def initialize(cache_path=Chef::Config[:syntax_check_cache_path])
+ def initialize(cache_path = Chef::Config[:syntax_check_cache_path])
@cache_path = cache_path
@cache_path_created = false
end
@@ -82,7 +82,7 @@ class Chef
# Creates a new SyntaxCheck given the +cookbook_name+ and a +cookbook_path+.
# If no +cookbook_path+ is given, +Chef::Config.cookbook_path+ is used.
- def self.for_cookbook(cookbook_name, cookbook_path=nil)
+ def self.for_cookbook(cookbook_name, cookbook_path = nil)
cookbook_path ||= Chef::Config.cookbook_path
unless cookbook_path
raise ArgumentError, "Cannot find cookbook #{cookbook_name} unless Chef::Config.cookbook_path is set or an explicit cookbook path is given"
@@ -110,12 +110,12 @@ class Chef
end
def remove_uninteresting_ruby_files(file_list)
- file_list.reject { |f| f =~ %r{#{cookbook_path}/(files|templates)/} }
+ file_list.reject { |f| f =~ %r{#{Regexp.quote(cookbook_path)}/(files|templates)/} }
end
def ruby_files
- path = Chef::Util::PathHelper.escape_glob(cookbook_path)
- files = Dir[File.join(path, '**', '*.rb')]
+ path = Chef::Util::PathHelper.escape_glob_dir(cookbook_path)
+ files = Dir[File.join(path, "**", "*.rb")]
files = remove_ignored_files(files)
files = remove_uninteresting_ruby_files(files)
files
@@ -133,7 +133,7 @@ class Chef
end
def template_files
- remove_ignored_files Dir[File.join(Chef::Util::PathHelper.escape_glob(cookbook_path), '**/templates/**', '*.erb')]
+ remove_ignored_files Dir[File.join(Chef::Util::PathHelper.escape_glob_dir(cookbook_path), "**/templates/**", "*.erb")]
end
def untested_template_files
@@ -209,7 +209,7 @@ class Chef
# Debug a syntax error in a template.
def invalid_erb_file(erb_file, error_message)
- file_relative_path = erb_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
+ file_relative_path = erb_file[/^#{Regexp.escape(cookbook_path + File::Separator)}(.*)/, 1]
Chef::Log.fatal("Erb template #{file_relative_path} has a syntax error:")
error_message.each_line { |l| Chef::Log.fatal(l.chomp) }
nil
@@ -244,7 +244,7 @@ class Chef
# Debugs ruby syntax errors by printing the path to the file and any
# diagnostic info given in +error_message+
def invalid_ruby_file(ruby_file, error_message)
- file_relative_path = ruby_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
+ file_relative_path = ruby_file[/^#{Regexp.escape(cookbook_path + File::Separator)}(.*)/, 1]
Chef::Log.fatal("Cookbook file #{file_relative_path} has a ruby syntax error:")
error_message.each_line { |l| Chef::Log.fatal(l.chomp) }
false
diff --git a/lib/chef/cookbook_loader.rb b/lib/chef/cookbook_loader.rb
index 79005b1569..a965b43c61 100644
--- a/lib/chef/cookbook_loader.rb
+++ b/lib/chef/cookbook_loader.rb
@@ -1,9 +1,9 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,12 +18,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/config'
-require 'chef/exceptions'
-require 'chef/cookbook/cookbook_version_loader'
-require 'chef/cookbook_version'
-require 'chef/cookbook/chefignore'
-require 'chef/cookbook/metadata'
+require "chef/config"
+require "chef/exceptions"
+require "chef/cookbook/cookbook_version_loader"
+require "chef/cookbook_version"
+require "chef/cookbook/chefignore"
+require "chef/cookbook/metadata"
#
# CookbookLoader class loads the cookbooks lazily as read
@@ -44,10 +44,10 @@ class Chef
@cookbooks_by_name = Mash.new
@loaded_cookbooks = {}
@metadata = Mash.new
- @cookbooks_paths = Hash.new {|h,k| h[k] = []} # for deprecation warnings
+ @cookbooks_paths = Hash.new { |h, k| h[k] = [] } # for deprecation warnings
@chefignores = {}
@repo_paths = repo_paths.map do |repo_path|
- repo_path = File.expand_path(repo_path)
+ File.expand_path(repo_path)
end
@preloaded_cookbooks = false
@@ -62,11 +62,21 @@ class Chef
def merged_cookbook_paths # for deprecation warnings
merged_cookbook_paths = {}
- @merged_cookbooks.each {|c| merged_cookbook_paths[c] = @cookbooks_paths[c]}
+ @merged_cookbooks.each { |c| merged_cookbook_paths[c] = @cookbooks_paths[c] }
merged_cookbook_paths
end
- def load_cookbooks
+ def warn_about_cookbook_shadowing
+ unless merged_cookbooks.empty?
+ Chef::Log.deprecation "The cookbook(s): #{merged_cookbooks.join(', ')} exist in multiple places in your cookbook_path. " +
+ "A composite version has been compiled. This has been deprecated since 0.10.4, in Chef 13 this behavior will be REMOVED."
+ end
+ end
+
+ # Will be removed when cookbook shadowing is removed, do NOT create new consumers of this API.
+ #
+ # @api private
+ def load_cookbooks_without_shadow_warning
preload_cookbooks
@loaders_by_name.each do |cookbook_name, _loaders|
load_cookbook(cookbook_name)
@@ -74,9 +84,17 @@ class Chef
@cookbooks_by_name
end
+ def load_cookbooks
+ ret = load_cookbooks_without_shadow_warning
+ warn_about_cookbook_shadowing
+ ret
+ end
+
def load_cookbook(cookbook_name)
preload_cookbooks
+ return @cookbooks_by_name[cookbook_name] if @cookbooks_by_name.has_key?(cookbook_name)
+
return nil unless @loaders_by_name.key?(cookbook_name.to_s)
cookbook_loaders_for(cookbook_name).each do |loader|
@@ -103,10 +121,10 @@ class Chef
end
def [](cookbook)
- if @cookbooks_by_name.has_key?(cookbook.to_sym) or load_cookbook(cookbook.to_sym)
+ if @cookbooks_by_name.has_key?(cookbook.to_sym) || load_cookbook(cookbook.to_sym)
@cookbooks_by_name[cookbook.to_sym]
else
- raise Exceptions::CookbookNotFoundInRepo, "Cannot find a cookbook named #{cookbook.to_s}; did you forget to add metadata to a cookbook? (https://docs.chef.io/config_rb_metadata.html)"
+ raise Exceptions::CookbookNotFoundInRepo, "Cannot find a cookbook named #{cookbook}; did you forget to add metadata to a cookbook? (https://docs.chef.io/config_rb_metadata.html)"
end
end
@@ -119,7 +137,7 @@ class Chef
alias :key? :has_key?
def each
- @cookbooks_by_name.keys.sort { |a,b| a.to_s <=> b.to_s }.each do |cname|
+ @cookbooks_by_name.keys.sort_by(&:to_s).each do |cname|
yield(cname, @cookbooks_by_name[cname])
end
end
@@ -161,7 +179,7 @@ class Chef
@all_files_in_repo_paths ||=
begin
@repo_paths.inject([]) do |all_children, repo_path|
- all_children += Dir[File.join(Chef::Util::PathHelper.escape_glob(repo_path), "*")]
+ all_children + Dir[File.join(Chef::Util::PathHelper.escape_glob_dir(repo_path), "*")]
end
end
end
diff --git a/lib/chef/cookbook_manifest.rb b/lib/chef/cookbook_manifest.rb
index 10654a4945..d6de9dd029 100644
--- a/lib/chef/cookbook_manifest.rb
+++ b/lib/chef/cookbook_manifest.rb
@@ -1,5 +1,5 @@
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'forwardable'
-require 'chef/util/path_helper'
-require 'chef/log'
+require "forwardable"
+require "chef/util/path_helper"
+require "chef/log"
class Chef
@@ -127,14 +127,14 @@ class Chef
def to_hash
result = manifest.dup
- result['frozen?'] = frozen_version?
- result['chef_type'] = 'cookbook_version'
+ result["frozen?"] = frozen_version?
+ result["chef_type"] = "cookbook_version"
result.to_hash
end
def to_json(*a)
result = to_hash
- result['json_class'] = "Chef::CookbookVersion"
+ result["json_class"] = "Chef::CookbookVersion"
Chef::JSONCompat.to_json(result, *a)
end
@@ -152,6 +152,7 @@ class Chef
def named_cookbook_url
"#{cookbook_url_path}/#{name}"
end
+
# Adds the `force=true` parameter to the upload URL. This allows
# the user to overwrite a frozen cookbook (a PUT against the
# normal #save_url raises a 409 Conflict in this case).
@@ -169,7 +170,7 @@ class Chef
COOKBOOK_SEGMENTS.each do |segment|
next unless @manifest.has_key?(segment)
- filenames = @manifest[segment].map{|manifest_record| manifest_record['name']}
+ filenames = @manifest[segment].map { |manifest_record| manifest_record["name"] }
cookbook_version.replace_segment_filenames(segment, filenames)
end
@@ -193,7 +194,7 @@ class Chef
:templates => Array.new,
:resources => Array.new,
:providers => Array.new,
- :root_files => Array.new
+ :root_files => Array.new,
})
@checksums = {}
@@ -215,7 +216,7 @@ class Chef
:name => file_name,
:path => path,
:checksum => csum,
- :specificity => specificity
+ :specificity => specificity,
})
manifest[segment] << rs
@@ -243,17 +244,17 @@ class Chef
parts = pathname.each_filename.take(2)
# Check if path is actually under root_path
- next if parts[0] == '..'
+ next if parts[0] == ".."
if segment == :templates || segment == :files
# Check if pathname looks like files/foo or templates/foo (unscoped)
if pathname.each_filename.to_a.length == 2
# Use root_default in case the same path exists at root_default and default
- return [ pathname.to_s, 'root_default' ]
+ return [ pathname.to_s, "root_default" ]
else
return [ pathname.to_s, parts[1] ]
end
else
- return [ pathname.to_s, 'default' ]
+ return [ pathname.to_s, "default" ]
end
end
Chef::Log.error("Cookbook file #{segment_file} not under cookbook root paths #{root_paths.inspect}.")
diff --git a/lib/chef/cookbook_site_streaming_uploader.rb b/lib/chef/cookbook_site_streaming_uploader.rb
index 2be189e942..c0e85ff984 100644
--- a/lib/chef/cookbook_site_streaming_uploader.rb
+++ b/lib/chef/cookbook_site_streaming_uploader.rb
@@ -1,8 +1,8 @@
#
# Author:: Stanislav Vitvitskiy
-# Author:: Nuo Yan (nuo@opscode.com)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Nuo Yan (nuo@chef.io)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2009-2016, 2010-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,10 @@
# limitations under the License.
#
-require 'uri'
-require 'net/http'
-require 'mixlib/authentication/signedheaderauth'
-require 'openssl'
+require "uri"
+require "net/http"
+require "mixlib/authentication/signedheaderauth"
+require "openssl"
class Chef
# == Chef::CookbookSiteStreamingUploader
@@ -31,7 +31,7 @@ class Chef
# inspired by http://stanislavvitvitskiy.blogspot.com/2008/12/multipart-post-in-ruby.html
class CookbookSiteStreamingUploader
- DefaultHeaders = { 'accept' => 'application/json', 'x-chef-version' => ::Chef::VERSION }
+ DefaultHeaders = { "accept" => "application/json", "x-chef-version" => ::Chef::VERSION } # rubocop:disable Style/ConstantName
class << self
@@ -73,11 +73,10 @@ class Chef
end
def make_request(http_verb, to_url, user_id, secret_key_filename, params = {}, headers = {})
- boundary = '----RubyMultipartClient' + rand(1000000).to_s + 'ZZZZZ'
+ boundary = "----RubyMultipartClient" + rand(1000000).to_s + "ZZZZZ"
parts = []
content_file = nil
- timestamp = Time.now.utc.iso8601
secret_key = OpenSSL::PKey::RSA.new(File.read(secret_key_filename))
unless params.nil? || params.empty?
@@ -114,14 +113,14 @@ class Chef
# TODO: tim: 2009-12-28: It'd be nice to remove this special case, and
# always hash the entire request body. In the file case it would just be
# expanded multipart text - the entire body of the POST.
- content_body = parts.inject("") { |result,part| result + part.read(0, part.size) }
+ content_body = parts.inject("") { |result, part| result + part.read(0, part.size) }
content_file.rewind if content_file # we consumed the file for the above operation, so rewind it.
signing_options = {
- :http_method=>http_verb,
- :path=>url.path,
- :user_id=>user_id,
- :timestamp=>timestamp}
+ :http_method => http_verb,
+ :path => url.path,
+ :user_id => user_id,
+ :timestamp => timestamp }
(content_file && signing_options[:file] = content_file) || (signing_options[:body] = (content_body || ""))
headers.merge!(Mixlib::Authentication::SignedHeaderAuth.signing_object(signing_options).sign(secret_key))
@@ -129,7 +128,7 @@ class Chef
content_file.rewind if content_file
# net/http doesn't like symbols for header keys, so we'll to_s each one just in case
- headers = DefaultHeaders.merge(Hash[*headers.map{ |k,v| [k.to_s, v] }.flatten])
+ headers = DefaultHeaders.merge(Hash[*headers.map { |k, v| [k.to_s, v] }.flatten])
req = case http_verb
when :put
@@ -138,7 +137,7 @@ class Chef
Net::HTTP::Post.new(url.path, headers)
end
req.content_length = body_stream.size
- req.content_type = 'multipart/form-data; boundary=' + boundary unless parts.empty?
+ req.content_type = "multipart/form-data; boundary=" + boundary unless parts.empty?
req.body_stream = body_stream
http = Chef::HTTP::BasicClient.new(url).http_client
@@ -150,11 +149,11 @@ class Chef
alias :to_s :body
# BUGBUG this makes the response compatible with what respsonse_steps expects to test headers (response.headers[] -> response[])
- def headers
+ def headers # rubocop:disable Lint/NestedMethodDefinition
self
end
- def status
+ def status # rubocop:disable Lint/NestedMethodDefinition
code.to_i
end
end
@@ -201,12 +200,12 @@ class Chef
end
def size
- @parts.inject(0) {|size, part| size + part.size}
+ @parts.inject(0) { |size, part| size + part.size }
end
def read(how_much, dst_buf = nil)
if @part_no >= @parts.size
- dst_buf.replace('') if dst_buf
+ dst_buf.replace("") if dst_buf
return dst_buf
end
@@ -229,14 +228,14 @@ class Chef
next_part = read(how_much_next_part)
result = current_part + if next_part
next_part
- else
- ''
- end
+ else
+ ""
+ end
else
@part_offset += how_much_current_part
result = current_part
end
- dst_buf ? dst_buf.replace(result || '') : result
+ dst_buf ? dst_buf.replace(result || "") : result
end
end
diff --git a/lib/chef/cookbook_uploader.rb b/lib/chef/cookbook_uploader.rb
index f24ce2cd56..bb75234563 100644
--- a/lib/chef/cookbook_uploader.rb
+++ b/lib/chef/cookbook_uploader.rb
@@ -1,14 +1,15 @@
-require 'set'
-require 'chef/exceptions'
-require 'chef/knife/cookbook_metadata'
-require 'chef/digester'
-require 'chef/cookbook_manifest'
-require 'chef/cookbook_version'
-require 'chef/cookbook/syntax_check'
-require 'chef/cookbook/file_system_file_vendor'
-require 'chef/util/threaded_job_queue'
-require 'chef/sandbox'
+require "set"
+require "chef/exceptions"
+require "chef/knife/cookbook_metadata"
+require "chef/digester"
+require "chef/cookbook_manifest"
+require "chef/cookbook_version"
+require "chef/cookbook/syntax_check"
+require "chef/cookbook/file_system_file_vendor"
+require "chef/util/threaded_job_queue"
+require "chef/sandbox"
+require "chef/server_api"
class Chef
class CookbookUploader
@@ -31,15 +32,15 @@ class Chef
# uploading the cookbook. This allows frozen CookbookVersion
# documents on the server to be overwritten (otherwise a 409 is
# returned by the server)
- # * :rest A Chef::REST object that you have configured the way you like it.
+ # * :rest A Chef::ServerAPI object that you have configured the way you like it.
# If you don't provide this, one will be created using the values
# in Chef::Config.
# * :concurrency An integer that decided how many threads will be used to
# perform concurrent uploads
- def initialize(cookbooks, opts={})
+ def initialize(cookbooks, opts = {})
@opts = opts
@cookbooks = Array(cookbooks)
- @rest = opts[:rest] || Chef::REST.new(Chef::Config[:chef_server_url])
+ @rest = opts[:rest] || Chef::ServerAPI.new(Chef::Config[:chef_server_url])
@concurrency = opts[:concurrency] || 10
@policy_mode = opts[:policy_mode] || false
end
@@ -54,7 +55,7 @@ class Chef
checksum_files.merge!(cb.checksums)
end
- checksums = checksum_files.inject({}){|memo,elt| memo[elt.first]=nil ; memo}
+ checksums = checksum_files.inject({}) { |memo, elt| memo[elt.first] = nil; memo }
new_sandbox = rest.post("sandboxes", { :checksums => checksums })
Chef::Log.info("Uploading files")
@@ -64,11 +65,11 @@ class Chef
checksums_to_upload = Set.new
# upload the new checksums and commit the sandbox
- new_sandbox['checksums'].each do |checksum, info|
- if info['needs_upload'] == true
+ new_sandbox["checksums"].each do |checksum, info|
+ if info["needs_upload"] == true
checksums_to_upload << checksum
Chef::Log.info("Uploading #{checksum_files[checksum]} (checksum hex = #{checksum}) to #{info['url']}")
- queue << uploader_function_for(checksum_files[checksum], checksum, info['url'], checksums_to_upload)
+ queue << uploader_function_for(checksum_files[checksum], checksum, info["url"], checksums_to_upload)
else
Chef::Log.debug("#{checksum_files[checksum]} has not changed")
end
@@ -76,13 +77,13 @@ class Chef
queue.process(@concurrency)
- sandbox_url = new_sandbox['uri']
+ sandbox_url = new_sandbox["uri"]
Chef::Log.debug("Committing sandbox")
# Retry if S3 is claims a checksum doesn't exist (the eventual
# in eventual consistency)
retries = 0
begin
- rest.put(sandbox_url, {:is_completed => true})
+ rest.put(sandbox_url, { :is_completed => true })
rescue Net::HTTPServerException => e
if e.message =~ /^400/ && (retries += 1) <= 5
sleep 2
@@ -119,10 +120,10 @@ class Chef
# but we need the base64 encoding for the content-md5
# header
checksum64 = Base64.encode64([checksum].pack("H*")).strip
- file_contents = File.open(file, "rb") {|f| f.read}
+ file_contents = File.open(file, "rb") { |f| f.read }
# Custom headers. 'content-type' disables JSON serialization of the request body.
- headers = { 'content-type' => 'application/x-binary', 'content-md5' => checksum64, "accept" => 'application/json' }
+ headers = { "content-type" => "application/x-binary", "content-md5" => checksum64, "accept" => "application/json" }
begin
rest.put(url, file_contents, headers)
diff --git a/lib/chef/cookbook_version.rb b/lib/chef/cookbook_version.rb
index 0e9617f98c..2037b5f972 100644
--- a/lib/chef/cookbook_version.rb
+++ b/lib/chef/cookbook_version.rb
@@ -1,10 +1,10 @@
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright 2008-2015 Chef Software, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,12 +19,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/log'
-require 'chef/cookbook/file_vendor'
-require 'chef/cookbook/metadata'
-require 'chef/version_class'
-require 'chef/digester'
-require 'chef/cookbook_manifest'
+require "chef/log"
+require "chef/cookbook/file_vendor"
+require "chef/cookbook/metadata"
+require "chef/version_class"
+require "chef/digester"
+require "chef/cookbook_manifest"
+require "chef/server_api"
class Chef
@@ -39,6 +40,8 @@ class Chef
COOKBOOK_SEGMENTS = [ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates, :root_files ]
+ attr_accessor :all_files
+
attr_accessor :root_paths
attr_accessor :definition_filenames
attr_accessor :template_filenames
@@ -51,12 +54,12 @@ class Chef
attr_accessor :metadata_filenames
def status=(new_status)
- Chef.log_deprecation("Deprecated method `status' called. This method will be removed.")
+ Chef.deprecated(:internal_api, "Deprecated method `status' called. This method will be removed.")
@status = new_status
end
def status
- Chef.log_deprecation("Deprecated method `status' called. This method will be removed.")
+ Chef.deprecated(:internal_api, "Deprecated method `status' called. This method will be removed.")
@status
end
@@ -127,6 +130,8 @@ class Chef
@metadata_filenames = Array.new
@root_filenames = Array.new
+ @all_files = Array.new
+
# deprecated
@status = :ready
@file_vendor = nil
@@ -299,23 +304,29 @@ class Chef
if segment == :files || segment == :templates
error_message = "Cookbook '#{name}' (#{version}) does not contain a file at any of these locations:\n"
error_locations = if filename.is_a?(Array)
- filename.map{|name| " #{File.join(segment.to_s, name)}"}
- else
- [
- " #{segment}/#{node[:platform]}-#{node[:platform_version]}/#{filename}",
- " #{segment}/#{node[:platform]}/#{filename}",
- " #{segment}/default/#{filename}",
- " #{segment}/#{filename}",
- ]
- end
+ filename.map { |name| " #{File.join(segment.to_s, name)}" }
+ else
+ [
+ " #{segment}/#{node[:platform]}-#{node[:platform_version]}/#{filename}",
+ " #{segment}/#{node[:platform]}/#{filename}",
+ " #{segment}/default/#{filename}",
+ " #{segment}/#{filename}",
+ ]
+ end
error_message << error_locations.join("\n")
existing_files = segment_filenames(segment)
# Strip the root_dir prefix off all files for readability
- existing_files.map!{|path| path[root_dir.length+1..-1]} if root_dir
+ pretty_existing_files = existing_files.map do |path|
+ if root_dir
+ path[root_dir.length + 1..-1]
+ else
+ path
+ end
+ end
# Show the files that the cookbook does have. If the user made a typo,
# hopefully they'll see it here.
- unless existing_files.empty?
- error_message << "\n\nThis cookbook _does_ contain: ['#{existing_files.join("','")}']"
+ unless pretty_existing_files.empty?
+ error_message << "\n\nThis cookbook _does_ contain: ['#{pretty_existing_files.join("','")}']"
end
raise Chef::Exceptions::FileNotFound, error_message
else
@@ -324,12 +335,12 @@ class Chef
end
end
- def preferred_filename_on_disk_location(node, segment, filename, current_filepath=nil)
+ def preferred_filename_on_disk_location(node, segment, filename, current_filepath = nil)
manifest_record = preferred_manifest_record(node, segment, filename)
- if current_filepath && (manifest_record['checksum'] == self.class.checksum_cookbook_file(current_filepath))
+ if current_filepath && (manifest_record["checksum"] == self.class.checksum_cookbook_file(current_filepath))
nil
else
- file_vendor.get_filename(manifest_record['path'])
+ file_vendor.get_filename(manifest_record["path"])
end
end
@@ -368,7 +379,6 @@ class Chef
raise Chef::Exceptions::FileNotFound, "cookbook #{name} has no directory #{segment}/default/#{dirname}" unless best_pref
filenames_by_pref[best_pref]
-
end
# Determine the manifest records from the most specific directory
@@ -384,10 +394,10 @@ class Chef
# extract the preference part from the path.
if manifest_record_path =~ /(#{Regexp.escape(segment.to_s)}\/[^\/]+\/#{Regexp.escape(dirname)})\/.+$/
- # Note the specificy_dirname includes the segment and
- # dirname argument as above, which is what
- # preferences_for_path returns. It could be
- # "files/ubuntu-9.10/dirname", for example.
+ # Note the specificy_dirname includes the segment and
+ # dirname argument as above, which is what
+ # preferences_for_path returns. It could be
+ # "files/ubuntu-9.10/dirname", for example.
specificity_dirname = $1
# Record the specificity_dirname only if it's in the list of
@@ -412,43 +422,43 @@ class Chef
# only files and templates can be platform-specific
if segment.to_sym == :files || segment.to_sym == :templates
relative_search_path = if path.is_a?(Array)
- path
- else
- begin
- platform, version = Chef::Platform.find_platform_and_version(node)
- rescue ArgumentError => e
- # Skip platform/version if they were not found by find_platform_and_version
- if e.message =~ /Cannot find a (?:platform|version)/
- platform = "/unknown_platform/"
- version = "/unknown_platform_version/"
- else
- raise
- end
- end
-
- fqdn = node[:fqdn]
-
- # Break version into components, eg: "5.7.1" => [ "5.7.1", "5.7", "5" ]
- search_versions = []
- parts = version.to_s.split('.')
-
- parts.size.times do
- search_versions << parts.join('.')
- parts.pop
- end
-
- # Most specific to least specific places to find the path
- search_path = [ File.join("host-#{fqdn}", path) ]
- search_versions.each do |v|
- search_path << File.join("#{platform}-#{v}", path)
- end
- search_path << File.join(platform.to_s, path)
- search_path << File.join("default", path)
- search_path << path
-
- search_path
- end
- relative_search_path.map {|relative_path| File.join(segment.to_s, relative_path)}
+ path
+ else
+ begin
+ platform, version = Chef::Platform.find_platform_and_version(node)
+ rescue ArgumentError => e
+ # Skip platform/version if they were not found by find_platform_and_version
+ if e.message =~ /Cannot find a (?:platform|version)/
+ platform = "/unknown_platform/"
+ version = "/unknown_platform_version/"
+ else
+ raise
+ end
+ end
+
+ fqdn = node[:fqdn]
+
+ # Break version into components, eg: "5.7.1" => [ "5.7.1", "5.7", "5" ]
+ search_versions = []
+ parts = version.to_s.split(".")
+
+ parts.size.times do
+ search_versions << parts.join(".")
+ parts.pop
+ end
+
+ # Most specific to least specific places to find the path
+ search_path = [ File.join("host-#{fqdn}", path) ]
+ search_versions.each do |v|
+ search_path << File.join("#{platform}-#{v}", path)
+ end
+ search_path << File.join(platform.to_s, path)
+ search_path << File.join("default", path)
+ search_path << path
+
+ search_path
+ end
+ relative_search_path.map { |relative_path| File.join(segment.to_s, relative_path) }
else
if segment.to_sym == :root_files
[path]
@@ -459,11 +469,13 @@ class Chef
end
private :preferences_for_path
- def self.json_create(o)
- cookbook_version = new(o["cookbook_name"])
+ def self.from_hash(o)
+ cookbook_version = new(o["cookbook_name"] || o["name"])
+
# We want the Chef::Cookbook::Metadata object to always be inflated
cookbook_version.metadata = Chef::Cookbook::Metadata.from_hash(o["metadata"])
cookbook_version.manifest = o
+ cookbook_version.identifier = o["identifier"] if o.key?("identifier")
# We don't need the following step when we decide to stop supporting deprecated operators in the metadata (e.g. <<, >>)
cookbook_version.manifest["metadata"] = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(cookbook_version.metadata))
@@ -472,33 +484,32 @@ class Chef
cookbook_version
end
+ def self.json_create(o)
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::CookbookVersion#from_hash")
+ from_hash(o)
+ end
+
def self.from_cb_artifact_data(o)
- cookbook_version = new(o["name"])
- # We want the Chef::Cookbook::Metadata object to always be inflated
- cookbook_version.metadata = Chef::Cookbook::Metadata.from_hash(o["metadata"])
- cookbook_version.manifest = o
- cookbook_version.identifier = o["identifier"]
- cookbook_version
+ from_hash(o)
end
# @deprecated This method was used by the Ruby Chef Server and is no longer
# needed. There is no replacement.
- def generate_manifest_with_urls(&url_generator)
- Chef.log_deprecation("Deprecated method #generate_manifest_with_urls.")
+ def generate_manifest_with_urls
+ Chef.deprecated(:internal_api, "Deprecated method #generate_manifest_with_urls.")
rendered_manifest = manifest.dup
COOKBOOK_SEGMENTS.each do |segment|
if rendered_manifest.has_key?(segment)
rendered_manifest[segment].each do |manifest_record|
url_options = { :cookbook_name => name.to_s, :cookbook_version => version, :checksum => manifest_record["checksum"] }
- manifest_record["url"] = url_generator.call(url_options)
+ manifest_record["url"] = yield(url_options)
end
end
end
rendered_manifest
end
-
def to_hash
# TODO: this should become deprecated when the API for CookbookManifest becomes stable
cookbook_manifest.to_hash
@@ -509,7 +520,6 @@ class Chef
cookbook_manifest.to_json
end
-
def metadata_json_file
File.join(root_paths[0], "metadata.json")
end
@@ -539,26 +549,26 @@ class Chef
end
def chef_server_rest
- @chef_server_rest ||= self.chef_server_rest
+ @chef_server_rest ||= chef_server_rest
end
def self.chef_server_rest
- Chef::REST.new(Chef::Config[:chef_server_url])
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url])
end
def destroy
- chef_server_rest.delete_rest("cookbooks/#{name}/#{version}")
+ chef_server_rest.delete("cookbooks/#{name}/#{version}")
self
end
- def self.load(name, version="_latest")
+ def self.load(name, version = "_latest")
version = "_latest" if version == "latest"
- chef_server_rest.get_rest("cookbooks/#{name}/#{version}")
+ from_hash(chef_server_rest.get("cookbooks/#{name}/#{version}"))
end
# The API returns only a single version of each cookbook in the result from the cookbooks method
def self.list
- chef_server_rest.get_rest('cookbooks')
+ chef_server_rest.get("cookbooks")
end
# Alias latest_cookbooks as list
@@ -567,7 +577,7 @@ class Chef
end
def self.list_all_versions
- chef_server_rest.get_rest('cookbooks?num_versions=all')
+ chef_server_rest.get("cookbooks?num_versions=all")
end
##
@@ -577,7 +587,7 @@ class Chef
# [String]:: Array of cookbook versions, which are strings like 'x.y.z'
# nil:: if the cookbook doesn't exist. an error will also be logged.
def self.available_versions(cookbook_name)
- chef_server_rest.get_rest("cookbooks/#{cookbook_name}")[cookbook_name]["versions"].map do |cb|
+ chef_server_rest.get("cookbooks/#{cookbook_name}")[cookbook_name]["versions"].map do |cb|
cb["version"]
end
rescue Net::HTTPServerException => e
@@ -589,12 +599,12 @@ class Chef
end
end
- def <=>(o)
- raise Chef::Exceptions::CookbookVersionNameMismatch if self.name != o.name
+ def <=>(other)
+ raise Chef::Exceptions::CookbookVersionNameMismatch if name != other.name
# FIXME: can we change the interface to the Metadata class such
# that metadata.version returns a Chef::Version instance instead
# of a string?
- Chef::Version.new(self.version) <=> Chef::Version.new(o.version)
+ Chef::Version.new(version) <=> Chef::Version.new(other.version)
end
private
@@ -607,13 +617,13 @@ class Chef
preferences = preferences_for_path(node, segment, filename)
# in order of prefernce, look for the filename in the manifest
- preferences.find {|preferred_filename| manifest_records_by_path[preferred_filename] }
+ preferences.find { |preferred_filename| manifest_records_by_path[preferred_filename] }
end
# For each filename, produce a mapping of base filename (i.e. recipe name
# or attribute file) to on disk location
def filenames_by_name(filenames)
- filenames.select{|filename| filename =~ /\.rb$/}.inject({}){|memo, filename| memo[File.basename(filename, '.rb')] = filename ; memo }
+ filenames.select { |filename| filename =~ /\.rb$/ }.inject({}) { |memo, filename| memo[File.basename(filename, ".rb")] = filename; memo }
end
def file_vendor
diff --git a/lib/chef/daemon.rb b/lib/chef/daemon.rb
index e5abca29d8..70bdddf457 100644
--- a/lib/chef/daemon.rb
+++ b/lib/chef/daemon.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@junglist.gen.nz>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
# I love you Merb (lib/merb-core/server.rb)
-require 'chef/config'
-require 'chef/run_lock'
-require 'etc'
+require "chef/config"
+require "chef/run_lock"
+require "etc"
class Chef
class Daemon
@@ -61,7 +61,7 @@ class Chef
# String::
# Location of the pid file for @name
def pid_file
- Chef::Config[:pid_file] or "/tmp/#{@name}.pid"
+ Chef::Config[:pid_file] || "/tmp/#{@name}.pid"
end
# Suck the pid out of pid_file
@@ -82,7 +82,7 @@ class Chef
def change_privilege
Dir.chdir("/")
- if Chef::Config[:user] and Chef::Config[:group]
+ if Chef::Config[:user] && Chef::Config[:group]
Chef::Log.info("About to change privilege to #{Chef::Config[:user]}:#{Chef::Config[:group]}")
_change_privilege(Chef::Config[:user], Chef::Config[:group])
elsif Chef::Config[:user]
@@ -100,7 +100,7 @@ class Chef
# ==== Alternatives
# If group is left out, the user will be used (changing to user:user)
#
- def _change_privilege(user, group=user)
+ def _change_privilege(user, group = user)
uid, gid = Process.euid, Process.egid
begin
@@ -117,7 +117,7 @@ class Chef
return false
end
- if (uid != target_uid) or (gid != target_gid)
+ if (uid != target_uid) || (gid != target_gid)
Process.initgroups(user, target_gid)
Process::GID.change_privilege(target_gid)
Process::UID.change_privilege(target_uid)
diff --git a/lib/chef/data_bag.rb b/lib/chef/data_bag.rb
index 401ba6f63f..4bb656a2c8 100644
--- a/lib/chef/data_bag.rb
+++ b/lib/chef/data_bag.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,12 +18,13 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/data_bag_item'
-require 'chef/mash'
-require 'chef/json_compat'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/data_bag_item"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/server_api"
class Chef
class DataBag
@@ -43,11 +44,11 @@ class Chef
# Create a new Chef::DataBag
def initialize(chef_server_rest: nil)
- @name = ''
+ @name = ""
@chef_server_rest = chef_server_rest
end
- def name(arg=nil)
+ def name(arg = nil)
set_or_return(
:name,
arg,
@@ -57,9 +58,9 @@ class Chef
def to_hash
result = {
- 'name' => @name,
- 'json_class' => self.class.name,
- 'chef_type' => 'data_bag',
+ "name" => @name,
+ "json_class" => self.class.name,
+ "chef_type" => "data_bag",
}
result
end
@@ -70,22 +71,27 @@ class Chef
end
def chef_server_rest
- @chef_server_rest ||= Chef::REST.new(Chef::Config[:chef_server_url])
+ @chef_server_rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url])
end
def self.chef_server_rest
- Chef::REST.new(Chef::Config[:chef_server_url])
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url])
end
# Create a Chef::Role from JSON
def self.json_create(o)
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::DataBag#from_hash")
+ from_hash(o)
+ end
+
+ def self.from_hash(o)
bag = new
bag.name(o["name"])
bag
end
- def self.list(inflate=false)
- if Chef::Config[:solo]
+ def self.list(inflate = false)
+ if Chef::Config[:solo_legacy_mode]
paths = Array(Chef::Config[:data_bag_path])
names = []
paths.each do |path|
@@ -93,9 +99,10 @@ class Chef
raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{path}' is invalid"
end
- names += Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(path), "*")).map{|f|File.basename(f)}.sort
+ names += Dir.glob(File.join(
+ Chef::Util::PathHelper.escape_glob_dir(path), "*")).map { |f| File.basename(f) }.sort
end
- names.inject({}) {|h, n| h[n] = n; h}
+ names.inject({}) { |h, n| h[n] = n; h }
else
if inflate
# Can't search for all data bags like other objects, fall back to N+1 :(
@@ -104,14 +111,14 @@ class Chef
response
end
else
- Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data")
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("data")
end
end
end
# Load a Data Bag by name via either the RESTful API or local data_bag_path if run in solo mode
def self.load(name)
- if Chef::Config[:solo]
+ if Chef::Config[:solo_legacy_mode]
paths = Array(Chef::Config[:data_bag_path])
data_bag = {}
paths.each do |path|
@@ -119,8 +126,8 @@ class Chef
raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{path}' is invalid"
end
- Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(path, name.to_s), "*.json")).inject({}) do |bag, f|
- item = Chef::JSONCompat.from_json(IO.read(f))
+ Dir.glob(File.join(Chef::Util::PathHelper.escape_glob_dir(path, name.to_s), "*.json")).inject({}) do |bag, f|
+ item = Chef::JSONCompat.parse(IO.read(f))
# Check if we have multiple items with similar names (ids) and raise if their content differs
if data_bag.has_key?(item["id"]) && data_bag[item["id"]] != item
@@ -130,14 +137,14 @@ class Chef
end
end
end
- return data_bag
+ data_bag
else
- Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data/#{name}")
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("data/#{name}")
end
end
def destroy
- chef_server_rest.delete_rest("data/#{@name}")
+ chef_server_rest.delete("data/#{@name}")
end
# Save the Data Bag via RESTful API
@@ -156,7 +163,7 @@ class Chef
#create a data bag via RESTful API
def create
- chef_server_rest.post_rest("data", self)
+ chef_server_rest.post("data", self)
self
end
diff --git a/lib/chef/data_bag_item.rb b/lib/chef/data_bag_item.rb
index 31c9b69330..2bd27e3eef 100644
--- a/lib/chef/data_bag_item.rb
+++ b/lib/chef/data_bag_item.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,15 @@
# limitations under the License.
#
-require 'forwardable'
+require "forwardable"
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/data_bag'
-require 'chef/mash'
-require 'chef/json_compat'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/data_bag"
+require "chef/mash"
+require "chef/server_api"
+require "chef/json_compat"
class Chef
class DataBagItem
@@ -58,11 +59,11 @@ class Chef
end
def chef_server_rest
- @chef_server_rest ||= Chef::REST.new(Chef::Config[:chef_server_url])
+ @chef_server_rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url])
end
def self.chef_server_rest
- Chef::REST.new(Chef::Config[:chef_server_url])
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url])
end
def raw_data
@@ -81,7 +82,7 @@ class Chef
@raw_data = new_data
end
- def data_bag(arg=nil)
+ def data_bag(arg = nil)
set_or_return(
:data_bag,
arg,
@@ -94,10 +95,10 @@ class Chef
end
def object_name
- raise Exceptions::ValidationFailed, "You must have an 'id' or :id key in the raw data" unless raw_data.has_key?('id')
+ raise Exceptions::ValidationFailed, "You must have an 'id' or :id key in the raw data" unless raw_data.has_key?("id")
raise Exceptions::ValidationFailed, "You must have declared what bag this item belongs to!" unless data_bag
- id = raw_data['id']
+ id = raw_data["id"]
"data_bag_item_#{data_bag}_#{id}"
end
@@ -106,9 +107,9 @@ class Chef
end
def to_hash
- result = self.raw_data
+ result = raw_data.dup
result["chef_type"] = "data_bag_item"
- result["data_bag"] = self.data_bag
+ result["data_bag"] = data_bag.to_s
result
end
@@ -119,37 +120,39 @@ class Chef
"json_class" => self.class.name,
"chef_type" => "data_bag_item",
"data_bag" => data_bag,
- "raw_data" => raw_data
+ "raw_data" => raw_data,
}
Chef::JSONCompat.to_json(result, *a)
end
def self.from_hash(h)
+ h.delete("chef_type")
+ h.delete("json_class")
+
item = new
- item.raw_data = h
+ item.data_bag(h.delete("data_bag")) if h.key?("data_bag")
+ if h.key?("raw_data")
+ item.raw_data = Mash.new(h["raw_data"])
+ else
+ item.raw_data = h
+ end
item
end
# Create a Chef::DataBagItem from JSON
def self.json_create(o)
- bag_item = new
- bag_item.data_bag(o["data_bag"])
- o.delete("data_bag")
- o.delete("chef_type")
- o.delete("json_class")
- o.delete("name")
-
- bag_item.raw_data = Mash.new(o["raw_data"])
- bag_item
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::DataBagItem#from_hash")
+ from_hash(o)
end
# Load a Data Bag Item by name via either the RESTful API or local data_bag_path if run in solo mode
def self.load(data_bag, name)
- if Chef::Config[:solo]
+ if Chef::Config[:solo_legacy_mode]
bag = Chef::DataBag.load(data_bag)
+ raise Exceptions::InvalidDataBagItemID, "Item #{name} not found in data bag #{data_bag}. Other items found: #{bag.keys.join(", ")}" unless bag.include?(name)
item = bag[name]
else
- item = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data/#{data_bag}/#{name}")
+ item = Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("data/#{data_bag}/#{name}")
end
if item.kind_of?(DataBagItem)
@@ -161,37 +164,37 @@ class Chef
end
end
- def destroy(data_bag=data_bag(), databag_item=name)
- chef_server_rest.delete_rest("data/#{data_bag}/#{databag_item}")
+ def destroy(data_bag = self.data_bag(), databag_item = name)
+ chef_server_rest.delete("data/#{data_bag}/#{databag_item}")
end
# Save this Data Bag Item via RESTful API
- def save(item_id=@raw_data['id'])
+ def save(item_id = @raw_data["id"])
r = chef_server_rest
begin
if Chef::Config[:why_run]
Chef::Log.warn("In why-run mode, so NOT performing data bag item save.")
else
- r.put_rest("data/#{data_bag}/#{item_id}", self)
+ r.put("data/#{data_bag}/#{item_id}", self)
end
rescue Net::HTTPServerException => e
raise e unless e.response.code == "404"
- r.post_rest("data/#{data_bag}", self)
+ r.post("data/#{data_bag}", self)
end
self
end
# Create this Data Bag Item via RESTful API
def create
- chef_server_rest.post_rest("data/#{data_bag}", self)
+ chef_server_rest.post("data/#{data_bag}", self)
self
end
def ==(other)
other.respond_to?(:to_hash) &&
- other.respond_to?(:data_bag) &&
- (other.to_hash == to_hash) &&
- (other.data_bag.to_s == data_bag.to_s)
+ other.respond_to?(:data_bag) &&
+ (other.to_hash == to_hash) &&
+ (other.data_bag.to_s == data_bag.to_s)
end
# As a string
@@ -204,11 +207,11 @@ class Chef
end
def pretty_print(pretty_printer)
- pretty_printer.pp({"data_bag_item('#{data_bag}', '#{id}')" => self.to_hash})
+ pretty_printer.pp({ "data_bag_item('#{data_bag}', '#{id}')" => to_hash })
end
def id
- @raw_data['id']
+ @raw_data["id"]
end
end
diff --git a/lib/chef/data_collector.rb b/lib/chef/data_collector.rb
new file mode 100644
index 0000000000..0a92b800a6
--- /dev/null
+++ b/lib/chef/data_collector.rb
@@ -0,0 +1,489 @@
+#
+# Author:: Adam Leff (<adamleff@chef.io>)
+# Author:: Ryan Cragun (<ryan@chef.io>)
+#
+# Copyright:: Copyright 2012-2017, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "uri"
+require "chef/server_api"
+require "chef/http/simple_json"
+require "chef/event_dispatch/base"
+require "chef/data_collector/messages"
+require "chef/data_collector/resource_report"
+require "ostruct"
+require "set"
+
+class Chef
+
+ # == Chef::DataCollector
+ # Provides methods for determinine whether a reporter should be registered.
+ class DataCollector
+
+ # Whether or not to enable data collection:
+ # * always disabled for why run mode
+ # * disabled when the user sets `Chef::Config[:data_collector][:mode]` to a
+ # value that excludes the mode (client or solo) that we are running as
+ # * disabled in solo mode if the user did not configure the auth token
+ # * disabled if `Chef::Config[:data_collector][:server_url]` is set to a
+ # falsey value
+ def self.register_reporter?
+ if why_run?
+ Chef::Log.debug("data collector is disabled for why run mode")
+ return false
+ end
+ unless reporter_enabled_for_current_mode?
+ Chef::Log.debug("data collector is configured to only run in " \
+ "#{Chef::Config[:data_collector][:mode].inspect} modes, disabling it")
+ return false
+ end
+ unless data_collector_url_configured?
+ Chef::Log.debug("data collector URL is not configured, disabling data collector")
+ return false
+ end
+ if solo? && !token_auth_configured?
+ Chef::Log.debug("Data collector token must be configured to use Chef Automate data collector with Chef Solo")
+ end
+ if !solo? && token_auth_configured?
+ Chef::Log.warn("Data collector token authentication is not recommended for client-server mode" \
+ "Please upgrade Chef Server to 12.11.0 and remove the token from your config file " \
+ "to use key based authentication instead")
+ end
+ true
+ end
+
+ def self.data_collector_url_configured?
+ !!Chef::Config[:data_collector][:server_url]
+ end
+
+ def self.why_run?
+ !!Chef::Config[:why_run]
+ end
+
+ def self.token_auth_configured?
+ !!Chef::Config[:data_collector][:token]
+ end
+
+ def self.solo?
+ !!Chef::Config[:solo] || !!Chef::Config[:local_mode]
+ end
+
+ def self.reporter_enabled_for_current_mode?
+ if Chef::Config[:solo] || Chef::Config[:local_mode]
+ acceptable_modes = [:solo, :both]
+ else
+ acceptable_modes = [:client, :both]
+ end
+
+ acceptable_modes.include?(Chef::Config[:data_collector][:mode])
+ end
+
+ # == Chef::DataCollector::Reporter
+ # Provides an event handler that can be registered to report on Chef
+ # run data. Unlike the existing Chef::ResourceReporter event handler,
+ # the DataCollector handler is not tied to a Chef Server / Chef Reporting
+ # and exports its data through a webhook-like mechanism to a configured
+ # endpoint.
+ class Reporter < EventDispatch::Base
+ attr_reader :all_resource_reports, :status, :exception, :error_descriptions,
+ :expanded_run_list, :run_context, :run_status, :http,
+ :current_resource_report, :enabled, :deprecations
+
+ def initialize
+ validate_data_collector_server_url!
+
+ @all_resource_reports = []
+ @current_resource_loaded = nil
+ @error_descriptions = {}
+ @expanded_run_list = {}
+ @deprecations = Set.new
+ @enabled = true
+
+ @http = setup_http_client
+ end
+
+ # see EventDispatch::Base#run_started
+ # Upon receipt, we will send our run start message to the
+ # configured DataCollector endpoint. Depending on whether
+ # the user has configured raise_on_failure, if we cannot
+ # send the message, we will either disable the DataCollector
+ # Reporter for the duration of this run, or we'll raise an
+ # exception.
+ def run_started(current_run_status)
+ update_run_status(current_run_status)
+
+ disable_reporter_on_error do
+ send_to_data_collector(
+ Chef::DataCollector::Messages.run_start_message(current_run_status)
+ )
+ end
+ end
+
+ # see EventDispatch::Base#run_completed
+ # Upon receipt, we will send our run completion message to the
+ # configured DataCollector endpoint.
+ def run_completed(node)
+ send_run_completion(status: "success")
+ end
+
+ # see EventDispatch::Base#run_failed
+ def run_failed(exception)
+ send_run_completion(status: "failure")
+ end
+
+ # see EventDispatch::Base#converge_start
+ # Upon receipt, we stash the run_context for use at the
+ # end of the run in order to determine what resource+action
+ # combinations have not yet fired so we can report on
+ # unprocessed resources.
+ def converge_start(run_context)
+ @run_context = run_context
+ end
+
+ # see EventDispatch::Base#converge_complete
+ # At the end of the converge, we add any unprocessed resources
+ # to our report list.
+ def converge_complete
+ detect_unprocessed_resources
+ end
+
+ # see EventDispatch::Base#converge_failed
+ # At the end of the converge, we add any unprocessed resources
+ # to our report list
+ def converge_failed(exception)
+ detect_unprocessed_resources
+ end
+
+ # see EventDispatch::Base#resource_current_state_loaded
+ # Create a new ResourceReport instance that we'll use to track
+ # the state of this resource during the run. Nested resources are
+ # ignored as they are assumed to be an inline resource of a custom
+ # resource, and we only care about tracking top-level resources.
+ def resource_current_state_loaded(new_resource, action, current_resource)
+ return if nested_resource?(new_resource)
+ initialize_resource_report_if_needed(new_resource, action, current_resource)
+ end
+
+ # see EventDispatch::Base#resource_up_to_date
+ # Mark our ResourceReport status accordingly
+ def resource_up_to_date(new_resource, action)
+ initialize_resource_report_if_needed(new_resource, action)
+ current_resource_report.up_to_date unless nested_resource?(new_resource)
+ end
+
+ # see EventDispatch::Base#resource_skipped
+ # If this is a top-level resource, we create a ResourceReport
+ # instance (because a skipped resource does not trigger the
+ # resource_current_state_loaded event), and flag it as skipped.
+ def resource_skipped(new_resource, action, conditional)
+ return if nested_resource?(new_resource)
+
+ initialize_resource_report_if_needed(new_resource, action)
+ current_resource_report.skipped(conditional)
+ end
+
+ # see EventDispatch::Base#resource_updated
+ # Flag the current ResourceReport instance as updated (as long as it's
+ # a top-level resource).
+ def resource_updated(new_resource, action)
+ initialize_resource_report_if_needed(new_resource, action)
+ current_resource_report.updated unless nested_resource?(new_resource)
+ end
+
+ # see EventDispatch::Base#resource_failed
+ # Flag the current ResourceReport as failed and supply the exception as
+ # long as it's a top-level resource, and update the run error text
+ # with the proper Formatter.
+ def resource_failed(new_resource, action, exception)
+ initialize_resource_report_if_needed(new_resource, action)
+ current_resource_report.failed(exception) unless nested_resource?(new_resource)
+ update_error_description(
+ Formatters::ErrorMapper.resource_failed(
+ new_resource,
+ action,
+ exception
+ ).for_json
+ )
+ end
+
+ # see EventDispatch::Base#resource_completed
+ # Mark the ResourceReport instance as finished (for timing details).
+ # This marks the end of this resource during this run.
+ def resource_completed(new_resource)
+ if current_resource_report && !nested_resource?(new_resource)
+ current_resource_report.finish
+ add_resource_report(current_resource_report)
+ clear_current_resource_report
+ end
+ end
+
+ # see EventDispatch::Base#run_list_expanded
+ # The expanded run list is stored for later use by the run_completed
+ # event and message.
+ def run_list_expanded(run_list_expansion)
+ @expanded_run_list = run_list_expansion
+ end
+
+ # see EventDispatch::Base#run_list_expand_failed
+ # The run error text is updated with the output of the appropriate
+ # formatter.
+ def run_list_expand_failed(node, exception)
+ update_error_description(
+ Formatters::ErrorMapper.run_list_expand_failed(
+ node,
+ exception
+ ).for_json
+ )
+ end
+
+ # see EventDispatch::Base#cookbook_resolution_failed
+ # The run error text is updated with the output of the appropriate
+ # formatter.
+ def cookbook_resolution_failed(expanded_run_list, exception)
+ update_error_description(
+ Formatters::ErrorMapper.cookbook_resolution_failed(
+ expanded_run_list,
+ exception
+ ).for_json
+ )
+ end
+
+ # see EventDispatch::Base#cookbook_sync_failed
+ # The run error text is updated with the output of the appropriate
+ # formatter.
+ def cookbook_sync_failed(cookbooks, exception)
+ update_error_description(
+ Formatters::ErrorMapper.cookbook_sync_failed(
+ cookbooks,
+ exception
+ ).for_json
+ )
+ end
+
+ # see EventDispatch::Base#deprecation
+ # Append a received deprecation to the list of deprecations
+ def deprecation(message, location = caller(2..2)[0])
+ add_deprecation(message.message, message.url, location)
+ end
+
+ private
+
+ # Selects the type of HTTP client to use based on whether we are using
+ # token-based or signed header authentication. Token authentication is
+ # intended to be used primarily for Chef Solo in which case no signing
+ # key will be available (in which case `Chef::ServerAPI.new()` would
+ # raise an exception.
+ def setup_http_client
+ if data_collector_token.nil?
+ Chef::ServerAPI.new(data_collector_server_url, validate_utf8: false)
+ else
+ Chef::HTTP::SimpleJSON.new(data_collector_server_url, validate_utf8: false)
+ end
+ end
+
+ #
+ # Yields to the passed-in block (which is expected to be some interaction
+ # with the DataCollector endpoint). If some communication failure occurs,
+ # either disable any future communications to the DataCollector endpoint, or
+ # raise an exception (if the user has set
+ # Chef::Config.data_collector.raise_on_failure to true.)
+ #
+ # @param block [Proc] A ruby block to run. Ignored if a command is given.
+ #
+ def disable_reporter_on_error
+ yield
+ rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
+ Errno::ECONNREFUSED, EOFError, Net::HTTPBadResponse,
+ Net::HTTPHeaderSyntaxError, Net::ProtocolError, OpenSSL::SSL::SSLError,
+ Errno::EHOSTDOWN => e
+ disable_data_collector_reporter
+ code = if e.respond_to?(:response) && e.response.code
+ e.response.code.to_s
+ else
+ "Exception Code Empty"
+ end
+
+ msg = "Error while reporting run start to Data Collector. " \
+ "URL: #{data_collector_server_url} " \
+ "Exception: #{code} -- #{e.message} "
+
+ if Chef::Config[:data_collector][:raise_on_failure]
+ Chef::Log.error(msg)
+ raise
+ else
+ # Make the message non-scary for folks who don't have automate:
+ msg << " (This is normal if you do not have Chef Automate)"
+ Chef::Log.info(msg)
+ end
+ end
+
+ def send_to_data_collector(message)
+ return unless data_collector_accessible?
+
+ http.post(nil, message, headers)
+ end
+
+ #
+ # Send any messages to the DataCollector endpoint that are necessary to
+ # indicate the run has completed. Currently, two messages are sent:
+ #
+ # - An "action" message with the node object indicating it's been updated
+ # - An "run_converge" (i.e. RunEnd) message with details about the run,
+ # what resources were modified/up-to-date/skipped, etc.
+ #
+ # @param opts [Hash] Additional details about the run, such as its success/failure.
+ #
+ def send_run_completion(opts)
+ # If run_status is nil we probably failed before the client triggered
+ # the run_started callback. In this case we'll skip updating because
+ # we have nothing to report.
+ return unless run_status
+
+ send_to_data_collector(
+ Chef::DataCollector::Messages.run_end_message(
+ run_status: run_status,
+ expanded_run_list: expanded_run_list,
+ resources: all_resource_reports,
+ status: opts[:status],
+ error_descriptions: error_descriptions,
+ deprecations: deprecations.to_a
+ )
+ )
+ end
+
+ def headers
+ headers = { "Content-Type" => "application/json" }
+
+ unless data_collector_token.nil?
+ headers["x-data-collector-token"] = data_collector_token
+ headers["x-data-collector-auth"] = "version=1.0"
+ end
+
+ headers
+ end
+
+ def data_collector_server_url
+ Chef::Config[:data_collector][:server_url]
+ end
+
+ def data_collector_token
+ Chef::Config[:data_collector][:token]
+ end
+
+ def add_resource_report(resource_report)
+ @all_resource_reports << OpenStruct.new(
+ resource: resource_report.new_resource,
+ action: resource_report.action,
+ report_data: resource_report.to_hash
+ )
+ end
+
+ def disable_data_collector_reporter
+ @enabled = false
+ end
+
+ def data_collector_accessible?
+ @enabled
+ end
+
+ def update_run_status(run_status)
+ @run_status = run_status
+ end
+
+ def update_error_description(discription_hash)
+ @error_descriptions = discription_hash
+ end
+
+ def add_deprecation(message, url, location)
+ @deprecations << { message: message, url: url, location: location }
+ end
+
+ def initialize_resource_report_if_needed(new_resource, action, current_resource = nil)
+ return unless current_resource_report.nil?
+ @current_resource_report = create_resource_report(new_resource, action, current_resource)
+ end
+
+ def create_resource_report(new_resource, action, current_resource = nil)
+ Chef::DataCollector::ResourceReport.new(
+ new_resource,
+ action,
+ current_resource
+ )
+ end
+
+ def clear_current_resource_report
+ @current_resource_report = nil
+ end
+
+ def detect_unprocessed_resources
+ # create a Hash (for performance reasons, rather than an Array) containing all
+ # resource+action combinations from the Resource Collection
+ #
+ # We use the object ID instead of the resource itself in the Hash key because
+ # we currently allow users to create a property called "hash" which creates
+ # a #hash instance method on the resource. Ruby expects that to be a Fixnum,
+ # so bad things happen when adding an object to an Array or a Hash if it's not.
+ collection_resources = {}
+ run_context.resource_collection.all_resources.each do |resource|
+ Array(resource.action).each do |action|
+ collection_resources[[resource.__id__, action]] = resource
+ end
+ end
+
+ # Delete from the Hash any resource+action combination we have
+ # already processed.
+ all_resource_reports.each do |report|
+ collection_resources.delete([report.resource.__id__, report.action])
+ end
+
+ # The items remaining in the Hash are unprocessed resource+actions,
+ # so we'll create new resource reports for them which default to
+ # a state of "unprocessed".
+ collection_resources.each do |key, resource|
+ # The Hash key is an array of the Resource's object ID and the action.
+ # We need to pluck out the action.
+ add_resource_report(create_resource_report(resource, key[1]))
+ end
+ end
+
+ # If we are getting messages about a resource while we are in the middle of
+ # another resource's update, we assume that the nested resource is just the
+ # implementation of a provider, and we want to hide it from the reporting
+ # output.
+ def nested_resource?(new_resource)
+ @current_resource_report && @current_resource_report.new_resource != new_resource
+ end
+
+ def validate_data_collector_server_url!
+ if data_collector_server_url.empty?
+ raise Chef::Exceptions::ConfigurationError,
+ "Chef::Config[:data_collector][:server_url] is empty. Please supply a valid URL."
+ end
+
+ begin
+ uri = URI(data_collector_server_url)
+ rescue URI::InvalidURIError
+ raise Chef::Exceptions::ConfigurationError, "Chef::Config[:data_collector][:server_url] (#{data_collector_server_url}) is not a valid URI."
+ end
+
+ if uri.host.nil?
+ raise Chef::Exceptions::ConfigurationError,
+ "Chef::Config[:data_collector][:server_url] (#{data_collector_server_url}) is a URI with no host. Please supply a valid URL."
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/data_collector/messages.rb b/lib/chef/data_collector/messages.rb
new file mode 100644
index 0000000000..c0683534a9
--- /dev/null
+++ b/lib/chef/data_collector/messages.rb
@@ -0,0 +1,98 @@
+#
+# Author:: Adam Leff (<adamleff@chef.io)
+# Author:: Ryan Cragun (<ryan@chef.io>)
+#
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "securerandom"
+require_relative "messages/helpers"
+
+class Chef
+ class DataCollector
+ module Messages
+ extend Helpers
+
+ #
+ # Message payload that is sent to the DataCollector server at the
+ # start of a Chef run.
+ #
+ # @param run_status [Chef::RunStatus] The RunStatus instance for this node/run.
+ #
+ # @return [Hash] A hash containing the run start message data.
+ #
+ def self.run_start_message(run_status)
+ {
+ "chef_server_fqdn" => chef_server_fqdn(run_status),
+ "entity_uuid" => node_uuid,
+ "id" => run_status.run_id,
+ "message_version" => "1.0.0",
+ "message_type" => "run_start",
+ "node_name" => run_status.node.name,
+ "organization_name" => organization,
+ "run_id" => run_status.run_id,
+ "source" => collector_source,
+ "start_time" => run_status.start_time.utc.iso8601,
+ }
+ end
+
+ #
+ # Message payload that is sent to the DataCollector server at the
+ # end of a Chef run.
+ #
+ # @param reporter_data [Hash] Data supplied by the Reporter, such as run_status, resource counts, etc.
+ #
+ # @return [Hash] A hash containing the run end message data.
+ #
+ def self.run_end_message(reporter_data)
+ run_status = reporter_data[:run_status]
+
+ message = {
+ "chef_server_fqdn" => chef_server_fqdn(run_status),
+ "entity_uuid" => node_uuid,
+ "expanded_run_list" => reporter_data[:expanded_run_list],
+ "id" => run_status.run_id,
+ "message_version" => "1.1.0",
+ "message_type" => "run_converge",
+ "node" => run_status.node,
+ "node_name" => run_status.node.name,
+ "organization_name" => organization,
+ "resources" => reporter_data[:resources].map(&:report_data),
+ "run_id" => run_status.run_id,
+ "run_list" => run_status.node.run_list.for_json,
+ "start_time" => run_status.start_time.utc.iso8601,
+ "end_time" => run_status.end_time.utc.iso8601,
+ "source" => collector_source,
+ "status" => reporter_data[:status],
+ "total_resource_count" => reporter_data[:resources].count,
+ "updated_resource_count" => reporter_data[:resources].select { |r| r.report_data["status"] == "updated" }.count,
+ "deprecations" => reporter_data[:deprecations],
+ }
+
+ if run_status.exception
+ message["error"] = {
+ "class" => run_status.exception.class,
+ "message" => run_status.exception.message,
+ "backtrace" => run_status.exception.backtrace,
+ "description" => reporter_data[:error_descriptions],
+ }
+ end
+
+ message
+ end
+ end
+ end
+end
diff --git a/lib/chef/data_collector/messages/helpers.rb b/lib/chef/data_collector/messages/helpers.rb
new file mode 100644
index 0000000000..f42ddaaa4e
--- /dev/null
+++ b/lib/chef/data_collector/messages/helpers.rb
@@ -0,0 +1,161 @@
+#
+# Author:: Adam Leff (<adamleff@chef.io)
+# Author:: Ryan Cragun (<ryan@chef.io>)
+#
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class DataCollector
+ module Messages
+ module Helpers
+ #
+ # Fully-qualified domain name of the Chef Server configured in Chef::Config
+ # If the chef_server_url cannot be parsed as a URI, the node["fqdn"] attribute
+ # will be returned, or "localhost" if the run_status is unavailable to us.
+ #
+ # @param run_status [Chef::RunStatus] The RunStatus object for this Chef Run.
+ #
+ # @return [String] FQDN of the configured Chef Server, or node/localhost if not found.
+ #
+ def chef_server_fqdn(run_status)
+ if !Chef::Config[:chef_server_url].nil?
+ URI(Chef::Config[:chef_server_url]).host
+ elsif !Chef::Config[:node_name].nil?
+ Chef::Config[:node_name]
+ else
+ "localhost"
+ end
+ end
+
+ #
+ # The organization name the node is associated with. For Chef Solo runs, a
+ # user-configured organization string is returned, or the string "chef_solo"
+ # if such a string is not configured.
+ #
+ # @return [String] Organization to which the node is associated
+ #
+ def organization
+ solo_run? ? data_collector_organization : chef_server_organization
+ end
+
+ #
+ # Returns the user-configured organization, or "chef_solo" if none is configured.
+ #
+ # This is only used when Chef is run in Solo mode.
+ #
+ # @return [String] Data-collector-specific organization used when running in Chef Solo
+ #
+ def data_collector_organization
+ Chef::Config[:data_collector][:organization] || "chef_solo"
+ end
+
+ #
+ # Return the organization assumed by the configured chef_server_url.
+ #
+ # We must parse this from the Chef::Config[:chef_server_url] because a node
+ # has no knowledge of an organization or to which organization is belongs.
+ #
+ # If we cannot determine the organization, we return "unknown_organization"
+ #
+ # @return [String] shortname of the Chef Server organization
+ #
+ def chef_server_organization
+ return "unknown_organization" unless Chef::Config[:chef_server_url]
+
+ Chef::Config[:chef_server_url].match(%r{/+organizations/+([a-z0-9][a-z0-9_-]{0,254})}).nil? ? "unknown_organization" : $1
+ end
+
+ #
+ # The source of the data collecting during this run, used by the
+ # DataCollector endpoint to determine if Chef was in Solo mode or not.
+ #
+ # @return [String] "chef_solo" if in Solo mode, "chef_client" if in Client mode
+ #
+ def collector_source
+ solo_run? ? "chef_solo" : "chef_client"
+ end
+
+ #
+ # If we're running in Solo (legacy) mode, or in Solo (formerly
+ # "Chef Client Local Mode"), we're considered to be in a "solo run".
+ #
+ # @return [Boolean] Whether we're in a solo run or not
+ #
+ def solo_run?
+ Chef::Config[:solo] || Chef::Config[:local_mode]
+ end
+
+ #
+ # Returns a UUID that uniquely identifies this node for reporting reasons.
+ #
+ # The node is read in from disk if it exists, or it's generated if it does
+ # does not exist.
+ #
+ # @return [String] UUID for the node
+ #
+ def node_uuid
+ read_node_uuid || generate_node_uuid
+ end
+
+ #
+ # Generates a UUID for the node via SecureRandom.uuid and writes out
+ # metadata file so the UUID persists between runs.
+ #
+ # @return [String] UUID for the node
+ #
+ def generate_node_uuid
+ uuid = SecureRandom.uuid
+ update_metadata("node_uuid", uuid)
+
+ uuid
+ end
+
+ #
+ # Reads in the node UUID from the node metadata file
+ #
+ # @return [String] UUID for the node
+ #
+ def read_node_uuid
+ metadata["node_uuid"]
+ end
+
+ #
+ # Returns the DataCollector metadata for this node
+ #
+ # If the metadata file does not exist in the file cache path,
+ # an empty hash will be returned.
+ #
+ # @return [Hash] DataCollector metadata for this node
+ #
+ def metadata
+ Chef::JSONCompat.parse(Chef::FileCache.load(metadata_filename))
+ rescue Chef::Exceptions::FileNotFound
+ {}
+ end
+
+ def update_metadata(key, value)
+ updated_metadata = metadata.tap { |x| x[key] = value }
+ Chef::FileCache.store(metadata_filename, Chef::JSONCompat.to_json(updated_metadata), 0644)
+ end
+
+ def metadata_filename
+ "data_collector_metadata.json"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/data_collector/resource_report.rb b/lib/chef/data_collector/resource_report.rb
new file mode 100644
index 0000000000..dcaf9c8e44
--- /dev/null
+++ b/lib/chef/data_collector/resource_report.rb
@@ -0,0 +1,95 @@
+#
+# Author:: Adam Leff (<adamleff@chef.io>)
+# Author:: Ryan Cragun (<ryan@chef.io>)
+#
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class DataCollector
+ class ResourceReport
+
+ attr_reader :action, :elapsed_time, :new_resource, :status
+ attr_accessor :conditional, :current_resource, :exception
+
+ def initialize(new_resource, action, current_resource = nil)
+ @new_resource = new_resource
+ @action = action
+ @current_resource = current_resource
+ @status = "unprocessed"
+ end
+
+ def skipped(conditional)
+ @status = "skipped"
+ @conditional = conditional
+ end
+
+ def updated
+ @status = "updated"
+ end
+
+ def failed(exception)
+ @current_resource = nil
+ @status = "failed"
+ @exception = exception
+ end
+
+ def up_to_date
+ @status = "up-to-date"
+ end
+
+ def finish
+ @elapsed_time = new_resource.elapsed_time
+ end
+
+ def elapsed_time_in_milliseconds
+ elapsed_time.nil? ? nil : (elapsed_time * 1000).to_i
+ end
+
+ def potentially_changed?
+ %w{updated failed}.include?(status)
+ end
+
+ def to_hash
+ hash = {
+ "type" => new_resource.resource_name.to_sym,
+ "name" => new_resource.name.to_s,
+ "id" => new_resource.identity.to_s,
+ "after" => new_resource.state_for_resource_reporter,
+ "before" => current_resource ? current_resource.state_for_resource_reporter : {},
+ "duration" => elapsed_time_in_milliseconds.to_s,
+ "delta" => new_resource.respond_to?(:diff) && potentially_changed? ? new_resource.diff : "",
+ "ignore_failure" => new_resource.ignore_failure,
+ "result" => action.to_s,
+ "status" => status,
+ }
+
+ if new_resource.cookbook_name
+ hash["cookbook_name"] = new_resource.cookbook_name
+ hash["cookbook_version"] = new_resource.cookbook_version.version
+ hash["recipe_name"] = new_resource.recipe_name
+ end
+
+ hash["conditional"] = conditional.to_text if status == "skipped"
+ hash["error_message"] = exception.message unless exception.nil?
+
+ hash
+ end
+ alias :to_h :to_hash
+ alias :for_json :to_hash
+ end
+ end
+end
diff --git a/lib/chef/decorator.rb b/lib/chef/decorator.rb
new file mode 100644
index 0000000000..ac0f8fdfbb
--- /dev/null
+++ b/lib/chef/decorator.rb
@@ -0,0 +1,81 @@
+#--
+# Copyright:: Copyright 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "delegate"
+
+class Chef
+ class Decorator < SimpleDelegator
+ NULL = ::Object.new
+
+ def initialize(obj = NULL)
+ @__defined_methods__ = []
+ super unless obj.equal?(NULL)
+ end
+
+ # if we wrap a nil then decorator.nil? should be true
+ def nil?
+ __getobj__.nil?
+ end
+
+ # if we wrap a Hash then decorator.is_a?(Hash) should be true
+ def is_a?(klass)
+ __getobj__.is_a?(klass) || super
+ end
+
+ # if we wrap a Hash then decorator.kind_of?(Hash) should be true
+ def kind_of?(klass)
+ __getobj__.kind_of?(klass) || super
+ end
+
+ # reset our methods on the instance if the object changes under us (this also
+ # clears out the closure over the target we create in method_missing below)
+ def __setobj__(obj)
+ __reset_methods__
+ super
+ end
+
+ # this is the ruby 2.2/2.3 implementation of Delegator#method_missing() with
+ # adding the define_singleton_method call and @__defined_methods__ tracking
+ def method_missing(m, *args, &block)
+ r = true
+ target = __getobj__ { r = false }
+
+ if r && target.respond_to?(m)
+ # these next 4 lines are the patched code
+ define_singleton_method(m) do |*args, &block|
+ target.__send__(m, *args, &block)
+ end
+ @__defined_methods__.push(m)
+ target.__send__(m, *args, &block)
+ elsif ::Kernel.respond_to?(m, true)
+ ::Kernel.instance_method(m).bind(self).call(*args, &block)
+ else
+ super(m, *args, &block)
+ end
+ end
+
+ private
+
+ # used by __setobj__ to clear the methods we've built on the instance.
+ def __reset_methods__
+ @__defined_methods__.each do |m|
+ singleton_class.send(:undef_method, m)
+ end
+ @__defined_methods__ = []
+ end
+ end
+end
diff --git a/lib/chef/decorator/lazy.rb b/lib/chef/decorator/lazy.rb
new file mode 100644
index 0000000000..71a2151d65
--- /dev/null
+++ b/lib/chef/decorator/lazy.rb
@@ -0,0 +1,60 @@
+#--
+# Copyright:: Copyright 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/decorator"
+
+class Chef
+ class Decorator
+ # Lazy wrapper to delay construction of an object until a method is
+ # called against the object.
+ #
+ # @example
+ #
+ # def foo
+ # puts "allocated"
+ # "value"
+ # end
+ #
+ # a = Chef::Decorator::Lazy.new { foo }
+ #
+ # puts "started"
+ # a
+ # puts "still lazy"
+ # puts a
+ #
+ # outputs:
+ #
+ # started
+ # still lazy
+ # allocated
+ # value
+ #
+ # @since 12.10.x
+ class Lazy < Decorator
+ def initialize(&block)
+ super
+ @block = block
+ end
+
+ def __getobj__
+ __setobj__(@block.call) unless defined?(@delegate_sd_obj)
+ super
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/decorator/lazy_array.rb b/lib/chef/decorator/lazy_array.rb
new file mode 100644
index 0000000000..dc8ea832ee
--- /dev/null
+++ b/lib/chef/decorator/lazy_array.rb
@@ -0,0 +1,59 @@
+#--
+# Copyright:: Copyright 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/decorator/lazy"
+
+class Chef
+ class Decorator
+ # Lazy Array around Lazy Objects
+ #
+ # This only lazys access through `#[]`. In order to implement #each we need to
+ # know how many items we have and what their indexes are, so we'd have to evalute
+ # the proc which makes that impossible. You can call methods like #each and the
+ # decorator will forward the method, but item access will not be lazy.
+ #
+ # #at() and #fetch() are not implemented but technically could be.
+ #
+ # @example
+ # def foo
+ # puts "allocated"
+ # "value"
+ # end
+ #
+ # a = Chef::Decorator::LazyArray.new { [ foo ] }
+ #
+ # puts "started"
+ # a[0]
+ # puts "still lazy"
+ # puts a[0]
+ #
+ # outputs:
+ #
+ # started
+ # still lazy
+ # allocated
+ # value
+ #
+ # @since 12.10.x
+ class LazyArray < Lazy
+ def [](idx)
+ block = @block
+ Lazy.new { block.call[idx] }
+ end
+ end
+ end
+end
diff --git a/lib/chef/decorator/unchain.rb b/lib/chef/decorator/unchain.rb
new file mode 100644
index 0000000000..b1e1f9fce1
--- /dev/null
+++ b/lib/chef/decorator/unchain.rb
@@ -0,0 +1,59 @@
+class Chef
+ class Decorator < SimpleDelegator
+ #
+ # This decorator unchains method call chains and turns them into method calls
+ # with variable args. So this:
+ #
+ # node.set_unless["foo"]["bar"] = "baz"
+ #
+ # Can become:
+ #
+ # node.set_unless("foo", "bar", "baz")
+ #
+ # While this is a decorator it is not a Decorator and does not inherit because
+ # it deliberately does not need or want the method_missing magic. It is not legal
+ # to call anything on the intermediate values and only supports method chaining with
+ # #[] until the chain comes to an end with #[]=, so does not behave like a hash or
+ # array... e.g.
+ #
+ # node.default['foo'].keys is legal
+ # node.set_unless['foo'].keys is not legal now or ever
+ #
+ class Unchain
+ attr_accessor :__path__
+ attr_accessor :__method__
+
+ def initialize(obj, method)
+ @__path__ = []
+ @__method__ = method
+ @delegate_sd_obj = obj
+ end
+
+ def [](key)
+ __path__.push(key)
+ self
+ end
+
+ def []=(key, value)
+ __path__.push(key)
+ @delegate_sd_obj.public_send(__method__, *__path__, value)
+ end
+
+ # unfortunately we have to support method_missing for node.set_unless.foo.bar = 'baz' notation
+ def method_missing(symbol, *args)
+ if symbol == :to_ary
+ merged_attributes.send(symbol, *args)
+ elsif args.empty?
+ Chef.deprecated :attributes, %q{method access to node attributes (node.foo.bar) is deprecated and will be removed in Chef 13, please use bracket syntax (node["foo"]["bar"])}
+ self[symbol]
+ elsif symbol.to_s =~ /=$/
+ Chef.deprecated :attributes, %q{method setting of node attributes (node.foo="bar") is deprecated and will be removed in Chef 13, please use bracket syntax (node["foo"]="bar")}
+ key_to_set = symbol.to_s[/^(.+)=$/, 1]
+ self[key_to_set] = (args.length == 1 ? args[0] : args)
+ else
+ raise NoMethodError, "Undefined node attribute or method `#{symbol}' on `node'"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/delayed_evaluator.rb b/lib/chef/delayed_evaluator.rb
index 9f18a53445..25cd3a17b8 100644
--- a/lib/chef/delayed_evaluator.rb
+++ b/lib/chef/delayed_evaluator.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser <jkeiser@chef.io>
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/deprecated.rb b/lib/chef/deprecated.rb
new file mode 100644
index 0000000000..e5026d2317
--- /dev/null
+++ b/lib/chef/deprecated.rb
@@ -0,0 +1,250 @@
+#--
+# Copyright:: Copyright 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/mixin/convert_to_class_name"
+
+# Structured deprecations have a unique URL associated with them, which must exist before the deprecation is merged.
+class Chef
+ class Deprecated
+
+ class << self
+ include Chef::Mixin::ConvertToClassName
+
+ def create(type, message = nil, location = nil)
+ Chef::Deprecated.const_get(convert_to_class_name(type.to_s)).send(:new, message, location)
+ end
+ end
+
+ class Base
+ BASE_URL = "https://docs.chef.io/deprecations_"
+
+ attr_accessor :message, :location
+
+ def initialize(msg = nil, location = nil)
+ @message = msg if msg
+ @location = location if location
+ end
+
+ def link
+ "Please see #{url} for further details and information on how to correct this problem."
+ end
+
+ def url
+ "#{BASE_URL}#{target}"
+ end
+
+ # We know that the only time this gets called is by Chef::Log.deprecation,
+ # so special case
+ def <<(location)
+ @location = location
+ end
+
+ def inspect
+ "#{message} (CHEF-#{id})#{location}.\n#{link}"
+ end
+
+ def id
+ raise NotImplementedError, "subclasses of Chef::Deprecated::Base should define #id with a unique number"
+ end
+
+ def target
+ raise NotImplementedError, "subclasses of Chef::Deprecated::Base should define #target"
+ end
+ end
+
+ class JsonAutoInflate < Base
+ def id
+ 1
+ end
+
+ def target
+ "json_auto_inflate.html"
+ end
+ end
+
+ class ExitCode < Base
+ def id
+ 2
+ end
+
+ def target
+ "exit_code.html"
+ end
+ end
+
+ class ChefGemCompileTime < Base
+ def id
+ 3
+ end
+
+ def target
+ "chef_gem_compile_time.html"
+ end
+ end
+
+ class Attributes < Base
+ def id
+ 4
+ end
+
+ def target
+ "attributes.html"
+ end
+ end
+
+ class CustomResource < Base
+ def id
+ 5
+ end
+
+ def target
+ "custom_resource_cleanups.html"
+ end
+ end
+
+ class EasyInstall < Base
+ def id
+ 6
+ end
+
+ def target
+ "easy_install.html"
+ end
+ end
+
+ class VerifyFile < Base
+ def id
+ 7
+ end
+
+ def target
+ "verify_file.html"
+ end
+ end
+
+ class SupportsProperty < Base
+ def id
+ 8
+ end
+
+ def target
+ "supports_property.html"
+ end
+ end
+
+ class ChefRest < Base
+ def id
+ 9
+ end
+
+ def target
+ "chef_rest.html"
+ end
+ end
+
+ class PropertyNameCollision < Base
+ def id
+ 11
+ end
+
+ def target
+ "property_name_collision.html"
+ end
+ end
+
+ class LaunchdHashProperty < Base
+ def id
+ 12
+ end
+
+ def target
+ "launchd_hash_property.html"
+ end
+ end
+
+ class ChefPlatformMethods < Base
+ def id
+ 13
+ end
+
+ def target
+ "chef_platform_methods.html"
+ end
+ end
+
+ class RunCommand < Base
+ def id
+ 14
+ end
+
+ def target
+ "run_command.html"
+ end
+ end
+
+ class PackageMisc < Base
+ def id
+ 15
+ end
+
+ def target
+ "package_misc.html"
+ end
+ end
+
+ class ResourceCloning < Base
+ def id
+ 3694
+ end
+
+ def target
+ "resource_cloning.html"
+ end
+ end
+
+ class InternalApi < Base
+ def id
+ 0
+ end
+
+ def target
+ "internal_api.html"
+ end
+ end
+
+ class DnfPackageAllowDowngrade < Base
+ def id
+ 10
+ end
+
+ def target
+ "dnf_package_allow_downgrade.html"
+ end
+ end
+
+ class Generic < Base
+ def url
+ "https://docs.chef.io/chef_deprecations_client.html"
+ end
+
+ def inspect
+ "#{message}\nThis is a generic error message and should be updated to have a proper deprecation class. #{location}\nPlease see #{url} for an overview of Chef deprecations."
+ end
+ end
+
+ end
+end
diff --git a/lib/chef/deprecation/mixin/template.rb b/lib/chef/deprecation/mixin/template.rb
index 58a661c4bd..0c902123cf 100644
--- a/lib/chef/deprecation/mixin/template.rb
+++ b/lib/chef/deprecation/mixin/template.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'tempfile'
-require 'erubis'
+require "tempfile"
+require "erubis"
class Chef
module Deprecation
diff --git a/lib/chef/deprecation/provider/cookbook_file.rb b/lib/chef/deprecation/provider/cookbook_file.rb
index 92f5ce3623..d6e8a7566e 100644
--- a/lib/chef/deprecation/provider/cookbook_file.rb
+++ b/lib/chef/deprecation/provider/cookbook_file.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,6 @@
# limitations under the License.
#
-
class Chef
module Deprecation
module Provider
diff --git a/lib/chef/deprecation/provider/file.rb b/lib/chef/deprecation/provider/file.rb
index 31038ab3d8..edb0052fdf 100644
--- a/lib/chef/deprecation/provider/file.rb
+++ b/lib/chef/deprecation/provider/file.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/util/path_helper'
+require "chef/util/path_helper"
class Chef
module Deprecation
@@ -52,14 +52,14 @@ class Chef
suppress_resource_reporting = false
return [ "(diff output suppressed by config)" ] if Chef::Config[:diff_disabled]
- return [ "(no temp file with new content, diff output suppressed)" ] unless ::File.exists?(temp_path) # should never happen?
+ return [ "(no temp file with new content, diff output suppressed)" ] unless ::File.exists?(temp_path) # should never happen?
# solaris does not support diff -N, so create tempfile to diff against if we are creating a new file
target_path = if ::File.exists?(@current_resource.path)
@current_resource.path
else
- suppress_resource_reporting = true # suppress big diffs going to resource reporting service
- tempfile = Tempfile.new('chef-tempfile')
+ suppress_resource_reporting = true # suppress big diffs going to resource reporting service
+ tempfile = Tempfile.new("chef-tempfile")
tempfile.path
end
@@ -119,13 +119,13 @@ class Chef
description << diff_current_from_content(@new_resource.content)
converge_by(description) do
backup @new_resource.path if ::File.exists?(@new_resource.path)
- ::File.open(@new_resource.path, "w") {|f| f.write @new_resource.content }
+ ::File.open(@new_resource.path, "w") { |f| f.write @new_resource.content }
Chef::Log.info("#{@new_resource} contents updated")
end
end
end
- def update_new_file_state(path=@new_resource.path)
+ def update_new_file_state(path = @new_resource.path)
if !::File.directory?(path)
@new_resource.checksum(checksum(path))
end
@@ -163,7 +163,7 @@ class Chef
end
end
- def backup(file=nil)
+ def backup(file = nil)
file ||= @new_resource.path
if @new_resource.backup != false && @new_resource.backup > 0 && ::File.exist?(file)
time = Time.now
@@ -181,7 +181,7 @@ class Chef
# Clean up after the number of backups
slice_number = @new_resource.backup
- backup_files = Dir[Chef::Util::PathHelper.escape_glob(prefix, ".#{@new_resource.path}") + ".chef-*"].sort { |a,b| b <=> a }
+ backup_files = Dir[Chef::Util::PathHelper.escape_glob_dir(prefix, ".#{@new_resource.path}") + ".chef-*"].sort { |a, b| b <=> a }
if backup_files.length >= @new_resource.backup
remainder = backup_files.slice(slice_number..-1)
remainder.each do |backup_to_delete|
diff --git a/lib/chef/deprecation/provider/remote_directory.rb b/lib/chef/deprecation/provider/remote_directory.rb
index cc8026ec55..9b442651d7 100644
--- a/lib/chef/deprecation/provider/remote_directory.rb
+++ b/lib/chef/deprecation/provider/remote_directory.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2013-2015 Chef Software, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,7 +22,7 @@ class Chef
module RemoteDirectory
def directory_root_in_cookbook_cache
- Chef.log_deprecation "the Chef::Provider::RemoteDirectory#directory_root_in_cookbook_cache method is deprecated"
+ Chef.deprecated :internal_api, "the Chef::Provider::RemoteDirectory#directory_root_in_cookbook_cache method is deprecated"
@directory_root_in_cookbook_cache ||=
begin
@@ -33,17 +33,17 @@ class Chef
# List all excluding . and ..
def ls(path)
- files = Dir.glob(::File.join(Chef::Util::PathHelper.escape_glob(path), '**', '*'),
+ files = Dir.glob(::File.join(Chef::Util::PathHelper.escape_glob_dir(path), "**", "*"),
::File::FNM_DOTMATCH)
# Remove current directory and previous directory
files = files.reject do |name|
basename = Pathname.new(name).basename().to_s
- ['.', '..'].include?(basename)
+ [".", ".."].include?(basename)
end
# Clean all the paths... this is required because of the join
- files.map {|f| Chef::Util::PathHelper.cleanpath(f)}
+ files.map { |f| Chef::Util::PathHelper.cleanpath(f) }
end
end
diff --git a/lib/chef/deprecation/provider/remote_file.rb b/lib/chef/deprecation/provider/remote_file.rb
index c06a5cc695..aefb04752e 100644
--- a/lib/chef/deprecation/provider/remote_file.rb
+++ b/lib/chef/deprecation/provider/remote_file.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -56,7 +56,7 @@ class Chef
def source_file(source, current_checksum, &block)
if absolute_uri?(source)
fetch_from_uri(source, &block)
- elsif !Chef::Config[:solo]
+ elsif !Chef::Config[:solo_legacy_mode]
fetch_from_chef_server(source, current_checksum, &block)
else
fetch_from_local_cookbook(source, &block)
@@ -64,7 +64,7 @@ class Chef
end
def http_client_opts(source)
- opts={}
+ opts = {}
# CHEF-3140
# 1. If it's already compressed, trying to compress it more will
# probably be counter-productive.
@@ -73,7 +73,7 @@ class Chef
# which tricks Chef::REST into decompressing the response body. In this
# case you'd end up with a tar archive (no gzip) named, e.g., foo.tgz,
# which is not what you wanted.
- if @new_resource.path =~ /gz$/ or source =~ /gz$/
+ if @new_resource.path =~ /gz$/ || source =~ /gz$/
opts[:disable_gzip] = true
end
opts
diff --git a/lib/chef/deprecation/provider/template.rb b/lib/chef/deprecation/provider/template.rb
index 34e5f54b7e..ea5a880798 100644
--- a/lib/chef/deprecation/provider/template.rb
+++ b/lib/chef/deprecation/provider/template.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/deprecation/mixin/template'
+require "chef/deprecation/mixin/template"
class Chef
module Deprecation
diff --git a/lib/chef/deprecation/warnings.rb b/lib/chef/deprecation/warnings.rb
index 0b1ec2d5ed..f5feb91063 100644
--- a/lib/chef/deprecation/warnings.rb
+++ b/lib/chef/deprecation/warnings.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,12 +22,10 @@ class Chef
def add_deprecation_warnings_for(method_names)
method_names.each do |name|
- m = instance_method(name)
define_method(name) do |*args|
- message = []
- message << "Method '#{name}' of '#{self.class}' is deprecated. It will be removed in Chef 13."
- message << "Please update your cookbooks accordingly."
- Chef.log_deprecation(message)
+ message = "Method '#{name}' of '#{self.class}' is deprecated. It will be removed in Chef 13."
+ message << " Please update your cookbooks accordingly."
+ Chef.deprecated(:internal_api, message)
super(*args)
end
end
diff --git a/lib/chef/digester.rb b/lib/chef/digester.rb
index f2b496b785..6e4588a661 100644
--- a/lib/chef/digester.rb
+++ b/lib/chef/digester.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
# limitations under the License.
#
-require 'openssl'
-require 'singleton'
+require "openssl"
+require "singleton"
class Chef
class Digester
@@ -60,7 +60,7 @@ class Chef
private
def checksum_file(file, digest)
- File.open(file, 'rb') { |f| checksum_io(f, digest) }
+ File.open(file, "rb") { |f| checksum_io(f, digest) }
end
def checksum_io(io, digest)
diff --git a/lib/chef/dsl.rb b/lib/chef/dsl.rb
index 7717d99113..1fa0099e91 100644
--- a/lib/chef/dsl.rb
+++ b/lib/chef/dsl.rb
@@ -1,6 +1,6 @@
-require 'chef/dsl/recipe'
-require 'chef/dsl/platform_introspection'
-require 'chef/dsl/data_query'
-require 'chef/dsl/include_recipe'
-require 'chef/dsl/include_attribute'
-require 'chef/dsl/registry_helper'
+require "chef/dsl/recipe"
+require "chef/dsl/platform_introspection"
+require "chef/dsl/data_query"
+require "chef/dsl/include_recipe"
+require "chef/dsl/include_attribute"
+require "chef/dsl/registry_helper"
diff --git a/lib/chef/dsl/audit.rb b/lib/chef/dsl/audit.rb
index d1bf09b313..9ef798df91 100644
--- a/lib/chef/dsl/audit.rb
+++ b/lib/chef/dsl/audit.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tyler Ball (<tball@getchef.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Tyler Ball (<tball@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/exceptions'
+require "chef/exceptions"
class Chef
module DSL
@@ -38,9 +38,9 @@ class Chef
cookbook_name = self.cookbook_name
metadata = {
cookbook_name: cookbook_name,
- cookbook_version: self.run_context.cookbook_collection[cookbook_name].version,
- recipe_name: self.recipe_name,
- line_number: block.source_location[1]
+ cookbook_version: run_context.cookbook_collection[cookbook_name].version,
+ recipe_name: recipe_name,
+ line_number: block.source_location[1],
}
run_context.audits[name] = Struct.new(:args, :block, :metadata).new(args, block, metadata)
diff --git a/lib/chef/dsl/chef_provisioning.rb b/lib/chef/dsl/chef_provisioning.rb
new file mode 100644
index 0000000000..a91d297d02
--- /dev/null
+++ b/lib/chef/dsl/chef_provisioning.rb
@@ -0,0 +1,57 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ module DSL
+ # Lazy activation for the chef-provisioning gem. Specifically, we set up methods for
+ # each resource and DSL method in chef-provisioning which, when invoked, will
+ # require 'chef-provisioning' (which will define the actual method) and then call the
+ # method chef-provisioning defined.
+ module ChefProvisioning
+ %w{
+ add_machine_options
+ current_image_options
+ current_machine_options
+ load_balancer
+ machine_batch
+ machine_execute
+ machine_file
+ machine_image
+ machine
+ with_driver
+ with_image_options
+ with_machine_options
+ }.each do |method_name|
+ eval(<<-EOM, binding, __FILE__, __LINE__ + 1)
+ def #{method_name}(*args, &block)
+ Chef::DSL::ChefProvisioning.load_chef_provisioning
+ self.#{method_name}(*args, &block)
+ end
+ EOM
+ end
+
+ def self.load_chef_provisioning
+ # Remove all chef-provisioning methods; they will be added back in by chef-provisioning
+ public_instance_methods(false).each do |method_name|
+ remove_method(method_name)
+ end
+ require "chef/provisioning"
+ end
+ end
+ end
+end
diff --git a/lib/chef/dsl/cheffish.rb b/lib/chef/dsl/cheffish.rb
new file mode 100644
index 0000000000..03290b3674
--- /dev/null
+++ b/lib/chef/dsl/cheffish.rb
@@ -0,0 +1,65 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ module DSL
+ # Lazy activation for the cheffish gem. Specifically, we set up methods for
+ # each resource and DSL method in cheffish which, when invoked, will
+ # require 'cheffish' (which will define the actual method) and then call the
+ # method cheffish defined.
+ module Cheffish
+ %w{
+ chef_acl
+ chef_client
+ chef_container
+ chef_data_bag_item
+ chef_data_bag
+ chef_environment
+ chef_group
+ chef_mirror
+ chef_node
+ chef_organization
+ chef_role
+ chef_user
+ private_key
+ public_key
+ with_chef_data_bag
+ with_chef_environment
+ with_chef_data_bag_item_encryption
+ with_chef_server
+ with_chef_local_server
+ get_private_key
+ }.each do |method_name|
+ eval(<<-EOM, binding, __FILE__, __LINE__ + 1)
+ def #{method_name}(*args, &block)
+ Chef::DSL::Cheffish.load_cheffish
+ self.#{method_name}(*args, &block)
+ end
+ EOM
+ end
+
+ def self.load_cheffish
+ # Remove all cheffish methods; they will be added back in by cheffish
+ public_instance_methods(false).each do |method_name|
+ remove_method(method_name)
+ end
+ require "cheffish"
+ end
+ end
+ end
+end
diff --git a/lib/chef/dsl/core.rb b/lib/chef/dsl/core.rb
new file mode 100644
index 0000000000..d7c5b6a006
--- /dev/null
+++ b/lib/chef/dsl/core.rb
@@ -0,0 +1,52 @@
+#--
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/dsl/declare_resource"
+require "chef/dsl/universal"
+require "chef/mixin/notifying_block"
+require "chef/mixin/lazy_module_include"
+
+class Chef
+ module DSL
+ # Part of a family of DSL mixins.
+ #
+ # Chef::DSL::Recipe mixes into Recipes and LWRP Providers.
+ # - this does not target core chef resources and providers.
+ # - this is restricted to recipe/resource/provider context where a resource collection exists.
+ # - cookbook authors should typically include modules into here.
+ #
+ # Chef::DSL::Core mixes into Recipes, LWRP Providers and Core Providers
+ # - this adds cores providers on top of the Recipe DSL.
+ # - this is restricted to recipe/resource/provider context where a resource collection exists.
+ # - core chef authors should typically include modules into here.
+ #
+ # Chef::DSL::Universal mixes into Recipes, LWRP Resources+Providers, Core Resources+Providers, and Attributes files.
+ # - this adds resources and attributes files.
+ # - do not add helpers which manipulate the resource collection.
+ # - this is for general-purpose stuff that is useful nearly everywhere.
+ # - it also pollutes the namespace of nearly every context, watch out.
+ #
+ module Core
+ include Chef::DSL::Universal
+ include Chef::DSL::DeclareResource
+ include Chef::Mixin::NotifyingBlock
+ extend Chef::Mixin::LazyModuleInclude
+ end
+ end
+end
diff --git a/lib/chef/dsl/data_query.rb b/lib/chef/dsl/data_query.rb
index e36784271a..b966885724 100644
--- a/lib/chef/dsl/data_query.rb
+++ b/lib/chef/dsl/data_query.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'chef/search/query'
-require 'chef/data_bag'
-require 'chef/data_bag_item'
-require 'chef/encrypted_data_bag_item'
-require 'chef/encrypted_data_bag_item/check_encrypted'
+require "chef/search/query"
+require "chef/data_bag"
+require "chef/data_bag_item"
+require "chef/encrypted_data_bag_item"
+require "chef/encrypted_data_bag_item/check_encrypted"
class Chef
module DSL
@@ -55,7 +55,7 @@ class Chef
raise
end
- def data_bag_item(bag, item, secret=nil)
+ def data_bag_item(bag, item, secret = nil)
DataBag.validate_name!(bag.to_s)
DataBagItem.validate_id!(item)
@@ -73,7 +73,7 @@ class Chef
raise
end
end
-
+
item
rescue Exception
Log.error("Failed to load data bag item: #{bag.inspect} #{item.inspect}")
@@ -86,4 +86,4 @@ end
# **DEPRECATED**
# This used to be part of chef/mixin/language. Load the file to activate the deprecation code.
-require 'chef/mixin/language'
+require "chef/mixin/language"
diff --git a/lib/chef/dsl/declare_resource.rb b/lib/chef/dsl/declare_resource.rb
new file mode 100644
index 0000000000..e48d741c60
--- /dev/null
+++ b/lib/chef/dsl/declare_resource.rb
@@ -0,0 +1,295 @@
+#--
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/exceptions"
+
+class Chef
+ module DSL
+ module DeclareResource
+
+ # Helper for switching run_contexts. Allows for using :parent or :root in place of
+ # passing the run_context. Executes the block in the run_context. Returns the return
+ # value of the passed block.
+ #
+ # @param rc [Chef::RunContext,Symbol] Either :root, :parent or a Chef::RunContext
+ #
+ # @return return value of the block
+ #
+ # @example
+ # # creates/returns a 'service[foo]' resource in the root run_context
+ # resource = with_run_context(:root)
+ # edit_resource(:service, "foo") do
+ # action :nothing
+ # end
+ # end
+ #
+ def with_run_context(rc)
+ raise ArgumentError, "with_run_context is useless without a block" unless block_given?
+ old_run_context = @run_context
+ @run_context =
+ case rc
+ when Chef::RunContext
+ rc
+ when :root
+ run_context.root_run_context
+ when :parent
+ run_context.parent_run_context
+ else
+ raise ArgumentError, "bad argument to run_context helper, must be :root, :parent, or a Chef::RunContext"
+ end
+ yield
+ ensure
+ @run_context = old_run_context
+ end
+
+ # Lookup a resource in the resource collection by name and delete it. This
+ # will raise Chef::Exceptions::ResourceNotFound if the resource is not found.
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ #
+ # @return [Chef::Resource] The resource
+ #
+ # @example
+ # delete_resource!(:template, '/x/y.txy')
+ #
+ def delete_resource!(type, name, run_context: self.run_context)
+ run_context.resource_collection.delete("#{type}[#{name}]").tap do |resource|
+ # Purge any pending notifications too. This will not raise an exception
+ # if there are no notifications.
+ if resource
+ run_context.before_notification_collection.delete(resource.declared_key)
+ run_context.immediate_notification_collection.delete(resource.declared_key)
+ run_context.delayed_notification_collection.delete(resource.declared_key)
+ end
+ end
+ end
+
+ # Lookup a resource in the resource collection by name and delete it. Returns
+ # nil if the resource is not found and should not fail.
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ #
+ # @return [Chef::Resource] The resource
+ #
+ # @example
+ # delete_resource(:template, '/x/y.txy')
+ #
+ def delete_resource(type, name, run_context: self.run_context)
+ delete_resource!(type, name, run_context: run_context)
+ rescue Chef::Exceptions::ResourceNotFound
+ nil
+ end
+
+ # Lookup a resource in the resource collection by name and edit the resource. If the resource is not
+ # found this will raise Chef::Exceptions::ResourceNotFound. This is the correct API to use for
+ # "chef_rewind" functionality.
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ # @param resource_attrs_block A block that lets you set attributes of the
+ # resource (it is instance_eval'd on the resource instance).
+ #
+ # @return [Chef::Resource] The updated resource
+ #
+ # @example
+ # edit_resource!(:template, '/x/y.txy') do
+ # cookbook_name: cookbook_name
+ # end
+ #
+ def edit_resource!(type, name, created_at = nil, run_context: self.run_context, &resource_attrs_block)
+ resource = find_resource!(type, name, run_context: run_context)
+ if resource_attrs_block
+ if defined?(new_resource)
+ resource.instance_exec(new_resource, &resource_attrs_block)
+ else
+ resource.instance_exec(&resource_attrs_block)
+ end
+ end
+ resource
+ end
+
+ # Lookup a resource in the resource collection by name. If it exists,
+ # return it. If it does not exist, create it. This is a useful function
+ # for accumulator patterns. In CRUD terminology this is an "upsert" operation and is
+ # used to assert that the resource must exist with the specified properties.
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param created_at [String] The caller of the resource. Use `caller[0]`
+ # to get the caller of your function. Defaults to the caller of this
+ # function.
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ # @param resource_attrs_block A block that lets you set attributes of the
+ # resource (it is instance_eval'd on the resource instance).
+ #
+ # @return [Chef::Resource] The updated or created resource
+ #
+ # @example
+ # resource = edit_resource(:template, '/x/y.txy') do
+ # source "y.txy.erb"
+ # variables {}
+ # end
+ # resource.variables.merge!({ home: "/home/klowns" })
+ #
+ def edit_resource(type, name, created_at = nil, run_context: self.run_context, &resource_attrs_block)
+ edit_resource!(type, name, created_at, run_context: run_context, &resource_attrs_block)
+ rescue Chef::Exceptions::ResourceNotFound
+ declare_resource(type, name, created_at, run_context: run_context, &resource_attrs_block)
+ end
+
+ # Lookup a resource in the resource collection by name. If the resource is not
+ # found this will raise Chef::Exceptions::ResourceNotFound. This API is identical to the
+ # resources() call and while it is a synonym it is not intended to deprecate that call.
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ #
+ # @return [Chef::Resource] The updated resource
+ #
+ # @example
+ # resource = find_resource!(:template, '/x/y.txy')
+ #
+ def find_resource!(type, name, run_context: self.run_context)
+ raise ArgumentError, "find_resource! does not take a block" if block_given?
+ run_context.resource_collection.find(type => name)
+ end
+
+ # Lookup a resource in the resource collection by name. If the resource is not found
+ # the will be no exception raised and the call will return nil. If a block is given and
+ # no resource is found it will create the resource using the block, if the resource is
+ # found then the block will not be applied. The block version is similar to create_if_missing
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ #
+ # @return [Chef::Resource] The updated resource
+ #
+ # @example
+ # if ( find_resource(:template, '/x/y.txy') )
+ # # do something
+ # else
+ # # don't worry about the error
+ # end
+ #
+ # @example
+ # # this API can be used to return a resource from an outer run context, and will only create
+ # # an action :nothing service if one does not already exist.
+ # resource = with_run_context(:root) do
+ # find_resource(:service, 'whatever') do
+ # action :nothing
+ # end
+ # end
+ #
+ def find_resource(type, name, created_at: nil, run_context: self.run_context, &resource_attrs_block)
+ find_resource!(type, name, run_context: run_context)
+ rescue Chef::Exceptions::ResourceNotFound
+ if resource_attrs_block
+ declare_resource(type, name, created_at, run_context: run_context, &resource_attrs_block)
+ end # returns nil otherwise
+ end
+
+ # Instantiates a resource (via #build_resource), then adds it to the
+ # resource collection. Note that resource classes are looked up directly,
+ # so this will create the resource you intended even if the method name
+ # corresponding to that resource has been overridden.
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param created_at [String] The caller of the resource. Use `caller[0]`
+ # to get the caller of your function. Defaults to the caller of this
+ # function.
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ # @param resource_attrs_block A block that lets you set attributes of the
+ # resource (it is instance_eval'd on the resource instance).
+ #
+ # @return [Chef::Resource] The new resource.
+ #
+ # @example
+ # declare_resource(:file, '/x/y.txy', caller[0]) do
+ # action :delete
+ # end
+ # # Equivalent to
+ # file '/x/y.txt' do
+ # action :delete
+ # end
+ #
+ def declare_resource(type, name, created_at = nil, run_context: self.run_context, create_if_missing: false, &resource_attrs_block)
+ created_at ||= caller[0]
+
+ if create_if_missing
+ Chef::Log.deprecation "build_resource with a create_if_missing flag is deprecated, use edit_resource instead"
+ # midly goofy since we call edit_resource only to re-call ourselves, but that's why its deprecated...
+ return edit_resource(type, name, created_at, run_context: run_context, &resource_attrs_block)
+ end
+
+ resource = build_resource(type, name, created_at, &resource_attrs_block)
+
+ run_context.resource_collection.insert(resource, resource_type: type, instance_name: name)
+ resource
+ end
+
+ # Instantiate a resource of the given +type+ with the given +name+ and
+ # attributes as given in the +resource_attrs_block+.
+ #
+ # The resource is NOT added to the resource collection.
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param created_at [String] The caller of the resource. Use `caller[0]`
+ # to get the caller of your function. Defaults to the caller of this
+ # function.
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ # @param resource_attrs_block A block that lets you set attributes of the
+ # resource (it is instance_eval'd on the resource instance).
+ #
+ # @return [Chef::Resource] The new resource.
+ #
+ # @example
+ # build_resource(:file, '/x/y.txy', caller[0]) do
+ # action :delete
+ # end
+ #
+ def build_resource(type, name, created_at = nil, run_context: self.run_context, &resource_attrs_block)
+ created_at ||= caller[0]
+
+ # this needs to be lazy in order to avoid circular dependencies since ResourceBuilder
+ # will requires the entire provider+resolver universe
+ require "chef/resource_builder" unless defined?(Chef::ResourceBuilder)
+
+ Chef::ResourceBuilder.new(
+ type: type,
+ name: name,
+ created_at: created_at,
+ params: @params,
+ run_context: run_context,
+ cookbook_name: cookbook_name,
+ recipe_name: recipe_name,
+ enclosing_provider: is_a?(Chef::Provider) ? self : nil
+ ).build(&resource_attrs_block)
+ end
+ end
+ end
+end
diff --git a/lib/chef/dsl/definitions.rb b/lib/chef/dsl/definitions.rb
index 1358f67720..60b1cf6f61 100644
--- a/lib/chef/dsl/definitions.rb
+++ b/lib/chef/dsl/definitions.rb
@@ -9,7 +9,7 @@ class Chef
#
module Definitions
def self.add_definition(dsl_name)
- module_eval <<-EOM, __FILE__, __LINE__+1
+ module_eval <<-EOM, __FILE__, __LINE__ + 1
def #{dsl_name}(*args, &block)
evaluate_resource_definition(#{dsl_name.inspect}, *args, &block)
end
@@ -25,7 +25,6 @@ class Chef
#
# @api private
def evaluate_resource_definition(definition_name, *args, &block)
-
# This dupes the high level object, but we still need to dup the params
new_def = run_context.definitions[definition_name].dup
diff --git a/lib/chef/dsl/include_attribute.rb b/lib/chef/dsl/include_attribute.rb
index 3a95ce7268..6d27fefc25 100644
--- a/lib/chef/dsl/include_attribute.rb
+++ b/lib/chef/dsl/include_attribute.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/log'
+require "chef/log"
class Chef
module DSL
@@ -58,6 +58,4 @@ end
# **DEPRECATED**
# This used to be part of chef/mixin/language_include_attribute. Load the file to activate the deprecation code.
-require 'chef/mixin/language_include_attribute'
-
-
+require "chef/mixin/language_include_attribute"
diff --git a/lib/chef/dsl/include_recipe.rb b/lib/chef/dsl/include_recipe.rb
index 5ea1075e67..9abd7d135b 100644
--- a/lib/chef/dsl/include_recipe.rb
+++ b/lib/chef/dsl/include_recipe.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/log'
+require "chef/log"
class Chef
module DSL
@@ -41,4 +41,4 @@ end
# **DEPRECATED**
# This used to be part of chef/mixin/language_include_recipe. Load the file to activate the deprecation code.
-require 'chef/mixin/language_include_recipe'
+require "chef/mixin/language_include_recipe"
diff --git a/lib/chef/dsl/method_missing.rb b/lib/chef/dsl/method_missing.rb
new file mode 100644
index 0000000000..2917a54ee8
--- /dev/null
+++ b/lib/chef/dsl/method_missing.rb
@@ -0,0 +1,75 @@
+#--
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ module DSL
+ # @deprecated scheduled to die in a Chef 13 fire
+ module MethodMissing
+ def describe_self_for_error
+ if respond_to?(:name)
+ %Q{`#{self.class} "#{name}"'}
+ elsif respond_to?(:recipe_name)
+ %Q{`#{self.class} "#{recipe_name}"'}
+ else
+ to_s
+ end
+ end
+
+ # DEPRECATED:
+ # method_missing must live for backcompat purposes until Chef 13.
+ def method_missing(method_symbol, *args, &block)
+ #
+ # If there is already DSL for this, someone must have called
+ # method_missing manually. Not a fan. Not. A. Fan.
+ #
+ if respond_to?(method_symbol)
+ Chef.deprecated(:internal_api, "Calling method_missing(#{method_symbol.inspect}) directly is deprecated in Chef 12 and will be removed in Chef 13. Use public_send() or send() instead.")
+ return send(method_symbol, *args, &block)
+ end
+
+ #
+ # If a definition exists, then Chef::DSL::Definitions.add_definition was
+ # never called. DEPRECATED.
+ #
+ if run_context.definitions.has_key?(method_symbol.to_sym)
+ Chef.deprecated(:internal_api, "Definition #{method_symbol} (#{run_context.definitions[method_symbol.to_sym]}) was added to the run_context without calling Chef::DSL::Definitions.add_definition(#{method_symbol.to_sym.inspect}). This will become required in Chef 13.")
+ Chef::DSL::Definitions.add_definition(method_symbol)
+ return send(method_symbol, *args, &block)
+ end
+
+ #
+ # See if the resource exists anyway. If the user had set
+ # Chef::Resource::Blah = <resource>, a deprecation warning will be
+ # emitted and the DSL method 'blah' will be added to the DSL.
+ #
+ resource_class = Chef::ResourceResolver.resolve(method_symbol, node: run_context ? run_context.node : nil)
+ if resource_class
+ Chef::DSL::Resources.add_resource_dsl(method_symbol)
+ return send(method_symbol, *args, &block)
+ end
+
+ begin
+ super
+ rescue NoMethodError
+ raise NoMethodError, "No resource or method named `#{method_symbol}' for #{describe_self_for_error}"
+ rescue NameError
+ raise NameError, "No resource, method, or local variable named `#{method_symbol}' for #{describe_self_for_error}"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/dsl/platform_introspection.rb b/lib/chef/dsl/platform_introspection.rb
index a6bd12d2ef..dc309f9acb 100644
--- a/lib/chef/dsl/platform_introspection.rb
+++ b/lib/chef/dsl/platform_introspection.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -45,7 +45,7 @@ class Chef
# :default => default_value
def initialize(platform_hash)
@values = {}
- platform_hash.each { |platforms, value| set(platforms, value)}
+ platform_hash.each { |platforms, value| set(platforms, value) }
end
def value_for_node(node)
@@ -68,49 +68,47 @@ class Chef
private
def match_versions(node)
- begin
- platform, version = node[:platform].to_s, node[:platform_version].to_s
- return nil unless @values.key?(platform)
- node_version = Chef::Version::Platform.new(version)
- key_matches = []
- keys = @values[platform].keys
- keys.each do |k|
- begin
- if Chef::VersionConstraint::Platform.new(k).include?(node_version)
- key_matches << k
- end
- rescue Chef::Exceptions::InvalidVersionConstraint => e
- Chef::Log.debug "Caught InvalidVersionConstraint. This means that a key in value_for_platform cannot be interpreted as a Chef::VersionConstraint::Platform."
- Chef::Log.debug(e)
+ platform, version = node[:platform].to_s, node[:platform_version].to_s
+ return nil unless @values.key?(platform)
+ node_version = Chef::Version::Platform.new(version)
+ key_matches = []
+ keys = @values[platform].keys
+ keys.each do |k|
+ begin
+ if Chef::VersionConstraint::Platform.new(k).include?(node_version)
+ key_matches << k
end
+ rescue Chef::Exceptions::InvalidVersionConstraint => e
+ Chef::Log.debug "Caught InvalidVersionConstraint. This means that a key in value_for_platform cannot be interpreted as a Chef::VersionConstraint::Platform."
+ Chef::Log.debug(e)
end
- return @values[platform][version] if key_matches.include?(version)
- case key_matches.length
- when 0
- return nil
- when 1
- return @values[platform][key_matches.first]
- else
- raise "Multiple matches detected for #{platform} with values #{@values}. The matches are: #{key_matches}"
- end
- rescue Chef::Exceptions::InvalidCookbookVersion => e
- # Lets not break because someone passes a weird string like 'default' :)
- Chef::Log.debug(e)
- Chef::Log.debug "InvalidCookbookVersion exceptions are common and expected here: the generic constraint matcher attempted to match something which is not a constraint. Moving on to next version or constraint"
- return nil
- rescue Chef::Exceptions::InvalidPlatformVersion => e
- Chef::Log.debug "Caught InvalidPlatformVersion, this means that Chef::Version::Platform does not know how to turn #{node_version} into an x.y.z format"
- Chef::Log.debug(e)
+ end
+ return @values[platform][version] if key_matches.include?(version)
+ case key_matches.length
+ when 0
return nil
+ when 1
+ return @values[platform][key_matches.first]
+ else
+ raise "Multiple matches detected for #{platform} with values #{@values}. The matches are: #{key_matches}"
end
+ rescue Chef::Exceptions::InvalidCookbookVersion => e
+ # Lets not break because someone passes a weird string like 'default' :)
+ Chef::Log.debug(e)
+ Chef::Log.debug "InvalidCookbookVersion exceptions are common and expected here: the generic constraint matcher attempted to match something which is not a constraint. Moving on to next version or constraint"
+ return nil
+ rescue Chef::Exceptions::InvalidPlatformVersion => e
+ Chef::Log.debug "Caught InvalidPlatformVersion, this means that Chef::Version::Platform does not know how to turn #{node_version} into an x.y.z format"
+ Chef::Log.debug(e)
+ return nil
end
def set(platforms, value)
- if platforms.to_s == 'default'
+ if platforms.to_s == "default"
@values["default"] = value
else
assert_valid_platform_values!(platforms, value)
- Array(platforms).each { |platform| @values[platform.to_s] = normalize_keys(value)}
+ Array(platforms).each { |platform| @values[platform.to_s] = normalize_keys(value) }
value
end
end
@@ -134,8 +132,6 @@ class Chef
end
end
-
-
# Given a hash similar to the one we use for Platforms, select a value from the hash. Supports
# per platform defaults, along with a single base default. Arrays may be passed as hash keys and
# will be expanded.
@@ -168,8 +164,6 @@ class Chef
has_platform
end
-
-
# Implementation class for determining platform family dependent values
class PlatformFamilyDependentValue
@@ -193,7 +187,7 @@ class Chef
def initialize(platform_family_hash)
@values = {}
@values["default"] = nil
- platform_family_hash.each { |platform_families, value| set(platform_families, value)}
+ platform_family_hash.each { |platform_families, value| set(platform_families, value) }
end
def value_for_node(node)
@@ -212,7 +206,7 @@ class Chef
private
def set(platform_family, value)
- if platform_family.to_s == 'default'
+ if platform_family.to_s == "default"
@values["default"] = value
else
Array(platform_family).each { |family| @values[family.to_s] = value }
@@ -221,7 +215,6 @@ class Chef
end
end
-
# Given a hash mapping platform families to values, select a value from the hash. Supports a single
# base default if platform family is not in the map. Arrays may be passed as hash keys and will be
# expanded
@@ -250,11 +243,26 @@ class Chef
end
end
+ # Shamelessly stolen from https://github.com/sethvargo/chef-sugar/blob/master/lib/chef/sugar/docker.rb
+ # Given a node object, returns whether the node is a docker container.
+ #
+ # === Parameters
+ # node:: [Chef::Node] The node to check.
+ #
+ # === Returns
+ # true:: if the current node is a docker container
+ # false:: if the current node is not a docker container
+ def docker?(node = run_context.nil? ? nil : run_context.node)
+ # Using "File.exist?('/.dockerinit') || File.exist?('/.dockerenv')" makes Travis sad,
+ # and that makes us sad too.
+ !!(node && node[:virtualization] && node[:virtualization][:systems] &&
+ node[:virtualization][:systems][:docker] && node[:virtualization][:systems][:docker] == "guest")
+ end
+
end
end
end
# **DEPRECATED**
# This used to be part of chef/mixin/language. Load the file to activate the deprecation code.
-require 'chef/mixin/language'
-
+require "chef/mixin/language"
diff --git a/lib/chef/dsl/powershell.rb b/lib/chef/dsl/powershell.rb
index a17971c689..7dc7a9a0f6 100644
--- a/lib/chef/dsl/powershell.rb
+++ b/lib/chef/dsl/powershell.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'chef/util/powershell/ps_credential'
+require "chef/util/powershell/ps_credential"
class Chef
module DSL
module Powershell
- def ps_credential(username='placeholder', password)
+ def ps_credential(username = "placeholder", password) # rubocop:disable Style/OptionalArguments
Chef::Util::Powershell::PSCredential.new(username, password)
end
end
diff --git a/lib/chef/dsl/reboot_pending.rb b/lib/chef/dsl/reboot_pending.rb
index 3d84b29ec5..fdd0f5a62b 100644
--- a/lib/chef/dsl/reboot_pending.rb
+++ b/lib/chef/dsl/reboot_pending.rb
@@ -1,6 +1,6 @@
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Author:: Seth Chisamore <schisamo@opscode.com>
-# Copyright:: Copyright (c) 2011,2014, Chef Software, Inc.
+# Author:: Seth Chisamore <schisamo@chef.io>
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/dsl/platform_introspection'
-require 'chef/dsl/registry_helper'
+require "chef/dsl/platform_introspection"
+require "chef/dsl/registry_helper"
class Chef
module DSL
@@ -29,33 +29,32 @@ class Chef
# Returns true if the system needs a reboot or is expected to reboot
# Note that we will silently miss any other platform-specific reboot notices besides Windows+Ubuntu.
def reboot_pending?
-
# don't break when used as a mixin in contexts without #node (e.g. specs).
- if self.respond_to?(:node, true) && node.run_context.reboot_requested?
+ if respond_to?(:node, true) && node.run_context.reboot_requested?
true
elsif platform?("windows")
# PendingFileRenameOperations contains pairs (REG_MULTI_SZ) of filenames that cannot be updated
# due to a file being in use (usually a temporary file and a system file)
# \??\c:\temp\test.sys!\??\c:\winnt\system32\test.sys
# http://technet.microsoft.com/en-us/library/cc960241.aspx
- registry_value_exists?('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => 'PendingFileRenameOperations' }) ||
+ registry_value_exists?('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => "PendingFileRenameOperations" }) ||
# RebootRequired key contains Update IDs with a value of 1 if they require a reboot.
# The existence of RebootRequired alone is sufficient on my Windows 8.1 workstation in Windows Update
- registry_key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired') ||
+ registry_key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired') ||
# Vista + Server 2008 and newer may have reboots pending from CBS
- registry_key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending') ||
+ registry_key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending') ||
# The mere existence of the UpdateExeVolatile key should indicate a pending restart for certain updates
# http://support.microsoft.com/kb/832475
- Chef::Platform.windows_server_2003? &&
- (registry_key_exists?('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile') &&
- !registry_get_values('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').select { |v| v[:name] == "Flags" }[0].nil? &&
- [1,2,3].include?(registry_get_values('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').select { |v| v[:name] == "Flags" }[0][:data]))
+ Chef::Platform.windows_server_2003? &&
+ (registry_key_exists?('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile') &&
+ !registry_get_values('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').select { |v| v[:name] == "Flags" }[0].nil? &&
+ [1, 2, 3].include?(registry_get_values('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').select { |v| v[:name] == "Flags" }[0][:data]))
elsif platform?("ubuntu")
# This should work for Debian as well if update-notifier-common happens to be installed. We need an API for that.
- File.exists?('/var/run/reboot-required')
+ File.exists?("/var/run/reboot-required")
else
false
end
diff --git a/lib/chef/dsl/recipe.rb b/lib/chef/dsl/recipe.rb
index 26c0ec6768..e2bd070179 100644
--- a/lib/chef/dsl/recipe.rb
+++ b/lib/chef/dsl/recipe.rb
@@ -1,7 +1,7 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,96 +17,52 @@
# limitations under the License.
#
-require 'chef/mixin/convert_to_class_name'
-require 'chef/exceptions'
-require 'chef/mixin/shell_out'
-require 'chef/mixin/powershell_out'
-require 'chef/dsl/resources'
-require 'chef/dsl/definitions'
+require "chef/exceptions"
+require "chef/dsl/resources"
+require "chef/dsl/definitions"
+require "chef/dsl/data_query"
+require "chef/dsl/include_recipe"
+require "chef/dsl/registry_helper"
+require "chef/dsl/reboot_pending"
+require "chef/dsl/audit"
+require "chef/dsl/powershell"
+require "chef/dsl/core"
+require "chef/dsl/method_missing"
+require "chef/mixin/lazy_module_include"
class Chef
module DSL
-
- # == Chef::DSL::Recipe
- # Provides the primary recipe DSL functionality for defining Chef resource
- # objects via method calls.
+ # Part of a family of DSL mixins.
+ #
+ # Chef::DSL::Recipe mixes into Recipes and LWRP Providers.
+ # - this does not target core chef resources and providers.
+ # - this is restricted to recipe/resource/provider context where a resource collection exists.
+ # - cookbook authors should typically include modules into here.
+ #
+ # Chef::DSL::Core mixes into Recipes, LWRP Providers and Core Providers
+ # - this adds cores providers on top of the Recipe DSL.
+ # - this is restricted to recipe/resource/provider context where a resource collection exists.
+ # - core chef authors should typically include modules into here.
+ #
+ # Chef::DSL::Universal mixes into Recipes, LWRP Resources+Providers, Core Resources+Providers, and Attributes files.
+ # - this adds resources and attributes files.
+ # - do not add helpers which manipulate the resource collection.
+ # - this is for general-purpose stuff that is useful nearly everywhere.
+ # - it also pollutes the namespace of nearly every context, watch out.
+ #
module Recipe
-
- include Chef::Mixin::ShellOut
- include Chef::Mixin::PowershellOut
-
+ include Chef::DSL::Core
+ include Chef::DSL::DataQuery
+ include Chef::DSL::IncludeRecipe
+ include Chef::DSL::RegistryHelper
+ include Chef::DSL::RebootPending
+ include Chef::DSL::Audit
+ include Chef::DSL::Powershell
include Chef::DSL::Resources
include Chef::DSL::Definitions
-
- #
- # Instantiates a resource (via #build_resource), then adds it to the
- # resource collection. Note that resource classes are looked up directly,
- # so this will create the resource you intended even if the method name
- # corresponding to that resource has been overridden.
- #
- # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
- # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
- # @param created_at [String] The caller of the resource. Use `caller[0]`
- # to get the caller of your function. Defaults to the caller of this
- # function.
- # @param resource_attrs_block A block that lets you set attributes of the
- # resource (it is instance_eval'd on the resource instance).
- #
- # @return [Chef::Resource] The new resource.
- #
- # @example
- # declare_resource(:file, '/x/y.txy', caller[0]) do
- # action :delete
- # end
- # # Equivalent to
- # file '/x/y.txt' do
- # action :delete
- # end
- #
- def declare_resource(type, name, created_at=nil, &resource_attrs_block)
- created_at ||= caller[0]
-
- resource = build_resource(type, name, created_at, &resource_attrs_block)
-
- run_context.resource_collection.insert(resource, resource_type: type, instance_name: name)
- resource
- end
-
- #
- # Instantiate a resource of the given +type+ with the given +name+ and
- # attributes as given in the +resource_attrs_block+.
- #
- # The resource is NOT added to the resource collection.
- #
- # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
- # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
- # @param created_at [String] The caller of the resource. Use `caller[0]`
- # to get the caller of your function. Defaults to the caller of this
- # function.
- # @param resource_attrs_block A block that lets you set attributes of the
- # resource (it is instance_eval'd on the resource instance).
- #
- # @return [Chef::Resource] The new resource.
- #
- # @example
- # build_resource(:file, '/x/y.txy', caller[0]) do
- # action :delete
- # end
- #
- def build_resource(type, name, created_at=nil, &resource_attrs_block)
- created_at ||= caller[0]
-
- Chef::ResourceBuilder.new(
- type: type,
- name: name,
- created_at: created_at,
- params: @params,
- run_context: run_context,
- cookbook_name: cookbook_name,
- recipe_name: recipe_name,
- enclosing_provider: self.is_a?(Chef::Provider) ? self : nil
- ).build(&resource_attrs_block)
- end
+ # method_missing will disappear in Chef 13
+ include Chef::DSL::MethodMissing
+ extend Chef::Mixin::LazyModuleInclude
def resource_class_for(snake_case_name)
Chef::Resource.resource_for_node(snake_case_name, run_context.node)
@@ -118,87 +74,22 @@ class Chef
false
end
- def describe_self_for_error
- if respond_to?(:name)
- %Q[`#{self.class} "#{name}"']
- elsif respond_to?(:recipe_name)
- %Q[`#{self.class} "#{recipe_name}"']
- else
- to_s
- end
- end
-
def exec(args)
raise Chef::Exceptions::ResourceNotFound, "exec was called, but you probably meant to use an execute resource. If not, please call Kernel#exec explicitly. The exec block called was \"#{args}\""
end
- # DEPRECATED:
- # method_missing must live for backcompat purposes until Chef 13.
- def method_missing(method_symbol, *args, &block)
- #
- # If there is already DSL for this, someone must have called
- # method_missing manually. Not a fan. Not. A. Fan.
- #
- if respond_to?(method_symbol)
- Chef.log_deprecation("Calling method_missing(#{method_symbol.inspect}) directly is deprecated in Chef 12 and will be removed in Chef 13. Use public_send() or send() instead.")
- return send(method_symbol, *args, &block)
- end
-
- #
- # If a definition exists, then Chef::DSL::Definitions.add_definition was
- # never called. DEPRECATED.
- #
- if run_context.definitions.has_key?(method_symbol.to_sym)
- Chef.log_deprecation("Definition #{method_symbol} (#{run_context.definitions[method_symbol.to_sym]}) was added to the run_context without calling Chef::DSL::Definitions.add_definition(#{method_symbol.to_sym.inspect}). This will become required in Chef 13.")
- Chef::DSL::Definitions.add_definition(method_symbol)
- return send(method_symbol, *args, &block)
- end
-
- #
- # See if the resource exists anyway. If the user had set
- # Chef::Resource::Blah = <resource>, a deprecation warning will be
- # emitted and the DSL method 'blah' will be added to the DSL.
- #
- resource_class = Chef::ResourceResolver.resolve(method_symbol, node: run_context ? run_context.node : nil)
- if resource_class
- Chef::DSL::Resources.add_resource_dsl(method_symbol)
- return send(method_symbol, *args, &block)
- end
-
- begin
- super
- rescue NoMethodError
- raise NoMethodError, "No resource or method named `#{method_symbol}' for #{describe_self_for_error}"
- rescue NameError
- raise NameError, "No resource, method, or local variable named `#{method_symbol}' for #{describe_self_for_error}"
- end
- end
-
+ # @deprecated Use Chef::DSL::Recipe instead, will be removed in Chef 13
module FullDSL
- require 'chef/dsl/data_query'
- require 'chef/dsl/platform_introspection'
- require 'chef/dsl/include_recipe'
- require 'chef/dsl/registry_helper'
- require 'chef/dsl/reboot_pending'
- require 'chef/dsl/audit'
- require 'chef/dsl/powershell'
- include Chef::DSL::DataQuery
- include Chef::DSL::PlatformIntrospection
- include Chef::DSL::IncludeRecipe
include Chef::DSL::Recipe
- include Chef::DSL::RegistryHelper
- include Chef::DSL::RebootPending
- include Chef::DSL::Audit
- include Chef::DSL::Powershell
+ extend Chef::Mixin::LazyModuleInclude
end
end
end
end
# Avoid circular references for things that are only used in instance methods
-require 'chef/resource_builder'
-require 'chef/resource'
+require "chef/resource"
# **DEPRECATED**
# This used to be part of chef/mixin/recipe_definition_dsl_core. Load the file to activate the deprecation code.
-require 'chef/mixin/recipe_definition_dsl_core'
+require "chef/mixin/recipe_definition_dsl_core"
diff --git a/lib/chef/dsl/registry_helper.rb b/lib/chef/dsl/registry_helper.rb
index 4dcd2f1eee..63da635ef1 100644
--- a/lib/chef/dsl/registry_helper.rb
+++ b/lib/chef/dsl/registry_helper.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,22 +33,27 @@ class Chef
registry = Chef::Win32::Registry.new(run_context, architecture)
registry.key_exists?(key_path)
end
+
def registry_get_values(key_path, architecture = :machine)
registry = Chef::Win32::Registry.new(run_context, architecture)
registry.get_values(key_path)
end
+
def registry_has_subkeys?(key_path, architecture = :machine)
registry = Chef::Win32::Registry.new(run_context, architecture)
registry.has_subkeys?(key_path)
end
+
def registry_get_subkeys(key_path, architecture = :machine)
registry = Chef::Win32::Registry.new(run_context, architecture)
registry.get_subkeys(key_path)
end
+
def registry_value_exists?(key_path, value, architecture = :machine)
registry = Chef::Win32::Registry.new(run_context, architecture)
registry.value_exists?(key_path, value)
end
+
def registry_data_exists?(key_path, value, architecture = :machine)
registry = Chef::Win32::Registry.new(run_context, architecture)
registry.data_exists?(key_path, value)
@@ -56,4 +61,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/dsl/resources.rb b/lib/chef/dsl/resources.rb
index 49588ed516..1401e3ed53 100644
--- a/lib/chef/dsl/resources.rb
+++ b/lib/chef/dsl/resources.rb
@@ -1,3 +1,23 @@
+#
+# Author:: John Keiser <jkeiser@chef.io>
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "chef/dsl/cheffish"
+require "chef/dsl/chef_provisioning"
+
class Chef
module DSL
#
@@ -7,24 +27,29 @@ class Chef
#
# @api private
module Resources
+ # Include the lazy loaders for cheffish and chef-provisioning, so that the
+ # resource DSL is there but the gems aren't activated yet.
+ include Chef::DSL::Cheffish
+ include Chef::DSL::ChefProvisioning
+
def self.add_resource_dsl(dsl_name)
- begin
- module_eval(<<-EOM, __FILE__, __LINE__+1)
+ module_eval(<<-EOM, __FILE__, __LINE__ + 1)
def #{dsl_name}(*args, &block)
- Chef.log_deprecation("Cannot create resource #{dsl_name} with more than one argument. All arguments except the name (\#{args[0].inspect}) will be ignored. This will cause an error in Chef 13. Arguments: \#{args}") if args.size > 1
+ Chef.deprecated(:internal_api, "Cannot create resource #{dsl_name} with more than one argument. All arguments except the name (\#{args[0].inspect}) will be ignored. This will cause an error in Chef 13. Arguments: \#{args}") if args.size > 1
declare_resource(#{dsl_name.inspect}, args[0], caller[0], &block)
end
EOM
- rescue SyntaxError
- # Handle the case where dsl_name has spaces, etc.
- define_method(dsl_name.to_sym) do |*args, &block|
- Chef.log_deprecation("Cannot create resource #{dsl_name} with more than one argument. All arguments except the name (#{args[0].inspect}) will be ignored. This will cause an error in Chef 13. Arguments: #{args}") if args.size > 1
- declare_resource(dsl_name, args[0], caller[0], &block)
- end
+ rescue SyntaxError
+ # Handle the case where dsl_name has spaces, etc.
+ define_method(dsl_name.to_sym) do |*args, &block|
+ Chef.deprecated(:internal_api, "Cannot create resource #{dsl_name} with more than one argument. All arguments except the name (#{args[0].inspect}) will be ignored. This will cause an error in Chef 13. Arguments: #{args}") if args.size > 1
+ declare_resource(dsl_name, args[0], caller[0], &block)
end
end
+
def self.remove_resource_dsl(dsl_name)
- remove_method(dsl_name) if method_defined?(dsl_name)
+ remove_method(dsl_name)
+ rescue NameError
end
end
end
diff --git a/lib/chef/dsl/universal.rb b/lib/chef/dsl/universal.rb
new file mode 100644
index 0000000000..6e3d162b6f
--- /dev/null
+++ b/lib/chef/dsl/universal.rb
@@ -0,0 +1,50 @@
+#--
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/dsl/platform_introspection"
+require "chef/mixin/powershell_out"
+require "chef/mixin/shell_out"
+
+class Chef
+ module DSL
+ # Part of a family of DSL mixins.
+ #
+ # Chef::DSL::Recipe mixes into Recipes and LWRP Providers.
+ # - this does not target core chef resources and providers.
+ # - this is restricted to recipe/resource/provider context where a resource collection exists.
+ # - cookbook authors should typically include modules into here.
+ #
+ # Chef::DSL::Core mixes into Recipes, LWRP Providers and Core Providers
+ # - this adds cores providers on top of the Recipe DSL.
+ # - this is restricted to recipe/resource/provider context where a resource collection exists.
+ # - core chef authors should typically include modules into here.
+ #
+ # Chef::DSL::Universal mixes into Recipes, LWRP Resources+Providers, Core Resources+Providers, and Attributes files.
+ # - this adds resources and attributes files.
+ # - do not add helpers which manipulate the resource collection.
+ # - this is for general-purpose stuff that is useful nearly everywhere.
+ # - it also pollutes the namespace of nearly every context, watch out.
+ #
+ module Universal
+ include Chef::DSL::PlatformIntrospection
+ include Chef::Mixin::PowershellOut
+ include Chef::Mixin::ShellOut
+ end
+ end
+end
diff --git a/lib/chef/encrypted_data_bag_item.rb b/lib/chef/encrypted_data_bag_item.rb
index 120eb2a4ae..c7c6145f61 100644
--- a/lib/chef/encrypted_data_bag_item.rb
+++ b/lib/chef/encrypted_data_bag_item.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/data_bag_item'
-require 'chef/encrypted_data_bag_item/decryptor'
-require 'chef/encrypted_data_bag_item/encryptor'
-require 'open-uri'
+require "chef/config"
+require "chef/data_bag_item"
+require "chef/encrypted_data_bag_item/decryptor"
+require "chef/encrypted_data_bag_item/encryptor"
+require "open-uri"
# An EncryptedDataBagItem represents a read-only data bag item where
# all values, except for the value associated with the id key, have
@@ -47,8 +47,8 @@ require 'open-uri'
# such nodes in the infrastructure.
#
class Chef::EncryptedDataBagItem
- ALGORITHM = 'aes-256-cbc'
- AEAD_ALGORITHM = 'aes-256-gcm'
+ ALGORITHM = "aes-256-cbc"
+ AEAD_ALGORITHM = "aes-256-gcm"
#
# === Synopsis
@@ -121,11 +121,11 @@ class Chef::EncryptedDataBagItem
#
def self.load(data_bag, name, secret = nil)
raw_hash = Chef::DataBagItem.load(data_bag, name)
- secret = secret || self.load_secret
- self.new(raw_hash, secret)
+ secret ||= load_secret
+ new(raw_hash, secret)
end
- def self.load_secret(path=nil)
+ def self.load_secret(path = nil)
path ||= Chef::Config[:encrypted_data_bag_secret]
if !path
raise ArgumentError, "No secret specified and no secret found at #{Chef::Config.platform_specific_path('/etc/chef/encrypted_data_bag_secret')}"
diff --git a/lib/chef/encrypted_data_bag_item/assertions.rb b/lib/chef/encrypted_data_bag_item/assertions.rb
index ab93f46c10..e8f8bfcbf2 100644
--- a/lib/chef/encrypted_data_bag_item/assertions.rb
+++ b/lib/chef/encrypted_data_bag_item/assertions.rb
@@ -1,6 +1,6 @@
#
# Author:: Xabier de Zuazo (<xabier@onddo.com>)
-# Copyright:: Copyright (c) 2014 Onddo Labs, SL.
+# Copyright:: Copyright 2014-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format'
-require 'chef/encrypted_data_bag_item/unsupported_cipher'
+require "chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format"
+require "chef/encrypted_data_bag_item/unsupported_cipher"
class Chef::EncryptedDataBagItem
@@ -27,7 +27,7 @@ class Chef::EncryptedDataBagItem
module Assertions
def assert_format_version_acceptable!(format_version)
- unless format_version.kind_of?(Integer) and format_version >= Chef::Config[:data_bag_decrypt_minimum_version]
+ unless format_version.kind_of?(Integer) && format_version >= Chef::Config[:data_bag_decrypt_minimum_version]
raise UnacceptableEncryptedDataBagItemFormat,
"The encrypted data bag item has format version `#{format_version}', " +
"but the config setting 'data_bag_decrypt_minimum_version' requires version `#{Chef::Config[:data_bag_decrypt_minimum_version]}'"
diff --git a/lib/chef/encrypted_data_bag_item/check_encrypted.rb b/lib/chef/encrypted_data_bag_item/check_encrypted.rb
index b7cb5841b3..cc378194ff 100644
--- a/lib/chef/encrypted_data_bag_item/check_encrypted.rb
+++ b/lib/chef/encrypted_data_bag_item/check_encrypted.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tyler Ball (<tball@getchef.com>)
-# Copyright:: Copyright (c) 2010-2014 Opscode, Inc.
+# Author:: Tyler Ball (<tball@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/encrypted_data_bag_item/encryptor'
+require "chef/encrypted_data_bag_item/encryptor"
class Chef::EncryptedDataBagItem
# Common code for checking if a data bag appears encrypted
diff --git a/lib/chef/encrypted_data_bag_item/decryption_failure.rb b/lib/chef/encrypted_data_bag_item/decryption_failure.rb
index 47d263f197..9d2d998057 100644
--- a/lib/chef/encrypted_data_bag_item/decryption_failure.rb
+++ b/lib/chef/encrypted_data_bag_item/decryption_failure.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/encrypted_data_bag_item/decryptor.rb b/lib/chef/encrypted_data_bag_item/decryptor.rb
index 86b99cc284..f35611d185 100644
--- a/lib/chef/encrypted_data_bag_item/decryptor.rb
+++ b/lib/chef/encrypted_data_bag_item/decryptor.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'yaml'
-require 'chef/json_compat'
-require 'openssl'
-require 'base64'
-require 'digest/sha2'
-require 'chef/encrypted_data_bag_item'
-require 'chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format'
-require 'chef/encrypted_data_bag_item/decryption_failure'
-require 'chef/encrypted_data_bag_item/assertions'
+require "yaml"
+require "chef/json_compat"
+require "openssl"
+require "base64"
+require "digest/sha2"
+require "chef/encrypted_data_bag_item"
+require "chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format"
+require "chef/encrypted_data_bag_item/decryption_failure"
+require "chef/encrypted_data_bag_item/assertions"
class Chef::EncryptedDataBagItem
@@ -92,7 +92,8 @@ class Chef::EncryptedDataBagItem
plaintext = openssl_decryptor.update(encrypted_bytes)
plaintext << openssl_decryptor.final
rescue OpenSSL::Cipher::CipherError => e
- raise DecryptionFailure, "Error decrypting data bag value: '#{e.message}'. Most likely the provided key is incorrect"
+ # if the key length is less than 255 characters, and it contains slashes, we think it may be a path.
+ raise DecryptionFailure, "Error decrypting data bag value: '#{e.message}'. Most likely the provided key is incorrect. #{(@key.length < 255 && @key.include?('/')) ? 'You may need to use --secret-file rather than --secret.' : ''}"
end
end
@@ -142,7 +143,8 @@ class Chef::EncryptedDataBagItem
plaintext = openssl_decryptor.update(encrypted_bytes)
plaintext << openssl_decryptor.final
rescue OpenSSL::Cipher::CipherError => e
- raise DecryptionFailure, "Error decrypting data bag value: '#{e.message}'. Most likely the provided key is incorrect"
+ # if the key length is less than 255 characters, and it contains slashes, we think it may be a path.
+ raise DecryptionFailure, "Error decrypting data bag value: '#{e.message}'. Most likely the provided key is incorrect. #{( @key.length < 255 && @key.include?('/')) ? 'You may need to use --secret-file rather than --secret.' : ''}"
end
end
@@ -214,7 +216,7 @@ class Chef::EncryptedDataBagItem
@openssl_decryptor ||= begin
d = super
d.auth_tag = auth_tag
- d.auth_data = ''
+ d.auth_data = ""
d
end
end
diff --git a/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb b/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb
index 9a54396174..e45c34248e 100644
--- a/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb
+++ b/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb
@@ -1,6 +1,6 @@
#
# Author:: Xabier de Zuazo (<xabier@onddo.com>)
-# Copyright:: Copyright (c) 2014 Onddo Labs, SL.
+# Copyright:: Copyright 2014-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/encrypted_data_bag_item/encryption_failure.rb b/lib/chef/encrypted_data_bag_item/encryption_failure.rb
index 380e9bc1f7..142d898b86 100644
--- a/lib/chef/encrypted_data_bag_item/encryption_failure.rb
+++ b/lib/chef/encrypted_data_bag_item/encryption_failure.rb
@@ -1,6 +1,6 @@
#
# Author:: Xabier de Zuazo (<xabier@onddo.com>)
-# Copyright:: Copyright (c) 2014 Onddo Labs, SL.
+# Copyright:: Copyright 2014-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/encrypted_data_bag_item/encryptor.rb b/lib/chef/encrypted_data_bag_item/encryptor.rb
index 034413c1bd..8d34033db6 100644
--- a/lib/chef/encrypted_data_bag_item/encryptor.rb
+++ b/lib/chef/encrypted_data_bag_item/encryptor.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'base64'
-require 'digest/sha2'
-require 'openssl'
-require 'ffi_yajl'
-require 'chef/encrypted_data_bag_item'
-require 'chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format'
-require 'chef/encrypted_data_bag_item/encryption_failure'
-require 'chef/encrypted_data_bag_item/assertions'
+require "base64"
+require "digest/sha2"
+require "openssl"
+require "ffi_yajl"
+require "chef/encrypted_data_bag_item"
+require "chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format"
+require "chef/encrypted_data_bag_item/encryption_failure"
+require "chef/encrypted_data_bag_item/assertions"
class Chef::EncryptedDataBagItem
@@ -35,7 +35,7 @@ class Chef::EncryptedDataBagItem
# for the desired encrypted data bag format version.
#
# +Chef::Config[:data_bag_encrypt_version]+ determines which version is used.
- def self.new(value, secret, iv=nil)
+ def self.new(value, secret, iv = nil)
format_version = Chef::Config[:data_bag_encrypt_version]
case format_version
when 1
@@ -65,7 +65,7 @@ class Chef::EncryptedDataBagItem
# * iv: The optional +iv+ parameter is intended for testing use only. When
# *not* supplied, Encryptor will use OpenSSL to generate a secure random
# IV, which is what you want.
- def initialize(plaintext_data, key, iv=nil)
+ def initialize(plaintext_data, key, iv = nil)
@plaintext_data = plaintext_data
@key = key
@iv = iv && Base64.decode64(iv)
@@ -83,7 +83,7 @@ class Chef::EncryptedDataBagItem
"encrypted_data" => encrypted_data,
"iv" => Base64.encode64(iv),
"version" => 1,
- "cipher" => algorithm
+ "cipher" => algorithm,
}
end
@@ -127,7 +127,7 @@ class Chef::EncryptedDataBagItem
end
def self.encryptor_keys
- %w( encrypted_data iv version cipher )
+ %w{ encrypted_data iv version cipher }
end
end
@@ -141,7 +141,7 @@ class Chef::EncryptedDataBagItem
"hmac" => hmac,
"iv" => Base64.encode64(iv),
"version" => 2,
- "cipher" => algorithm
+ "cipher" => algorithm,
}
end
@@ -155,14 +155,14 @@ class Chef::EncryptedDataBagItem
end
def self.encryptor_keys
- super + %w( hmac )
+ super + %w{ hmac }
end
end
class Version3Encryptor < Version1Encryptor
include Chef::EncryptedDataBagItem::Assertions
- def initialize(plaintext_data, key, iv=nil)
+ def initialize(plaintext_data, key, iv = nil)
super
assert_aead_requirements_met!(algorithm)
@auth_tag = nil
@@ -176,7 +176,7 @@ class Chef::EncryptedDataBagItem
"iv" => Base64.encode64(iv),
"auth_tag" => Base64.encode64(auth_tag),
"version" => 3,
- "cipher" => algorithm
+ "cipher" => algorithm,
}
end
@@ -201,7 +201,7 @@ class Chef::EncryptedDataBagItem
def openssl_encryptor
@openssl_encryptor ||= begin
encryptor = super
- encryptor.auth_data = ''
+ encryptor.auth_data = ""
encryptor
end
end
@@ -216,7 +216,7 @@ class Chef::EncryptedDataBagItem
end
def self.encryptor_keys
- super + %w( auth_tag )
+ super + %w{ auth_tag }
end
end
diff --git a/lib/chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format.rb b/lib/chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format.rb
index 2f3b07c7f3..362954b24d 100644
--- a/lib/chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format.rb
+++ b/lib/chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/encrypted_data_bag_item/unsupported_cipher.rb b/lib/chef/encrypted_data_bag_item/unsupported_cipher.rb
index 1df5cd5efd..6f1221bb68 100644
--- a/lib/chef/encrypted_data_bag_item/unsupported_cipher.rb
+++ b/lib/chef/encrypted_data_bag_item/unsupported_cipher.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format.rb b/lib/chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format.rb
index e7cf087307..ea464636db 100644
--- a/lib/chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format.rb
+++ b/lib/chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/environment.rb b/lib/chef/environment.rb
index 7d4b410639..545a2e51eb 100644
--- a/lib/chef/environment.rb
+++ b/lib/chef/environment.rb
@@ -1,9 +1,9 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
# Author:: John Keiser (<jkeiser@ospcode.com>)
# Author:: Kyle Goodwin (<kgoodwin@primerevenue.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,11 +19,12 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/mash'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/version_constraint'
+require "chef/config"
+require "chef/mash"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/version_constraint"
+require "chef/server_api"
class Chef
class Environment
@@ -35,11 +36,11 @@ class Chef
attr_accessor :chef_server_rest
- COMBINED_COOKBOOK_CONSTRAINT = /(.+)(?:[\s]+)((?:#{Chef::VersionConstraint::OPS.join('|')})(?:[\s]+).+)$/.freeze
+ COMBINED_COOKBOOK_CONSTRAINT = /(.+)(?:[\s]+)((?:#{Chef::VersionConstraint::OPS.join('|')})(?:[\s]+).+)$/
def initialize(chef_server_rest: nil)
- @name = ''
- @description = ''
+ @name = ""
+ @description = ""
@default_attributes = Mash.new
@override_attributes = Mash.new
@cookbook_versions = Hash.new
@@ -47,14 +48,14 @@ class Chef
end
def chef_server_rest
- @chef_server_rest ||= Chef::REST.new(Chef::Config[:chef_server_url])
+ @chef_server_rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url])
end
def self.chef_server_rest
- Chef::REST.new(Chef::Config[:chef_server_url])
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url])
end
- def name(arg=nil)
+ def name(arg = nil)
set_or_return(
:name,
arg,
@@ -62,7 +63,7 @@ class Chef
)
end
- def description(arg=nil)
+ def description(arg = nil)
set_or_return(
:description,
arg,
@@ -70,7 +71,7 @@ class Chef
)
end
- def default_attributes(arg=nil)
+ def default_attributes(arg = nil)
set_or_return(
:default_attributes,
arg,
@@ -82,7 +83,7 @@ class Chef
default_attributes(attrs)
end
- def override_attributes(arg=nil)
+ def override_attributes(arg = nil)
set_or_return(
:override_attributes,
arg,
@@ -94,26 +95,26 @@ class Chef
override_attributes(attrs)
end
- def cookbook_versions(arg=nil)
+ def cookbook_versions(arg = nil)
set_or_return(
:cookbook_versions,
arg,
{
:kind_of => Hash,
:callbacks => {
- "should be a valid set of cookbook version requirements" => lambda { |cv| Chef::Environment.validate_cookbook_versions(cv) }
- }
+ "should be a valid set of cookbook version requirements" => lambda { |cv| Chef::Environment.validate_cookbook_versions(cv) },
+ },
}
)
end
def cookbook(cookbook, version)
validate({
- :version => version
- },{
+ :version => version,
+ }, {
:version => {
- :callbacks => { "should be a valid version requirement" => lambda { |v| Chef::Environment.validate_cookbook_version(v) } }
- }
+ :callbacks => { "should be a valid version requirement" => lambda { |v| Chef::Environment.validate_cookbook_version(v) } },
+ },
})
@cookbook_versions[cookbook] = version
end
@@ -122,11 +123,11 @@ class Chef
result = {
"name" => @name,
"description" => @description,
- "cookbook_versions" => @cookbook_versions,
+ "cookbook_versions" => @cookbook_versions,
"json_class" => self.class.name,
"chef_type" => "environment",
"default_attributes" => @default_attributes,
- "override_attributes" => @override_attributes
+ "override_attributes" => @override_attributes,
}
result
end
@@ -169,8 +170,8 @@ class Chef
unless params[:cookbook_version].nil?
params[:cookbook_version].each do |index, cookbook_constraint_spec|
- unless (cookbook_constraint_spec.nil? || cookbook_constraint_spec.size == 0)
- valid = valid && update_cookbook_constraint_from_param(index, cookbook_constraint_spec)
+ unless cookbook_constraint_spec.nil? || cookbook_constraint_spec.size == 0
+ valid &&= update_cookbook_constraint_from_param(index, cookbook_constraint_spec)
end
end
end
@@ -216,6 +217,11 @@ class Chef
end
def self.json_create(o)
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::Environment#from_hash")
+ from_hash(o)
+ end
+
+ def self.from_hash(o)
environment = new
environment.name(o["name"])
environment.description(o["description"])
@@ -225,7 +231,7 @@ class Chef
environment
end
- def self.list(inflate=false)
+ def self.list(inflate = false)
if inflate
response = Hash.new
Chef::Search::Query.new.search(:environment) do |e|
@@ -233,15 +239,15 @@ class Chef
end
response
else
- chef_server_rest.get_rest("environments")
+ chef_server_rest.get("environments")
end
end
def self.load(name)
- if Chef::Config[:solo]
+ if Chef::Config[:solo_legacy_mode]
load_from_file(name)
else
- chef_server_rest.get_rest("environments/#{name}")
+ from_hash(chef_server_rest.get("environments/#{name}"))
end
end
@@ -255,7 +261,8 @@ class Chef
if File.exists?(js_file)
# from_json returns object.class => json_class in the JSON.
- Chef::JSONCompat.from_json(IO.read(js_file))
+ hash = Chef::JSONCompat.parse(IO.read(js_file))
+ from_hash(hash)
elsif File.exists?(rb_file)
environment = Chef::Environment.new
environment.name(name)
@@ -267,26 +274,26 @@ class Chef
end
def destroy
- chef_server_rest.delete_rest("environments/#{@name}")
+ chef_server_rest.delete("environments/#{@name}")
end
def save
begin
- chef_server_rest.put_rest("environments/#{@name}", self)
+ chef_server_rest.put("environments/#{@name}", self)
rescue Net::HTTPServerException => e
raise e unless e.response.code == "404"
- chef_server_rest.post_rest("environments", self)
+ chef_server_rest.post("environments", self)
end
self
end
def create
- chef_server_rest.post_rest("environments", self)
+ chef_server_rest.post("environments", self)
self
end
def self.load_filtered_recipe_list(environment)
- chef_server_rest.get_rest("environments/#{environment}/recipes")
+ chef_server_rest.get("environments/#{environment}/recipes")
end
def to_s
@@ -302,17 +309,15 @@ class Chef
end
def self.validate_cookbook_version(version)
- begin
- if Chef::Config[:solo]
- raise Chef::Exceptions::IllegalVersionConstraint,
- "Environment cookbook version constraints not allowed in chef-solo"
- else
- Chef::VersionConstraint.new version
- true
- end
- rescue ArgumentError
- false
+ if Chef::Config[:solo_legacy_mode]
+ raise Chef::Exceptions::IllegalVersionConstraint,
+ "Environment cookbook version constraints not allowed in chef-solo"
+ else
+ Chef::VersionConstraint.new version
+ true
end
+ rescue ArgumentError
+ false
end
end
diff --git a/lib/chef/event_dispatch/base.rb b/lib/chef/event_dispatch/base.rb
index 585a3db174..926bbe24b5 100644
--- a/lib/chef/event_dispatch/base.rb
+++ b/lib/chef/event_dispatch/base.rb
@@ -139,6 +139,26 @@ class Chef
def cookbook_sync_complete
end
+ # Called when starting to collect gems from the cookbooks
+ def cookbook_gem_start(gems)
+ end
+
+ # Called when the result of installing the bundle is to install the gem
+ def cookbook_gem_installing(gem, version)
+ end
+
+ # Called when the result of installing the bundle is to use the gem
+ def cookbook_gem_using(gem, version)
+ end
+
+ # Called when finished installing cookbook gems
+ def cookbook_gem_finished
+ end
+
+ # Called when cookbook gem installation fails
+ def cookbook_gem_failed(exception)
+ end
+
## TODO: add cookbook name to the API for file load callbacks
## TODO: add callbacks for overall cookbook eval start and complete.
@@ -212,11 +232,11 @@ class Chef
end
# Called after the recipe has been loaded
- def recipe_file_loaded(path)
+ def recipe_file_loaded(path, recipe)
end
# Called after a recipe file fails to load
- def recipe_file_load_failed(path, exception)
+ def recipe_file_load_failed(path, exception, recipe)
end
# Called when a recipe cannot be resolved
@@ -298,7 +318,7 @@ class Chef
#
# Called before action is executed on a resource.
- def resource_action_start(resource, action, notification_type=nil, notifier=nil)
+ def resource_action_start(resource, action, notification_type = nil, notifier = nil)
end
# Called when a resource action has been skipped b/c of a conditional
@@ -324,6 +344,12 @@ class Chef
def resource_update_applied(resource, action, update)
end
+ # Called when a progress notification should be sent to the user to
+ # indicate the overall progress of a long running operation, such as
+ # a large file download.
+ def resource_update_progress(resource, current, total, interval)
+ end
+
# Called when a resource fails, but will retry.
def resource_failed_retriable(resource, action, retry_count, exception)
end
@@ -381,7 +407,7 @@ class Chef
end
# Emit a message about something being deprecated.
- def deprecation(message, location=caller(2..2)[0])
+ def deprecation(message, location = caller(2..2)[0])
end
def run_list_expanded(run_list_expansion)
@@ -395,6 +421,9 @@ class Chef
def msg(message)
end
+ # Called when an attribute is changed by simple assignment
+ def attribute_changed(precedence, keys, value)
+ end
end
end
end
diff --git a/lib/chef/event_dispatch/dispatcher.rb b/lib/chef/event_dispatch/dispatcher.rb
index f3e55539a9..69419a393b 100644
--- a/lib/chef/event_dispatch/dispatcher.rb
+++ b/lib/chef/event_dispatch/dispatcher.rb
@@ -1,4 +1,4 @@
-require 'chef/event_dispatch/base'
+require "chef/event_dispatch/base"
class Chef
module EventDispatch
@@ -20,6 +20,11 @@ class Chef
@subscribers << subscriber
end
+ # Check to see if we are dispatching to a formatter
+ def formatter?
+ @subscribers.any? { |s| s.respond_to?(:is_formatter?) && s.is_formatter? }
+ end
+
####
# All messages are unconditionally forwarded to all subscribers, so just
# define the forwarding in one go:
@@ -49,7 +54,7 @@ class Chef
end
# Special case deprecation, since it needs to know its caller
- def deprecation(message, location=caller(2..2)[0])
+ def deprecation(message, location = caller(2..2)[0])
call_subscribers(:deprecation, message, location)
end
end
diff --git a/lib/chef/event_dispatch/dsl.rb b/lib/chef/event_dispatch/dsl.rb
index c6f21c9b45..999d536fbe 100644
--- a/lib/chef/event_dispatch/dsl.rb
+++ b/lib/chef/event_dispatch/dsl.rb
@@ -1,6 +1,6 @@
#
# Author:: Ranjib Dey (<ranjib@linux.com>)
-# Copyright:: Copyright (c) 2015 Ranjib Dey
+# Copyright:: Copyright 2015-2016, Ranjib Dey
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,9 +15,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/event_dispatch/base'
-require 'chef/exceptions'
-require 'chef/config'
+require "chef/event_dispatch/base"
+require "chef/exceptions"
+require "chef/config"
class Chef
module EventDispatch
@@ -33,7 +33,7 @@ class Chef
# Use event.register API to add anonymous handler if Chef.run_context
# and associated event dispatcher is set, else fallback to
- # Chef::Config[:hanlder]
+ # Chef::Config[:event_handlers]
if Chef.run_context && Chef.run_context.events
Chef::Log.debug("Registering handler '#{name}' using events api")
Chef.run_context.events.register(handler)
@@ -55,6 +55,7 @@ class Chef
end
private
+
def validate!(event_type)
all_event_types = (Chef::EventDispatch::Base.instance_methods - Object.instance_methods)
raise Chef::Exceptions::InvalidEventType, "Invalid event type: #{event_type}" unless all_event_types.include?(event_type)
diff --git a/lib/chef/event_dispatch/events_output_stream.rb b/lib/chef/event_dispatch/events_output_stream.rb
index 8de9b0fed1..d9c21642b7 100644
--- a/lib/chef/event_dispatch/events_output_stream.rb
+++ b/lib/chef/event_dispatch/events_output_stream.rb
@@ -21,6 +21,14 @@ class Chef
events.stream_output(self, str, options)
end
+ def <<(str)
+ events.stream_output(self, str, options)
+ end
+
+ def write(str)
+ events.stream_output(self, str, options)
+ end
+
def close
events.stream_closed(self, options)
end
diff --git a/lib/chef/event_loggers/base.rb b/lib/chef/event_loggers/base.rb
index 1f676dd516..3c11e809f6 100644
--- a/lib/chef/event_loggers/base.rb
+++ b/lib/chef/event_loggers/base.rb
@@ -1,7 +1,7 @@
#
-# Author:: Jay Mundrawala (<jdm@getchef.com>)
+# Author:: Jay Mundrawala (<jdm@chef.io>)
#
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/event_dispatch/base'
+require "chef/event_dispatch/base"
class Chef
module EventLoggers
@@ -42,8 +42,8 @@ class Chef
end
def self.new(name)
- event_logger_class = by_name(name.to_s) or
- raise UnknownEventLogger, "No event logger found for #{name} (available: #{available_event_loggers.join(', ')})"
+ event_logger_class = by_name(name.to_s)
+ raise UnknownEventLogger, "No event logger found for #{name} (available: #{available_event_loggers.join(', ')})" unless event_logger_class
raise UnavailableEventLogger unless available_event_loggers.include? name.to_s
event_logger_class.new
end
diff --git a/lib/chef/event_loggers/windows_eventlog.rb b/lib/chef/event_loggers/windows_eventlog.rb
index 7a3a28b61f..1ff87945e7 100644
--- a/lib/chef/event_loggers/windows_eventlog.rb
+++ b/lib/chef/event_loggers/windows_eventlog.rb
@@ -1,7 +1,7 @@
#
-# Author:: Jay Mundrawala (<jdm@getchef.com>)
+# Author:: Jay Mundrawala (<jdm@chef.io>)
#
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/event_loggers/base'
-require 'chef/platform/query_helpers'
-require 'chef/win32/eventlog'
+require "chef/event_loggers/base"
+require "chef/platform/query_helpers"
+require "chef/win32/eventlog"
class Chef
module EventLoggers
@@ -35,14 +35,14 @@ class Chef
LOG_CATEGORY_ID = 11001
# Since we must install the event logger, this is not really configurable
- SOURCE = 'Chef'
+ SOURCE = "Chef"
def self.available?
- return Chef::Platform::windows?
+ Chef::Platform.windows?
end
def initialize
- @eventlog = ::Win32::EventLog::open('Application')
+ @eventlog = ::Win32::EventLog.open("Application")
end
def run_start(version)
@@ -83,7 +83,7 @@ class Chef
[@run_status.run_id,
@run_status.elapsed_time.to_s]
else
- ["UNKNOWN", "UNKNOWN"]
+ %w{UNKNOWN UNKNOWN}
end
@eventlog.report_event(
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index 855c86d9cc..ae62f42b09 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
# Author:: Kyle Goodwin (<kgoodwin@primerevenue.com>)
-# Copyright:: Copyright 2008-2010 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef-config/exceptions'
+require "chef-config/exceptions"
class Chef
# == Chef::Exceptions
@@ -28,12 +28,12 @@ class Chef
ConfigurationError = ChefConfig::ConfigurationError
# Backcompat with Chef::ShellOut code:
- require 'mixlib/shellout/exceptions'
+ require "mixlib/shellout/exceptions"
def self.const_missing(const_name)
if const_name == :ShellCommandFailed
Chef::Log.warn("Chef::Exceptions::ShellCommandFailed is deprecated, use Mixlib::ShellOut::ShellCommandFailed")
- called_from = caller[0..3].inject("Called from:\n") {|msg, trace_line| msg << " #{trace_line}\n" }
+ called_from = caller[0..3].inject("Called from:\n") { |msg, trace_line| msg << " #{trace_line}\n" }
Chef::Log.warn(called_from)
Mixlib::ShellOut::ShellCommandFailed
else
@@ -42,6 +42,8 @@ class Chef
end
class Application < RuntimeError; end
+ class SigInt < RuntimeError; end
+ class SigTerm < RuntimeError; end
class Cron < RuntimeError; end
class Env < RuntimeError; end
class Exec < RuntimeError; end
@@ -56,6 +58,14 @@ class Chef
class UnsupportedAction < RuntimeError; end
class MissingLibrary < RuntimeError; end
+ class DeprecatedExitCode < RuntimeError
+ def initalize
+ super "Exiting with a non RFC 062 Exit Code."
+ require "chef/application/exit_code"
+ Chef::Application::ExitCode.notify_deprecated_exit_code
+ end
+ end
+
class CannotDetermineNodeName < RuntimeError
def initialize
super "Unable to determine node name: configure node_name or configure the system's hostname and fqdn"
@@ -66,11 +76,16 @@ class Chef
class Group < RuntimeError; end
class Link < RuntimeError; end
class Mount < RuntimeError; end
+ class Reboot < Exception; end # rubocop:disable Lint/InheritException
+ class RebootPending < Exception; end # rubocop:disable Lint/InheritException
+ class RebootFailed < Mixlib::ShellOut::ShellCommandFailed; end
+ class ClientUpgraded < Exception; end # rubocop:disable Lint/InheritException
class PrivateKeyMissing < RuntimeError; end
class CannotWritePrivateKey < RuntimeError; end
class RoleNotFound < RuntimeError; end
class DuplicateRole < RuntimeError; end
class ValidationFailed < ArgumentError; end
+ class CannotValidateStaticallyError < ArgumentError; end
class InvalidPrivateKey < ArgumentError; end
class MissingKeyAttribute < ArgumentError; end
class KeyCommandInputError < ArgumentError; end
@@ -92,7 +107,12 @@ class Chef
# for back compat, need to raise an error that inherits from ArgumentError
class CookbookNotFoundInRepo < ArgumentError; end
class RecipeNotFound < ArgumentError; end
+ # AttributeNotFound really means the attribute file could not be found
class AttributeNotFound < RuntimeError; end
+ # NoSuchAttribute is raised on access by node.read!("foo", "bar") when node["foo"]["bar"] does not exist.
+ class NoSuchAttribute < RuntimeError; end
+ # AttributeTypeMismatch is raised by node.write!("foo", "bar", "baz") when e.g. node["foo"] = "bar" (overwriting String with Hash)
+ class AttributeTypeMismatch < RuntimeError; end
class MissingCookbookDependency < StandardError; end # CHEF-5120
class InvalidCommandOption < RuntimeError; end
class CommandTimeout < RuntimeError; end
@@ -137,25 +157,9 @@ class Chef
# Errors originating from calls to the Win32 API
class Win32APIError < RuntimeError; end
- class Win32NetAPIError < Win32APIError
- attr_reader :msg, :error_code
- def initialize(msg, error_code)
- @msg = msg
- @error_code = error_code
-
- formatted_message = ""
- formatted_message << "---- Begin Win32 API output ----\n"
- formatted_message << "Net Api Error Code: #{error_code}\n"
- formatted_message << "Net Api Error Message: #{msg}\n"
- formatted_message << "---- End Win32 API output ----\n"
-
- super(formatted_message)
- end
- end
-
# Thrown when Win32 API layer binds to non-existent Win32 function. Occurs
# when older versions of Windows don't support newer Win32 API functions.
- class Win32APIFunctionNotImplemented < NotImplementedError; end
+ class Win32APIFunctionNotImplemented < NotImplementedError; end # rubocop:disable Lint/InheritException
# Attempting to run windows code on a not-windows node
class Win32NotWindows < RuntimeError; end
class WindowsNotAdmin < RuntimeError; end
@@ -169,6 +173,8 @@ class Chef
class LCMParser < RuntimeError; end
class CannotDetermineHomebrewOwner < Package; end
+ class CannotDetermineWindowsInstallerType < Package; end
+ class NoWindowsPackageSource < Package; end
# Can not create staging file during file deployment
class FileContentStagingError < RuntimeError
@@ -179,7 +185,7 @@ class Chef
# A different version of a cookbook was added to a
# VersionedRecipeList than the one already there.
- class CookbookVersionConflict < ArgumentError ; end
+ class CookbookVersionConflict < ArgumentError; end
# does not follow X.Y.Z format. ArgumentError?
class InvalidPlatformVersion < ArgumentError; end
@@ -190,7 +196,7 @@ class Chef
class InvalidVersionConstraint < ArgumentError; end
# Version constraints are not allowed in chef-solo
- class IllegalVersionConstraint < NotImplementedError; end
+ class IllegalVersionConstraint < NotImplementedError; end # rubocop:disable Lint/InheritException
class MetadataNotValid < StandardError; end
class MetadataNotFound < StandardError
@@ -218,7 +224,7 @@ class Chef
class ImmutableAttributeModification < NoMethodError
def initialize
super "Node attributes are read-only when you do not specify which precedence level to set. " +
- %Q(To set an attribute use code like `node.default["key"] = "value"')
+ %q{To set an attribute use code like `node.default["key"] = "value"'}
end
end
@@ -240,6 +246,10 @@ class Chef
class Win32RegBadValueSize < ArgumentError; end
class Win32RegTypesMismatch < ArgumentError; end
+ # incorrect input for registry_key create action throws following error
+ class RegKeyValuesTypeMissing < ArgumentError; end
+ class RegKeyValuesDataMissing < ArgumentError; end
+
class InvalidEnvironmentPath < ArgumentError; end
class EnvironmentNotFound < RuntimeError; end
@@ -252,7 +262,7 @@ class Chef
class ChildConvergeError < RuntimeError; end
- class DeprecatedFeatureError < RuntimeError;
+ class DeprecatedFeatureError < RuntimeError
def initalize(message)
super("#{message} (raising error due to treat_deprecation_warnings_as_errors being set)")
end
@@ -263,7 +273,7 @@ class Chef
attr_reader :expansion
- def initialize(message_or_expansion=NULL)
+ def initialize(message_or_expansion = NULL)
@expansion = nil
case message_or_expansion
when NULL
@@ -272,7 +282,7 @@ class Chef
super
when RunList::RunListExpansion
@expansion = message_or_expansion
- missing_roles = @expansion.errors.join(', ')
+ missing_roles = @expansion.errors.join(", ")
super("The expanded run list includes nonexistent roles: #{missing_roles}")
end
end
@@ -305,7 +315,7 @@ class Chef
def raise!
unless empty?
- raise self.for_raise
+ raise for_raise
end
end
@@ -342,7 +352,7 @@ class Chef
result = {
"message" => message,
"non_existent_cookbooks" => non_existent_cookbooks,
- "cookbooks_with_no_versions" => cookbooks_with_no_matching_versions
+ "cookbooks_with_no_versions" => cookbooks_with_no_matching_versions,
}
Chef::JSONCompat.to_json(result, *a)
end
@@ -377,7 +387,7 @@ class Chef
"message" => message,
"unsatisfiable_run_list_item" => run_list_item,
"non_existent_cookbooks" => non_existent_cookbooks,
- "most_constrained_cookbooks" => most_constrained_cookbooks
+ "most_constrained_cookbooks" => most_constrained_cookbooks,
}
Chef::JSONCompat.to_json(result, *a)
end
@@ -395,7 +405,10 @@ class Chef
# length declared in the http response.
class ContentLengthMismatch < RuntimeError
def initialize(response_length, content_length)
- super "Response body length #{response_length} does not match HTTP Content-Length header #{content_length}."
+ super <<-EOF
+Response body length #{response_length} does not match HTTP Content-Length header #{content_length}.
+This error is most often caused by network issues (proxies, etc) outside of chef-client.
+ EOF
end
end
@@ -436,18 +449,20 @@ class Chef
end
end
- class AuditControlGroupDuplicate < RuntimeError
+ class AuditError < RuntimeError; end
+
+ class AuditControlGroupDuplicate < AuditError
def initialize(name)
super "Control group with name '#{name}' has already been defined"
end
end
- class AuditNameMissing < RuntimeError; end
- class NoAuditsProvided < RuntimeError
+ class AuditNameMissing < AuditError; end
+ class NoAuditsProvided < AuditError
def initialize
super "You must provide a block with controls"
end
end
- class AuditsFailed < RuntimeError
+ class AuditsFailed < AuditError
def initialize(num_failed, num_total)
super "Audit phase found failures - #{num_failed}/#{num_total} controls failed"
end
@@ -459,7 +474,7 @@ class Chef
class RunFailedWrappingError < RuntimeError
attr_reader :wrapped_errors
def initialize(*errors)
- errors = errors.select {|e| !e.nil?}
+ errors = errors.select { |e| !e.nil? }
output = "Found #{errors.size} errors, they are stored in the backtrace"
@wrapped_errors = errors
super output
@@ -467,8 +482,8 @@ class Chef
def fill_backtrace
backtrace = []
- wrapped_errors.each_with_index do |e,i|
- backtrace << "#{i+1}) #{e.class} - #{e.message}"
+ wrapped_errors.each_with_index do |e, i|
+ backtrace << "#{i + 1}) #{e.class} - #{e.message}"
backtrace += e.backtrace if e.backtrace
backtrace << "" unless i == wrapped_errors.length - 1
end
@@ -482,12 +497,26 @@ class Chef
end
end
+ class CookbookChefVersionMismatch < RuntimeError
+ def initialize(chef_version, cookbook_name, cookbook_version, *constraints)
+ constraint_str = constraints.map { |c| c.requirement.as_list.to_s }.join(", ")
+ super "Cookbook '#{cookbook_name}' version '#{cookbook_version}' depends on chef version #{constraint_str}, but the running chef version is #{chef_version}"
+ end
+ end
+
+ class CookbookOhaiVersionMismatch < RuntimeError
+ def initialize(ohai_version, cookbook_name, cookbook_version, *constraints)
+ constraint_str = constraints.map { |c| c.requirement.as_list.to_s }.join(", ")
+ super "Cookbook '#{cookbook_name}' version '#{cookbook_version}' depends on ohai version #{constraint_str}, but the running ohai version is #{ohai_version}"
+ end
+ end
+
class MultipleDscResourcesFound < RuntimeError
attr_reader :resources_found
def initialize(resources_found)
@resources_found = resources_found
matches_info = @resources_found.each do |r|
- if r['Module'].nil?
+ if r["Module"].nil?
"Resource #{r['Name']} was found in #{r['Module']['Name']}"
else
"Resource #{r['Name']} is a binary resource"
@@ -496,5 +525,8 @@ class Chef
super "Found multiple matching resources. #{matches_info.join("\n")}"
end
end
+
+ # exception specific to invalid usage of 'dsc_resource' resource
+ class DSCModuleNameMissing < ArgumentError; end
end
end
diff --git a/lib/chef/file_access_control.rb b/lib/chef/file_access_control.rb
index cc7fa8fc1a..50a1ea29bb 100644
--- a/lib/chef/file_access_control.rb
+++ b/lib/chef/file_access_control.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'chef/log'
+require "chef/log"
class Chef
@@ -27,10 +27,10 @@ class Chef
class FileAccessControl
if RUBY_PLATFORM =~ /mswin|mingw|windows/
- require 'chef/file_access_control/windows'
+ require "chef/file_access_control/windows"
include FileAccessControl::Windows
else
- require 'chef/file_access_control/unix'
+ require "chef/file_access_control/unix"
include FileAccessControl::Unix
end
diff --git a/lib/chef/file_access_control/unix.rb b/lib/chef/file_access_control/unix.rb
index 8178d5fbf2..66f724ddd8 100644
--- a/lib/chef/file_access_control/unix.rb
+++ b/lib/chef/file_access_control/unix.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
# limitations under the License.
#
-require 'chef/log'
+require "chef/log"
class Chef
class FileAccessControl
@@ -80,19 +80,19 @@ class Chef
if target_uid.nil?
# the user has not specified a permission on the new resource, so we never manage it with FAC
Chef::Log.debug("Found target_uid == nil, so no owner was specified on resource, not managing owner")
- return false
+ false
elsif current_uid.nil?
# the user has specified a permission, and we are creating a file, so always enforce permissions
Chef::Log.debug("Found current_uid == nil, so we are creating a new file, updating owner")
- return true
+ true
elsif target_uid != current_uid
# the user has specified a permission, and it does not match the file, so fix the permission
Chef::Log.debug("Found target_uid != current_uid, updating owner")
- return true
+ true
else
Chef::Log.debug("Found target_uid == current_uid, not updating owner")
# the user has specified a permission, but it matches the file, so behave idempotently
- return false
+ false
end
end
@@ -117,13 +117,13 @@ class Chef
end
def gid_from_resource(resource)
- return nil if resource == nil or resource.group.nil?
+ return nil if resource.nil? || resource.group.nil?
if resource.group.kind_of?(String)
diminished_radix_complement( Etc.getgrnam(resource.group).gid )
elsif resource.group.kind_of?(Integer)
resource.group
else
- Chef::Log.error("The `group` parameter of the #@resource resource is set to an invalid value (#{resource.owner.inspect})")
+ Chef::Log.error("The `group` parameter of the #{@resource} resource is set to an invalid value (#{resource.owner.inspect})")
raise ArgumentError, "cannot resolve #{resource.group.inspect} to gid, group must be a string or integer"
end
rescue ArgumentError
@@ -139,19 +139,19 @@ class Chef
if target_gid.nil?
# the user has not specified a permission on the new resource, so we never manage it with FAC
Chef::Log.debug("Found target_gid == nil, so no group was specified on resource, not managing group")
- return false
+ false
elsif current_gid.nil?
# the user has specified a permission, and we are creating a file, so always enforce permissions
Chef::Log.debug("Found current_gid == nil, so we are creating a new file, updating group")
- return true
+ true
elsif target_gid != current_gid
# the user has specified a permission, and it does not match the file, so fix the permission
Chef::Log.debug("Found target_gid != current_gid, updating group")
- return true
+ true
else
Chef::Log.debug("Found target_gid == current_gid, not updating group")
# the user has specified a permission, but it matches the file, so behave idempotently
- return false
+ false
end
end
@@ -168,7 +168,7 @@ class Chef
end
def mode_from_resource(res)
- return nil if res == nil or res.mode.nil?
+ return nil if res.nil? || res.mode.nil?
(res.mode.respond_to?(:oct) ? res.mode.oct : res.mode.to_i) & 007777
end
@@ -188,21 +188,21 @@ class Chef
if target_mode.nil?
# the user has not specified a permission on the new resource, so we never manage it with FAC
Chef::Log.debug("Found target_mode == nil, so no mode was specified on resource, not managing mode")
- return false
+ false
elsif current_mode.nil?
# the user has specified a permission, and we are creating a file, so always enforce permissions
Chef::Log.debug("Found current_mode == nil, so we are creating a new file, updating mode")
- return true
+ true
elsif target_mode != current_mode
# the user has specified a permission, and it does not match the file, so fix the permission
Chef::Log.debug("Found target_mode != current_mode, updating mode")
- return true
- elsif suid_bit_set? and (should_update_group? or should_update_owner?)
- return true
+ true
+ elsif suid_bit_set? && (should_update_group? || should_update_owner?)
+ true
else
Chef::Log.debug("Found target_mode == current_mode, not updating mode")
# the user has specified a permission, but it matches the file, so behave idempotently
- return false
+ false
end
end
@@ -264,13 +264,13 @@ class Chef
end
def uid_from_resource(resource)
- return nil if resource == nil or resource.owner.nil?
+ return nil if resource.nil? || resource.owner.nil?
if resource.owner.kind_of?(String)
diminished_radix_complement( Etc.getpwnam(resource.owner).uid )
elsif resource.owner.kind_of?(Integer)
resource.owner
else
- Chef::Log.error("The `owner` parameter of the #@resource resource is set to an invalid value (#{resource.owner.inspect})")
+ Chef::Log.error("The `owner` parameter of the #{@resource} resource is set to an invalid value (#{resource.owner.inspect})")
raise ArgumentError, "cannot resolve #{resource.owner.inspect} to uid, owner must be a string or integer"
end
rescue ArgumentError
@@ -283,7 +283,7 @@ class Chef
end
def suid_bit_set?
- return target_mode & 04000 > 0
+ target_mode & 04000 > 0
end
end
end
diff --git a/lib/chef/file_access_control/windows.rb b/lib/chef/file_access_control/windows.rb
index 1781a6fa63..2c6b69c257 100644
--- a/lib/chef/file_access_control/windows.rb
+++ b/lib/chef/file_access_control/windows.rb
@@ -1,7 +1,7 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/win32/security'
-require 'chef/win32/file'
+require "chef/win32/security"
+require "chef/win32/file"
class Chef
class FileAccessControl
@@ -100,7 +100,7 @@ class Chef
new_target_acl << children_ace
end
end
- return actual_acl == new_target_acl
+ actual_acl == new_target_acl
end
def existing_descriptor
@@ -128,7 +128,7 @@ class Chef
end
def should_update_dacl?
- return true unless ::File.exists?(file)
+ return true unless ::File.exists?(file) || ::File.symlink?(file)
dacl = target_dacl
existing_dacl = existing_descriptor.dacl
inherits = target_inherits
@@ -161,7 +161,7 @@ class Chef
end
def should_update_group?
- return true unless ::File.exists?(file)
+ return true unless ::File.exists?(file) || ::File.symlink?(file)
(group = target_group) && (group != existing_descriptor.group)
end
@@ -180,7 +180,7 @@ class Chef
end
def should_update_owner?
- return true unless ::File.exists?(file)
+ return true unless ::File.exists?(file) || ::File.symlink?(file)
(owner = target_owner) && (owner != existing_descriptor.owner)
end
@@ -319,7 +319,7 @@ class Chef
def target_group
return nil if resource.group.nil?
- sid = get_sid(resource.group)
+ get_sid(resource.group)
end
def target_inherits
@@ -328,7 +328,7 @@ class Chef
def target_owner
return nil if resource.owner.nil?
- sid = get_sid(resource.owner)
+ get_sid(resource.owner)
end
end
end
diff --git a/lib/chef/file_cache.rb b/lib/chef/file_cache.rb
index c2f77bdff6..8e9bb1e3e4 100644
--- a/lib/chef/file_cache.rb
+++ b/lib/chef/file_cache.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,12 +15,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/mixin/params_validate'
-require 'chef/mixin/create_path'
-require 'chef/exceptions'
-require 'chef/json_compat'
-require 'fileutils'
-require 'chef/util/path_helper'
+require "chef/mixin/params_validate"
+require "chef/mixin/create_path"
+require "chef/exceptions"
+require "chef/json_compat"
+require "fileutils"
+require "chef/util/path_helper"
class Chef
class FileCache
@@ -39,11 +39,11 @@ class Chef
#
# === Returns
# true
- def store(path, contents, perm=0640)
+ def store(path, contents, perm = 0640)
validate(
{
:path => path,
- :contents => contents
+ :contents => contents,
},
{
:path => { :kind_of => String },
@@ -69,7 +69,7 @@ class Chef
validate(
{
:file => file,
- :path => path
+ :path => path,
},
{
:file => { :kind_of => String },
@@ -85,7 +85,7 @@ class Chef
File.join(create_cache_path(File.join(file_path_array), true), file_name)
)
else
- raise RuntimeError, "Cannot move #{file} to #{path}!"
+ raise "Cannot move #{file} to #{path}!"
end
end
@@ -102,13 +102,13 @@ class Chef
#
# === Raises
# Chef::Exceptions::FileNotFound:: If it cannot find the file in the cache
- def load(path, read=true)
+ def load(path, read = true)
validate(
{
- :path => path
+ :path => path,
},
{
- :path => { :kind_of => String }
+ :path => { :kind_of => String },
}
)
cache_path = create_cache_path(path, false)
@@ -131,7 +131,7 @@ class Chef
def delete(path)
validate(
{
- :path => path
+ :path => path,
},
{
:path => { :kind_of => String },
@@ -158,9 +158,9 @@ class Chef
# [String] - An array of file cache keys matching the glob
def find(glob_pattern)
keys = Array.new
- Dir[File.join(Chef::Util::PathHelper.escape_glob(file_cache_path), glob_pattern)].each do |f|
+ Dir[File.join(Chef::Util::PathHelper.escape_glob_dir(file_cache_path), glob_pattern)].each do |f|
if File.file?(f)
- keys << f[/^#{Regexp.escape(Dir[Chef::Util::PathHelper.escape_glob(file_cache_path)].first) + File::Separator}(.+)/, 1]
+ keys << f[/^#{Regexp.escape(Dir[Chef::Util::PathHelper.escape_glob_dir(file_cache_path)].first) + File::Separator}(.+)/, 1]
end
end
keys
@@ -178,7 +178,7 @@ class Chef
def has_key?(path)
validate(
{
- :path => path
+ :path => path,
},
{
:path => { :kind_of => String },
@@ -201,7 +201,7 @@ class Chef
#
# === Returns
# String:: The fully expanded path
- def create_cache_path(path, create_if_missing=true)
+ def create_cache_path(path, create_if_missing = true)
cache_dir = File.expand_path(File.join(file_cache_path, path))
if create_if_missing
create_path(cache_dir)
diff --git a/lib/chef/file_content_management/content_base.rb b/lib/chef/file_content_management/content_base.rb
index 985e22213c..6080e37180 100644
--- a/lib/chef/file_content_management/content_base.rb
+++ b/lib/chef/file_content_management/content_base.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/file_content_management/deploy.rb b/lib/chef/file_content_management/deploy.rb
index 35ea3c6fc8..1e3ae55c21 100644
--- a/lib/chef/file_content_management/deploy.rb
+++ b/lib/chef/file_content_management/deploy.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'chef/file_content_management/deploy/cp'
-require 'chef/file_content_management/deploy/mv_unix'
+require "chef/file_content_management/deploy/cp"
+require "chef/file_content_management/deploy/mv_unix"
if Chef::Platform.windows?
- require 'chef/file_content_management/deploy/mv_windows'
+ require "chef/file_content_management/deploy/mv_windows"
end
class Chef
@@ -35,4 +35,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/file_content_management/deploy/cp.rb b/lib/chef/file_content_management/deploy/cp.rb
index ea378c2e5d..14dde85d13 100644
--- a/lib/chef/file_content_management/deploy/cp.rb
+++ b/lib/chef/file_content_management/deploy/cp.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/file_content_management/deploy/mv_unix.rb b/lib/chef/file_content_management/deploy/mv_unix.rb
index 9712486424..3805b3bef3 100644
--- a/lib/chef/file_content_management/deploy/mv_unix.rb
+++ b/lib/chef/file_content_management/deploy/mv_unix.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -74,4 +74,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/file_content_management/deploy/mv_windows.rb b/lib/chef/file_content_management/deploy/mv_windows.rb
index e2951dba4c..0e6e6cd76f 100644
--- a/lib/chef/file_content_management/deploy/mv_windows.rb
+++ b/lib/chef/file_content_management/deploy/mv_windows.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,9 +21,9 @@
# ACL information on the dst file.
#
-require 'chef/platform/query_helpers'
+require "chef/platform/query_helpers"
if Chef::Platform.windows?
- require 'chef/win32/security'
+ require "chef/win32/security"
end
class Chef
@@ -96,10 +96,8 @@ class Chef
dst_so.owner = dst_sd.owner
dst_so.set_dacl(apply_dacl, dst_sd.dacl_inherits?) if dacl_present
dst_so.set_sacl(apply_sacl, dst_sd.sacl_inherits?) if sacl_present
-
end
end
end
end
end
-
diff --git a/lib/chef/file_content_management/tempfile.rb b/lib/chef/file_content_management/tempfile.rb
index 6e1624f9a4..cf59a87996 100644
--- a/lib/chef/file_content_management/tempfile.rb
+++ b/lib/chef/file_content_management/tempfile.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -40,7 +40,8 @@ class Chef
tempfile_dirnames.each do |tempfile_dirname|
begin
- tf = ::Tempfile.open(tempfile_basename, tempfile_dirname)
+ # preserving the file extension of the target filename should be considered a public API
+ tf = ::Tempfile.open([tempfile_basename, tempfile_extension], tempfile_dirname)
break
rescue SystemCallError => e
message = "Creating temp file under '#{tempfile_dirname}' failed with: '#{e.message}'"
@@ -63,11 +64,21 @@ class Chef
# as the arguments to Tempfile.new() consistently.
#
def tempfile_basename
- basename = ::File.basename(@new_resource.name)
- basename.insert 0, "." unless Chef::Platform.windows? # dotfile if we're not on windows
+ basename = ::File.basename(@new_resource.path, tempfile_extension)
+ # the leading "[.]chef-" here should be considered a public API and should not be changed
+ basename.insert 0, "chef-"
+ basename.insert 0, "." unless Chef::Platform.windows? # dotfile if we're not on windows
basename
end
+ # this is similar to File.extname() but greedy about the extension (from the first dot, not the last dot)
+ def tempfile_extension
+ # complexity here is due to supporting mangling non-UTF8 strings (e.g. latin-1 filenames with characters that are illegal in UTF-8)
+ b = File.basename(@new_resource.path)
+ i = b.index(".")
+ i.nil? ? "" : b[i..-1]
+ end
+
# Returns the possible directories for the tempfile to be created in.
def tempfile_dirnames
# in why-run mode we need to create a Tempfile to compare against, which we will never
diff --git a/lib/chef/formatters/base.rb b/lib/chef/formatters/base.rb
index d3756ef00c..2fbe00862c 100644
--- a/lib/chef/formatters/base.rb
+++ b/lib/chef/formatters/base.rb
@@ -1,7 +1,7 @@
#
-# Author:: Tyler Cloke (<tyler@opscode.com>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
#
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +17,11 @@
# limitations under the License.
#
-require 'chef/event_dispatch/base'
-require 'chef/formatters/error_inspectors'
-require 'chef/formatters/error_descriptor'
-require 'chef/formatters/error_mapper'
-require 'chef/formatters/indentable_output_stream'
+require "chef/event_dispatch/base"
+require "chef/formatters/error_inspectors"
+require "chef/formatters/error_description"
+require "chef/formatters/error_mapper"
+require "chef/formatters/indentable_output_stream"
class Chef
@@ -51,8 +51,8 @@ class Chef
#--
# TODO: is it too clever to be defining new() on a module like this?
def self.new(name, out, err)
- formatter_class = by_name(name.to_s) or
- raise UnknownFormatter, "No output formatter found for #{name} (available: #{available_formatters.join(', ')})"
+ formatter_class = by_name(name.to_s)
+ raise UnknownFormatter, "No output formatter found for #{name} (available: #{available_formatters.join(', ')})" unless formatter_class
formatter_class.new(out, err)
end
@@ -203,20 +203,33 @@ class Chef
end
# Delegates to #file_loaded
- def recipe_file_loaded(path)
+ def recipe_file_loaded(path, recipe)
file_loaded(path)
end
# Delegates to #file_load_failed
- def recipe_file_load_failed(path, exception)
+ def recipe_file_load_failed(path, exception, recipe)
file_load_failed(path, exception)
end
- def deprecation(message, location=caller(2..2)[0])
- Chef::Log.deprecation("#{message} at #{location}")
+ def deprecation(message, location = caller(2..2)[0])
+ out = if is_structured_deprecation?(message)
+ message.inspect
+ else
+ "#{message} at #{location}"
+ end
+
+ Chef::Log.deprecation(out)
end
- end
+ def is_structured_deprecation?(deprecation)
+ deprecation.kind_of?(Chef::Deprecated::Base)
+ end
+
+ def is_formatter?
+ true
+ end
+ end
# == NullFormatter
# Formatter that doesn't actually produce any output. You can use this to
@@ -225,6 +238,9 @@ class Chef
cli_name(:null)
+ def is_formatter?
+ false
+ end
end
end
diff --git a/lib/chef/formatters/doc.rb b/lib/chef/formatters/doc.rb
index 70108f547b..0c51cc2cfb 100644
--- a/lib/chef/formatters/doc.rb
+++ b/lib/chef/formatters/doc.rb
@@ -1,5 +1,5 @@
-require 'chef/formatters/base'
-require 'chef/config'
+require "chef/formatters/base"
+require "chef/config"
class Chef
module Formatters
@@ -23,6 +23,7 @@ class Chef
@start_time = Time.now
@end_time = @start_time
@skipped_resources = 0
+ @progress = {}
end
def elapsed_time
@@ -31,9 +32,9 @@ class Chef
def pretty_elapsed_time
time = elapsed_time
- if time < 60 then
+ if time < 60
message = Time.at(time).utc.strftime("%S seconds")
- elsif time < 3600 then
+ elsif time < 3600
message = Time.at(time).utc.strftime("%M minutes %S seconds")
else
message = Time.at(time).utc.strftime("%H hours %M minutes %S seconds")
@@ -43,6 +44,7 @@ class Chef
def run_start(version)
puts_line "Starting Chef Client, version #{version}"
+ puts_line "OpenSSL FIPS 140 mode enabled" if Chef::Config[:fips]
end
def total_resources
@@ -59,9 +61,10 @@ class Chef
if !deprecations.empty?
puts_line ""
puts_line "Deprecated features used!"
- deprecations.each do |message, locations|
+ deprecations.each do |message, details|
+ locations = details[:locations]
if locations.size == 1
- puts_line " #{message} at #{locations.size} location:"
+ puts_line " #{message} at 1 location:"
else
puts_line " #{message} at #{locations.size} locations:"
end
@@ -72,6 +75,9 @@ class Chef
prefix = " "
end
end
+ unless details[:url].nil?
+ puts_line " See #{details[:url]} for further details."
+ end
end
puts_line ""
end
@@ -179,6 +185,32 @@ class Chef
unindent
end
+ # Called when starting to collect gems from the cookbooks
+ def cookbook_gem_start(gems)
+ puts_line "Installing Cookbook Gems:"
+ indent
+ end
+
+ # Called when the result of installing the bundle is to install the gem
+ def cookbook_gem_installing(gem, version)
+ puts_line "- Installing #{gem} #{version}", :green
+ end
+
+ # Called when the result of installing the bundle is to use the gem
+ def cookbook_gem_using(gem, version)
+ puts_line "- Using #{gem} #{version}"
+ end
+
+ # Called when finished installing cookbook gems
+ def cookbook_gem_finished
+ unindent
+ end
+
+ # Called when cookbook gem installation fails
+ def cookbook_gem_failed(exception)
+ unindent
+ end
+
# Called when cookbook loading starts.
def library_load_start(file_count)
puts_line "Compiling Cookbooks..."
@@ -239,7 +271,7 @@ class Chef
end
# Called before action is executed on a resource.
- def resource_action_start(resource, action, notification_type=nil, notifier=nil)
+ def resource_action_start(resource, action, notification_type = nil, notifier = nil)
if resource.cookbook_name && resource.recipe_name
resource_recipe = "#{resource.cookbook_name}::#{resource.recipe_name}"
else
@@ -257,6 +289,21 @@ class Chef
indent
end
+ def resource_update_progress(resource, current, total, interval)
+ @progress[resource] ||= 0
+
+ percent_complete = (current.to_f / total.to_f * 100).to_i
+
+ if percent_complete > @progress[resource]
+
+ @progress[resource] = percent_complete
+
+ if percent_complete % interval == 0
+ start_line " - Progress: #{percent_complete}%", :green
+ end
+ end
+ end
+
# Called when a resource fails, but will retry.
def resource_failed_retriable(resource, action, retry_count, exception)
end
@@ -281,7 +328,7 @@ class Chef
# Called when a resource has no converge actions, e.g., it was already correct.
def resource_up_to_date(resource, action)
- @up_to_date_resources+= 1
+ @up_to_date_resources += 1
puts " (up to date)", :stream => resource
unindent
end
@@ -292,7 +339,6 @@ class Chef
end
def output_record(line)
-
end
# Called when a change has been made to a resource. May be called multiple
@@ -334,7 +380,7 @@ class Chef
# Called before handlers run
def handlers_start(handler_count)
- puts ''
+ puts ""
puts "Running handlers:"
indent
end
@@ -368,14 +414,19 @@ class Chef
end
end
- def deprecation(message, location=caller(2..2)[0])
+ def deprecation(message, location = caller(2..2)[0])
if Chef::Config[:treat_deprecation_warnings_as_errors]
super
end
# Save deprecations to the screen until the end
- deprecations[message] ||= Set.new
- deprecations[message] << location
+ if is_structured_deprecation?(message)
+ url = message.url
+ message = message.message
+ end
+
+ deprecations[message] ||= { url: url, locations: Set.new }
+ deprecations[message][:locations] << location
end
def indent
diff --git a/lib/chef/formatters/error_descriptor.rb b/lib/chef/formatters/error_description.rb
index c2e656f167..ece33bdd49 100644
--- a/lib/chef/formatters/error_descriptor.rb
+++ b/lib/chef/formatters/error_description.rb
@@ -1,7 +1,7 @@
#
-# Author:: Tyler Cloke (<tyler@opscode.com>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
#
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,7 +31,7 @@ class Chef
end
def section(heading, text)
- @sections << {heading => (text or "")}
+ @sections << { heading => (text || "") }
end
def display(out)
@@ -39,17 +39,19 @@ class Chef
out.puts @title, :red
out.puts "=" * 80
out.puts "\n"
+
sections.each do |section|
section.each do |heading, text|
display_section(heading, text, out)
end
end
+ display_section("Platform:", RUBY_PLATFORM, out)
end
- def for_json()
+ def for_json
{
- 'title' => @title,
- 'sections' => @sections
+ "title" => @title,
+ "sections" => @sections,
}
end
diff --git a/lib/chef/formatters/error_inspectors.rb b/lib/chef/formatters/error_inspectors.rb
index 418457322d..9221ecda4d 100644
--- a/lib/chef/formatters/error_inspectors.rb
+++ b/lib/chef/formatters/error_inspectors.rb
@@ -1,9 +1,9 @@
-require 'chef/formatters/error_inspectors/node_load_error_inspector'
+require "chef/formatters/error_inspectors/node_load_error_inspector"
require "chef/formatters/error_inspectors/registration_error_inspector"
-require 'chef/formatters/error_inspectors/compile_error_inspector'
-require 'chef/formatters/error_inspectors/resource_failure_inspector'
-require 'chef/formatters/error_inspectors/run_list_expansion_error_inspector'
-require 'chef/formatters/error_inspectors/cookbook_resolve_error_inspector'
+require "chef/formatters/error_inspectors/compile_error_inspector"
+require "chef/formatters/error_inspectors/resource_failure_inspector"
+require "chef/formatters/error_inspectors/run_list_expansion_error_inspector"
+require "chef/formatters/error_inspectors/cookbook_resolve_error_inspector"
require "chef/formatters/error_inspectors/cookbook_sync_error_inspector"
class Chef
diff --git a/lib/chef/formatters/error_inspectors/api_error_formatting.rb b/lib/chef/formatters/error_inspectors/api_error_formatting.rb
index 05ee3132a7..53549ee77c 100644
--- a/lib/chef/formatters/error_inspectors/api_error_formatting.rb
+++ b/lib/chef/formatters/error_inspectors/api_error_formatting.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/http/authenticator'
+require "chef/http/authenticator"
class Chef
module Formatters
@@ -26,30 +26,66 @@ class Chef
NETWORK_ERROR_CLASSES = [Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError]
def describe_network_errors(error_description)
- error_description.section("Networking Error:",<<-E)
+ error_description.section("Networking Error:", <<-E)
#{exception.message}
Your chef_server_url may be misconfigured, or the network could be down.
E
- error_description.section("Relevant Config Settings:",<<-E)
+ error_description.section("Relevant Config Settings:", <<-E)
chef_server_url "#{server_url}"
E
end
+ def describe_eof_error(error_description)
+ error_description.section("Authentication Error:", <<-E)
+Received an EOF on transport socket. This almost always indicates a network
+error external to chef-client. Some causes include:
+
+ - Blocking ICMP Dest Unreachable (breaking Path MTU Discovery)
+ - IPsec or VPN tunnelling / TCP Encapsulation MTU issues
+ - Jumbo frames configured only on one side (breaking Path MTU)
+ - Jumbo frames configured on a LAN that does not support them
+ - Proxies or Load Balancers breaking large POSTs
+ - Broken TCP offload in network drivers/hardware
+
+Try sending large pings to the destination:
+
+ windows: ping server.example.com -f -l 9999
+ unix: ping server.example.com -s 9999
+
+Try sending large POSTs to the destination (any HTTP code returned is success):
+
+ e.g.: curl http://server.example.com/`printf '%*s' 9999 '' | tr ' ' 'a'`
+
+Try disabling TCP Offload Engines (TOE) in your ethernet drivers.
+
+ windows:
+ Disable-NetAdapterChecksumOffload * -TcpIPv4 -UdpIPv4 -IpIPv4 -NoRestart
+ Disable-NetAdapterLso * -IPv4 -NoRestart
+ Set-NetAdapterAdvancedProperty * -DisplayName "Large Receive Offload (IPv4)" -DisplayValue Disabled –NoRestart
+ Restart-NetAdapter *
+ unix(bash):
+ for i in rx tx sg tso ufo gso gro lro rxvlan txvlan rxhash; do /sbin/ethtool -K eth0 $i off; done
+
+In some cases the underlying virtualization layer (Xen, VMware, KVM, Hyper-V, etc) may have
+broken virtual networking code.
+ E
+ end
+
def describe_401_error(error_description)
if clock_skew?
- error_description.section("Authentication Error:",<<-E)
+ error_description.section("Authentication Error:", <<-E)
Failed to authenticate to the chef server (http 401).
The request failed because your clock has drifted by more than 15 minutes.
Syncing your clock to an NTP Time source should resolve the issue.
E
else
- error_description.section("Authentication Error:",<<-E)
+ error_description.section("Authentication Error:", <<-E)
Failed to authenticate to the chef server (http 401).
E
error_description.section("Server Response:", format_rest_error)
- error_description.section("Relevant Config Settings:",<<-E)
+ error_description.section("Relevant Config Settings:", <<-E)
chef_server_url "#{server_url}"
node_name "#{username}"
client_key "#{api_key}"
@@ -61,10 +97,10 @@ E
end
def describe_400_error(error_description)
- error_description.section("Invalid Request Data:",<<-E)
+ error_description.section("Invalid Request Data:", <<-E)
The data in your request was invalid (HTTP 400).
E
- error_description.section("Server Response:",format_rest_error)
+ error_description.section("Server Response:", format_rest_error)
end
def describe_406_error(error_description, response)
@@ -74,7 +110,7 @@ E
min_server_version = version_header["min_version"]
max_server_version = version_header["max_version"]
- error_description.section("Incompatible server API version:",<<-E)
+ error_description.section("Incompatible server API version:", <<-E)
This version of the API that this Chef request specified is not supported by the Chef server you sent this request to.
The server supports a min API version of #{min_server_version} and a max API version of #{max_server_version}.
Chef just made a request with an API version of #{client_api_version}.
@@ -86,18 +122,17 @@ E
end
def describe_500_error(error_description)
- error_description.section("Unknown Server Error:",<<-E)
+ error_description.section("Unknown Server Error:", <<-E)
The server had a fatal error attempting to load the node data.
E
error_description.section("Server Response:", format_rest_error)
end
def describe_503_error(error_description)
- error_description.section("Server Unavailable","The Chef Server is temporarily unavailable")
+ error_description.section("Server Unavailable", "The Chef Server is temporarily unavailable")
error_description.section("Server Response:", format_rest_error)
end
-
# Fallback for unexpected/uncommon http errors
def describe_http_error(error_description)
error_description.section("Unexpected API Request Failure:", format_rest_error)
@@ -106,7 +141,7 @@ E
# Parses JSON from the error response sent by Chef Server and returns the
# error message
def format_rest_error
- Array(Chef::JSONCompat.from_json(exception.response.body)["error"]).join('; ')
+ Array(Chef::JSONCompat.from_json(exception.response.body)["error"]).join("; ")
rescue Exception
safe_format_rest_error
end
@@ -137,11 +172,10 @@ E
# .../lib/ruby/1.9.1/net/http.rb:2709:in `read_body'
# .../lib/ruby/1.9.1/net/http.rb:2736:in `body'
# .../lib/chef/formatters/error_inspectors/api_error_formatting.rb:91:in `rescue in format_rest_error'
- begin
- exception.response.body
- rescue Exception
- "Cannot fetch the contents of the response."
- end
+
+ exception.response.body
+ rescue Exception
+ "Cannot fetch the contents of the response."
end
end
diff --git a/lib/chef/formatters/error_inspectors/compile_error_inspector.rb b/lib/chef/formatters/error_inspectors/compile_error_inspector.rb
index 621fadce40..d5ed69a83d 100644
--- a/lib/chef/formatters/error_inspectors/compile_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/compile_error_inspector.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -40,7 +40,7 @@ class Chef
error_description.section(exception.class.name, exception.message)
if found_error_in_cookbooks?
- traceback = filtered_bt.map {|line| " #{line}"}.join("\n")
+ traceback = filtered_bt.map { |line| " #{line}" }.join("\n")
error_description.section("Cookbook Trace:", traceback)
error_description.section("Relevant File Content:", context)
end
@@ -74,7 +74,7 @@ class Chef
MESSAGE
- error_description.section("Additional information:", msg.gsub(/^ {6}/, ''))
+ error_description.section("Additional information:", msg.gsub(/^ {6}/, ""))
end
end
@@ -107,22 +107,22 @@ class Chef
def culprit_backtrace_entry
@culprit_backtrace_entry ||= begin
- bt_entry = filtered_bt.first
- Chef::Log.debug("Backtrace entry for compile error: '#{bt_entry}'")
- bt_entry
+ bt_entry = filtered_bt.first
+ Chef::Log.debug("Backtrace entry for compile error: '#{bt_entry}'")
+ bt_entry
end
end
def culprit_line
@culprit_line ||= begin
- line_number = culprit_backtrace_entry[/^(?:.\:)?[^:]+:([\d]+)/,1].to_i
+ line_number = culprit_backtrace_entry[/^(?:.\:)?[^:]+:([\d]+)/, 1].to_i
Chef::Log.debug("Line number of compile error: '#{line_number}'")
line_number
end
end
def culprit_file
- @culprit_file ||= culprit_backtrace_entry[/^((?:.\:)?[^:]+):([\d]+)/,1]
+ @culprit_file ||= culprit_backtrace_entry[/^((?:.\:)?[^:]+):([\d]+)/, 1]
end
def filtered_bt
@@ -136,8 +136,8 @@ class Chef
def backtrace_lines_in_cookbooks
@backtrace_lines_in_cookbooks ||=
begin
- filters = Array(Chef::Config.cookbook_path).map {|p| /^#{Regexp.escape(p)}/i }
- r = exception.backtrace.select {|line| filters.any? {|filter| line =~ filter }}
+ filters = Array(Chef::Config.cookbook_path).map { |p| /^#{Regexp.escape(p)}/i }
+ r = exception.backtrace.select { |line| filters.any? { |filter| line =~ filter } }
Chef::Log.debug("Filtered backtrace of compile error: #{r.join(",")}")
r
end
diff --git a/lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb b/lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb
index e011fa9d9b..eb1aa629ff 100644
--- a/lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/formatters/error_inspectors/api_error_formatting'
+require "chef/formatters/error_inspectors/api_error_formatting"
class Chef
module Formatters
@@ -37,10 +37,12 @@ class Chef
case exception
when Net::HTTPServerException, Net::HTTPFatalError
humanize_http_exception(error_description)
+ when EOFError
+ describe_eof_error(error_description)
when *NETWORK_ERROR_CLASSES
describe_network_errors(error_description)
else
- error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}")
+ error_description.section("Unexpected Error:", "#{exception.class.name}: #{exception.message}")
end
end
@@ -54,7 +56,7 @@ class Chef
# TODO: we're rescuing errors from Node.find_or_create
# * could be no write on nodes container
# * could be no read on the node
- error_description.section("Authorization Error",<<-E)
+ error_description.section("Authorization Error", <<-E)
This client is not authorized to read some of the information required to
access its cookbooks (HTTP 403).
@@ -126,7 +128,7 @@ EOM
end
def expanded_run_list_ul
- @expanded_run_list.map {|i| "* #{i}"}.join("\n")
+ @expanded_run_list.map { |i| "* #{i}" }.join("\n")
end
# In my tests, the error from the server is double JSON encoded, but we
@@ -160,9 +162,7 @@ EOM
maybe_json_string
end
-
end
end
end
end
-
diff --git a/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb b/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb
index 971dbd664e..3bd9b419fa 100644
--- a/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/formatters/error_inspectors/api_error_formatting'
+require "chef/formatters/error_inspectors/api_error_formatting"
class Chef
module Formatters
@@ -41,12 +41,14 @@ class Chef
def add_explanation(error_description)
case exception
- when *NETWORK_ERROR_CLASSES
- describe_network_errors(error_description)
when Net::HTTPServerException, Net::HTTPFatalError
humanize_http_exception(error_description)
+ when EOFError
+ describe_eof_error(error_description)
+ when *NETWORK_ERROR_CLASSES
+ describe_network_errors(error_description)
else
- error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}")
+ error_description.section("Unexpected Error:", "#{exception.class.name}: #{exception.message}")
end
end
diff --git a/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb b/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
index d81a9f7cc8..c52dad4c09 100644
--- a/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,12 @@
# limitations under the License.
#
-require 'chef/formatters/error_inspectors/api_error_formatting'
+require "chef/formatters/error_inspectors/api_error_formatting"
class Chef
module Formatters
module ErrorInspectors
-
# == APIErrorInspector
# Wraps exceptions caused by API calls to the server.
class NodeLoadErrorInspector
@@ -43,18 +42,20 @@ class Chef
case exception
when Net::HTTPServerException, Net::HTTPFatalError
humanize_http_exception(error_description)
- when *NETWORK_ERROR_CLASSES
- describe_network_errors(error_description)
when Chef::Exceptions::PrivateKeyMissing
- error_description.section("Private Key Not Found:",<<-E)
+ error_description.section("Private Key Not Found:", <<-E)
Your private key could not be loaded. If the key file exists, ensure that it is
readable by chef-client.
E
- error_description.section("Relevant Config Settings:",<<-E)
+ error_description.section("Relevant Config Settings:", <<-E)
client_key "#{api_key}"
E
+ when EOFError
+ describe_eof_error(error_description)
+ when *NETWORK_ERROR_CLASSES
+ describe_network_errors(error_description)
else
- error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}")
+ error_description.section("Unexpected Error:", "#{exception.class.name}: #{exception.message}")
end
end
@@ -68,12 +69,12 @@ E
# TODO: we're rescuing errors from Node.find_or_create
# * could be no write on nodes container
# * could be no read on the node
- error_description.section("Authorization Error",<<-E)
+ error_description.section("Authorization Error", <<-E)
Your client is not authorized to load the node data (HTTP 403).
E
error_description.section("Server Response:", format_rest_error)
- error_description.section("Possible Causes:",<<-E)
+ error_description.section("Possible Causes:", <<-E)
* Your client (#{username}) may have misconfigured authorization permissions.
E
when Net::HTTPBadRequest
@@ -96,10 +97,10 @@ E
# one, e.g., PUT http://wrong.url/nodes/node-name becomes a GET after a
# redirect.
def describe_404_error(error_description)
- error_description.section("Resource Not Found:",<<-E)
+ error_description.section("Resource Not Found:", <<-E)
The server returned a HTTP 404. This usually indicates that your chef_server_url is incorrect.
E
- error_description.section("Relevant Config Settings:",<<-E)
+ error_description.section("Relevant Config Settings:", <<-E)
chef_server_url "#{server_url}"
E
end
diff --git a/lib/chef/formatters/error_inspectors/registration_error_inspector.rb b/lib/chef/formatters/error_inspectors/registration_error_inspector.rb
index dbd23f4a52..c7c1454311 100644
--- a/lib/chef/formatters/error_inspectors/registration_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/registration_error_inspector.rb
@@ -26,27 +26,29 @@ class Chef
when Net::HTTPServerException, Net::HTTPFatalError
humanize_http_exception(error_description)
when Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError
- error_description.section("Network Error:",<<-E)
+ error_description.section("Network Error:", <<-E)
There was a network error connecting to the Chef Server:
#{exception.message}
E
- error_description.section("Relevant Config Settings:",<<-E)
+ error_description.section("Relevant Config Settings:", <<-E)
chef_server_url "#{server_url}"
If your chef_server_url is correct, your network could be down.
E
when Chef::Exceptions::PrivateKeyMissing
- error_description.section("Private Key Not Found:",<<-E)
+ error_description.section("Private Key Not Found:", <<-E)
Your private key could not be loaded. If the key file exists, ensure that it is
readable by chef-client.
E
- error_description.section("Relevant Config Settings:",<<-E)
+ error_description.section("Relevant Config Settings:", <<-E)
validation_key "#{api_key}"
E
when Chef::Exceptions::InvalidRedirect
- error_description.section("Invalid Redirect:",<<-E)
+ error_description.section("Invalid Redirect:", <<-E)
Change your server location in client.rb to the server's FQDN to avoid unwanted redirections.
E
+ when EOFError
+ describe_eof_error(error_description)
else
"#{exception.class.name}: #{exception.message}"
end
@@ -57,18 +59,18 @@ E
case response
when Net::HTTPUnauthorized
if clock_skew?
- error_description.section("Authentication Error:",<<-E)
+ error_description.section("Authentication Error:", <<-E)
Failed to authenticate to the chef server (http 401).
The request failed because your clock has drifted by more than 15 minutes.
Syncing your clock to an NTP Time source should resolve the issue.
E
else
- error_description.section("Authentication Error:",<<-E)
+ error_description.section("Authentication Error:", <<-E)
Failed to authenticate to the chef server (http 401).
E
error_description.section("Server Response:", format_rest_error)
- error_description.section("Relevant Config Settings:",<<-E)
+ error_description.section("Relevant Config Settings:", <<-E)
chef_server_url "#{server_url}"
validation_client_name "#{username}"
validation_key "#{api_key}"
@@ -77,34 +79,34 @@ If these settings are correct, your validation_key may be invalid.
E
end
when Net::HTTPForbidden
- error_description.section("Authorization Error:",<<-E)
+ error_description.section("Authorization Error:", <<-E)
Your validation client is not authorized to create the client for this node (HTTP 403).
E
- error_description.section("Possible Causes:",<<-E)
+ error_description.section("Possible Causes:", <<-E)
* There may already be a client named "#{config[:node_name]}"
* Your validation client (#{username}) may have misconfigured authorization permissions.
E
when Net::HTTPBadRequest
- error_description.section("Invalid Request Data:",<<-E)
+ error_description.section("Invalid Request Data:", <<-E)
The data in your request was invalid (HTTP 400).
E
- error_description.section("Server Response:",format_rest_error)
+ error_description.section("Server Response:", format_rest_error)
when Net::HTTPNotFound
- error_description.section("Resource Not Found:",<<-E)
+ error_description.section("Resource Not Found:", <<-E)
The server returned a HTTP 404. This usually indicates that your chef_server_url is incorrect.
E
- error_description.section("Relevant Config Settings:",<<-E)
+ error_description.section("Relevant Config Settings:", <<-E)
chef_server_url "#{server_url}"
E
when Net::HTTPNotAcceptable
describe_406_error(error_description, response)
when Net::HTTPInternalServerError
- error_description.section("Unknown Server Error:",<<-E)
+ error_description.section("Unknown Server Error:", <<-E)
The server had a fatal error attempting to load the node data.
E
error_description.section("Server Response:", format_rest_error)
when Net::HTTPBadGateway, Net::HTTPServiceUnavailable
- error_description.section("Server Unavailable","The Chef Server is temporarily unavailable")
+ error_description.section("Server Unavailable", "The Chef Server is temporarily unavailable")
error_description.section("Server Response:", format_rest_error)
else
error_description.section("Unexpected API Request Failure:", format_rest_error)
@@ -134,7 +136,7 @@ E
#--
# TODO: this code belongs in Chef::REST
def format_rest_error
- Array(Chef::JSONCompat.from_json(exception.response.body)["error"]).join('; ')
+ Array(Chef::JSONCompat.from_json(exception.response.body)["error"]).join("; ")
rescue Exception
exception.response.body
end
diff --git a/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb b/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
index 6e4d9322f9..94ecce88de 100644
--- a/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
@@ -1,7 +1,7 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -52,7 +52,7 @@ class Chef
end
if Chef::Platform.windows?
- require 'chef/win32/security'
+ require "chef/win32/security"
if !Chef::ReservedNames::Win32::Security.has_admin_privileges?
error_description.section("Missing Windows Admin Privileges", "chef-client doesn't have administrator privileges. This can be a possible reason for the resource failure.")
@@ -63,13 +63,12 @@ class Chef
def recipe_snippet
return nil if dynamic_resource?
@snippet ||= begin
- if file = parse_source and line = parse_line(file)
+ if (file = parse_source) && (line = parse_line(file))
return nil unless ::File.exists?(file)
lines = IO.readlines(file)
relevant_lines = ["# In #{file}\n\n"]
-
current_line = line - 1
current_line = 0 if current_line < 0
nesting = 0
@@ -99,8 +98,8 @@ class Chef
end
def filtered_bt
- filters = Array(Chef::Config.cookbook_path).map {|p| /^#{Regexp.escape(p)}/ }
- exception.backtrace.select {|line| filters.any? {|filter| line =~ filter }}
+ filters = Array(Chef::Config.cookbook_path).map { |p| /^#{Regexp.escape(p)}/ }
+ exception.backtrace.select { |line| filters.any? { |filter| line =~ filter } }
end
private
@@ -112,15 +111,13 @@ class Chef
end
def parse_source
- resource.source_line[/^(([\w]:)?[^:]+):([\d]+)/,1]
+ resource.source_line[/^(([\w]:)?[^:]+):([\d]+)/, 1]
end
def parse_line(source)
- resource.source_line[/^#{Regexp.escape(source)}:([\d]+)/,1].to_i
+ resource.source_line[/^#{Regexp.escape(source)}:([\d]+)/, 1].to_i
end
-
-
end
end
end
diff --git a/lib/chef/formatters/error_inspectors/run_list_expansion_error_inspector.rb b/lib/chef/formatters/error_inspectors/run_list_expansion_error_inspector.rb
index 818228276e..e94b347378 100644
--- a/lib/chef/formatters/error_inspectors/run_list_expansion_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/run_list_expansion_error_inspector.rb
@@ -1,7 +1,7 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'chef/formatters/error_inspectors/api_error_formatting'
+require "chef/formatters/error_inspectors/api_error_formatting"
class Chef
module Formatters
@@ -36,7 +36,7 @@ class Chef
def add_explanation(error_description)
case exception
when Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError
- error_description.section("Networking Error:",<<-E)
+ error_description.section("Networking Error:", <<-E)
#{exception.message}
Your chef_server_url may be misconfigured, or the network could be down.
@@ -45,14 +45,16 @@ E
humanize_http_exception(error_description)
when Chef::Exceptions::MissingRole
describe_missing_role(error_description)
+ when EOFError
+ describe_eof_error(error_description)
else
- error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}")
+ error_description.section("Unexpected Error:", "#{exception.class.name}: #{exception.message}")
end
end
def describe_missing_role(error_description)
error_description.section("Missing Role(s) in Run List:", missing_roles_explained)
- original_run_list = node.run_list.map {|item| "* #{item}"}.join("\n")
+ original_run_list = node.run_list.map { |item| "* #{item}" }.join("\n")
error_description.section("Original Run List", original_run_list)
end
@@ -74,12 +76,12 @@ E
response = exception.response
case response
when Net::HTTPUnauthorized
- error_description.section("Authentication Error:",<<-E)
+ error_description.section("Authentication Error:", <<-E)
Failed to authenticate to the chef server (http 401).
E
error_description.section("Server Response:", format_rest_error)
- error_description.section("Relevant Config Settings:",<<-E)
+ error_description.section("Relevant Config Settings:", <<-E)
chef_server_url "#{server_url}"
node_name "#{username}"
client_key "#{api_key}"
@@ -90,23 +92,23 @@ E
# TODO: we're rescuing errors from Node.find_or_create
# * could be no write on nodes container
# * could be no read on the node
- error_description.section("Authorization Error",<<-E)
+ error_description.section("Authorization Error", <<-E)
Your client is not authorized to load one or more of your roles (HTTP 403).
E
error_description.section("Server Response:", format_rest_error)
- error_description.section("Possible Causes:",<<-E)
+ error_description.section("Possible Causes:", <<-E)
* Your client (#{username}) may have misconfigured authorization permissions.
E
when Net::HTTPNotAcceptable
describe_406_error(error_description, response)
when Net::HTTPInternalServerError
- error_description.section("Unknown Server Error:",<<-E)
+ error_description.section("Unknown Server Error:", <<-E)
The server had a fatal error attempting to load a role.
E
error_description.section("Server Response:", format_rest_error)
when Net::HTTPBadGateway, Net::HTTPServiceUnavailable
- error_description.section("Server Unavailable","The Chef Server is temporarily unavailable")
+ error_description.section("Server Unavailable", "The Chef Server is temporarily unavailable")
error_description.section("Server Response:", format_rest_error)
else
error_description.section("Unexpected API Request Failure:", format_rest_error)
@@ -117,4 +119,3 @@ E
end
end
end
-
diff --git a/lib/chef/formatters/error_mapper.rb b/lib/chef/formatters/error_mapper.rb
index 2140c638bc..eb89662308 100644
--- a/lib/chef/formatters/error_mapper.rb
+++ b/lib/chef/formatters/error_mapper.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,7 +30,7 @@ class Chef
headline = "Chef encountered an error attempting to create the client \"#{node_name}\""
description = ErrorDescription.new(headline)
error_inspector.add_explanation(description)
- return description
+ description
end
def self.node_load_failed(node_name, exception, config)
@@ -38,7 +38,7 @@ class Chef
headline = "Chef encountered an error attempting to load the node data for \"#{node_name}\""
description = ErrorDescription.new(headline)
error_inspector.add_explanation(description)
- return description
+ description
end
def self.run_list_expand_failed(node, exception)
@@ -46,7 +46,7 @@ class Chef
headline = "Error expanding the run_list:"
description = ErrorDescription.new(headline)
error_inspector.add_explanation(description)
- return description
+ description
end
def self.cookbook_resolution_failed(expanded_run_list, exception)
@@ -54,7 +54,7 @@ class Chef
headline = "Error Resolving Cookbooks for Run List:"
description = ErrorDescription.new(headline)
error_inspector.add_explanation(description)
- return description
+ description
end
def self.cookbook_sync_failed(cookbooks, exception)
@@ -62,7 +62,7 @@ class Chef
headline = "Error Syncing Cookbooks:"
description = ErrorDescription.new(headline)
error_inspector.add_explanation(description)
- return description
+ description
end
def self.resource_failed(resource, action, exception)
@@ -70,7 +70,7 @@ class Chef
headline = "Error executing action `#{action}` on resource '#{resource}'"
description = ErrorDescription.new(headline)
error_inspector.add_explanation(description)
- return description
+ description
end
def self.file_load_failed(path, exception)
diff --git a/lib/chef/formatters/indentable_output_stream.rb b/lib/chef/formatters/indentable_output_stream.rb
index 1beb286e7f..e5e84e0f65 100644
--- a/lib/chef/formatters/indentable_output_stream.rb
+++ b/lib/chef/formatters/indentable_output_stream.rb
@@ -19,7 +19,7 @@ class Chef
def highline
@highline ||= begin
- require 'highline'
+ require "highline"
HighLine.new
end
end
@@ -50,6 +50,11 @@ class Chef
print(string, from_args(args, :start_line => true, :end_line => true))
end
+ # Print a raw chunk
+ def <<(obj)
+ print(obj)
+ end
+
# Print a string.
#
# == Arguments
@@ -105,7 +110,7 @@ class Chef
def print_string(string, options)
if string.empty?
if options[:end_line]
- print_line('', options)
+ print_line("", options)
end
else
string.lines.each do |line|
@@ -131,7 +136,7 @@ class Chef
def move_to_next_line
if @line_started
- @out.puts ''
+ @out.puts ""
@line_started = false
end
end
@@ -146,11 +151,11 @@ class Chef
if @current_stream != options[:stream]
@out.print "#{(' ' * indent)}[#{options[:name]}] "
else
- @out.print ' ' * (indent + 3 + options[:name].size)
+ @out.print " " * (indent + 3 + options[:name].size)
end
else
# Otherwise, just print indents.
- @out.print ' ' * indent
+ @out.print " " * indent
end
if @current_stream != options[:stream]
diff --git a/lib/chef/formatters/minimal.rb b/lib/chef/formatters/minimal.rb
index 3862951f76..c8fc504eb0 100644
--- a/lib/chef/formatters/minimal.rb
+++ b/lib/chef/formatters/minimal.rb
@@ -1,10 +1,9 @@
-require 'chef/formatters/base'
+require "chef/formatters/base"
class Chef
module Formatters
-
# == Formatters::Minimal
# Shows the progress of the chef run by printing single characters, and
# displays a summary of updates at the conclusion of the run. For events
@@ -20,16 +19,16 @@ class Chef
attr_reader :updated_resources
attr_reader :updates_by_resource
-
def initialize(out, err)
super
@updated_resources = []
- @updates_by_resource = Hash.new {|h, k| h[k] = []}
+ @updates_by_resource = Hash.new { |h, k| h[k] = [] }
end
# Called at the very start of a Chef Run
def run_start(version)
- puts "Starting Chef Client, version #{version}"
+ puts_line "Starting Chef Client, version #{version}"
+ puts_line "OpenSSL FIPS 140 mode enabled" if Chef::Config[:fips]
end
# Called at the end of the Chef run.
@@ -130,7 +129,7 @@ class Chef
# Called after a file in a cookbook is loaded.
def file_loaded(path)
- print '.'
+ print "."
end
def file_load_failed(path, exception)
@@ -157,7 +156,7 @@ class Chef
puts "\n"
puts "resources updated this run:"
updated_resources.each do |resource|
- puts "* #{resource.to_s}"
+ puts "* #{resource}"
updates_by_resource[resource.name].flatten.each do |update|
puts " - #{update}"
end
@@ -167,7 +166,7 @@ class Chef
end
# Called before action is executed on a resource.
- def resource_action_start(resource, action, notification_type=nil, notifier=nil)
+ def resource_action_start(resource, action, notification_type = nil, notifier = nil)
end
# Called when a resource fails, but will retry.
@@ -232,4 +231,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/guard_interpreter.rb b/lib/chef/guard_interpreter.rb
index b968f273b9..e11201e50b 100644
--- a/lib/chef/guard_interpreter.rb
+++ b/lib/chef/guard_interpreter.rb
@@ -1,6 +1,6 @@
#
# Author:: Steven Danna (<steve@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/guard_interpreter/default_guard_interpreter'
-require 'chef/guard_interpreter/resource_guard_interpreter'
+require "chef/guard_interpreter/default_guard_interpreter"
+require "chef/guard_interpreter/resource_guard_interpreter"
class Chef
class GuardInterpreter
diff --git a/lib/chef/guard_interpreter/default_guard_interpreter.rb b/lib/chef/guard_interpreter/default_guard_interpreter.rb
index fead9886b2..449ca9a316 100644
--- a/lib/chef/guard_interpreter/default_guard_interpreter.rb
+++ b/lib/chef/guard_interpreter/default_guard_interpreter.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
+require "chef/mixin/shell_out"
class Chef
class GuardInterpreter
@@ -41,4 +41,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/guard_interpreter/resource_guard_interpreter.rb b/lib/chef/guard_interpreter/resource_guard_interpreter.rb
index 8cff3bc032..6df60aec89 100644
--- a/lib/chef/guard_interpreter/resource_guard_interpreter.rb
+++ b/lib/chef/guard_interpreter/resource_guard_interpreter.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'chef/guard_interpreter'
+require "chef/guard_interpreter"
class Chef
class GuardInterpreter
class ResourceGuardInterpreter < DefaultGuardInterpreter
- def initialize(parent_resource, command, opts, &block)
+ def initialize(parent_resource, command, opts)
super(command, opts)
@parent_resource = parent_resource
@resource = get_interpreter_resource(parent_resource)
@@ -42,9 +42,9 @@ class Chef
# We need to make sure we check for Script first because any resource
# that can get to here is an Execute resource.
if @resource.is_a? Chef::Resource::Script
- block_attributes = @command_opts.merge({:code => @command})
+ block_attributes = @command_opts.merge({ :code => @command })
else
- block_attributes = @command_opts.merge({:command => @command})
+ block_attributes = @command_opts.merge({ :command => @command })
end
# Handles cases like powershell_script where default
@@ -62,7 +62,7 @@ class Chef
protected
- def evaluate_action(action=nil, &block)
+ def evaluate_action(action = nil, &block)
@resource.instance_eval(&block)
run_action = action || @resource.action
@@ -71,7 +71,7 @@ class Chef
# Coerce to an array to be safe. This could happen with a legacy
# resource or something overriding the default_action code in a
# subclass.
- Array(run_action).each {|action_to_run| @resource.run_action(action_to_run) }
+ Array(run_action).each { |action_to_run| @resource.run_action(action_to_run) }
resource_updated = @resource.updated
rescue Mixlib::ShellOut::ShellCommandFailed
resource_updated = nil
@@ -88,7 +88,7 @@ class Chef
resource_class = Chef::Resource.resource_for_node(parent_resource.guard_interpreter, parent_resource.node)
if resource_class.nil?
- raise ArgumentError, "Specified guard_interpreter resource #{parent_resource.guard_interpreter.to_s} unknown for this platform"
+ raise ArgumentError, "Specified guard_interpreter resource #{parent_resource.guard_interpreter} unknown for this platform"
end
if ! resource_class.ancestors.include?(Chef::Resource::Execute)
@@ -100,7 +100,7 @@ class Chef
# See https://github.com/chef/chef/issues/3485.
empty_events = Chef::EventDispatch::Dispatcher.new
anonymous_run_context = Chef::RunContext.new(parent_resource.node.dup, {}, empty_events)
- interpreter_resource = resource_class.new('Guard resource', anonymous_run_context)
+ interpreter_resource = resource_class.new("Guard resource", anonymous_run_context)
interpreter_resource.is_guard_interpreter = true
interpreter_resource
diff --git a/lib/chef/handler.rb b/lib/chef/handler.rb
index c4b729eeca..100ed23d9e 100644
--- a/lib/chef/handler.rb
+++ b/lib/chef/handler.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/client'
-require 'forwardable'
+require "chef/client"
+require "forwardable"
class Chef
# == Chef::Handler
@@ -57,16 +57,47 @@ class Chef
#
class Handler
+ def self.handler_for(*args)
+ if args.include?(:start)
+ Chef::Config[:start_handlers] ||= []
+ Chef::Config[:start_handlers] |= [self]
+ end
+ if args.include?(:report)
+ Chef::Config[:report_handlers] ||= []
+ Chef::Config[:report_handlers] |= [self]
+ end
+ if args.include?(:exception)
+ Chef::Config[:exception_handlers] ||= []
+ Chef::Config[:exception_handlers] |= [self]
+ end
+ end
+
# The list of currently configured start handlers
def self.start_handlers
Array(Chef::Config[:start_handlers])
end
+ def self.resolve_handler_instance(handler)
+ if handler.is_a?(Class)
+ if handler.respond_to?(:instance)
+ # support retrieving a Singleton reporting object
+ handler.instance
+ else
+ # just a class with no way to insert data
+ handler.new
+ end
+ else
+ # the Chef::Config array contains an instance, not a class
+ handler
+ end
+ end
+
# Run the start handlers. This will usually be called by a notification
# from Chef::Client
def self.run_start_handlers(run_status)
Chef::Log.info("Running start handlers")
start_handlers.each do |handler|
+ handler = resolve_handler_instance(handler)
handler.run_report_safely(run_status)
end
Chef::Log.info("Start handlers complete.")
@@ -90,6 +121,7 @@ class Chef
events.handlers_start(report_handlers.size)
Chef::Log.info("Running report handlers")
report_handlers.each do |handler|
+ handler = resolve_handler_instance(handler)
handler.run_report_safely(run_status)
events.handler_executed(handler)
end
@@ -115,6 +147,7 @@ class Chef
events.handlers_start(exception_handlers.size)
Chef::Log.error("Running exception handlers")
exception_handlers.each do |handler|
+ handler = resolve_handler_instance(handler)
handler.run_report_safely(run_status)
events.handler_executed(handler)
end
diff --git a/lib/chef/handler/error_report.rb b/lib/chef/handler/error_report.rb
index 8bf676418d..e84a817e06 100644
--- a/lib/chef/handler/error_report.rb
+++ b/lib/chef/handler/error_report.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/handler'
-require 'chef/resource/directory'
+require "chef/handler"
+require "chef/resource/directory"
class Chef
class Handler
diff --git a/lib/chef/handler/json_file.rb b/lib/chef/handler/json_file.rb
index 405c91795e..9ba3d70383 100644
--- a/lib/chef/handler/json_file.rb
+++ b/lib/chef/handler/json_file.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/handler'
-require 'chef/resource/directory'
+require "chef/handler"
+require "chef/resource/directory"
class Chef
class Handler
@@ -25,7 +25,7 @@ class Chef
attr_reader :config
- def initialize(config={})
+ def initialize(config = {})
@config = config
@config[:path] ||= "/var/chef/reports"
@config
diff --git a/lib/chef/http.rb b/lib/chef/http.rb
index 16a826a3db..12acae953c 100644
--- a/lib/chef/http.rb
+++ b/lib/chef/http.rb
@@ -1,11 +1,11 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Thom May (<thom@clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010, 2013 Opscode, Inc.
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2009-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,15 +21,14 @@
# limitations under the License.
#
-require 'tempfile'
-require 'net/https'
-require 'uri'
-require 'chef/http/basic_client'
-require 'chef/http/socketless_chef_zero_client'
-require 'chef/monkey_patches/net_http'
-require 'chef/config'
-require 'chef/platform/query_helpers'
-require 'chef/exceptions'
+require "tempfile"
+require "net/https"
+require "uri"
+require "chef/http/basic_client"
+require "chef/monkey_patches/net_http"
+require "chef/config"
+require "chef/platform/query_helpers"
+require "chef/exceptions"
class Chef
@@ -62,7 +61,6 @@ class Chef
end
-
def self.middlewares
@middlewares ||= []
end
@@ -75,18 +73,25 @@ class Chef
attr_reader :sign_on_redirect
attr_reader :redirect_limit
+ attr_reader :options
+
attr_reader :middlewares
+ # [Boolean] if we're doing keepalives or not
+ attr_reader :keepalives
+
# Create a HTTP client object. The supplied +url+ is used as the base for
# all subsequent requests. For example, when initialized with a base url
# http://localhost:4000, a call to +get+ with 'nodes' will make an
# HTTP GET request to http://localhost:4000/nodes
- def initialize(url, options={})
+ def initialize(url, options = {})
@url = url
@default_headers = options[:headers] || {}
@sign_on_redirect = true
@redirects_followed = 0
@redirect_limit = 10
+ @keepalives = options[:keepalives] || false
+ @options = options
@middlewares = []
self.class.middlewares.each do |middleware_class|
@@ -98,7 +103,7 @@ class Chef
#
# === Parameters
# path:: path part of the request URL
- def head(path, headers={})
+ def head(path, headers = {})
request(:HEAD, path, headers)
end
@@ -106,7 +111,7 @@ class Chef
#
# === Parameters
# path:: The path to GET
- def get(path, headers={})
+ def get(path, headers = {})
request(:GET, path, headers)
end
@@ -114,7 +119,7 @@ class Chef
#
# === Parameters
# path:: path part of the request URL
- def put(path, json, headers={})
+ def put(path, json, headers = {})
request(:PUT, path, headers, json)
end
@@ -122,7 +127,7 @@ class Chef
#
# === Parameters
# path:: path part of the request URL
- def post(path, json, headers={})
+ def post(path, json, headers = {})
request(:POST, path, headers, json)
end
@@ -130,13 +135,13 @@ class Chef
#
# === Parameters
# path:: path part of the request URL
- def delete(path, headers={})
+ def delete(path, headers = {})
request(:DELETE, path, headers)
end
# Makes an HTTP request to +path+ with the given +method+, +headers+, and
# +data+ (if applicable).
- def request(method, path, headers={}, data=false)
+ def request(method, path, headers = {}, data = false)
url = create_url(path)
method, url, headers, data = apply_request_middleware(method, url, headers, data)
@@ -153,13 +158,43 @@ class Chef
raise
end
+ def streaming_request_with_progress(path, headers = {}, &progress_block)
+ url = create_url(path)
+ response, rest_request, return_value = nil, nil, nil
+ tempfile = nil
+
+ method = :GET
+ method, url, headers, data = apply_request_middleware(method, url, headers, data)
+
+ response, rest_request, return_value = send_http_request(method, url, headers, data) do |http_response|
+ if http_response.kind_of?(Net::HTTPSuccess)
+ tempfile = stream_to_tempfile(url, http_response, &progress_block)
+ end
+ apply_stream_complete_middleware(http_response, rest_request, return_value)
+ end
+ return nil if response.kind_of?(Net::HTTPRedirection)
+ unless response.kind_of?(Net::HTTPSuccess)
+ response.error!
+ end
+ tempfile
+ rescue Exception => e
+ log_failed_request(response, return_value) unless response.nil?
+ if e.respond_to?(:chef_rest_request=)
+ e.chef_rest_request = rest_request
+ end
+ raise
+ end
+
# Makes a streaming download request, streaming the response body to a
# tempfile. If a block is given, the tempfile is passed to the block and
# the tempfile will automatically be unlinked after the block is executed.
#
# If no block is given, the tempfile is returned, which means it's up to
# you to unlink the tempfile when you're done with it.
- def streaming_request(path, headers={}, &block)
+ #
+ # @yield [tempfile] block to process the tempfile
+ # @yieldparams [tempfile<Tempfile>] tempfile
+ def streaming_request(path, headers = {})
url = create_url(path)
response, rest_request, return_value = nil, nil, nil
tempfile = nil
@@ -195,31 +230,66 @@ class Chef
raise
end
- def http_client(base_url=nil)
+ def http_client(base_url = nil)
base_url ||= url
+ if keepalives && !base_url.nil?
+ # only reuse the http_client if we want keepalives and have a base_url
+ @http_client ||= {}
+ # the per-host per-port cache here gets peristent connections correct when
+ # redirecting to different servers
+ if base_url.is_a?(String) # sigh, this kind of abuse can't happen with strongly typed languages
+ @http_client[base_url] ||= build_http_client(base_url)
+ else
+ @http_client[base_url.host] ||= {}
+ @http_client[base_url.host][base_url.port] ||= build_http_client(base_url)
+ end
+ else
+ build_http_client(base_url)
+ end
+ end
+
+ # DEPRECATED: This is only kept around to provide access to cache control data in
+ # lib/chef/provider/remote_file/http.rb
+ # FIXME: Find a better API.
+ def last_response
+ @last_response
+ end
+
+ private
+
+ # @api private
+ def build_http_client(base_url)
if chef_zero_uri?(base_url)
+ # PERFORMANCE CRITICAL: *MUST* lazy require here otherwise we load up webrick
+ # via chef-zero and that hits DNS (at *require* time) which may timeout,
+ # when for most knife/chef-client work we never need/want this loaded.
+
+ unless defined?(SocketlessChefZeroClient)
+ require "chef/http/socketless_chef_zero_client"
+ end
+
SocketlessChefZeroClient.new(base_url)
else
- BasicClient.new(base_url, :ssl_policy => Chef::HTTP::APISSLPolicy)
+ BasicClient.new(base_url, ssl_policy: Chef::HTTP::APISSLPolicy, keepalives: keepalives)
end
end
- protected
-
+ # @api private
def create_url(path)
return path if path.is_a?(URI)
if path =~ /^(http|https|chefzero):\/\//i
URI.parse(path)
- elsif path.nil? or path.empty?
+ elsif path.nil? || path.empty?
URI.parse(@url)
else
# The regular expressions used here are to make sure '@url' does not have
# any trailing slashes and 'path' does not have any leading slashes. This
# way they are always joined correctly using just one slash.
- URI.parse(@url.gsub(%r{/+$}, '') + '/' + path.gsub(%r{^/+}, ''))
+ URI.parse(@url.gsub(%r{/+$}, "") + "/" + path.gsub(%r{^/+}, ""))
end
end
+ # @api private
def apply_request_middleware(method, url, headers, data)
middlewares.inject([method, url, headers, data]) do |req_data, middleware|
Chef::Log.debug("Chef::HTTP calling #{middleware.class}#handle_request")
@@ -227,6 +297,7 @@ class Chef
end
end
+ # @api private
def apply_response_middleware(response, rest_request, return_value)
middlewares.reverse.inject([response, rest_request, return_value]) do |res_data, middleware|
Chef::Log.debug("Chef::HTTP calling #{middleware.class}#handle_response")
@@ -234,6 +305,7 @@ class Chef
end
end
+ # @api private
def apply_stream_complete_middleware(response, rest_request, return_value)
middlewares.reverse.inject([response, rest_request, return_value]) do |res_data, middleware|
Chef::Log.debug("Chef::HTTP calling #{middleware.class}#handle_stream_complete")
@@ -241,6 +313,7 @@ class Chef
end
end
+ # @api private
def log_failed_request(response, return_value)
return_value ||= {}
error_message = "HTTP Request Returned #{response.code} #{response.message}: "
@@ -248,22 +321,23 @@ class Chef
Chef::Log.info(error_message)
end
+ # @api private
def success_response?(response)
response.kind_of?(Net::HTTPSuccess) || response.kind_of?(Net::HTTPRedirection)
end
# Runs a synchronous HTTP request, with no middleware applied (use #request
# to have the middleware applied). The entire response will be loaded into memory.
- def send_http_request(method, url, headers, body, &response_handler)
- headers = build_headers(method, url, headers, body)
-
+ # @api private
+ def send_http_request(method, url, base_headers, body, &response_handler)
retrying_http_errors(url) do
+ headers = build_headers(method, url, base_headers, body)
client = http_client(url)
return_value = nil
if block_given?
request, response = client.request(method, url, body, headers, &response_handler)
else
- request, response = client.request(method, url, body, headers) {|r| r.read_body }
+ request, response = client.request(method, url, body, headers) { |r| r.read_body }
return_value = response.read_body
end
@last_response = response
@@ -275,7 +349,7 @@ class Chef
elsif redirect_location = redirected_to(response)
if [:GET, :HEAD].include?(method)
follow_redirect do
- send_http_request(method, url+redirect_location, headers, body, &response_handler)
+ send_http_request(method, url + redirect_location, headers, body, &response_handler)
end
else
raise Exceptions::InvalidRedirect, "#{method} request was redirected from #{url} to #{redirect_location}. Only GET and HEAD support redirects."
@@ -286,10 +360,10 @@ class Chef
end
end
-
# Wraps an HTTP request with retry logic.
# === Arguments
# url:: URL of the request, used for error messages
+ # @api private
def retrying_http_errors(url)
http_attempts = 0
begin
@@ -299,7 +373,7 @@ class Chef
# handle HTTP 50X Error
if response.kind_of?(Net::HTTPServerError) && !Chef::Config.local_mode
if http_retry_count - http_attempts + 1 > 0
- sleep_time = 1 + (2 ** http_attempts) + rand(2 ** http_attempts)
+ sleep_time = 1 + (2**http_attempts) + rand(2**http_attempts)
Chef::Log.error("Server returned error #{response.code} for #{url}, retrying #{http_attempts}/#{http_retry_count} in #{sleep_time}s")
sleep(sleep_time)
redo
@@ -307,7 +381,7 @@ class Chef
end
return [response, request, return_value]
end
- rescue SocketError, Errno::ETIMEDOUT => e
+ rescue SocketError, Errno::ETIMEDOUT, Errno::ECONNRESET => e
if http_retry_count - http_attempts + 1 > 0
Chef::Log.error("Error connecting to #{url}, retry #{http_attempts}/#{http_retry_count}")
sleep(http_retry_delay)
@@ -329,21 +403,32 @@ class Chef
retry
end
raise Timeout::Error, "Timeout connecting to #{url}, giving up"
+ rescue OpenSSL::SSL::SSLError => e
+ if (http_retry_count - http_attempts + 1 > 0) && !e.message.include?("certificate verify failed")
+ Chef::Log.error("SSL Error connecting to #{url}, retry #{http_attempts}/#{http_retry_count}")
+ sleep(http_retry_delay)
+ retry
+ end
+ raise OpenSSL::SSL::SSLError, "SSL Error connecting to #{url} - #{e.message}"
end
end
+ # @api private
def http_retry_delay
config[:http_retry_delay]
end
+ # @api private
def http_retry_count
config[:http_retry_count]
end
+ # @api private
def config
Chef::Config
end
+ # @api private
def follow_redirect
raise Chef::Exceptions::RedirectLimitExceeded if @redirects_followed >= redirect_limit
@redirects_followed += 1
@@ -354,33 +439,36 @@ class Chef
@redirects_followed = 0
end
- private
-
+ # @api private
def chef_zero_uri?(uri)
uri = URI.parse(uri) unless uri.respond_to?(:scheme)
uri.scheme == "chefzero"
end
+ # @api private
def redirected_to(response)
return nil unless response.kind_of?(Net::HTTPRedirection)
# Net::HTTPNotModified is undesired subclass of Net::HTTPRedirection so test for this
return nil if response.kind_of?(Net::HTTPNotModified)
- response['location']
+ response["location"]
end
- def build_headers(method, url, headers={}, json_body=false)
- headers = @default_headers.merge(headers)
- headers['Content-Length'] = json_body.bytesize.to_s if json_body
+ # @api private
+ def build_headers(method, url, headers = {}, json_body = false)
+ headers = @default_headers.merge(headers)
+ headers["Content-Length"] = json_body.bytesize.to_s if json_body
headers.merge!(Chef::Config[:custom_http_headers]) if Chef::Config[:custom_http_headers]
headers
end
- def stream_to_tempfile(url, response)
+ # @api private
+ def stream_to_tempfile(url, response, &progress_block)
+ content_length = response["Content-Length"]
tf = Tempfile.open("chef-rest")
if Chef::Platform.windows?
tf.binmode # required for binary files on Windows platforms
end
- Chef::Log.debug("Streaming download from #{url.to_s} to tempfile #{tf.path}")
+ Chef::Log.debug("Streaming download from #{url} to tempfile #{tf.path}")
# Stolen from http://www.ruby-forum.com/topic/166423
# Kudos to _why!
@@ -388,27 +476,14 @@ class Chef
response.read_body do |chunk|
tf.write(stream_handler.handle_chunk(chunk))
+ yield tf.size, content_length if block_given?
end
tf.close
tf
rescue Exception
- tf.close!
+ tf.close! if tf
raise
end
-
- public
-
- ############################################################################
- # DEPRECATED
- ############################################################################
-
- # This is only kept around to provide access to cache control data in
- # lib/chef/provider/remote_file/http.rb
- # Find a better API.
- def last_response
- @last_response
- end
-
end
end
diff --git a/lib/chef/http/api_versions.rb b/lib/chef/http/api_versions.rb
new file mode 100644
index 0000000000..e164da262d
--- /dev/null
+++ b/lib/chef/http/api_versions.rb
@@ -0,0 +1,50 @@
+#--
+# Copyright:: Copyright 2017, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/server_api_versions"
+
+class Chef
+ class HTTP
+ # An HTTP middleware to retrieve and store the Chef Server's minimum
+ # and maximum supported API versions.
+ class APIVersions
+
+ def initialize(options = {})
+ end
+
+ def handle_request(method, url, headers = {}, data = false)
+ [method, url, headers, data]
+ end
+
+ def handle_response(http_response, rest_request, return_value)
+ if http_response.key?("x-ops-server-api-version")
+ ServerAPIVersions.instance.set_versions(http_response["x-ops-server-api-version"])
+ end
+ [http_response, rest_request, return_value]
+ end
+
+ def stream_response_handler(response)
+ nil
+ end
+
+ def handle_stream_complete(http_response, rest_request, return_value)
+ [http_response, rest_request, return_value]
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/http/auth_credentials.rb b/lib/chef/http/auth_credentials.rb
index bd73524b1f..053b2c938e 100644
--- a/lib/chef/http/auth_credentials.rb
+++ b/lib/chef/http/auth_credentials.rb
@@ -1,11 +1,11 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Thom May (<thom@clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,15 +20,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/log'
-require 'mixlib/authentication/signedheaderauth'
+require "chef/log"
+require "mixlib/authentication/signedheaderauth"
class Chef
class HTTP
class AuthCredentials
attr_reader :client_name, :key
- def initialize(client_name=nil, key=nil)
+ def initialize(client_name = nil, key = nil)
@client_name, @key = client_name, key
end
@@ -36,7 +36,7 @@ class Chef
!!key
end
- def signature_headers(request_params={})
+ def signature_headers(request_params = {})
raise ArgumentError, "Cannot sign the request without a client name, check that :node_name is assigned" if client_name.nil?
Chef::Log.debug("Signing the request as #{client_name}")
@@ -48,8 +48,8 @@ class Chef
host = request_params.delete(:host) || "localhost"
sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object(request_params)
- signed = sign_obj.sign(key).merge({:host => host})
- signed.inject({}){|memo, kv| memo["#{kv[0].to_s.upcase}"] = kv[1];memo}
+ signed = sign_obj.sign(key).merge({ :host => host })
+ signed.inject({}) { |memo, kv| memo["#{kv[0].to_s.upcase}"] = kv[1]; memo }
end
end
diff --git a/lib/chef/http/authenticator.rb b/lib/chef/http/authenticator.rb
index bffa9c4b3a..84065bf816 100644
--- a/lib/chef/http/authenticator.rb
+++ b/lib/chef/http/authenticator.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/http/auth_credentials'
-require 'chef/exceptions'
-require 'openssl'
+require "chef/http/auth_credentials"
+require "chef/exceptions"
+require "openssl"
class Chef
class HTTP
@@ -33,7 +33,7 @@ class Chef
attr_accessor :sign_request
- def initialize(opts={})
+ def initialize(opts = {})
@raw_key = nil
@sign_request = true
@signing_key_filename = opts[:signing_key_filename]
@@ -46,9 +46,9 @@ class Chef
end
end
- def handle_request(method, url, headers={}, data=false)
- headers.merge!(authentication_headers(method, url, data)) if sign_requests?
- headers.merge!({'X-Ops-Server-API-Version' => @api_version})
+ def handle_request(method, url, headers = {}, data = false)
+ headers["X-Ops-Server-API-Version"] = @api_version
+ headers.merge!(authentication_headers(method, url, data, headers)) if sign_requests?
[method, url, headers, data]
end
@@ -73,9 +73,9 @@ class Chef
end
def load_signing_key(key_file, raw_key = nil)
- if (!!key_file)
+ if !!key_file
@raw_key = IO.read(key_file).strip
- elsif (!!raw_key)
+ elsif !!raw_key
@raw_key = raw_key.strip
else
return nil
@@ -90,12 +90,17 @@ class Chef
raise Chef::Exceptions::InvalidPrivateKey, msg
end
- def authentication_headers(method, url, json_body=nil)
- request_params = {:http_method => method, :path => url.path, :body => json_body, :host => "#{url.host}:#{url.port}"}
+ def authentication_headers(method, url, json_body = nil, headers = nil)
+ request_params = {
+ :http_method => method,
+ :path => url.path,
+ :body => json_body,
+ :host => "#{url.host}:#{url.port}",
+ :headers => headers,
+ }
request_params[:body] ||= ""
auth_credentials.signature_headers(request_params)
end
-
end
end
end
diff --git a/lib/chef/http/basic_client.rb b/lib/chef/http/basic_client.rb
index de5e7c03a8..9a000136e6 100644
--- a/lib/chef/http/basic_client.rb
+++ b/lib/chef/http/basic_client.rb
@@ -1,11 +1,11 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Thom May (<thom@clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,10 +20,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'uri'
-require 'net/http'
-require 'chef/http/ssl_policies'
-require 'chef/http/http_request'
+require "uri"
+require "net/http"
+require "chef/http/ssl_policies"
+require "chef/http/http_request"
class Chef
class HTTP
@@ -34,16 +34,21 @@ class Chef
attr_reader :url
attr_reader :http_client
attr_reader :ssl_policy
+ attr_reader :keepalives
# Instantiate a BasicClient.
# === Arguments:
# url:: An URI for the remote server.
# === Options:
# ssl_policy:: The SSL Policy to use, defaults to DefaultSSLPolicy
- def initialize(url, opts={})
+ def initialize(url, opts = {})
@url = url
@ssl_policy = opts[:ssl_policy] || DefaultSSLPolicy
- @http_client = build_http_client
+ @keepalives = opts[:keepalives] || false
+ end
+
+ def http_client
+ @http_client ||= build_http_client
end
def host
@@ -54,7 +59,7 @@ class Chef
@url.port
end
- def request(method, url, req_body, base_headers={})
+ def request(method, url, req_body, base_headers = {})
http_request = HTTPRequest.new(method, url, req_body, base_headers).http_request
Chef::Log.debug("Initiating #{method} to #{url}")
Chef::Log.debug("---- HTTP Request Header Data: ----")
@@ -72,7 +77,7 @@ class Chef
Chef::Log.debug("---- End HTTP Status/Header Data ----")
# For non-400's, log the request and response bodies
- if !response.code || !response.code.start_with?('2')
+ if !response.code || !response.code.start_with?("2")
if response.body
Chef::Log.debug("---- HTTP Response Body ----")
Chef::Log.debug(response.body)
@@ -95,30 +100,18 @@ class Chef
raise
end
- #adapted from buildr/lib/buildr/core/transports.rb
def proxy_uri
- proxy = Chef::Config["#{url.scheme}_proxy"] ||
- env["#{url.scheme.upcase}_PROXY"] || env["#{url.scheme}_proxy"]
-
- # Check if the proxy string contains a scheme. If not, add the url's scheme to the
- # proxy before parsing. The regex /^.*:\/\// matches, for example, http://. Reusing proxy
- # here since we are really just trying to get the string built correctly.
- if String === proxy && !proxy.strip.empty?
- if proxy.match(/^.*:\/\//)
- proxy = URI.parse(proxy.strip)
- else
- proxy = URI.parse("#{url.scheme}://#{proxy.strip}")
- end
- end
-
- no_proxy = Chef::Config[:no_proxy] || env['NO_PROXY'] || env['no_proxy']
- excludes = no_proxy.to_s.split(/\s*,\s*/).compact
- excludes = excludes.map { |exclude| exclude =~ /:\d+$/ ? exclude : "#{exclude}:*" }
- return proxy unless excludes.any? { |exclude| File.fnmatch(exclude, "#{host}:#{port}") }
+ @proxy_uri ||= Chef::Config.proxy_uri(url.scheme, host, port)
end
def build_http_client
- http_client = http_client_builder.new(host, port)
+ # Note: the last nil in the new below forces Net::HTTP to ignore the
+ # no_proxy environment variable. This is a workaround for limitations
+ # in Net::HTTP use of the no_proxy environment variable. We internally
+ # match no_proxy with a fuzzy matcher, rather than letting Net::HTTP
+ # do it.
+ http_client = http_client_builder.new(host, port, nil)
+ http_client.proxy_port = nil if http_client.proxy_address.nil?
if url.scheme == HTTPS
configure_ssl(http_client)
@@ -126,37 +119,33 @@ class Chef
http_client.read_timeout = config[:rest_timeout]
http_client.open_timeout = config[:rest_timeout]
- http_client
+ if keepalives
+ http_client.start
+ else
+ http_client
+ end
end
def config
Chef::Config
end
- def env
- ENV
- end
-
def http_client_builder
- http_proxy = proxy_uri
- if http_proxy.nil?
+ if proxy_uri.nil?
Net::HTTP
else
- Chef::Log.debug("Using #{http_proxy.host}:#{http_proxy.port} for proxy")
- user = http_proxy_user(http_proxy)
- pass = http_proxy_pass(http_proxy)
- Net::HTTP.Proxy(http_proxy.host, http_proxy.port, user, pass)
+ Chef::Log.debug("Using #{proxy_uri.host}:#{proxy_uri.port} for proxy")
+ Net::HTTP.Proxy(proxy_uri.host, proxy_uri.port, http_proxy_user(proxy_uri),
+ http_proxy_pass(proxy_uri))
end
end
- def http_proxy_user(http_proxy)
- http_proxy.user || Chef::Config["#{url.scheme}_proxy_user"] ||
- env["#{url.scheme.upcase}_PROXY_USER"] || env["#{url.scheme}_proxy_user"]
+ def http_proxy_user(proxy_uri)
+ proxy_uri.user || Chef::Config["#{proxy_uri.scheme}_proxy_user"]
end
- def http_proxy_pass(http_proxy)
- http_proxy.password || Chef::Config["#{url.scheme}_proxy_pass"] ||
- env["#{url.scheme.upcase}_PROXY_PASS"] || env["#{url.scheme}_proxy_pass"]
+ def http_proxy_pass(proxy_uri)
+ proxy_uri.password || Chef::Config["#{proxy_uri.scheme}_proxy_pass"]
end
def configure_ssl(http_client)
diff --git a/lib/chef/http/cookie_jar.rb b/lib/chef/http/cookie_jar.rb
index 418fb1d352..4908fde0c9 100644
--- a/lib/chef/http/cookie_jar.rb
+++ b/lib/chef/http/cookie_jar.rb
@@ -1,11 +1,11 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Thom May (<thom@clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'singleton'
+require "singleton"
class Chef
class HTTP
diff --git a/lib/chef/http/cookie_manager.rb b/lib/chef/http/cookie_manager.rb
index e9cb7aa4f7..18824a8eff 100644
--- a/lib/chef/http/cookie_manager.rb
+++ b/lib/chef/http/cookie_manager.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/http/cookie_jar'
+require "chef/http/cookie_jar"
class Chef
class HTTP
@@ -27,21 +27,21 @@ class Chef
# it, so it's included with Chef::REST
class CookieManager
- def initialize(options={})
+ def initialize(options = {})
@cookies = CookieJar.instance
end
- def handle_request(method, url, headers={}, data=false)
+ def handle_request(method, url, headers = {}, data = false)
@host, @port = url.host, url.port
if @cookies.has_key?("#{@host}:#{@port}")
- headers['Cookie'] = @cookies["#{@host}:#{@port}"]
+ headers["Cookie"] = @cookies["#{@host}:#{@port}"]
end
[method, url, headers, data]
end
def handle_response(http_response, rest_request, return_value)
- if http_response['set-cookie']
- @cookies["#{@host}:#{@port}"] = http_response['set-cookie']
+ if http_response["set-cookie"]
+ @cookies["#{@host}:#{@port}"] = http_response["set-cookie"]
end
[http_response, rest_request, return_value]
end
diff --git a/lib/chef/http/decompressor.rb b/lib/chef/http/decompressor.rb
index a61f510e7d..1bba4cc492 100644
--- a/lib/chef/http/decompressor.rb
+++ b/lib/chef/http/decompressor.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'zlib'
-require 'chef/http/http_request'
+require "zlib"
+require "chef/http/http_request"
class Chef
class HTTP
@@ -50,12 +50,12 @@ class Chef
DEFLATE = "deflate".freeze
IDENTITY = "identity".freeze
- def initialize(opts={})
+ def initialize(opts = {})
@disable_gzip = false
handle_options(opts)
end
- def handle_request(method, url, headers={}, data=false)
+ def handle_request(method, url, headers = {}, data = false)
headers[HTTPRequest::ACCEPT_ENCODING] = HTTPRequest::ENCODING_GZIP_DEFLATE unless gzip_disabled?
[method, url, headers, data]
end
@@ -114,7 +114,6 @@ class Chef
end
end
-
# gzip is disabled using the disable_gzip => true option in the
# constructor. When gzip is disabled, no 'Accept-Encoding' header will be
# set, and the response will not be decompressed, no matter what the
@@ -132,13 +131,12 @@ class Chef
def handle_options(opts)
opts.each do |name, value|
case name.to_s
- when 'disable_gzip'
+ when "disable_gzip"
@disable_gzip = value
end
end
end
-
end
end
end
diff --git a/lib/chef/http/http_request.rb b/lib/chef/http/http_request.rb
index 1baf5724ae..20c46aaa8d 100644
--- a/lib/chef/http/http_request.rb
+++ b/lib/chef/http/http_request.rb
@@ -1,11 +1,11 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Thom May (<thom@clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2009-2016, 2010-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,19 +20,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'uri'
-require 'net/http'
+require "uri"
+require "net/http"
# To load faster, we only want ohai's version string.
# However, in ohai before 0.6.0, the version is defined
# in ohai, not ohai/version
begin
- require 'ohai/version' #used in user agent string.
+ require "ohai/version" #used in user agent string.
rescue LoadError
- require 'ohai'
+ require "ohai"
end
-require 'chef/version'
+require "chef/version"
class Chef
class HTTP
@@ -60,7 +60,7 @@ class Chef
HOST_LOWER = "host".freeze
- URI_SCHEME_DEFAULT_PORT = { 'http' => 80, 'https' => 443 }.freeze
+ URI_SCHEME_DEFAULT_PORT = { "http" => 80, "https" => 443 }.freeze
def self.user_agent=(ua)
@user_agent = ua
@@ -72,7 +72,7 @@ class Chef
attr_reader :method, :url, :headers, :http_client, :http_request
- def initialize(method, url, req_body, base_headers={})
+ def initialize(method, url, req_body, base_headers = {})
@method, @url = method, url
@request_body = nil
build_headers(base_headers)
@@ -125,9 +125,9 @@ class Chef
rescue NoMethodError => e
# http://redmine.ruby-lang.org/issues/show/2708
# http://redmine.ruby-lang.org/issues/show/2758
- if e.to_s =~ /#{Regexp.escape(%q|undefined method `closed?' for nil:NilClass|)}/
+ if e.to_s =~ /#{Regexp.escape(%q{undefined method `closed?' for nil:NilClass})}/
Chef::Log.debug("Rescued error in http connect, re-raising as Errno::ECONNREFUSED to hide bug in net/http")
- Chef::Log.debug("#{e.class.name}: #{e.to_s}")
+ Chef::Log.debug("#{e.class.name}: #{e}")
Chef::Log.debug(e.backtrace.join("\n"))
raise Errno::ECONNREFUSED, "Connection refused attempting to contact #{url.scheme}://#{host}:#{port}"
else
@@ -139,38 +139,37 @@ class Chef
@headers = headers.dup
# No response compression unless we asked for it explicitly:
@headers[HTTPRequest::ACCEPT_ENCODING] ||= "identity"
- @headers['X-Chef-Version'] = ::Chef::VERSION
+ @headers["X-Chef-Version"] = ::Chef::VERSION
# Only include port in Host header when it is not the default port
# for the url scheme (80;443) - Fixes CHEF-5355
host_header = uri_safe_host.dup
host_header << ":#{port}" unless URI_SCHEME_DEFAULT_PORT[@url.scheme] == port.to_i
- @headers['Host'] = host_header unless @headers.keys.any? {|k| k.downcase.to_s == HOST_LOWER }
+ @headers["Host"] = host_header unless @headers.keys.any? { |k| k.downcase.to_s == HOST_LOWER }
@headers
end
-
- def configure_http_request(request_body=nil)
+ def configure_http_request(request_body = nil)
req_path = "#{path}"
req_path << "?#{query}" if query
@http_request = case method.to_s.downcase
- when GET
- Net::HTTP::Get.new(req_path, headers)
- when POST
- Net::HTTP::Post.new(req_path, headers)
- when PUT
- Net::HTTP::Put.new(req_path, headers)
- when DELETE
- Net::HTTP::Delete.new(req_path, headers)
- when HEAD
- Net::HTTP::Head.new(req_path, headers)
- else
- raise ArgumentError, "You must provide :GET, :PUT, :POST, :DELETE or :HEAD as the method"
- end
-
- @http_request.body = request_body if (request_body && @http_request.request_body_permitted?)
+ when GET
+ Net::HTTP::Get.new(req_path, headers)
+ when POST
+ Net::HTTP::Post.new(req_path, headers)
+ when PUT
+ Net::HTTP::Put.new(req_path, headers)
+ when DELETE
+ Net::HTTP::Delete.new(req_path, headers)
+ when HEAD
+ Net::HTTP::Head.new(req_path, headers)
+ else
+ raise ArgumentError, "You must provide :GET, :PUT, :POST, :DELETE or :HEAD as the method"
+ end
+
+ @http_request.body = request_body if request_body && @http_request.request_body_permitted?
# Optionally handle HTTP Basic Authentication
if url.user
user = URI.unescape(url.user)
diff --git a/lib/chef/http/json_input.rb b/lib/chef/http/json_input.rb
index 3296d8821f..7cf2e4012f 100644
--- a/lib/chef/http/json_input.rb
+++ b/lib/chef/http/json_input.rb
@@ -1,7 +1,7 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'chef/json_compat'
+require "chef/json_compat"
class Chef
class HTTP
@@ -27,14 +27,14 @@ class Chef
attr_accessor :opts
- def initialize(opts={})
+ def initialize(opts = {})
@opts = opts
end
- def handle_request(method, url, headers={}, data=false)
+ def handle_request(method, url, headers = {}, data = false)
if data && should_encode_as_json?(headers)
- headers.delete_if { |key, _value| key.downcase == 'content-type' }
- headers["Content-Type"] = 'application/json'
+ headers.delete_if { |key, _value| key.casecmp("content-type") == 0 }
+ headers["Content-Type"] = "application/json"
json_opts = {}
json_opts[:validate_utf8] = opts[:validate_utf8] if opts.has_key?(:validate_utf8)
data = Chef::JSONCompat.to_json(data, json_opts)
@@ -64,7 +64,7 @@ class Chef
# ruby/Net::HTTP don't enforce capitalized headers (it normalizes them
# for you before sending the request), so we have to account for all
# the variations we might find
- requested_content_type = headers.find {|k, v| k.downcase == "content-type" }
+ requested_content_type = headers.find { |k, v| k.casecmp("content-type") == 0 }
requested_content_type.nil? || requested_content_type.last.include?("json")
end
diff --git a/lib/chef/http/json_output.rb b/lib/chef/http/json_output.rb
index 069eb6a87f..6053c38a56 100644
--- a/lib/chef/http/json_output.rb
+++ b/lib/chef/http/json_output.rb
@@ -1,7 +1,7 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/json_compat'
-require 'chef/log'
+require "chef/json_compat"
+require "chef/log"
class Chef
class HTTP
@@ -29,16 +29,16 @@ class Chef
attr_accessor :raw_output
attr_accessor :inflate_json_class
- def initialize(opts={})
+ def initialize(opts = {})
@raw_output = opts[:raw_output]
@inflate_json_class = opts[:inflate_json_class]
end
- def handle_request(method, url, headers={}, data=false)
+ def handle_request(method, url, headers = {}, data = false)
# Ideally this should always set Accept to application/json, but
# Chef::REST is sometimes used to make non-JSON requests, so it sets
# Accept to the desired value before middlewares get called.
- headers['Accept'] ||= 'application/json'
+ headers["Accept"] ||= "application/json"
[method, url, headers, data]
end
@@ -46,7 +46,7 @@ class Chef
# temporary hack, skip processing if return_value is false
# needed to keep conditional get stuff working correctly.
return [http_response, rest_request, return_value] if return_value == false
- if http_response['content-type'] =~ /json/
+ if http_response["content-type"] =~ /json/
if http_response.body.nil?
return_value = nil
elsif raw_output
diff --git a/lib/chef/http/json_to_model_output.rb b/lib/chef/http/json_to_model_output.rb
index 9bc90a52ae..12ca1a90aa 100644
--- a/lib/chef/http/json_to_model_output.rb
+++ b/lib/chef/http/json_to_model_output.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/http/json_output'
+require "chef/http/json_output"
class Chef
class HTTP
@@ -25,7 +25,7 @@ class Chef
# possible, and converts it into an appropriate model object if it contains
# a `json_class` key.
class JSONToModelOutput < JSONOutput
- def initialize(opts={})
+ def initialize(opts = {})
opts[:inflate_json_class] = true if !opts.has_key?(:inflate_json_class)
super
end
diff --git a/lib/chef/http/remote_request_id.rb b/lib/chef/http/remote_request_id.rb
index 6bec5dba4f..a779df805e 100644
--- a/lib/chef/http/remote_request_id.rb
+++ b/lib/chef/http/remote_request_id.rb
@@ -1,5 +1,5 @@
-# Author:: Prajakta Purohit (<prajakta@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010, 2013, 2014 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,17 +15,17 @@
# limitations under the License.
#
-require 'chef/request_id'
+require "chef/request_id"
class Chef
class HTTP
class RemoteRequestID
- def initialize(opts={})
+ def initialize(opts = {})
end
- def handle_request(method, url, headers={}, data=false)
- headers.merge!({'X-REMOTE-REQUEST-ID' => Chef::RequestID.instance.request_id})
+ def handle_request(method, url, headers = {}, data = false)
+ headers["X-REMOTE-REQUEST-ID"] = Chef::RequestID.instance.request_id
[method, url, headers, data]
end
diff --git a/lib/chef/http/simple.rb b/lib/chef/http/simple.rb
index 8519554f2b..bdbc31c9f1 100644
--- a/lib/chef/http/simple.rb
+++ b/lib/chef/http/simple.rb
@@ -1,8 +1,26 @@
-require 'chef/http'
-require 'chef/http/authenticator'
-require 'chef/http/decompressor'
-require 'chef/http/cookie_manager'
-require 'chef/http/validate_content_length'
+#
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/http"
+require "chef/http/authenticator"
+require "chef/http/decompressor"
+require "chef/http/cookie_manager"
+require "chef/http/validate_content_length"
class Chef
class HTTP
diff --git a/lib/chef/http/simple_json.rb b/lib/chef/http/simple_json.rb
new file mode 100644
index 0000000000..7357d859ee
--- /dev/null
+++ b/lib/chef/http/simple_json.rb
@@ -0,0 +1,43 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/http"
+require "chef/http/authenticator"
+require "chef/http/decompressor"
+require "chef/http/cookie_manager"
+require "chef/http/validate_content_length"
+
+class Chef
+ class HTTP
+
+ class SimpleJSON < HTTP
+
+ use JSONInput
+ use JSONOutput
+ use CookieManager
+ use Decompressor
+ use RemoteRequestID
+
+ # ValidateContentLength should come after Decompressor
+ # because the order of middlewares is reversed when handling
+ # responses.
+ use ValidateContentLength
+
+ end
+ end
+end
diff --git a/lib/chef/http/socketless_chef_zero_client.rb b/lib/chef/http/socketless_chef_zero_client.rb
index 8f5543a16f..d2f1f45b1d 100644
--- a/lib/chef/http/socketless_chef_zero_client.rb
+++ b/lib/chef/http/socketless_chef_zero_client.rb
@@ -1,6 +1,6 @@
#--
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,7 +22,7 @@
# fakeweb is distributed under the MIT license, which is copied below:
# ---
#
-# Copyright 2006-2010 Blaine Cook, Chris Kampmeier, and other contributors
+# Copyright 2006-2016, Blaine Cook, Chris Kampmeier, and other contributors
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -43,7 +43,7 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-require 'chef_zero/server'
+require "chef_zero/server"
class Chef
class HTTP
@@ -67,7 +67,7 @@ class Chef
end
if block_given?
- block.call(@body)
+ yield(@body)
else
super
end
@@ -81,59 +81,59 @@ class Chef
#
# HTTP status codes and descriptions
STATUS_MESSAGE = {
- 100 => 'Continue',
- 101 => 'Switching Protocols',
- 200 => 'OK',
- 201 => 'Created',
- 202 => 'Accepted',
- 203 => 'Non-Authoritative Information',
- 204 => 'No Content',
- 205 => 'Reset Content',
- 206 => 'Partial Content',
- 207 => 'Multi-Status',
- 300 => 'Multiple Choices',
- 301 => 'Moved Permanently',
- 302 => 'Found',
- 303 => 'See Other',
- 304 => 'Not Modified',
- 305 => 'Use Proxy',
- 307 => 'Temporary Redirect',
- 400 => 'Bad Request',
- 401 => 'Unauthorized',
- 402 => 'Payment Required',
- 403 => 'Forbidden',
- 404 => 'Not Found',
- 405 => 'Method Not Allowed',
- 406 => 'Not Acceptable',
- 407 => 'Proxy Authentication Required',
- 408 => 'Request Timeout',
- 409 => 'Conflict',
- 410 => 'Gone',
- 411 => 'Length Required',
- 412 => 'Precondition Failed',
- 413 => 'Request Entity Too Large',
- 414 => 'Request-URI Too Large',
- 415 => 'Unsupported Media Type',
- 416 => 'Request Range Not Satisfiable',
- 417 => 'Expectation Failed',
- 422 => 'Unprocessable Entity',
- 423 => 'Locked',
- 424 => 'Failed Dependency',
- 426 => 'Upgrade Required',
- 428 => 'Precondition Required',
- 429 => 'Too Many Requests',
- 431 => 'Request Header Fields Too Large',
- 500 => 'Internal Server Error',
- 501 => 'Not Implemented',
- 502 => 'Bad Gateway',
- 503 => 'Service Unavailable',
- 504 => 'Gateway Timeout',
- 505 => 'HTTP Version Not Supported',
- 507 => 'Insufficient Storage',
- 511 => 'Network Authentication Required',
+ 100 => "Continue",
+ 101 => "Switching Protocols",
+ 200 => "OK",
+ 201 => "Created",
+ 202 => "Accepted",
+ 203 => "Non-Authoritative Information",
+ 204 => "No Content",
+ 205 => "Reset Content",
+ 206 => "Partial Content",
+ 207 => "Multi-Status",
+ 300 => "Multiple Choices",
+ 301 => "Moved Permanently",
+ 302 => "Found",
+ 303 => "See Other",
+ 304 => "Not Modified",
+ 305 => "Use Proxy",
+ 307 => "Temporary Redirect",
+ 400 => "Bad Request",
+ 401 => "Unauthorized",
+ 402 => "Payment Required",
+ 403 => "Forbidden",
+ 404 => "Not Found",
+ 405 => "Method Not Allowed",
+ 406 => "Not Acceptable",
+ 407 => "Proxy Authentication Required",
+ 408 => "Request Timeout",
+ 409 => "Conflict",
+ 410 => "Gone",
+ 411 => "Length Required",
+ 412 => "Precondition Failed",
+ 413 => "Request Entity Too Large",
+ 414 => "Request-URI Too Large",
+ 415 => "Unsupported Media Type",
+ 416 => "Request Range Not Satisfiable",
+ 417 => "Expectation Failed",
+ 422 => "Unprocessable Entity",
+ 423 => "Locked",
+ 424 => "Failed Dependency",
+ 426 => "Upgrade Required",
+ 428 => "Precondition Required",
+ 429 => "Too Many Requests",
+ 431 => "Request Header Fields Too Large",
+ 500 => "Internal Server Error",
+ 501 => "Not Implemented",
+ 502 => "Bad Gateway",
+ 503 => "Service Unavailable",
+ 504 => "Gateway Timeout",
+ 505 => "HTTP Version Not Supported",
+ 507 => "Insufficient Storage",
+ 511 => "Network Authentication Required",
}
- STATUS_MESSAGE.values.each {|v| v.freeze }
+ STATUS_MESSAGE.values.each { |v| v.freeze }
STATUS_MESSAGE.freeze
def initialize(base_url)
@@ -148,7 +148,8 @@ class Chef
@url.port
end
- def request(method, url, body, headers, &handler_block)
+ # FIXME: yard with @yield
+ def request(method, url, body, headers)
request = req_to_rack(method, url, body, headers)
res = ChefZero::SocketlessServerMap.request(port, request)
@@ -175,8 +176,9 @@ class Chef
end
def to_net_http(code, headers, chunked_body)
- body = chunked_body.join('')
- msg = STATUS_MESSAGE[code] or raise "Cannot determine HTTP status message for code #{code}"
+ body = chunked_body.join("")
+ msg = STATUS_MESSAGE[code]
+ raise "Cannot determine HTTP status message for code #{code}" unless msg
response = Net::HTTPResponse.send(:response_class, code.to_s).new("1.0", code.to_s, msg)
response.instance_variable_set(:@body, body)
headers.each do |name, value|
@@ -195,12 +197,11 @@ class Chef
private
def headers_extracted_from_options
- options.reject {|name, _| KNOWN_OPTIONS.include?(name) }.map { |name, value|
+ options.reject { |name, _| KNOWN_OPTIONS.include?(name) }.map do |name, value|
[name.to_s.split("_").map { |segment| segment.capitalize }.join("-"), value]
- }
+ end
end
-
end
end
diff --git a/lib/chef/http/ssl_policies.rb b/lib/chef/http/ssl_policies.rb
index 9c180c154e..a3692b81b6 100644
--- a/lib/chef/http/ssl_policies.rb
+++ b/lib/chef/http/ssl_policies.rb
@@ -1,11 +1,11 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Thom May (<thom@clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010, 2013 Opscode, Inc.
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,8 +21,8 @@
# limitations under the License.
#
-require 'openssl'
-require 'chef/util/path_helper'
+require "openssl"
+require "chef/util/path_helper"
class Chef
class HTTP
@@ -77,7 +77,7 @@ class Chef
http_client.cert_store.set_default_paths
end
if config.trusted_certs_dir
- certs = Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(config.trusted_certs_dir), "*.{crt,pem}"))
+ certs = Dir.glob(File.join(Chef::Util::PathHelper.escape_glob_dir(config.trusted_certs_dir), "*.{crt,pem}"))
certs.each do |cert_file|
cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
add_trusted_cert(cert)
@@ -86,8 +86,8 @@ class Chef
end
def set_client_credentials
- if (config[:ssl_client_cert] || config[:ssl_client_key])
- unless (config[:ssl_client_cert] && config[:ssl_client_key])
+ if config[:ssl_client_cert] || config[:ssl_client_key]
+ unless config[:ssl_client_cert] && config[:ssl_client_key]
raise Chef::Exceptions::ConfigurationError, "You must configure ssl_client_cert and ssl_client_key together"
end
unless ::File.exists?(config[:ssl_client_cert])
@@ -110,7 +110,7 @@ class Chef
def add_trusted_cert(cert)
http_client.cert_store.add_cert(cert)
rescue OpenSSL::X509::StoreError => e
- raise e unless e.message == 'cert already in hash table'
+ raise e unless e.message == "cert already in hash table"
end
end
@@ -118,7 +118,7 @@ class Chef
class APISSLPolicy < DefaultSSLPolicy
def set_verify_mode
- if config[:ssl_verify_mode] == :verify_peer or config[:verify_api_cert]
+ if config[:ssl_verify_mode] == :verify_peer || config[:verify_api_cert]
http_client.verify_mode = OpenSSL::SSL::VERIFY_PEER
elsif config[:ssl_verify_mode] == :verify_none
http_client.verify_mode = OpenSSL::SSL::VERIFY_NONE
diff --git a/lib/chef/http/validate_content_length.rb b/lib/chef/http/validate_content_length.rb
index 076194e31a..3a8d3bda2b 100644
--- a/lib/chef/http/validate_content_length.rb
+++ b/lib/chef/http/validate_content_length.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Lamont Granquist (<lamont@getchef.com>)
-# Copyright:: Copyright (c) 2013 Chef Software, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'pp'
-require 'chef/log'
+require "pp"
+require "chef/log"
class Chef
class HTTP
@@ -41,16 +41,16 @@ class Chef
end
end
- def initialize(opts={})
+ def initialize(opts = {})
end
- def handle_request(method, url, headers={}, data=false)
+ def handle_request(method, url, headers = {}, data = false)
[method, url, headers, data]
end
def handle_response(http_response, rest_request, return_value)
validate(http_response, http_response.body.bytesize) if http_response && http_response.body
- return [http_response, rest_request, return_value]
+ [http_response, rest_request, return_value]
end
def handle_stream_complete(http_response, rest_request, return_value)
@@ -63,7 +63,7 @@ class Chef
# Make sure the counter is reset since this object might get used
# again. See CHEF-5100
@content_length_counter = nil
- return [http_response, rest_request, return_value]
+ [http_response, rest_request, return_value]
end
def stream_response_handler(response)
@@ -73,24 +73,28 @@ class Chef
private
def response_content_length(response)
- return nil if response['content-length'].nil?
- if response['content-length'].is_a?(Array)
- response['content-length'].first.to_i
+ return nil if response["content-length"].nil?
+ if response["content-length"].is_a?(Array)
+ response["content-length"].first.to_i
else
- response['content-length'].to_i
+ response["content-length"].to_i
end
end
def validate(http_response, response_length)
content_length = response_content_length(http_response)
- transfer_encoding = http_response['transfer-encoding']
- content_encoding = http_response['content-encoding']
+ transfer_encoding = http_response["transfer-encoding"]
if content_length.nil?
Chef::Log.debug "HTTP server did not include a Content-Length header in response, cannot identify truncated downloads."
return true
end
+ if content_length < 0
+ Chef::Log.debug "HTTP server responded with a negative Content-Length header (#{content_length}), cannot identify truncated downloads."
+ return true
+ end
+
# if Transfer-Encoding is set the RFC states that we must ignore the Content-Length field
# CHEF-5041: some proxies uncompress gzip content, leave the incorrect content-length, but set the transfer-encoding field
unless transfer_encoding.nil?
diff --git a/lib/chef/json_compat.rb b/lib/chef/json_compat.rb
index 5e9f29a60b..c8f5496345 100644
--- a/lib/chef/json_compat.rb
+++ b/lib/chef/json_compat.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
# Wrapper class for interacting with JSON.
-require 'ffi_yajl'
-require 'chef/exceptions'
+require "ffi_yajl"
+require "chef/exceptions"
# We're requiring this to prevent breaking consumers using Hash.to_json
-require 'json'
+require "json"
class Chef
class JSONCompat
@@ -47,11 +47,9 @@ class Chef
# API to use to avoid create_addtions
def parse(source, opts = {})
- begin
- FFI_Yajl::Parser.parse(source, opts)
- rescue FFI_Yajl::ParseError => e
- raise Chef::Exceptions::JSON::ParseError, e.message
- end
+ FFI_Yajl::Parser.parse(source, opts)
+ rescue FFI_Yajl::ParseError => e
+ raise Chef::Exceptions::JSON::ParseError, e.message
end
# Just call the JSON gem's parse method with a modified :max_nesting field
@@ -61,7 +59,7 @@ class Chef
# JSON gem requires top level object to be a Hash or Array (otherwise
# you get the "must contain two octets" error). Yajl doesn't impose the
# same limitation. For compatibility, we re-impose this condition.
- unless obj.kind_of?(Hash) or obj.kind_of?(Array)
+ unless obj.kind_of?(Hash) || obj.kind_of?(Array)
raise Chef::Exceptions::JSON::ParseError, "Top level JSON object must be a Hash or Array. (actual: #{obj.class})"
end
@@ -88,7 +86,7 @@ class Chef
mapped_hash
end
when Array
- json_obj.map {|e| map_to_rb_obj(e) }
+ json_obj.map { |e| map_to_rb_obj(e) }
else
json_obj
end
@@ -102,11 +100,9 @@ class Chef
end
def to_json(obj, opts = nil)
- begin
- FFI_Yajl::Encoder.encode(obj, opts)
- rescue FFI_Yajl::EncodeError => e
- raise Chef::Exceptions::JSON::EncodeError, e.message
- end
+ FFI_Yajl::Encoder.encode(obj, opts)
+ rescue FFI_Yajl::EncodeError => e
+ raise Chef::Exceptions::JSON::EncodeError, e.message
end
def to_json_pretty(obj, opts = nil)
diff --git a/lib/chef/key.rb b/lib/chef/key.rb
index be4be7f230..c68fe1039c 100644
--- a/lib/chef/key.rb
+++ b/lib/chef/key.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,10 @@
# limitations under the License.
#
-require 'chef/json_compat'
-require 'chef/mixin/params_validate'
-require 'chef/exceptions'
+require "chef/json_compat"
+require "chef/mixin/params_validate"
+require "chef/exceptions"
+require "chef/server_api"
class Chef
# Class for interacting with a chef key object. Can be used to create new keys,
@@ -31,7 +32,7 @@ class Chef
# @attr [String] public_key the RSA string of this key
# @attr [String] private_key the RSA string of the private key if returned via a POST or PUT
# @attr [String] expiration_date the ISO formatted string YYYY-MM-DDTHH:MM:SSZ, i.e. 2020-12-24T21:00:00Z
- # @attr [String] rest Chef::REST object, initialized and cached via chef_rest method
+ # @attr [String] rest Chef::ServerAPI object, initialized and cached via chef_rest method
# @attr [string] api_base either "users" or "clients", initialized and cached via api_base method
#
# @attr_reader [String] actor_field_name must be either 'client' or 'user'
@@ -60,9 +61,9 @@ class Chef
def chef_rest
@rest ||= if @actor_field_name == "user"
- Chef::REST.new(Chef::Config[:chef_server_root])
+ Chef::ServerAPI.new(Chef::Config[:chef_server_root])
else
- Chef::REST.new(Chef::Config[:chef_server_url])
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url])
end
end
@@ -74,23 +75,23 @@ class Chef
end
end
- def actor(arg=nil)
+ def actor(arg = nil)
set_or_return(:actor, arg,
:regex => /^[a-z0-9\-_]+$/)
end
- def name(arg=nil)
+ def name(arg = nil)
set_or_return(:name, arg,
:kind_of => String)
end
- def public_key(arg=nil)
+ def public_key(arg = nil)
raise Chef::Exceptions::InvalidKeyAttribute, "you cannot set the public_key if create_key is true" if !arg.nil? && @create_key
set_or_return(:public_key, arg,
:kind_of => String)
end
- def private_key(arg=nil)
+ def private_key(arg = nil)
set_or_return(:private_key, arg,
:kind_of => String)
end
@@ -103,20 +104,20 @@ class Chef
@create_key = nil
end
- def create_key(arg=nil)
+ def create_key(arg = nil)
raise Chef::Exceptions::InvalidKeyAttribute, "you cannot set create_key to true if the public_key field exists" if arg == true && !@public_key.nil?
set_or_return(:create_key, arg,
:kind_of => [TrueClass, FalseClass])
end
- def expiration_date(arg=nil)
+ def expiration_date(arg = nil)
set_or_return(:expiration_date, arg,
:regex => /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z|infinity)$/)
end
def to_hash
result = {
- @actor_field_name => @actor
+ @actor_field_name => @actor,
}
result["name"] = @name if @name
result["public_key"] = @public_key if @public_key
@@ -147,14 +148,14 @@ class Chef
end
end
- payload = {"name" => @name}
- payload['public_key'] = @public_key unless @public_key.nil?
- payload['create_key'] = @create_key if @create_key
- payload['expiration_date'] = @expiration_date unless @expiration_date.nil?
- result = chef_rest.post_rest("#{api_base}/#{@actor}/keys", payload)
+ payload = { "name" => @name }
+ payload["public_key"] = @public_key unless @public_key.nil?
+ payload["create_key"] = @create_key if @create_key
+ payload["expiration_date"] = @expiration_date unless @expiration_date.nil?
+ result = chef_rest.post("#{api_base}/#{@actor}/keys", payload)
# append the private key to the current key if the server returned one,
# since the POST endpoint just returns uri and private_key if needed.
- new_key = self.to_hash
+ new_key = to_hash
new_key["private_key"] = result["private_key"] if result["private_key"]
Chef::Key.from_hash(new_key)
end
@@ -164,7 +165,7 @@ class Chef
end
# set @name and pass put_name if you wish to update the name of an existing key put_name to @name
- def update(put_name=nil)
+ def update(put_name = nil)
if @name.nil? && put_name.nil?
raise Chef::Exceptions::MissingKeyAttribute, "the name field must be populated or you must pass a name to update when update is called"
end
@@ -174,12 +175,12 @@ class Chef
# to @name.
put_name = @name if put_name.nil?
- new_key = chef_rest.put_rest("#{api_base}/#{@actor}/keys/#{put_name}", to_hash)
+ new_key = chef_rest.put("#{api_base}/#{@actor}/keys/#{put_name}", to_hash)
# if the server returned a public_key, remove the create_key field, as we now have a key
if new_key["public_key"]
- self.delete_create_key
+ delete_create_key
end
- Chef::Key.from_hash(self.to_hash.merge(new_key))
+ Chef::Key.from_hash(to_hash.merge(new_key))
end
def save
@@ -197,74 +198,74 @@ class Chef
raise Chef::Exceptions::MissingKeyAttribute, "the name field must be populated when delete is called"
end
- chef_rest.delete_rest("#{api_base}/#{@actor}/keys/#{@name}")
+ chef_rest.delete("#{api_base}/#{@actor}/keys/#{@name}")
end
- # Class methods
- def self.from_hash(key_hash)
- if key_hash.has_key?("user")
- key = Chef::Key.new(key_hash["user"], "user")
- elsif key_hash.has_key?("client")
- key = Chef::Key.new(key_hash["client"], "client")
- else
- raise Chef::Exceptions::MissingKeyAttribute, "The hash passed to from_hash does not contain the key 'user' or 'client'. Please pass a hash that defines one of those keys."
+ class << self
+ def from_hash(key_hash)
+ if key_hash.has_key?("user")
+ key = Chef::Key.new(key_hash["user"], "user")
+ elsif key_hash.has_key?("client")
+ key = Chef::Key.new(key_hash["client"], "client")
+ else
+ raise Chef::Exceptions::MissingKeyAttribute, "The hash passed to from_hash does not contain the key 'user' or 'client'. Please pass a hash that defines one of those keys."
+ end
+ key.name key_hash["name"] if key_hash.key?("name")
+ key.public_key key_hash["public_key"] if key_hash.key?("public_key")
+ key.private_key key_hash["private_key"] if key_hash.key?("private_key")
+ key.create_key key_hash["create_key"] if key_hash.key?("create_key")
+ key.expiration_date key_hash["expiration_date"] if key_hash.key?("expiration_date")
+ key
end
- key.name key_hash['name'] if key_hash.key?('name')
- key.public_key key_hash['public_key'] if key_hash.key?('public_key')
- key.private_key key_hash['private_key'] if key_hash.key?('private_key')
- key.create_key key_hash['create_key'] if key_hash.key?('create_key')
- key.expiration_date key_hash['expiration_date'] if key_hash.key?('expiration_date')
- key
- end
- def self.from_json(json)
- Chef::Key.from_hash(Chef::JSONCompat.from_json(json))
- end
+ def from_json(json)
+ Chef::Key.from_hash(Chef::JSONCompat.from_json(json))
+ end
- class << self
- alias_method :json_create, :from_json
- end
+ def json_create(json)
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::Key#from_json or one of the load_by methods.")
+ Chef::Key.from_json(json)
+ end
- def self.list_by_user(actor, inflate=false)
- keys = Chef::REST.new(Chef::Config[:chef_server_root]).get_rest("users/#{actor}/keys")
- self.list(keys, actor, :load_by_user, inflate)
- end
+ def list_by_user(actor, inflate = false)
+ keys = Chef::ServerAPI.new(Chef::Config[:chef_server_root]).get("users/#{actor}/keys")
+ list(keys, actor, :load_by_user, inflate)
+ end
- def self.list_by_client(actor, inflate=false)
- keys = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("clients/#{actor}/keys")
- self.list(keys, actor, :load_by_client, inflate)
- end
+ def list_by_client(actor, inflate = false)
+ keys = Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("clients/#{actor}/keys")
+ list(keys, actor, :load_by_client, inflate)
+ end
- def self.load_by_user(actor, key_name)
- response = Chef::REST.new(Chef::Config[:chef_server_root]).get_rest("users/#{actor}/keys/#{key_name}")
- Chef::Key.from_hash(response.merge({"user" => actor}))
- end
+ def load_by_user(actor, key_name)
+ response = Chef::ServerAPI.new(Chef::Config[:chef_server_root]).get("users/#{actor}/keys/#{key_name}")
+ Chef::Key.from_hash(response.merge({ "user" => actor }))
+ end
- def self.load_by_client(actor, key_name)
- response = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("clients/#{actor}/keys/#{key_name}")
- Chef::Key.from_hash(response.merge({"client" => actor}))
- end
+ def load_by_client(actor, key_name)
+ response = Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("clients/#{actor}/keys/#{key_name}")
+ Chef::Key.from_hash(response.merge({ "client" => actor }))
+ end
- def self.generate_fingerprint(public_key)
+ def generate_fingerprint(public_key)
openssl_key_object = OpenSSL::PKey::RSA.new(public_key)
data_string = OpenSSL::ASN1::Sequence([
- OpenSSL::ASN1::Integer.new(openssl_key_object.public_key.n),
- OpenSSL::ASN1::Integer.new(openssl_key_object.public_key.e)
- ])
- OpenSSL::Digest::SHA1.hexdigest(data_string.to_der).scan(/../).join(':')
- end
-
- private
+ OpenSSL::ASN1::Integer.new(openssl_key_object.public_key.n),
+ OpenSSL::ASN1::Integer.new(openssl_key_object.public_key.e),
+ ])
+ OpenSSL::Digest::SHA1.hexdigest(data_string.to_der).scan(/../).join(":")
+ end
- def self.list(keys, actor, load_method_symbol, inflate)
- if inflate
- keys.inject({}) do |key_map, result|
- name = result["name"]
- key_map[name] = Chef::Key.send(load_method_symbol, actor, name)
- key_map
+ def list(keys, actor, load_method_symbol, inflate)
+ if inflate
+ keys.inject({}) do |key_map, result|
+ name = result["name"]
+ key_map[name] = Chef::Key.send(load_method_symbol, actor, name)
+ key_map
+ end
+ else
+ keys
end
- else
- keys
end
end
end
diff --git a/lib/chef/knife.rb b/lib/chef/knife.rb
index 46e968827e..47ce85b9e3 100644
--- a/lib/chef/knife.rb
+++ b/lib/chef/knife.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,23 +17,25 @@
# limitations under the License.
#
-require 'forwardable'
-require 'chef/version'
-require 'mixlib/cli'
-require 'chef/workstation_config_loader'
-require 'chef/mixin/convert_to_class_name'
-require 'chef/mixin/path_sanity'
-require 'chef/knife/core/subcommand_loader'
-require 'chef/knife/core/ui'
-require 'chef/local_mode'
-require 'chef/rest'
-require 'chef/http/authenticator'
-require 'pp'
+require "forwardable"
+require "chef/version"
+require "mixlib/cli"
+require "chef/workstation_config_loader"
+require "chef/mixin/convert_to_class_name"
+require "chef/mixin/path_sanity"
+require "chef/knife/core/subcommand_loader"
+require "chef/knife/core/ui"
+require "chef/local_mode"
+require "chef/server_api"
+require "chef/http/authenticator"
+require "chef/http/http_request"
+require "chef/http"
+require "pp"
class Chef
class Knife
- Chef::REST::RESTRequest.user_agent = "Chef Knife#{Chef::REST::RESTRequest::UA_COMMON}"
+ Chef::HTTP::HTTPRequest.user_agent = "Chef Knife#{Chef::HTTP::HTTPRequest::UA_COMMON}"
include Mixlib::CLI
include Chef::Mixin::PathSanity
@@ -70,7 +72,7 @@ class Chef
@ui ||= Chef::Knife::UI.new(STDOUT, STDERR, STDIN, {})
end
- def self.msg(msg="")
+ def self.msg(msg = "")
ui.msg(msg)
end
@@ -87,7 +89,16 @@ class Chef
def self.inherited(subclass)
unless subclass.unnamed?
subcommands[subclass.snake_case_name] = subclass
- subcommand_files[subclass.snake_case_name] += [caller[0].split(/:\d+/).first]
+ subcommand_files[subclass.snake_case_name] +=
+ if subclass.superclass.to_s == "Chef::ChefFS::Knife"
+ # ChefFS-based commands have a superclass that defines an
+ # inhereited method which calls super. This means that the
+ # top of the call stack is not the class definition for
+ # our subcommand. Try the second entry in the call stack.
+ [path_from_caller(caller[1])]
+ else
+ [path_from_caller(caller[0])]
+ end
end
end
@@ -105,15 +116,15 @@ class Chef
end
def self.subcommand_category
- @category || snake_case_name.split('_').first unless unnamed?
+ @category || snake_case_name.split("_").first unless unnamed?
end
def self.snake_case_name
- convert_to_snake_case(name.split('::').last) unless unnamed?
+ convert_to_snake_case(name.split("::").last) unless unnamed?
end
def self.common_name
- snake_case_name.split('_').join(' ')
+ snake_case_name.split("_").join(" ")
end
# Does this class have a name? (Classes created via Class.new don't)
@@ -134,6 +145,11 @@ class Chef
end
def self.subcommand_class_from(args)
+ if args.size == 1 && args[0].strip.casecmp("rehash") == 0
+ # To prevent issues with the rehash file not pointing to the correct plugins,
+ # we always use the glob loader when regenerating the rehash file
+ @subcommand_loader = Chef::Knife::SubcommandLoader.gem_glob_loader(chef_config_dir)
+ end
subcommand_loader.command_class_from(args) || subcommand_not_found!(args)
end
@@ -184,13 +200,13 @@ class Chef
# args::: usually ARGV
# options::: A Mixlib::CLI option parser hash. These +options+ are how
# subcommands know about global knife CLI options
- def self.run(args, options={})
+ def self.run(args, options = {})
# Fallback debug logging. Normally the logger isn't configured until we
# read the config, but this means any logging that happens before the
# config file is read may be lost. If the KNIFE_DEBUG variable is set, we
# setup the logger for debug logging to stderr immediately to catch info
# from early in the setup process.
- if ENV['KNIFE_DEBUG']
+ if ENV["KNIFE_DEBUG"]
Chef::Log.init($stderr)
Chef::Log.level(:debug)
end
@@ -217,73 +233,81 @@ class Chef
end
end
- private
-
- OFFICIAL_PLUGINS = %w[ec2 rackspace windows openstack terremark bluebox]
-
- # :nodoc:
- # Error out and print usage. probably because the arguments given by the
- # user could not be resolved to a subcommand.
- def self.subcommand_not_found!(args)
- ui.fatal("Cannot find subcommand for: '#{args.join(' ')}'")
-
- # Mention rehash when the subcommands cache(plugin_manifest.json) is used
- if subcommand_loader.is_a?(Chef::Knife::SubcommandLoader::HashedCommandLoader) ||
- subcommand_loader.is_a?(Chef::Knife::SubcommandLoader::CustomManifestLoader)
- ui.info("If this is a recently installed plugin, please run 'knife rehash' to update the subcommands cache.")
+ OFFICIAL_PLUGINS = %w{ec2 rackspace windows openstack terremark bluebox}
+
+ class << self
+ def list_commands(preferred_category = nil)
+ category_desc = preferred_category ? preferred_category + " " : ""
+ msg "Available #{category_desc}subcommands: (for details, knife SUB-COMMAND --help)\n\n"
+ subcommand_loader.list_commands(preferred_category).sort.each do |category, commands|
+ next if category =~ /deprecated/i
+ msg "** #{category.upcase} COMMANDS **"
+ commands.sort.each do |command|
+ subcommand_loader.load_command(command)
+ msg subcommands[command].banner if subcommands[command]
+ end
+ msg
+ end
end
- if category_commands = guess_category(args)
- list_commands(category_commands)
- elsif missing_plugin = ( OFFICIAL_PLUGINS.find {|plugin| plugin == args[0]} )
- ui.info("The #{missing_plugin} commands were moved to plugins in Chef 0.10")
- ui.info("You can install the plugin with `(sudo) gem install knife-#{missing_plugin}`")
- ui.info("Use `chef gem install knife-#{missing_plugin}` instead if using ChefDK")
- else
- list_commands
+ private
+
+ # @api private
+ def path_from_caller(caller_line)
+ caller_line.split(/:\d+/).first
end
- exit 10
- end
+ # :nodoc:
+ # Error out and print usage. probably because the arguments given by the
+ # user could not be resolved to a subcommand.
+ # @api private
+ def subcommand_not_found!(args)
+ ui.fatal("Cannot find subcommand for: '#{args.join(' ')}'")
+
+ # Mention rehash when the subcommands cache(plugin_manifest.json) is used
+ if subcommand_loader.is_a?(Chef::Knife::SubcommandLoader::HashedCommandLoader) ||
+ subcommand_loader.is_a?(Chef::Knife::SubcommandLoader::CustomManifestLoader)
+ ui.info("If this is a recently installed plugin, please run 'knife rehash' to update the subcommands cache.")
+ end
- def self.list_commands(preferred_category=nil)
- category_desc = preferred_category ? preferred_category + " " : ''
- msg "Available #{category_desc}subcommands: (for details, knife SUB-COMMAND --help)\n\n"
- subcommand_loader.list_commands(preferred_category).sort.each do |category, commands|
- next if category =~ /deprecated/i
- msg "** #{category.upcase} COMMANDS **"
- commands.sort.each do |command|
- subcommand_loader.load_command(command)
- msg subcommands[command].banner if subcommands[command]
+ if category_commands = guess_category(args)
+ list_commands(category_commands)
+ elsif missing_plugin = ( OFFICIAL_PLUGINS.find { |plugin| plugin == args[0] } )
+ ui.info("The #{missing_plugin} commands were moved to plugins in Chef 0.10")
+ ui.info("You can install the plugin with `(sudo) gem install knife-#{missing_plugin}`")
+ ui.info("Use `chef gem install knife-#{missing_plugin}` instead if using ChefDK")
+ else
+ list_commands
end
- msg
+
+ exit 10
+ end
+
+ # @api private
+ def reset_config_path!
+ @@chef_config_dir = nil
end
- end
- def self.reset_config_path!
- @@chef_config_dir = nil
end
reset_config_path!
- public
-
# Create a new instance of the current class configured for the given
# arguments and options
- def initialize(argv=[])
+ def initialize(argv = [])
super() # having to call super in initialize is the most annoying anti-pattern :(
@ui = Chef::Knife::UI.new(STDOUT, STDERR, STDIN, config)
- command_name_words = self.class.snake_case_name.split('_')
+ command_name_words = self.class.snake_case_name.split("_")
# Mixlib::CLI ignores the embedded name_args
@name_args = parse_options(argv)
- @name_args.delete(command_name_words.join('-'))
+ @name_args.delete(command_name_words.join("-"))
@name_args.reject! { |name_arg| command_name_words.delete(name_arg) }
# knife node run_list add requires that we have extra logic to handle
# the case that command name words could be joined by an underscore :/
- command_name_words = command_name_words.join('_')
+ command_name_words = command_name_words.join("_")
@name_args.reject! { |name_arg| command_name_words == name_arg }
if config[:help]
@@ -293,7 +317,7 @@ class Chef
# copy Mixlib::CLI over so that it can be configured in knife.rb
# config file
- Chef::Config[:verbosity] = config[:verbosity]
+ Chef::Config[:verbosity] = config[:verbosity] if config[:verbosity]
end
def parse_options(args)
@@ -304,31 +328,35 @@ class Chef
exit(1)
end
- # Returns a subset of the Chef::Config[:knife] Hash that is relevant to the
- # currently executing knife command. This is used by #configure_chef to
- # apply settings from knife.rb to the +config+ hash.
+ # keys from mixlib-cli options
+ def cli_keys
+ self.class.options.keys
+ end
+
+ # extracts the settings from the Chef::Config[:knife] sub-hash that correspond
+ # to knife cli options -- in preparation for merging config values with cli values
+ #
+ # NOTE: due to weirdness in mixlib-config #has_key? is only true if the value has
+ # been set by the user -- the Chef::Config defaults return #has_key?() of false and
+ # this code DEPENDS on that functionality since applying the default values in
+ # Chef::Config[:knife] would break the defaults in the cli that we would otherwise
+ # overwrite.
def config_file_settings
- config_file_settings = {}
- self.class.options.keys.each do |key|
- config_file_settings[key] = Chef::Config[:knife][key] if Chef::Config[:knife].has_key?(key)
+ cli_keys.each_with_object({}) do |key, memo|
+ memo[key] = Chef::Config[:knife][key] if Chef::Config[:knife].has_key?(key)
end
- config_file_settings
end
- # Apply Config in this order:
- # defaults from mixlib-cli
- # settings from config file, via Chef::Config[:knife]
- # config from command line
+ # config is merged in this order (inverse of precedence)
+ # default_config - mixlib-cli defaults (accessor from the mixin)
+ # config_file_settings - Chef::Config[:knife] sub-hash
+ # config - mixlib-cli settings (accessor from the mixin)
def merge_configs
- # Apply config file settings on top of mixlib-cli defaults
- combined_config = default_config.merge(config_file_settings)
- # Apply user-supplied options on top of the above combination
- combined_config = combined_config.merge(config)
- # replace the config hash from mixlib-cli with our own.
- # Need to use the mutate-in-place #replace method instead of assigning to
- # the instance variable because other code may have a reference to the
- # original config hash object.
- config.replace(combined_config)
+ # other code may have a handle to the config object, so use Hash#replace to deliberately
+ # update-in-place.
+ config.replace(
+ default_config.merge(config_file_settings).merge(config)
+ )
end
# Catch-all method that does any massaging needed for various config
@@ -346,7 +374,7 @@ class Chef
Chef::Config[:log_level] = :debug
end
- Chef::Config[:log_level] = :debug if ENV['KNIFE_DEBUG']
+ Chef::Config[:log_level] = :debug if ENV["KNIFE_DEBUG"]
Chef::Config[:node_name] = config[:node_name] if config[:node_name]
Chef::Config[:client_key] = config[:client_key] if config[:client_key]
@@ -372,12 +400,6 @@ class Chef
Mixlib::Log::Formatter.show_time = false
Chef::Log.init(Chef::Config[:log_location])
Chef::Log.level(Chef::Config[:log_level] || :error)
-
- if Chef::Config[:node_name] && Chef::Config[:node_name].bytesize > 90
- # node names > 90 bytes only work with authentication protocol >= 1.1
- # see discussion in config.rb.
- Chef::Config[:authentication_protocol_version] = "1.1"
- end
end
def configure_chef
@@ -386,21 +408,37 @@ class Chef
config_loader = self.class.load_config(config[:config_file])
config[:config_file] = config_loader.config_location
+ # For CLI options like `--config-option key=value`. These have to get
+ # parsed and applied separately.
+ extra_config_options = config.delete(:config_option)
+
merge_configs
apply_computed_config
+
# This has to be after apply_computed_config so that Mixlib::Log is configured
Chef::Log.info("Using configuration from #{config[:config_file]}") if config[:config_file]
+
+ begin
+ Chef::Config.apply_extra_config_options(extra_config_options)
+ rescue ChefConfig::UnparsableConfigOption => e
+ ui.error e.message
+ show_usage
+ exit(1)
+ end
+
+ Chef::Config.export_proxies
end
def show_usage
- stdout.puts("USAGE: " + self.opt_parser.to_s)
+ stdout.puts("USAGE: " + opt_parser.to_s)
end
def run_with_pretty_exceptions(raise_exception = false)
- unless self.respond_to?(:run)
+ unless respond_to?(:run)
ui.error "You need to add a #run method to your knife command before you can use it"
end
enforce_path_sanity
+ maybe_setup_fips
Chef::LocalMode.with_server_connectivity do
run
end
@@ -494,32 +532,38 @@ class Chef
#--
# TODO: this code belongs in Chef::REST
def format_rest_error(response)
- Array(Chef::JSONCompat.from_json(response.body)["error"]).join('; ')
+ Array(Chef::JSONCompat.from_json(response.body)["error"]).join("; ")
rescue Exception
response.body
end
- def create_object(object, pretty_name=nil, &block)
- output = edit_data(object)
+ # FIXME: yard with @yield
+ def create_object(object, pretty_name = nil, object_class: nil)
+ output = if object_class
+ edit_data(object, object_class: object_class)
+ else
+ edit_hash(object)
+ end
if Kernel.block_given?
- output = block.call(output)
+ output = yield(output)
else
output.save
end
pretty_name ||= output
- self.msg("Created #{pretty_name}")
+ msg("Created #{pretty_name}")
output(output) if config[:print_after]
end
- def delete_object(klass, name, delete_name=nil, &block)
+ # FIXME: yard with @yield
+ def delete_object(klass, name, delete_name = nil)
confirm("Do you really want to delete #{name}")
if Kernel.block_given?
- object = block.call
+ object = yield
else
object = klass.load(name)
object.destroy
@@ -528,7 +572,7 @@ class Chef
output(format_for_display(object)) if config[:print_after]
obj_name = delete_name ? "#{delete_name}[#{name}]" : object
- self.msg("Deleted #{obj_name}")
+ msg("Deleted #{obj_name}")
end
# helper method for testing if a field exists
@@ -543,15 +587,15 @@ class Chef
def rest
@rest ||= begin
- require 'chef/rest'
- Chef::REST.new(Chef::Config[:chef_server_url])
+ require "chef/server_api"
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url])
end
end
def noauth_rest
@rest ||= begin
- require 'chef/rest'
- Chef::REST.new(Chef::Config[:chef_server_url], false, false)
+ require "chef/http/simple_json"
+ Chef::HTTP::SimpleJSON.new(Chef::Config[:chef_server_url])
end
end
@@ -559,5 +603,11 @@ class Chef
Chef::Config[:chef_server_url]
end
+ def maybe_setup_fips
+ if !config[:fips].nil?
+ Chef::Config[:fips] = config[:fips]
+ end
+ Chef::Config.init_openssl
+ end
end
end
diff --git a/lib/chef/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb
index 8502ccb8eb..ee4d9ce7af 100644
--- a/lib/chef/knife/bootstrap.rb
+++ b/lib/chef/knife/bootstrap.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/data_bag_secret_options'
-require 'erubis'
-require 'chef/knife/bootstrap/chef_vault_handler'
-require 'chef/knife/bootstrap/client_builder'
-require 'chef/util/path_helper'
+require "chef/knife"
+require "chef/knife/data_bag_secret_options"
+require "erubis"
+require "chef/knife/bootstrap/chef_vault_handler"
+require "chef/knife/bootstrap/client_builder"
+require "chef/util/path_helper"
class Chef
class Knife
@@ -32,13 +32,13 @@ class Chef
attr_accessor :chef_vault_handler
deps do
- require 'chef/knife/core/bootstrap_context'
- require 'chef/json_compat'
- require 'tempfile'
- require 'highline'
- require 'net/ssh'
- require 'net/ssh/multi'
- require 'chef/knife/ssh'
+ require "chef/knife/core/bootstrap_context"
+ require "chef/json_compat"
+ require "tempfile"
+ require "highline"
+ require "net/ssh"
+ require "net/ssh/multi"
+ require "chef/knife/ssh"
Chef::Knife::Ssh.load_deps
end
@@ -74,8 +74,12 @@ class Chef
:boolean => true
option :identity_file,
- :short => "-i IDENTITY_FILE",
:long => "--identity-file IDENTITY_FILE",
+ :description => "The SSH identity file used for authentication. [DEPRECATED] Use --ssh-identity-file instead."
+
+ option :ssh_identity_file,
+ :short => "-i IDENTITY_FILE",
+ :long => "--ssh-identity-file IDENTITY_FILE",
:description => "The SSH identity file used for authentication"
option :chef_node_name,
@@ -97,6 +101,14 @@ class Chef
:description => "The proxy server for the node being bootstrapped",
:proc => Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p }
+ option :bootstrap_proxy_user,
+ :long => "--bootstrap-proxy-user PROXY_USER",
+ :description => "The proxy authentication username for the node being bootstrapped"
+
+ option :bootstrap_proxy_pass,
+ :long => "--bootstrap-proxy-pass PROXY_PASS",
+ :description => "The proxy authentication password for the node being bootstrapped"
+
option :bootstrap_no_proxy,
:long => "--bootstrap-no-proxy [NO_PROXY_URL|NO_PROXY_IP]",
:description => "Do not proxy locations for the node being bootstrapped; this option is used internally by Opscode",
@@ -185,7 +197,7 @@ class Chef
option :hint,
:long => "--hint HINT_NAME[=HINT_FILE]",
- :description => "Specify Ohai Hint to be set on the bootstrap target. Use multiple --hint options to specify multiple hints.",
+ :description => "Specify Ohai Hint to be set on the bootstrap target. Use multiple --hint options to specify multiple hints.",
:proc => Proc.new { |h|
Chef::Config[:knife][:hints] ||= Hash.new
name, path = h.split("=")
@@ -216,10 +228,11 @@ class Chef
:long => "--node-ssl-verify-mode [peer|none]",
:description => "Whether or not to verify the SSL cert for all HTTPS requests.",
:proc => Proc.new { |v|
- valid_values = ["none", "peer"]
+ valid_values = %w{none peer}
unless valid_values.include?(v)
raise "Invalid value '#{v}' for --node-ssl-verify-mode. Valid values are: #{valid_values.join(", ")}"
end
+ v
}
option :node_verify_api_cert,
@@ -228,15 +241,15 @@ class Chef
:boolean => true
option :bootstrap_vault_file,
- :long => '--bootstrap-vault-file VAULT_FILE',
- :description => 'A JSON file with a list of vault(s) and item(s) to be updated'
+ :long => "--bootstrap-vault-file VAULT_FILE",
+ :description => "A JSON file with a list of vault(s) and item(s) to be updated"
option :bootstrap_vault_json,
- :long => '--bootstrap-vault-json VAULT_JSON',
- :description => 'A JSON string with the vault(s) and item(s) to be updated'
+ :long => "--bootstrap-vault-json VAULT_JSON",
+ :description => "A JSON string with the vault(s) and item(s) to be updated"
option :bootstrap_vault_item,
- :long => '--bootstrap-vault-item VAULT_ITEM',
+ :long => "--bootstrap-vault-item VAULT_ITEM",
:description => 'A single vault and item to update as "vault:item"',
:proc => Proc.new { |i|
(vault, item) = i.split(/:/)
@@ -246,12 +259,12 @@ class Chef
Chef::Config[:knife][:bootstrap_vault_item]
}
- def initialize(argv=[])
+ def initialize(argv = [])
super
@client_builder = Chef::Knife::Bootstrap::ClientBuilder.new(
chef_config: Chef::Config,
knife_config: config,
- ui: ui,
+ ui: ui
)
@chef_vault_handler = Chef::Knife::Bootstrap::ChefVaultHandler.new(
knife_config: config,
@@ -278,13 +291,13 @@ class Chef
# @return [String] The DNS or IP that bootstrap will connect to
def server_name
if host_descriptor
- @server_name ||= host_descriptor.split('@').reverse[0]
+ @server_name ||= host_descriptor.split("@").reverse[0]
end
end
def user_name
if host_descriptor
- @user_name ||= host_descriptor.split('@').reverse[1]
+ @user_name ||= host_descriptor.split("@").reverse[1]
end
end
@@ -306,10 +319,10 @@ class Chef
# Otherwise search the template directories until we find the right one
bootstrap_files = []
- bootstrap_files << File.join(File.dirname(__FILE__), 'bootstrap/templates', "#{template}.erb")
+ bootstrap_files << File.join(File.dirname(__FILE__), "bootstrap/templates", "#{template}.erb")
bootstrap_files << File.join(Knife.chef_config_dir, "bootstrap", "#{template}.erb") if Chef::Knife.chef_config_dir
- Chef::Util::PathHelper.home('.chef', 'bootstrap', "#{template}.erb") {|p| bootstrap_files << p}
- bootstrap_files << Gem.find_files(File.join("chef","knife","bootstrap","#{template}.erb"))
+ Chef::Util::PathHelper.home(".chef", "bootstrap", "#{template}.erb") { |p| bootstrap_files << p }
+ bootstrap_files << Gem.find_files(File.join("chef", "knife", "bootstrap", "#{template}.erb"))
bootstrap_files.flatten!
template_file = Array(bootstrap_files).find do |bootstrap_template|
@@ -363,7 +376,7 @@ class Chef
# chef-vault integration must use the new client-side hawtness, otherwise to use the
# new client-side hawtness, just delete your validation key.
- if chef_vault_handler.doing_chef_vault? ||
+ if chef_vault_handler.doing_chef_vault? ||
(Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key])))
unless config[:chef_node_name]
@@ -373,7 +386,7 @@ class Chef
client_builder.run
- chef_vault_handler.run(node_name: config[:chef_node_name])
+ chef_vault_handler.run(client_builder.client)
bootstrap_context.client_pem = client_builder.client_path
else
@@ -426,7 +439,7 @@ class Chef
ssh.config[:ssh_port] = config[:ssh_port]
ssh.config[:ssh_gateway] = config[:ssh_gateway]
ssh.config[:forward_agent] = config[:forward_agent]
- ssh.config[:identity_file] = config[:identity_file]
+ ssh.config[:ssh_identity_file] = config[:ssh_identity_file] || config[:identity_file]
ssh.config[:manual] = true
ssh.config[:host_key_verify] = config[:host_key_verify]
ssh.config[:on_error] = :raise
@@ -435,7 +448,7 @@ class Chef
def knife_ssh_with_password_auth
ssh = knife_ssh
- ssh.config[:identity_file] = nil
+ ssh.config[:ssh_identity_file] = nil
ssh.config[:ssh_password] = ssh.get_password
ssh
end
@@ -445,7 +458,7 @@ class Chef
if config[:use_sudo]
sudo_prefix = config[:use_sudo_password] ? "echo '#{config[:ssh_password]}' | sudo -S " : "sudo "
- command = config[:preserve_home] ? "#{sudo_prefix} #{command}" : "#{sudo_prefix} -H #{command}"
+ command = config[:preserve_home] ? "#{sudo_prefix} #{command}" : "#{sudo_prefix} -H #{command}"
end
command
@@ -455,7 +468,15 @@ class Chef
# True if policy_name and run_list are both given
def policyfile_and_run_list_given?
- !config[:run_list].empty? && !!config[:policy_name]
+ run_list_given? && policyfile_options_given?
+ end
+
+ def run_list_given?
+ !config[:run_list].nil? && !config[:run_list].empty?
+ end
+
+ def policyfile_options_given?
+ !!config[:policy_name]
end
# True if one of policy_name or policy_group was given, but not both
diff --git a/lib/chef/knife/bootstrap/chef_vault_handler.rb b/lib/chef/knife/bootstrap/chef_vault_handler.rb
index f658957499..9990565856 100644
--- a/lib/chef/knife/bootstrap/chef_vault_handler.rb
+++ b/lib/chef/knife/bootstrap/chef_vault_handler.rb
@@ -1,6 +1,6 @@
#
# Author:: Lamont Granquist (<lamont@chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/knife/bootstrap'
+require "chef/knife/bootstrap"
class Chef
class Knife
@@ -28,8 +28,8 @@ class Chef
# @return [Chef::Knife::UI] ui object for output
attr_accessor :ui
- # @return [String] name of the node (technically name of the client)
- attr_reader :node_name
+ # @return [Chef::ApiClient] vault client
+ attr_reader :client
# @param knife_config [Hash] knife merged config, typically @config
# @param ui [Chef::Knife::UI] ui object for output
@@ -38,18 +38,15 @@ class Chef
@ui = ui
end
- # Updates the chef vault items for the newly created node.
+ # Updates the chef vault items for the newly created client.
#
- # @param node_name [String] name of the node (technically name of the client)
- # @todo: node_name should be mandatory (ruby 2.0 compat)
- def run(node_name: nil)
+ # @param client [Chef::ApiClient] vault client
+ def run(client)
return unless doing_chef_vault?
sanity_check
- @node_name = node_name
-
- ui.info("Updating Chef Vault, waiting for client to be searchable..") while wait_for_client
+ @client = client
update_bootstrap_vault_json!
end
@@ -126,7 +123,7 @@ class Chef
def update_vault(vault, item)
require_chef_vault!
bootstrap_vault_item = load_chef_bootstrap_vault_item(vault, item)
- bootstrap_vault_item.clients("name:#{node_name}")
+ bootstrap_vault_item.clients(client)
bootstrap_vault_item.save
end
@@ -139,24 +136,20 @@ class Chef
ChefVault::Item.load(vault, item)
end
- public :load_chef_bootstrap_vault_item # for stubbing
-
- # Helper used to spin waiting for the client to appear in search.
- #
- # @return [Boolean] true if the client is searchable
- def wait_for_client
- sleep 1
- !Chef::Search::Query.new.search(:client, "name:#{node_name}")[0]
- end
+ public :load_chef_bootstrap_vault_item # for stubbing
# Helper to very lazily require the chef-vault gem
def require_chef_vault!
@require_chef_vault ||=
begin
- require 'chef-vault'
+ error_message = "Knife bootstrap requires version 2.6.0 or higher of the chef-vault gem to configure chef vault items"
+ require "chef-vault"
+ if Gem::Version.new(ChefVault::VERSION) < Gem::Version.new("2.6.0")
+ raise error_message
+ end
true
rescue LoadError
- raise "Knife bootstrap cannot configure chef vault items when the chef-vault gem is not installed"
+ raise error_message
end
end
diff --git a/lib/chef/knife/bootstrap/client_builder.rb b/lib/chef/knife/bootstrap/client_builder.rb
index 7eb1e22628..cab33cd811 100644
--- a/lib/chef/knife/bootstrap/client_builder.rb
+++ b/lib/chef/knife/bootstrap/client_builder.rb
@@ -1,6 +1,6 @@
#
# Author:: Lamont Granquist (<lamont@chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'chef/node'
-require 'chef/rest'
-require 'chef/api_client/registration'
-require 'chef/api_client'
-require 'chef/knife/bootstrap'
-require 'tmpdir'
+require "chef/node"
+require "chef/server_api"
+require "chef/api_client/registration"
+require "chef/api_client"
+require "chef/knife/bootstrap"
+require "tmpdir"
class Chef
class Knife
@@ -34,6 +34,8 @@ class Chef
attr_accessor :chef_config
# @return [Chef::Knife::UI] ui object for output
attr_accessor :ui
+ # @return [Chef::ApiClient] client saved on run
+ attr_reader :client
# @param knife_config [Hash] Hash of knife config settings
# @param chef_config [Hash] Hash of chef config settings
@@ -51,7 +53,7 @@ class Chef
ui.info("Creating new client for #{node_name}")
- create_client!
+ @client = create_client!
ui.info("Creating new node for #{node_name}")
@@ -183,22 +185,22 @@ class Chef
# @param relative_path [String] URI path relative to the chef organization
# @return [Boolean] if the relative path exists or returns a 404
def resource_exists?(relative_path)
- rest.get_rest(relative_path)
+ rest.get(relative_path)
true
rescue Net::HTTPServerException => e
raise unless e.response.code == "404"
false
end
- # @return [Chef::REST] REST client using the client credentials
+ # @return [Chef::ServerAPI] REST client using the client credentials
def client_rest
- @client_rest ||= Chef::REST.new(chef_server_url, node_name, client_path)
+ @client_rest ||= Chef::ServerAPI.new(chef_server_url, :client_name => node_name, :signing_key_filename => client_path)
end
- # @return [Chef::REST] REST client using the cli user's knife credentials
+ # @return [Chef::ServerAPI] REST client using the cli user's knife credentials
# this uses the users's credentials
def rest
- @rest ||= Chef::REST.new(chef_server_url)
+ @rest ||= Chef::ServerAPI.new(chef_server_url)
end
end
end
diff --git a/lib/chef/knife/bootstrap/templates/chef-full.erb b/lib/chef/knife/bootstrap/templates/chef-full.erb
index 575aec0f50..6007ff9859 100644
--- a/lib/chef/knife/bootstrap/templates/chef-full.erb
+++ b/lib/chef/knife/bootstrap/templates/chef-full.erb
@@ -165,7 +165,7 @@ do_download() {
<% if knife_config[:bootstrap_install_command] %>
<%= knife_config[:bootstrap_install_command] %>
<% else %>
- install_sh="<%= knife_config[:bootstrap_url] ? knife_config[:bootstrap_url] : "https://www.opscode.com/chef/install.sh" %>"
+ install_sh="<%= knife_config[:bootstrap_url] ? knife_config[:bootstrap_url] : "https://omnitruck-direct.chef.io/chef/install.sh" %>"
if test -f /usr/bin/chef-client; then
echo "-----> Existing Chef installation detected"
else
@@ -226,6 +226,11 @@ cat > /etc/chef/first-boot.json <<EOP
<%= Chef::JSONCompat.to_json(first_boot) %>
EOP
+<% unless client_d.empty? -%>
+mkdir -p /etc/chef/client.d
+<%= client_d %>
+<% end -%>
+
echo "Starting the first Chef Client run..."
<%= start_chef %>'
diff --git a/lib/chef/knife/client_bulk_delete.rb b/lib/chef/knife/client_bulk_delete.rb
index b439e6f995..a7fa7142c8 100644
--- a/lib/chef/knife/client_bulk_delete.rb
+++ b/lib/chef/knife/client_bulk_delete.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class ClientBulkDelete < Knife
deps do
- require 'chef/api_client_v1'
- require 'chef/json_compat'
+ require "chef/api_client_v1"
+ require "chef/json_compat"
end
option :delete_validators,
@@ -65,7 +65,7 @@ class Chef
def check_and_delete_validators(validators)
unless validators.empty?
unless config[:delete_validators]
- ui.msg("Following clients are validators and will not be deleted.")
+ ui.msg("The following clients are validators and will not be deleted:")
print_clients(validators)
ui.msg("You must specify --delete-validators to delete the validator clients")
else
diff --git a/lib/chef/knife/client_create.rb b/lib/chef/knife/client_create.rb
index fa9a1a7e32..e28378cd4a 100644
--- a/lib/chef/knife/client_create.rb
+++ b/lib/chef/knife/client_create.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class ClientCreate < Knife
deps do
- require 'chef/api_client_v1'
- require 'chef/json_compat'
+ require "chef/api_client_v1"
+ require "chef/json_compat"
end
option :file,
@@ -35,11 +35,11 @@ class Chef
option :admin,
:short => "-a",
:long => "--admin",
- :description => "Open Source Chef 11 only. Create the client as an admin.",
+ :description => "Open Source Chef Server 11 only. Create the client as an admin.",
:boolean => true
option :validator,
- :long => "--validator",
+ :long => "--validator",
:description => "Create the client as a validator.",
:boolean => true
@@ -51,7 +51,7 @@ class Chef
option :prevent_keygen,
:short => "-k",
:long => "--prevent-keygen",
- :description => "API V1 only. Prevent server from generating a default key pair for you. Cannot be passed with --public-key.",
+ :description => "API V1 (Chef Server 12.1+) only. Prevent server from generating a default key pair for you. Cannot be passed with --public-key.",
:boolean => true
banner "knife client create CLIENTNAME (options)"
@@ -91,7 +91,7 @@ class Chef
client.public_key File.read(File.expand_path(config[:public_key]))
end
- output = edit_data(client)
+ output = edit_hash(client)
final_client = create_client(output)
ui.info("Created #{final_client}")
diff --git a/lib/chef/knife/client_delete.rb b/lib/chef/knife/client_delete.rb
index a49c0867a8..38da5c2a73 100644
--- a/lib/chef/knife/client_delete.rb
+++ b/lib/chef/knife/client_delete.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class ClientDelete < Knife
deps do
- require 'chef/api_client_v1'
- require 'chef/json_compat'
+ require "chef/api_client_v1"
+ require "chef/json_compat"
end
option :delete_validators,
@@ -32,29 +32,32 @@ class Chef
:long => "--delete-validators",
:description => "Force deletion of client if it's a validator"
- banner "knife client delete CLIENT (options)"
+ banner "knife client delete [CLIENT[,CLIENT]] (options)"
def run
- @client_name = @name_args[0]
-
- if @client_name.nil?
+ if @name_args.length == 0
show_usage
- ui.fatal("You must specify a client name")
+ ui.fatal("You must specify at least one client name")
exit 1
end
- delete_object(Chef::ApiClientV1, @client_name, 'client') {
- object = Chef::ApiClientV1.load(@client_name)
+ @name_args.each do |client_name|
+ delete_client(client_name)
+ end
+ end
+
+ def delete_client(client_name)
+ delete_object(Chef::ApiClientV1, client_name, "client") do
+ object = Chef::ApiClientV1.load(client_name)
if object.validator
unless config[:delete_validators]
- ui.fatal("You must specify --delete-validators to delete the validator client #{@client_name}")
+ ui.fatal("You must specify --delete-validators to delete the validator client #{client_name}")
exit 2
end
end
object.destroy
- }
+ end
end
-
end
end
end
diff --git a/lib/chef/knife/client_edit.rb b/lib/chef/knife/client_edit.rb
index 5dcd8f212b..948d43cc67 100644
--- a/lib/chef/knife/client_edit.rb
+++ b/lib/chef/knife/client_edit.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class ClientEdit < Knife
deps do
- require 'chef/api_client_v1'
- require 'chef/json_compat'
+ require "chef/api_client_v1"
+ require "chef/json_compat"
end
banner "knife client edit CLIENT (options)"
@@ -39,7 +39,7 @@ class Chef
end
original_data = Chef::ApiClientV1.load(@client_name).to_hash
- edited_client = edit_data(original_data)
+ edited_client = edit_hash(original_data)
if original_data != edited_client
client = Chef::ApiClientV1.from_hash(edited_client)
client.save
diff --git a/lib/chef/knife/client_key_create.rb b/lib/chef/knife/client_key_create.rb
index 3b7e97eb24..68ad4d16d2 100644
--- a/lib/chef/knife/client_key_create.rb
+++ b/lib/chef/knife/client_key_create.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/key_create_base'
+require "chef/knife"
+require "chef/knife/key_create_base"
class Chef
class Knife
@@ -32,7 +32,7 @@ class Chef
attr_reader :actor
- def initialize(argv=[])
+ def initialize(argv = [])
super(argv)
@service_object = nil
end
@@ -43,7 +43,7 @@ class Chef
end
def actor_field_name
- 'client'
+ "client"
end
def service_object
@@ -51,7 +51,7 @@ class Chef
end
def actor_missing_error
- 'You must specify a client name'
+ "You must specify a client name"
end
def apply_params!(params)
diff --git a/lib/chef/knife/client_key_delete.rb b/lib/chef/knife/client_key_delete.rb
index 8ecdfe1ec8..64eae2e27c 100644
--- a/lib/chef/knife/client_key_delete.rb
+++ b/lib/chef/knife/client_key_delete.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -31,7 +31,7 @@ class Chef
attr_reader :actor
- def initialize(argv=[])
+ def initialize(argv = [])
super(argv)
@service_object = nil
end
@@ -42,15 +42,15 @@ class Chef
end
def actor_field_name
- 'client'
+ "client"
end
def actor_missing_error
- 'You must specify a client name'
+ "You must specify a client name"
end
def keyname_missing_error
- 'You must specify a key name'
+ "You must specify a key name"
end
def service_object
diff --git a/lib/chef/knife/client_key_edit.rb b/lib/chef/knife/client_key_edit.rb
index 1de45f4ca2..1dbd3c487b 100644
--- a/lib/chef/knife/client_key_edit.rb
+++ b/lib/chef/knife/client_key_edit.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/key_edit_base'
+require "chef/knife"
+require "chef/knife/key_edit_base"
class Chef
class Knife
@@ -30,11 +30,11 @@ class Chef
class ClientKeyEdit < Knife
include Chef::Knife::KeyEditBase
- banner 'knife client key edit CLIENT KEYNAME (options)'
+ banner "knife client key edit CLIENT KEYNAME (options)"
attr_reader :actor
- def initialize(argv=[])
+ def initialize(argv = [])
super(argv)
@service_object = nil
end
@@ -45,7 +45,7 @@ class Chef
end
def actor_field_name
- 'client'
+ "client"
end
def service_object
@@ -53,11 +53,11 @@ class Chef
end
def actor_missing_error
- 'You must specify a client name'
+ "You must specify a client name"
end
def keyname_missing_error
- 'You must specify a key name'
+ "You must specify a key name"
end
def apply_params!(params)
@@ -77,4 +77,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/knife/client_key_list.rb b/lib/chef/knife/client_key_list.rb
index f6f29ae03f..194ad42931 100644
--- a/lib/chef/knife/client_key_list.rb
+++ b/lib/chef/knife/client_key_list.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/key_list_base'
+require "chef/knife"
+require "chef/knife/key_list_base"
class Chef
class Knife
@@ -34,7 +34,7 @@ class Chef
attr_reader :actor
- def initialize(argv=[])
+ def initialize(argv = [])
super(argv)
@service_object = nil
end
@@ -49,7 +49,7 @@ class Chef
end
def actor_missing_error
- 'You must specify a client name'
+ "You must specify a client name"
end
def service_object
diff --git a/lib/chef/knife/client_key_show.rb b/lib/chef/knife/client_key_show.rb
index c39a279000..77f9e96c5a 100644
--- a/lib/chef/knife/client_key_show.rb
+++ b/lib/chef/knife/client_key_show.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -31,7 +31,7 @@ class Chef
attr_reader :actor
- def initialize(argv=[])
+ def initialize(argv = [])
super(argv)
@service_object = nil
end
@@ -46,11 +46,11 @@ class Chef
end
def actor_missing_error
- 'You must specify a client name'
+ "You must specify a client name"
end
def keyname_missing_error
- 'You must specify a key name'
+ "You must specify a key name"
end
def service_object
diff --git a/lib/chef/knife/client_list.rb b/lib/chef/knife/client_list.rb
index d8a3698b6a..b17de0f3ad 100644
--- a/lib/chef/knife/client_list.rb
+++ b/lib/chef/knife/client_list.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class ClientList < Knife
deps do
- require 'chef/api_client_v1'
- require 'chef/json_compat'
+ require "chef/api_client_v1"
+ require "chef/json_compat"
end
banner "knife client list (options)"
diff --git a/lib/chef/knife/client_reregister.rb b/lib/chef/knife/client_reregister.rb
index b94761e718..5d9b2c0962 100644
--- a/lib/chef/knife/client_reregister.rb
+++ b/lib/chef/knife/client_reregister.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class ClientReregister < Knife
deps do
- require 'chef/api_client_v1'
- require 'chef/json_compat'
+ require "chef/api_client_v1"
+ require "chef/json_compat"
end
banner "knife client reregister CLIENT (options)"
diff --git a/lib/chef/knife/client_show.rb b/lib/chef/knife/client_show.rb
index bdac3f9758..ce3bf458b2 100644
--- a/lib/chef/knife/client_show.rb
+++ b/lib/chef/knife/client_show.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -25,8 +25,8 @@ class Chef
include Knife::Core::MultiAttributeReturnOption
deps do
- require 'chef/api_client_v1'
- require 'chef/json_compat'
+ require "chef/api_client_v1"
+ require "chef/json_compat"
end
banner "knife client show CLIENT (options)"
diff --git a/lib/chef/knife/configure.rb b/lib/chef/knife/configure.rb
index 8bb8930aee..48007bbee7 100644
--- a/lib/chef/knife/configure.rb
+++ b/lib/chef/knife/configure.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -25,7 +25,7 @@ class Chef
attr_reader :chef_repo, :new_client_key, :validation_client_name, :validation_key
deps do
- require 'ohai'
+ require "ohai"
Chef::Knife::ClientCreate.load_deps
Chef::Knife::UserCreate.load_deps
end
@@ -61,7 +61,7 @@ class Chef
def configure_chef
# We are just faking out the system so that you can do this without a key specified
- Chef::Config[:node_name] = 'woot'
+ Chef::Config[:node_name] = "woot"
super
Chef::Config[:node_name] = nil
end
@@ -97,7 +97,7 @@ EOH
user_create = Chef::Knife::UserCreate.new
user_create.name_args = [ new_client_name ]
user_create.config[:user_password] = config[:user_password] ||
- ui.ask("Please enter a password for the new user: ") {|q| q.echo = false}
+ ui.ask("Please enter a password for the new user: ") { |q| q.echo = false }
user_create.config[:admin] = true
user_create.config[:file] = new_client_key
user_create.config[:yes] = true
@@ -108,13 +108,13 @@ EOH
ui.msg("")
ui.msg("You must place your client key in:")
ui.msg(" #{new_client_key}")
- ui.msg("Before running commands with Knife!")
+ ui.msg("Before running commands with Knife")
ui.msg("")
ui.msg("*****")
ui.msg("")
ui.msg("You must place your validation key in:")
ui.msg(" #{validation_key}")
- ui.msg("Before generating instance data with Knife!")
+ ui.msg("Before generating instance data with Knife")
ui.msg("")
ui.msg("*****")
end
@@ -133,17 +133,17 @@ EOH
def ask_user_for_config
server_name = guess_servername
- @chef_server = config[:chef_server_url] || ask_question("Please enter the chef server URL: ", :default => "https://#{server_name}:443")
+ @chef_server = config[:chef_server_url] || ask_question("Please enter the chef server URL: ", :default => "https://#{server_name}/organizations/myorg")
if config[:initial]
@new_client_name = config[:node_name] || ask_question("Please enter a name for the new user: ", :default => Etc.getlogin)
- @admin_client_name = config[:admin_client_name] || ask_question("Please enter the existing admin name: ", :default => 'admin')
- @admin_client_key = config[:admin_client_key] || ask_question("Please enter the location of the existing admin's private key: ", :default => '/etc/chef-server/admin.pem')
+ @admin_client_name = config[:admin_client_name] || ask_question("Please enter the existing admin name: ", :default => "admin")
+ @admin_client_key = config[:admin_client_key] || ask_question("Please enter the location of the existing admin's private key: ", :default => "/etc/chef-server/admin.pem")
@admin_client_key = File.expand_path(@admin_client_key)
else
@new_client_name = config[:node_name] || ask_question("Please enter an existing username or clientname for the API: ", :default => Etc.getlogin)
end
- @validation_client_name = config[:validation_client_name] || ask_question("Please enter the validation clientname: ", :default => 'chef-validator')
- @validation_key = config[:validation_key] || ask_question("Please enter the location of the validation key: ", :default => '/etc/chef-server/chef-validator.pem')
+ @validation_client_name = config[:validation_client_name] || ask_question("Please enter the validation clientname: ", :default => "chef-validator")
+ @validation_key = config[:validation_key] || ask_question("Please enter the location of the validation key: ", :default => "/etc/chef-server/chef-validator.pem")
@validation_key = File.expand_path(@validation_key)
@chef_repo = config[:repository] || ask_question("Please enter the path to a chef repository (or leave blank): ")
@@ -154,9 +154,9 @@ EOH
def guess_servername
o = Ohai::System.new
o.load_plugins
- o.require_plugin 'os'
- o.require_plugin 'hostname'
- o[:fqdn] || o[:machinename] || o[:hostname] || 'localhost'
+ o.require_plugin "os"
+ o.require_plugin "hostname"
+ o[:fqdn] || o[:machinename] || o[:hostname] || "localhost"
end
def config_file
diff --git a/lib/chef/knife/configure_client.rb b/lib/chef/knife/configure_client.rb
index 838d9a1f58..7d0b3d260d 100644
--- a/lib/chef/knife/configure_client.rb
+++ b/lib/chef/knife/configure_client.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -34,13 +34,13 @@ class Chef
FileUtils.mkdir_p(@config_dir)
ui.info("Writing client.rb")
File.open(File.join(@config_dir, "client.rb"), "w") do |file|
- file.puts('log_level :info')
- file.puts('log_location STDOUT')
+ file.puts("log_level :info")
+ file.puts("log_location STDOUT")
file.puts("chef_server_url '#{Chef::Config[:chef_server_url]}'")
file.puts("validation_client_name '#{Chef::Config[:validation_client_name]}'")
end
ui.info("Writing validation.pem")
- File.open(File.join(@config_dir, 'validation.pem'), "w") do |validation|
+ File.open(File.join(@config_dir, "validation.pem"), "w") do |validation|
validation.puts(IO.read(Chef::Config[:validation_key]))
end
end
diff --git a/lib/chef/knife/cookbook_bulk_delete.rb b/lib/chef/knife/cookbook_bulk_delete.rb
index 65fa888486..cdd1584e36 100644
--- a/lib/chef/knife/cookbook_bulk_delete.rb
+++ b/lib/chef/knife/cookbook_bulk_delete.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,18 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class CookbookBulkDelete < Knife
deps do
- require 'chef/knife/cookbook_delete'
- require 'chef/cookbook_version'
+ require "chef/knife/cookbook_delete"
+ require "chef/cookbook_version"
end
- option :purge, :short => '-p', :long => '--purge', :boolean => true, :description => 'Permanently remove files from backing data store'
+ option :purge, :short => "-p", :long => "--purge", :boolean => true, :description => "Permanently remove files from backing data store"
banner "knife cookbook bulk delete REGEX (options)"
@@ -42,7 +42,7 @@ class Chef
all_cookbooks = Chef::CookbookVersion.list
cookbooks_names = all_cookbooks.keys.grep(regex)
- cookbooks_to_delete = cookbooks_names.inject({}) { |hash, name| hash[name] = all_cookbooks[name];hash }
+ cookbooks_to_delete = cookbooks_names.inject({}) { |hash, name| hash[name] = all_cookbooks[name]; hash }
ui.msg "All versions of the following cookbooks will be deleted:"
ui.msg ""
ui.msg ui.list(cookbooks_to_delete.keys.sort, :columns_down)
@@ -58,11 +58,10 @@ class Chef
ui.msg ""
end
-
cookbooks_names.each do |cookbook_name|
- versions = rest.get_rest("cookbooks/#{cookbook_name}")[cookbook_name]["versions"].map {|v| v["version"]}.flatten
+ versions = rest.get("cookbooks/#{cookbook_name}")[cookbook_name]["versions"].map { |v| v["version"] }.flatten
versions.each do |version|
- object = rest.delete_rest("cookbooks/#{cookbook_name}/#{version}#{config[:purge] ? "?purge=true" : ""}")
+ rest.delete("cookbooks/#{cookbook_name}/#{version}#{config[:purge] ? "?purge=true" : ""}")
ui.info("Deleted cookbook #{cookbook_name.ljust(25)} [#{version}]")
end
end
diff --git a/lib/chef/knife/cookbook_create.rb b/lib/chef/knife/cookbook_create.rb
index 97f6e65d3c..ccb78bb7a6 100644
--- a/lib/chef/knife/cookbook_create.rb
+++ b/lib/chef/knife/cookbook_create.rb
@@ -1,6 +1,6 @@
#
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class CookbookCreate < Knife
deps do
- require 'chef/json_compat'
- require 'uri'
- require 'fileutils'
+ require "chef/json_compat"
+ require "uri"
+ require "fileutils"
end
banner "knife cookbook create COOKBOOK (options)"
@@ -56,6 +56,10 @@ class Chef
:description => "Email address of cookbook maintainer"
def run
+ Chef::Log.deprecation <<EOF
+This command is being deprecated in favor of `chef generate cookbook` and will soon return an error.
+Please use `chef generate cookbook` instead of this command.
+EOF
self.config = Chef::Config.merge!(config)
if @name_args.length < 1
show_usage
@@ -182,16 +186,14 @@ EOH
def create_changelog(dir, cookbook_name)
msg("** Creating CHANGELOG for cookbook: #{cookbook_name}")
- unless File.exists?(File.join(dir,cookbook_name,'CHANGELOG.md'))
- open(File.join(dir, cookbook_name, 'CHANGELOG.md'),'w') do |file|
+ unless File.exists?(File.join(dir, cookbook_name, "CHANGELOG.md"))
+ open(File.join(dir, cookbook_name, "CHANGELOG.md"), "w") do |file|
file.puts <<-EOH
-#{cookbook_name} CHANGELOG
-#{'='*"#{cookbook_name} CHANGELOG".length}
+# #{cookbook_name} CHANGELOG
This file is used to list changes made in each version of the #{cookbook_name} cookbook.
-0.1.0
------
+## 0.1.0
- [your_name] - Initial release of #{cookbook_name}
- - -
@@ -205,7 +207,7 @@ EOH
def create_readme(dir, cookbook_name, readme_format)
msg("** Creating README for cookbook: #{cookbook_name}")
- unless File.exists?(File.join(dir, cookbook_name, "README.#{readme_format}"))
+ unless File.exist?(File.join(dir, cookbook_name, "README.#{readme_format}"))
open(File.join(dir, cookbook_name, "README.#{readme_format}"), "w") do |file|
case readme_format
when "rdoc"
@@ -271,29 +273,39 @@ e.g.
== License and Authors
Authors: TODO: List authors
EOH
- when "md","mkd","txt"
+ when "md", "mkd", "txt"
file.puts <<-EOH
-#{cookbook_name} Cookbook
-#{'='*"#{cookbook_name} Cookbook".length}
+# #{cookbook_name} Cookbook
+
TODO: Enter the cookbook description here.
e.g.
This cookbook makes your favorite breakfast sandwich.
-Requirements
-------------
+## Requirements
+
TODO: List your cookbook requirements. Be sure to include any requirements this cookbook has on platforms, libraries, other cookbooks, packages, operating systems, etc.
e.g.
-#### packages
+### Platforms
+
+- SandwichOS
+
+### Chef
+
+- Chef 12.0 or later
+
+### Cookbooks
+
- `toaster` - #{cookbook_name} needs toaster to brown your bagel.
-Attributes
-----------
+## Attributes
+
TODO: List your cookbook attributes here.
e.g.
-#### #{cookbook_name}::default
+### #{cookbook_name}::default
+
<table>
<tr>
<th>Key</th>
@@ -309,9 +321,10 @@ e.g.
</tr>
</table>
-Usage
------
-#### #{cookbook_name}::default
+## Usage
+
+### #{cookbook_name}::default
+
TODO: Write usage instructions for each cookbook.
e.g.
@@ -326,8 +339,8 @@ Just include `#{cookbook_name}` in your node's `run_list`:
}
```
-Contributing
-------------
+## Contributing
+
TODO: (optional) If this is a public cookbook, detail the process for contributing. If this is a private cookbook, remove this section.
e.g.
@@ -338,14 +351,15 @@ e.g.
5. Run the tests, ensuring they all pass
6. Submit a Pull Request using Github
-License and Authors
--------------------
+## License and Authors
+
Authors: TODO: List authors
+
EOH
else
file.puts <<-EOH
#{cookbook_name} Cookbook
-#{'='*"#{cookbook_name} Cookbook".length}
+#{'=' * "#{cookbook_name} Cookbook".length}
TODO: Enter the cookbook description here.
e.g.
@@ -415,9 +429,9 @@ EOH
"All rights reserved"
end
- unless File.exists?(File.join(dir, cookbook_name, "metadata.rb"))
+ unless File.exist?(File.join(dir, cookbook_name, "metadata.rb"))
open(File.join(dir, cookbook_name, "metadata.rb"), "w") do |file|
- if File.exists?(File.join(dir, cookbook_name, "README.#{readme_format}"))
+ if File.exist?(File.join(dir, cookbook_name, "README.#{readme_format}"))
long_description = "long_description IO.read(File.join(File.dirname(__FILE__), 'README.#{readme_format}'))"
end
file.puts <<-EOH
diff --git a/lib/chef/knife/cookbook_delete.rb b/lib/chef/knife/cookbook_delete.rb
index f436d270bd..b1bb88b388 100644
--- a/lib/chef/knife/cookbook_delete.rb
+++ b/lib/chef/knife/cookbook_delete.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -25,12 +25,12 @@ class Chef
attr_accessor :cookbook_name, :version
deps do
- require 'chef/cookbook_version'
+ require "chef/cookbook_version"
end
- option :all, :short => '-a', :long => '--all', :boolean => true, :description => 'delete all versions'
+ option :all, :short => "-a", :long => "--all", :boolean => true, :description => "delete all versions"
- option :purge, :short => '-p', :long => '--purge', :boolean => true, :description => 'Permanently remove files from backing data store'
+ option :purge, :short => "-p", :long => "--purge", :boolean => true, :description => "Permanently remove files from backing data store"
banner "knife cookbook delete COOKBOOK VERSION (options)"
@@ -85,8 +85,8 @@ class Chef
end
def available_versions
- @available_versions ||= rest.get_rest("cookbooks/#{@cookbook_name}").map do |name, url_and_version|
- url_and_version["versions"].map {|url_by_version| url_by_version["version"]}
+ @available_versions ||= rest.get("cookbooks/#{@cookbook_name}").map do |name, url_and_version|
+ url_and_version["versions"].map { |url_by_version| url_by_version["version"] }
end.flatten
rescue Net::HTTPServerException => e
if e.to_s =~ /^404/
@@ -106,7 +106,7 @@ class Chef
end
valid_responses[(available_versions.size + 1).to_s] = :all
question << "#{available_versions.size + 1}. All versions\n\n"
- responses = ask_question(question).split(',').map { |response| response.strip }
+ responses = ask_question(question).split(",").map { |response| response.strip }
if responses.empty?
ui.error("No versions specified, exiting")
@@ -143,7 +143,7 @@ class Chef
def delete_request(path)
path += "?purge=true" if config[:purge]
- rest.delete_rest(path)
+ rest.delete(path)
end
end
diff --git a/lib/chef/knife/cookbook_download.rb b/lib/chef/knife/cookbook_download.rb
index cb8eeb8edf..741f444093 100644
--- a/lib/chef/knife/cookbook_download.rb
+++ b/lib/chef/knife/cookbook_download.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -27,7 +27,7 @@ class Chef
attr_accessor :cookbook_name
deps do
- require 'chef/cookbook_version'
+ require "chef/cookbook_version"
end
banner "knife cookbook download COOKBOOK [VERSION] (options)"
@@ -69,7 +69,7 @@ class Chef
ui.info("Downloading #{@cookbook_name} cookbook version #{@version}")
- cookbook = rest.get_rest("cookbooks/#{@cookbook_name}/#{@version}")
+ cookbook = Chef::CookbookVersion.load(@cookbook_name, @version)
manifest = cookbook.manifest
basedir = File.join(config[:download_directory], "#{@cookbook_name}-#{cookbook.version}")
@@ -87,11 +87,10 @@ class Chef
next unless manifest.has_key?(segment)
ui.info("Downloading #{segment}")
manifest[segment].each do |segment_file|
- dest = File.join(basedir, segment_file['path'].gsub('/', File::SEPARATOR))
+ dest = File.join(basedir, segment_file["path"].gsub("/", File::SEPARATOR))
Chef::Log.debug("Downloading #{segment_file['path']} to #{dest}")
FileUtils.mkdir_p(File.dirname(dest))
- rest.sign_on_redirect = false
- tempfile = rest.get_rest(segment_file['url'], true)
+ tempfile = rest.streaming_request(segment_file["url"])
FileUtils.mv(tempfile.path, dest)
end
end
@@ -99,7 +98,6 @@ class Chef
end
def determine_version
-
if available_versions.nil?
nil
elsif available_versions.size == 1
diff --git a/lib/chef/knife/cookbook_list.rb b/lib/chef/knife/cookbook_list.rb
index 75f18a154b..ea81f5d286 100644
--- a/lib/chef/knife/cookbook_list.rb
+++ b/lib/chef/knife/cookbook_list.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -39,7 +39,7 @@ class Chef
env = config[:environment]
num_versions = config[:all_versions] ? "num_versions=all" : "num_versions=1"
api_endpoint = env ? "/environments/#{env}/cookbooks?#{num_versions}" : "/cookbooks?#{num_versions}"
- cookbook_versions = rest.get_rest(api_endpoint)
+ cookbook_versions = rest.get(api_endpoint)
ui.output(format_cookbook_list_for_display(cookbook_versions))
end
end
diff --git a/lib/chef/knife/cookbook_metadata.rb b/lib/chef/knife/cookbook_metadata.rb
index dfa69ae39f..29eba6a36a 100644
--- a/lib/chef/knife/cookbook_metadata.rb
+++ b/lib/chef/knife/cookbook_metadata.rb
@@ -1,7 +1,7 @@
#
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class CookbookMetadata < Knife
deps do
- require 'chef/cookbook_loader'
- require 'chef/cookbook/metadata'
+ require "chef/cookbook_loader"
+ require "chef/cookbook/metadata"
end
banner "knife cookbook metadata COOKBOOK (options)"
@@ -61,8 +61,8 @@ class Chef
end
def generate_metadata(cookbook)
- Array(config[:cookbook_path]).reverse.each do |path|
- file = File.expand_path(File.join(path, cookbook, 'metadata.rb'))
+ Array(config[:cookbook_path]).reverse_each do |path|
+ file = File.expand_path(File.join(path, cookbook, "metadata.rb"))
if File.exists?(file)
generate_metadata_from_file(cookbook, file)
else
@@ -76,11 +76,10 @@ class Chef
md = Chef::Cookbook::Metadata.new
md.name(cookbook)
md.from_file(file)
- json_file = File.join(File.dirname(file), 'metadata.json')
+ json_file = File.join(File.dirname(file), "metadata.json")
File.open(json_file, "w") do |f|
f.write(Chef::JSONCompat.to_json_pretty(md))
end
- generated = true
Chef::Log.debug("Generated #{json_file}")
rescue Exceptions::ObsoleteDependencySyntax, Exceptions::InvalidVersionConstraint => e
ui.stderr.puts "ERROR: The cookbook '#{cookbook}' contains invalid or obsolete metadata syntax."
@@ -91,7 +90,7 @@ class Chef
end
def validate_metadata_json(path, cookbook)
- json_file = File.join(path, cookbook, 'metadata.json')
+ json_file = File.join(path, cookbook, "metadata.json")
if File.exist?(json_file)
Chef::Cookbook::Metadata.validate_json(IO.read(json_file))
end
diff --git a/lib/chef/knife/cookbook_metadata_from_file.rb b/lib/chef/knife/cookbook_metadata_from_file.rb
index 8e26251d6e..ec46379da7 100644
--- a/lib/chef/knife/cookbook_metadata_from_file.rb
+++ b/lib/chef/knife/cookbook_metadata_from_file.rb
@@ -1,9 +1,9 @@
#
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Matthew Kent (<mkent@magoazul.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2010 Matthew Kent
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2010-2016, Matthew Kent
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,14 +19,14 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class CookbookMetadataFromFile < Knife
deps do
- require 'chef/cookbook/metadata'
+ require "chef/cookbook/metadata"
end
banner "knife cookbook metadata from FILE (options)"
diff --git a/lib/chef/knife/cookbook_show.rb b/lib/chef/knife/cookbook_show.rb
index 7c9cbebdb1..d0c930de0a 100644
--- a/lib/chef/knife/cookbook_show.rb
+++ b/lib/chef/knife/cookbook_show.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class CookbookShow < Knife
deps do
- require 'chef/json_compat'
- require 'uri'
- require 'chef/cookbook_version'
+ require "chef/json_compat"
+ require "uri"
+ require "chef/cookbook_version"
end
banner "knife cookbook show COOKBOOK [VERSION] [PART] [FILENAME] (options)"
@@ -51,6 +51,10 @@ class Chef
:description => "Show corresponding URIs"
def run
+ cookbook_name, cookbook_version, segment, filename = @name_args
+
+ cookbook = Chef::CookbookVersion.load(cookbook_name, cookbook_version) unless cookbook_version.nil?
+
case @name_args.length
when 4 # We are showing a specific file
node = Hash.new
@@ -59,34 +63,26 @@ class Chef
node[:platform_version] = config[:platform_version] if config.has_key?(:platform_version)
class << node
- def attribute?(name)
+ def attribute?(name) # rubocop:disable Lint/NestedMethodDefinition
has_key?(name)
end
end
- cookbook_name, segment, filename = @name_args[0], @name_args[2], @name_args[3]
- cookbook_version = @name_args[1] == 'latest' ? '_latest' : @name_args[1]
-
- cookbook = rest.get_rest("cookbooks/#{cookbook_name}/#{cookbook_version}")
manifest_entry = cookbook.preferred_manifest_record(node, segment, filename)
- temp_file = rest.get_rest(manifest_entry[:url], true)
+ temp_file = rest.streaming_request(manifest_entry[:url])
# the temp file is cleaned up elsewhere
temp_file.open if temp_file.closed?
pretty_print(temp_file.read)
when 3 # We are showing a specific part of the cookbook
- cookbook_version = @name_args[1] == 'latest' ? '_latest' : @name_args[1]
- result = rest.get_rest("cookbooks/#{@name_args[0]}/#{cookbook_version}")
- output(result.manifest[@name_args[2]])
+ output(cookbook.manifest[segment])
when 2 # We are showing the whole cookbook data
- cookbook_version = @name_args[1] == 'latest' ? '_latest' : @name_args[1]
- output(rest.get_rest("cookbooks/#{@name_args[0]}/#{cookbook_version}"))
+ output(cookbook)
when 1 # We are showing the cookbook versions (all of them)
- cookbook_name = @name_args[0]
env = config[:environment]
api_endpoint = env ? "environments/#{env}/cookbooks/#{cookbook_name}" : "cookbooks/#{cookbook_name}"
- output(format_cookbook_list_for_display(rest.get_rest(api_endpoint)))
+ output(format_cookbook_list_for_display(rest.get(api_endpoint)))
when 0
show_usage
ui.fatal("You must specify a cookbook name")
@@ -96,7 +92,3 @@ class Chef
end
end
end
-
-
-
-
diff --git a/lib/chef/knife/cookbook_site_download.rb b/lib/chef/knife/cookbook_site_download.rb
index 3e586e6542..43677cfa78 100644
--- a/lib/chef/knife/cookbook_site_download.rb
+++ b/lib/chef/knife/cookbook_site_download.rb
@@ -1,5 +1,5 @@
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,14 +15,14 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class CookbookSiteDownload < Knife
deps do
- require 'fileutils'
+ require "fileutils"
end
banner "knife cookbook site download COOKBOOK [VERSION] (options)"
@@ -37,14 +37,21 @@ class Chef
:long => "--force",
:description => "Force download deprecated version"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
if current_cookbook_deprecated?
- message = 'DEPRECATION: This cookbook has been deprecated. '
+ message = "DEPRECATION: This cookbook has been deprecated. "
message << "It has been replaced by #{replacement_cookbook}."
ui.warn message
unless config[:force]
- ui.warn 'Use --force to force download deprecated cookbook.'
+ ui.warn "Use --force to force download deprecated cookbook."
return
end
end
@@ -53,40 +60,40 @@ class Chef
end
def version
- @version = desired_cookbook_data['version']
+ @version = desired_cookbook_data["version"]
end
private
+
def cookbooks_api_url
- 'https://supermarket.chef.io/api/v1/cookbooks'
+ "#{config[:supermarket_site]}/api/v1/cookbooks"
end
def current_cookbook_data
@current_cookbook_data ||= begin
- noauth_rest.get_rest "#{cookbooks_api_url}/#{@name_args[0]}"
- end
+ noauth_rest.get "#{cookbooks_api_url}/#{@name_args[0]}"
+ end
end
def current_cookbook_deprecated?
- current_cookbook_data['deprecated'] == true
+ current_cookbook_data["deprecated"] == true
end
def desired_cookbook_data
@desired_cookbook_data ||= begin
- uri = if @name_args.length == 1
- current_cookbook_data['latest_version']
- else
- specific_cookbook_version_url
- end
-
- noauth_rest.get_rest uri
- end
+ uri = if @name_args.length == 1
+ current_cookbook_data["latest_version"]
+ else
+ specific_cookbook_version_url
+ end
+
+ noauth_rest.get uri
+ end
end
def download_cookbook
ui.info "Downloading #{@name_args[0]} from Supermarket at version #{version} to #{download_location}"
- noauth_rest.sign_on_redirect = false
- tf = noauth_rest.get_rest desired_cookbook_data["file"], true
+ tf = noauth_rest.streaming_request(desired_cookbook_data["file"])
::FileUtils.cp tf.path, download_location
ui.info "Cookbook saved: #{download_location}"
@@ -98,11 +105,11 @@ class Chef
end
def replacement_cookbook
- replacement = File.basename(current_cookbook_data['replacement'])
+ File.basename(current_cookbook_data["replacement"])
end
def specific_cookbook_version_url
- "#{cookbooks_api_url}/#{@name_args[0]}/versions/#{@name_args[1].gsub('.', '_')}"
+ "#{cookbooks_api_url}/#{@name_args[0]}/versions/#{@name_args[1].tr('.', '_')}"
end
end
end
diff --git a/lib/chef/knife/cookbook_site_install.rb b/lib/chef/knife/cookbook_site_install.rb
index cc68fe7897..72fb426554 100644
--- a/lib/chef/knife/cookbook_site_install.rb
+++ b/lib/chef/knife/cookbook_site_install.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,19 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/exceptions'
-require 'shellwords'
+require "chef/knife"
+require "chef/exceptions"
+require "shellwords"
+require "mixlib/archive"
class Chef
class Knife
class CookbookSiteInstall < Knife
deps do
- require 'chef/mixin/shell_out'
- require 'chef/knife/core/cookbook_scm_repo'
- require 'chef/cookbook/metadata'
+ require "chef/mixin/shell_out"
+ require "chef/knife/core/cookbook_scm_repo"
+ require "chef/cookbook/metadata"
end
banner "knife cookbook site install COOKBOOK [VERSION] (options)"
@@ -53,12 +54,19 @@ class Chef
:default => "master"
option :use_current_branch,
- :short => "-b",
+ :short => "-b",
:long => "--use-current-branch",
:description => "Use the current branch",
:boolean => true,
:default => false
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
attr_reader :cookbook_name
attr_reader :vendor_path
@@ -75,7 +83,7 @@ class Chef
# Check to ensure we have a valid source of cookbooks before continuing
#
@install_path = File.expand_path(Array(config[:cookbook_path]).first)
- ui.info "Installing #@cookbook_name to #{@install_path}"
+ ui.info "Installing #{@cookbook_name} to #{@install_path}"
@repo = CookbookSCMRepo.new(@install_path, ui, config)
#cookbook_path = File.join(vendor_path, name_args[0])
@@ -123,7 +131,7 @@ class Chef
ui.error("Please specify a cookbook to download and install.")
exit 1
elsif name_args.size >= 2
- unless name_args.last.match(/^(\d+)(\.\d+){1,2}$/) and name_args.size == 2
+ unless name_args.last.match(/^(\d+)(\.\d+){1,2}$/) && name_args.size == 2
ui.error("Installing multiple cookbooks at once is not supported.")
exit 1
end
@@ -134,6 +142,7 @@ class Chef
def download_cookbook_to(download_path)
downloader = Chef::Knife::CookbookSiteDownload.new
downloader.config[:file] = download_path
+ downloader.config[:supermarket_site] = config[:supermarket_site]
downloader.name_args = name_args
downloader.run
downloader
@@ -141,12 +150,7 @@ class Chef
def extract_cookbook(upstream_file, version)
ui.info("Uncompressing #{@cookbook_name} version #{version}.")
- # FIXME: Detect if we have the bad tar from git on Windows: https://github.com/opscode/chef/issues/1753
- extract_command="tar zxvf \"#{convert_path upstream_file}\""
- if Chef::Platform.windows?
- extract_command << " --force-local"
- end
- shell_out!(extract_command, :cwd => @install_path)
+ Mixlib::Archive.new(convert_path(upstream_file)).extract(@install_path, perms: false)
end
def clear_existing_files(cookbook_path)
@@ -156,10 +160,10 @@ class Chef
def convert_path(upstream_file)
# converts a Windows path (C:\foo) to a mingw path (/c/foo)
- if ENV['MSYSTEM'] == 'MINGW32'
- return upstream_file.sub(/^([[:alpha:]]):/, '/\1')
+ if ENV["MSYSTEM"] == "MINGW32"
+ upstream_file.sub(/^([[:alpha:]]):/, '/\1')
else
- return Shellwords.escape upstream_file
+ Shellwords.escape upstream_file
end
end
@@ -172,7 +176,7 @@ class Chef
def preferred_metadata
md = Chef::Cookbook::Metadata.new
- rb = File.join(@install_path, @cookbook_name, "metadata.rb")
+ rb = File.join(@install_path, @cookbook_name, "metadata.rb")
if File.exist?(rb)
md.from_file(rb)
return md
diff --git a/lib/chef/knife/cookbook_site_list.rb b/lib/chef/knife/cookbook_site_list.rb
index 846123c867..3bdef8abe5 100644
--- a/lib/chef/knife/cookbook_site_list.rb
+++ b/lib/chef/knife/cookbook_site_list.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -30,19 +30,26 @@ class Chef
:long => "--with-uri",
:description => "Show corresponding URIs"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
if config[:with_uri]
cookbooks = Hash.new
- get_cookbook_list.each{ |k,v| cookbooks[k] = v['cookbook'] }
+ get_cookbook_list.each { |k, v| cookbooks[k] = v["cookbook"] }
ui.output(format_for_display(cookbooks))
else
ui.msg(ui.list(get_cookbook_list.keys.sort, :columns_down))
end
end
- def get_cookbook_list(items=10, start=0, cookbook_collection={})
- cookbooks_url = "https://supermarket.chef.io/api/v1/cookbooks?items=#{items}&start=#{start}"
- cr = noauth_rest.get_rest(cookbooks_url)
+ def get_cookbook_list(items = 10, start = 0, cookbook_collection = {})
+ cookbooks_url = "#{config[:supermarket_site]}/api/v1/cookbooks?items=#{items}&start=#{start}"
+ cr = noauth_rest.get(cookbooks_url)
cr["items"].each do |cookbook|
cookbook_collection[cookbook["cookbook_name"]] = cookbook
end
@@ -56,7 +63,3 @@ class Chef
end
end
end
-
-
-
-
diff --git a/lib/chef/knife/cookbook_site_search.rb b/lib/chef/knife/cookbook_site_search.rb
index 0baaf90f1c..d401844217 100644
--- a/lib/chef/knife/cookbook_site_search.rb
+++ b/lib/chef/knife/cookbook_site_search.rb
@@ -1,5 +1,5 @@
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -24,13 +24,20 @@ class Chef
banner "knife cookbook site search QUERY (options)"
category "cookbook site"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
output(search_cookbook(name_args[0]))
end
- def search_cookbook(query, items=10, start=0, cookbook_collection={})
- cookbooks_url = "https://supermarket.chef.io/api/v1/search?q=#{query}&items=#{items}&start=#{start}"
- cr = noauth_rest.get_rest(cookbooks_url)
+ def search_cookbook(query, items = 10, start = 0, cookbook_collection = {})
+ cookbooks_url = "#{config[:supermarket_site]}/api/v1/search?q=#{query}&items=#{items}&start=#{start}"
+ cr = noauth_rest.get(cookbooks_url)
cr["items"].each do |cookbook|
cookbook_collection[cookbook["cookbook_name"]] = cookbook
end
@@ -44,8 +51,3 @@ class Chef
end
end
end
-
-
-
-
-
diff --git a/lib/chef/knife/cookbook_site_share.rb b/lib/chef/knife/cookbook_site_share.rb
index beb98b71b8..d55d6c123a 100644
--- a/lib/chef/knife/cookbook_site_share.rb
+++ b/lib/chef/knife/cookbook_site_share.rb
@@ -1,6 +1,6 @@
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/mixin/shell_out'
+require "chef/knife"
+require "chef/mixin/shell_out"
class Chef
class Knife
@@ -26,10 +26,10 @@ class Chef
include Chef::Mixin::ShellOut
deps do
- require 'chef/cookbook_loader'
- require 'chef/cookbook_uploader'
- require 'chef/cookbook_site_streaming_uploader'
- require 'mixlib/shellout'
+ require "chef/cookbook_loader"
+ require "chef/cookbook_uploader"
+ require "chef/cookbook_site_streaming_uploader"
+ require "mixlib/shellout"
end
include Chef::Mixin::ShellOut
@@ -44,12 +44,19 @@ class Chef
:proc => lambda { |o| Chef::Config.cookbook_path = o.split(":") }
option :dry_run,
- :long => '--dry-run',
- :short => '-n',
+ :long => "--dry-run",
+ :short => "-n",
:boolean => true,
:default => false,
:description => "Don't take action, only print what files will be uploaded to Supermarket."
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
config[:cookbook_path] ||= Chef::Config[:cookbook_path]
@@ -90,7 +97,7 @@ class Chef
begin
do_upload("#{tmp_cookbook_dir}/#{cookbook_name}.tgz", category, Chef::Config[:node_name], Chef::Config[:client_key])
- ui.info("Upload complete!")
+ ui.info("Upload complete")
Chef::Log.debug("Removing local staging directory at #{tmp_cookbook_dir}")
FileUtils.rm_rf tmp_cookbook_dir
rescue => e
@@ -103,39 +110,32 @@ class Chef
ui.error("Could not find cookbook #{cookbook_name} in your cookbook path.")
exit(1)
end
-
end
def get_category(cookbook_name)
- begin
- data = noauth_rest.get_rest("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}")
- if !data["category"] && data["error_code"]
- ui.fatal("Received an error from Supermarket: #{data["error_code"]}. On the first time you upload it, you are required to specify the category you want to share this cookbook to.")
- exit(1)
- else
- data['category']
- end
- rescue => e
- ui.fatal("Unable to reach Supermarket: #{e.message}. Increase log verbosity (-VV) for more information.")
- Chef::Log.debug("\n#{e.backtrace.join("\n")}")
- exit(1)
- end
+ data = noauth_rest.get("#{config[:supermarket_site]}/api/v1/cookbooks/#{@name_args[0]}")
+ data["category"]
+ rescue => e
+ return "Other" if e.kind_of?(Net::HTTPServerException) && e.response.code == "404"
+ ui.fatal("Unable to reach Supermarket: #{e.message}. Increase log verbosity (-VV) for more information.")
+ Chef::Log.debug("\n#{e.backtrace.join("\n")}")
+ exit(1)
end
def do_upload(cookbook_filename, cookbook_category, user_id, user_secret_filename)
- uri = "https://supermarket.chef.io/api/v1/cookbooks"
+ uri = "#{config[:supermarket_site]}/api/v1/cookbooks"
- category_string = Chef::JSONCompat.to_json({ 'category'=>cookbook_category })
+ category_string = Chef::JSONCompat.to_json({ "category" => cookbook_category })
http_resp = Chef::CookbookSiteStreamingUploader.post(uri, user_id, user_secret_filename, {
:tarball => File.open(cookbook_filename),
- :cookbook => category_string
+ :cookbook => category_string,
})
res = Chef::JSONCompat.from_json(http_resp.body)
if http_resp.code.to_i != 201
- if res['error_messages']
- if res['error_messages'][0] =~ /Version already exists/
+ if res["error_messages"]
+ if res["error_messages"][0] =~ /Version already exists/
ui.error "The same version of this cookbook already exists on Supermarket."
exit(1)
else
diff --git a/lib/chef/knife/cookbook_site_show.rb b/lib/chef/knife/cookbook_site_show.rb
index 6b65b62570..ce153ca5a1 100644
--- a/lib/chef/knife/cookbook_site_show.rb
+++ b/lib/chef/knife/cookbook_site_show.rb
@@ -1,5 +1,5 @@
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -24,22 +24,33 @@ class Chef
banner "knife cookbook site show COOKBOOK [VERSION] (options)"
category "cookbook site"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
output(format_for_display(get_cookbook_data))
end
+ def supermarket_uri
+ "#{config[:supermarket_site]}/api/v1"
+ end
+
def get_cookbook_data
case @name_args.length
when 1
- noauth_rest.get_rest("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}")
+ noauth_rest.get("#{supermarket_uri}/cookbooks/#{@name_args[0]}")
when 2
- noauth_rest.get_rest("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}/versions/#{name_args[1].gsub('.', '_')}")
+ noauth_rest.get("#{supermarket_uri}/cookbooks/#{@name_args[0]}/versions/#{name_args[1].tr('.', '_')}")
end
end
- def get_cookbook_list(items=10, start=0, cookbook_collection={})
- cookbooks_url = "https://supermarket.chef.io/api/v1/cookbooks?items=#{items}&start=#{start}"
- cr = noauth_rest.get_rest(cookbooks_url)
+ def get_cookbook_list(items = 10, start = 0, cookbook_collection = {})
+ cookbooks_url = "#{supermarket_uri}/cookbooks?items=#{items}&start=#{start}"
+ cr = noauth_rest.get(cookbooks_url)
cr["items"].each do |cookbook|
cookbook_collection[cookbook["cookbook_name"]] = cookbook
end
@@ -53,8 +64,3 @@ class Chef
end
end
end
-
-
-
-
-
diff --git a/lib/chef/knife/cookbook_site_unshare.rb b/lib/chef/knife/cookbook_site_unshare.rb
index 77bb18322c..bdabff0b94 100644
--- a/lib/chef/knife/cookbook_site_unshare.rb
+++ b/lib/chef/knife/cookbook_site_unshare.rb
@@ -1,7 +1,7 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,19 +17,26 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class CookbookSiteUnshare < Knife
deps do
- require 'chef/json_compat'
+ require "chef/json_compat"
end
banner "knife cookbook site unshare COOKBOOK"
category "cookbook site"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
@cookbook_name = @name_args[0]
if @cookbook_name.nil?
@@ -41,7 +48,7 @@ class Chef
confirm "Do you really want to unshare all versions of the cookbook #{@cookbook_name}"
begin
- rest.delete_rest "https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}"
+ rest.delete "#{config[:supermarket_site]}/api/v1/cookbooks/#{@name_args[0]}"
rescue Net::HTTPServerException => e
raise e unless e.message =~ /Forbidden/
ui.error "Forbidden: You must be the maintainer of #{@cookbook_name} to unshare it."
diff --git a/lib/chef/knife/cookbook_site_vendor.rb b/lib/chef/knife/cookbook_site_vendor.rb
index 82575958bd..291715cc0b 100644
--- a/lib/chef/knife/cookbook_site_vendor.rb
+++ b/lib/chef/knife/cookbook_site_vendor.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/cookbook_site_install'
+require "chef/knife"
+require "chef/knife/cookbook_site_install"
class Chef::Knife::CookbookSiteVendor < Chef::Knife::CookbookSiteInstall
@@ -41,6 +41,6 @@ DEPRECATED: please use knife cookbook site install
#{superclass.banner}
B
- category 'deprecated'
+ category "deprecated"
end
diff --git a/lib/chef/knife/cookbook_test.rb b/lib/chef/knife/cookbook_test.rb
index 91e0b55c47..1a5c9df74e 100644
--- a/lib/chef/knife/cookbook_test.rb
+++ b/lib/chef/knife/cookbook_test.rb
@@ -1,9 +1,9 @@
#
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Matthew Kent (<mkent@magoazul.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2010 Matthew Kent
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2010-2016, Matthew Kent
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,15 +18,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class CookbookTest < Knife
deps do
- require 'chef/cookbook_loader'
- require 'chef/cookbook/syntax_check'
+ require "chef/cookbook_loader"
+ require "chef/cookbook/syntax_check"
end
banner "knife cookbook test [COOKBOOKS...] (options)"
@@ -69,14 +69,13 @@ class Chef
def test_cookbook(cookbook)
ui.info("Running syntax check on #{cookbook}")
- Array(config[:cookbook_path]).reverse.each do |path|
+ Array(config[:cookbook_path]).reverse_each do |path|
syntax_checker = Chef::Cookbook::SyntaxCheck.for_cookbook(cookbook, path)
test_ruby(syntax_checker)
test_templates(syntax_checker)
end
end
-
def test_ruby(syntax_checker)
ui.info("Validating ruby files")
exit(1) unless syntax_checker.validate_ruby_files
diff --git a/lib/chef/knife/cookbook_upload.rb b/lib/chef/knife/cookbook_upload.rb
index b2acd74b4b..6938ac280d 100644
--- a/lib/chef/knife/cookbook_upload.rb
+++ b/lib/chef/knife/cookbook_upload.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
# Author:: Nuo Yan (<yan.nuo@gmail.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/cookbook_uploader'
+require "chef/knife"
+require "chef/cookbook_uploader"
class Chef
class Knife
@@ -29,9 +29,9 @@ class Chef
MATCH_CHECKSUM = /[0-9a-f]{32,}/
deps do
- require 'chef/exceptions'
- require 'chef/cookbook_loader'
- require 'chef/cookbook_uploader'
+ require "chef/exceptions"
+ require "chef/cookbook_loader"
+ require "chef/cookbook_uploader"
end
banner "knife cookbook upload [COOKBOOKS...] (options)"
@@ -43,8 +43,8 @@ class Chef
:proc => lambda { |o| o.split(":") }
option :freeze,
- :long => '--freeze',
- :description => 'Freeze this version of the cookbook so that it cannot be overwritten',
+ :long => "--freeze",
+ :description => "Freeze this version of the cookbook so that it cannot be overwritten",
:boolean => true
option :all,
@@ -53,19 +53,19 @@ class Chef
:description => "Upload all cookbooks, rather than just a single cookbook"
option :force,
- :long => '--force',
+ :long => "--force",
:boolean => true,
:description => "Update cookbook versions even if they have been frozen"
option :concurrency,
- :long => '--concurrency NUMBER_OF_THREADS',
+ :long => "--concurrency NUMBER_OF_THREADS",
:description => "How many concurrent threads will be used",
:default => 10,
:proc => lambda { |o| o.to_i }
option :environment,
- :short => '-E',
- :long => '--environment ENVIRONMENT',
+ :short => "-E",
+ :long => "--environment ENVIRONMENT",
:description => "Set ENVIRONMENT's version dependency match the version you're uploading.",
:default => nil
@@ -86,7 +86,7 @@ class Chef
config[:cookbook_path] ||= Chef::Config[:cookbook_path]
- if @name_args.empty? and ! config[:all]
+ if @name_args.empty? && ! config[:all]
show_usage
ui.fatal("You must specify the --all flag or at least one cookbook name")
exit 1
@@ -101,9 +101,9 @@ class Chef
# Get a list of cookbooks and their versions from the server
# to check for the existence of a cookbook's dependencies.
@server_side_cookbooks = Chef::CookbookVersion.list_all_versions
- justify_width = @server_side_cookbooks.map {|name| name.size}.max.to_i + 2
+ justify_width = @server_side_cookbooks.map { |name| name.size }.max.to_i + 2
if config[:all]
- cookbook_repo.load_cookbooks
+ cookbook_repo.load_cookbooks_without_shadow_warning
cookbooks_for_upload = []
cookbook_repo.each do |cookbook_name, cookbook|
cookbooks_for_upload << cookbook
@@ -118,7 +118,7 @@ class Chef
end
ui.info("Uploaded all cookbooks.")
else
- cookbook_path = config[:cookbook_path].respond_to?(:join) ? config[:cookbook_path].join(', ') : config[:cookbook_path]
+ cookbook_path = config[:cookbook_path].respond_to?(:join) ? config[:cookbook_path].join(", ") : config[:cookbook_path]
ui.warn("Could not find any cookbooks in your cookbook path: #{cookbook_path}. Use --cookbook-path to specify the desired path.")
end
else
@@ -145,9 +145,6 @@ class Chef
end
end
-
- upload_failures += @name_args.length - @cookbooks_to_upload.length
-
if upload_failures == 0
ui.info "Uploaded #{upload_ok} cookbook#{upload_ok > 1 ? "s" : ""}."
elsif upload_failures > 0 && upload_ok > 0
@@ -167,7 +164,7 @@ class Chef
def cookbooks_to_upload
@cookbooks_to_upload ||=
if config[:all]
- cookbook_repo.load_cookbooks
+ cookbook_repo.load_cookbooks_without_shadow_warning
else
upload_set = {}
@name_args.each do |cookbook_name|
@@ -259,7 +256,7 @@ WARNING
info[CHECKSUM].nil? || info[CHECKSUM] !~ MATCH_CHECKSUM
end
unless broken_files.empty?
- broken_filenames = Array(broken_files).map {|path, info| path}
+ broken_filenames = Array(broken_files).map { |path, info| path }
ui.error "The cookbook #{cookbook.name} has one or more broken files"
ui.error "This is probably caused by broken symlinks in the cookbook directory"
ui.error "The broken file(s) are: #{broken_filenames.join(' ')}"
@@ -275,7 +272,7 @@ WARNING
end
unless missing_dependencies.empty?
- missing_cookbook_names = missing_dependencies.map { |cookbook_name, version| "'#{cookbook_name}' version '#{version}'"}
+ missing_cookbook_names = missing_dependencies.map { |cookbook_name, version| "'#{cookbook_name}' version '#{version}'" }
ui.error "Cookbook #{cookbook.name} depends on cookbooks which are not currently"
ui.error "being uploaded and cannot be found on the server."
ui.error "The missing cookbook(s) are: #{missing_cookbook_names.join(', ')}"
@@ -287,7 +284,7 @@ WARNING
if @server_side_cookbooks[cookbook_name].nil?
false
else
- versions = @server_side_cookbooks[cookbook_name]['versions'].collect {|versions| versions["version"]}
+ versions = @server_side_cookbooks[cookbook_name]["versions"].collect { |versions| versions["version"] }
Log.debug "Versions of cookbook '#{cookbook_name}' returned by the server: #{versions.join(", ")}"
@server_side_cookbooks[cookbook_name]["versions"].each do |versions_hash|
if Chef::VersionConstraint.new(version).include?(versions_hash["version"])
diff --git a/lib/chef/knife/core/bootstrap_context.rb b/lib/chef/knife/core/bootstrap_context.rb
index 8613a50cb4..c395ebcfa0 100644
--- a/lib/chef/knife/core/bootstrap_context.rb
+++ b/lib/chef/knife/core/bootstrap_context.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,9 @@
# limitations under the License.
#
-require 'chef/run_list'
-require 'chef/util/path_helper'
+require "chef/run_list"
+require "chef/util/path_helper"
+require "pathname"
class Chef
class Knife
@@ -44,13 +45,18 @@ class Chef
end
def validation_key
- if File.exist?(File.expand_path(@chef_config[:validation_key]))
+ if @chef_config.has_key?(:validation_key) &&
+ File.exist?(File.expand_path(@chef_config[:validation_key]))
IO.read(File.expand_path(@chef_config[:validation_key]))
else
false
end
end
+ def client_d
+ @client_d ||= client_d_content
+ end
+
def encrypted_data_bag_secret
@secret
end
@@ -61,12 +67,36 @@ class Chef
@trusted_certs ||= trusted_certs_content
end
+ def get_log_location
+ if !(@chef_config[:config_log_location].class == IO ) && (@chef_config[:config_log_location].nil? || @chef_config[:config_log_location].to_s.empty?)
+ "STDOUT"
+ elsif @chef_config[:config_log_location].equal?(:win_evt)
+ raise "The value :win_evt is not supported for config_log_location on Linux Platforms \n"
+ elsif @chef_config[:config_log_location].equal?(:syslog)
+ ":syslog"
+ elsif @chef_config[:config_log_location].equal?(STDOUT)
+ "STDOUT"
+ elsif @chef_config[:config_log_location].equal?(STDERR)
+ "STDERR"
+ elsif @chef_config[:config_log_location]
+ %Q{"#{@chef_config[:config_log_location]}"}
+ else
+ "STDOUT"
+ end
+ end
+
def config_content
client_rb = <<-CONFIG
-log_location STDOUT
chef_server_url "#{@chef_config[:chef_server_url]}"
validation_client_name "#{@chef_config[:validation_client_name]}"
-CONFIG
+ CONFIG
+
+ if !(@chef_config[:config_log_level].nil? || @chef_config[:config_log_level].empty?)
+ client_rb << %Q{log_level :#{@chef_config[:config_log_level]}\n}
+ end
+
+ client_rb << "log_location #{get_log_location}\n"
+
if @config[:chef_node_name]
client_rb << %Q{node_name "#{@config[:chef_node_name]}"\n}
else
@@ -84,15 +114,15 @@ CONFIG
# or when specified in the knife config.
if @config[:node_ssl_verify_mode] || knife_config.has_key?(:ssl_verify_mode)
value = case @config[:node_ssl_verify_mode]
- when "peer"
- :verify_peer
- when "none"
- :verify_none
- when nil
- knife_config[:ssl_verify_mode]
- else
- nil
- end
+ when "peer"
+ :verify_peer
+ when "none"
+ :verify_none
+ when nil
+ knife_config[:ssl_verify_mode]
+ else
+ nil
+ end
if value
client_rb << %Q{ssl_verify_mode :#{value}\n}
@@ -108,6 +138,16 @@ CONFIG
client_rb << %Q{https_proxy "#{knife_config[:bootstrap_proxy]}"\n}
end
+ if knife_config[:bootstrap_proxy_user]
+ client_rb << %Q{http_proxy_user "#{knife_config[:bootstrap_proxy_user]}"\n}
+ client_rb << %Q{https_proxy_user "#{knife_config[:bootstrap_proxy_user]}"\n}
+ end
+
+ if knife_config[:bootstrap_proxy_pass]
+ client_rb << %Q{http_proxy_pass "#{knife_config[:bootstrap_proxy_pass]}"\n}
+ client_rb << %Q{https_proxy_pass "#{knife_config[:bootstrap_proxy_pass]}"\n}
+ end
+
if knife_config[:bootstrap_no_proxy]
client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n}
end
@@ -120,15 +160,27 @@ CONFIG
client_rb << %Q{trusted_certs_dir "/etc/chef/trusted_certs"\n}
end
+ if Chef::Config[:fips]
+ client_rb << <<-CONFIG.gsub(/^ {14}/, "")
+ fips true
+ require "chef/version"
+ chef_version = ::Chef::VERSION.split(".")
+ unless chef_version[0].to_i > 12 || (chef_version[0].to_i == 12 && chef_version[1].to_i >= 8)
+ raise "FIPS Mode requested but not supported by this client"
+ end
+ CONFIG
+ end
+
client_rb
end
def start_chef
# If the user doesn't have a client path configure, let bash use the PATH for what it was designed for
- client_path = @chef_config[:chef_client_path] || 'chef-client'
+ client_path = @chef_config[:chef_client_path] || "chef-client"
s = "#{client_path} -j /etc/chef/first-boot.json"
- s << ' -l debug' if @config[:verbosity] and @config[:verbosity] >= 2
+ s << " -l debug" if @config[:verbosity] && @config[:verbosity] >= 2
s << " -E #{bootstrap_environment}" unless bootstrap_environment.nil?
+ s << " --no-color" unless @config[:color]
s
end
@@ -146,10 +198,10 @@ CONFIG
installer_version_string = ["-p"]
else
chef_version_string = if knife_config[:bootstrap_version]
- knife_config[:bootstrap_version]
- else
- Chef::VERSION.split(".").first
- end
+ knife_config[:bootstrap_version]
+ else
+ Chef::VERSION.split(".").first
+ end
installer_version_string = ["-v", chef_version_string]
@@ -165,9 +217,10 @@ CONFIG
def first_boot
(@config[:first_boot_attributes] || {}).tap do |attributes|
if @config[:policy_name] && @config[:policy_group]
- attributes.merge!(:policy_name => @config[:policy_name], :policy_group => @config[:policy_group])
+ attributes[:policy_name] = @config[:policy_name]
+ attributes[:policy_group] = @config[:policy_group]
else
- attributes.merge!(:run_list => @run_list)
+ attributes[:run_list] = @run_list
end
attributes.merge!(:tags => @config[:tags]) if @config[:tags] && !@config[:tags].empty?
@@ -181,9 +234,29 @@ CONFIG
def trusted_certs_content
content = ""
if @chef_config[:trusted_certs_dir]
- Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(@chef_config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert|
+ Dir.glob(File.join(Chef::Util::PathHelper.escape_glob_dir(@chef_config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert|
content << "cat > /etc/chef/trusted_certs/#{File.basename(cert)} <<'EOP'\n" +
- IO.read(File.expand_path(cert)) + "\nEOP\n"
+ IO.read(File.expand_path(cert)) + "\nEOP\n"
+ end
+ end
+ content
+ end
+
+ def client_d_content
+ content = ""
+ if @chef_config[:client_d_dir] && File.exist?(@chef_config[:client_d_dir])
+ root = Pathname(@chef_config[:client_d_dir])
+ root.find do |f|
+ relative = f.relative_path_from(root)
+ if f != root
+ file_on_node = "/etc/chef/client.d/#{relative}"
+ if f.directory?
+ content << "mkdir #{file_on_node}\n"
+ else
+ content << "cat > #{file_on_node} <<'EOP'\n" +
+ f.read + "\nEOP\n"
+ end
+ end
end
end
content
diff --git a/lib/chef/knife/core/cookbook_scm_repo.rb b/lib/chef/knife/core/cookbook_scm_repo.rb
index 727cff3153..38f432e5bb 100644
--- a/lib/chef/knife/core/cookbook_scm_repo.rb
+++ b/lib/chef/knife/core/cookbook_scm_repo.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
+require "chef/mixin/shell_out"
class Chef
class Knife
@@ -31,10 +31,10 @@ class Chef
attr_reader :use_current_branch
attr_reader :ui
- def initialize(repo_path, ui, opts={})
+ def initialize(repo_path, ui, opts = {})
@repo_path = repo_path
@ui = ui
- @default_branch = 'master'
+ @default_branch = "master"
@use_current_branch = false
apply_opts(opts)
end
@@ -57,7 +57,7 @@ class Chef
ui.info "If this is a new git repo, make sure you have at least one commit before installing cookbooks"
exit 1
end
- cmd = git('status --porcelain')
+ cmd = git("status --porcelain")
if cmd.stdout =~ DIRTY_REPO
ui.error "You have uncommitted changes to your cookbook repo (#{repo_path}):"
ui.msg cmd.stdout
@@ -119,21 +119,21 @@ class Chef
end
def branch_exists?(branch_name)
- git("branch --no-color").stdout.lines.any? {|l| l =~ /\s#{Regexp.escape(branch_name)}(?:\s|$)/ }
+ git("branch --no-color").stdout.lines.any? { |l| l =~ /\s#{Regexp.escape(branch_name)}(?:\s|$)/ }
end
- def get_current_branch()
+ def get_current_branch
ref = git("symbolic-ref HEAD").stdout
- ref.chomp.split('/')[2]
+ ref.chomp.split("/")[2]
end
private
def git_repo?(directory)
- if File.directory?(File.join(directory, '.git'))
- return true
+ if File.directory?(File.join(directory, ".git"))
+ true
elsif File.dirname(directory) == directory
- return false
+ false
else
git_repo?(File.dirname(directory))
end
@@ -142,9 +142,9 @@ class Chef
def apply_opts(opts)
opts.each do |option, value|
case option.to_s
- when 'default_branch'
+ when "default_branch"
@default_branch = value
- when 'use_current_branch'
+ when "use_current_branch"
@use_current_branch = value
end
end
@@ -157,4 +157,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/knife/core/custom_manifest_loader.rb b/lib/chef/knife/core/custom_manifest_loader.rb
index c19e749f32..9fe51599af 100644
--- a/lib/chef/knife/core/custom_manifest_loader.rb
+++ b/lib/chef/knife/core/custom_manifest_loader.rb
@@ -1,4 +1,4 @@
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,7 @@
# limitations under the License.
#
-require 'chef/version'
+require "chef/version"
class Chef
class Knife
class SubcommandLoader
@@ -61,7 +61,7 @@ class Chef
end
def subcommand_files
- subcommand_files ||= (find_subcommands_via_manifest.values + site_subcommands).flatten.uniq
+ @subcommand_files ||= (find_subcommands_via_manifest.values + site_subcommands).flatten.uniq
end
end
end
diff --git a/lib/chef/knife/core/gem_glob_loader.rb b/lib/chef/knife/core/gem_glob_loader.rb
index d09131aacb..c4523d69ad 100644
--- a/lib/chef/knife/core/gem_glob_loader.rb
+++ b/lib/chef/knife/core/gem_glob_loader.rb
@@ -1,6 +1,6 @@
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2009-2015 Chef Software, Inc
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'chef/version'
-require 'chef/util/path_helper'
+require "chef/version"
+require "chef/util/path_helper"
class Chef
class Knife
class SubcommandLoader
class GemGlobLoader < Chef::Knife::SubcommandLoader
- MATCHES_CHEF_GEM = %r{/chef-[\d]+\.[\d]+\.[\d]+}.freeze
- MATCHES_THIS_CHEF_GEM = %r{/chef-#{Chef::VERSION}(-\w+)?(-\w+)?/}.freeze
+ MATCHES_CHEF_GEM = %r{/chef-[\d]+\.[\d]+\.[\d]+}
+ MATCHES_THIS_CHEF_GEM = %r{/chef-#{Chef::VERSION}(-\w+)?(-\w+)?/}
def subcommand_files
@subcommand_files ||= (gem_and_builtin_subcommands.values + site_subcommands).flatten.uniq
@@ -39,7 +39,7 @@ class Chef
# subcommand loader has been modified to load the plugins by using Kernel.load
# with the absolute path.
def gem_and_builtin_subcommands
- require 'rubygems'
+ require "rubygems"
find_subcommands_via_rubygems
rescue LoadError
find_subcommands_via_dirglob
@@ -47,17 +47,17 @@ class Chef
def find_subcommands_via_dirglob
# The "require paths" of the core knife subcommands bundled with chef
- files = Dir[File.join(Chef::Util::PathHelper.escape_glob(File.expand_path('../../../knife', __FILE__)), '*.rb')]
+ files = Dir[File.join(Chef::Util::PathHelper.escape_glob_dir(File.expand_path("../../../knife", __FILE__)), "*.rb")]
subcommand_files = {}
files.each do |knife_file|
- rel_path = knife_file[/#{CHEF_ROOT}#{Regexp.escape(File::SEPARATOR)}(.*)\.rb/,1]
+ rel_path = knife_file[/#{CHEF_ROOT}#{Regexp.escape(File::SEPARATOR)}(.*)\.rb/, 1]
subcommand_files[rel_path] = knife_file
end
subcommand_files
end
def find_subcommands_via_rubygems
- files = find_files_latest_gems 'chef/knife/*.rb'
+ files = find_files_latest_gems "chef/knife/*.rb"
subcommand_files = {}
files.each do |file|
rel_path = file[/(#{Regexp.escape File.join('chef', 'knife', '')}.*)\.rb/, 1]
@@ -77,13 +77,13 @@ class Chef
private
- def find_files_latest_gems(glob, check_load_path=true)
+ def find_files_latest_gems(glob, check_load_path = true)
files = []
if check_load_path
- files = $LOAD_PATH.map { |load_path|
- Dir["#{File.expand_path glob, Chef::Util::PathHelper.escape_glob(load_path)}#{Gem.suffix_pattern}"]
- }.flatten.select { |file| File.file? file.untaint }
+ files = $LOAD_PATH.map do |load_path|
+ Dir["#{File.expand_path glob, Chef::Util::PathHelper.escape_glob_dir(load_path)}#{Gem.suffix_pattern}"]
+ end.flatten.select { |file| File.file? file.untaint }
end
gem_files = latest_gem_specs.map do |spec|
@@ -98,25 +98,25 @@ class Chef
files.concat gem_files
files.uniq! if check_load_path
- return files
+ files
end
def latest_gem_specs
@latest_gem_specs ||= if Gem::Specification.respond_to? :latest_specs
- Gem::Specification.latest_specs(true) # find prerelease gems
+ Gem::Specification.latest_specs(true) # find prerelease gems
else
Gem.source_index.latest_specs(true)
end
end
def check_spec_for_glob(spec, glob)
- dirs = if spec.require_paths.size > 1 then
+ dirs = if spec.require_paths.size > 1
"{#{spec.require_paths.join(',')}}"
else
spec.require_paths.first
end
- glob = File.join(Chef::Util::PathHelper.escape_glob(spec.full_gem_path, dirs), glob)
+ glob = File.join(Chef::Util::PathHelper.escape_glob_dir(spec.full_gem_path, dirs), glob)
Dir[glob].map { |f| f.untaint }
end
diff --git a/lib/chef/knife/core/generic_presenter.rb b/lib/chef/knife/core/generic_presenter.rb
index 2df9603faa..861bf1510d 100644
--- a/lib/chef/knife/core/generic_presenter.rb
+++ b/lib/chef/knife/core/generic_presenter.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife/core/text_formatter'
+require "chef/knife/core/text_formatter"
class Chef
class Knife
@@ -28,12 +28,19 @@ class Chef
# :nodoc:
def self.included(includer)
includer.class_eval do
- @attrs_to_show = []
+ option :field_separator,
+ :short => "-S SEPARATOR",
+ :long => "--field-separator SEPARATOR",
+ :description => "Character separator used to delineate nesting in --attribute filters (default \".\")"
+
option :attribute,
:short => "-a ATTR1 [-a ATTR2]",
:long => "--attribute ATTR1 [--attribute ATTR2] ",
- :proc => lambda {|val| @attrs_to_show << val},
- :description => "Show one or more attributes"
+ :description => "Show one or more attributes",
+ :proc => Proc.new { |a|
+ Chef::Config[:knife][:attribute] ||= []
+ Chef::Config[:knife][:attribute].push(a)
+ }
end
end
end
@@ -80,13 +87,13 @@ class Chef
when :json
Chef::JSONCompat.to_json_pretty(data)
when :yaml
- require 'yaml'
- YAML::dump(data)
+ require "yaml"
+ YAML.dump(data)
when :pp
- require 'stringio'
+ require "stringio"
# If you were looking for some attribute and there is only one match
# just dump the attribute value
- if config[:attribute] and data.length == 1
+ if config[:attribute] && data.length == 1
data.values[0]
else
out = StringIO.new
@@ -133,7 +140,7 @@ class Chef
end
def format_list_for_display(list)
- config[:with_uri] ? list : list.keys.sort { |a,b| a <=> b }
+ config[:with_uri] ? list : list.keys.sort { |a, b| a <=> b }
end
def format_for_display(data)
@@ -142,7 +149,7 @@ class Chef
elsif config[:id_only]
name_or_id_for(data)
elsif config[:environment] && data.respond_to?(:chef_environment)
- {"chef_environment" => data.chef_environment}
+ { "chef_environment" => data.chef_environment }
else
data
end
@@ -150,19 +157,19 @@ class Chef
def format_data_subset_for_display(data)
subset = if config[:attribute]
- result = {}
- Array(config[:attribute]).each do |nested_value_spec|
- nested_value = extract_nested_value(data, nested_value_spec)
- result[nested_value_spec] = nested_value
- end
- result
- elsif config[:run_list]
- run_list = data.run_list.run_list
- { "run_list" => run_list }
- else
- raise ArgumentError, "format_data_subset_for_display requires attribute, run_list, or id_only config option to be set"
- end
- {name_or_id_for(data) => subset }
+ result = {}
+ Array(config[:attribute]).each do |nested_value_spec|
+ nested_value = extract_nested_value(data, nested_value_spec)
+ result[nested_value_spec] = nested_value
+ end
+ result
+ elsif config[:run_list]
+ run_list = data.run_list.run_list
+ { "run_list" => run_list }
+ else
+ raise ArgumentError, "format_data_subset_for_display requires attribute, run_list, or id_only config option to be set"
+ end
+ { name_or_id_for(data) => subset }
end
def name_or_id_for(data)
@@ -173,26 +180,28 @@ class Chef
config[:attribute] || config[:run_list]
end
+ # GenericPresenter is used in contexts where MultiAttributeReturnOption
+ # is not, so we need to set the default value here rather than as part
+ # of the CLI option.
+ def attribute_field_separator
+ config[:field_separator] || "."
+ end
def extract_nested_value(data, nested_value_spec)
- nested_value_spec.split(".").each do |attr|
- if data.nil?
- nil # don't get no method error on nil
- # Must check :[] before attr because spec can include
- # `keys` - want the key named `keys`, not a list of
- # available keys.
- elsif data.respond_to?(:[]) && data.has_key?(attr)
- data = data[attr]
- elsif data.respond_to?(attr.to_sym)
- data = data.send(attr.to_sym)
- else
- data = begin
- data.send(attr.to_sym)
- rescue NoMethodError
+ nested_value_spec.split(attribute_field_separator).each do |attr|
+ data =
+ if data.is_a?(Array)
+ data[attr.to_i]
+ elsif data.respond_to?(:[], false) && data.key?(attr)
+ data[attr]
+ elsif data.respond_to?(attr.to_sym, false)
+ # handles -a chef_environment and other things that hang of the node and aren't really attributes
+ data.public_send(attr.to_sym)
+ else
nil
end
- end
end
+ # necessary (?) for coercing objects (the run_list object?) to hashes
( !data.kind_of?(Array) && data.respond_to?(:to_hash) ) ? data.to_hash : data
end
@@ -200,17 +209,17 @@ class Chef
if config[:with_uri]
item.inject({}) do |collected, (cookbook, versions)|
collected[cookbook] = Hash.new
- versions['versions'].each do |ver|
- collected[cookbook][ver['version']] = ver['url']
+ versions["versions"].each do |ver|
+ collected[cookbook][ver["version"]] = ver["url"]
end
collected
end
else
versions_by_cookbook = item.inject({}) do |collected, ( cookbook, versions )|
- collected[cookbook] = versions["versions"].map {|v| v['version']}
+ collected[cookbook] = versions["versions"].map { |v| v["version"] }
collected
end
- key_length = versions_by_cookbook.empty? ? 0 : versions_by_cookbook.keys.map {|name| name.size }.max + 2
+ key_length = versions_by_cookbook.empty? ? 0 : versions_by_cookbook.keys.map { |name| name.size }.max + 2
versions_by_cookbook.sort.map do |cookbook, versions|
"#{cookbook.ljust(key_length)} #{versions.join(' ')}"
end
diff --git a/lib/chef/knife/core/hashed_command_loader.rb b/lib/chef/knife/core/hashed_command_loader.rb
index 6eb3635726..8423c01812 100644
--- a/lib/chef/knife/core/hashed_command_loader.rb
+++ b/lib/chef/knife/core/hashed_command_loader.rb
@@ -1,5 +1,5 @@
# Author:: Steven Danna (<steve@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# limitations under the License.
#
-require 'chef/version'
+require "chef/version"
class Chef
class Knife
class SubcommandLoader
@@ -24,7 +24,7 @@ class Chef
# for the given command.
#
class HashedCommandLoader < Chef::Knife::SubcommandLoader
- KEY = '_autogenerated_command_paths'
+ KEY = "_autogenerated_command_paths"
attr_accessor :manifest
def initialize(chef_config_dir, plugin_manifest)
@@ -34,15 +34,35 @@ class Chef
def guess_category(args)
category_words = positional_arguments(args)
- category_words.map! { |w| w.split('-') }.flatten!
- find_longest_key(manifest[KEY]["plugins_by_category"], category_words, ' ')
+ category_words.map! { |w| w.split("-") }.flatten!
+ find_longest_key(manifest[KEY]["plugins_by_category"], category_words, " ")
end
- def list_commands(pref_category=nil)
+ def list_commands(pref_category = nil)
if pref_category || manifest[KEY]["plugins_by_category"].key?(pref_category)
- { pref_category => manifest[KEY]["plugins_by_category"][pref_category] }
+ commands = { pref_category => manifest[KEY]["plugins_by_category"][pref_category] }
else
- manifest[KEY]["plugins_by_category"]
+ commands = manifest[KEY]["plugins_by_category"]
+ end
+ # If any of the specified plugins in the manifest dont have a valid path we will
+ # eventually get an error and the user will need to rehash - instead, lets just
+ # print out 1 error here telling them to rehash
+ errors = {}
+ commands.collect { |k, v| v }.flatten.each do |command|
+ paths = manifest[KEY]["plugins_paths"][command]
+ if paths && paths.is_a?(Array)
+ # It is only an error if all the paths don't exist
+ if paths.all? { |sc| !File.exists?(sc) }
+ errors[command] = paths
+ end
+ end
+ end
+ if errors.empty?
+ commands
+ else
+ Chef::Log.error "There are files specified in the manifest that are missing. Please rehash to update the subcommands cache. If you see this error after rehashing delete the cache at #{Chef::Knife::SubcommandLoader.plugin_manifest_path}"
+ Chef::Log.error "Missing files:\n\t#{errors.values.flatten.join("\n\t")}"
+ {}
end
end
@@ -59,7 +79,6 @@ class Chef
if File.exists?(sc)
Kernel.load sc
else
- Chef::Log.error "The file #{sc} is missing for subcommand '#{subcommand_for_args(args)}'. Please rehash to update the subcommands cache."
return false
end
end
diff --git a/lib/chef/knife/core/node_editor.rb b/lib/chef/knife/core/node_editor.rb
index fe14e18d9d..b009bf8652 100644
--- a/lib/chef/knife/core/node_editor.rb
+++ b/lib/chef/knife/core/node_editor.rb
@@ -1,6 +1,7 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Jordan Running (<jr@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,83 +17,103 @@
# limitations under the License.
#
-require 'chef/json_compat'
-require 'chef/node'
-require 'tempfile'
+require "chef/json_compat"
+require "chef/node"
class Chef
class Knife
class NodeEditor
+ attr_reader :node, :ui, :config
+ private :node, :ui, :config
- attr_reader :node
- attr_reader :ui
- attr_reader :config
-
+ # @param node [Chef::Node]
+ # @param ui [Chef::Knife::UI]
+ # @param config [Hash]
def initialize(node, ui, config)
@node, @ui, @config = node, ui, config
end
+ # Opens the node data (as JSON) in the user's editor and returns a new
+ # {Chef::Node} reflecting the user's changes.
+ #
+ # @return [Chef::Node]
def edit_node
abort "You specified the --disable_editing option, nothing to edit" if config[:disable_editing]
assert_editor_set!
- updated_node_data = @ui.edit_data(view)
+ updated_node_data = ui.edit_hash(view)
apply_updates(updated_node_data)
@updated_node
end
+ # Returns an array of the names of properties that have been changed or
+ # +false+ if none were changed.
+ #
+ # @return [Array<String>] if any properties have been changed.
+ # @return [false] if no properties have been changed.
def updated?
+ return false if @updated_node.nil?
+
pristine_copy = Chef::JSONCompat.parse(Chef::JSONCompat.to_json(node))
updated_copy = Chef::JSONCompat.parse(Chef::JSONCompat.to_json(@updated_node))
- unless pristine_copy == updated_copy
- updated_properties = %w{name normal chef_environment run_list default override automatic}.reject do |key|
- pristine_copy[key] == updated_copy[key]
- end
+
+ updated_properties = %w{
+ name
+ chef_environment
+ automatic
+ default
+ normal
+ override
+ policy_name
+ policy_group
+ run_list
+ }.reject do |key|
+ pristine_copy[key] == updated_copy[key]
end
- ( pristine_copy != updated_copy ) && updated_properties
- end
- private
+ updated_properties.any? && updated_properties
+ end
+ # @api private
def view
- result = {}
- result["name"] = node.name
- result["chef_environment"] = node.chef_environment
- result["normal"] = node.normal_attrs
- result["run_list"] = node.run_list
+ result = {
+ "name" => node.name,
+ "chef_environment" => node.chef_environment,
+ "normal" => node.normal_attrs,
+ "policy_name" => node.policy_name,
+ "policy_group" => node.policy_group,
+ "run_list" => node.run_list,
+ }
if config[:all_attributes]
result["default"] = node.default_attrs
result["override"] = node.override_attrs
result["automatic"] = node.automatic_attrs
end
+
result
end
+ # @api private
def apply_updates(updated_data)
- if node.name and node.name != updated_data["name"]
+ if node.name && node.name != updated_data["name"]
ui.warn "Changing the name of a node results in a new node being created, #{node.name} will not be modified or removed."
- confirm = ui.confirm "Proceed with creation of new node"
+ ui.confirm "Proceed with creation of new node"
end
- @updated_node = Node.new.tap do |n|
- n.name( updated_data["name"] )
- n.chef_environment( updated_data["chef_environment"] )
- n.run_list( updated_data["run_list"])
- n.normal_attrs = updated_data["normal"]
-
- if config[:all_attributes]
- n.default_attrs = updated_data["default"]
- n.override_attrs = updated_data["override"]
- n.automatic_attrs = updated_data["automatic"]
- else
- n.default_attrs = node.default_attrs
- n.override_attrs = node.override_attrs
- n.automatic_attrs = node.automatic_attrs
- end
+ data = updated_data.dup
+
+ unless config[:all_attributes]
+ data["automatic"] = node.automatic_attrs
+ data["default"] = node.default_attrs
+ data["override"] = node.override_attrs
end
+
+ @updated_node = Node.from_hash(data)
end
+ private
+
def abort(message)
ui.error(message)
exit 1
diff --git a/lib/chef/knife/core/node_presenter.rb b/lib/chef/knife/core/node_presenter.rb
index d9ea8c7669..cdb664ec33 100644
--- a/lib/chef/knife/core/node_presenter.rb
+++ b/lib/chef/knife/core/node_presenter.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife/core/text_formatter'
-require 'chef/knife/core/generic_presenter'
+require "chef/knife/core/text_formatter"
+require "chef/knife/core/generic_presenter"
class Chef
class Knife
@@ -32,18 +32,18 @@ class Chef
def self.included(includer)
includer.class_eval do
option :medium_output,
- :short => '-m',
- :long => '--medium',
+ :short => "-m",
+ :long => "--medium",
:boolean => true,
:default => false,
- :description => 'Include normal attributes in the output'
+ :description => "Include normal attributes in the output"
option :long_output,
- :short => '-l',
- :long => '--long',
+ :short => "-l",
+ :long => "--long",
:boolean => true,
:default => false,
- :description => 'Include all attributes in the output'
+ :description => "Include all attributes in the output"
end
end
end
@@ -98,7 +98,7 @@ class Chef
# special case ec2 with their split horizon whatsis.
ip = (node[:ec2] && node[:ec2][:public_ipv4]) || node[:ipaddress]
- summarized=<<-SUMMARY
+ summarized = <<-SUMMARY
#{ui.color('Node Name:', :bold)} #{ui.color(node.name, :bold)}
SUMMARY
show_policy = !(node.policy_name.nil? && node.policy_group.nil?)
@@ -125,16 +125,16 @@ ROLES
summarized << <<-SUMMARY
#{key('Recipes:')} #{Array(node[:recipes]).join(', ')}
#{key('Platform:')} #{node[:platform]} #{node[:platform_version]}
-#{key('Tags:')} #{Array(node[:tags]).join(', ')}
+#{key('Tags:')} #{node.tags.join(', ')}
SUMMARY
if config[:medium_output] || config[:long_output]
- summarized +=<<-MORE
+ summarized += <<-MORE
#{key('Attributes:')}
#{text_format(node.normal_attrs)}
MORE
end
if config[:long_output]
- summarized +=<<-MOST
+ summarized += <<-MOST
#{key('Default Attributes:')}
#{text_format(node.default_attrs)}
#{key('Override Attributes:')}
@@ -157,4 +157,3 @@ MOST
end
end
end
-
diff --git a/lib/chef/knife/core/object_loader.rb b/lib/chef/knife/core/object_loader.rb
index 97ca381471..b08483f9a2 100644
--- a/lib/chef/knife/core/object_loader.rb
+++ b/lib/chef/knife/core/object_loader.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'ffi_yajl'
-require 'chef/util/path_helper'
-require 'chef/data_bag_item'
+require "ffi_yajl"
+require "chef/util/path_helper"
+require "chef/data_bag_item"
class Chef
class Knife
@@ -71,14 +71,14 @@ class Chef
#
# @api public
def find_all_objects(path)
- path = File.join(Chef::Util::PathHelper.escape_glob(File.expand_path(path)), '*')
- path << '.{json,rb}'
+ path = File.join(Chef::Util::PathHelper.escape_glob_dir(File.expand_path(path)), "*")
+ path << ".{json,rb}"
objects = Dir.glob(path)
objects.map { |o| File.basename(o) }
end
def find_all_object_dirs(path)
- path = File.join(Chef::Util::PathHelper.escape_glob(File.expand_path(path)), '*')
+ path = File.join(Chef::Util::PathHelper.escape_glob_dir(File.expand_path(path)), "*")
objects = Dir.glob(path)
objects.delete_if { |o| !File.directory?(o) }
objects.map { |o| File.basename(o) }
@@ -93,7 +93,7 @@ class Chef
if @klass == Chef::DataBagItem
r
else
- @klass.json_create(r)
+ @klass.from_hash(r)
end
when /\.rb$/
r = klass.new
diff --git a/lib/chef/knife/core/status_presenter.rb b/lib/chef/knife/core/status_presenter.rb
index 9cf839d3a6..df6c2fe942 100644
--- a/lib/chef/knife/core/status_presenter.rb
+++ b/lib/chef/knife/core/status_presenter.rb
@@ -1,6 +1,6 @@
#
# Author:: Nicolas DUPEUX (<nicolas.dupeux@arkea.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife/core/text_formatter'
-require 'chef/knife/core/generic_presenter'
+require "chef/knife/core/text_formatter"
+require "chef/knife/core/generic_presenter"
class Chef
class Knife
@@ -32,18 +32,18 @@ class Chef
def self.included(includer)
includer.class_eval do
option :medium_output,
- :short => '-m',
- :long => '--medium',
+ :short => "-m",
+ :long => "--medium",
:boolean => true,
:default => false,
- :description => 'Include normal attributes in the output'
+ :description => "Include normal attributes in the output"
option :long_output,
- :short => '-l',
- :long => '--long',
+ :short => "-l",
+ :long => "--long",
:boolean => true,
:default => false,
- :description => 'Include all attributes in the output'
+ :description => "Include all attributes in the output"
end
end
end
@@ -93,15 +93,15 @@ class Chef
# the volume of output is adjusted accordingly. Uses colors if enabled
# in the ui object.
def summarize(list)
- summarized=''
+ summarized = ""
list.each do |data|
node = data
# special case ec2 with their split horizon whatsis.
ip = (node[:ec2] && node[:ec2][:public_ipv4]) || node[:ipaddress]
fqdn = (node[:ec2] && node[:ec2][:public_hostname]) || node[:fqdn]
- name = node['name'] || node.name
+ name = node["name"] || node.name
- hours, minutes, _ = time_difference_in_hms(node["ohai_time"])
+ hours, minutes, = time_difference_in_hms(node["ohai_time"])
hours_text = "#{hours} hour#{hours == 1 ? ' ' : 's'}"
minutes_text = "#{minutes} minute#{minutes == 1 ? ' ' : 's'}"
run_list = "#{node['run_list']}" if config[:run_list]
@@ -117,20 +117,20 @@ class Chef
end
line_parts = Array.new
- line_parts << @ui.color(text, color) + ' ago' << name
+ line_parts << @ui.color(text, color) + " ago" << name
line_parts << fqdn if fqdn
line_parts << ip if ip
line_parts << run_list if run_list
- if node['platform']
- platform = node['platform']
- if node['platform_version']
+ if node["platform"]
+ platform = node["platform"]
+ if node["platform_version"]
platform << " #{node['platform_version']}"
end
line_parts << platform
end
- summarized=summarized + line_parts.join(', ') + ".\n"
+ summarized = summarized + line_parts.join(", ") + ".\n"
end
summarized
end
@@ -148,7 +148,7 @@ class Chef
difference = difference % 3600
minutes = (difference / 60).to_i
seconds = (difference % 60)
- return [hours, minutes, seconds]
+ [hours, minutes, seconds]
end
end
diff --git a/lib/chef/knife/core/subcommand_loader.rb b/lib/chef/knife/core/subcommand_loader.rb
index 808e053c40..30a438b780 100644
--- a/lib/chef/knife/core/subcommand_loader.rb
+++ b/lib/chef/knife/core/subcommand_loader.rb
@@ -1,6 +1,6 @@
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2011 Opscode, Inc.
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'chef/version'
-require 'chef/util/path_helper'
-require 'chef/knife/core/gem_glob_loader'
-require 'chef/knife/core/hashed_command_loader'
-require 'chef/knife/core/custom_manifest_loader'
+require "chef/version"
+require "chef/util/path_helper"
+require "chef/knife/core/gem_glob_loader"
+require "chef/knife/core/hashed_command_loader"
+require "chef/knife/core/custom_manifest_loader"
class Chef
class Knife
@@ -51,13 +51,19 @@ class Chef
Chef::Log.debug("Using autogenerated hashed command manifest #{plugin_manifest_path}")
Knife::SubcommandLoader::HashedCommandLoader.new(chef_config_dir, plugin_manifest)
elsif custom_manifest?
- Chef.log_deprecation("Using custom manifest #{plugin_manifest_path} is deprecated. Please use a `knife rehash` autogenerated manifest instead.")
+ Chef.deprecated(:internal_api, "Using custom manifest #{plugin_manifest_path} is deprecated. Please use a `knife rehash` autogenerated manifest instead.")
Knife::SubcommandLoader::CustomManifestLoader.new(chef_config_dir, plugin_manifest)
else
Knife::SubcommandLoader::GemGlobLoader.new(chef_config_dir)
end
end
+ # There are certain situations where we want to shortcut the loader selection
+ # in self.for_config and force using the GemGlobLoader
+ def self.gem_glob_loader(chef_config_dir)
+ Knife::SubcommandLoader::GemGlobLoader.new(chef_config_dir)
+ end
+
def self.plugin_manifest?
plugin_manifest_path && File.exist?(plugin_manifest_path)
end
@@ -75,7 +81,7 @@ class Chef
end
def self.plugin_manifest_path
- Chef::Util::PathHelper.home('.chef', 'plugin_manifest.json')
+ Chef::Util::PathHelper.home(".chef", "plugin_manifest.json")
end
def initialize(chef_config_dir, env = nil)
@@ -84,7 +90,7 @@ class Chef
# Deprecated and un-used instance variable.
@env = env
unless env.nil?
- Chef.log_deprecation("The env argument to Chef::Knife::SubcommandLoader is deprecated. If you are using env to inject/mock HOME, consider mocking Chef::Util::PathHelper.home instead.")
+ Chef.deprecated(:internal_api, "The env argument to Chef::Knife::SubcommandLoader is deprecated. If you are using env to inject/mock HOME, consider mocking Chef::Util::PathHelper.home instead.")
end
end
@@ -96,7 +102,7 @@ class Chef
end
def force_load
- @loaded=false
+ @loaded = false
load_commands
end
@@ -117,27 +123,26 @@ class Chef
cmd_words = positional_arguments(args)
load_command(cmd_words)
result = Chef::Knife.subcommands[find_longest_key(Chef::Knife.subcommands,
- cmd_words, '_')]
- result || Chef::Knife.subcommands[args.first.gsub('-', '_')]
+ cmd_words, "_")]
+ result || Chef::Knife.subcommands[args.first.tr("-", "_")]
end
def guess_category(args)
category_words = positional_arguments(args)
- category_words.map! { |w| w.split('-') }.flatten!
+ category_words.map! { |w| w.split("-") }.flatten!
find_longest_key(Chef::Knife.subcommands_by_category,
- category_words, ' ')
+ category_words, " ")
end
-
#
# This is shared between the custom_manifest_loader and the gem_glob_loader
#
def find_subcommands_via_dirglob
# The "require paths" of the core knife subcommands bundled with chef
- files = Dir[File.join(Chef::Util::PathHelper.escape_glob(File.expand_path('../../../knife', __FILE__)), '*.rb')]
+ files = Dir[File.join(Chef::Util::PathHelper.escape_glob_dir(File.expand_path("../../../knife", __FILE__)), "*.rb")]
subcommand_files = {}
files.each do |knife_file|
- rel_path = knife_file[/#{CHEF_ROOT}#{Regexp.escape(File::SEPARATOR)}(.*)\.rb/,1]
+ rel_path = knife_file[/#{CHEF_ROOT}#{Regexp.escape(File::SEPARATOR)}(.*)\.rb/, 1]
subcommand_files[rel_path] = knife_file
end
subcommand_files
@@ -149,7 +154,7 @@ class Chef
# to get in the past.
#
def subcommand_files
- Chef.log_deprecation "Using Chef::Knife::SubcommandLoader directly is deprecated.
+ Chef.deprecated :internal_api, "Using Chef::Knife::SubcommandLoader directly is deprecated.
Please use Chef::Knife::SubcommandLoader.for_config(chef_config_dir, env)"
@subcommand_files ||= if Chef::Knife::SubcommandLoader.plugin_manifest?
Chef::Knife::SubcommandLoader::CustomManifestLoader.new(chef_config_dir, env).subcommand_files
@@ -163,7 +168,7 @@ Please use Chef::Knife::SubcommandLoader.for_config(chef_config_dir, env)"
# of words and a separator. We find the the longest key in the
# hash composed of the given words joined by the separator.
#
- def find_longest_key(hash, words, sep = '_')
+ def find_longest_key(hash, words, sep = "_")
match = nil
until match || words.empty?
candidate = words.join(sep)
@@ -192,12 +197,12 @@ Please use Chef::Knife::SubcommandLoader.for_config(chef_config_dir, env)"
user_specific_files = []
if chef_config_dir
- user_specific_files.concat Dir.glob(File.expand_path("plugins/knife/*.rb", Chef::Util::PathHelper.escape_glob(chef_config_dir)))
+ user_specific_files.concat Dir.glob(File.expand_path("plugins/knife/*.rb", Chef::Util::PathHelper.escape_glob_dir(chef_config_dir)))
end
# finally search ~/.chef/plugins/knife/*.rb
- Chef::Util::PathHelper.home('.chef', 'plugins', 'knife') do |p|
- user_specific_files.concat Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(p), '*.rb'))
+ Chef::Util::PathHelper.home(".chef", "plugins", "knife") do |p|
+ user_specific_files.concat Dir.glob(File.join(Chef::Util::PathHelper.escape_glob_dir(p), "*.rb"))
end
user_specific_files
diff --git a/lib/chef/knife/core/text_formatter.rb b/lib/chef/knife/core/text_formatter.rb
index 60328488b2..8775e2e76f 100644
--- a/lib/chef/knife/core/text_formatter.rb
+++ b/lib/chef/knife/core/text_formatter.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,14 +27,14 @@ class Chef
def initialize(data, ui)
@ui = ui
@data = if data.respond_to?(:display_hash)
- data.display_hash
- elsif data.kind_of?(Array)
- data
- elsif data.respond_to?(:to_hash)
- data.to_hash
- else
- data
- end
+ data.display_hash
+ elsif data.kind_of?(Array)
+ data
+ elsif data.respond_to?(:to_hash)
+ data.to_hash
+ else
+ data
+ end
end
def formatted_data
@@ -42,10 +42,10 @@ class Chef
end
def text_format(data)
- buffer = ''
+ buffer = ""
if data.respond_to?(:keys)
- justify_width = data.keys.map {|k| k.to_s.size }.max.to_i + 1
+ justify_width = data.keys.map { |k| k.to_s.size }.max.to_i + 1
data.sort.each do |key, value|
# key: ['value'] should be printed as key: value
if value.kind_of?(Array) && value.size == 1 && is_singleton(value[0])
@@ -68,7 +68,7 @@ class Chef
buffer << text_format(data[index])
# Separate items with newlines if it's an array of hashes or an
# array of arrays
- buffer << "\n" if !is_singleton(data[index]) && index != data.size-1
+ buffer << "\n" if !is_singleton(data[index]) && index != data.size - 1
end
else
buffer << "#{data}\n"
@@ -83,4 +83,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/knife/core/ui.rb b/lib/chef/knife/core/ui.rb
index a54f14afc1..1fc6d3d0e2 100644
--- a/lib/chef/knife/core/ui.rb
+++ b/lib/chef/knife/core/ui.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,10 @@
# limitations under the License.
#
-require 'forwardable'
-require 'chef/platform/query_helpers'
-require 'chef/knife/core/generic_presenter'
-require 'tempfile'
+require "forwardable"
+require "chef/platform/query_helpers"
+require "chef/knife/core/generic_presenter"
+require "tempfile"
class Chef
class Knife
@@ -57,7 +57,7 @@ class Chef
def highline
@highline ||= begin
- require 'highline'
+ require "highline"
HighLine.new
end
end
@@ -65,22 +65,18 @@ class Chef
# Prints a message to stdout. Aliased as +info+ for compatibility with
# the logger API.
def msg(message)
- begin
- stdout.puts message
- rescue Errno::EPIPE => e
- raise e if @config[:verbosity] >= 2
- exit 0
- end
+ stdout.puts message
+ rescue Errno::EPIPE => e
+ raise e if @config[:verbosity] >= 2
+ exit 0
end
# Prints a msg to stderr. Used for info, warn, error, and fatal.
def log(message)
- begin
- stderr.puts message
- rescue Errno::EPIPE => e
- raise e if @config[:verbosity] >= 2
- exit 0
- end
+ stderr.puts message
+ rescue Errno::EPIPE => e
+ raise e if @config[:verbosity] >= 2
+ exit 0
end
alias :info :log
@@ -137,10 +133,10 @@ class Chef
@presenter.interchange?
end
- def ask_question(question, opts={})
- question = question + "[#{opts[:default]}] " if opts[:default]
+ def ask_question(question, opts = {})
+ question += "[#{opts[:default]}] " if opts[:default]
- if opts[:default] and config[:defaults]
+ if opts[:default] && config[:defaults]
opts[:default]
else
stdout.print question
@@ -155,27 +151,24 @@ class Chef
end
def pretty_print(data)
- begin
- stdout.puts data
- rescue Errno::EPIPE => e
- raise e if @config[:verbosity] >= 2
- exit 0
- end
+ stdout.puts data
+ rescue Errno::EPIPE => e
+ raise e if @config[:verbosity] >= 2
+ exit 0
end
-
# Hash -> Hash
# Works the same as edit_data but
- # returns a hash rather than a JSON string/Fully infated object
+ # returns a hash rather than a JSON string/Fully inflated object
def edit_hash(hash)
raw = edit_data(hash, false)
Chef::JSONCompat.parse(raw)
end
- def edit_data(data, parse_output=true)
+ def edit_data(data, parse_output = true, object_class: nil)
output = Chef::JSONCompat.to_json_pretty(data)
- if (!config[:disable_editing])
- Tempfile.open([ 'knife-edit-', '.json' ]) do |tf|
+ if !config[:disable_editing]
+ Tempfile.open([ "knife-edit-", ".json" ]) do |tf|
tf.sync = true
tf.puts output
tf.close
@@ -185,13 +178,22 @@ class Chef
end
end
- parse_output ? Chef::JSONCompat.from_json(output) : output
+ if parse_output
+ if object_class.nil?
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please pass in the class to inflate or use #edit_hash")
+ Chef::JSONCompat.from_json(output)
+ else
+ object_class.from_hash(Chef::JSONCompat.parse(output))
+ end
+ else
+ output
+ end
end
def edit_object(klass, name)
object = klass.load(name)
- output = edit_data(object)
+ output = edit_data(object, object_class: klass)
# Only make the save if the user changed the object.
#
@@ -207,9 +209,9 @@ class Chef
output_parsed_again = Chef::JSONCompat.parse(Chef::JSONCompat.to_json(output))
if object_parsed_again != output_parsed_again
output.save
- self.msg("Saved #{output}")
+ msg("Saved #{output}")
else
- self.msg("Object unchanged, not saving")
+ msg("Object unchanged, not saving")
end
output(format_for_display(object)) if config[:print_after]
end
@@ -217,16 +219,16 @@ class Chef
def confirmation_instructions(default_choice)
case default_choice
when true
- '? (Y/n) '
+ "? (Y/n) "
when false
- '? (y/N) '
+ "? (y/N) "
else
- '? (Y/N) '
+ "? (Y/N) "
end
end
# See confirm method for argument information
- def confirm_without_exit(question, append_instructions=true, default_choice=nil)
+ def confirm_without_exit(question, append_instructions = true, default_choice = nil)
return true if config[:yes]
stdout.print question
@@ -239,19 +241,19 @@ class Chef
when "Y", "y"
true
when "N", "n"
- self.msg("You said no, so I'm done here.")
+ msg("You said no, so I'm done here.")
false
when ""
unless default_choice.nil?
default_choice
else
- self.msg("I have no idea what to do with '#{answer}'")
- self.msg("Just say Y or N, please.")
+ msg("I have no idea what to do with '#{answer}'")
+ msg("Just say Y or N, please.")
confirm_without_exit(question, append_instructions, default_choice)
end
else
- self.msg("I have no idea what to do with '#{answer}'")
- self.msg("Just say Y or N, please.")
+ msg("I have no idea what to do with '#{answer}'")
+ msg("Just say Y or N, please.")
confirm_without_exit(question, append_instructions, default_choice)
end
end
@@ -264,7 +266,7 @@ class Chef
# append_instructions => Should print '? (Y/N)' as instructions
# default_choice => Set to true for 'Y', and false for 'N' as default answer
#
- def confirm(question, append_instructions=true, default_choice=nil)
+ def confirm(question, append_instructions = true, default_choice = nil)
unless confirm_without_exit(question, append_instructions, default_choice)
exit 3
end
diff --git a/lib/chef/knife/data_bag_create.rb b/lib/chef/knife/data_bag_create.rb
index f8a7619a8a..196278bb80 100644
--- a/lib/chef/knife/data_bag_create.rb
+++ b/lib/chef/knife/data_bag_create.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2009-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/data_bag_secret_options'
+require "chef/knife"
+require "chef/knife/data_bag_secret_options"
class Chef
class Knife
@@ -26,8 +26,8 @@ class Chef
include DataBagSecretOptions
deps do
- require 'chef/data_bag'
- require 'chef/encrypted_data_bag_item'
+ require "chef/data_bag"
+ require "chef/encrypted_data_bag_item"
end
banner "knife data bag create BAG [ITEM] (options)"
@@ -51,7 +51,7 @@ class Chef
# create the data bag
begin
- rest.post_rest("data", { "name" => @data_bag_name })
+ rest.post("data", { "name" => @data_bag_name })
ui.info("Created data_bag[#{@data_bag_name}]")
rescue Net::HTTPServerException => e
raise unless e.to_s =~ /^409/
@@ -66,9 +66,10 @@ class Chef
Chef::EncryptedDataBagItem.encrypt_data_bag_item(output, read_secret)
else
output
- end)
+ end
+ )
item.data_bag(@data_bag_name)
- rest.post_rest("data/#{@data_bag_name}", item)
+ rest.post("data/#{@data_bag_name}", item)
end
end
end
diff --git a/lib/chef/knife/data_bag_delete.rb b/lib/chef/knife/data_bag_delete.rb
index 575e9d604d..c1ea2013c8 100644
--- a/lib/chef/knife/data_bag_delete.rb
+++ b/lib/chef/knife/data_bag_delete.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class DataBagDelete < Knife
deps do
- require 'chef/data_bag'
+ require "chef/data_bag"
end
banner "knife data bag delete BAG [ITEM] (options)"
@@ -32,11 +32,11 @@ class Chef
def run
if @name_args.length == 2
delete_object(Chef::DataBagItem, @name_args[1], "data_bag_item") do
- rest.delete_rest("data/#{@name_args[0]}/#{@name_args[1]}")
+ rest.delete("data/#{@name_args[0]}/#{@name_args[1]}")
end
elsif @name_args.length == 1
delete_object(Chef::DataBag, @name_args[0], "data_bag") do
- rest.delete_rest("data/#{@name_args[0]}")
+ rest.delete("data/#{@name_args[0]}")
end
else
show_usage
@@ -47,5 +47,3 @@ class Chef
end
end
end
-
-
diff --git a/lib/chef/knife/data_bag_edit.rb b/lib/chef/knife/data_bag_edit.rb
index 6ef4b33f59..5d76762058 100644
--- a/lib/chef/knife/data_bag_edit.rb
+++ b/lib/chef/knife/data_bag_edit.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2009-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/data_bag_secret_options'
+require "chef/knife"
+require "chef/knife/data_bag_secret_options"
class Chef
class Knife
@@ -26,8 +26,8 @@ class Chef
include DataBagSecretOptions
deps do
- require 'chef/data_bag_item'
- require 'chef/encrypted_data_bag_item'
+ require "chef/data_bag_item"
+ require "chef/encrypted_data_bag_item"
end
banner "knife data bag edit BAG ITEM (options)"
@@ -49,29 +49,26 @@ class Chef
def run
if @name_args.length != 2
- stdout.puts "You must supply the data bag and an item to edit!"
+ stdout.puts "You must supply the data bag and an item to edit"
stdout.puts opt_parser
exit 1
end
item, was_encrypted = load_item(@name_args[0], @name_args[1])
- edited_item = edit_data(item)
+ edited_item = edit_hash(item)
if was_encrypted || encryption_secret_provided?
ui.info("Encrypting data bag using provided secret.")
item_to_save = Chef::EncryptedDataBagItem.encrypt_data_bag_item(edited_item, read_secret)
else
- ui.info("Saving data bag unencrypted. To encrypt it, provide an appropriate secret.")
+ ui.info("Saving data bag unencrypted. To encrypt it, provide an appropriate secret.")
item_to_save = edited_item
end
- rest.put_rest("data/#{@name_args[0]}/#{@name_args[1]}", item_to_save)
+ rest.put("data/#{@name_args[0]}/#{@name_args[1]}", item_to_save)
stdout.puts("Saved data_bag_item[#{@name_args[1]}]")
ui.output(edited_item) if config[:print_after]
end
end
end
end
-
-
-
diff --git a/lib/chef/knife/data_bag_from_file.rb b/lib/chef/knife/data_bag_from_file.rb
index d1b7daa4a2..30b9de3386 100644
--- a/lib/chef/knife/data_bag_from_file.rb
+++ b/lib/chef/knife/data_bag_from_file.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/util/path_helper'
-require 'chef/knife/data_bag_secret_options'
+require "chef/knife"
+require "chef/util/path_helper"
+require "chef/knife/data_bag_secret_options"
class Chef
class Knife
@@ -27,11 +27,11 @@ class Chef
include DataBagSecretOptions
deps do
- require 'chef/data_bag'
- require 'chef/data_bag_item'
- require 'chef/knife/core/object_loader'
- require 'chef/json_compat'
- require 'chef/encrypted_data_bag_item'
+ require "chef/data_bag"
+ require "chef/data_bag_item"
+ require "chef/knife/core/object_loader"
+ require "chef/json_compat"
+ require "chef/encrypted_data_bag_item"
end
banner "knife data bag from file BAG FILE|FOLDER [FILE|FOLDER..] (options)"
@@ -60,6 +60,7 @@ class Chef
end
private
+
def data_bags_path
@data_bag_path ||= "data_bags"
end
@@ -101,7 +102,7 @@ class Chef
paths = Array.new
args.each do |path|
if File.directory?(path)
- paths.concat(Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(path), "*.json")))
+ paths.concat(Dir.glob(File.join(Chef::Util::PathHelper.escape_glob_dir(path), "*.json")))
else
paths << path
end
diff --git a/lib/chef/knife/data_bag_list.rb b/lib/chef/knife/data_bag_list.rb
index 5e556b60bc..d507925ec8 100644
--- a/lib/chef/knife/data_bag_list.rb
+++ b/lib/chef/knife/data_bag_list.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class DataBagList < Knife
deps do
- require 'chef/data_bag'
+ require "chef/data_bag"
end
banner "knife data bag list (options)"
@@ -40,7 +40,3 @@ class Chef
end
end
end
-
-
-
-
diff --git a/lib/chef/knife/data_bag_secret_options.rb b/lib/chef/knife/data_bag_secret_options.rb
index 766006089e..4246c9edfa 100644
--- a/lib/chef/knife/data_bag_secret_options.rb
+++ b/lib/chef/knife/data_bag_secret_options.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tyler Ball (<tball@opscode.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Tyler Ball (<tball@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'mixlib/cli'
-require 'chef/config'
-require 'chef/encrypted_data_bag_item/check_encrypted'
+require "mixlib/cli"
+require "chef/config"
+require "chef/encrypted_data_bag_item/check_encrypted"
class Chef
class Knife
@@ -37,14 +37,14 @@ class Chef
base.option :secret,
:short => "-s SECRET",
:long => "--secret ",
- :description => "The secret key to use to encrypt data bag item values. Can also be defaulted in your config with the key 'secret'",
+ :description => "The secret key to use to encrypt data bag item values. Can also be defaulted in your config with the key 'secret'",
# Need to store value from command line in separate variable - knife#merge_configs populates same keys
# on config object from
:proc => Proc.new { |s| set_cl_secret(s) }
base.option :secret_file,
:long => "--secret-file SECRET_FILE",
- :description => "A file containing the secret key to use to encrypt data bag item values. Can also be defaulted in your config with the key 'secret_file'",
+ :description => "A file containing the secret key to use to encrypt data bag item values. Can also be defaulted in your config with the key 'secret_file'",
:proc => Proc.new { |sf| set_cl_secret_file(sf) }
base.option :encrypt,
@@ -65,7 +65,7 @@ class Chef
def read_secret
# Moving the non 'compile-time' requires into here to speed up knife command loading
# IE, if we are not running 'knife data bag *' we don't need to load 'chef/encrypted_data_bag_item'
- require 'chef/encrypted_data_bag_item'
+ require "chef/encrypted_data_bag_item"
if has_cl_secret?
config[:secret]
@@ -114,7 +114,7 @@ class Chef
# Certain situations (show and bootstrap) don't need a --encrypt flag to use the config file secret
return true
end
- return false
+ false
end
def has_cl_secret?
diff --git a/lib/chef/knife/data_bag_show.rb b/lib/chef/knife/data_bag_show.rb
index 36715286e8..ea9c390f19 100644
--- a/lib/chef/knife/data_bag_show.rb
+++ b/lib/chef/knife/data_bag_show.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2009-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/data_bag_secret_options'
+require "chef/knife"
+require "chef/knife/data_bag_secret_options"
class Chef
class Knife
@@ -26,8 +26,8 @@ class Chef
include DataBagSecretOptions
deps do
- require 'chef/data_bag'
- require 'chef/encrypted_data_bag_item'
+ require "chef/data_bag"
+ require "chef/encrypted_data_bag_item"
end
banner "knife data bag show BAG [ITEM] (options)"
@@ -35,32 +35,32 @@ class Chef
def run
display = case @name_args.length
- when 2 # Bag and Item names provided
- secret = encryption_secret_provided_ignore_encrypt_flag? ? read_secret : nil
- raw_data = Chef::DataBagItem.load(@name_args[0], @name_args[1]).raw_data
- encrypted = encrypted?(raw_data)
+ when 2 # Bag and Item names provided
+ secret = encryption_secret_provided_ignore_encrypt_flag? ? read_secret : nil
+ raw_data = Chef::DataBagItem.load(@name_args[0], @name_args[1]).raw_data
+ encrypted = encrypted?(raw_data)
- if encrypted && secret
- # Users do not need to pass --encrypt to read data, we simply try to use the provided secret
- ui.info("Encrypted data bag detected, decrypting with provided secret.")
- raw = Chef::EncryptedDataBagItem.load(@name_args[0],
- @name_args[1],
- secret)
- format_for_display(raw.to_hash)
- elsif encrypted && !secret
- ui.warn("Encrypted data bag detected, but no secret provided for decoding. Displaying encrypted data.")
- format_for_display(raw_data)
- else
- ui.info("Unencrypted data bag detected, ignoring any provided secret options.")
- format_for_display(raw_data)
- end
+ if encrypted && secret
+ # Users do not need to pass --encrypt to read data, we simply try to use the provided secret
+ ui.info("Encrypted data bag detected, decrypting with provided secret.")
+ raw = Chef::EncryptedDataBagItem.load(@name_args[0],
+ @name_args[1],
+ secret)
+ format_for_display(raw.to_hash)
+ elsif encrypted && !secret
+ ui.warn("Encrypted data bag detected, but no secret provided for decoding. Displaying encrypted data.")
+ format_for_display(raw_data)
+ else
+ ui.warn("Unencrypted data bag detected, ignoring any provided secret options.")
+ format_for_display(raw_data)
+ end
- when 1 # Only Bag name provided
- format_list_for_display(Chef::DataBag.load(@name_args[0]))
- else
- stdout.puts opt_parser
- exit(1)
- end
+ when 1 # Only Bag name provided
+ format_list_for_display(Chef::DataBag.load(@name_args[0]))
+ else
+ stdout.puts opt_parser
+ exit(1)
+ end
output(display)
end
diff --git a/lib/chef/knife/delete.rb b/lib/chef/knife/delete.rb
index 0030c45026..cf6ca09878 100644
--- a/lib/chef/knife/delete.rb
+++ b/lib/chef/knife/delete.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
class Chef
class Knife
@@ -8,22 +8,22 @@ class Chef
category "path-based"
deps do
- require 'chef/chef_fs/file_system'
+ require "chef/chef_fs/file_system"
end
option :recurse,
- :short => '-r',
- :long => '--[no-]recurse',
+ :short => "-r",
+ :long => "--[no-]recurse",
:boolean => true,
:default => false,
:description => "Delete directories recursively."
option :both,
- :long => '--both',
+ :long => "--both",
:boolean => true,
:default => false,
:description => "Delete both the local and remote copies."
option :local,
- :long => '--local',
+ :long => "--local",
:boolean => true,
:default => false,
:description => "Delete the local copy (leave the remote copy)."
@@ -31,7 +31,7 @@ class Chef
def run
if name_args.length == 0
show_usage
- ui.fatal("Must specify at least one argument. If you want to delete everything in this directory, type \"knife delete --recurse .\"")
+ ui.fatal("You must specify at least one argument. If you want to delete everything in this directory, run \"knife delete --recurse .\"")
exit 1
end
@@ -105,4 +105,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/knife/deps.rb b/lib/chef/knife/deps.rb
index 4b23468962..b5c6d6379a 100644
--- a/lib/chef/knife/deps.rb
+++ b/lib/chef/knife/deps.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
class Chef
class Knife
@@ -8,20 +8,20 @@ class Chef
category "path-based"
deps do
- require 'chef/chef_fs/file_system'
- require 'chef/run_list'
+ require "chef/chef_fs/file_system"
+ require "chef/run_list"
end
option :recurse,
- :long => '--[no-]recurse',
+ :long => "--[no-]recurse",
:boolean => true,
- :description => "List dependencies recursively (default: true). Only works with --tree."
+ :description => "List dependencies recursively (default: true). Only works with --tree."
option :tree,
- :long => '--tree',
+ :long => "--tree",
:boolean => true,
- :description => "Show dependencies in a visual tree. May show duplicates."
+ :description => "Show dependencies in a visual tree. May show duplicates."
option :remote,
- :long => '--remote',
+ :long => "--remote",
:boolean => true,
:description => "List dependencies on the server instead of the local filesystem"
@@ -61,60 +61,58 @@ class Chef
def print_dependencies_tree(entry, dependencies, printed = {}, depth = 0)
dependencies[entry.path] = get_dependencies(entry) if !dependencies[entry.path]
- output "#{' '*depth}#{format_path(entry)}"
+ output "#{' ' * depth}#{format_path(entry)}"
if !printed[entry.path] && (config[:recurse] || depth == 0)
printed[entry.path] = true
dependencies[entry.path].each do |child|
child_entry = Chef::ChefFS::FileSystem.resolve_path(@root, child)
- print_dependencies_tree(child_entry, dependencies, printed, depth+1)
+ print_dependencies_tree(child_entry, dependencies, printed, depth + 1)
end
end
end
def get_dependencies(entry)
- begin
- if entry.parent && entry.parent.path == '/cookbooks'
- return entry.chef_object.metadata.dependencies.keys.map { |cookbook| "/cookbooks/#{cookbook}" }
+ if entry.parent && entry.parent.path == "/cookbooks"
+ return entry.chef_object.metadata.dependencies.keys.map { |cookbook| "/cookbooks/#{cookbook}" }
- elsif entry.parent && entry.parent.path == '/nodes'
- node = Chef::JSONCompat.parse(entry.read)
- result = []
- if node['chef_environment'] && node['chef_environment'] != '_default'
- result << "/environments/#{node['chef_environment']}.json"
- end
- if node['run_list']
- result += dependencies_from_runlist(node['run_list'])
- end
- result
+ elsif entry.parent && entry.parent.path == "/nodes"
+ node = Chef::JSONCompat.parse(entry.read)
+ result = []
+ if node["chef_environment"] && node["chef_environment"] != "_default"
+ result << "/environments/#{node['chef_environment']}.json"
+ end
+ if node["run_list"]
+ result += dependencies_from_runlist(node["run_list"])
+ end
+ result
- elsif entry.parent && entry.parent.path == '/roles'
- role = Chef::JSONCompat.parse(entry.read)
- result = []
- if role['run_list']
- dependencies_from_runlist(role['run_list']).each do |dependency|
- result << dependency if !result.include?(dependency)
- end
+ elsif entry.parent && entry.parent.path == "/roles"
+ role = Chef::JSONCompat.parse(entry.read)
+ result = []
+ if role["run_list"]
+ dependencies_from_runlist(role["run_list"]).each do |dependency|
+ result << dependency if !result.include?(dependency)
end
- if role['env_run_lists']
- role['env_run_lists'].each_pair do |env,run_list|
- dependencies_from_runlist(run_list).each do |dependency|
- result << dependency if !result.include?(dependency)
- end
+ end
+ if role["env_run_lists"]
+ role["env_run_lists"].each_pair do |env, run_list|
+ dependencies_from_runlist(run_list).each do |dependency|
+ result << dependency if !result.include?(dependency)
end
end
- result
+ end
+ result
- elsif !entry.exists?
- raise Chef::ChefFS::FileSystem::NotFoundError.new(entry)
+ elsif !entry.exists?
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(entry)
- else
- []
- end
- rescue Chef::ChefFS::FileSystem::NotFoundError => e
- ui.error "#{format_path(e.entry)}: No such file or directory"
- self.exit_code = 2
+ else
[]
end
+ rescue Chef::ChefFS::FileSystem::NotFoundError => e
+ ui.error "#{format_path(e.entry)}: No such file or directory"
+ self.exit_code = 2
+ []
end
def dependencies_from_runlist(run_list)
diff --git a/lib/chef/knife/diff.rb b/lib/chef/knife/diff.rb
index e5eda5228c..d965490f0a 100644
--- a/lib/chef/knife/diff.rb
+++ b/lib/chef/knife/diff.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
class Chef
class Knife
@@ -8,33 +8,33 @@ class Chef
category "path-based"
deps do
- require 'chef/chef_fs/command_line'
+ require "chef/chef_fs/command_line"
end
option :recurse,
- :long => '--[no-]recurse',
+ :long => "--[no-]recurse",
:boolean => true,
:default => true,
:description => "List directories recursively."
option :name_only,
- :long => '--name-only',
+ :long => "--name-only",
:boolean => true,
:description => "Only show names of modified files."
option :name_status,
- :long => '--name-status',
+ :long => "--name-status",
:boolean => true,
:description => "Only show names and statuses of modified files: Added, Deleted, Modified, and Type Changed."
option :diff_filter,
- :long => '--diff-filter=[(A|D|M|T)...[*]]',
+ :long => "--diff-filter=[(A|D|M|T)...[*]]",
:description => "Select only files that are Added (A), Deleted (D), Modified (M), or have their type (i.e. regular file, directory) changed (T). Any combination of the filter characters (including none) can be used. When * (All-or-none) is added to the combination, all paths are selected if
there is any file that matches other criteria in the comparison; if there is no file that matches other criteria, nothing is selected."
option :cookbook_version,
- :long => '--cookbook-version VERSION',
- :description => 'Version of cookbook to download (if there are multiple versions and cookbook_versions is false)'
+ :long => "--cookbook-version VERSION",
+ :description => "Version of cookbook to download (if there are multiple versions and cookbook_versions is false)"
def run
if config[:name_only]
@@ -66,4 +66,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/knife/download.rb b/lib/chef/knife/download.rb
index 5a432afd47..ac8420d468 100644
--- a/lib/chef/knife/download.rb
+++ b/lib/chef/knife/download.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
class Chef
class Knife
@@ -8,48 +8,48 @@ class Chef
category "path-based"
deps do
- require 'chef/chef_fs/command_line'
+ require "chef/chef_fs/command_line"
end
option :recurse,
- :long => '--[no-]recurse',
+ :long => "--[no-]recurse",
:boolean => true,
:default => true,
:description => "List directories recursively."
option :purge,
- :long => '--[no-]purge',
+ :long => "--[no-]purge",
:boolean => true,
:default => false,
:description => "Delete matching local files and directories that do not exist remotely."
option :force,
- :long => '--[no-]force',
+ :long => "--[no-]force",
:boolean => true,
:default => false,
:description => "Force upload of files even if they match (quicker and harmless, but doesn't print out what it changed)"
option :dry_run,
- :long => '--dry-run',
- :short => '-n',
+ :long => "--dry-run",
+ :short => "-n",
:boolean => true,
:default => false,
:description => "Don't take action, only print what would happen"
option :diff,
- :long => '--[no-]diff',
+ :long => "--[no-]diff",
:boolean => true,
:default => true,
- :description => 'Turn off to avoid uploading existing files; only new (and possibly deleted) files with --no-diff'
+ :description => "Turn off to avoid uploading existing files; only new (and possibly deleted) files with --no-diff"
option :cookbook_version,
- :long => '--cookbook-version VERSION',
- :description => 'Version of cookbook to download (if there are multiple versions and cookbook_versions is false)'
+ :long => "--cookbook-version VERSION",
+ :description => "Version of cookbook to download (if there are multiple versions and cookbook_versions is false)"
def run
if name_args.length == 0
show_usage
- ui.fatal("Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"")
+ ui.fatal("You must specify at least one argument. If you want to download everything in this directory, run \"knife download .\"")
exit 1
end
@@ -66,4 +66,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/knife/edit.rb b/lib/chef/knife/edit.rb
index 7408179ed0..8489e4e179 100644
--- a/lib/chef/knife/edit.rb
+++ b/lib/chef/knife/edit.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
class Chef
class Knife
@@ -8,12 +8,12 @@ class Chef
category "path-based"
deps do
- require 'chef/chef_fs/file_system'
- require 'chef/chef_fs/file_system/not_found_error'
+ require "chef/chef_fs/file_system"
+ require "chef/chef_fs/file_system/not_found_error"
end
option :local,
- :long => '--local',
+ :long => "--local",
:boolean => true,
:description => "Show local files instead of remote"
@@ -32,7 +32,7 @@ class Chef
result.write(new_value)
output "Updated #{format_path(result)}"
else
- output "#{format_path(result)} unchanged!"
+ output "#{format_path(result)} unchanged"
end
rescue Chef::ChefFS::FileSystem::OperationNotAllowedError => e
ui.error "#{format_path(e.entry)}: #{e.reason}."
@@ -50,15 +50,15 @@ class Chef
end
def edit_text(text, extension)
- if (!config[:disable_editing])
- Tempfile.open([ 'knife-edit-', extension ]) do |file|
+ if !config[:disable_editing]
+ Tempfile.open([ "knife-edit-", extension ]) do |file|
# Write the text to a temporary file
file.write(text)
file.close
# Let the user edit the temporary file
if !system("#{config[:editor]} #{file.path}")
- raise "Please set EDITOR environment variable"
+ raise "Please set EDITOR environment variable. See https://docs.chef.io/knife_using.html for details."
end
result_text = IO.read(file.path)
@@ -70,4 +70,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/knife/environment_compare.rb b/lib/chef/knife/environment_compare.rb
index 792ec444ea..8a2ef853d3 100644
--- a/lib/chef/knife/environment_compare.rb
+++ b/lib/chef/knife/environment_compare.rb
@@ -1,6 +1,6 @@
#
# Author:: Sander Botman (<sbotman@schubergphilis.com>)
-# Copyright:: Copyright (c) 2013 Sander Botman.
+# Copyright:: Copyright 2013-2016, Sander Botman.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,37 +15,37 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
-require 'chef/knife'
-
+
+require "chef/knife"
+
class Chef
class Knife
class EnvironmentCompare < Knife
-
+
deps do
- require 'chef/environment'
+ require "chef/environment"
end
-
+
banner "knife environment compare [ENVIRONMENT..] (options)"
option :all,
:short => "-a",
:long => "--all",
:description => "Show all cookbooks",
- :boolean => true
+ :boolean => true
option :mismatch,
:short => "-m",
:long => "--mismatch",
:description => "Only show mismatching versions",
:boolean => true
-
+
def run
# Get the commandline environments or all if none are provided.
- environments = environment_list
+ environments = environment_list
# Get a list of all cookbooks that have constraints and their environment.
- constraints = constraint_list(environments)
+ constraints = constraint_list(environments)
# Get the total list of cookbooks that have constraints
cookbooks = cookbook_list(constraints)
@@ -55,12 +55,12 @@ class Chef
ui.error "Cannot find any environment cookbook constraints"
exit 1
end
-
+
# Get all cookbooks so we can compare them all
- cookbooks = rest.get_rest("/cookbooks?num_versions=1") if config[:all]
+ cookbooks = rest.get("/cookbooks?num_versions=1") if config[:all]
# display matrix view of in the requested format.
- if config[:format] == 'summary'
+ if config[:format] == "summary"
matrix = matrix_output(cookbooks, constraints)
ui.output(matrix)
else
@@ -77,11 +77,11 @@ class Chef
else
environments = Chef::Environment.list
end
- end
+ end
def constraint_list(environments)
constraints = {}
- environments.each do |env,url|
+ environments.each do |env, url|
# Because you cannot modify the default environment I filter it out here.
unless env == "_default"
envdata = Chef::Environment.load(env)
@@ -91,22 +91,22 @@ class Chef
end
constraints
end
-
+
def cookbook_list(constraints)
result = {}
constraints.each { |env, cb| result.merge!(cb) }
result
- end
+ end
def matrix_output(cookbooks, constraints)
- rows = [ '' ]
+ rows = [ "" ]
environments = []
- constraints.each { |e,v| environments << e.to_s }
+ constraints.each { |e, v| environments << e.to_s }
columns = environments.count + 1
environments.each { |env| rows << ui.color(env, :bold) }
- cookbooks.each do |c,v|
+ cookbooks.each do |c, v|
total = []
- environments.each { |n| total << constraints[n][c]}
+ environments.each { |n| total << constraints[n][c] }
if total.uniq.count == 1
next if config[:mismatch]
color = :white
@@ -116,7 +116,7 @@ class Chef
rows << ui.color(c, :bold)
environments.each do |e|
tag = constraints[e][c] || "latest"
- rows << ui.color(tag, color)
+ rows << ui.color(tag, color)
end
end
ui.list(rows, :uneven_columns_across, columns)
diff --git a/lib/chef/knife/environment_create.rb b/lib/chef/knife/environment_create.rb
index 6bc00d52b9..cfc1bc268c 100644
--- a/lib/chef/knife/environment_create.rb
+++ b/lib/chef/knife/environment_create.rb
@@ -1,6 +1,6 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class EnvironmentCreate < Knife
deps do
- require 'chef/environment'
- require 'chef/json_compat'
+ require "chef/environment"
+ require "chef/json_compat"
end
banner "knife environment create ENVIRONMENT (options)"
@@ -46,7 +46,7 @@ class Chef
env = Chef::Environment.new
env.name(env_name)
env.description(config[:description]) if config[:description]
- create_object(env)
+ create_object(env, object_class: Chef::Environment)
end
end
end
diff --git a/lib/chef/knife/environment_delete.rb b/lib/chef/knife/environment_delete.rb
index e17841f805..869d1c74fe 100644
--- a/lib/chef/knife/environment_delete.rb
+++ b/lib/chef/knife/environment_delete.rb
@@ -1,6 +1,6 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class EnvironmentDelete < Knife
deps do
- require 'chef/environment'
- require 'chef/json_compat'
+ require "chef/environment"
+ require "chef/json_compat"
end
banner "knife environment delete ENVIRONMENT (options)"
diff --git a/lib/chef/knife/environment_edit.rb b/lib/chef/knife/environment_edit.rb
index 54962ac20d..43f0b067ae 100644
--- a/lib/chef/knife/environment_edit.rb
+++ b/lib/chef/knife/environment_edit.rb
@@ -1,6 +1,6 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class EnvironmentEdit < Knife
deps do
- require 'chef/environment'
- require 'chef/json_compat'
+ require "chef/environment"
+ require "chef/json_compat"
end
banner "knife environment edit ENVIRONMENT (options)"
diff --git a/lib/chef/knife/environment_from_file.rb b/lib/chef/knife/environment_from_file.rb
index 3812024c9c..5272c8934a 100644
--- a/lib/chef/knife/environment_from_file.rb
+++ b/lib/chef/knife/environment_from_file.rb
@@ -1,6 +1,6 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,8 +21,8 @@ class Chef
class EnvironmentFromFile < Knife
deps do
- require 'chef/environment'
- require 'chef/knife/core/object_loader'
+ require "chef/environment"
+ require "chef/knife/core/object_loader"
end
banner "knife environment from file FILE [FILE..] (options)"
@@ -62,7 +62,6 @@ class Chef
ui.info("Updated Environment #{updated.name}")
end
-
def run
if config[:all] == true
load_all_environments
diff --git a/lib/chef/knife/environment_list.rb b/lib/chef/knife/environment_list.rb
index 4e70818093..f278046bf9 100644
--- a/lib/chef/knife/environment_list.rb
+++ b/lib/chef/knife/environment_list.rb
@@ -1,6 +1,6 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class EnvironmentList < Knife
deps do
- require 'chef/environment'
- require 'chef/json_compat'
+ require "chef/environment"
+ require "chef/json_compat"
end
banner "knife environment list (options)"
diff --git a/lib/chef/knife/environment_show.rb b/lib/chef/knife/environment_show.rb
index 2dd07fe6e9..6d260adbd6 100644
--- a/lib/chef/knife/environment_show.rb
+++ b/lib/chef/knife/environment_show.rb
@@ -1,6 +1,6 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -25,8 +25,8 @@ class Chef
include Knife::Core::MultiAttributeReturnOption
deps do
- require 'chef/environment'
- require 'chef/json_compat'
+ require "chef/environment"
+ require "chef/json_compat"
end
banner "knife environment show ENVIRONMENT (options)"
diff --git a/lib/chef/knife/exec.rb b/lib/chef/knife/exec.rb
index ace4ee2300..0aa8ea2ba8 100644
--- a/lib/chef/knife/exec.rb
+++ b/lib/chef/knife/exec.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/util/path_helper'
+require "chef/knife"
+require "chef/util/path_helper"
class Chef::Knife::Exec < Chef::Knife
@@ -35,15 +35,15 @@ class Chef::Knife::Exec < Chef::Knife
:proc => lambda { |o| o.split(":") }
deps do
- require 'chef/shell/ext'
+ require "chef/shell/ext"
end
def run
config[:script_path] ||= Array(Chef::Config[:script_path])
# Default script paths are chef-repo/.chef/scripts and ~/.chef/scripts
- config[:script_path] << File.join(Chef::Knife.chef_config_dir, 'scripts') if Chef::Knife.chef_config_dir
- Chef::Util::PathHelper.home('.chef', 'scripts') { |p| config[:script_path] << p }
+ config[:script_path] << File.join(Chef::Knife.chef_config_dir, "scripts") if Chef::Knife.chef_config_dir
+ Chef::Util::PathHelper.home(".chef", "scripts") { |p| config[:script_path] << p }
scripts = Array(name_args)
context = Object.new
diff --git a/lib/chef/knife/help.rb b/lib/chef/knife/help.rb
index 13fe674704..075bf4b310 100644
--- a/lib/chef/knife/help.rb
+++ b/lib/chef/knife/help.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -40,17 +40,15 @@ class Chef
MOAR_HELP
exit 1
else
- @query = name_args.join('-')
+ @query = name_args.join("-")
end
-
-
case @query
- when 'topics', 'list'
+ when "topics", "list"
print_help_topics
exit 1
- when 'intro', 'knife'
- @topic = 'knife'
+ when "intro", "knife"
+ @topic = "knife"
else
@topic = find_manpages_for_query(@query)
end
@@ -67,7 +65,7 @@ MOAR_HELP
def print_help_topics
ui.info "Available help topics are: "
- help_topics.collect {|t| t.gsub(/knife-/, '') }.sort.each do |topic|
+ help_topics.collect { |t| t.gsub(/knife-/, "") }.sort.each do |topic|
ui.msg " #{topic}"
end
end
@@ -92,7 +90,7 @@ MOAR_HELP
def find_manpage_path(topic)
if ::File.exists?(::File.expand_path("../distro/common/man/man1/#{topic}.1", CHEF_ROOT))
# If we've provided the man page in the gem, give that
- return ::File.expand_path("../distro/common/man/man1/#{topic}.1", CHEF_ROOT)
+ ::File.expand_path("../distro/common/man/man1/#{topic}.1", CHEF_ROOT)
else
# Otherwise, we'll just be using MANPATH
topic
diff --git a/lib/chef/knife/index_rebuild.rb b/lib/chef/knife/index_rebuild.rb
index 4b9fcdd159..206b7b0fbf 100644
--- a/lib/chef/knife/index_rebuild.rb
+++ b/lib/chef/knife/index_rebuild.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -38,9 +38,8 @@ class Chef
else
deprecated_server_message
nag
- output rest.post_rest("/search/reindex", {})
+ output rest.post("/search/reindex", {})
end
-
end
def grab_api_info
@@ -50,7 +49,7 @@ class Chef
# for a node we know won't exist; the 404 response that comes
# back will give us what we want
dummy_node = "knife_index_rebuild_test_#{rand(1000000)}"
- rest.get_rest("/nodes/#{dummy_node}")
+ rest.get("/nodes/#{dummy_node}")
rescue Net::HTTPServerException => exception
r = exception.response
parse_api_info(r)
@@ -69,11 +68,11 @@ class Chef
end
def deprecated_server_message
- ui.warn("'knife index rebuild' has been removed for Chef 11+ servers. It will continue to work for prior versions, however.")
+ ui.warn("'knife index rebuild' has been removed for Chef 11+ servers. It will continue to work for prior versions, however.")
end
def nag
- ui.info("This operation is destructive. Rebuilding the index may take some time.")
+ ui.info("This operation is destructive. Rebuilding the index may take some time.")
ui.confirm("Continue")
end
diff --git a/lib/chef/knife/key_create.rb b/lib/chef/knife/key_create.rb
index 5ee36e9793..a9f9da97a7 100644
--- a/lib/chef/knife/key_create.rb
+++ b/lib/chef/knife/key_create.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/key'
-require 'chef/json_compat'
-require 'chef/exceptions'
+require "chef/key"
+require "chef/json_compat"
+require "chef/exceptions"
class Chef
class Knife
@@ -40,7 +40,7 @@ class Chef
end
def public_key_or_key_name_error_msg
-<<EOS
+ <<EOS
You must pass either --public-key or --key-name, or both.
If you only pass --public-key, a key name will be generated from the fingerprint of your key.
If you only pass --key-name, a key pair will be generated by the server.
@@ -51,6 +51,10 @@ EOS
@ui.edit_data(key)
end
+ def edit_hash(key)
+ @ui.edit_hash(key)
+ end
+
def display_info(input)
@ui.info(input)
end
@@ -91,7 +95,7 @@ EOS
key.expiration_date("infinity")
end
- output = edit_data(key)
+ output = edit_hash(key)
key = create_key_from_hash(output)
display_info("Created key: #{key.name}")
diff --git a/lib/chef/knife/key_create_base.rb b/lib/chef/knife/key_create_base.rb
index da31f70d1d..d02d5ee180 100644
--- a/lib/chef/knife/key_create_base.rb
+++ b/lib/chef/knife/key_create_base.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/knife/key_delete.rb b/lib/chef/knife/key_delete.rb
index fb996cff17..a798e06475 100644
--- a/lib/chef/knife/key_delete.rb
+++ b/lib/chef/knife/key_delete.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/key'
+require "chef/key"
class Chef
class Knife
@@ -39,7 +39,7 @@ class Chef
end
def print_destroyed
- @ui.info("Destroyed key named #{@name} for the #{@actor_field_name} named #{@actor}")
+ @ui.info("Deleted key named #{@name} for the #{@actor_field_name} named #{@actor}")
end
def run
diff --git a/lib/chef/knife/key_edit.rb b/lib/chef/knife/key_edit.rb
index 48ae344e6e..8490d10fa5 100644
--- a/lib/chef/knife/key_edit.rb
+++ b/lib/chef/knife/key_edit.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/key'
-require 'chef/json_compat'
-require 'chef/exceptions'
+require "chef/key"
+require "chef/json_compat"
+require "chef/exceptions"
class Chef
class Knife
@@ -41,7 +41,7 @@ class Chef
end
def public_key_and_create_key_error_msg
-<<EOS
+ <<EOS
You passed both --public-key and --create-key. Only pass one, or the other, or neither.
Do not pass either if you do not want to change the public_key field of your key.
Pass --public-key if you want to update the public_key field of your key from a specific public key.
@@ -53,6 +53,10 @@ EOS
@ui.edit_data(key)
end
+ def edit_hash(key)
+ @ui.edit_hash(key)
+ end
+
def display_info(input)
@ui.info(input)
end
@@ -95,7 +99,7 @@ EOS
key.expiration_date(@config[:expiration_date])
end
- output = edit_data(key)
+ output = edit_hash(key)
key = update_key_from_hash(output)
to_display = "Updated key: #{key.name}"
diff --git a/lib/chef/knife/key_edit_base.rb b/lib/chef/knife/key_edit_base.rb
index bb5a951a5b..1a613ef1bc 100644
--- a/lib/chef/knife/key_edit_base.rb
+++ b/lib/chef/knife/key_edit_base.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/knife/key_list.rb b/lib/chef/knife/key_list.rb
index e96a27161f..9a820b7a50 100644
--- a/lib/chef/knife/key_list.rb
+++ b/lib/chef/knife/key_list.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/key'
-require 'chef/json_compat'
-require 'chef/exceptions'
+require "chef/key"
+require "chef/json_compat"
+require "chef/exceptions"
class Chef
class Knife
@@ -40,7 +40,7 @@ class Chef
end
def expired_and_non_expired_msg
-<<EOS
+ <<EOS
You cannot pass both --only-expired and --only-non-expired.
Please pass one or none.
EOS
@@ -64,21 +64,21 @@ EOS
if @config[:with_details]
max_length = 0
keys.each do |key|
- key['name'] = key['name'] + ":"
- max_length = key['name'].length if key['name'].length > max_length
+ key["name"] = key["name"] + ":"
+ max_length = key["name"].length if key["name"].length > max_length
end
keys.each do |key|
- next if !key['expired'] && @config[:only_expired]
- next if key['expired'] && @config[:only_non_expired]
+ next if !key["expired"] && @config[:only_expired]
+ next if key["expired"] && @config[:only_non_expired]
display = "#{colorize(key['name'].ljust(max_length))} #{key['uri']}"
display = "#{display} (expired)" if key["expired"]
display_info(display)
end
else
keys.each do |key|
- next if !key['expired'] && @config[:only_expired]
- next if key['expired'] && @config[:only_non_expired]
- display_info(key['name'])
+ next if !key["expired"] && @config[:only_expired]
+ next if key["expired"] && @config[:only_non_expired]
+ display_info(key["name"])
end
end
end
diff --git a/lib/chef/knife/key_list_base.rb b/lib/chef/knife/key_list_base.rb
index 861db0d75a..95858e9ba1 100644
--- a/lib/chef/knife/key_list_base.rb
+++ b/lib/chef/knife/key_list_base.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/knife/key_show.rb b/lib/chef/knife/key_show.rb
index 522f7a1a77..851db7208b 100644
--- a/lib/chef/knife/key_show.rb
+++ b/lib/chef/knife/key_show.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/key'
-require 'chef/json_compat'
-require 'chef/exceptions'
+require "chef/key"
+require "chef/json_compat"
+require "chef/exceptions"
class Chef
class Knife
diff --git a/lib/chef/knife/list.rb b/lib/chef/knife/list.rb
index 137d61f3a5..6f314eb86d 100644
--- a/lib/chef/knife/list.rb
+++ b/lib/chef/knife/list.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
class Chef
class Knife
@@ -8,33 +8,33 @@ class Chef
category "path-based"
deps do
- require 'chef/chef_fs/file_system'
- require 'highline'
+ require "chef/chef_fs/file_system"
+ require "highline"
end
option :recursive,
- :short => '-R',
+ :short => "-R",
:boolean => true,
:description => "List directories recursively"
option :bare_directories,
- :short => '-d',
+ :short => "-d",
:boolean => true,
:description => "When directories match the pattern, do not show the directories' children"
option :local,
- :long => '--local',
+ :long => "--local",
:boolean => true,
:description => "List local directory instead of remote"
option :flat,
- :short => '-f',
- :long => '--flat',
+ :short => "-f",
+ :long => "--flat",
:boolean => true,
:description => "Show a list of filenames rather than the prettified ls-like output normally produced"
option :one_column,
- :short => '-1',
+ :short => "-1",
:boolean => true,
:description => "Show only one column of results"
option :trailing_slashes,
- :short => '-p',
+ :short => "-p",
:boolean => true,
:description => "Show trailing slashes after directories"
@@ -44,9 +44,9 @@ class Chef
patterns = name_args.length == 0 ? [""] : name_args
# Get the top-level matches
- args = pattern_args_from(patterns)
all_results = parallelize(pattern_args_from(patterns)) do |pattern|
pattern_results = Chef::ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern).to_a
+
if pattern_results.first && !pattern_results.first.exists? && pattern.exact_path
ui.error "#{format_path(pattern_results.first)}: No such file or directory"
self.exit_code = 1
@@ -94,10 +94,10 @@ class Chef
printed_something = true
end
output "#{format_path(result)}:"
- print_results(children.map { |result| maybe_add_slash(result.name, result.dir?) }.sort, "")
+ print_results(children.map { |result| maybe_add_slash(result.display_name, result.dir?) }.sort, "")
end
- exit self.exit_code if self.exit_code
+ exit exit_code if exit_code
end
def add_dir_result(result)
@@ -129,17 +129,17 @@ class Chef
else
columns = HighLine::SystemExtensions.terminal_size[0]
end
- current_line = ''
+ current_line = ""
results.each do |result|
if current_line.length > 0 && current_line.length + print_space > columns
output current_line.rstrip
- current_line = ''
+ current_line = ""
end
if current_line.length == 0
current_line << indent
end
current_line << result
- current_line << (' ' * (print_space - result.length))
+ current_line << (" " * (print_space - result.length))
end
output current_line.rstrip if current_line.length > 0
end
diff --git a/lib/chef/knife/node_bulk_delete.rb b/lib/chef/knife/node_bulk_delete.rb
index 89b2abe6ae..2ca63da512 100644
--- a/lib/chef/knife/node_bulk_delete.rb
+++ b/lib/chef/knife/node_bulk_delete.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class NodeBulkDelete < Knife
deps do
- require 'chef/node'
- require 'chef/json_compat'
+ require "chef/node"
+ require "chef/json_compat"
end
banner "knife node bulk delete REGEX (options)"
@@ -35,7 +35,6 @@ class Chef
exit 42
end
-
nodes_to_delete = {}
matcher = /#{name_args[0]}/
@@ -55,7 +54,6 @@ class Chef
ui.msg("")
ui.confirm("Are you sure you want to delete these nodes")
-
nodes_to_delete.sort.each do |name, node|
node.destroy
ui.msg("Deleted node #{name}")
@@ -66,7 +64,7 @@ class Chef
node_uris_by_name = Chef::Node.list
node_uris_by_name.keys.inject({}) do |nodes_by_name, name|
- nodes_by_name[name] = Chef::Node.new.tap {|n| n.name(name)}
+ nodes_by_name[name] = Chef::Node.new.tap { |n| n.name(name) }
nodes_by_name
end
end
@@ -74,7 +72,3 @@ class Chef
end
end
end
-
-
-
-
diff --git a/lib/chef/knife/node_create.rb b/lib/chef/knife/node_create.rb
index 7f50a30c80..f80ac9e87c 100644
--- a/lib/chef/knife/node_create.rb
+++ b/lib/chef/knife/node_create.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class NodeCreate < Knife
deps do
- require 'chef/node'
- require 'chef/json_compat'
+ require "chef/node"
+ require "chef/json_compat"
end
banner "knife node create NODE (options)"
@@ -40,11 +40,8 @@ class Chef
node = Chef::Node.new
node.name(@node_name)
- create_object(node)
+ create_object(node, object_class: Chef::Node)
end
end
end
end
-
-
-
diff --git a/lib/chef/knife/node_delete.rb b/lib/chef/knife/node_delete.rb
index a645d32035..b03569cded 100644
--- a/lib/chef/knife/node_delete.rb
+++ b/lib/chef/knife/node_delete.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,32 +16,31 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class NodeDelete < Knife
deps do
- require 'chef/node'
- require 'chef/json_compat'
+ require "chef/node"
+ require "chef/json_compat"
end
- banner "knife node delete NODE (options)"
+ banner "knife node delete [NODE[,NODE]] (options)"
def run
- @node_name = @name_args[0]
-
- if @node_name.nil?
+ if @name_args.length == 0
show_usage
- ui.fatal("You must specify a node name")
+ ui.fatal("You must specify at least one node name")
exit 1
end
- delete_object(Chef::Node, @node_name)
+ @name_args.each do |node_name|
+ delete_object(Chef::Node, node_name)
+ end
end
end
end
end
-
diff --git a/lib/chef/knife/node_edit.rb b/lib/chef/knife/node_edit.rb
index 0d6b8fcf6c..4632c0a5b4 100644
--- a/lib/chef/knife/node_edit.rb
+++ b/lib/chef/knife/node_edit.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -24,9 +24,9 @@ class Chef
class NodeEdit < Knife
deps do
- require 'chef/node'
- require 'chef/json_compat'
- require 'chef/knife/core/node_editor'
+ require "chef/node"
+ require "chef/json_compat"
+ require "chef/knife/core/node_editor"
end
banner "knife node edit NODE (options)"
@@ -68,5 +68,3 @@ class Chef
end
end
end
-
-
diff --git a/lib/chef/knife/node_environment_set.rb b/lib/chef/knife/node_environment_set.rb
index da72aeaab8..ecba01be29 100644
--- a/lib/chef/knife/node_environment_set.rb
+++ b/lib/chef/knife/node_environment_set.rb
@@ -1,6 +1,6 @@
#
# Author:: Jimmy McCrory (<jimmy.mccrory@gmail.com>)
-# Copyright:: Copyright (c) 2014 Jimmy McCrory
+# Copyright:: Copyright 2014-2016, Jimmy McCrory
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class NodeEnvironmentSet < Knife
deps do
- require 'chef/node'
+ require "chef/node"
end
banner "knife node environment set NODE ENVIRONMENT"
@@ -46,7 +46,7 @@ class Chef
config[:attribute] = "chef_environment"
- output(format_for_display(node))
+ output(format_for_display(node))
end
end
diff --git a/lib/chef/knife/node_from_file.rb b/lib/chef/knife/node_from_file.rb
index 66f2a466fd..61b83edd92 100644
--- a/lib/chef/knife/node_from_file.rb
+++ b/lib/chef/knife/node_from_file.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class NodeFromFile < Knife
deps do
- require 'chef/node'
- require 'chef/json_compat'
- require 'chef/knife/core/object_loader'
+ require "chef/node"
+ require "chef/json_compat"
+ require "chef/knife/core/object_loader"
end
banner "knife node from file FILE (options)"
@@ -36,13 +36,13 @@ class Chef
def run
@name_args.each do |arg|
- updated = loader.load_from('nodes', arg)
-
+ updated = loader.load_from("nodes", arg)
+
updated.save
-
+
output(format_for_display(updated)) if config[:print_after]
-
- ui.info("Updated Node #{updated.name}!")
+
+ ui.info("Updated Node #{updated.name}")
end
end
diff --git a/lib/chef/knife/node_list.rb b/lib/chef/knife/node_list.rb
index 3926d101cf..4885208136 100644
--- a/lib/chef/knife/node_list.rb
+++ b/lib/chef/knife/node_list.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class NodeList < Knife
deps do
- require 'chef/node'
- require 'chef/json_compat'
+ require "chef/node"
+ require "chef/json_compat"
end
banner "knife node list (options)"
@@ -42,5 +42,3 @@ class Chef
end
end
end
-
-
diff --git a/lib/chef/knife/node_run_list_add.rb b/lib/chef/knife/node_run_list_add.rb
index 519c280400..f8d40c8321 100644
--- a/lib/chef/knife/node_run_list_add.rb
+++ b/lib/chef/knife/node_run_list_add.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class NodeRunListAdd < Knife
deps do
- require 'chef/node'
- require 'chef/json_compat'
+ require "chef/node"
+ require "chef/json_compat"
end
banner "knife node run_list add [NODE] [ENTRY[,ENTRY]] (options)"
@@ -44,11 +44,11 @@ class Chef
if @name_args.size > 2
# Check for nested lists and create a single plain one
entries = @name_args[1..-1].map do |entry|
- entry.split(',').map { |e| e.strip }
+ entry.split(",").map { |e| e.strip }
end.flatten
else
# Convert to array and remove the extra spaces
- entries = @name_args[1].split(',').map { |e| e.strip }
+ entries = @name_args[1].split(",").map { |e| e.strip }
end
if config[:after] && config[:before]
@@ -73,7 +73,7 @@ class Chef
private
- def add_to_run_list_after(node, entries, after=nil)
+ def add_to_run_list_after(node, entries, after = nil)
if after
nlist = []
node.run_list.each do |entry|
diff --git a/lib/chef/knife/node_run_list_remove.rb b/lib/chef/knife/node_run_list_remove.rb
index ef03c176b8..3f9cdabfff 100644
--- a/lib/chef/knife/node_run_list_remove.rb
+++ b/lib/chef/knife/node_run_list_remove.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class NodeRunListRemove < Knife
deps do
- require 'chef/node'
- require 'chef/json_compat'
+ require "chef/node"
+ require "chef/json_compat"
end
banner "knife node run_list remove [NODE] [ENTRY[,ENTRY]] (options)"
@@ -35,11 +35,11 @@ class Chef
if @name_args.size > 2
# Check for nested lists and create a single plain one
entries = @name_args[1..-1].map do |entry|
- entry.split(',').map { |e| e.strip }
+ entry.split(",").map { |e| e.strip }
end.flatten
else
# Convert to array and remove the extra spaces
- entries = @name_args[1].split(',').map { |e| e.strip }
+ entries = @name_args[1].split(",").map { |e| e.strip }
end
# iterate over the list of things to remove,
@@ -50,7 +50,7 @@ class Chef
else
ui.warn "#{e} is not in the run list"
unless e =~ /^(recipe|role)\[/
- ui.warn '(did you forget recipe[] or role[] around it?)'
+ ui.warn "(did you forget recipe[] or role[] around it?)"
end
end
end
diff --git a/lib/chef/knife/node_run_list_set.rb b/lib/chef/knife/node_run_list_set.rb
index e327d2acee..2d68c88415 100644
--- a/lib/chef/knife/node_run_list_set.rb
+++ b/lib/chef/knife/node_run_list_set.rb
@@ -1,6 +1,6 @@
#
# Author:: Mike Fiedler (<miketheman@gmail.com>)
-# Copyright:: Copyright (c) 2013 Mike Fiedler
+# Copyright:: Copyright 2013-2016, Mike Fiedler
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class NodeRunListSet < Knife
deps do
- require 'chef/node'
- require 'chef/json_compat'
+ require "chef/node"
+ require "chef/json_compat"
end
banner "knife node run_list set NODE ENTRIES (options)"
@@ -37,11 +37,11 @@ class Chef
elsif @name_args.size > 2
# Check for nested lists and create a single plain one
entries = @name_args[1..-1].map do |entry|
- entry.split(',').map { |e| e.strip }
+ entry.split(",").map { |e| e.strip }
end.flatten
else
# Convert to array and remove the extra spaces
- entries = @name_args[1].split(',').map { |e| e.strip }
+ entries = @name_args[1].split(",").map { |e| e.strip }
end
node = Chef::Node.load(@name_args[0])
diff --git a/lib/chef/knife/node_show.rb b/lib/chef/knife/node_show.rb
index dc47da1e8f..3092b3fc27 100644
--- a/lib/chef/knife/node_show.rb
+++ b/lib/chef/knife/node_show.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/core/node_presenter'
+require "chef/knife"
+require "chef/knife/core/node_presenter"
class Chef
class Knife
@@ -27,8 +27,8 @@ class Chef
include Knife::Core::MultiAttributeReturnOption
deps do
- require 'chef/node'
- require 'chef/json_compat'
+ require "chef/node"
+ require "chef/json_compat"
end
banner "knife node show NODE (options)"
@@ -55,13 +55,7 @@ class Chef
node = Chef::Node.load(@node_name)
output(format_for_display(node))
- self.class.attrs_to_show = []
- end
-
- def self.attrs_to_show=(attrs)
- @attrs_to_show = attrs
end
end
end
end
-
diff --git a/lib/chef/knife/osc_user_create.rb b/lib/chef/knife/osc_user_create.rb
index 6c3415473f..74b50a4ef4 100644
--- a/lib/chef/knife/osc_user_create.rb
+++ b/lib/chef/knife/osc_user_create.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
# DEPRECATION NOTE
# This code only remains to support users still operating with
@@ -27,8 +27,8 @@ class Chef
class OscUserCreate < Knife
deps do
- require 'chef/user'
- require 'chef/json_compat'
+ require "chef/user"
+ require "chef/json_compat"
end
option :file,
@@ -50,7 +50,7 @@ class Chef
option :user_key,
:long => "--user-key FILENAME",
- :description => "Public key for newly created user. By default a key will be created for you."
+ :description => "Public key for newly created user. By default a key will be created for you."
banner "knife osc_user create USER (options)"
@@ -78,7 +78,7 @@ class Chef
user.public_key File.read(File.expand_path(config[:user_key]))
end
- output = edit_data(user)
+ output = edit_hash(user)
user = Chef::User.from_hash(output).create
ui.info("Created #{user}")
diff --git a/lib/chef/knife/osc_user_delete.rb b/lib/chef/knife/osc_user_delete.rb
index 5cd4f10413..51abc1c668 100644
--- a/lib/chef/knife/osc_user_delete.rb
+++ b/lib/chef/knife/osc_user_delete.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
# DEPRECATION NOTE
# This code only remains to support users still operating with
@@ -28,8 +28,8 @@ class Chef
class OscUserDelete < Knife
deps do
- require 'chef/user'
- require 'chef/json_compat'
+ require "chef/user"
+ require "chef/json_compat"
end
banner "knife osc_user delete USER (options)"
diff --git a/lib/chef/knife/osc_user_edit.rb b/lib/chef/knife/osc_user_edit.rb
index 526475db05..89986c6f04 100644
--- a/lib/chef/knife/osc_user_edit.rb
+++ b/lib/chef/knife/osc_user_edit.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
# DEPRECATION NOTE
# This code only remains to support users still operating with
@@ -28,8 +28,8 @@ class Chef
class OscUserEdit < Knife
deps do
- require 'chef/user'
- require 'chef/json_compat'
+ require "chef/user"
+ require "chef/json_compat"
end
banner "knife osc_user edit USER (options)"
@@ -44,13 +44,13 @@ class Chef
end
original_user = Chef::User.load(@user_name).to_hash
- edited_user = edit_data(original_user)
+ edited_user = edit_hash(original_user)
if original_user != edited_user
user = Chef::User.from_hash(edited_user)
user.update
ui.msg("Saved #{user}.")
else
- ui.msg("User unchaged, not saving.")
+ ui.msg("User unchanged, not saving.")
end
end
end
diff --git a/lib/chef/knife/osc_user_list.rb b/lib/chef/knife/osc_user_list.rb
index 84fca31899..f1002c4f54 100644
--- a/lib/chef/knife/osc_user_list.rb
+++ b/lib/chef/knife/osc_user_list.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
# DEPRECATION NOTE
# This code only remains to support users still operating with
@@ -28,8 +28,8 @@ class Chef
class OscUserList < Knife
deps do
- require 'chef/user'
- require 'chef/json_compat'
+ require "chef/user"
+ require "chef/json_compat"
end
banner "knife osc_user list (options)"
diff --git a/lib/chef/knife/osc_user_reregister.rb b/lib/chef/knife/osc_user_reregister.rb
index 163b286fe0..b513f31328 100644
--- a/lib/chef/knife/osc_user_reregister.rb
+++ b/lib/chef/knife/osc_user_reregister.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
# DEPRECATION NOTE
# This code only remains to support users still operating with
@@ -28,8 +28,8 @@ class Chef
class OscUserReregister < Knife
deps do
- require 'chef/user'
- require 'chef/json_compat'
+ require "chef/user"
+ require "chef/json_compat"
end
banner "knife osc_user reregister USER (options)"
diff --git a/lib/chef/knife/osc_user_show.rb b/lib/chef/knife/osc_user_show.rb
index cb3a77585a..5350837ad3 100644
--- a/lib/chef/knife/osc_user_show.rb
+++ b/lib/chef/knife/osc_user_show.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
# DEPRECATION NOTE
# This code only remains to support users still operating with
@@ -30,8 +30,8 @@ class Chef
include Knife::Core::MultiAttributeReturnOption
deps do
- require 'chef/user'
- require 'chef/json_compat'
+ require "chef/user"
+ require "chef/json_compat"
end
banner "knife osc_user show USER (options)"
@@ -48,7 +48,6 @@ class Chef
user = Chef::User.load(@user_name)
output(format_for_display(user))
end
-
end
end
end
diff --git a/lib/chef/knife/raw.rb b/lib/chef/knife/raw.rb
index 601cfcef9b..76b83d2212 100644
--- a/lib/chef/knife/raw.rb
+++ b/lib/chef/knife/raw.rb
@@ -1,4 +1,5 @@
-require 'chef/knife'
+require "chef/knife"
+require "chef/http"
class Chef
class Knife
@@ -6,37 +7,37 @@ class Chef
banner "knife raw REQUEST_PATH"
deps do
- require 'chef/json_compat'
- require 'chef/config'
- require 'chef/http'
- require 'chef/http/authenticator'
- require 'chef/http/cookie_manager'
- require 'chef/http/decompressor'
- require 'chef/http/json_output'
+ require "chef/json_compat"
+ require "chef/config"
+ require "chef/http"
+ require "chef/http/authenticator"
+ require "chef/http/cookie_manager"
+ require "chef/http/decompressor"
+ require "chef/http/json_output"
end
option :method,
- :long => '--method METHOD',
- :short => '-m METHOD',
+ :long => "--method METHOD",
+ :short => "-m METHOD",
:default => "GET",
- :description => "Request method (GET, POST, PUT or DELETE). Default: GET"
+ :description => "Request method (GET, POST, PUT or DELETE). Default: GET"
option :pretty,
- :long => '--[no-]pretty',
+ :long => "--[no-]pretty",
:boolean => true,
:default => true,
- :description => "Pretty-print JSON output. Default: true"
+ :description => "Pretty-print JSON output. Default: true"
option :input,
- :long => '--input FILE',
- :short => '-i FILE',
+ :long => "--input FILE",
+ :short => "-i FILE",
:description => "Name of file to use for PUT or POST"
option :proxy_auth,
- :long => '--proxy-auth',
+ :long => "--proxy-auth",
:boolean => true,
:default => false,
- :description => "Use webui proxy authentication. Client key must be the webui key."
+ :description => "Use webui proxy authentication. Client key must be the webui key."
class RawInputServerAPI < Chef::HTTP
def initialize(options = {})
@@ -58,7 +59,7 @@ class Chef
exit(1)
elsif name_args.length > 1
show_usage
- ui.fatal("Only one path accepted for knife raw")
+ ui.fatal("You must specify only a single path")
exit(1)
end
@@ -70,10 +71,10 @@ class Chef
begin
method = config[:method].to_sym
- headers = {'Content-Type' => 'application/json'}
+ headers = { "Content-Type" => "application/json" }
if config[:proxy_auth]
- headers['x-ops-request-source'] = 'web'
+ headers["x-ops-request-source"] = "web"
end
if config[:pretty]
@@ -92,7 +93,7 @@ class Chef
exit 1
rescue Net::HTTPServerException => e
ui.error "Server responded with error #{e.response.code} \"#{e.response.message}\""
- ui.error "Error Body: #{e.response.body}" if e.response.body && e.response.body != ''
+ ui.error "Error Body: #{e.response.body}" if e.response.body && e.response.body != ""
exit 1
end
end
diff --git a/lib/chef/knife/recipe_list.rb b/lib/chef/knife/recipe_list.rb
index ed7d2a9509..8f76e494ad 100644
--- a/lib/chef/knife/recipe_list.rb
+++ b/lib/chef/knife/recipe_list.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef::Knife::RecipeList < Chef::Knife
banner "knife recipe list [PATTERN]"
def run
- recipes = rest.get_rest('cookbooks/_recipes')
+ recipes = rest.get("cookbooks/_recipes")
if pattern = @name_args.first
recipes = recipes.grep(Regexp.new(pattern))
end
diff --git a/lib/chef/knife/rehash.rb b/lib/chef/knife/rehash.rb
index 6f1fd91911..79286368f8 100644
--- a/lib/chef/knife/rehash.rb
+++ b/lib/chef/knife/rehash.rb
@@ -1,6 +1,6 @@
#
# Author:: Steven Danna <steve@chef.io>
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/core/subcommand_loader'
+require "chef/knife"
+require "chef/knife/core/subcommand_loader"
class Chef
class Knife
- class Rehash < Chef::Knife
+ class Rehash < Chef::Knife
banner "knife rehash"
def run
@@ -35,24 +35,27 @@ class Chef
end
def reload_plugins
- Chef::Knife::SubcommandLoader::GemGlobLoader.new(@@chef_config_dir).load_commands
+ # The subcommand_loader for this knife command should _always_ be the GemGlobLoader. The GemGlobLoader loads
+ # plugins from disc and ensures the hash we write is always correct. By this point it should also already have
+ # loaded plugins and `load_commands` shouldn't have an effect.
+ Chef::Knife.subcommand_loader.load_commands
end
def generate_hash
output = if Chef::Knife::SubcommandLoader.plugin_manifest?
Chef::Knife::SubcommandLoader.plugin_manifest
else
- { Chef::Knife::SubcommandLoader::HashedCommandLoader::KEY => {}}
+ { Chef::Knife::SubcommandLoader::HashedCommandLoader::KEY => {} }
end
- output[Chef::Knife::SubcommandLoader::HashedCommandLoader::KEY]['plugins_paths'] = Chef::Knife.subcommand_files
- output[Chef::Knife::SubcommandLoader::HashedCommandLoader::KEY]['plugins_by_category'] = Chef::Knife.subcommands_by_category
+ output[Chef::Knife::SubcommandLoader::HashedCommandLoader::KEY]["plugins_paths"] = Chef::Knife.subcommand_files
+ output[Chef::Knife::SubcommandLoader::HashedCommandLoader::KEY]["plugins_by_category"] = Chef::Knife.subcommands_by_category
output
end
def write_hash(data)
- plugin_manifest_dir = File.expand_path('..', Chef::Knife::SubcommandLoader.plugin_manifest_path)
+ plugin_manifest_dir = File.expand_path("..", Chef::Knife::SubcommandLoader.plugin_manifest_path)
FileUtils.mkdir_p(plugin_manifest_dir) unless File.directory?(plugin_manifest_dir)
- File.open(Chef::Knife::SubcommandLoader.plugin_manifest_path, 'w') do |f|
+ File.open(Chef::Knife::SubcommandLoader.plugin_manifest_path, "w") do |f|
f.write(Chef::JSONCompat.to_json_pretty(data))
ui.msg "Knife subcommands are cached in #{Chef::Knife::SubcommandLoader.plugin_manifest_path}. Delete this file to disable the caching."
end
diff --git a/lib/chef/knife/role_bulk_delete.rb b/lib/chef/knife/role_bulk_delete.rb
index 8b24f55846..0726454da3 100644
--- a/lib/chef/knife/role_bulk_delete.rb
+++ b/lib/chef/knife/role_bulk_delete.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleBulkDelete < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role bulk delete REGEX (options)"
@@ -63,8 +63,3 @@ class Chef
end
end
end
-
-
-
-
-
diff --git a/lib/chef/knife/role_create.rb b/lib/chef/knife/role_create.rb
index e9e363e870..a389d849f7 100644
--- a/lib/chef/knife/role_create.rb
+++ b/lib/chef/knife/role_create.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleCreate < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role create ROLE (options)"
@@ -46,10 +46,8 @@ class Chef
role = Chef::Role.new
role.name(@role_name)
role.description(config[:description]) if config[:description]
- create_object(role)
+ create_object(role, object_class: Chef::Role)
end
end
end
end
-
-
diff --git a/lib/chef/knife/role_delete.rb b/lib/chef/knife/role_delete.rb
index b823f37359..5c10a05d85 100644
--- a/lib/chef/knife/role_delete.rb
+++ b/lib/chef/knife/role_delete.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleDelete < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role delete ROLE (options)"
@@ -44,4 +44,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/knife/role_edit.rb b/lib/chef/knife/role_edit.rb
index b0580988a0..d3697849ad 100644
--- a/lib/chef/knife/role_edit.rb
+++ b/lib/chef/knife/role_edit.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleEdit < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role edit ROLE (options)"
@@ -43,6 +43,3 @@ class Chef
end
end
end
-
-
-
diff --git a/lib/chef/knife/role_env_run_list_add.rb b/lib/chef/knife/role_env_run_list_add.rb
index faf84ccfdb..61aec506a9 100644
--- a/lib/chef/knife/role_env_run_list_add.rb
+++ b/lib/chef/knife/role_env_run_list_add.rb
@@ -1,6 +1,6 @@
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: William Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleEnvRunListAdd < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role env_run_list add [ROLE] [ENVIRONMENT] [ENTRY[,ENTRY]] (options)"
@@ -34,13 +34,13 @@ class Chef
:long => "--after ITEM",
:description => "Place the ENTRY in the run list after ITEM"
- def add_to_env_run_list(role, environment, entries, after=nil)
+ def add_to_env_run_list(role, environment, entries, after = nil)
if after
nlist = []
unless role.env_run_lists.key?(environment)
role.env_run_lists_add(environment => nlist)
end
- role.run_list_for(environment).each do |entry|
+ role.run_list_for(environment).each do |entry|
nlist << entry
if entry == after
entries.each { |e| nlist << e }
@@ -68,11 +68,11 @@ class Chef
if @name_args.size > 2
# Check for nested lists and create a single plain one
entries = @name_args[2..-1].map do |entry|
- entry.split(',').map { |e| e.strip }
+ entry.split(",").map { |e| e.strip }
end.flatten
else
# Convert to array and remove the extra spaces
- entries = @name_args[2].split(',').map { |e| e.strip }
+ entries = @name_args[2].split(",").map { |e| e.strip }
end
add_to_env_run_list(role, environment, entries, config[:after])
diff --git a/lib/chef/knife/role_env_run_list_clear.rb b/lib/chef/knife/role_env_run_list_clear.rb
index 4304f29a38..d9dc96c87d 100644
--- a/lib/chef/knife/role_env_run_list_clear.rb
+++ b/lib/chef/knife/role_env_run_list_clear.rb
@@ -1,7 +1,7 @@
#
# Author:: Mike Fiedler (<miketheman@gmail.com>)
# Author:: William Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2013 Mike Fiedler
+# Copyright:: Copyright 2013-2016, Mike Fiedler
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleEnvRunListClear < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role env_run_list clear [ROLE] [ENVIRONMENT]"
diff --git a/lib/chef/knife/role_env_run_list_remove.rb b/lib/chef/knife/role_env_run_list_remove.rb
index 9ffc3f520e..576e32e2a9 100644
--- a/lib/chef/knife/role_env_run_list_remove.rb
+++ b/lib/chef/knife/role_env_run_list_remove.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,28 +16,28 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleEnvRunListRemove < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role env_run_list remove [ROLE] [ENVIRONMENT] [ENTRIES]"
def remove_from_env_run_list(role, environment, item_to_remove)
- nlist = []
- role.run_list_for(environment).each do |entry|
- nlist << entry unless entry == item_to_remove
- #unless entry == @name_args[2]
- # nlist << entry
- #end
- end
- role.env_run_lists_add(environment => nlist)
+ nlist = []
+ role.run_list_for(environment).each do |entry|
+ nlist << entry unless entry == item_to_remove
+ #unless entry == @name_args[2]
+ # nlist << entry
+ #end
+ end
+ role.env_run_lists_add(environment => nlist)
end
def run
diff --git a/lib/chef/knife/role_env_run_list_replace.rb b/lib/chef/knife/role_env_run_list_replace.rb
index 146d0c4905..e84e351c1e 100644
--- a/lib/chef/knife/role_env_run_list_replace.rb
+++ b/lib/chef/knife/role_env_run_list_replace.rb
@@ -1,6 +1,6 @@
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: William Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,22 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleEnvRunListReplace < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role env_run_list replace [ROLE] [ENVIRONMENT] [OLD_ENTRY] [NEW_ENTRY] "
def replace_in_env_run_list(role, environment, old_entry, new_entry)
nlist = []
- role.run_list_for(environment).each do |entry|
+ role.run_list_for(environment).each do |entry|
if entry == old_entry
nlist << new_entry
else
diff --git a/lib/chef/knife/role_env_run_list_set.rb b/lib/chef/knife/role_env_run_list_set.rb
index a1618516c0..f53616e151 100644
--- a/lib/chef/knife/role_env_run_list_set.rb
+++ b/lib/chef/knife/role_env_run_list_set.rb
@@ -1,7 +1,7 @@
#
# Author:: Mike Fiedler (<miketheman@gmail.com>)
# Author:: William Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2013 Mike Fiedler
+# Copyright:: Copyright 2013-2016, Mike Fiedler
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleEnvRunListSet < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role env_run_list set [ROLE] [ENVIRONMENT] [ENTRIES]"
@@ -52,11 +52,11 @@ class Chef
elsif @name_args.size > 2
# Check for nested lists and create a single plain one
entries = @name_args[2..-1].map do |entry|
- entry.split(',').map { |e| e.strip }
+ entry.split(",").map { |e| e.strip }
end.flatten
else
# Convert to array and remove the extra spaces
- entries = @name_args[2].split(',').map { |e| e.strip }
+ entries = @name_args[2].split(",").map { |e| e.strip }
end
set_env_run_list(role, environment, entries )
diff --git a/lib/chef/knife/role_from_file.rb b/lib/chef/knife/role_from_file.rb
index c80218b753..bf21a38fd7 100644
--- a/lib/chef/knife/role_from_file.rb
+++ b/lib/chef/knife/role_from_file.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleFromFile < Knife
deps do
- require 'chef/role'
- require 'chef/knife/core/object_loader'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/knife/core/object_loader"
+ require "chef/json_compat"
end
banner "knife role from file FILE [FILE..] (options)"
@@ -42,15 +42,10 @@ class Chef
output(format_for_display(updated)) if config[:print_after]
- ui.info("Updated Role #{updated.name}!")
+ ui.info("Updated Role #{updated.name}")
end
end
end
end
end
-
-
-
-
-
diff --git a/lib/chef/knife/role_list.rb b/lib/chef/knife/role_list.rb
index 0f105b2188..1247478ef5 100644
--- a/lib/chef/knife/role_list.rb
+++ b/lib/chef/knife/role_list.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleList < Knife
deps do
- require 'chef/node'
- require 'chef/json_compat'
+ require "chef/node"
+ require "chef/json_compat"
end
banner "knife role list (options)"
@@ -40,4 +40,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/knife/role_run_list_add.rb b/lib/chef/knife/role_run_list_add.rb
index c9d7785bb7..6aa92d37ba 100644
--- a/lib/chef/knife/role_run_list_add.rb
+++ b/lib/chef/knife/role_run_list_add.rb
@@ -1,6 +1,6 @@
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: William Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleRunListAdd < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role run_list add [ROLE] [ENTRY[,ENTRY]] (options)"
@@ -34,13 +34,13 @@ class Chef
:long => "--after ITEM",
:description => "Place the ENTRY in the run list after ITEM"
- def add_to_env_run_list(role, environment, entries, after=nil)
+ def add_to_env_run_list(role, environment, entries, after = nil)
if after
nlist = []
unless role.env_run_lists.key?(environment)
role.env_run_lists_add(environment => nlist)
end
- role.run_list_for(environment).each do |entry|
+ role.run_list_for(environment).each do |entry|
nlist << entry
if entry == after
entries.each { |e| nlist << e }
@@ -68,11 +68,11 @@ class Chef
if @name_args.size > 1
# Check for nested lists and create a single plain one
entries = @name_args[1..-1].map do |entry|
- entry.split(',').map { |e| e.strip }
+ entry.split(",").map { |e| e.strip }
end.flatten
else
# Convert to array and remove the extra spaces
- entries = @name_args[1].split(',').map { |e| e.strip }
+ entries = @name_args[1].split(",").map { |e| e.strip }
end
add_to_env_run_list(role, environment, entries, config[:after])
diff --git a/lib/chef/knife/role_run_list_clear.rb b/lib/chef/knife/role_run_list_clear.rb
index ed6225d83d..81678d39ef 100644
--- a/lib/chef/knife/role_run_list_clear.rb
+++ b/lib/chef/knife/role_run_list_clear.rb
@@ -1,7 +1,7 @@
#
# Author:: Mike Fiedler (<miketheman@gmail.com>)
# Author:: William Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2013 Mike Fiedler
+# Copyright:: Copyright 2013-2016, Mike Fiedler
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleRunListClear < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role run_list clear [ROLE]"
diff --git a/lib/chef/knife/role_run_list_remove.rb b/lib/chef/knife/role_run_list_remove.rb
index d783b34ab4..0dacfee051 100644
--- a/lib/chef/knife/role_run_list_remove.rb
+++ b/lib/chef/knife/role_run_list_remove.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,28 +16,28 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleRunListRemove < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role run_list remove [ROLE] [ENTRY]"
def remove_from_env_run_list(role, environment, item_to_remove)
- nlist = []
- role.run_list_for(environment).each do |entry|
- nlist << entry unless entry == item_to_remove
- #unless entry == @name_args[2]
- # nlist << entry
- #end
- end
- role.env_run_lists_add(environment => nlist)
+ nlist = []
+ role.run_list_for(environment).each do |entry|
+ nlist << entry unless entry == item_to_remove
+ #unless entry == @name_args[2]
+ # nlist << entry
+ #end
+ end
+ role.env_run_lists_add(environment => nlist)
end
def run
diff --git a/lib/chef/knife/role_run_list_replace.rb b/lib/chef/knife/role_run_list_replace.rb
index 1ab94df111..3e7bc2d5ec 100644
--- a/lib/chef/knife/role_run_list_replace.rb
+++ b/lib/chef/knife/role_run_list_replace.rb
@@ -1,6 +1,6 @@
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: William Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,22 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleRunListReplace < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role run_list replace [ROLE] [OLD_ENTRY] [NEW_ENTRY] "
def replace_in_env_run_list(role, environment, old_entry, new_entry)
nlist = []
- role.run_list_for(environment).each do |entry|
+ role.run_list_for(environment).each do |entry|
if entry == old_entry
nlist << new_entry
else
diff --git a/lib/chef/knife/role_run_list_set.rb b/lib/chef/knife/role_run_list_set.rb
index b9675c70dd..644af1c381 100644
--- a/lib/chef/knife/role_run_list_set.rb
+++ b/lib/chef/knife/role_run_list_set.rb
@@ -1,7 +1,7 @@
#
# Author:: Mike Fiedler (<miketheman@gmail.com>)
# Author:: William Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2013 Mike Fiedler
+# Copyright:: Copyright 2013-2016, Mike Fiedler
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class RoleRunListSet < Knife
deps do
- require 'chef/role'
- require 'chef/json_compat'
+ require "chef/role"
+ require "chef/json_compat"
end
banner "knife role run_list set [ROLE] [ENTRIES]"
@@ -52,11 +52,11 @@ class Chef
elsif @name_args.size > 1
# Check for nested lists and create a single plain one
entries = @name_args[1..-1].map do |entry|
- entry.split(',').map { |e| e.strip }
+ entry.split(",").map { |e| e.strip }
end.flatten
else
# Convert to array and remove the extra spaces
- entries = @name_args[1].split(',').map { |e| e.strip }
+ entries = @name_args[1].split(",").map { |e| e.strip }
end
set_env_run_list(role, environment, entries )
diff --git a/lib/chef/knife/role_show.rb b/lib/chef/knife/role_show.rb
index 159571f281..99684768bb 100644
--- a/lib/chef/knife/role_show.rb
+++ b/lib/chef/knife/role_show.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -25,13 +25,12 @@ class Chef
include Knife::Core::MultiAttributeReturnOption
deps do
- require 'chef/node'
- require 'chef/json_compat'
+ require "chef/node"
+ require "chef/json_compat"
end
banner "knife role show ROLE (options)"
-
def run
@role_name = @name_args[0]
@@ -48,5 +47,3 @@ class Chef
end
end
end
-
-
diff --git a/lib/chef/knife/search.rb b/lib/chef/knife/search.rb
index 014fc8dd87..046d1c7c52 100644
--- a/lib/chef/knife/search.rb
+++ b/lib/chef/knife/search.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,9 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/core/node_presenter'
+require "chef/knife"
+require "chef/knife/core/node_presenter"
+require "addressable/uri"
class Chef
class Knife
@@ -26,10 +27,10 @@ class Chef
include Knife::Core::MultiAttributeReturnOption
deps do
- require 'chef/node'
- require 'chef/environment'
- require 'chef/api_client'
- require 'chef/search/query'
+ require "chef/node"
+ require "chef/environment"
+ require "chef/api_client"
+ require "chef/search/query"
end
include Knife::Core::NodeFormattingOptions
@@ -74,19 +75,18 @@ class Chef
option :filter_result,
:short => "-f FILTER",
:long => "--filter-result FILTER",
- :description => "Only bring back specific attributes of the matching objects; for example: \"ServerName=name, Kernel=kernel.version\""
+ :description => "Only return specific attributes of the matching objects; for example: \"ServerName=name, Kernel=kernel.version\""
def run
read_cli_args
fuzzify_query
- if @type == 'node'
+ if @type == "node"
ui.use_presenter Knife::Core::NodePresenter
end
q = Chef::Search::Query.new
- escaped_query = URI.escape(@query,
- Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
+ escaped_query = Addressable::URI.encode_component(@query, Addressable::URI::CharacterClasses::QUERY)
result_items = []
result_count = 0
@@ -106,7 +106,7 @@ class Chef
formatted_item = Hash.new
if item.is_a?(Hash)
# doing a little magic here to set the correct name
- formatted_item[item["__display_name"]] = item.reject{|k| k == "__display_name"}
+ formatted_item[item["__display_name"]] = item.reject { |k| k == "__display_name" }
else
formatted_item = format_for_display(item)
end
@@ -120,7 +120,7 @@ class Chef
end
if ui.interchange?
- output({:results => result_count, :rows => result_items})
+ output({ :results => result_count, :rows => result_items })
else
ui.log "#{result_count} items found"
ui.log("\n")
@@ -177,13 +177,13 @@ class Chef
# See lib/chef/search/query.rb for more examples of this.
def create_result_filter(filter_string)
final_filter = Hash.new
- filter_string.gsub!(" ", "")
+ filter_string.delete!(" ")
filters = filter_string.split(",")
filters.each do |f|
return_id, attr_path = f.split("=")
final_filter[return_id.to_sym] = attr_path.split(".")
end
- return final_filter
+ final_filter
end
def create_result_filter_from_attributes(filter_array)
@@ -193,7 +193,7 @@ class Chef
end
# adding magic filter so we can actually pull the name as before
final_filter["__display_name"] = [ "name" ]
- return final_filter
+ final_filter
end
end
diff --git a/lib/chef/knife/serve.rb b/lib/chef/knife/serve.rb
index 84918e2ef2..95996e6d1e 100644
--- a/lib/chef/knife/serve.rb
+++ b/lib/chef/knife/serve.rb
@@ -1,23 +1,23 @@
-require 'chef/knife'
-require 'chef/local_mode'
+require "chef/knife"
+require "chef/local_mode"
class Chef
class Knife
class Serve < Knife
-
- banner 'knife serve (options)'
+
+ banner "knife serve (options)"
option :repo_mode,
- :long => '--repo-mode MODE',
- :description => "Specifies the local repository layout. Values: static (only environments/roles/data_bags/cookbooks), everything (includes nodes/clients/users), hosted_everything (includes acls/groups/etc. for Enterprise/Hosted Chef). Default: everything/hosted_everything"
+ :long => "--repo-mode MODE",
+ :description => "Specifies the local repository layout. Values: static (only environments/roles/data_bags/cookbooks), everything (includes nodes/clients/users), hosted_everything (includes acls/groups/etc. for Enterprise/Hosted Chef). Default: everything/hosted_everything"
option :chef_repo_path,
- :long => '--chef-repo-path PATH',
- :description => 'Overrides the location of chef repo. Default is specified by chef_repo_path in the config'
+ :long => "--chef-repo-path PATH",
+ :description => "Overrides the location of chef repo. Default is specified by chef_repo_path in the config"
option :chef_zero_host,
- :long => '--chef-zero-host IP',
- :description => 'Overrides the host upon which chef-zero listens. Default is 127.0.0.1.'
+ :long => "--chef-zero-host IP",
+ :description => "Overrides the host upon which chef-zero listens. Default is 127.0.0.1."
def configure_chef
super
@@ -27,7 +27,7 @@ class Chef
# --chef-repo-path forcibly overrides all other paths
if config[:chef_repo_path]
Chef::Config.chef_repo_path = config[:chef_repo_path]
- %w(acl client cookbook container data_bag environment group node role user).each do |variable_name|
+ %w{acl client cookbook container data_bag environment group node role user}.each do |variable_name|
Chef::Config.delete("#{variable_name}_path".to_sym)
end
end
diff --git a/lib/chef/knife/show.rb b/lib/chef/knife/show.rb
index 4684a6ac7e..4c1c882815 100644
--- a/lib/chef/knife/show.rb
+++ b/lib/chef/knife/show.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
class Chef
class Knife
@@ -8,12 +8,12 @@ class Chef
category "path-based"
deps do
- require 'chef/chef_fs/file_system'
- require 'chef/chef_fs/file_system/not_found_error'
+ require "chef/chef_fs/file_system"
+ require "chef/chef_fs/file_system/exceptions"
end
option :local,
- :long => '--local',
+ :long => "--local",
:boolean => true,
:description => "Show local files instead of remote"
diff --git a/lib/chef/knife/ssh.rb b/lib/chef/knife/ssh.rb
index 89a9608c60..e206f72630 100644
--- a/lib/chef/knife/ssh.rb
+++ b/lib/chef/knife/ssh.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,23 +16,21 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/mixin/shell_out"
+require "chef/knife"
class Chef
class Knife
class Ssh < Knife
deps do
- require 'net/ssh'
- require 'net/ssh/multi'
- require 'chef/monkey_patches/net-ssh-multi'
- require 'readline'
- require 'chef/exceptions'
- require 'chef/search/query'
- require 'chef/mixin/shell_out'
- require 'chef/mixin/command'
- require 'chef/util/path_helper'
- require 'mixlib/shellout'
+ require "net/ssh"
+ require "net/ssh/multi"
+ require "readline"
+ require "chef/exceptions"
+ require "chef/search/query"
+ require "chef/util/path_helper"
+ require "mixlib/shellout"
end
include Chef::Mixin::ShellOut
@@ -72,7 +70,7 @@ class Chef
:description => "The ssh password - will prompt if flag is specified but no password is given",
# default to a value that can not be a password (boolean)
# so we can effectively test if this parameter was specified
- # without a vlaue
+ # without a value
:default => false
option :ssh_port,
@@ -81,6 +79,13 @@ class Chef
:description => "The ssh port",
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key.strip }
+ option :ssh_timeout,
+ :short => "-t SECONDS",
+ :long => "--ssh-timeout SECONDS",
+ :description => "The ssh connection timeout",
+ :proc => Proc.new { |key| Chef::Config[:knife][:ssh_timeout] = key.strip.to_i },
+ :default => 120
+
option :ssh_gateway,
:short => "-G GATEWAY",
:long => "--ssh-gateway GATEWAY",
@@ -94,8 +99,12 @@ class Chef
:boolean => true
option :identity_file,
- :short => "-i IDENTITY_FILE",
:long => "--identity-file IDENTITY_FILE",
+ :description => "The SSH identity file used for authentication. [DEPRECATED] Use --ssh-identity-file instead."
+
+ option :ssh_identity_file,
+ :short => "-i IDENTITY_FILE",
+ :long => "--ssh-identity-file IDENTITY_FILE",
:description => "The SSH identity file used for authentication"
option :host_key_verify,
@@ -105,8 +114,8 @@ class Chef
:default => true
option :on_error,
- :short => '-e',
- :long => '--exit-on-error',
+ :short => "-e",
+ :long => "--exit-on-error",
:description => "Immediately exit if an error is encountered",
:boolean => true,
:proc => Proc.new { :raise }
@@ -136,8 +145,8 @@ class Chef
def configure_gateway
config[:ssh_gateway] ||= Chef::Config[:knife][:ssh_gateway]
if config[:ssh_gateway]
- gw_host, gw_user = config[:ssh_gateway].split('@').reverse
- gw_host, gw_port = gw_host.split(':')
+ gw_host, gw_user = config[:ssh_gateway].split("@").reverse
+ gw_host, gw_port = gw_host.split(":")
gw_opts = session_options(gw_host, gw_port, gw_user)
user = gw_opts.delete(:user)
@@ -154,14 +163,12 @@ class Chef
end
def configure_session
- list = config[:manual] ?
- @name_args[0].split(" ") :
- search_nodes
+ list = config[:manual] ? @name_args[0].split(" ") : search_nodes
if list.length == 0
- if @action_nodes.length == 0
- ui.fatal("No nodes returned from search!")
+ if @search_count == 0
+ ui.fatal("No nodes returned from search")
else
- ui.fatal("#{@action_nodes.length} #{@action_nodes.length > 1 ? "nodes":"node"} found, " +
+ ui.fatal("#{@search_count} #{@search_count > 1 ? "nodes" : "node"} found, " +
"but does not have the required attribute to establish the connection. " +
"Try setting another attribute to open the connection using --attribute.")
end
@@ -176,41 +183,56 @@ class Chef
# 2) configuration file
# 3) cloud attribute
# 4) fqdn
- if config[:attribute]
- Chef::Log.debug("Using node attribute '#{config[:attribute]}' as the ssh target")
- attribute = config[:attribute]
+ if node["config"]
+ Chef::Log.debug("Using node attribute '#{config[:attribute]}' as the ssh target: #{node["config"]}")
+ node["config"]
elsif Chef::Config[:knife][:ssh_attribute]
- Chef::Log.debug("Using node attribute #{Chef::Config[:knife][:ssh_attribute]}")
- attribute = Chef::Config[:knife][:ssh_attribute]
- elsif node[:cloud] &&
- node[:cloud][:public_hostname] &&
- !node[:cloud][:public_hostname].empty?
- Chef::Log.debug("Using node attribute 'cloud[:public_hostname]' automatically as the ssh target")
- attribute = 'cloud.public_hostname'
+ Chef::Log.debug("Using node attribute #{Chef::Config[:knife][:ssh_attribute]}: #{node["knife_config"]}")
+ node["knife_config"]
+ elsif node["cloud"] &&
+ node["cloud"]["public_hostname"] &&
+ !node["cloud"]["public_hostname"].empty?
+ Chef::Log.debug("Using node attribute 'cloud[:public_hostname]' automatically as the ssh target: #{node["cloud"]["public_hostname"]}")
+ node["cloud"]["public_hostname"]
else
# falling back to default of fqdn
- Chef::Log.debug("Using node attribute 'fqdn' as the ssh target")
- attribute = "fqdn"
+ Chef::Log.debug("Using node attribute 'fqdn' as the ssh target: #{node["fqdn"]}")
+ node["fqdn"]
end
- attribute
end
def search_nodes
list = Array.new
query = Chef::Search::Query.new
- @action_nodes = query.search(:node, @name_args[0])[0]
- @action_nodes.each do |item|
+ required_attributes = { fqdn: ["fqdn"], cloud: ["cloud"] }
+
+ separator = ui.presenter.attribute_field_separator
+
+ # if we've set an attribute to use on the command line
+ if config[:attribute]
+ required_attributes[:config] = config[:attribute].split(separator)
+ end
+
+ # if we've configured an attribute in our config
+ if Chef::Config[:knife][:ssh_attribute]
+ required_attributes[:knife_config] = Chef::Config[:knife][:ssh_attribute].split(separator)
+ end
+
+ @search_count = 0
+ query.search(:node, @name_args[0], filter_result: required_attributes) do |item|
+ @search_count += 1
# we should skip the loop to next iteration if the item
# returned by the search is nil
next if item.nil?
# next if we couldn't find the specified attribute in the
# returned node object
- host = extract_nested_value(item,get_ssh_attribute(item))
+ host = get_ssh_attribute(item)
next if host.nil?
ssh_port = item[:cloud].nil? ? nil : item[:cloud][:public_ssh_port]
srv = [host, ssh_port]
list.push(srv)
end
+
list
end
@@ -223,13 +245,13 @@ class Chef
# @param port [String] SSH port for this session.
# @param user [String] Optional username for this session.
# @return [Hash<Symbol, Object>]
- def session_options(host, port, user=nil)
- ssh_config = Net::SSH.configuration_for(host)
+ def session_options(host, port, user = nil)
+ ssh_config = Net::SSH.configuration_for(host, true)
{}.tap do |opts|
# Chef::Config[:knife][:ssh_user] is parsed in #configure_user and written to config[:ssh_user]
opts[:user] = user || config[:ssh_user] || ssh_config[:user]
- if config[:identity_file]
- opts[:keys] = File.expand_path(config[:identity_file])
+ if config[:ssh_identity_file]
+ opts[:keys] = File.expand_path(config[:ssh_identity_file])
opts[:keys_only] = true
elsif config[:ssh_password]
opts[:password] = config[:ssh_password]
@@ -242,7 +264,7 @@ class Chef
opts[:logger] = Chef::Log.logger if Chef::Log.level == :debug
if !config[:host_key_verify]
opts[:paranoid] = false
- opts[:user_known_hosts_file] = '/dev/null'
+ opts[:user_known_hosts_file] = "/dev/null"
end
end
end
@@ -255,6 +277,9 @@ class Chef
# Handle port overrides for the main connection.
session_opts[:port] = Chef::Config[:knife][:ssh_port] if Chef::Config[:knife][:ssh_port]
session_opts[:port] = config[:ssh_port] if config[:ssh_port]
+ # Handle connection timeout
+ session_opts[:timeout] = Chef::Config[:knife][:ssh_timeout] if Chef::Config[:knife][:ssh_timeout]
+ session_opts[:timeout] = config[:ssh_timeout] if config[:ssh_timeout]
# Create the hostspec.
hostspec = session_opts[:user] ? "#{session_opts.delete(:user)}@#{host}" : host
# Connect a new session on the multi.
@@ -293,14 +318,14 @@ class Chef
ui.msg(str)
end
- def ssh_command(command, subsession=nil)
+ def ssh_command(command, subsession = nil)
exit_status = 0
subsession ||= session
command = fixup_sudo(command)
- command.force_encoding('binary') if command.respond_to?(:force_encoding)
- subsession.open_channel do |ch|
- ch.request_pty
- ch.exec command do |ch, success|
+ command.force_encoding("binary") if command.respond_to?(:force_encoding)
+ subsession.open_channel do |chan|
+ chan.request_pty
+ chan.exec command do |ch, success|
raise ArgumentError, "Cannot execute #{command}" unless success
ch.on_data do |ichannel, data|
print_data(ichannel[:host], data)
@@ -363,8 +388,8 @@ class Chef
loop do
command = read_line
case command
- when 'quit!'
- puts 'Bye!'
+ when "quit!"
+ puts "Bye!"
break
when /^on (.+?); (.+)$/
raw_list = $1.split(" ")
@@ -382,7 +407,7 @@ class Chef
def screen
tf = Tempfile.new("knife-ssh-screen")
- Chef::Util::PathHelper.home('.screenrc') do |screenrc_path|
+ Chef::Util::PathHelper.home(".screenrc") do |screenrc_path|
if File.exist? screenrc_path
tf.puts("source #{screenrc_path}")
end
@@ -392,7 +417,7 @@ class Chef
window = 0
session.servers_for.each do |server|
tf.print("screen -t \"#{server.host}\" #{window} ssh ")
- tf.print("-i #{config[:identity_file]} ") if config[:identity_file]
+ tf.print("-i #{config[:ssh_identity_file]} ") if config[:ssh_identity_file]
server.user ? tf.puts("#{server.user}@#{server.host}") : tf.puts(server.host)
window += 1
end
@@ -402,7 +427,7 @@ class Chef
def tmux
ssh_dest = lambda do |server|
- identity = "-i #{config[:identity_file]} " if config[:identity_file]
+ identity = "-i #{config[:ssh_identity_file]} " if config[:ssh_identity_file]
prefix = server.user ? "#{server.user}@" : ""
"'ssh #{identity}#{prefix}#{server.host}'"
end
@@ -421,7 +446,7 @@ class Chef
end.join(" \\; ")
end
- tmux_name = "'knife ssh #{@name_args[0].gsub(/:/,'=')}'"
+ tmux_name = "'knife ssh #{@name_args[0].tr(':', '=')}'"
begin
server = session.servers_for.first
cmd = ["tmux new-session -d -s #{tmux_name}",
@@ -435,31 +460,31 @@ class Chef
def macterm
begin
- require 'appscript'
+ require "appscript"
rescue LoadError
STDERR.puts "You need the rb-appscript gem to use knife ssh macterm. `(sudo) gem install rb-appscript` to install"
raise
end
Appscript.app("/Applications/Utilities/Terminal.app").windows.first.activate
- Appscript.app("System Events").application_processes["Terminal.app"].keystroke("n", :using=>:command_down)
- term = Appscript.app('Terminal')
+ Appscript.app("System Events").application_processes["Terminal.app"].keystroke("n", :using => :command_down)
+ term = Appscript.app("Terminal")
window = term.windows.first.get
(session.servers_for.size - 1).times do |i|
window.activate
- Appscript.app("System Events").application_processes["Terminal.app"].keystroke("t", :using=>:command_down)
+ Appscript.app("System Events").application_processes["Terminal.app"].keystroke("t", :using => :command_down)
end
session.servers_for.each_with_index do |server, tab_number|
cmd = "unset PROMPT_COMMAND; echo -e \"\\033]0;#{server.host}\\007\"; ssh #{server.user ? "#{server.user}@#{server.host}" : server.host}"
- Appscript.app('Terminal').do_script(cmd, :in => window.tabs[tab_number + 1].get)
+ Appscript.app("Terminal").do_script(cmd, :in => window.tabs[tab_number + 1].get)
end
end
def cssh
cssh_cmd = nil
- %w[csshX cssh].each do |cmd|
+ %w{csshX cssh}.each do |cmd|
begin
# Unix and Mac only
cssh_cmd = shell_out!("which #{cmd}").stdout.strip
@@ -469,9 +494,9 @@ class Chef
end
raise Chef::Exceptions::Exec, "no command found for cssh" unless cssh_cmd
- # pass in the consolidated itentity file option to cssh(X)
- if config[:identity_file]
- cssh_cmd << " --ssh_args '-i #{File.expand_path(config[:identity_file])}'"
+ # pass in the consolidated identity file option to cssh(X)
+ if config[:ssh_identity_file]
+ cssh_cmd << " --ssh_args '-i #{File.expand_path(config[:ssh_identity_file])}'"
end
session.servers_for.each do |server|
@@ -516,45 +541,40 @@ class Chef
end
end
- def configure_identity_file
- config[:identity_file] = get_stripped_unfrozen_value(config[:identity_file] ||
- Chef::Config[:knife][:ssh_identity_file])
- end
-
- def extract_nested_value(data_structure, path_spec)
- ui.presenter.extract_nested_value(data_structure, path_spec)
+ def configure_ssh_identity_file
+ # config[:identity_file] is DEPRECATED in favor of :ssh_identity_file
+ config[:ssh_identity_file] = get_stripped_unfrozen_value(config[:ssh_identity_file] || config[:identity_file] || Chef::Config[:knife][:ssh_identity_file])
end
def run
- extend Chef::Mixin::Command
-
@longest = 0
configure_user
configure_password
- configure_identity_file
+ @password = config[:ssh_password] if config[:ssh_password]
+ configure_ssh_identity_file
configure_gateway
configure_session
exit_status =
- case @name_args[1]
- when "interactive"
- interactive
- when "screen"
- screen
- when "tmux"
- tmux
- when "macterm"
- macterm
- when "cssh"
- cssh
- when "csshx"
- Chef::Log.warn("knife ssh csshx will be deprecated in a future release")
- Chef::Log.warn("please use knife ssh cssh instead")
- cssh
- else
- ssh_command(@name_args[1..-1].join(" "))
- end
+ case @name_args[1]
+ when "interactive"
+ interactive
+ when "screen"
+ screen
+ when "tmux"
+ tmux
+ when "macterm"
+ macterm
+ when "cssh"
+ cssh
+ when "csshx"
+ Chef::Log.warn("knife ssh csshx will be deprecated in a future release")
+ Chef::Log.warn("please use knife ssh cssh instead")
+ cssh
+ else
+ ssh_command(@name_args[1..-1].join(" "))
+ end
session.close
if exit_status != 0
diff --git a/lib/chef/knife/ssl_check.rb b/lib/chef/knife/ssl_check.rb
index d71eacfc7e..b3374e0999 100644
--- a/lib/chef/knife/ssl_check.rb
+++ b/lib/chef/knife/ssl_check.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,21 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/config'
+require "chef/knife"
+require "chef/config"
class Chef
class Knife
class SslCheck < Chef::Knife
deps do
- require 'pp'
- require 'socket'
- require 'uri'
- require 'chef/http/ssl_policies'
- require 'openssl'
+ require "pp"
+ require "socket"
+ require "uri"
+ require "chef/http/ssl_policies"
+ require "openssl"
+ require "chef/mixin/proxified_socket"
+ include Chef::Mixin::ProxifiedSocket
end
banner "knife ssl check [URL] (options)"
@@ -48,7 +50,7 @@ class Chef
end
def given_uri
- (name_args[0] or Chef::Config.chef_server_url)
+ (name_args[0] || Chef::Config.chef_server_url)
end
def host
@@ -75,7 +77,7 @@ class Chef
def verify_peer_socket
@verify_peer_socket ||= begin
- tcp_connection = TCPSocket.new(host, port)
+ tcp_connection = proxified_socket(host, port)
ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_connection, verify_peer_ssl_context)
ssl_client.hostname = host
ssl_client
@@ -93,7 +95,7 @@ class Chef
def noverify_socket
@noverify_socket ||= begin
- tcp_connection = TCPSocket.new(host, port)
+ tcp_connection = proxified_socket(host, port)
OpenSSL::SSL::SSLSocket.new(tcp_connection, noverify_peer_ssl_context)
end
end
@@ -204,7 +206,7 @@ ADVICE
def debug_invalid_host
noverify_socket.connect
subject = noverify_socket.peer_cert.subject
- cn_field_tuple = subject.to_a.find {|field| field[0] == "CN" }
+ cn_field_tuple = subject.to_a.find { |field| field[0] == "CN" }
cn = cn_field_tuple[1]
ui.error("You are attempting to connect to: '#{host}'")
@@ -243,6 +245,7 @@ ADVICE
def run
validate_uri
+
if verify_X509 && verify_cert && verify_cert_host
ui.msg "Successfully verified certificates from `#{host}'"
else
@@ -251,9 +254,11 @@ ADVICE
end
private
+
def trusted_certificates
if configuration.trusted_certs_dir && Dir.exist?(configuration.trusted_certs_dir)
- Dir.glob(File.join(configuration.trusted_certs_dir, "*.{crt,pem}"))
+ glob_dir = ChefConfig::PathHelper.escape_glob_dir(configuration.trusted_certs_dir)
+ Dir.glob(File.join(glob_dir, "*.{crt,pem}"))
else
[]
end
@@ -271,7 +276,7 @@ ADVICE
rescue OpenSSL::X509::StoreError => e
return e.message
end
- return nil
+ nil
end
end
end
diff --git a/lib/chef/knife/ssl_fetch.rb b/lib/chef/knife/ssl_fetch.rb
index fd7d101fd8..238796c804 100644
--- a/lib/chef/knife/ssl_fetch.rb
+++ b/lib/chef/knife/ssl_fetch.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,20 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/config'
+require "chef/knife"
+require "chef/config"
class Chef
class Knife
class SslFetch < Chef::Knife
deps do
- require 'pp'
- require 'socket'
- require 'uri'
- require 'openssl'
+ require "pp"
+ require "socket"
+ require "uri"
+ require "openssl"
+ require "chef/mixin/proxified_socket"
+ include Chef::Mixin::ProxifiedSocket
end
banner "knife ssl fetch [URL] (options)"
@@ -45,7 +47,7 @@ class Chef
end
def given_uri
- (name_args[0] or Chef::Config.chef_server_url)
+ (name_args[0] || Chef::Config.chef_server_url)
end
def host
@@ -71,7 +73,7 @@ class Chef
end
def remote_cert_chain
- tcp_connection = TCPSocket.new(host, port)
+ tcp_connection = proxified_socket(host, port)
shady_ssl_connection = OpenSSL::SSL::SSLSocket.new(tcp_connection, noverify_peer_ssl_context)
shady_ssl_connection.connect
shady_ssl_connection.peer_cert_chain
@@ -85,11 +87,13 @@ class Chef
end
end
-
def cn_of(certificate)
subject = certificate.subject
- cn_field_tuple = subject.to_a.find {|field| field[0] == "CN" }
- cn_field_tuple[1]
+ if cn_field_tuple = subject.to_a.find { |field| field[0] == "CN" }
+ cn_field_tuple[1]
+ else
+ nil
+ end
end
# Convert the CN of a certificate into something that will work well as a
@@ -102,7 +106,7 @@ class Chef
# practice.
# https://tools.ietf.org/html/rfc6125#section-6.4.2
def normalize_cn(cn)
- cn.gsub("*", "wildcard").gsub(/[^[:alnum:]\-]/, '_')
+ cn.gsub("*", "wildcard").gsub(/[^[:alnum:]\-]/, "_")
end
def configuration
@@ -116,9 +120,10 @@ class Chef
def write_cert(cert)
FileUtils.mkdir_p(trusted_certs_dir)
cn = cn_of(cert)
- filename = File.join(trusted_certs_dir, "#{normalize_cn(cn)}.crt")
- ui.msg("Adding certificate for #{cn} in #{filename}")
- File.open(filename, File::CREAT|File::TRUNC|File::RDWR, 0644) do |f|
+ filename = cn.nil? ? "#{host}_#{Time.new.to_i}" : normalize_cn(cn)
+ full_path = File.join(trusted_certs_dir, "#{filename}.crt")
+ ui.msg("Adding certificate for #{filename} in #{full_path}")
+ File.open(full_path, File::CREAT | File::TRUNC | File::RDWR, 0644) do |f|
f.print(cert.to_s)
end
end
@@ -145,14 +150,12 @@ TRUST_TRUST
ui.error("The service at the given URI (#{uri}) does not accept SSL connections")
if uri.scheme == "http"
- https_uri = uri.to_s.sub(/^http/, 'https')
+ https_uri = uri.to_s.sub(/^http/, "https")
ui.error("Perhaps you meant to connect to '#{https_uri}'?")
end
exit 1
end
-
end
end
end
-
diff --git a/lib/chef/knife/status.rb b/lib/chef/knife/status.rb
index 1a61b035cb..0e3cd7e7d6 100644
--- a/lib/chef/knife/status.rb
+++ b/lib/chef/knife/status.rb
@@ -1,6 +1,6 @@
#
# Author:: Ian Meyer (<ianmmeyer@gmail.com>)
-# Copyright:: Copyright (c) 2010 Ian Meyer
+# Copyright:: Copyright 2010-2016, Ian Meyer
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/core/status_presenter'
-require 'chef/knife/core/node_presenter'
+require "chef/knife"
+require "chef/knife/core/status_presenter"
+require "chef/knife/core/node_presenter"
class Chef
class Knife
@@ -26,7 +26,7 @@ class Chef
include Knife::Core::NodeFormattingOptions
deps do
- require 'chef/search/query'
+ require "chef/search/query"
end
banner "knife status QUERY (options)"
@@ -61,10 +61,10 @@ class Chef
if config[:long_output]
opts = {}
else
- opts = {filter_result:
+ opts = { filter_result:
{ name: ["name"], ipaddress: ["ipaddress"], ohai_time: ["ohai_time"],
- ec2: ["ec2"], run_list: ["run_list"], platform: ["platform"],
- platform_version: ["platform_version"], chef_environment: ["chef_environment"]}}
+ ec2: ["ec2"], run_list: ["run_list"], platform: ["platform"],
+ platform_version: ["platform_version"], chef_environment: ["chef_environment"] } }
end
@query ||= ""
@@ -76,7 +76,7 @@ class Chef
time = Time.now.to_i
# AND NOT is not valid lucene syntax, so don't use append_to_query
@query << " " unless @query.empty?
- @query << "NOT ohai_time:[#{(time - 60*60).to_s} TO #{time.to_s}]"
+ @query << "NOT ohai_time:[#{(time - 60 * 60)} TO #{time}]"
end
if config[:hide_by_mins]
@@ -84,7 +84,7 @@ class Chef
time = Time.now.to_i
# AND NOT is not valid lucene syntax, so don't use append_to_query
@query << " " unless @query.empty?
- @query << "NOT ohai_time:[#{(time - hidemins*60).to_s} TO #{time.to_s}]"
+ @query << "NOT ohai_time:[#{(time - hidemins * 60)} TO #{time}]"
end
@query = @query.empty? ? "*:*" : @query
@@ -96,13 +96,13 @@ class Chef
all_nodes << node
end
- output(all_nodes.sort { |n1, n2|
- if (config[:sort_reverse] || Chef::Config[:knife][:sort_status_reverse])
- (n2["ohai_time"] or 0) <=> (n1["ohai_time"] or 0)
+ output(all_nodes.sort do |n1, n2|
+ if config[:sort_reverse] || Chef::Config[:knife][:sort_status_reverse]
+ (n2["ohai_time"] || 0) <=> (n1["ohai_time"] || 0)
else
- (n1["ohai_time"] or 0) <=> (n2["ohai_time"] or 0)
+ (n1["ohai_time"] || 0) <=> (n2["ohai_time"] || 0)
end
- })
+ end)
end
end
diff --git a/lib/chef/knife/supermarket_download.rb b/lib/chef/knife/supermarket_download.rb
new file mode 100644
index 0000000000..5657558591
--- /dev/null
+++ b/lib/chef/knife/supermarket_download.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_download"
+
+class Chef
+ class Knife
+ class SupermarketDownload < Knife::CookbookSiteDownload
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket download COOKBOOK [VERSION] (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_install.rb b/lib/chef/knife/supermarket_install.rb
new file mode 100644
index 0000000000..7642e68181
--- /dev/null
+++ b/lib/chef/knife/supermarket_install.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_install"
+
+class Chef
+ class Knife
+ class SupermarketInstall < Knife::CookbookSiteInstall
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket install COOKBOOK [VERSION] (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_list.rb b/lib/chef/knife/supermarket_list.rb
new file mode 100644
index 0000000000..f2bc98bd0e
--- /dev/null
+++ b/lib/chef/knife/supermarket_list.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_list"
+
+class Chef
+ class Knife
+ class SupermarketList < Knife::CookbookSiteList
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket list (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_search.rb b/lib/chef/knife/supermarket_search.rb
new file mode 100644
index 0000000000..3206b0cb80
--- /dev/null
+++ b/lib/chef/knife/supermarket_search.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_search"
+
+class Chef
+ class Knife
+ class SupermarketSearch < Knife::CookbookSiteSearch
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket search QUERY (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_share.rb b/lib/chef/knife/supermarket_share.rb
new file mode 100644
index 0000000000..3109b9e794
--- /dev/null
+++ b/lib/chef/knife/supermarket_share.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_share"
+
+class Chef
+ class Knife
+ class SupermarketShare < Knife::CookbookSiteShare
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket share COOKBOOK [CATEGORY] (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_show.rb b/lib/chef/knife/supermarket_show.rb
new file mode 100644
index 0000000000..2ad122143f
--- /dev/null
+++ b/lib/chef/knife/supermarket_show.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_show"
+
+class Chef
+ class Knife
+ class SupermarketShow < Knife::CookbookSiteShow
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket show COOKBOOK [VERSION] (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_unshare.rb b/lib/chef/knife/supermarket_unshare.rb
new file mode 100644
index 0000000000..fd48e172ce
--- /dev/null
+++ b/lib/chef/knife/supermarket_unshare.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_unshare"
+
+class Chef
+ class Knife
+ class SupermarketUnshare < Knife::CookbookSiteUnshare
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket unshare COOKBOOK (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/tag_create.rb b/lib/chef/knife/tag_create.rb
index d3ca95242d..e8cfe11303 100644
--- a/lib/chef/knife/tag_create.rb
+++ b/lib/chef/knife/tag_create.rb
@@ -1,8 +1,8 @@
#
# Author:: Ryan Davis (<ryand-ruby@zenspider.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Ryan Davis and Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Copyright:: Copyright 2011-2016, Ryan Davis and Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,14 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class TagCreate < Knife
deps do
- require 'chef/node'
+ require "chef/node"
end
banner "knife tag create NODE TAG ..."
diff --git a/lib/chef/knife/tag_delete.rb b/lib/chef/knife/tag_delete.rb
index 10751db216..d00ec2f60b 100644
--- a/lib/chef/knife/tag_delete.rb
+++ b/lib/chef/knife/tag_delete.rb
@@ -1,8 +1,8 @@
#
# Author:: Ryan Davis (<ryand-ruby@zenspider.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Ryan Davis and Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Copyright:: Copyright 2011-2016, Ryan Davis and Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,14 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class TagDelete < Knife
deps do
- require 'chef/node'
+ require "chef/node"
end
banner "knife tag delete NODE TAG ..."
diff --git a/lib/chef/knife/tag_list.rb b/lib/chef/knife/tag_list.rb
index 499eb8578c..2665e53bf4 100644
--- a/lib/chef/knife/tag_list.rb
+++ b/lib/chef/knife/tag_list.rb
@@ -1,8 +1,8 @@
#
# Author:: Ryan Davis (<ryand-ruby@zenspider.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Ryan Davis and Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Copyright:: Copyright 2011-2016, Ryan Davis and Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,14 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class TagList < Knife
deps do
- require 'chef/node'
+ require "chef/node"
end
banner "knife tag list NODE"
diff --git a/lib/chef/knife/upload.rb b/lib/chef/knife/upload.rb
index 8abd22b4dd..f0ecaaae47 100644
--- a/lib/chef/knife/upload.rb
+++ b/lib/chef/knife/upload.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
class Chef
class Knife
@@ -8,50 +8,50 @@ class Chef
category "path-based"
deps do
- require 'chef/chef_fs/command_line'
+ require "chef/chef_fs/command_line"
end
option :recurse,
- :long => '--[no-]recurse',
+ :long => "--[no-]recurse",
:boolean => true,
:default => true,
:description => "List directories recursively."
option :purge,
- :long => '--[no-]purge',
+ :long => "--[no-]purge",
:boolean => true,
:default => false,
:description => "Delete matching local files and directories that do not exist remotely."
option :force,
- :long => '--[no-]force',
+ :long => "--[no-]force",
:boolean => true,
:default => false,
- :description => "Force upload of files even if they match (quicker for many files). Will overwrite frozen cookbooks."
+ :description => "Force upload of files even if they match (quicker for many files). Will overwrite frozen cookbooks."
option :freeze,
- :long => '--[no-]freeze',
+ :long => "--[no-]freeze",
:boolean => true,
:default => false,
:description => "Freeze cookbooks that get uploaded."
option :dry_run,
- :long => '--dry-run',
- :short => '-n',
+ :long => "--dry-run",
+ :short => "-n",
:boolean => true,
:default => false,
:description => "Don't take action, only print what would happen"
option :diff,
- :long => '--[no-]diff',
+ :long => "--[no-]diff",
:boolean => true,
:default => true,
- :description => 'Turn off to avoid uploading existing files; only new (and possibly deleted) files with --no-diff'
+ :description => "Turn off to avoid uploading existing files; only new (and possibly deleted) files with --no-diff"
def run
if name_args.length == 0
show_usage
- ui.fatal("Must specify at least one argument. If you want to upload everything in this directory, type \"knife upload .\"")
+ ui.fatal("You must specify at least one argument. If you want to upload everything in this directory, run \"knife upload .\"")
exit 1
end
@@ -68,4 +68,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/knife/user_create.rb b/lib/chef/knife/user_create.rb
index 995573cd03..d21afb1059 100644
--- a/lib/chef/knife/user_create.rb
+++ b/lib/chef/knife/user_create.rb
@@ -1,7 +1,7 @@
#
# Author:: Steven Danna (<steve@chef.io>)
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2012, 2015 Chef Software, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/osc_user_create'
+require "chef/knife"
+require "chef/knife/osc_user_create"
class Chef
class Knife
@@ -27,8 +27,8 @@ class Chef
attr_accessor :user_field
deps do
- require 'chef/user_v1'
- require 'chef/json_compat'
+ require "chef/user_v1"
+ require "chef/json_compat"
end
option :file,
@@ -38,12 +38,12 @@ class Chef
option :user_key,
:long => "--user-key FILENAME",
- :description => "Set the initial default key for the user from a file on disk (cannot pass with --prevent-keygen)."
+ :description => "Set the initial default key for the user from a file on disk (cannot pass with --prevent-keygen)."
option :prevent_keygen,
:short => "-k",
:long => "--prevent-keygen",
- :description => "API V1 only. Prevent server from generating a default key pair for you. Cannot be passed with --user-key.",
+ :description => "API V1 (Chef Server 12.1+) only. Prevent server from generating a default key pair for you. Cannot be passed with --user-key.",
:boolean => true
option :admin,
@@ -69,7 +69,7 @@ class Chef
end
def osc_11_warning
-<<-EOF
+ <<-EOF
IF YOU ARE USING CHEF SERVER 12+, PLEASE FOLLOW THE INSTRUCTIONS UNDER knife user create --help.
You only passed a single argument to knife user create.
For backwards compatibility, when only a single argument is passed,
@@ -130,7 +130,7 @@ EOF
user.public_key File.read(File.expand_path(config[:user_key]))
end
- output = edit_data(user)
+ output = edit_hash(user)
final_user = create_user_from_hash(output)
ui.info("Created #{user}")
@@ -144,8 +144,6 @@ EOF
end
end
end
-
-
end
end
end
diff --git a/lib/chef/knife/user_delete.rb b/lib/chef/knife/user_delete.rb
index 828cd51588..cc92b4b36c 100644
--- a/lib/chef/knife/user_delete.rb
+++ b/lib/chef/knife/user_delete.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,21 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class UserDelete < Knife
deps do
- require 'chef/user_v1'
- require 'chef/json_compat'
+ require "chef/user_v1"
+ require "chef/json_compat"
end
banner "knife user delete USER (options)"
def osc_11_warning
-<<-EOF
+ <<-EOF
The Chef Server you are using does not support the username field.
This means it is an Open Source 11 Server.
knife user delete for Open Source 11 Server is being deprecated.
@@ -60,7 +60,7 @@ EOF
end
output(format_for_display(object)) if config[:print_after]
- self.msg("Deleted #{user_name}")
+ msg("Deleted #{user_name}")
end
def run
@@ -89,7 +89,6 @@ EOF
else # proceed with EC / CS delete
delete_object(@user_name)
end
-
end
end
end
diff --git a/lib/chef/knife/user_edit.rb b/lib/chef/knife/user_edit.rb
index c3a4326ee8..bb80ede267 100644
--- a/lib/chef/knife/user_edit.rb
+++ b/lib/chef/knife/user_edit.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,21 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class UserEdit < Knife
deps do
- require 'chef/user_v1'
- require 'chef/json_compat'
+ require "chef/user_v1"
+ require "chef/json_compat"
end
banner "knife user edit USER (options)"
def osc_11_warning
-<<-EOF
+ <<-EOF
The Chef Server you are using does not support the username field.
This means it is an Open Source 11 Server.
knife user edit for Open Source 11 Server is being deprecated.
@@ -66,7 +66,7 @@ EOF
ui.warn(osc_11_warning)
run_osc_11_user_edit
else # EC / CS 12 user create
- edited_user = edit_data(original_user)
+ edited_user = edit_hash(original_user)
if original_user != edited_user
user = Chef::UserV1.from_hash(edited_user)
user.update
@@ -75,7 +75,6 @@ EOF
ui.msg("User unchanged, not saving.")
end
end
-
end
end
end
diff --git a/lib/chef/knife/user_key_create.rb b/lib/chef/knife/user_key_create.rb
index 5ed699ff5b..95a98a2f4f 100644
--- a/lib/chef/knife/user_key_create.rb
+++ b/lib/chef/knife/user_key_create.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/key_create_base'
+require "chef/knife"
+require "chef/knife/key_create_base"
class Chef
class Knife
@@ -30,11 +30,11 @@ class Chef
class UserKeyCreate < Knife
include Chef::Knife::KeyCreateBase
- banner 'knife user key create USER (options)'
+ banner "knife user key create USER (options)"
attr_reader :actor
- def initialize(argv=[])
+ def initialize(argv = [])
super(argv)
@service_object = nil
end
@@ -45,7 +45,7 @@ class Chef
end
def actor_field_name
- 'user'
+ "user"
end
def service_object
@@ -53,7 +53,7 @@ class Chef
end
def actor_missing_error
- 'You must specify a user name'
+ "You must specify a user name"
end
def apply_params!(params)
diff --git a/lib/chef/knife/user_key_delete.rb b/lib/chef/knife/user_key_delete.rb
index 6db1c9f552..1c559f2ef0 100644
--- a/lib/chef/knife/user_key_delete.rb
+++ b/lib/chef/knife/user_key_delete.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -31,7 +31,7 @@ class Chef
attr_reader :actor
- def initialize(argv=[])
+ def initialize(argv = [])
super(argv)
@service_object = nil
end
@@ -42,15 +42,15 @@ class Chef
end
def actor_field_name
- 'user'
+ "user"
end
def actor_missing_error
- 'You must specify a user name'
+ "You must specify a user name"
end
def keyname_missing_error
- 'You must specify a key name'
+ "You must specify a key name"
end
def service_object
diff --git a/lib/chef/knife/user_key_edit.rb b/lib/chef/knife/user_key_edit.rb
index 0c35332523..561af8edd0 100644
--- a/lib/chef/knife/user_key_edit.rb
+++ b/lib/chef/knife/user_key_edit.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/key_edit_base'
+require "chef/knife"
+require "chef/knife/key_edit_base"
class Chef
class Knife
@@ -30,11 +30,11 @@ class Chef
class UserKeyEdit < Knife
include Chef::Knife::KeyEditBase
- banner 'knife user key edit USER KEYNAME (options)'
+ banner "knife user key edit USER KEYNAME (options)"
attr_reader :actor
- def initialize(argv=[])
+ def initialize(argv = [])
super(argv)
@service_object = nil
end
@@ -45,7 +45,7 @@ class Chef
end
def actor_field_name
- 'user'
+ "user"
end
def service_object
@@ -53,11 +53,11 @@ class Chef
end
def actor_missing_error
- 'You must specify a user name'
+ "You must specify a user name"
end
def keyname_missing_error
- 'You must specify a key name'
+ "You must specify a key name"
end
def apply_params!(params)
@@ -77,4 +77,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/knife/user_key_list.rb b/lib/chef/knife/user_key_list.rb
index a73f59c86f..799c069182 100644
--- a/lib/chef/knife/user_key_list.rb
+++ b/lib/chef/knife/user_key_list.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/knife/key_list_base'
+require "chef/knife"
+require "chef/knife/key_list_base"
class Chef
class Knife
@@ -34,7 +34,7 @@ class Chef
attr_reader :actor
- def initialize(argv=[])
+ def initialize(argv = [])
super(argv)
@service_object = nil
end
@@ -49,7 +49,7 @@ class Chef
end
def actor_missing_error
- 'You must specify a user name'
+ "You must specify a user name"
end
def service_object
diff --git a/lib/chef/knife/user_key_show.rb b/lib/chef/knife/user_key_show.rb
index b8453dd28e..e09d5e04ed 100644
--- a/lib/chef/knife/user_key_show.rb
+++ b/lib/chef/knife/user_key_show.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -31,7 +31,7 @@ class Chef
attr_reader :actor
- def initialize(argv=[])
+ def initialize(argv = [])
super(argv)
@service_object = nil
end
@@ -46,11 +46,11 @@ class Chef
end
def actor_missing_error
- 'You must specify a user name'
+ "You must specify a user name"
end
def keyname_missing_error
- 'You must specify a key name'
+ "You must specify a key name"
end
def service_object
diff --git a/lib/chef/knife/user_list.rb b/lib/chef/knife/user_list.rb
index 6a130392b9..88e834025d 100644
--- a/lib/chef/knife/user_list.rb
+++ b/lib/chef/knife/user_list.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
# NOTE: only knife user command that is backwards compatible with OSC 11,
# so no deprecation warnings are necessary.
@@ -25,8 +25,8 @@ class Chef
class UserList < Knife
deps do
- require 'chef/user_v1'
- require 'chef/json_compat'
+ require "chef/user_v1"
+ require "chef/json_compat"
end
banner "knife user list (options)"
diff --git a/lib/chef/knife/user_reregister.rb b/lib/chef/knife/user_reregister.rb
index 09fd1cd2d6..8d2f2c1e73 100644
--- a/lib/chef/knife/user_reregister.rb
+++ b/lib/chef/knife/user_reregister.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,21 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
class UserReregister < Knife
deps do
- require 'chef/user_v1'
- require 'chef/json_compat'
+ require "chef/user_v1"
+ require "chef/json_compat"
end
banner "knife user reregister USER (options)"
def osc_11_warning
-<<-EOF
+ <<-EOF
The Chef Server you are using does not support the username field.
This means it is an Open Source 11 Server.
knife user reregister for Open Source 11 Server is being deprecated.
@@ -83,7 +83,6 @@ EOF
ui.msg key
end
end
-
end
end
end
diff --git a/lib/chef/knife/user_show.rb b/lib/chef/knife/user_show.rb
index 3a2443471a..04251c0863 100644
--- a/lib/chef/knife/user_show.rb
+++ b/lib/chef/knife/user_show.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/knife'
+require "chef/knife"
class Chef
class Knife
@@ -25,14 +25,14 @@ class Chef
include Knife::Core::MultiAttributeReturnOption
deps do
- require 'chef/user_v1'
- require 'chef/json_compat'
+ require "chef/user_v1"
+ require "chef/json_compat"
end
banner "knife user show USER (options)"
def osc_11_warning
-<<-EOF
+ <<-EOF
The Chef Server you are using does not support the username field.
This means it is an Open Source 11 Server.
knife user show for Open Source 11 Server is being deprecated.
diff --git a/lib/chef/knife/xargs.rb b/lib/chef/knife/xargs.rb
index dd8e848058..6559ca2e74 100644
--- a/lib/chef/knife/xargs.rb
+++ b/lib/chef/knife/xargs.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
class Chef
class Knife
@@ -8,65 +8,65 @@ class Chef
category "path-based"
deps do
- require 'chef/chef_fs/file_system'
- require 'chef/chef_fs/file_system/not_found_error'
+ require "chef/chef_fs/file_system"
+ require "chef/chef_fs/file_system/not_found_error"
end
# TODO modify to remote-only / local-only pattern (more like delete)
option :local,
- :long => '--local',
+ :long => "--local",
:boolean => true,
:description => "Xargs local files instead of remote"
option :patterns,
- :long => '--pattern [PATTERN]',
- :short => '-p [PATTERN]',
- :description => "Pattern on command line (if these are not specified, a list of patterns is expected on standard input). Multiple patterns may be passed in this way.",
- :arg_arity => [1,-1]
+ :long => "--pattern [PATTERN]",
+ :short => "-p [PATTERN]",
+ :description => "Pattern on command line (if these are not specified, a list of patterns is expected on standard input). Multiple patterns may be passed in this way.",
+ :arg_arity => [1, -1]
option :diff,
- :long => '--[no-]diff',
+ :long => "--[no-]diff",
:default => true,
:boolean => true,
:description => "Whether to show a diff when files change (default: true)"
option :dry_run,
- :long => '--dry-run',
+ :long => "--dry-run",
:boolean => true,
:description => "Prevents changes from actually being uploaded to the server."
option :force,
- :long => '--[no-]force',
+ :long => "--[no-]force",
:boolean => true,
:default => false,
:description => "Force upload of files even if they are not changed (quicker and harmless, but doesn't print out what it changed)"
option :replace_first,
- :long => '--replace-first REPLACESTR',
- :short => '-J REPLACESTR',
- :description => "String to replace with filenames. -J will only replace the FIRST occurrence of the replacement string."
+ :long => "--replace-first REPLACESTR",
+ :short => "-J REPLACESTR",
+ :description => "String to replace with filenames. -J will only replace the FIRST occurrence of the replacement string."
option :replace_all,
- :long => '--replace REPLACESTR',
- :short => '-I REPLACESTR',
- :description => "String to replace with filenames. -I will replace ALL occurrence of the replacement string."
+ :long => "--replace REPLACESTR",
+ :short => "-I REPLACESTR",
+ :description => "String to replace with filenames. -I will replace ALL occurrence of the replacement string."
option :max_arguments_per_command,
- :long => '--max-args MAXARGS',
- :short => '-n MAXARGS',
+ :long => "--max-args MAXARGS",
+ :short => "-n MAXARGS",
:description => "Maximum number of arguments per command line."
option :max_command_line,
- :long => '--max-chars LENGTH',
- :short => '-s LENGTH',
+ :long => "--max-chars LENGTH",
+ :short => "-s LENGTH",
:description => "Maximum size of command line, in characters"
option :verbose_commands,
- :short => '-t',
+ :short => "-t",
:description => "Print command to be run on the command line"
option :null_separator,
- :short => '-0',
+ :short => "-0",
:boolean => true,
:description => "Use the NULL character (\0) as a separator, instead of whitespace"
@@ -78,7 +78,7 @@ class Chef
Chef::ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern).each do |result|
if result.dir?
# TODO option to include directories
- ui.warn "#{format_path(result)}: is a directory. Will not run #{command} on it."
+ ui.warn "#{format_path(result)}: is a directory. Will not run #{command} on it."
else
files << result
ran = false
@@ -151,7 +151,7 @@ class Chef
end
def create_command(files)
- command = name_args.join(' ')
+ command = name_args.join(" ")
# Create the (empty) tempfiles
tempfiles = {}
@@ -167,7 +167,7 @@ class Chef
end
# Create the command
- paths = tempfiles.keys.map { |tempfile| tempfile.path }.join(' ')
+ paths = tempfiles.keys.map { |tempfile| tempfile.path }.join(" ")
if config[:replace_all]
final_command = command.gsub(config[:replace_all], paths)
elsif config[:replace_first]
@@ -264,4 +264,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/local_mode.rb b/lib/chef/local_mode.rb
index fbb72cd6cb..5ce17e6fb3 100644
--- a/lib/chef/local_mode.rb
+++ b/lib/chef/local_mode.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@getchef.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,10 +14,10 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/config'
+require "chef/config"
if Chef::Platform.windows?
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.1')
- require 'chef/monkey_patches/webrick-utils'
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.1")
+ require "chef/monkey_patches/webrick-utils"
end
end
@@ -54,17 +54,19 @@ class Chef
if Chef::Config.chef_zero.enabled
destroy_server_connectivity
- require 'chef_zero/server'
- require 'chef/chef_fs/chef_fs_data_store'
- require 'chef/chef_fs/config'
+ require "chef_zero/server"
+ require "chef/chef_fs/chef_fs_data_store"
+ require "chef/chef_fs/config"
@chef_fs = Chef::ChefFS::Config.new.local_fs
@chef_fs.write_pretty_json = true
data_store = Chef::ChefFS::ChefFSDataStore.new(@chef_fs)
- data_store = ChefZero::DataStore::V1ToV2Adapter.new(data_store, 'chef')
+ data_store = ChefZero::DataStore::V1ToV2Adapter.new(data_store, "chef")
server_options = {}
server_options[:data_store] = data_store
server_options[:log_level] = Chef::Log.level
+ server_options[:osc_compat] = Chef::Config.chef_zero.osc_compat
+ server_options[:single_org] = Chef::Config.chef_zero.single_org
server_options[:host] = Chef::Config.chef_zero.host
server_options[:port] = parse_port(Chef::Config.chef_zero.port)
@@ -103,9 +105,9 @@ class Chef
def self.parse_port(port)
if port.is_a?(String)
- parts = port.split(',')
+ parts = port.split(",")
if parts.size == 1
- a,b = parts[0].split('-',2)
+ a, b = parts[0].split("-", 2)
if b
a.to_i.upto(b.to_i)
else
diff --git a/lib/chef/log.rb b/lib/chef/log.rb
index bf846c2072..10c9f0f20d 100644
--- a/lib/chef/log.rb
+++ b/lib/chef/log.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: AJ Christensen (<@aj@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Christopher Brown (<cb@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,12 +17,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'logger'
-require 'chef/monologger'
-require 'chef/exceptions'
-require 'mixlib/log'
-require 'chef/log/syslog' unless (RUBY_PLATFORM =~ /mswin|mingw|windows/)
-require 'chef/log/winevt'
+require "logger"
+require "chef/monologger"
+require "chef/exceptions"
+require "mixlib/log"
+require "chef/log/syslog" unless RUBY_PLATFORM =~ /mswin|mingw|windows/
+require "chef/log/winevt"
class Chef
class Log
@@ -37,14 +37,28 @@ class Chef
end
end
- def self.deprecation(msg=nil, location=caller(2..2)[0], &block)
+ #
+ # Get the location of the caller (from the recipe). Grabs the first caller
+ # that is *not* in the chef gem proper (allowing us to weed out internal
+ # calls and give the user a more useful perspective).
+ #
+ # @return [String] The location of the caller (file:line#) from caller(0..20), or nil if no non-chef caller is found.
+ #
+ def self.caller_location
+ # Pick the first caller that is *not* part of the Chef gem, that's the
+ # thing the user wrote.
+ chef_gem_path = File.expand_path("../..", __FILE__)
+ caller(0..20).find { |c| !c.start_with?(chef_gem_path) }
+ end
+
+ def self.deprecation(msg = nil, location = caller(2..2)[0], &block)
if msg
msg << " at #{Array(location).join("\n")}"
msg = msg.join("") if msg.respond_to?(:join)
end
if Chef::Config[:treat_deprecation_warnings_as_errors]
error(msg, &block)
- raise Chef::Exceptions::DeprecatedFeatureError.new(msg)
+ raise Chef::Exceptions::DeprecatedFeatureError.new(msg.inspect)
else
warn(msg, &block)
end
diff --git a/lib/chef/log/syslog.rb b/lib/chef/log/syslog.rb
index 0c8190797f..58d6671095 100644
--- a/lib/chef/log/syslog.rb
+++ b/lib/chef/log/syslog.rb
@@ -1,7 +1,7 @@
#
# Author:: Lamont Granquist (<lamont@chef.io>)
# Author:: SAWANOBORI Yukihiko (<sawanoboriyu@higanworks.com>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'logger'
-require 'syslog-logger'
-require 'chef/mixin/unformatter'
+require "logger"
+require "syslog-logger"
+require "chef/mixin/unformatter"
class Chef
class Log
@@ -32,7 +32,7 @@ class Chef
attr_accessor :sync, :formatter
- def initialize(program_name = 'chef-client', facility = ::Syslog::LOG_DAEMON, logopts=nil)
+ def initialize(program_name = "chef-client", facility = ::Syslog::LOG_DAEMON, logopts = nil)
super
return if defined? ::Logger::Syslog::SYSLOG
::Logger::Syslog.const_set :SYSLOG, SYSLOG
@@ -43,4 +43,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/log/winevt.rb b/lib/chef/log/winevt.rb
index c5b7c3485a..506d4c9a6c 100644
--- a/lib/chef/log/winevt.rb
+++ b/lib/chef/log/winevt.rb
@@ -1,7 +1,7 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
#
-# Copyright:: 2015, Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/event_loggers/base'
-require 'chef/platform/query_helpers'
-require 'chef/mixin/unformatter'
+require "chef/event_loggers/base"
+require "chef/platform/query_helpers"
+require "chef/mixin/unformatter"
class Chef
class Log
@@ -36,14 +36,14 @@ class Chef
FATAL_EVENT_ID = 10104
# Since we must install the event logger, this is not really configurable
- SOURCE = 'Chef'
+ SOURCE = "Chef"
include Chef::Mixin::Unformatter
attr_accessor :sync, :formatter, :level
- def initialize(eventlog=nil)
- @eventlog = eventlog || ::Win32::EventLog::open('Application')
+ def initialize(eventlog = nil)
+ @eventlog = eventlog || ::Win32::EventLog.open("Application")
end
def close
diff --git a/lib/chef/mash.rb b/lib/chef/mash.rb
index edd254cb77..4e4f06634d 100644
--- a/lib/chef/mash.rb
+++ b/lib/chef/mash.rb
@@ -1,4 +1,4 @@
-# Copyright (c) 2009 Dan Kubb
+# Copyright 2009-2016, Dan Kubb
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -25,7 +25,7 @@
# Some portions of blank.rb and mash.rb are verbatim copies of software
# licensed under the MIT license. That license is included below:
-# Copyright (c) 2005-2008 David Heinemeier Hansson
+# Copyright 2005-2016, David Heinemeier Hansson
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -71,7 +71,7 @@ class Mash < Hash
def initialize_copy(orig)
super
# Handle nested values
- each do |k,v|
+ each do |k, v|
if v.kind_of?(Mash) || v.is_a?(Array)
self[k] = v.dup
end
@@ -142,14 +142,14 @@ class Mash < Hash
#
# @return [Array] The values at each of the provided keys
def values_at(*indices)
- indices.collect {|key| self[convert_key(key)]}
+ indices.collect { |key| self[convert_key(key)] }
end
# @param hash<Hash> The hash to merge with the mash.
#
# @return [Mash] A new mash with the hash values merged in.
def merge(hash)
- self.dup.update(hash)
+ dup.update(hash)
end
# @param key<Object>
@@ -166,7 +166,7 @@ class Mash < Hash
# { :one => 1, :two => 2, :three => 3 }.except(:one)
# #=> { "two" => 2, "three" => 3 }
def except(*keys)
- super(*keys.map {|k| convert_key(k)})
+ super(*keys.map { |k| convert_key(k) })
end
# Used to provide the same interface as Hash.
@@ -195,6 +195,7 @@ class Mash < Hash
end
protected
+
# @param key<Object> The key to convert.
#
# @param [Object]
diff --git a/lib/chef/mixin/api_version_request_handling.rb b/lib/chef/mixin/api_version_request_handling.rb
index 20ab3bf452..b91a1dfe0a 100644
--- a/lib/chef/mixin/api_version_request_handling.rb
+++ b/lib/chef/mixin/api_version_request_handling.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/mixin/checksum.rb b/lib/chef/mixin/checksum.rb
index 1d9c99ec7e..2888b205a9 100644
--- a/lib/chef/mixin/checksum.rb
+++ b/lib/chef/mixin/checksum.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'digest/sha2'
-require 'chef/digester'
+require "digest/sha2"
+require "chef/digester"
class Chef
module Mixin
@@ -27,6 +27,11 @@ class Chef
Chef::Digester.checksum_for_file(file)
end
+ def short_cksum(checksum)
+ return "none" if checksum.nil?
+ checksum.slice(0, 6)
+ end
+
end
end
end
diff --git a/lib/chef/mixin/command.rb b/lib/chef/mixin/command.rb
index d9a9c4f006..b1fa7ebd89 100644
--- a/lib/chef/mixin/command.rb
+++ b/lib/chef/mixin/command.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/exceptions'
-require 'tmpdir'
-require 'fcntl'
-require 'etc'
+require "chef/log"
+require "chef/exceptions"
+require "tmpdir"
+require "fcntl"
+require "etc"
class Chef
module Mixin
@@ -50,11 +50,11 @@ class Chef
# NOTE: run_command is deprecated in favor of using Chef::Shellout which now comes from the mixlib-shellout gem. NOTE #
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
- require 'chef/mixin/command/windows'
+ require "chef/mixin/command/windows"
include ::Chef::Mixin::Command::Windows
extend ::Chef::Mixin::Command::Windows
else
- require 'chef/mixin/command/unix'
+ require "chef/mixin/command/unix"
include ::Chef::Mixin::Command::Unix
extend ::Chef::Mixin::Command::Unix
end
@@ -75,7 +75,7 @@ class Chef
#
# === Returns
# Returns the exit status of args[:command]
- def run_command(args={})
+ def run_command(args = {})
status, stdout, stderr = run_command_and_return_stdout_stderr(args)
status
@@ -84,7 +84,7 @@ class Chef
# works same as above, except that it returns stdout and stderr
# requirement => platforms like solaris 9,10 has weird issues where
# even in command failure the exit code is zero, so we need to lookup stderr.
- def run_command_and_return_stdout_stderr(args={})
+ def run_command_and_return_stdout_stderr(args = {})
command_output = ""
args[:ignore_failure] ||= false
@@ -103,10 +103,11 @@ class Chef
command_output << "STDERR: #{stderr}"
handle_command_failures(status, command_output, args)
- return status, stdout, stderr
+ [status, stdout, stderr]
end
def output_of_command(command, args)
+ Chef.deprecated(:run_command, "Chef::Mixin::Command.run_command is deprecated, please use shell_out")
Chef::Log.debug("Executing #{command}")
stderr_string, stdout_string, status = "", "", nil
@@ -140,10 +141,10 @@ class Chef
Chef::Log.debug("Ran #{command} returned #{status.exitstatus}")
end
- return status, stdout_string, stderr_string
+ [status, stdout_string, stderr_string]
end
- def handle_command_failures(status, command_output, opts={})
+ def handle_command_failures(status, command_output, opts = {})
return if opts[:ignore_failure]
opts[:returns] ||= 0
return if Array(opts[:returns]).include?(status.exitstatus)
@@ -165,7 +166,7 @@ class Chef
#
# === Returns
# Returns the result of #run_command
- def run_command_with_systems_locale(args={})
+ def run_command_with_systems_locale(args = {})
args[:environment] ||= {}
args[:environment]["LC_ALL"] = ENV["LC_ALL"]
run_command args
@@ -177,13 +178,14 @@ class Chef
# module_function :popen4
- def chdir_or_tmpdir(dir, &block)
+ # FIXME: yard with @yield
+ def chdir_or_tmpdir(dir)
dir ||= Dir.tmpdir
unless File.directory?(dir)
raise Chef::Exceptions::Exec, "#{dir} does not exist or is not a directory"
end
Dir.chdir(dir) do
- block.call
+ yield
end
end
diff --git a/lib/chef/mixin/command/unix.rb b/lib/chef/mixin/command/unix.rb
index 2bad4e6bcf..aa541c3637 100644
--- a/lib/chef/mixin/command/unix.rb
+++ b/lib/chef/mixin/command/unix.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,7 +27,7 @@ class Chef
# The original appears in external/open4.rb in its unmodified form.
#
# Thanks Ara!
- def popen4(cmd, args={}, &b)
+ def popen4(cmd, args = {}, &b)
# Ruby 1.8 suffers from intermittent segfaults believed to be due to GC while IO.select
# See CHEF-2916 / CHEF-1305
GC.disable
@@ -64,7 +64,7 @@ class Chef
$VERBOSE = nil
ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
- cid = fork {
+ cid = fork do
pw.last.close
STDIN.reopen pw.first
pw.first.close
@@ -89,7 +89,7 @@ class Chef
Process.uid = args[:user]
end
- args[:environment].each do |key,value|
+ args[:environment].each do |key, value|
ENV[key] = value
end
@@ -104,19 +104,19 @@ class Chef
else
Kernel.exec(cmd)
end
- raise 'forty-two'
+ raise "forty-two"
rescue Exception => e
Marshal.dump(e, ps.last)
ps.last.flush
end
- ps.last.close unless (ps.last.closed?)
+ ps.last.close unless ps.last.closed?
exit!
- }
+ end
ensure
$VERBOSE = verbose
end
- [pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}
+ [pw.first, pr.last, pe.last, ps.last].each { |fd| fd.close }
begin
e = Marshal.load ps.first
@@ -205,7 +205,7 @@ class Chef
results.last
end
ensure
- pi.each{|fd| fd.close unless fd.closed?}
+ pi.each { |fd| fd.close unless fd.closed? }
end
else
[cid, pw.last, pr.first, pe.first]
diff --git a/lib/chef/mixin/command/windows.rb b/lib/chef/mixin/command/windows.rb
index 0147d58039..fd45ab0467 100644
--- a/lib/chef/mixin/command/windows.rb
+++ b/lib/chef/mixin/command/windows.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,20 +18,19 @@
# limitations under the License.
#
-require 'open3'
+require "open3"
class Chef
module Mixin
module Command
module Windows
- def popen4(cmd, args={}, &b)
-
+ def popen4(cmd, args = {}, &b)
# By default, we are waiting before we yield the block.
args[:waitlast] ||= false
#XXX :user, :group, :environment support?
- Open3.popen3(cmd) do |stdin,stdout,stderr,cid|
+ Open3.popen3(cmd) do |stdin, stdout, stderr, cid|
if b
if args[:waitlast]
b[cid, stdin, stdout, stderr]
diff --git a/lib/chef/mixin/convert_to_class_name.rb b/lib/chef/mixin/convert_to_class_name.rb
index 14676e5ed4..d6bd8a4ea7 100644
--- a/lib/chef/mixin/convert_to_class_name.rb
+++ b/lib/chef/mixin/convert_to_class_name.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -40,10 +40,10 @@ class Chef
rname
end
- def convert_to_snake_case(str, namespace=nil)
+ def convert_to_snake_case(str, namespace = nil)
str = str.dup
- str.sub!(/^#{namespace}(\:\:)?/, '') if namespace
- str.gsub!(/[A-Z]/) {|s| "_" + s}
+ str.sub!(/^#{namespace}(\:\:)?/, "") if namespace
+ str.gsub!(/[A-Z]/) { |s| "_" + s }
str.downcase!
str.sub!(/^\_/, "")
str
@@ -51,19 +51,19 @@ class Chef
def normalize_snake_case_name(str)
str = str.dup
- str.gsub!(/[^A-Za-z0-9_]/,'_')
- str.gsub!(/^(_+)?/,'')
+ str.gsub!(/[^A-Za-z0-9_]/, "_")
+ str.gsub!(/^(_+)?/, "")
str
end
def snake_case_basename(str)
with_namespace = convert_to_snake_case(str)
- with_namespace.split("::").last.sub(/^_/, '')
+ with_namespace.split("::").last.sub(/^_/, "")
end
def filename_to_qualified_string(base, filename)
file_base = File.basename(filename, ".rb")
- str = base.to_s + (file_base == 'default' ? '' : "_#{file_base}")
+ str = base.to_s + (file_base == "default" ? "" : "_#{file_base}")
normalize_snake_case_name(str)
end
@@ -91,7 +91,7 @@ class Chef
# NameError is raised when the name is not in CamelCase or the constant is
# unknown.
def constantize(camel_cased_word)
- names = camel_cased_word.split('::')
+ names = camel_cased_word.split("::")
# Trigger a built-in NameError exception including the ill-formed constant in the message.
Object.const_get(camel_cased_word) if names.empty?
diff --git a/lib/chef/mixin/create_path.rb b/lib/chef/mixin/create_path.rb
index 547224dda9..21a945d2ae 100644
--- a/lib/chef/mixin/create_path.rb
+++ b/lib/chef/mixin/create_path.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,7 +35,7 @@ class Chef
if file_path.kind_of?(String)
file_path = File.expand_path(file_path).split(File::SEPARATOR)
- file_path.shift if file_path[0] == ''
+ file_path.shift if file_path[0] == ""
# Check if path starts with a separator or drive letter (Windows)
unless file_path[0].match("^#{File::SEPARATOR}|^[a-zA-Z]:")
file_path[0] = "#{File::SEPARATOR}#{file_path[0]}"
@@ -53,7 +53,6 @@ class Chef
private
def create_dir(path)
- begin
# When doing multithreaded downloads into the file cache, the following
# interleaving raises an error here:
#
@@ -62,10 +61,9 @@ class Chef
# File.directory?(create_path) <- false
# Dir.mkdir(create_path)
# Dir.mkdir(create_path) <- raises Errno::EEXIST
- Chef::Log.debug("Creating directory #{path}")
- Dir.mkdir(path)
- rescue Errno::EEXIST
- end
+ Chef::Log.debug("Creating directory #{path}")
+ Dir.mkdir(path)
+ rescue Errno::EEXIST
end
end
diff --git a/lib/chef/mixin/deep_merge.rb b/lib/chef/mixin/deep_merge.rb
index 825406a93e..7016b08ff7 100644
--- a/lib/chef/mixin/deep_merge.rb
+++ b/lib/chef/mixin/deep_merge.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Steve Midgley (http://www.misuse.org/science)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2008 Steve Midgley
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2008-2016, Steve Midgley
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -75,7 +75,7 @@ class Chef
end
when Array
if dest.kind_of?(Array)
- dest = dest | source
+ dest |= source
else
dest = source
end
diff --git a/lib/chef/mixin/deprecation.rb b/lib/chef/mixin/deprecation.rb
index 562af541bd..14414036e7 100644
--- a/lib/chef/mixin/deprecation.rb
+++ b/lib/chef/mixin/deprecation.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,10 +19,9 @@
class Chef
module Mixin
-
- def self.deprecated_constants
- @deprecated_constants ||= {}
- end
+ def self.deprecated_constants
+ @deprecated_constants ||= {}
+ end
# Add a deprecated constant to the Chef::Mixin namespace.
# === Arguments
@@ -33,40 +32,40 @@ class Chef
# deprecate_constant(:RecipeDefinitionDSLCore, Chef::DSL::Recipe, <<-EOM)
# Chef::Mixin::RecipeDefinitionDSLCore is deprecated, use Chef::DSL::Recipe instead.
# EOM
- def self.deprecate_constant(name, replacement, message)
- deprecated_constants[name] = {:replacement => replacement, :message => message}
- end
+ def self.deprecate_constant(name, replacement, message)
+ deprecated_constants[name] = { :replacement => replacement, :message => message }
+ end
# Const missing hook to look up deprecated constants defined with
# deprecate_constant. Emits a warning to the logger and returns the
# replacement constant. Will call super, most likely causing an exception
# for the missing constant, if +name+ is not found in the
# deprecated_constants collection.
- def self.const_missing(name)
- if new_const = deprecated_constants[name]
- Chef::Log.warn(new_const[:message])
- Chef::Log.warn("Called from: \n#{caller[0...3].map {|l| "\t#{l}"}.join("\n")}")
- new_const[:replacement]
- else
- super
- end
+ def self.const_missing(name)
+ if new_const = deprecated_constants[name]
+ Chef::Log.warn(new_const[:message])
+ Chef::Log.warn("Called from: \n#{caller[0...3].map { |l| "\t#{l}" }.join("\n")}")
+ new_const[:replacement]
+ else
+ super
end
+ end
module Deprecation
class DeprecatedObjectProxyBase
KEEPERS = %w{__id__ __send__ instance_eval == equal? initialize object_id}
- instance_methods.each { |method_name| undef_method(method_name) unless KEEPERS.include?(method_name.to_s)}
+ instance_methods.each { |method_name| undef_method(method_name) unless KEEPERS.include?(method_name.to_s) }
end
class DeprecatedInstanceVariable < DeprecatedObjectProxyBase
- def initialize(target, ivar_name, level=nil)
+ def initialize(target, ivar_name, level = nil)
@target, @ivar_name = target, ivar_name
@level ||= :warn
end
def method_missing(method_name, *args, &block)
- log_deprecation_msg(caller[0..3])
+ deprecated_msg(caller[0..3])
@target.send(method_name, *args, &block)
end
@@ -76,11 +75,11 @@ class Chef
private
- def log_deprecation_msg(*called_from)
+ def deprecated_msg(*called_from)
called_from = called_from.flatten
log("Accessing #{@ivar_name} by the variable @#{@ivar_name} is deprecated. Support will be removed in a future release.")
log("Please update your cookbooks to use #{@ivar_name} in place of @#{@ivar_name}. Accessed from:")
- called_from.each {|l| log(l)}
+ called_from.each { |l| log(l) }
end
def log(msg)
@@ -91,7 +90,7 @@ class Chef
end
- def deprecated_ivar(obj, name, level=nil)
+ def deprecated_ivar(obj, name, level = nil)
DeprecatedInstanceVariable.new(obj, name, level)
end
@@ -100,22 +99,16 @@ class Chef
deprecated_attr_writer(name, alternative)
end
- def deprecated_attr_reader(name, alternative, level=:warn)
+ def deprecated_attr_reader(name, alternative, level = :warn)
define_method(name) do
- Chef.log_deprecation("#{self.class}.#{name} is deprecated. Support will be removed in a future release.")
- Chef.log_deprecation(alternative)
- Chef.log_deprecation("Called from:")
- caller[0..3].each {|c| Chef.log_deprecation(c)}
+ Chef.deprecated(:internal_api, "#{self.class}.#{name} is deprecated. Support will be removed in a future release. #{alternative}")
instance_variable_get("@#{name}")
end
end
- def deprecated_attr_writer(name, alternative, level=:warn)
+ def deprecated_attr_writer(name, alternative, level = :warn)
define_method("#{name}=") do |value|
- Chef.log_deprecation("Writing to #{self.class}.#{name} with #{name}= is deprecated. Support will be removed in a future release.")
- Chef.log_deprecation(alternative)
- Chef.log_deprecation("Called from:")
- caller[0..3].each {|c| Chef.log_deprecation(c)}
+ Chef.deprecated(:internal_api, "Writing to #{self.class}.#{name} with #{name}= is deprecated. Support will be removed in a future release. #{alternative}")
instance_variable_set("@#{name}", value)
end
end
diff --git a/lib/chef/mixin/descendants_tracker.rb b/lib/chef/mixin/descendants_tracker.rb
index 75d1f620d4..b0f0ff2227 100644
--- a/lib/chef/mixin/descendants_tracker.rb
+++ b/lib/chef/mixin/descendants_tracker.rb
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2005-2012 David Heinemeier Hansson
+# Copyright 2005-2016, David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -21,7 +21,6 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-
# This is lifted from rails activesupport (note the copyright above):
# https://github.com/rails/rails/blob/9f84e60ac9d7bf07d6ae1bc94f3941f5b8f1a228/activesupport/lib/active_support/descendants_tracker.rb
@@ -42,7 +41,7 @@ class Chef
end
def find_descendants_by_name(klass, name)
- descendants(klass).first {|c| c.name == name }
+ descendants(klass).first { |c| c.name == name }
end
# This is the only method that is not thread safe, but is only ever called
diff --git a/lib/chef/mixin/enforce_ownership_and_permissions.rb b/lib/chef/mixin/enforce_ownership_and_permissions.rb
index 9c1e4dda93..e02c34748f 100644
--- a/lib/chef/mixin/enforce_ownership_and_permissions.rb
+++ b/lib/chef/mixin/enforce_ownership_and_permissions.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/file_access_control'
+require "chef/file_access_control"
class Chef
module Mixin
diff --git a/lib/chef/mixin/file_class.rb b/lib/chef/mixin/file_class.rb
index f6a663daed..166dd5796a 100644
--- a/lib/chef/mixin/file_class.rb
+++ b/lib/chef/mixin/file_class.rb
@@ -1,8 +1,8 @@
#
-# Author:: Mark Mzyk <mmzyk@opscode.com>
-# Author:: Seth Chisamore <schisamo@opscode.com>
-# Author:: Bryan McLellan <btm@opscode.com>
-# Copyright:: Copyright (c) 2011-2012 Opscode, Inc.
+# Author:: Mark Mzyk <mmzyk@chef.io>
+# Author:: Seth Chisamore <schisamo@chef.io>
+# Author:: Bryan McLellan <btm@chef.io>
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,14 +24,12 @@ class Chef
def file_class
@host_os_file ||= if Chef::Platform.windows?
- require 'chef/win32/file'
- Chef::ReservedNames::Win32::File
- else
- ::File
- end
+ require "chef/win32/file"
+ Chef::ReservedNames::Win32::File
+ else
+ ::File
+ end
end
end
end
end
-
-
diff --git a/lib/chef/mixin/from_file.rb b/lib/chef/mixin/from_file.rb
index 0d1ddca4fa..4afea5d9f4 100644
--- a/lib/chef/mixin/from_file.rb
+++ b/lib/chef/mixin/from_file.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,7 +27,7 @@ class Chef
# Raises an IOError if the file cannot be found, or is not readable.
def from_file(filename)
if File.exists?(filename) && File.readable?(filename)
- self.instance_eval(IO.read(filename), filename, 1)
+ instance_eval(IO.read(filename), filename, 1)
else
raise IOError, "Cannot open or read #{filename}!"
end
@@ -39,7 +39,7 @@ class Chef
# Raises an IOError if the file cannot be found, or is not readable.
def class_from_file(filename)
if File.exists?(filename) && File.readable?(filename)
- self.class_eval(IO.read(filename), filename, 1)
+ class_eval(IO.read(filename), filename, 1)
else
raise IOError, "Cannot open or read #{filename}!"
end
diff --git a/lib/chef/mixin/get_source_from_package.rb b/lib/chef/mixin/get_source_from_package.rb
index 2ed251854a..96cef058ed 100644
--- a/lib/chef/mixin/get_source_from_package.rb
+++ b/lib/chef/mixin/get_source_from_package.rb
@@ -1,5 +1,5 @@
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,6 @@
# limitations under the License.
#
-
#
# mixin to make this syntax work without specifying a source:
#
@@ -27,17 +26,22 @@
class Chef
module Mixin
module GetSourceFromPackage
+ # FIXME: this is some bad code that I wrote a long time ago.
+ # - it does too much in the initializer
+ # - it mutates the new_resource
+ # - it does not support multipackage arrays
+ # this code is deprecated, check out the :use_package_names_for_source
+ # subclass directive instead
def initialize(new_resource, run_context)
super
return if new_resource.package_name.is_a?(Array)
# if we're passed something that looks like a filesystem path, with no source, use it
# - require at least one '/' in the path to avoid gem_package "foo" breaking if a file named 'foo' exists in the cwd
- if new_resource.source.nil? && new_resource.package_name.match(/#{::File::SEPARATOR}/) && ::File.exists?(new_resource.package_name)
+ if new_resource.source.nil? && new_resource.package_name.match(/#{::File::SEPARATOR}/) && ::File.exist?(new_resource.package_name)
Chef::Log.debug("No package source specified, but #{new_resource.package_name} exists on the filesystem, copying to package source")
- new_resource.source(@new_resource.package_name)
+ new_resource.source(new_resource.package_name)
end
end
end
end
end
-
diff --git a/lib/chef/mixin/homebrew_user.rb b/lib/chef/mixin/homebrew_user.rb
index ab6fb19563..888c1bcbfd 100644
--- a/lib/chef/mixin/homebrew_user.rb
+++ b/lib/chef/mixin/homebrew_user.rb
@@ -1,9 +1,9 @@
#
-# Author:: Joshua Timberman (<joshua@getchef.com>)
+# Author:: Joshua Timberman (<joshua@chef.io>)
# Author:: Graeme Mathieson (<mathie@woss.name>)
#
-# Copyright 2011-2013, Opscode, Inc.
-# Copyright 2014, Chef Software, Inc <legal@getchef.com>
+# Copyright 2011-2016, Chef Software Inc.
+# Copyright 2014-2016, Chef Software, Inc <legal@chef.io>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -22,8 +22,8 @@
# This lives here in Chef::Mixin because Chef's namespacing makes it
# awkward to use modules elsewhere (e.g., chef/provider/package/homebrew/owner)
-require 'chef/mixin/shell_out'
-require 'etc'
+require "chef/mixin/shell_out"
+require "etc"
class Chef
module Mixin
@@ -48,7 +48,7 @@ class Chef
private
def calculate_owner
- default_brew_path = '/usr/local/bin/brew'
+ default_brew_path = "/usr/local/bin/brew"
if ::File.exist?(default_brew_path)
# By default, this follows symlinks which is what we want
owner = ::File.stat(default_brew_path).uid
diff --git a/lib/chef/mixin/language.rb b/lib/chef/mixin/language.rb
index f4df86bdc3..3f53645a55 100644
--- a/lib/chef/mixin/language.rb
+++ b/lib/chef/mixin/language.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/dsl/platform_introspection'
-require 'chef/dsl/data_query'
-require 'chef/mixin/deprecation'
+require "chef/dsl/platform_introspection"
+require "chef/dsl/data_query"
+require "chef/mixin/deprecation"
class Chef
module Mixin
diff --git a/lib/chef/mixin/language_include_attribute.rb b/lib/chef/mixin/language_include_attribute.rb
index 0be2614e41..7cb66dc272 100644
--- a/lib/chef/mixin/language_include_attribute.rb
+++ b/lib/chef/mixin/language_include_attribute.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/dsl/include_attribute'
-require 'chef/mixin/deprecation'
+require "chef/dsl/include_attribute"
+require "chef/mixin/deprecation"
class Chef
module Mixin
@@ -32,4 +32,3 @@ EOM
end
end
-
diff --git a/lib/chef/mixin/language_include_recipe.rb b/lib/chef/mixin/language_include_recipe.rb
index d85e5c682d..97e384c7c4 100644
--- a/lib/chef/mixin/language_include_recipe.rb
+++ b/lib/chef/mixin/language_include_recipe.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/dsl/include_recipe'
-require 'chef/mixin/deprecation'
+require "chef/dsl/include_recipe"
+require "chef/mixin/deprecation"
class Chef
module Mixin
@@ -29,4 +29,3 @@ EOM
end
end
-
diff --git a/lib/chef/mixin/lazy_module_include.rb b/lib/chef/mixin/lazy_module_include.rb
new file mode 100644
index 0000000000..34e1fce4f1
--- /dev/null
+++ b/lib/chef/mixin/lazy_module_include.rb
@@ -0,0 +1,77 @@
+#
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ module Mixin
+ # If you have:
+ #
+ # module A
+ # extend LazyModuleInclude
+ # end
+ #
+ # module B
+ # include A
+ # end
+ #
+ # module C
+ # include B
+ # end
+ #
+ # module Monkeypatches
+ # def monkey
+ # puts "monkey!"
+ # end
+ # end
+ #
+ # A.send(:include, Monkeypatches)
+ #
+ # Then B and C and any classes that they're included in will also get the #monkey method patched into them.
+ #
+ module LazyModuleInclude
+
+ # Most of the magick is in this hook which creates a closure over the parent class and then builds an
+ # "infector" module which infects all descendants and which is responsible for updating the list of
+ # descendants in the parent class.
+ def included(klass)
+ super
+ parent_klass = self
+ infector = Module.new do
+ define_method(:included) do |subklass|
+ super(subklass)
+ subklass.extend(infector)
+ parent_klass.descendants.push(subklass)
+ end
+ end
+ klass.extend(infector)
+ parent_klass.descendants.push(klass)
+ end
+
+ def descendants
+ @descendants ||= []
+ end
+
+ def include(*classes)
+ super
+ classes.each do |klass|
+ descendants.each do |descendant|
+ descendant.send(:include, klass)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/mixin/notifying_block.rb b/lib/chef/mixin/notifying_block.rb
new file mode 100644
index 0000000000..d3f235f968
--- /dev/null
+++ b/lib/chef/mixin/notifying_block.rb
@@ -0,0 +1,51 @@
+#--
+# Author:: Lamont Granquist <lamont@chef.io>
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class Chef
+ module Mixin
+ module NotifyingBlock
+
+ def notifying_block(&block)
+ subcontext = subcontext_block(&block)
+ Chef::Runner.new(subcontext).converge
+ ensure
+ # recipes don't have a new_resource
+ if respond_to?(:new_resource)
+ if subcontext && subcontext.resource_collection.any?(&:updated?)
+ new_resource.updated_by_last_action(true)
+ end
+ end
+ end
+
+ def subcontext_block(parent_context = nil, &block)
+ parent_context ||= @run_context
+ sub_run_context = parent_context.create_child
+
+ begin
+ outer_run_context = @run_context
+ @run_context = sub_run_context
+ instance_eval(&block)
+ ensure
+ @run_context = outer_run_context
+ end
+
+ sub_run_context
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/mixin/params_validate.rb b/lib/chef/mixin/params_validate.rb
index e3c7657b1b..0db058c3ab 100644
--- a/lib/chef/mixin/params_validate.rb
+++ b/lib/chef/mixin/params_validate.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,14 +15,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/constants'
-require 'chef/property'
-require 'chef/delayed_evaluator'
+require "chef/constants"
+require "chef/property"
+require "chef/delayed_evaluator"
class Chef
module Mixin
module ParamsValidate
-
# Takes a hash of options, along with a map to validate them. Returns the original
# options hash, plus any changes that might have been made (through things like setting
# default values in the validation map)
@@ -103,8 +102,8 @@ class Chef
when Hash
validation.each do |check, carg|
check_method = "_pv_#{check}"
- if self.respond_to?(check_method, true)
- self.send(check_method, opts, key, carg)
+ if respond_to?(check_method, true)
+ send(check_method, opts, key, carg)
else
raise ArgumentError, "Validation map has unknown check: #{check}"
end
@@ -141,7 +140,7 @@ class Chef
end
# Raise an exception if the parameter is not found.
- def _pv_required(opts, key, is_required=true, explicitly_allows_nil=false)
+ def _pv_required(opts, key, is_required = true, explicitly_allows_nil = false)
if is_required
return true if opts.has_key?(key.to_s) && (explicitly_allows_nil || !opts[key.to_s].nil?)
return true if opts.has_key?(key.to_sym) && (explicitly_allows_nil || !opts[key.to_sym].nil?)
@@ -330,10 +329,11 @@ class Chef
# property :x, name_property: true
# ```
#
- def _pv_name_property(opts, key, is_name_property=true)
+ def _pv_name_property(opts, key, is_name_property = true)
if is_name_property
if opts[key].nil?
- opts[key] = self.instance_variable_get(:"@name")
+ raise CannotValidateStaticallyError, "name_property cannot be evaluated without a resource." if self == Chef::Mixin::ParamsValidate
+ opts[key] = instance_variable_get(:"@name")
end
end
end
@@ -400,22 +400,34 @@ class Chef
return true if !opts.has_key?(key.to_s) && !opts.has_key?(key.to_sym)
value = _pv_opts_lookup(opts, key)
to_be = [ to_be ].flatten(1)
- to_be.each do |tb|
+ errors = []
+ passed = to_be.any? do |tb|
case tb
when Proc
- return true if instance_exec(value, &tb)
+ raise CannotValidateStaticallyError, "is: proc { } must be evaluated once for each resource" if self == Chef::Mixin::ParamsValidate
+ instance_exec(value, &tb)
when Property
- validate(opts, { key => tb.validation_options })
- return true
+ begin
+ validate(opts, { key => tb.validation_options })
+ true
+ rescue Exceptions::ValidationFailed
+ # re-raise immediately if there is only one "is" so we get a better stack
+ raise if to_be.size == 1
+ errors << $!
+ false
+ end
else
- return true if tb === value
+ tb === value
end
end
-
- if raise_error
- raise Exceptions::ValidationFailed, "Option #{key} must be one of: #{to_be.join(", ")}! You passed #{value.inspect}."
+ if passed
+ true
else
- false
+ message = "Property #{key} must be one of: #{to_be.map { |v| v.inspect }.join(", ")}! You passed #{value.inspect}."
+ unless errors.empty?
+ message << " Errors:\n#{errors.map { |m| "- #{m}" }.join("\n")}"
+ end
+ raise Exceptions::ValidationFailed, message
end
end
@@ -436,17 +448,25 @@ class Chef
#
def _pv_coerce(opts, key, coercer)
if opts.has_key?(key.to_s)
+ raise CannotValidateStaticallyError, "coerce must be evaluated for each resource." if self == Chef::Mixin::ParamsValidate
opts[key.to_s] = instance_exec(opts[key], &coercer)
elsif opts.has_key?(key.to_sym)
+ raise CannotValidateStaticallyError, "coerce must be evaluated for each resource." if self == Chef::Mixin::ParamsValidate
opts[key.to_sym] = instance_exec(opts[key], &coercer)
end
end
+ # We allow Chef::Mixin::ParamsValidate.validate(), but we will raise an
+ # error if you try to do anything requiring there to be an actual resource.
+ # This way, you can statically validate things if you have constant validation
+ # (which is the norm).
+ extend self
+
# Used by #set_or_return to avoid emitting a deprecation warning for
# "value nil" and to keep default stickiness working exactly the same
# @api private
class SetOrReturnProperty < Chef::Property
- def get(resource)
+ def get(resource, nil_set: false)
value = super
# All values are sticky, frozen or not
if !is_set?(resource)
@@ -455,10 +475,10 @@ class Chef
value
end
- def call(resource, value=NOT_PASSED)
+ def call(resource, value = NOT_PASSED)
# setting to nil does a get
if value.nil? && !explicitly_accepts_nil?(resource)
- get(resource)
+ get(resource, nil_set: true)
else
super
end
diff --git a/lib/chef/mixin/path_sanity.rb b/lib/chef/mixin/path_sanity.rb
index ed857ffd36..6a8e017bcd 100644
--- a/lib/chef/mixin/path_sanity.rb
+++ b/lib/chef/mixin/path_sanity.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,10 +20,10 @@ class Chef
module Mixin
module PathSanity
- def enforce_path_sanity(env=ENV)
+ def enforce_path_sanity(env = ENV)
if Chef::Config[:enforce_path_sanity]
env["PATH"] = "" if env["PATH"].nil?
- path_separator = Chef::Platform.windows? ? ';' : ':'
+ path_separator = Chef::Platform.windows? ? ";" : ":"
existing_paths = env["PATH"].split(path_separator)
# ensure the Ruby and Gem bindirs are included
# mainly for 'full-stack' Chef installs
@@ -37,7 +37,7 @@ class Chef
env_path = env["PATH"].dup
env_path << path_separator unless env["PATH"].empty?
env_path << sane_path
- env["PATH"] = env_path
+ env["PATH"] = env_path.encode("utf-8", invalid: :replace, undef: :replace)
end
end
end
@@ -48,15 +48,15 @@ class Chef
def sane_paths
@sane_paths ||= begin
if Chef::Platform.windows?
- %w[]
+ %w{}
else
- %w[/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin]
+ %w{/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin}
end
end
end
def ruby_bindir
- RbConfig::CONFIG['bindir']
+ RbConfig::CONFIG["bindir"]
end
def gem_bindir
diff --git a/lib/chef/mixin/powershell_out.rb b/lib/chef/mixin/powershell_out.rb
index e4f29c07c4..ab7cf00a72 100644
--- a/lib/chef/mixin/powershell_out.rb
+++ b/lib/chef/mixin/powershell_out.rb
@@ -1,5 +1,5 @@
#--
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/mixin/shell_out'
-require 'chef/mixin/windows_architecture_helper'
+require "chef/mixin/shell_out"
+require "chef/mixin/windows_architecture_helper"
class Chef
module Mixin
@@ -88,10 +88,10 @@ class Chef
"-ExecutionPolicy Unrestricted",
# Powershell will hang if STDIN is redirected
# http://connect.microsoft.com/PowerShell/feedback/details/572313/powershell-exe-can-hang-if-stdin-is-redirected
- "-InputFormat None"
+ "-InputFormat None",
]
- "powershell.exe #{flags.join(' ')} -Command \"#{script}\""
+ "powershell.exe #{flags.join(' ')} -Command \"#{script.gsub('"', '\"')}\""
end
end
end
diff --git a/lib/chef/mixin/powershell_type_coercions.rb b/lib/chef/mixin/powershell_type_coercions.rb
index 75b3276c84..792ec18842 100644
--- a/lib/chef/mixin/powershell_type_coercions.rb
+++ b/lib/chef/mixin/powershell_type_coercions.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
+# Author:: Adam Edwards (<adamed@chef.io>)
# Author:: Jay Mundrawala (<jdm@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,33 +21,35 @@ class Chef
module Mixin
module PowershellTypeCoercions
- def type_coercions
- @type_coercions ||= {
- Fixnum => { :type => lambda { |x| x.to_s }},
- Float => { :type => lambda { |x| x.to_s }},
- FalseClass => { :type => lambda { |x| '$false' }},
- TrueClass => { :type => lambda { |x| '$true' }},
- Hash => {:type => Proc.new { |x| translate_hash(x)}},
- Array => {:type => Proc.new { |x| translate_array(x)}}
- }
+ def type_coercion(value)
+ case value
+ when Integer, Float
+ value.to_s
+ when FalseClass
+ "$false"
+ when TrueClass
+ "$true"
+ when Hash, Chef::Node::ImmutableMash
+ translate_hash(value)
+ when Array, Chef::Node::ImmutableArray
+ translate_array(value)
+ end
end
- def translate_type(value)
- translation = type_coercions[value.class]
-
- if translation
- translation[:type].call(value)
- elsif value.respond_to? :to_psobject
+ def psobject_conversion(value)
+ if value.respond_to?(:to_psobject)
"(#{value.to_psobject})"
- else
- safe_string(value.to_s)
end
end
+ def translate_type(value)
+ type_coercion(value) || psobject_conversion(value) || safe_string(value.to_s)
+ end
+
private
def translate_hash(x)
- translated = x.inject([]) do |memo, (k,v)|
+ translated = x.inject([]) do |memo, (k, v)|
memo << "#{k}=#{translate_type(v)}"
end
"@{#{translated.join(';')}}"
@@ -61,7 +63,7 @@ class Chef
end
def unsafe?(s)
- ["'", '#', '`', '"'].any? do |x|
+ ["'", "#", "`", '"'].any? do |x|
s.include? x
end
end
diff --git a/lib/chef/mixin/properties.rb b/lib/chef/mixin/properties.rb
index 85abe4427e..8ff2cc4501 100644
--- a/lib/chef/mixin/properties.rb
+++ b/lib/chef/mixin/properties.rb
@@ -1,6 +1,6 @@
-require 'chef/delayed_evaluator'
-require 'chef/mixin/params_validate'
-require 'chef/property'
+require "chef/delayed_evaluator"
+require "chef/mixin/params_validate"
+require "chef/property"
class Chef
module Mixin
@@ -17,7 +17,7 @@ class Chef
#
# @return [Hash<Symbol,Property>] The list of property names and types.
#
- def properties(include_superclass=true)
+ def properties(include_superclass = true)
if include_superclass
result = {}
ancestors.reverse_each { |c| result.merge!(c.properties(false)) if c.respond_to?(:properties) }
@@ -79,6 +79,9 @@ class Chef
# part of desired state. Defaults to `true`.
# @option options [Boolean] :identity `true` if this property
# is part of object identity. Defaults to `false`.
+ # @option options [Boolean] :sensitive `true` if this property could
+ # contain sensitive information and whose value should be redacted
+ # in any resource reporting / auditing output. Defaults to `false`.
#
# @example Bare property
# property :x
@@ -92,13 +95,14 @@ class Chef
# @example With type and options
# property :x, String, default: 'hi'
#
- def property(name, type=NOT_PASSED, **options)
+ def property(name, type = NOT_PASSED, **options)
name = name.to_sym
- options.each { |k,v| options[k.to_sym] = v if k.is_a?(String) }
+ options = options.inject({}) { |memo, (key, value)| memo[key.to_sym] = value; memo }
options[:instance_variable_name] = :"@#{name}" if !options.has_key?(:instance_variable_name)
- options.merge!(name: name, declared_in: self)
+ options[:name] = name
+ options[:declared_in] = self
if type == NOT_PASSED
# If a type is not passed, the property derives from the
@@ -200,7 +204,7 @@ class Chef
# If state_attrs *excludes* something which is currently desired state,
# mark it as desired_state: false.
- local_properties.each do |name,property|
+ local_properties.each do |name, property|
if property.desired_state? && !names.include?(name)
self.property name, desired_state: false
end
@@ -248,7 +252,7 @@ class Chef
# If identity_properties *excludes* something which is currently part of
# the identity, mark it as identity: false.
- properties.each do |name,property|
+ properties.each do |name, property|
if property.identity? && !names.include?(name)
self.property name, identity: false
diff --git a/lib/chef/mixin/provides.rb b/lib/chef/mixin/provides.rb
index 095e273dab..43a726de8c 100644
--- a/lib/chef/mixin/provides.rb
+++ b/lib/chef/mixin/provides.rb
@@ -1,5 +1,5 @@
-require 'chef/mixin/descendants_tracker'
+require "chef/mixin/descendants_tracker"
class Chef
module Mixin
@@ -7,12 +7,13 @@ class Chef
# TODO no longer needed, remove or deprecate?
include Chef::Mixin::DescendantsTracker
- def provides(short_name, opts={}, &block)
+ def provides(short_name, opts = {})
raise NotImplementedError, :provides
end
# Check whether this resource provides the resource_name DSL for the given
# node. TODO remove this when we stop checking unregistered things.
+ # FIXME: yard with @yield
def provides?(node, resource)
raise NotImplementedError, :provides?
end
diff --git a/lib/chef/mixin/proxified_socket.rb b/lib/chef/mixin/proxified_socket.rb
new file mode 100644
index 0000000000..5c9bc3c7d0
--- /dev/null
+++ b/lib/chef/mixin/proxified_socket.rb
@@ -0,0 +1,42 @@
+# Author:: Tyler Ball (<tball@chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "proxifier"
+require "chef-config/mixin/fuzzy_hostname_matcher"
+
+class Chef
+ module Mixin
+ module ProxifiedSocket
+
+ include ChefConfig::Mixin::FuzzyHostnameMatcher
+
+ # This looks at the environment variables and leverages Proxifier to
+ # make the TCPSocket respect ENV['https_proxy'] or ENV['http_proxy'] if
+ # they are present
+ def proxified_socket(host, port)
+ proxy = ENV["https_proxy"] || ENV["http_proxy"] || false
+
+ if proxy && !fuzzy_hostname_match_any?(host, ENV["no_proxy"])
+ Proxifier.Proxy(proxy).open(host, port)
+ else
+ TCPSocket.new(host, port)
+ end
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/mixin/recipe_definition_dsl_core.rb b/lib/chef/mixin/recipe_definition_dsl_core.rb
index 704ee162be..6a9b12d31a 100644
--- a/lib/chef/mixin/recipe_definition_dsl_core.rb
+++ b/lib/chef/mixin/recipe_definition_dsl_core.rb
@@ -1,7 +1,7 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,7 +24,7 @@
# This constant (module name) will eventually be deprecated and then removed.
###
-require 'chef/mixin/deprecation'
+require "chef/mixin/deprecation"
class Chef
module Mixin
diff --git a/lib/chef/mixin/securable.rb b/lib/chef/mixin/securable.rb
index aaedf0b9ba..85c9dea1d4 100644
--- a/lib/chef/mixin/securable.rb
+++ b/lib/chef/mixin/securable.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@ class Chef
module Mixin
module Securable
- def owner(arg=nil)
+ def owner(arg = nil)
set_or_return(
:owner,
arg,
@@ -30,7 +30,7 @@ class Chef
alias :user :owner
- def group(arg=nil)
+ def group(arg = nil)
set_or_return(
:group,
arg,
@@ -38,28 +38,27 @@ class Chef
)
end
- def mode(arg=nil)
+ def mode(arg = nil)
set_or_return(
:mode,
arg,
:callbacks => {
- "not in valid numeric range" => lambda { |m|
+ "not in valid numeric range" => lambda do |m|
if m.kind_of?(String)
- m =~ /^0/ || m="0#{m}"
+ m =~ /^0/ || m = "0#{m}"
end
# Windows does not support the sticky or setuid bits
if Chef::Platform.windows?
- Integer(m)<=0777 && Integer(m)>=0
+ Integer(m) <= 0777 && Integer(m) >= 0
else
- Integer(m)<=07777 && Integer(m)>=0
+ Integer(m) <= 07777 && Integer(m) >= 0
end
- },
+ end,
}
)
end
-
#==WindowsMacros
# Defines methods for adding attributes to a chef resource to describe
# Windows file security metadata.
@@ -108,29 +107,28 @@ class Chef
# * `:one_level_deep` (optional): Boolean
#
def rights_attribute(name)
-
# equivalent to something like:
# def rights(permissions=nil, principals=nil, args_hash=nil)
- define_method(name) do |permissions=nil, principals=nil, args_hash=nil|
- rights = self.instance_variable_get("@#{name.to_s}".to_sym)
+ define_method(name) do |permissions = nil, principals = nil, args_hash = nil|
+ rights = instance_variable_get("@#{name}".to_sym)
unless permissions.nil?
input = {
:permissions => permissions,
- :principals => principals
+ :principals => principals,
}
input.merge!(args_hash) unless args_hash.nil?
- validations = {:permissions => { :required => true },
- :principals => { :required => true, :kind_of => [String, Array] },
- :applies_to_children => { :equal_to => [ true, false, :containers_only, :objects_only ]},
- :applies_to_self => { :kind_of => [ TrueClass, FalseClass ] },
- :one_level_deep => { :kind_of => [ TrueClass, FalseClass ] }
+ validations = { :permissions => { :required => true },
+ :principals => { :required => true, :kind_of => [String, Array] },
+ :applies_to_children => { :equal_to => [ true, false, :containers_only, :objects_only ] },
+ :applies_to_self => { :kind_of => [ TrueClass, FalseClass ] },
+ :one_level_deep => { :kind_of => [ TrueClass, FalseClass ] },
}
validate(input, validations)
[ permissions ].flatten.each do |permission|
if permission.is_a?(Integer)
- if permission < 0 || permission > 1<<32
+ if permission < 0 || permission > 1 << 32
raise ArgumentError, "permissions flags must be positive and <= 32 bits (#{permission})"
end
elsif !([:full_control, :modify, :read_execute, :read, :write].include?(permission.to_sym))
@@ -169,8 +167,7 @@ class Chef
# including class
module WindowsSecurableAttributes
-
- def inherits(arg=nil)
+ def inherits(arg = nil)
set_or_return(
:inherits,
arg,
diff --git a/lib/chef/mixin/shell_out.rb b/lib/chef/mixin/shell_out.rb
index 529023056d..18bd067989 100644
--- a/lib/chef/mixin/shell_out.rb
+++ b/lib/chef/mixin/shell_out.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,12 +15,85 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'mixlib/shellout'
+require "mixlib/shellout"
+require "chef/deprecated"
class Chef
module Mixin
module ShellOut
+ # PREFERRED APIS:
+ #
+ # shell_out_compact and shell_out_compact! flatten their array arguments and remove nils and pass
+ # the resultant array to shell_out. this actually eliminates spaces-in-args bugs because this:
+ #
+ # shell_out!("command #{arg}")
+ #
+ # becomes two arguments if arg has spaces and requires quotations:
+ #
+ # shell_out!("command '#{arg}'")
+ #
+ # using shell_out_compact! this becomes:
+ #
+ # shell_out_compact!("command", arg)
+ #
+ # and spaces in the arg just works and it does not become two arguments (and the shell quoting around
+ # the argument must actually be removed).
+ #
+ # there's also an implicit join between all the array elements, and nested arrays are flattened which
+ # means that odd where-do-i-put-the-spaces options handling just works, and instead of this:
+ #
+ # opts = "" # needs to be empty string for when foo and bar are both missing
+ # opts << " -foo" if needs_foo? # needs the leading space on both of these
+ # opts << " -bar" if needs_bar?
+ # shell_out!("cmd#{opts}") # have to think way too hard about why there's no space here
+ #
+ # becomes:
+ #
+ # opts = []
+ # opts << "-foo" if needs_foo?
+ # opts << "-bar" if needs_bar?
+ # shell_out_compact!("cmd", opts)
+ #
+ # and opts can be an empty array or nil and it'll work out fine.
+ #
+ # generally its best to use shell_out_compact! in code and setup expectations on shell_out! in tests
+ #
+
+ def shell_out_compact(*args, **options)
+ if options.empty?
+ shell_out(*clean_array(*args))
+ else
+ shell_out(*clean_array(*args), **options)
+ end
+ end
+
+ def shell_out_compact!(*args, **options)
+ if options.empty?
+ shell_out!(*clean_array(*args))
+ else
+ shell_out!(*clean_array(*args), **options)
+ end
+ end
+
+ # helper sugar for resources that support passing timeouts to shell_out
+
+ def shell_out_compact_timeout(*args, **options)
+ raise "object is not a resource that supports timeouts" unless respond_to?(:new_resource) && new_resource.respond_to?(:timeout)
+ options_dup = options.dup
+ options_dup[:timeout] = new_resource.timeout if new_resource.timeout
+ options_dup[:timeout] = 900 unless options_dup.key?(:timeout)
+ shell_out_compact(*args, **options_dup)
+ end
+
+ def shell_out_compact_timeout!(*args, **options)
+ raise "object is not a resource that supports timeouts" unless respond_to?(:new_resource) && new_resource.respond_to?(:timeout)
+ options_dup = options.dup
+ options_dup[:timeout] = new_resource.timeout if new_resource.timeout
+ options_dup[:timeout] = 900 unless options_dup.key?(:timeout)
+ shell_out_compact!(*args, **options_dup)
+ end
+
# shell_out! runs a command on the system and will raise an error if the command fails, which is what you want
# for debugging, shell_out and shell_out! both will display command output to the tty when the log level is debug
# Generally speaking, 'extend Chef::Mixin::ShellOut' in your recipes and include 'Chef::Mixin::ShellOut' in your LWRPs
@@ -28,26 +101,15 @@ class Chef
# we use 'en_US.UTF-8' by default because we parse localized strings in English as an API and
# generally must support UTF-8 unicode.
- def shell_out(*command_args)
- args = command_args.dup
- if args.last.is_a?(Hash)
- options = args.pop.dup
- env_key = options.has_key?(:env) ? :env : :environment
- options[env_key] ||= {}
- options[env_key] = options[env_key].dup
- options[env_key]['LC_ALL'] ||= Chef::Config[:internal_locale] unless options[env_key].has_key?('LC_ALL')
- options[env_key]['LANGUAGE'] ||= Chef::Config[:internal_locale] unless options[env_key].has_key?('LANGUAGE')
- options[env_key]['LANG'] ||= Chef::Config[:internal_locale] unless options[env_key].has_key?('LANG')
- args << options
- else
- args << { :environment => {
- 'LC_ALL' => Chef::Config[:internal_locale],
- 'LANGUAGE' => Chef::Config[:internal_locale],
- 'LANG' => Chef::Config[:internal_locale],
- } }
- end
-
- shell_out_command(*args)
+ def shell_out(*args, **options)
+ options = options.dup
+ env_key = options.has_key?(:env) ? :env : :environment
+ options[env_key] = {
+ "LC_ALL" => Chef::Config[:internal_locale],
+ "LANGUAGE" => Chef::Config[:internal_locale],
+ "LANG" => Chef::Config[:internal_locale],
+ }.update(options[env_key] || {})
+ shell_out_command(*args, **options)
end
# call shell_out (using en_US.UTF-8) and raise errors
@@ -72,7 +134,7 @@ class Chef
[:command_log_prepend, :log_tag] ]
# CHEF-3090: Deprecate command_log_level and command_log_prepend
- # Patterned after https://github.com/opscode/chef/commit/e1509990b559984b43e428d4d801c394e970f432
+ # Patterned after https://github.com/chef/chef/commit/e1509990b559984b43e428d4d801c394e970f432
def run_command_compatible_options(command_args)
return command_args unless command_args.last.is_a?(Hash)
@@ -86,7 +148,39 @@ class Chef
my_options[new_option] = value
end
- return my_command_args
+ my_command_args
+ end
+
+ # Helper for sublcasses to convert an array of string args into a string. It
+ # will compact nil or empty strings in the array and will join the array elements
+ # with spaces, without introducing any double spaces for nil/empty elements.
+ #
+ # @param args [String] variable number of string arguments
+ # @return [String] nicely concatenated string or empty string
+ def a_to_s(*args)
+ # can't quite deprecate this yet
+ #Chef.deprecated(:package_misc, "a_to_s is deprecated use shell_out_compact or shell_out_compact_timeout instead")
+ args.flatten.reject { |i| i.nil? || i == "" }.map(&:to_s).join(" ")
+ end
+
+ # Helper for sublcasses to reject nil out of an array. It allows
+ # using the array form of shell_out (which avoids the need to surround arguments with
+ # quote marks to deal with shells).
+ #
+ # Usage:
+ # shell_out!(*clean_array("useradd", universal_options, useradd_options, new_resource.username))
+ #
+ # universal_options and useradd_options can be nil, empty array, empty string, strings or arrays
+ # and the result makes sense.
+ #
+ # keeping this separate from shell_out!() makes it a bit easier to write expectations against the
+ # shell_out args and be able to omit nils and such in the tests (and to test that the nils are
+ # being rejected correctly).
+ #
+ # @param args [String] variable number of string arguments
+ # @return [Array] array of strings with nil and null string rejection
+ def clean_array(*args)
+ args.flatten.compact.map(&:to_s)
end
private
@@ -99,7 +193,7 @@ class Chef
end
def deprecate_option(old_option, new_option)
- Chef::Log.logger.warn "DEPRECATION: Chef::Mixin::ShellOut option :#{old_option} is deprecated. Use :#{new_option}"
+ Chef.deprecated :internal_api, "Chef::Mixin::ShellOut option :#{old_option} is deprecated. Use :#{new_option}"
end
def io_for_live_stream
@@ -114,4 +208,4 @@ class Chef
end
# Break circular dep
-require 'chef/config'
+require "chef/config"
diff --git a/lib/chef/mixin/subclass_directive.rb b/lib/chef/mixin/subclass_directive.rb
new file mode 100644
index 0000000000..397a37c6b8
--- /dev/null
+++ b/lib/chef/mixin/subclass_directive.rb
@@ -0,0 +1,37 @@
+#
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ module Mixin
+ module SubclassDirective
+ def subclass_directive(sym)
+ define_singleton_method sym do
+ instance_variable_set(:"@#{sym}", true)
+ end
+
+ define_singleton_method :"#{sym}?" do
+ !!instance_variable_get(:"@#{sym}")
+ end
+
+ define_method :"#{sym}?" do
+ self.class.send(:"#{sym}?")
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/mixin/template.rb b/lib/chef/mixin/template.rb
index db9a2f6d91..b10e036c4e 100644
--- a/lib/chef/mixin/template.rb
+++ b/lib/chef/mixin/template.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'tempfile'
-require 'erubis'
+require "tempfile"
+require "erubis"
class Chef
module Mixin
@@ -105,10 +105,9 @@ class Chef
def node
return @node if @node
raise "Could not find a value for node. If you are explicitly setting variables in a template, " +
- "include a node variable if you plan to use it."
+ "include a node variable if you plan to use it."
end
-
#
# Takes the name of the partial, plus a hash of options. Returns a
# string that contains the result of the evaluation of the partial.
@@ -177,7 +176,7 @@ class Chef
# this template.
if Chef::Platform.windows?
- output = output.gsub(/\r?\n/,"\r\n")
+ output = output.gsub(/\r?\n/, "\r\n")
end
output
@@ -187,7 +186,7 @@ class Chef
module_names.each do |mod|
context_methods = [:node, :render, :render_template, :render_template_from_string]
context_methods.each do |core_method|
- if mod.method_defined?(core_method) or mod.private_method_defined?(core_method)
+ if mod.method_defined?(core_method) || mod.private_method_defined?(core_method)
Chef::Log.warn("Core template method `#{core_method}' overridden by extension module #{mod}")
end
end
@@ -225,7 +224,7 @@ class Chef
end
def line_number
- @line_number ||= $1.to_i if original_exception.backtrace.find {|line| line =~ /\(erubis\):(\d+)/ }
+ @line_number ||= $1.to_i if original_exception.backtrace.find { |line| line =~ /\(erubis\):(\d+)/ }
end
def source_location
@@ -246,7 +245,7 @@ class Chef
contextual_lines = lines[beginning_line, source_size]
output = []
contextual_lines.each_with_index do |line, index|
- line_number = (index+beginning_line+1).to_s.rjust(3)
+ line_number = (index + beginning_line + 1).to_s.rjust(3)
output << "#{line_number}: #{line}"
end
output.join("\n")
diff --git a/lib/chef/mixin/unformatter.rb b/lib/chef/mixin/unformatter.rb
index aa5977edd7..5663749e58 100644
--- a/lib/chef/mixin/unformatter.rb
+++ b/lib/chef/mixin/unformatter.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software
+# Copyright:: Copyright 2015-2016, Chef Software
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,9 +22,9 @@ class Chef
def write(message)
data = message.match(/(\[.+?\] )?([\w]+):(.*)$/)
- self.send(data[2].downcase.chomp.to_sym, data[3].strip)
+ send(data[2].downcase.chomp.to_sym, data[3].strip)
rescue NoMethodError
- self.send(:info, message)
+ send(:info, message)
end
end
diff --git a/lib/chef/mixin/uris.rb b/lib/chef/mixin/uris.rb
index 0136b55f6a..ea55eefd8f 100644
--- a/lib/chef/mixin/uris.rb
+++ b/lib/chef/mixin/uris.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,8 @@
# limitations under the License.
#
-require 'uri'
+require "uri"
+require "addressable/uri"
class Chef
module Mixin
@@ -29,14 +30,11 @@ class Chef
!!(%r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ source)
end
-
def as_uri(source)
- begin
- URI.parse(source)
- rescue URI::InvalidURIError
- Chef::Log.warn("#{source} was an invalid URI. Trying to escape invalid characters")
- URI.parse(URI.escape(source))
- end
+ URI.parse(source)
+ rescue URI::InvalidURIError
+ Chef::Log.warn("#{source} was an invalid URI. Trying to escape invalid characters")
+ URI.parse(Addressable::URI.encode(source))
end
end
diff --git a/lib/chef/mixin/versioned_api.rb b/lib/chef/mixin/versioned_api.rb
new file mode 100644
index 0000000000..9c2f2f4cdb
--- /dev/null
+++ b/lib/chef/mixin/versioned_api.rb
@@ -0,0 +1,69 @@
+#--
+# Copyright:: Copyright 2017, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ module Mixin
+ module VersionedAPI
+
+ def minimum_api_version(version = nil)
+ if version
+ @minimum_api_version = version
+ else
+ @minimum_api_version
+ end
+ end
+
+ end
+
+ module VersionedAPIFactory
+
+ def versioned_interfaces
+ @versioned_interfaces ||= []
+ end
+
+ def add_versioned_api_class(klass)
+ versioned_interfaces << klass
+ end
+
+ def versioned_api_class
+ versioned_interfaces.select do |klass|
+ version = klass.send(:minimum_api_version)
+ # min and max versions will be nil if we've not made a request to the server yet,
+ # in which case we'll just start with the highest version and see what happens
+ ServerAPIVersions.instance.min_server_version.nil? || (version >= ServerAPIVersions.instance.min_server_version && version <= ServerAPIVersions.instance.max_server_version)
+ end
+ .sort { |a, b| a.send(:minimum_api_version) <=> b.send(:minimum_api_version) }
+ .last
+ end
+
+ def def_versioned_delegator(method)
+ line_no = __LINE__; str = %{
+ def self.#{method}(*args, &block)
+ versioned_api_class.__send__(:#{method}, *args, &block)
+ end
+ }
+ module_eval(str, __FILE__, line_no)
+ end
+
+ def new(*args)
+ object = versioned_api_class.allocate
+ object.send(:initialize, *args)
+ object
+ end
+ end
+ end
+end
diff --git a/lib/chef/mixin/which.rb b/lib/chef/mixin/which.rb
index 4e1c516386..fd386241a0 100644
--- a/lib/chef/mixin/which.rb
+++ b/lib/chef/mixin/which.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Lamont Granquist <lamont@getchef.io>
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Lamont Granquist <lamont@chef.io>
+# Copyright:: Copyright 2010-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,19 +18,32 @@
class Chef
module Mixin
module Which
- def which(cmd, opts = {})
- extra_path =
- if opts[:extra_path].nil?
- [ '/bin', '/usr/bin', '/sbin', '/usr/sbin' ]
- else
- [ opts[:extra_path] ].flatten
- end
- paths = ENV['PATH'].split(File::PATH_SEPARATOR) + extra_path
- paths.each do |path|
- filename = File.join(path, cmd)
- return filename if File.executable?(Chef.path_to(filename))
- end
- false
+ def which(*cmds, extra_path: nil, &block)
+ where(*cmds, extra_path: extra_path, &block).first || false
+ end
+
+ def where(*cmds, extra_path: nil, &block)
+ # NOTE: unnecessarily duplicates function of path_sanity
+ extra_path ||= [ "/bin", "/usr/bin", "/sbin", "/usr/sbin" ]
+ paths = env_path.split(File::PATH_SEPARATOR) + extra_path
+ cmds.map do |cmd|
+ paths.map do |path|
+ filename = Chef.path_to(File.join(path, cmd))
+ filename if valid_executable?(filename, &block)
+ end.compact
+ end.flatten
+ end
+
+ private
+
+ # for test stubbing
+ def env_path
+ ENV["PATH"]
+ end
+
+ def valid_executable?(filename, &block)
+ return false unless File.executable?(filename) && !File.directory?(filename)
+ block ? yield(filename) : true
end
end
end
diff --git a/lib/chef/mixin/why_run.rb b/lib/chef/mixin/why_run.rb
index d3acea5490..ea62527bdd 100644
--- a/lib/chef/mixin/why_run.rb
+++ b/lib/chef/mixin/why_run.rb
@@ -1,7 +1,7 @@
#
-# Author:: Dan DeLeo ( <dan@opscode.com> )
-# Author:: Marc Paradise ( <marc@opscode.com> )
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Dan DeLeo ( <dan@chef.io> )
+# Author:: Marc Paradise ( <marc@chef.io> )
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -49,7 +49,7 @@ class Chef
def add_action(descriptions, &block)
@actions << [descriptions, block]
if (@resource.respond_to?(:is_guard_interpreter) && @resource.is_guard_interpreter) || !Chef::Config[:why_run]
- block.call
+ yield
end
events.resource_update_applied(@resource, @action, descriptions)
end
@@ -222,7 +222,6 @@ class Chef
@assertion_failed
end
-
# Runs the assertion/assumption logic. Will raise an Exception of the
# type specified in #failure_message (or AssertionFailure by default)
# if the requirement is not met and Chef is not running in why run
@@ -247,7 +246,7 @@ class Chef
def initialize(resource, run_context)
@resource, @run_context = resource, run_context
- @assertions = Hash.new {|h,k| h[k] = [] }
+ @assertions = Hash.new { |h, k| h[k] = [] }
@blocked_actions = []
end
@@ -313,16 +312,16 @@ class Chef
def assert(*actions)
assertion = Assertion.new
yield assertion
- actions.each {|action| @assertions[action] << assertion }
+ actions.each { |action| @assertions[action] << assertion }
end
# Run the assertion and assumption logic.
def run(action)
@assertions[action.to_sym].each do |a|
a.run(action, events, @resource)
- if a.assertion_failed? and a.block_action?
+ if a.assertion_failed? && a.block_action?
@blocked_actions << action
- return
+ break
end
end
end
diff --git a/lib/chef/mixin/wide_string.rb b/lib/chef/mixin/wide_string.rb
index 0c32b76365..ef7828e2d8 100644
--- a/lib/chef/mixin/wide_string.rb
+++ b/lib/chef/mixin/wide_string.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala(<jdm@chef.io>)
-# Copyright:: Copyright 2015 Chef Software
+# Copyright:: Copyright 2015-2016, Chef Software
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,17 +31,17 @@ class Chef
def utf8_to_wide(ustring)
# ensure it is actually UTF-8
# Ruby likes to mark binary data as ASCII-8BIT
- ustring = (ustring + "").force_encoding('UTF-8') if ustring.respond_to?(:force_encoding) && ustring.encoding.name != "UTF-8"
+ ustring = (ustring + "").force_encoding("UTF-8") if ustring.respond_to?(:force_encoding) && ustring.encoding.name != "UTF-8"
# ensure we have the double-null termination Windows Wide likes
- ustring = ustring + "\000\000" if ustring.length == 0 or ustring[-1].chr != "\000"
+ ustring += "\000\000" if ustring.length == 0 || ustring[-1].chr != "\000"
# encode it all as UTF-16LE AKA Windows Wide Character AKA Windows Unicode
ustring = begin
if ustring.respond_to?(:encode)
- ustring.encode('UTF-16LE')
+ ustring.encode("UTF-16LE")
else
- require 'iconv'
+ require "iconv"
Iconv.conv("UTF-16LE", "UTF-8", ustring)
end
end
@@ -51,14 +51,14 @@ class Chef
def wide_to_utf8(wstring)
# ensure it is actually UTF-16LE
# Ruby likes to mark binary data as ASCII-8BIT
- wstring = wstring.force_encoding('UTF-16LE') if wstring.respond_to?(:force_encoding)
+ wstring = wstring.force_encoding("UTF-16LE") if wstring.respond_to?(:force_encoding)
# encode it all as UTF-8
wstring = begin
if wstring.respond_to?(:encode)
- wstring.encode('UTF-8')
+ wstring.encode("UTF-8")
else
- require 'iconv'
+ require "iconv"
Iconv.conv("UTF-8", "UTF-16LE", wstring)
end
end
diff --git a/lib/chef/mixin/windows_architecture_helper.rb b/lib/chef/mixin/windows_architecture_helper.rb
index 744001f8a2..67c34a85a1 100644
--- a/lib/chef/mixin/windows_architecture_helper.rb
+++ b/lib/chef/mixin/windows_architecture_helper.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,10 @@
# limitations under the License.
#
-
-require 'chef/exceptions'
-require 'chef/platform/query_helpers'
-require 'chef/win32/process' if Chef::Platform.windows?
-require 'chef/win32/system' if Chef::Platform.windows?
+require "chef/exceptions"
+require "chef/platform/query_helpers"
+require "chef/win32/process" if Chef::Platform.windows?
+require "chef/win32/system" if Chef::Platform.windows?
class Chef
module Mixin
@@ -48,11 +47,11 @@ class Chef
def with_os_architecture(node, architecture: nil)
node ||= begin
- os_arch = ENV['PROCESSOR_ARCHITEW6432'] ||
- ENV['PROCESSOR_ARCHITECTURE']
+ os_arch = ENV["PROCESSOR_ARCHITEW6432"] ||
+ ENV["PROCESSOR_ARCHITECTURE"]
Hash.new.tap do |n|
n[:kernel] = Hash.new
- n[:kernel][:machine] = os_arch == 'AMD64' ? :x86_64 : :i386
+ n[:kernel][:machine] = os_arch == "AMD64" ? :x86_64 : :i386
end
end
@@ -75,16 +74,15 @@ class Chef
def node_supports_windows_architecture?(node, desired_architecture)
assert_valid_windows_architecture!(desired_architecture)
- return (node_windows_architecture(node) == :x86_64 ||
- desired_architecture == :i386) ? true : false
+ ( node_windows_architecture(node) == :x86_64 ) || ( desired_architecture == :i386 )
end
def valid_windows_architecture?(architecture)
- return (architecture == :x86_64) || (architecture == :i386)
+ ( architecture == :x86_64 ) || ( architecture == :i386 )
end
def assert_valid_windows_architecture!(architecture)
- if ! valid_windows_architecture?(architecture)
+ if !valid_windows_architecture?(architecture)
raise Chef::Exceptions::Win32ArchitectureIncorrect,
"The specified architecture was not valid. It must be one of :i386 or :x86_64"
end
@@ -99,13 +97,13 @@ class Chef
end
def disable_wow64_file_redirection( node )
- if ( ( node_windows_architecture(node) == :x86_64) && ::Chef::Platform.windows?)
+ if ( node_windows_architecture(node) == :x86_64) && ::Chef::Platform.windows?
Chef::ReservedNames::Win32::System.wow64_disable_wow64_fs_redirection
end
end
def restore_wow64_file_redirection( node, original_redirection_state )
- if ( (node_windows_architecture(node) == :x86_64) && ::Chef::Platform.windows?)
+ if (node_windows_architecture(node) == :x86_64) && ::Chef::Platform.windows?
Chef::ReservedNames::Win32::System.wow64_revert_wow64_fs_redirection(original_redirection_state)
end
end
diff --git a/lib/chef/mixin/windows_env_helper.rb b/lib/chef/mixin/windows_env_helper.rb
index cd12b4254a..65b4b33cf0 100644
--- a/lib/chef/mixin/windows_env_helper.rb
+++ b/lib/chef/mixin/windows_env_helper.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,12 @@
# limitations under the License.
#
-
-require 'chef/exceptions'
-require 'chef/mixin/wide_string'
-require 'chef/platform/query_helpers'
-require 'chef/win32/error' if Chef::Platform.windows?
-require 'chef/win32/api/system' if Chef::Platform.windows?
-require 'chef/win32/api/unicode' if Chef::Platform.windows?
+require "chef/exceptions"
+require "chef/mixin/wide_string"
+require "chef/platform/query_helpers"
+require "chef/win32/error" if Chef::Platform.windows?
+require "chef/win32/api/system" if Chef::Platform.windows?
+require "chef/win32/api/unicode" if Chef::Platform.windows?
class Chef
module Mixin
@@ -44,12 +43,12 @@ class Chef
flags = SMTO_BLOCK | SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG
# for why two calls, see:
# http://stackoverflow.com/questions/4968373/why-doesnt-sendmessagetimeout-update-the-environment-variables
- if ( SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, FFI::MemoryPointer.from_string('Environment').address, flags, 5000, nil) == 0 )
+ if SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, FFI::MemoryPointer.from_string("Environment").address, flags, 5000, nil) == 0
Chef::ReservedNames::Win32::Error.raise!
end
- if ( SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, FFI::MemoryPointer.from_string(
- utf8_to_wide('Environment')
- ).address, flags, 5000, nil) == 0 )
+ if SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, FFI::MemoryPointer.from_string(
+ utf8_to_wide("Environment")
+ ).address, flags, 5000, nil) == 0
Chef::ReservedNames::Win32::Error.raise!
end
end
diff --git a/lib/chef/mixin/xml_escape.rb b/lib/chef/mixin/xml_escape.rb
index ceb45df3e6..243bb7f044 100644
--- a/lib/chef/mixin/xml_escape.rb
+++ b/lib/chef/mixin/xml_escape.rb
@@ -1,7 +1,7 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2005 Sam Ruby
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2005-2016, Sam Ruby
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,7 +26,7 @@
#
# Thanks, Sam!
#
-# Copyright (c) 2005, Sam Ruby
+# Copyright 2005-2016, Sam Ruby
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -46,10 +46,10 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-require 'chef/log'
+require "chef/log"
begin
- require 'fast_xs'
+ require "fast_xs"
rescue LoadError
Chef::Log.info "The fast_xs gem is not installed, slower pure ruby XML escaping will be used."
end
@@ -64,14 +64,14 @@ class Chef
CP1252 = {
128 => 8364, # euro sign
130 => 8218, # single low-9 quotation mark
- 131 => 402, # latin small letter f with hook
+ 131 => 402, # latin small letter f with hook
132 => 8222, # double low-9 quotation mark
133 => 8230, # horizontal ellipsis
134 => 8224, # dagger
135 => 8225, # double dagger
- 136 => 710, # modifier letter circumflex accent
+ 136 => 710, # modifier letter circumflex accent
137 => 8240, # per mille sign
- 138 => 352, # latin capital letter s with caron
+ 138 => 352, # latin capital letter s with caron
139 => 8249, # single left-pointing angle quotation mark
140 => 338, # latin capital ligature oe
142 => 381, # latin capital letter z with caron
@@ -82,9 +82,9 @@ class Chef
149 => 8226, # bullet
150 => 8211, # en dash
151 => 8212, # em dash
- 152 => 732, # small tilde
+ 152 => 732, # small tilde
153 => 8482, # trade mark sign
- 154 => 353, # latin small letter s with caron
+ 154 => 353, # latin small letter s with caron
155 => 8250, # single right-pointing angle quotation mark
156 => 339, # latin small ligature oe
158 => 382, # latin small letter z with caron
@@ -93,9 +93,9 @@ class Chef
# http://www.w3.org/TR/REC-xml/#dt-chardata
PREDEFINED = {
- 38 => '&amp;', # ampersand
- 60 => '&lt;', # left angle bracket
- 62 => '&gt;' # right angle bracket
+ 38 => "&amp;", # ampersand
+ 60 => "&lt;", # left angle bracket
+ 62 => "&gt;" # right angle bracket
}
# http://www.w3.org/TR/REC-xml/#charsets
@@ -103,19 +103,17 @@ class Chef
(0xE000..0xFFFD), (0x10000..0x10FFFF)]
def xml_escape(unescaped_str)
- begin
- unescaped_str.unpack("U*").map {|char| xml_escape_char!(char)}.join
- rescue
- unescaped_str.unpack("C*").map {|char| xml_escape_char!(char)}.join
- end
+ unescaped_str.unpack("U*").map { |char| xml_escape_char!(char) }.join
+ rescue
+ unescaped_str.unpack("C*").map { |char| xml_escape_char!(char) }.join
end
private
def xml_escape_char!(char)
char = CP1252[char] || char
- char = 42 unless VALID.detect {|range| range.include? char}
- char = PREDEFINED[char] || (char<128 ? char.chr : "&##{char};")
+ char = 42 unless VALID.detect { |range| range.include? char }
+ char = PREDEFINED[char] || (char < 128 ? char.chr : "&##{char};")
end
end
diff --git a/lib/chef/mixins.rb b/lib/chef/mixins.rb
index 17be1622af..b980e81287 100644
--- a/lib/chef/mixins.rb
+++ b/lib/chef/mixins.rb
@@ -1,14 +1,13 @@
-require 'chef/mixin/shell_out'
-require 'chef/mixin/checksum'
-require 'chef/mixin/command'
-require 'chef/mixin/convert_to_class_name'
-require 'chef/mixin/create_path'
-require 'chef/mixin/deep_merge'
-require 'chef/mixin/enforce_ownership_and_permissions'
-require 'chef/mixin/from_file'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/path_sanity'
-require 'chef/mixin/template'
-require 'chef/mixin/securable'
-require 'chef/mixin/xml_escape'
-
+require "chef/mixin/shell_out"
+require "chef/mixin/checksum"
+require "chef/mixin/command"
+require "chef/mixin/convert_to_class_name"
+require "chef/mixin/create_path"
+require "chef/mixin/deep_merge"
+require "chef/mixin/enforce_ownership_and_permissions"
+require "chef/mixin/from_file"
+require "chef/mixin/params_validate"
+require "chef/mixin/path_sanity"
+require "chef/mixin/template"
+require "chef/mixin/securable"
+require "chef/mixin/xml_escape"
diff --git a/lib/chef/monkey_patches/net-ssh-multi.rb b/lib/chef/monkey_patches/net-ssh-multi.rb
deleted file mode 100644
index 0f4dd6655c..0000000000
--- a/lib/chef/monkey_patches/net-ssh-multi.rb
+++ /dev/null
@@ -1,140 +0,0 @@
-#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# == net-ssh-multi gem patch for concurrency
-# net-ssh-multi gem has 2 bugs associated with the use of
-# :concurrent_connections option.
-# 1-) There is a race condition while fetching the next_session when
-# :concurrent_connections are set. @open_connections is being
-# incremented by the connection thread and sometimes
-# realize_pending_connections!() method can create more than required
-# connection threads before the @open_connections is set by the
-# previously created threads.
-# 2-) When :concurrent_connections is set, server classes are setup
-# with PendingConnection objects that always return true to busy?
-# calls. If a connection fails when :concurrent_connections is set,
-# server ends up returning true to all busy? calls since the session
-# object is not replaced. Due to this, main event loop (process()
-# function) never gets terminated.
-#
-# See: https://github.com/net-ssh/net-ssh-multi/pull/4
-
-require 'net/ssh/multi/version'
-
-if Net::SSH::Multi::Version::STRING == "1.1.0" || Net::SSH::Multi::Version::STRING == "1.2.0"
-
- require 'net/ssh/multi'
-
- module Net
- module SSH
- module Multi
- class Server
-
- # Make sure that server returns false if the ssh connection
- # has failed.
- def busy?(include_invisible=false)
- !failed? && session && session.busy?(include_invisible)
- end
-
- end
-
- class Session
- def next_session(server, force=false) #:nodoc:
- # don't retry a failed attempt
- return nil if server.failed?
-
- @session_mutex.synchronize do
- if !force && concurrent_connections && concurrent_connections <= open_connections
- connection = PendingConnection.new(server)
- @pending_sessions << connection
- return connection
- end
-
- # ===== PATCH START
- # Only increment the open_connections count if the connection
- # is not being forced. Incase of a force, it will already be
- # incremented.
- if !force
- @open_connections += 1
- end
- # ===== PATCH END
- end
-
- begin
- server.new_session
-
- # I don't understand why this should be necessary--StandardError is a
- # subclass of Exception, after all--but without explicitly rescuing
- # StandardError, things like Errno::* and SocketError don't get caught
- # here!
- rescue Exception, StandardError => e
- server.fail!
- @session_mutex.synchronize { @open_connections -= 1 }
-
- case on_error
- when :ignore then
- # do nothing
- when :warn then
- warn("error connecting to #{server}: #{e.class} (#{e.message})")
- when Proc then
- go = catch(:go) { on_error.call(server); nil }
- case go
- when nil, :ignore then # nothing
- when :retry then retry
- when :raise then raise
- else warn "unknown 'go' command: #{go.inspect}"
- end
- else
- raise
- end
-
- return nil
- end
- end
-
- def realize_pending_connections! #:nodoc:
- return unless concurrent_connections
-
- server_list.each do |server|
- server.close if !server.busy?(true)
- server.update_session!
- end
-
- @connect_threads.delete_if { |t| !t.alive? }
-
- count = concurrent_connections ? (concurrent_connections - open_connections) : @pending_sessions.length
- count.times do
- session = @pending_sessions.pop or break
- # ===== PATCH START
- # Increment the open_connections count here to prevent
- # creation of connection thread again before that is
- # incremented by the thread.
- @session_mutex.synchronize { @open_connections += 1 }
- # ===== PATCH END
- @connect_threads << Thread.new do
- session.replace_with(next_session(session.server, true))
- end
- end
- end
-
- end
- end
- end
- end
-
-end
diff --git a/lib/chef/monkey_patches/net_http.rb b/lib/chef/monkey_patches/net_http.rb
index 9c8044a9a7..c1cb87bffd 100644
--- a/lib/chef/monkey_patches/net_http.rb
+++ b/lib/chef/monkey_patches/net_http.rb
@@ -5,7 +5,7 @@ module ChefNetHTTPExceptionExtensions
attr_accessor :chef_rest_request
end
-require 'net/http'
+require "net/http"
module Net
class HTTPError
include ChefNetHTTPExceptionExtensions
@@ -21,7 +21,7 @@ module Net
end
end
-if Net::HTTP.instance_methods.map {|m| m.to_s}.include?("proxy_uri")
+if Net::HTTP.instance_methods.map { |m| m.to_s }.include?("proxy_uri")
begin
# Ruby 2.0 changes the way proxy support is implemented in Net::HTTP.
# The implementation does not work correctly with IPv6 literals because it
diff --git a/lib/chef/monkey_patches/webrick-utils.rb b/lib/chef/monkey_patches/webrick-utils.rb
index 57f6db54ed..7f525f122f 100644
--- a/lib/chef/monkey_patches/webrick-utils.rb
+++ b/lib/chef/monkey_patches/webrick-utils.rb
@@ -1,4 +1,4 @@
-require 'webrick/utils'
+require "webrick/utils"
module WEBrick
module Utils
@@ -11,40 +11,40 @@ module WEBrick
# create_listeners on Windows with Ruby > 2.0.0 does not
# raise an error if we're already listening on a port.
#
- def create_listeners(address, port, logger=nil)
+ def create_listeners(address, port, logger = nil)
#
# utils.rb -- Miscellaneous utilities
#
# Author: IPR -- Internet Programming with Ruby -- writers
- # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
- # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+ # Copyright 2001-2016, TAKAHASHI Masayoshi, GOTOU Yuuzou
+ # Copyright 2002-2016, Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: utils.rb,v 1.10 2003/02/16 22:22:54 gotoyuzo Exp $
unless port
raise ArgumentError, "must specify port"
end
- res = Socket::getaddrinfo(address, port,
+ res = Socket.getaddrinfo(address, port,
Socket::AF_UNSPEC, # address family
Socket::SOCK_STREAM, # socket type
0, # protocol
Socket::AI_PASSIVE) # flag
last_error = nil
sockets = []
- res.each{|ai|
+ res.each do |ai|
begin
logger.debug("TCPServer.new(#{ai[3]}, #{port})") if logger
sock = TCPServer.new(ai[3], port)
port = sock.addr[1] if port == 0
- Utils::set_close_on_exec(sock)
+ Utils.set_close_on_exec(sock)
sockets << sock
rescue => ex
logger.warn("TCPServer Error: #{ex}") if logger
- last_error = ex
+ last_error = ex
end
- }
+ end
raise last_error if sockets.empty?
- return sockets
+ sockets
end
module_function :create_listeners
end
diff --git a/lib/chef/monkey_patches/win32/registry.rb b/lib/chef/monkey_patches/win32/registry.rb
index 2ce2ac97f1..a08d67becf 100644
--- a/lib/chef/monkey_patches/win32/registry.rb
+++ b/lib/chef/monkey_patches/win32/registry.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,51 +15,65 @@
# limitations under the License.
#
-require 'chef/win32/api/registry'
-require 'chef/win32/unicode'
-require 'win32/registry'
+require "chef/win32/api/registry"
+require "chef/win32/unicode"
+require "win32/registry"
module Win32
class Registry
+ # ::Win32::Registry#export_string is used when enumerating child
+ # keys and values and re encodes a UTF-16LE to the local codepage.
+ # This can result in encoding incompatibilities if the native codepage
+ # does not support the characters in the registry. There is an open bug
+ # in ruby at https://bugs.ruby-lang.org/issues/11410. Rather than converting
+ # the UTF-16LE originally returned by the win32 api, we encode to UTF-8
+ # which will likely not result in any conversion error.
+ def export_string(str, enc = Encoding.default_internal || "utf-8")
+ str.encode(enc)
+ end
+
module API
extend Chef::ReservedNames::Win32::API::Registry
module_function
- if RUBY_VERSION =~ /^2\.1/
- # ::Win32::Registry#delete_value is broken in Ruby 2.1 (up to Ruby 2.1.6).
- # This should be resolved in a later release (see note #9 in link below).
- # https://bugs.ruby-lang.org/issues/10820
- def DeleteValue(hkey, name)
- check RegDeleteValueW(hkey, name.to_wstring)
- end
+ # ::Win32::Registry#delete_value uses RegDeleteValue which
+ # is not an imported function after bug 10820 was solved. So
+ # we overwrite it to call the correct imported function.
+ # https://bugs.ruby-lang.org/issues/10820
+ # Still a bug in trunk as of March 21, 2016 (Ruby 2.3.0)
+ def DeleteValue(hkey, name)
+ check RegDeleteValueW(hkey, name.to_wstring)
end
# ::Win32::Registry#delete_key uses RegDeleteKeyW. We need to use
# RegDeleteKeyExW to properly support WOW64 systems.
+ # Still a bug in trunk as of March 21, 2016 (Ruby 2.3.0)
def DeleteKey(hkey, name)
check RegDeleteKeyExW(hkey, name.to_wstring, 0, 0)
end
end
- if RUBY_VERSION =~ /^2.1/
- # ::Win32::Registry#write does not correctly handle data in Ruby 2.1 (up to Ruby 2.1.6).
+ if RUBY_VERSION =~ /^2\.1/
+ # ::Win32::Registry#write does not correctly handle data in Ruby 2.1
+ # This bug is _reportedly_ resolved in Ruby 2.1.7 and 2.2.3
+ # but fails in appveyor on 2.1.8 unless we keep applying this monkeypatch
# https://bugs.ruby-lang.org/issues/11439
def write(name, type, data)
case type
when REG_SZ, REG_EXPAND_SZ
data = data.to_s.encode(WCHAR) + WCHAR_NUL
when REG_MULTI_SZ
- data = data.to_a.map {|s| s.encode(WCHAR)}.join(WCHAR_NUL) << WCHAR_NUL << WCHAR_NUL
+ data = data.to_a.map { |s| s.encode(WCHAR) }.join(WCHAR_NUL) << WCHAR_NUL << WCHAR_NUL
when REG_BINARY
data = data.to_s
when REG_DWORD
data = API.packdw(data.to_i)
when REG_DWORD_BIG_ENDIAN
- data = [data.to_i].pack('N')
+ data = [data.to_i].pack("N")
when REG_QWORD
data = API.packqw(data.to_i)
else
diff --git a/lib/chef/monologger.rb b/lib/chef/monologger.rb
index f7d226f82e..82816e887f 100644
--- a/lib/chef/monologger.rb
+++ b/lib/chef/monologger.rb
@@ -1,5 +1,5 @@
-require 'logger'
-require 'pp'
+require "logger"
+require "pp"
#== MonoLogger
# A subclass of Ruby's stdlib Logger with all the mutex and logrotation stuff
@@ -38,12 +38,11 @@ class MonoLogger < Logger
end
end
-
class LocklessLogDevice < LogDevice
def initialize(log = nil)
@dev = @filename = @shift_age = @shift_size = nil
- if log.respond_to?(:write) and log.respond_to?(:close)
+ if log.respond_to?(:write) && log.respond_to?(:close)
@dev = log
else
@dev = open_logfile(log)
@@ -62,10 +61,10 @@ class MonoLogger < Logger
@dev.close rescue nil
end
- private
+ private
def open_logfile(filename)
- if (FileTest.exist?(filename))
+ if FileTest.exist?(filename)
open(filename, (File::WRONLY | File::APPEND))
else
create_logfile(filename)
@@ -86,5 +85,4 @@ class MonoLogger < Logger
end
-
end
diff --git a/lib/chef/node.rb b/lib/chef/node.rb
index 83ec7e2550..808fb1dc6e 100644
--- a/lib/chef/node.rb
+++ b/lib/chef/node.rb
@@ -1,9 +1,8 @@
-#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,22 +18,22 @@
# limitations under the License.
#
-require 'forwardable'
-require 'chef/config'
-require 'chef/nil_argument'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/mixin/deep_merge'
-require 'chef/dsl/include_attribute'
-require 'chef/dsl/platform_introspection'
-require 'chef/environment'
-require 'chef/rest'
-require 'chef/run_list'
-require 'chef/node/attribute'
-require 'chef/mash'
-require 'chef/json_compat'
-require 'chef/search/query'
-require 'chef/whitelist'
+require "forwardable"
+require "chef/config"
+require "chef/nil_argument"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/mixin/deep_merge"
+require "chef/dsl/include_attribute"
+require "chef/dsl/universal"
+require "chef/environment"
+require "chef/server_api"
+require "chef/run_list"
+require "chef/node/attribute"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/search/query"
+require "chef/whitelist"
class Chef
class Node
@@ -44,6 +43,8 @@ class Chef
def_delegators :attributes, :keys, :each_key, :each_value, :key?, :has_key?
def_delegators :attributes, :rm, :rm_default, :rm_normal, :rm_override
def_delegators :attributes, :default!, :normal!, :override!, :force_default!, :force_override!
+ def_delegators :attributes, :default_unless, :normal_unless, :override_unless, :set_unless
+ def_delegators :attributes, :read, :read!, :write, :write!, :unlink, :unlink!
attr_accessor :recipe_list, :run_state, :override_runlist
@@ -59,7 +60,7 @@ class Chef
include Chef::Mixin::FromFile
include Chef::DSL::IncludeAttribute
- include Chef::DSL::PlatformIntrospection
+ include Chef::DSL::Universal
include Chef::Mixin::ParamsValidate
@@ -70,14 +71,14 @@ class Chef
@chef_server_rest = chef_server_rest
@name = nil
- @chef_environment = '_default'
+ @chef_environment = "_default"
@primary_runlist = Chef::RunList.new
@override_runlist = Chef::RunList.new
@policy_name = nil
@policy_group = nil
- @attributes = Chef::Node::Attribute.new({}, {}, {}, {})
+ @attributes = Chef::Node::Attribute.new({}, {}, {}, {}, self)
@run_state = {}
end
@@ -100,22 +101,22 @@ class Chef
# for saving node data we use validate_utf8: false which will not
# raise an exception on bad utf8 data, but will replace the bad
# characters and render valid JSON.
- @chef_server_rest ||= Chef::REST.new(
+ @chef_server_rest ||= Chef::ServerAPI.new(
Chef::Config[:chef_server_url],
- Chef::Config[:node_name],
- Chef::Config[:client_key],
- validate_utf8: false,
+ client_name: Chef::Config[:node_name],
+ signing_key_filename: Chef::Config[:client_key],
+ validate_utf8: false
)
end
# Set the name of this Node, or return the current name.
- def name(arg=nil)
- if arg != nil
+ def name(arg = nil)
+ if !arg.nil?
validate(
- {:name => arg },
- {:name => { :kind_of => String,
- :cannot_be => :blank,
- :regex => /^[\-[:alnum:]_:.]+$/}
+ { :name => arg },
+ { :name => { :kind_of => String,
+ :cannot_be => :blank,
+ :regex => /^[\-[:alnum:]_:.]+$/ },
})
@name = arg
else
@@ -123,7 +124,7 @@ class Chef
end
end
- def chef_environment(arg=nil)
+ def chef_environment(arg = nil)
set_or_return(
:chef_environment,
arg,
@@ -146,9 +147,9 @@ class Chef
#
# @param arg [String] the new policy_name value
# @return [String] the current policy_name, or the one you just set
- def policy_name(arg=NULL_ARG)
+ def policy_name(arg = NULL_ARG)
return @policy_name if arg.equal?(NULL_ARG)
- validate({policy_name: arg}, { policy_name: { kind_of: [ String, NilClass ], regex: /^[\-:.[:alnum:]_]+$/ } })
+ validate({ policy_name: arg }, { policy_name: { kind_of: [ String, NilClass ], regex: /^[\-:.[:alnum:]_]+$/ } })
@policy_name = arg
end
@@ -168,9 +169,9 @@ class Chef
#
# @param arg [String] the new policy_group value
# @return [String] the current policy_group, or the one you just set
- def policy_group(arg=NULL_ARG)
+ def policy_group(arg = NULL_ARG)
return @policy_group if arg.equal?(NULL_ARG)
- validate({policy_group: arg}, { policy_group: { kind_of: [ String, NilClass ], regex: /^[\-:.[:alnum:]_]+$/ } })
+ validate({ policy_group: arg }, { policy_group: { kind_of: [ String, NilClass ], regex: /^[\-:.[:alnum:]_]+$/ } })
@policy_group = arg
end
@@ -196,52 +197,23 @@ class Chef
# Set a normal attribute of this node, but auto-vivify any Mashes that
# might be missing
def normal
- attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = false
attributes.normal
end
- alias_method :set, :normal
-
- # Set a normal attribute of this node, auto-vivifying any mashes that are
- # missing, but if the final value already exists, don't set it
- def normal_unless
- attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = true
- attributes.normal
+ def set
+ Chef.deprecated(:attributes, "node.set is deprecated and will be removed in Chef 14, please use node.default/node.override (or node.normal only if you really need persistence)")
+ normal
end
- alias_method :set_unless, :normal_unless
-
# Set a default of this node, but auto-vivify any Mashes that might
# be missing
def default
- attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = false
- attributes.default
- end
-
- # Set a default attribute of this node, auto-vivifying any mashes that are
- # missing, but if the final value already exists, don't set it
- def default_unless
- attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = true
attributes.default
end
# Set an override attribute of this node, but auto-vivify any Mashes that
# might be missing
def override
- attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = false
- attributes.override
- end
-
- # Set an override attribute of this node, auto-vivifying any mashes that
- # are missing, but if the final value already exists, don't set it
- def override_unless
- attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = true
attributes.override
end
@@ -262,8 +234,6 @@ class Chef
end
def automatic_attrs
- attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = false
attributes.automatic
end
@@ -291,8 +261,14 @@ class Chef
end
# Only works for attribute fetches, setting is no longer supported
- def method_missing(symbol, *args)
- attributes.send(symbol, *args)
+ # XXX: this should be deprecated
+ def method_missing(method, *args, &block)
+ attributes.public_send(method, *args, &block)
+ end
+
+ # Fix respond_to + method so that it works with method_missing delegation
+ def respond_to_missing?(method, include_private = false)
+ attributes.respond_to?(method, false)
end
# Returns true if this Node expects a given recipe, false if not.
@@ -357,8 +333,8 @@ class Chef
platform, version = Chef::Platform.find_platform_and_version(self)
Chef::Log.debug("Platform is #{platform} version #{version}")
- self.automatic[:platform] = platform
- self.automatic[:platform_version] = version
+ automatic[:platform] = platform
+ automatic[:platform_version] = version
end
# Consumes the combined run_list and other attributes in +attrs+
@@ -366,22 +342,22 @@ class Chef
normal_attrs_to_merge = consume_run_list(attrs)
normal_attrs_to_merge = consume_chef_environment(normal_attrs_to_merge)
Chef::Log.debug("Applying attributes from json file")
- self.normal_attrs = Chef::Mixin::DeepMerge.merge(normal_attrs,normal_attrs_to_merge)
- self.tags # make sure they're defined
+ self.normal_attrs = Chef::Mixin::DeepMerge.merge(normal_attrs, normal_attrs_to_merge)
+ tags # make sure they're defined
end
# Lazy initializer for tags attribute
def tags
- normal[:tags] = [] unless attribute?(:tags)
+ normal[:tags] = Array(normal[:tags])
normal[:tags]
end
- def tag(*tags)
- tags.each do |tag|
- self.normal[:tags].push(tag.to_s) unless self[:tags].include? tag.to_s
+ def tag(*args)
+ args.each do |tag|
+ tags.push(tag.to_s) unless tags.include? tag.to_s
end
- self[:tags]
+ tags
end
# Extracts the run list from +attrs+ and applies it. Returns the remaining attributes
@@ -391,7 +367,7 @@ class Chef
if attrs.key?("recipes") || attrs.key?("run_list")
raise Chef::Exceptions::AmbiguousRunlistSpecification, "please set the node's run list using the 'run_list' attribute only."
end
- Chef::Log.info("Setting the run_list to #{new_run_list.to_s} from CLI options")
+ Chef::Log.info("Setting the run_list to #{new_run_list} from CLI options")
run_list(new_run_list)
end
attrs
@@ -418,8 +394,8 @@ class Chef
# Clear defaults and overrides, so that any deleted attributes
# between runs are still gone.
def reset_defaults_and_overrides
- self.default.clear
- self.override.clear
+ default.clear
+ override.clear
end
# Expands the node's run list and sets the default and override
@@ -434,11 +410,11 @@ class Chef
# run_list is mutated? Or perhaps do something smarter like
# on-demand generation of default_attrs and override_attrs,
# invalidated only when run_list is mutated?
- def expand!(data_source = 'server')
+ def expand!(data_source = "server")
expansion = run_list.expand(chef_environment, data_source)
raise Chef::Exceptions::MissingRole, expansion if expansion.errors?
- self.tags # make sure they're defined
+ tags # make sure they're defined
automatic_attrs[:recipes] = expansion.recipes.with_duplicate_names
automatic_attrs[:expanded_run_list] = expansion.recipes.with_fully_qualified_names_and_version_constraints
@@ -453,7 +429,7 @@ class Chef
# passed in, which came from roles.
def apply_expansion_attributes(expansion)
loaded_environment = if chef_environment == "_default"
- Chef::Environment.new.tap {|e| e.name("_default")}
+ Chef::Environment.new.tap { |e| e.name("_default") }
else
Chef::Environment.load(chef_environment)
end
@@ -501,14 +477,14 @@ class Chef
result = {
"name" => name,
"chef_environment" => chef_environment,
- 'json_class' => self.class.name,
+ "json_class" => self.class.name,
"automatic" => attributes.automatic,
"normal" => attributes.normal,
"chef_type" => "node",
"default" => attributes.combined_default,
"override" => attributes.combined_override,
#Render correctly for run_list items so malformed json does not result
- "run_list" => @primary_runlist.run_list.map { |item| item.to_s }
+ "run_list" => @primary_runlist.run_list.map { |item| item.to_s },
}
# Chef Server rejects node JSON with extra keys; prior to 12.3,
# "policy_name" and "policy_group" are unknown; after 12.3 they are
@@ -533,6 +509,12 @@ class Chef
# Create a Chef::Node from JSON
def self.json_create(o)
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::Node#from_hash")
+ from_hash(o)
+ end
+
+ def self.from_hash(o)
+ return o if o.kind_of? Chef::Node
node = new
node.name(o["name"])
node.chef_environment(o["chef_environment"])
@@ -546,7 +528,7 @@ class Chef
if o.has_key?("run_list")
node.run_list.reset!(o["run_list"])
- else
+ elsif o.has_key?("recipes")
o["recipes"].each { |r| node.recipes << r }
end
@@ -556,32 +538,33 @@ class Chef
node
end
- def self.list_by_environment(environment, inflate=false)
+ def self.list_by_environment(environment, inflate = false)
if inflate
response = Hash.new
- Chef::Search::Query.new.search(:node, "chef_environment:#{environment}") {|n| response[n.name] = n unless n.nil?}
+ Chef::Search::Query.new.search(:node, "chef_environment:#{environment}") { |n| response[n.name] = n unless n.nil? }
response
else
- Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("environments/#{environment}/nodes")
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("environments/#{environment}/nodes")
end
end
- def self.list(inflate=false)
+ def self.list(inflate = false)
if inflate
response = Hash.new
Chef::Search::Query.new.search(:node) do |n|
+ n = Chef::Node.from_hash(n)
response[n.name] = n unless n.nil?
end
response
else
- Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("nodes")
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("nodes")
end
end
def self.find_or_create(node_name)
load(node_name)
rescue Net::HTTPServerException => e
- raise unless e.response.code == '404'
+ raise unless e.response.code == "404"
node = build(node_name)
node.create
end
@@ -595,12 +578,12 @@ class Chef
# Load a node by name
def self.load(name)
- Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("nodes/#{name}")
+ from_hash(Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("nodes/#{name}"))
end
# Remove this node via the REST API
def destroy
- chef_server_rest.delete_rest("nodes/#{name}")
+ chef_server_rest.delete("nodes/#{name}")
end
# Save this node via the REST API
@@ -611,11 +594,11 @@ class Chef
if Chef::Config[:why_run]
Chef::Log.warn("In why-run mode, so NOT performing node save.")
else
- chef_server_rest.put_rest("nodes/#{name}", data_for_save)
+ chef_server_rest.put("nodes/#{name}", data_for_save)
end
rescue Net::HTTPServerException => e
if e.response.code == "404"
- chef_server_rest.post_rest("nodes", data_for_save)
+ chef_server_rest.post("nodes", data_for_save)
# Chef Server before 12.3 rejects node JSON with 'policy_name' or
# 'policy_group' keys, but 'policy_name' will be detected first.
# Backcompat can be removed in 13.0
@@ -630,14 +613,14 @@ class Chef
# Create the node via the REST API
def create
- chef_server_rest.post_rest("nodes", data_for_save)
+ chef_server_rest.post("nodes", data_for_save)
self
rescue Net::HTTPServerException => e
# Chef Server before 12.3 rejects node JSON with 'policy_name' or
# 'policy_group' keys, but 'policy_name' will be detected first.
# Backcompat can be removed in 13.0
if e.response.code == "400" && e.response.body.include?("Invalid key policy_name")
- chef_server_rest.post_rest("nodes", data_for_save_without_policyfile_attrs)
+ chef_server_rest.post("nodes", data_for_save_without_policyfile_attrs)
else
raise
end
@@ -649,14 +632,14 @@ class Chef
def ==(other)
if other.kind_of?(self.class)
- self.name == other.name
+ name == other.name
else
false
end
end
- def <=>(other_node)
- self.name <=> other_node.name
+ def <=>(other)
+ name <=> other.name
end
private
@@ -664,10 +647,10 @@ class Chef
def save_without_policyfile_attrs
trimmed_data = data_for_save_without_policyfile_attrs
- chef_server_rest.put_rest("nodes/#{name}", trimmed_data)
+ chef_server_rest.put("nodes/#{name}", trimmed_data)
rescue Net::HTTPServerException => e
raise e unless e.response.code == "404"
- chef_server_rest.post_rest("nodes", trimmed_data)
+ chef_server_rest.post("nodes", trimmed_data)
end
def data_for_save_without_policyfile_attrs
@@ -679,7 +662,7 @@ class Chef
def data_for_save
data = for_json
- ["automatic", "default", "normal", "override"].each do |level|
+ %w{automatic default normal override}.each do |level|
whitelist_config_option = "#{level}_attribute_whitelist".to_sym
whitelist = Chef::Config[whitelist_config_option]
unless whitelist.nil? # nil => save everything
diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb
index 45f2ef01ee..4febd47b44 100644
--- a/lib/chef/node/attribute.rb
+++ b/lib/chef/node/attribute.rb
@@ -1,7 +1,7 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,14 @@
# limitations under the License.
#
-require 'chef/node/immutable_collections'
-require 'chef/node/attribute_collections'
-require 'chef/mixin/deep_merge'
-require 'chef/log'
+require "chef/node/mixin/deep_merge_cache"
+require "chef/node/mixin/immutablize_hash"
+require "chef/node/mixin/state_tracking"
+require "chef/node/immutable_collections"
+require "chef/node/attribute_collections"
+require "chef/decorator/unchain"
+require "chef/mixin/deep_merge"
+require "chef/log"
class Chef
class Node
@@ -33,9 +37,18 @@ class Chef
class Attribute < Mash
include Immutablize
-
+ # FIXME: what is include Enumerable doing up here, when down below we delegate
+ # most of the Enumerable/Hash things to the underlying merged ImmutableHash. That
+ # is, in fact, the correct, thing to do, while including Enumerable to try to create
+ # a hash-like API gets lots of things wrong because of the difference between the
+ # Hash `each do |key, value|` vs the Array-like `each do |value|` API that Enumerable
+ # expects. This include should probably be deleted?
include Enumerable
+ include Chef::Node::Mixin::DeepMergeCache
+ include Chef::Node::Mixin::StateTracking
+ include Chef::Node::Mixin::ImmutablizeHash
+
# List of the component attribute hashes, in order of precedence, low to
# high.
COMPONENTS = [
@@ -48,21 +61,21 @@ class Chef
:@role_override,
:@env_override,
:@force_override,
- :@automatic
+ :@automatic,
].freeze
DEFAULT_COMPONENTS = [
:@default,
:@env_default,
:@role_default,
- :@force_default
+ :@force_default,
]
OVERRIDE_COMPONENTS = [
:@override,
:@role_override,
:@env_override,
- :@force_override
+ :@force_override,
]
[:all?,
@@ -132,6 +145,7 @@ class Chef
:take,
:take_while,
:to_a,
+ :to_h,
:to_hash,
:to_set,
:value?,
@@ -144,272 +158,241 @@ class Chef
end
# return the cookbook level default attribute component
- attr_reader :default
+ attr_reader :default
# return the role level default attribute component
- attr_reader :role_default
+ attr_reader :role_default
# return the environment level default attribute component
- attr_reader :env_default
+ attr_reader :env_default
# return the force_default level attribute component
- attr_reader :force_default
+ attr_reader :force_default
# return the "normal" level attribute component
- attr_reader :normal
+ attr_reader :normal
# return the cookbook level override attribute component
- attr_reader :override
+ attr_reader :override
# return the role level override attribute component
- attr_reader :role_override
+ attr_reader :role_override
# return the enviroment level override attribute component
- attr_reader :env_override
+ attr_reader :env_override
# return the force override level attribute component
- attr_reader :force_override
+ attr_reader :force_override
# return the automatic level attribute component
- attr_reader :automatic
-
- # This is used to track the top level key as we descend through method chaining into
- # a precedence level (e.g. node.default['foo']['bar']['baz']= results in 'foo' here). We
- # need this so that when we hit the end of a method chain which results in a mutator method
- # that we can invalidate the whole top-level deep merge cache for the top-level key. It is
- # the responsibility of the accessor on the Chef::Node object to reset this to nil, and then
- # the first VividMash#[] call can ||= and set this to the first key we encounter.
- attr_accessor :top_level_breadcrumb
-
- # Cache of deep merged values by top-level key. This is a simple hash which has keys that are the
- # top-level keys of the node object, and we save the computed deep-merge for that key here. There is
- # no cache of subtrees.
- attr_accessor :deep_merge_cache
-
- def initialize(normal, default, override, automatic)
- @set_unless_present = false
-
- @default = VividMash.new(self, default)
- @env_default = VividMash.new(self, {})
- @role_default = VividMash.new(self, {})
- @force_default = VividMash.new(self, {})
-
- @normal = VividMash.new(self, normal)
-
- @override = VividMash.new(self, override)
- @role_override = VividMash.new(self, {})
- @env_override = VividMash.new(self, {})
- @force_override = VividMash.new(self, {})
-
- @automatic = VividMash.new(self, automatic)
-
- @merged_attributes = nil
- @combined_override = nil
- @combined_default = nil
- @top_level_breadcrumb = nil
- @deep_merge_cache = {}
- end
+ attr_reader :automatic
+
+ def initialize(normal, default, override, automatic, node = nil)
+ @default = VividMash.new(default, self, node, :default)
+ @env_default = VividMash.new({}, self, node, :env_default)
+ @role_default = VividMash.new({}, self, node, :role_default)
+ @force_default = VividMash.new({}, self, node, :force_default)
+
+ @normal = VividMash.new(normal, self, node, :normal)
+
+ @override = VividMash.new(override, self, node, :override)
+ @role_override = VividMash.new({}, self, node, :role_override)
+ @env_override = VividMash.new({}, self, node, :env_override)
+ @force_override = VividMash.new({}, self, node, :force_override)
+
+ @automatic = VividMash.new(automatic, self, node, :automatic)
+
+ super(nil, self, node, :merged)
+ end
# Debug what's going on with an attribute. +args+ is a path spec to the
# attribute you're interested in. For example, to debug where the value
# of `node[:network][:default_interface]` is coming from, use:
# debug_value(:network, :default_interface).
- # The return value is an Array of Arrays. The first element is
- # `["set_unless_enabled?", Boolean]`, which describes whether the
- # attribute collection is in "set_unless" mode. The rest of the Arrays
+ # The return value is an Array of Arrays. The Arrays
# are pairs of `["precedence_level", value]`, where precedence level is
# the component, such as role default, normal, etc. and value is the
# attribute value set at that precedence level. If there is no value at
# that precedence level, +value+ will be the symbol +:not_present+.
- def debug_value(*args)
- components = COMPONENTS.map do |component|
- ivar = instance_variable_get(component)
- value = args.inject(ivar) do |so_far, key|
- if so_far == :not_present
- :not_present
- elsif so_far.has_key?(key)
- so_far[key]
- else
- :not_present
- end
- end
- [component.to_s.sub(/^@/,""), value]
- end
- [["set_unless_enabled?", @set_unless_present]] + components
- end
-
- # Enables or disables `||=`-like attribute setting. See, e.g., Node#set_unless
- def set_unless_value_present=(setting)
- @set_unless_present = setting
- end
-
- # Invalidate a key in the deep_merge_cache. If called with nil, or no arg, this will invalidate
- # the entire deep_merge cache. In the case of the user doing node.default['foo']['bar']['baz']=
- # that eventually results in a call to reset_cache('foo') here. A node.default=hash_thing call
- # must invalidate the entire cache and re-deep-merge the entire node object.
- def reset_cache(path = nil)
- if path.nil?
- @deep_merge_cache = {}
- else
- deep_merge_cache.delete(path.to_s)
- end
- end
-
- alias :reset :reset_cache
+ def debug_value(*args)
+ COMPONENTS.map do |component|
+ ivar = instance_variable_get(component)
+ value = args.inject(ivar) do |so_far, key|
+ if so_far == :not_present
+ :not_present
+ elsif so_far.has_key?(key)
+ so_far[key]
+ else
+ :not_present
+ end
+ end
+ [component.to_s.sub(/^@/, ""), value]
+ end
+ end
# Set the cookbook level default attribute component to +new_data+.
- def default=(new_data)
- reset
- @default = VividMash.new(self, new_data)
- end
+ def default=(new_data)
+ reset
+ @default = VividMash.new(new_data, self, __node__, :default)
+ end
# Set the role level default attribute component to +new_data+
- def role_default=(new_data)
- reset
- @role_default = VividMash.new(self, new_data)
- end
+ def role_default=(new_data)
+ reset
+ @role_default = VividMash.new(new_data, self, __node__, :role_default)
+ end
# Set the environment level default attribute component to +new_data+
- def env_default=(new_data)
- reset
- @env_default = VividMash.new(self, new_data)
- end
+ def env_default=(new_data)
+ reset
+ @env_default = VividMash.new(new_data, self, __node__, :env_default)
+ end
# Set the force_default (+default!+) level attributes to +new_data+
- def force_default=(new_data)
- reset
- @force_default = VividMash.new(self, new_data)
- end
+ def force_default=(new_data)
+ reset
+ @force_default = VividMash.new(new_data, self, __node__, :force_default)
+ end
# Set the normal level attribute component to +new_data+
- def normal=(new_data)
- reset
- @normal = VividMash.new(self, new_data)
- end
+ def normal=(new_data)
+ reset
+ @normal = VividMash.new(new_data, self, __node__, :normal)
+ end
# Set the cookbook level override attribute component to +new_data+
- def override=(new_data)
- reset
- @override = VividMash.new(self, new_data)
- end
+ def override=(new_data)
+ reset
+ @override = VividMash.new(new_data, self, __node__, :override)
+ end
# Set the role level override attribute component to +new_data+
- def role_override=(new_data)
- reset
- @role_override = VividMash.new(self, new_data)
- end
+ def role_override=(new_data)
+ reset
+ @role_override = VividMash.new(new_data, self, __node__, :role_override)
+ end
# Set the environment level override attribute component to +new_data+
- def env_override=(new_data)
- reset
- @env_override = VividMash.new(self, new_data)
- end
+ def env_override=(new_data)
+ reset
+ @env_override = VividMash.new(new_data, self, __node__, :env_override)
+ end
- def force_override=(new_data)
- reset
- @force_override = VividMash.new(self, new_data)
- end
+ def force_override=(new_data)
+ reset
+ @force_override = VividMash.new(new_data, self, __node__, :force_override)
+ end
- def automatic=(new_data)
- reset
- @automatic = VividMash.new(self, new_data)
- end
+ def automatic=(new_data)
+ reset
+ @automatic = VividMash.new(new_data, self, __node__, :automatic)
+ end
#
# Deleting attributes
#
# clears attributes from all precedence levels
- def rm(*args)
- reset(args[0])
- # just easier to compute our retval, rather than collect+merge sub-retvals
- ret = args.inject(merged_attributes) do |attr, arg|
- if attr.nil? || !attr.respond_to?(:[])
- nil
- else
- begin
- attr[arg]
- rescue TypeError
- raise TypeError, "Wrong type in index of attribute (did you use a Hash index on an Array?)"
- end
- end
- end
- rm_default(*args)
- rm_normal(*args)
- rm_override(*args)
- ret
- end
-
- # does <level>['foo']['bar'].delete('baz')
- def remove_from_precedence_level(level, *args, key)
- multimash = level.element(*args)
- multimash.nil? ? nil : multimash.delete(key)
- end
-
- private :remove_from_precedence_level
+ def rm(*args)
+ with_deep_merged_return_value(self, *args) do
+ rm_default(*args)
+ rm_normal(*args)
+ rm_override(*args)
+ end
+ end
# clears attributes from all default precedence levels
#
- # equivalent to: force_default!['foo']['bar'].delete('baz')
- def rm_default(*args)
- reset(args[0])
- remove_from_precedence_level(force_default!(autovivify: false), *args)
- end
+ # similar to: force_default!['foo']['bar'].delete('baz')
+ # - does not autovivify
+ # - does not trainwreck if interior keys do not exist
+ def rm_default(*args)
+ with_deep_merged_return_value(combined_default, *args) do
+ default.unlink(*args)
+ role_default.unlink(*args)
+ env_default.unlink(*args)
+ force_default.unlink(*args)
+ end
+ end
# clears attributes from normal precedence
#
# equivalent to: normal!['foo']['bar'].delete('baz')
- def rm_normal(*args)
- reset(args[0])
- remove_from_precedence_level(normal!(autovivify: false), *args)
- end
+ # - does not autovivify
+ # - does not trainwreck if interior keys do not exist
+ def rm_normal(*args)
+ normal.unlink(*args)
+ end
# clears attributes from all override precedence levels
#
# equivalent to: force_override!['foo']['bar'].delete('baz')
- def rm_override(*args)
- reset(args[0])
- remove_from_precedence_level(force_override!(autovivify: false), *args)
- end
+ # - does not autovivify
+ # - does not trainwreck if interior keys do not exist
+ def rm_override(*args)
+ with_deep_merged_return_value(combined_override, *args) do
+ override.unlink(*args)
+ role_override.unlink(*args)
+ env_override.unlink(*args)
+ force_override.unlink(*args)
+ end
+ end
+
+ def with_deep_merged_return_value(obj, *path, last)
+ hash = obj.read(*path)
+ return nil unless hash.is_a?(Hash)
+ ret = hash[last]
+ yield
+ ret
+ end
+
+ private :with_deep_merged_return_value
#
# Replacing attributes without merging
#
# sets default attributes without merging
- def default!(opts={})
- # FIXME: do not flush whole cache
- reset
- MultiMash.new(self, @default, [], opts)
- end
+ #
+ # - this API autovivifies (and cannot trainwreck)
+ def default!(*args)
+ return Decorator::Unchain.new(self, :default!) unless args.length > 0
+ write(:default, *args)
+ end
# sets normal attributes without merging
- def normal!(opts={})
- # FIXME: do not flush whole cache
- reset
- MultiMash.new(self, @normal, [], opts)
- end
+ #
+ # - this API autovivifies (and cannot trainwreck)
+ def normal!(*args)
+ return Decorator::Unchain.new(self, :normal!) unless args.length > 0
+ write(:normal, *args)
+ end
# sets override attributes without merging
- def override!(opts={})
- # FIXME: do not flush whole cache
- reset
- MultiMash.new(self, @override, [], opts)
- end
+ #
+ # - this API autovivifies (and cannot trainwreck)
+ def override!(*args)
+ return Decorator::Unchain.new(self, :override!) unless args.length > 0
+ write(:override, *args)
+ end
# clears from all default precedence levels and then sets force_default
- def force_default!(opts={})
- # FIXME: do not flush whole cache
- reset
- MultiMash.new(self, @force_default, [@default, @env_default, @role_default], opts)
- end
+ #
+ # - this API autovivifies (and cannot trainwreck)
+ def force_default!(*args)
+ return Decorator::Unchain.new(self, :force_default!) unless args.length > 0
+ value = args.pop
+ rm_default(*args)
+ write(:force_default, *args, value)
+ end
# clears from all override precedence levels and then sets force_override
- def force_override!(opts={})
- # FIXME: do not flush whole cache
- reset
- MultiMash.new(self, @force_override, [@override, @env_override, @role_override], opts)
- end
+ def force_override!(*args)
+ return Decorator::Unchain.new(self, :force_override!) unless args.length > 0
+ value = args.pop
+ rm_override(*args)
+ write(:force_override, *args, value)
+ end
#
# Accessing merged attributes.
@@ -419,77 +402,110 @@ class Chef
# all of node['foo'] even if the user only requires node['foo']['bar']['baz'].
#
- def merged_attributes(*path)
- # immutablize(
- merge_all(path)
- # )
- end
-
- def combined_override(*path)
- immutablize(merge_overrides(path))
- end
-
- def combined_default(*path)
- immutablize(merge_defaults(path))
- end
-
- def [](key)
- if deep_merge_cache.has_key?(key.to_s)
- # return the cache of the deep merged values by top-level key
- deep_merge_cache[key.to_s]
- else
- # save all the work of computing node[key]
- deep_merge_cache[key.to_s] = merged_attributes(key)
- end
- end
-
- def []=(key, value)
- raise Exceptions::ImmutableAttributeModification
- end
-
- def has_key?(key)
- COMPONENTS.any? do |component_ivar|
- instance_variable_get(component_ivar).has_key?(key)
- end
- end
-
- alias :attribute? :has_key?
- alias :member? :has_key?
- alias :include? :has_key?
- alias :key? :has_key?
-
- alias :each_attribute :each
-
- def method_missing(symbol, *args)
- if args.empty?
- if key?(symbol)
- self[symbol]
- else
- raise NoMethodError, "Undefined method or attribute `#{symbol}' on `node'"
- end
- elsif symbol.to_s =~ /=$/
- key_to_set = symbol.to_s[/^(.+)=$/, 1]
- self[key_to_set] = (args.length == 1 ? args[0] : args)
- else
- raise NoMethodError, "Undefined node attribute or method `#{symbol}' on `node'"
- end
- end
-
- def to_s
- merged_attributes.to_s
- end
-
- def inspect
- "#<#{self.class} " << (COMPONENTS + [:@merged_attributes, :@properties]).map{|iv|
- "#{iv}=#{instance_variable_get(iv).inspect}"
- }.join(', ') << ">"
- end
-
- def set_unless?
- @set_unless_present
- end
-
- private
+ def merged_attributes(*path)
+ immutablize(merge_all(path))
+ end
+
+ def combined_override(*path)
+ immutablize(merge_overrides(path))
+ end
+
+ def combined_default(*path)
+ immutablize(merge_defaults(path))
+ end
+
+ def normal_unless(*args)
+ return Decorator::Unchain.new(self, :normal_unless) unless args.length > 0
+ write(:normal, *args) if normal.read(*args[0...-1]).nil?
+ end
+
+ def default_unless(*args)
+ return Decorator::Unchain.new(self, :default_unless) unless args.length > 0
+ write(:default, *args) if default.read(*args[0...-1]).nil?
+ end
+
+ def override_unless(*args)
+ return Decorator::Unchain.new(self, :override_unless) unless args.length > 0
+ write(:override, *args) if override.read(*args[0...-1]).nil?
+ end
+
+ def set_unless(*args)
+ Chef.deprecated(:attributes, "node.set_unless is deprecated and will be removed in Chef 14, please use node.default_unless/node.override_unless (or node.normal_unless if you really need persistence)")
+ normal_unless(*args)
+ end
+
+ def has_key?(key)
+ COMPONENTS.any? do |component_ivar|
+ instance_variable_get(component_ivar).has_key?(key)
+ end
+ end
+ # method-style access to attributes (has to come after the prepended ImmutablizeHash)
+
+ def read(*path)
+ merged_attributes.read(*path)
+ end
+
+ def read!(*path)
+ merged_attributes.read!(*path)
+ end
+
+ def exist?(*path)
+ merged_attributes.exist?(*path)
+ end
+
+ def write(level, *args, &block)
+ send(level).write(*args, &block)
+ end
+
+ def write!(level, *args, &block)
+ send(level).write!(*args, &block)
+ end
+
+ def unlink(level, *path)
+ send(level).unlink(*path)
+ end
+
+ def unlink!(level, *path)
+ send(level).unlink!(*path)
+ end
+
+ alias :attribute? :has_key?
+ alias :member? :has_key?
+ alias :include? :has_key?
+ alias :key? :has_key?
+
+ alias :each_attribute :each
+
+ def method_missing(symbol, *args)
+ if symbol == :to_ary
+ merged_attributes.send(symbol, *args)
+ elsif args.empty?
+ Chef.deprecated(:attributes, %q{method access to node attributes (node.foo.bar) is deprecated and will be removed in Chef 13, please use bracket syntax (node["foo"]["bar"])})
+ if key?(symbol)
+ self[symbol]
+ else
+ raise NoMethodError, "Undefined method or attribute `#{symbol}' on `node'"
+ end
+ elsif symbol.to_s =~ /=$/
+ Chef.deprecated(:attributes, %q{method setting of node attributes (node.foo="bar") is deprecated and will be removed in Chef 13, please use bracket syntax (node["foo"]="bar")})
+ key_to_set = symbol.to_s[/^(.+)=$/, 1]
+ self[key_to_set] = (args.length == 1 ? args[0] : args)
+ else
+ raise NoMethodError, "Undefined node attribute or method `#{symbol}' on `node'"
+ end
+ end
+
+ def to_s
+ merged_attributes.to_s
+ end
+
+ def inspect
+ "#<#{self.class} " << (COMPONENTS + [:@merged_attributes, :@properties]).map do |iv|
+ "#{iv}=#{instance_variable_get(iv).inspect}"
+ end.join(", ") << ">"
+ end
+
+ private
# Helper method for merge_all/merge_defaults/merge_overrides.
#
@@ -501,32 +517,32 @@ class Chef
# raise any TypeError if it attempts to apply a hash key to an Integer/String/TrueClass, and just returns
# nil in that case.
#
- def apply_path(component, path)
- path ||= []
- path.inject(component) do |val, path_arg|
- if val.respond_to?(:[])
- # Have an Array-like or Hash-like thing
- if !val.respond_to?(:has_key?)
- # Have an Array-like thing
- val[path_arg]
- elsif val.has_key?(path_arg)
- # Hash-like thing (must check has_key? first to protect against Autovivification)
- val[path_arg]
- else
- nil
- end
- else
- nil
- end
- end
- end
+ def apply_path(component, path)
+ path ||= []
+ path.inject(component) do |val, path_arg|
+ if val.respond_to?(:[])
+ # Have an Array-like or Hash-like thing
+ if !val.respond_to?(:has_key?)
+ # Have an Array-like thing
+ val[path_arg]
+ elsif val.has_key?(path_arg)
+ # Hash-like thing (must check has_key? first to protect against Autovivification)
+ val[path_arg]
+ else
+ nil
+ end
+ else
+ nil
+ end
+ end
+ end
# For elements like Fixnums, true, nil...
- def safe_dup(e)
- e.dup
- rescue TypeError
- e
- end
+ def safe_dup(e)
+ e.dup
+ rescue TypeError
+ e
+ end
# Deep merge all attribute levels using hash-only merging between different precidence
# levels (so override arrays completely replace arrays set at any default level).
@@ -535,24 +551,24 @@ class Chef
#
# @param path [Array] Array of args to method chain to descend into the node object
# @return [attr] Deep Merged values (may be VividMash, Hash, Array, etc) from the node object
- def merge_all(path)
- components = [
- merge_defaults(path),
- apply_path(@normal, path),
- merge_overrides(path),
- apply_path(@automatic, path),
- ]
-
- components.map! do |component|
- safe_dup(component)
- end
+ def merge_all(path)
+ components = [
+ merge_defaults(path),
+ apply_path(@normal, path),
+ merge_overrides(path),
+ apply_path(@automatic, path),
+ ]
- return nil if components.compact.empty?
+ components.map! do |component|
+ safe_dup(component)
+ end
- components.inject(ImmutableMash.new({})) do |merged, component|
- Chef::Mixin::DeepMerge.hash_only_merge!(merged, component)
- end
- end
+ return nil if components.compact.empty?
+
+ components.inject(ImmutableMash.new({}, self, __node__, :merged)) do |merged, component|
+ Chef::Mixin::DeepMerge.hash_only_merge!(merged, component)
+ end
+ end
# Deep merge the default attribute levels with array merging.
#
@@ -560,12 +576,12 @@ class Chef
#
# @param path [Array] Array of args to method chain to descend into the node object
# @return [attr] Deep Merged values (may be VividMash, Hash, Array, etc) from the node object
- def merge_defaults(path)
- DEFAULT_COMPONENTS.inject(nil) do |merged, component_ivar|
- component_value = apply_path(instance_variable_get(component_ivar), path)
- Chef::Mixin::DeepMerge.deep_merge(component_value, merged)
- end
- end
+ def merge_defaults(path)
+ DEFAULT_COMPONENTS.inject(nil) do |merged, component_ivar|
+ component_value = apply_path(instance_variable_get(component_ivar), path)
+ Chef::Mixin::DeepMerge.deep_merge(component_value, merged)
+ end
+ end
# Deep merge the override attribute levels with array merging.
#
@@ -573,12 +589,17 @@ class Chef
#
# @param path [Array] Array of args to method chain to descend into the node object
# @return [attr] Deep Merged values (may be VividMash, Hash, Array, etc) from the node object
- def merge_overrides(path)
- OVERRIDE_COMPONENTS.inject(nil) do |merged, component_ivar|
- component_value = apply_path(instance_variable_get(component_ivar), path)
- Chef::Mixin::DeepMerge.deep_merge(component_value, merged)
- end
- end
+ def merge_overrides(path)
+ OVERRIDE_COMPONENTS.inject(nil) do |merged, component_ivar|
+ component_value = apply_path(instance_variable_get(component_ivar), path)
+ Chef::Mixin::DeepMerge.deep_merge(component_value, merged)
+ end
+ end
+
+ # needed for __path__
+ def convert_key(key)
+ key.kind_of?(Symbol) ? key.to_s : key
+ end
end
diff --git a/lib/chef/node/attribute_collections.rb b/lib/chef/node/attribute_collections.rb
index b912904534..694b5fbc3a 100644
--- a/lib/chef/node/attribute_collections.rb
+++ b/lib/chef/node/attribute_collections.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,16 @@
# limitations under the License.
#
+require "chef/node/common_api"
+require "chef/node/mixin/state_tracking"
+
class Chef
class Node
-
# == AttrArray
# AttrArray is identical to Array, except that it keeps a reference to the
# "root" (Chef::Node::Attribute) object, and will trigger a cache
# invalidation on that object when mutated.
class AttrArray < Array
-
MUTATOR_METHODS = [
:<<,
:[]=,
@@ -33,7 +34,6 @@ class Chef
:compact!,
:default=,
:default_proc=,
- :delete,
:delete_at,
:delete_if,
:fill,
@@ -54,7 +54,7 @@ class Chef
:sort!,
:sort_by!,
:uniq!,
- :unshift
+ :unshift,
]
# For all of the methods that may mutate an Array, we override them to
@@ -62,16 +62,20 @@ class Chef
# Node::Attribute object.
MUTATOR_METHODS.each do |mutator|
define_method(mutator) do |*args, &block|
- root.reset_cache(root.top_level_breadcrumb)
- super(*args, &block)
+ ret = super(*args, &block)
+ send_reset_cache
+ ret
end
end
- attr_reader :root
+ def delete(key, &block)
+ send_reset_cache(__path__, key)
+ super
+ end
- def initialize(root, data)
- @root = root
+ def initialize(data = [])
super(data)
+ map! { |e| convert_value(e) }
end
# For elements like Fixnums, true, nil...
@@ -82,9 +86,32 @@ class Chef
end
def dup
- Array.new(map {|e| safe_dup(e)})
+ Array.new(map { |e| safe_dup(e) })
end
+ private
+
+ def convert_value(value)
+ case value
+ when VividMash
+ value
+ when AttrArray
+ value
+ when Hash
+ VividMash.new(value, __root__, __node__, __precedence__)
+ when Array
+ AttrArray.new(value, __root__, __node__, __precedence__)
+ else
+ value
+ end
+ end
+
+ # needed for __path__
+ def convert_key(key)
+ key
+ end
+
+ prepend Chef::Node::Mixin::StateTracking
end
# == VividMash
@@ -96,20 +123,15 @@ class Chef
# in the creation of a new VividMash for that key. (This only works when
# using the element reference method, `[]` -- other methods, such as
# #fetch, work as normal).
- # * It supports a set_unless flag (via the root Attribute object) which
- # allows `||=` style behavior (`||=` does not work with
- # auto-vivification). This is only implemented for #[]=; methods such as
- # #store work as normal.
# * attr_accessor style element set and get are supported via method_missing
class VividMash < Mash
- attr_reader :root
+ include CommonAPI
# Methods that mutate a VividMash. Each of them is overridden so that it
# also invalidates the cached merged_attributes on the root Attribute
# object.
MUTATOR_METHODS = [
:clear,
- :delete,
:delete_if,
:keep_if,
:merge!,
@@ -117,29 +139,33 @@ class Chef
:reject!,
:replace,
:select!,
- :shift
+ :shift,
]
# For all of the mutating methods on Mash, override them so that they
# also invalidate the cached `merged_attributes` on the root Attribute
# object.
+
+ def delete(key, &block)
+ send_reset_cache(__path__, key)
+ super
+ end
+
MUTATOR_METHODS.each do |mutator|
define_method(mutator) do |*args, &block|
- root.reset_cache(root.top_level_breadcrumb)
+ send_reset_cache
super(*args, &block)
end
end
- def initialize(root, data={})
- @root = root
+ def initialize(data = {})
super(data)
end
def [](key)
- root.top_level_breadcrumb ||= key
value = super
if !key?(key)
- value = self.class.new(root)
+ value = self.class.new({}, __root__)
self[key] = value
else
value
@@ -147,13 +173,9 @@ class Chef
end
def []=(key, value)
- root.top_level_breadcrumb ||= key
- if set_unless? && key?(key)
- self[key]
- else
- root.reset_cache(root.top_level_breadcrumb)
- super
- end
+ ret = super
+ send_reset_cache(__path__, key)
+ ret
end
alias :attribute? :has_key?
@@ -176,10 +198,6 @@ class Chef
end
end
- def set_unless?
- @root.set_unless?
- end
-
def convert_key(key)
super
end
@@ -192,10 +210,12 @@ class Chef
case value
when VividMash
value
+ when AttrArray
+ value
when Hash
- VividMash.new(root, value)
+ VividMash.new(value, __root__, __node__, __precedence__)
when Array
- AttrArray.new(root, value)
+ AttrArray.new(value, __root__, __node__, __precedence__)
else
value
end
@@ -205,119 +225,7 @@ class Chef
Mash.new(self)
end
+ prepend Chef::Node::Mixin::StateTracking
end
-
- # == MultiMash
- # This is a Hash-like object that contains multiple VividMashes in it. Its
- # purpose is so that the user can descend into the mash and delete a subtree
- # from all of the Mash objects (used to delete all values in a subtree from
- # default, force_default, role_default and env_default at the same time). The
- # assignment operator strictly does assignment (does no merging) and works
- # by deleting the subtree and then assigning to the last mash which passed in
- # the initializer.
- #
- # A lot of the complexity of this class comes from the fact that at any key
- # value some or all of the mashes may walk off their ends and become nil or
- # true or something. The schema may change so that one precidence leve may
- # be 'true' object and another may be a VividMash. It is also possible that
- # one or many of them may transition from VividMashes to Hashes or Arrays.
- #
- # It also supports the case where you may be deleting a key using node.rm
- # in which case if intermediate keys all walk off into nil then you don't want
- # to be autovivifying keys as you go. On the other hand you may be using
- # node.force_default! in which case you'll wind up with a []= operator at the
- # end and you want autovivification, so we conditionally have to support either
- # operation.
- #
- # @todo: can we have an autovivify class that decorates a class that doesn't
- # autovivify or something so that the code is less awful?
- #
- class MultiMash
- attr_reader :root
- attr_reader :mashes
- attr_reader :opts
- attr_reader :primary_mash
-
- # Initialize with an array of mashes. For the delete return value to work
- # properly the mashes must come from the same attribute level (i.e. all
- # override or all default, but not a mix of both).
- def initialize(root, primary_mash, mashes, opts={})
- @root = root
- @primary_mash = primary_mash
- @mashes = mashes
- @opts = opts
- @opts[:autovivify] = true if @opts[:autovivify].nil?
- end
-
- def [](key)
- # handle the secondary mashes
- new_mashes = []
- mashes.each do |mash|
- new_mash = safe_evalute_key(mash, key)
- # secondary mashes never autovivify so once they fall into nil, we just stop tracking them
- new_mashes.push(new_mash) unless new_mash.nil?
- end
-
- new_primary_mash = safe_evalute_key(primary_mash, key)
-
- if new_primary_mash.nil? && @opts[:autovivify]
- primary_mash[key] = VividMash.new(root)
- new_primary_mash = primary_mash[key]
- end
-
- MultiMash.new(root, new_primary_mash, new_mashes, opts)
- end
-
- def []=(key, value)
- if primary_mash.nil?
- # This theoretically should never happen since node#force_default! setter methods will autovivify and
- # node#rm methods do not end in #[]= operators.
- raise TypeError, "No autovivification was specified initially on a method chain ending in assignment"
- end
- ret = delete(key)
- primary_mash[key] = value
- ret
- end
-
- # mash.element('foo', 'bar') is the same as mash['foo']['bar']
- def element(key = nil, *subkeys)
- return self if key.nil?
- submash = self[key]
- subkeys.empty? ? submash : submash.element(*subkeys)
- end
-
- def delete(key)
- # the return value is a deep merge which is correct semantics when
- # merging between attributes on the same level (this would be incorrect
- # if passed both override and default attributes which would need hash_only
- # merging).
- ret = mashes.inject(Mash.new) do |merged, mash|
- Chef::Mixin::DeepMerge.merge(merged, mash)
- end
- ret = Chef::Mixin::DeepMerge.merge(ret, primary_mash)
- mashes.each do |mash|
- mash.delete(key) if mash.respond_to?(:delete)
- end
- primary_mash.delete(key) if primary_mash.respond_to?(:delete)
- ret[key]
- end
-
- private
-
- def safe_evalute_key(mash, key)
- if mash.respond_to?(:[])
- if mash.respond_to?(:has_key?)
- if mash.has_key?(key)
- return mash[key] if mash[key].respond_to?(:[])
- end
- elsif !mash[key].nil?
- return mash[key] if mash[key].respond_to?(:[])
- end
- end
- return nil
- end
-
- end
-
end
end
diff --git a/lib/chef/node/common_api.rb b/lib/chef/node/common_api.rb
new file mode 100644
index 0000000000..a703c1ef54
--- /dev/null
+++ b/lib/chef/node/common_api.rb
@@ -0,0 +1,121 @@
+#--
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Node
+ # shared API between VividMash and ImmutableMash, writer code can be
+ # 'shared' to keep it logically in this file by adding them to the
+ # block list in ImmutableMash.
+ module CommonAPI
+ # method-style access to attributes
+
+ def valid_container?(obj, key)
+ obj.is_a?(Hash) || (obj.is_a?(Array) && key.is_a?(Integer))
+ end
+
+ private :valid_container?
+
+ # - autovivifying / autoreplacing writer
+ # - non-container-ey intermediate objects are replaced with hashes
+ def write(*args, &block)
+ value = block_given? ? yield : args.pop
+ last = args.pop
+ prev_memo = prev_key = nil
+ chain = args.inject(self) do |memo, key|
+ if !valid_container?(memo, key)
+ prev_memo[prev_key] = {}
+ memo = prev_memo[prev_key]
+ end
+ prev_memo = memo
+ prev_key = key
+ memo[key]
+ end
+ if !valid_container?(chain, last)
+ prev_memo[prev_key] = {}
+ chain = prev_memo[prev_key]
+ end
+ chain[last] = value
+ end
+
+ # this autovivifies, but can throw NoSuchAttribute when trying to access #[] on
+ # something that is not a container ("schema violation" issues).
+ #
+ def write!(*args, &block)
+ value = block_given? ? yield : args.pop
+ last = args.pop
+ obj = args.inject(self) do |memo, key|
+ raise Chef::Exceptions::AttributeTypeMismatch unless valid_container?(memo, key)
+ memo[key]
+ end
+ raise Chef::Exceptions::AttributeTypeMismatch unless valid_container?(obj, last)
+ obj[last] = value
+ end
+
+ # FIXME:(?) does anyone need a non-autovivifying writer for attributes that throws exceptions?
+
+ # return true or false based on if the attribute exists
+ def exist?(*path)
+ path.inject(self) do |memo, key|
+ return false unless valid_container?(memo, key)
+ if memo.is_a?(Hash)
+ if memo.key?(key)
+ memo[key]
+ else
+ return false
+ end
+ elsif memo.is_a?(Array)
+ if memo.length > key
+ memo[key]
+ else
+ return false
+ end
+ end
+ end
+ true
+ end
+
+ # this is a safe non-autovivifying reader that returns nil if the attribute does not exist
+ def read(*path)
+ read!(*path)
+ rescue Chef::Exceptions::NoSuchAttribute
+ nil
+ end
+
+ # non-autovivifying reader that throws an exception if the attribute does not exist
+ def read!(*path)
+ raise Chef::Exceptions::NoSuchAttribute unless exist?(*path)
+ path.inject(self) do |memo, key|
+ memo[key]
+ end
+ end
+
+ # FIXME:(?) does anyone really like the autovivifying reader that we have and wants the same behavior? readers that write? ugh...
+
+ def unlink(*path, last)
+ hash = path.empty? ? self : read(*path)
+ return nil unless hash.is_a?(Hash) || hash.is_a?(Array)
+ hash.delete(last)
+ end
+
+ def unlink!(*path)
+ raise Chef::Exceptions::NoSuchAttribute unless exist?(*path)
+ unlink(*path)
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/node/immutable_collections.rb b/lib/chef/node/immutable_collections.rb
index 0e2800641a..dad712e078 100644
--- a/lib/chef/node/immutable_collections.rb
+++ b/lib/chef/node/immutable_collections.rb
@@ -1,3 +1,24 @@
+#--
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/node/common_api"
+require "chef/node/mixin/state_tracking"
+require "chef/node/mixin/immutablize_array"
+require "chef/node/mixin/immutablize_hash"
class Chef
class Node
@@ -6,9 +27,9 @@ class Chef
def immutablize(value)
case value
when Hash
- ImmutableMash.new(value)
+ ImmutableMash.new(value, __root__, __node__, __precedence__)
when Array
- ImmutableArray.new(value)
+ ImmutableArray.new(value, __root__, __node__, __precedence__)
else
value
end
@@ -31,55 +52,12 @@ class Chef
alias :internal_push :<<
private :internal_push
- # A list of methods that mutate Array. Each of these is overridden to
- # raise an error, making this instances of this class more or less
- # immutable.
- DISALLOWED_MUTATOR_METHODS = [
- :<<,
- :[]=,
- :clear,
- :collect!,
- :compact!,
- :default=,
- :default_proc=,
- :delete,
- :delete_at,
- :delete_if,
- :fill,
- :flatten!,
- :insert,
- :keep_if,
- :map!,
- :merge!,
- :pop,
- :push,
- :update,
- :reject!,
- :reverse!,
- :replace,
- :select!,
- :shift,
- :slice!,
- :sort!,
- :sort_by!,
- :uniq!,
- :unshift
- ]
-
- def initialize(array_data)
+ def initialize(array_data = [])
array_data.each do |value|
internal_push(immutablize(value))
end
end
- # Redefine all of the methods that mutate a Hash to raise an error when called.
- # This is the magic that makes this object "Immutable"
- DISALLOWED_MUTATOR_METHODS.each do |mutator_method_name|
- define_method(mutator_method_name) do |*args, &block|
- raise Exceptions::ImmutableAttributeModification
- end
- end
-
# For elements like Fixnums, true, nil...
def safe_dup(e)
e.dup
@@ -88,7 +66,7 @@ class Chef
end
def dup
- Array.new(map {|e| safe_dup(e)})
+ Array.new(map { |e| safe_dup(e) })
end
def to_a
@@ -107,6 +85,13 @@ class Chef
a
end
+ # for consistency's sake -- integers 'converted' to integers
+ def convert_key(key)
+ key
+ end
+
+ prepend Chef::Node::Mixin::StateTracking
+ prepend Chef::Node::Mixin::ImmutablizeArray
end
# == ImmutableMash
@@ -122,31 +107,13 @@ class Chef
# it is stale.
# * Values can be accessed in attr_reader-like fashion via method_missing.
class ImmutableMash < Mash
-
include Immutablize
+ include CommonAPI
alias :internal_set :[]=
private :internal_set
- DISALLOWED_MUTATOR_METHODS = [
- :[]=,
- :clear,
- :collect!,
- :default=,
- :default_proc=,
- :delete,
- :delete_if,
- :keep_if,
- :map!,
- :merge!,
- :update,
- :reject!,
- :replace,
- :select!,
- :shift
- ]
-
- def initialize(mash_data)
+ def initialize(mash_data = {})
mash_data.each do |key, value|
internal_set(key, immutablize(value))
end
@@ -158,22 +125,16 @@ class Chef
alias :attribute? :has_key?
- # Redefine all of the methods that mutate a Hash to raise an error when called.
- # This is the magic that makes this object "Immutable"
- DISALLOWED_MUTATOR_METHODS.each do |mutator_method_name|
- define_method(mutator_method_name) do |*args, &block|
- raise Exceptions::ImmutableAttributeModification
- end
- end
-
def method_missing(symbol, *args)
- if args.empty?
+ if symbol == :to_ary
+ super
+ elsif args.empty?
if key?(symbol)
self[symbol]
else
raise NoMethodError, "Undefined method or attribute `#{symbol}' on `node'"
end
- # This will raise a ImmutableAttributeModification error:
+ # This will raise a ImmutableAttributeModification error:
elsif symbol.to_s =~ /=$/
key_to_set = symbol.to_s[/^(.+)=$/, 1]
self[key_to_set] = (args.length == 1 ? args[0] : args)
@@ -213,7 +174,8 @@ class Chef
h
end
+ prepend Chef::Node::Mixin::StateTracking
+ prepend Chef::Node::Mixin::ImmutablizeHash
end
-
end
end
diff --git a/lib/chef/node/mixin/deep_merge_cache.rb b/lib/chef/node/mixin/deep_merge_cache.rb
new file mode 100644
index 0000000000..b18d6b10cb
--- /dev/null
+++ b/lib/chef/node/mixin/deep_merge_cache.rb
@@ -0,0 +1,61 @@
+#--
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Node
+ module Mixin
+ module DeepMergeCache
+ # Cache of deep merged values by top-level key. This is a simple hash which has keys that are the
+ # top-level keys of the node object, and we save the computed deep-merge for that key here. There is
+ # no cache of subtrees.
+ attr_accessor :deep_merge_cache
+
+ def initialize
+ @merged_attributes = nil
+ @combined_override = nil
+ @combined_default = nil
+ @deep_merge_cache = {}
+ end
+
+ # Invalidate a key in the deep_merge_cache. If called with nil, or no arg, this will invalidate
+ # the entire deep_merge cache. In the case of the user doing node.default['foo']['bar']['baz']=
+ # that eventually results in a call to reset_cache('foo') here. A node.default=hash_thing call
+ # must invalidate the entire cache and re-deep-merge the entire node object.
+ def reset_cache(path = nil)
+ if path.nil?
+ deep_merge_cache.clear
+ else
+ deep_merge_cache.delete(path.to_s)
+ end
+ end
+
+ alias :reset :reset_cache
+
+ def [](key)
+ if deep_merge_cache.has_key?(key.to_s)
+ # return the cache of the deep merged values by top-level key
+ deep_merge_cache[key.to_s]
+ else
+ # save all the work of computing node[key]
+ deep_merge_cache[key.to_s] = merged_attributes(key)
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/node/mixin/immutablize_array.rb b/lib/chef/node/mixin/immutablize_array.rb
new file mode 100644
index 0000000000..cfa7266b9a
--- /dev/null
+++ b/lib/chef/node/mixin/immutablize_array.rb
@@ -0,0 +1,67 @@
+#--
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Node
+ module Mixin
+ module ImmutablizeArray
+ # A list of methods that mutate Array. Each of these is overridden to
+ # raise an error, making this instances of this class more or less
+ # immutable.
+ DISALLOWED_MUTATOR_METHODS = [
+ :<<,
+ :[]=,
+ :clear,
+ :collect!,
+ :compact!,
+ :default=,
+ :default_proc=,
+ :delete,
+ :delete_at,
+ :delete_if,
+ :fill,
+ :flatten!,
+ :insert,
+ :keep_if,
+ :map!,
+ :merge!,
+ :pop,
+ :push,
+ :update,
+ :reject!,
+ :reverse!,
+ :replace,
+ :select!,
+ :shift,
+ :slice!,
+ :sort!,
+ :sort_by!,
+ :uniq!,
+ :unshift,
+ ]
+
+ # Redefine all of the methods that mutate a Hash to raise an error when called.
+ # This is the magic that makes this object "Immutable"
+ DISALLOWED_MUTATOR_METHODS.each do |mutator_method_name|
+ define_method(mutator_method_name) do |*args, &block|
+ raise Exceptions::ImmutableAttributeModification
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/node/mixin/immutablize_hash.rb b/lib/chef/node/mixin/immutablize_hash.rb
new file mode 100644
index 0000000000..f09e6944fc
--- /dev/null
+++ b/lib/chef/node/mixin/immutablize_hash.rb
@@ -0,0 +1,54 @@
+#--
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Node
+ module Mixin
+ module ImmutablizeHash
+ DISALLOWED_MUTATOR_METHODS = [
+ :[]=,
+ :clear,
+ :collect!,
+ :default=,
+ :default_proc=,
+ :delete,
+ :delete_if,
+ :keep_if,
+ :map!,
+ :merge!,
+ :update,
+ :reject!,
+ :replace,
+ :select!,
+ :shift,
+ :write,
+ :write!,
+ :unlink,
+ :unlink!,
+ ]
+
+ # Redefine all of the methods that mutate a Hash to raise an error when called.
+ # This is the magic that makes this object "Immutable"
+ DISALLOWED_MUTATOR_METHODS.each do |mutator_method_name|
+ define_method(mutator_method_name) do |*args, &block|
+ raise Exceptions::ImmutableAttributeModification
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/node/mixin/state_tracking.rb b/lib/chef/node/mixin/state_tracking.rb
new file mode 100644
index 0000000000..5958973024
--- /dev/null
+++ b/lib/chef/node/mixin/state_tracking.rb
@@ -0,0 +1,96 @@
+#--
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Node
+ module Mixin
+ module StateTracking
+ attr_reader :__path__
+ attr_reader :__root__
+ attr_reader :__node__
+ attr_reader :__precedence__
+
+ def initialize(data = nil, root = self, node = nil, precedence = nil)
+ # __path__ and __root__ must be nil when we call super so it knows
+ # to avoid resetting the cache on construction
+ data.nil? ? super() : super(data)
+ @__path__ = []
+ @__root__ = root
+ @__node__ = node
+ @__precedence__ = precedence
+ end
+
+ def [](*args)
+ ret = super
+ key = args.first
+ next_path = [ __path__, convert_key(key) ].flatten.compact
+ copy_state_to(ret, next_path)
+ end
+
+ def []=(*args)
+ ret = super
+ key = args.first
+ value = args.last
+ next_path = [ __path__, convert_key(key) ].flatten.compact
+ send_attribute_changed_event(next_path, value)
+ copy_state_to(ret, next_path)
+ end
+
+ protected
+
+ def __path__=(path)
+ @__path__ = path
+ end
+
+ def __root__=(root)
+ @__root__ = root
+ end
+
+ def __precedence__=(precedence)
+ @__precedence__ = precedence
+ end
+
+ def __node__=(node)
+ @__node__ = node
+ end
+
+ private
+
+ def send_attribute_changed_event(next_path, value)
+ if __node__ && __node__.run_context && __node__.run_context.events
+ __node__.run_context.events.attribute_changed(__precedence__, next_path, value)
+ end
+ end
+
+ def send_reset_cache(path = nil, key = nil)
+ next_path = [ path, key ].flatten.compact
+ __root__.reset_cache(next_path.first) if !__root__.nil? && __root__.respond_to?(:reset_cache) && !next_path.nil?
+ end
+
+ def copy_state_to(ret, next_path)
+ if ret.is_a?(StateTracking)
+ ret.__path__ = next_path
+ ret.__root__ = __root__
+ ret.__node__ = __node__
+ ret.__precedence__ = __precedence__
+ end
+ ret
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb
index 751f9576f6..552c90b8d1 100644
--- a/lib/chef/node_map.rb
+++ b/lib/chef/node_map.rb
@@ -1,6 +1,6 @@
#
# Author:: Lamont Granquist (<lamont@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,8 +32,8 @@ class Chef
# @return [NodeMap] Returns self for possible chaining
#
def set(key, value, platform: nil, platform_version: nil, platform_family: nil, os: nil, on_platform: nil, on_platforms: nil, canonical: nil, override: nil, &block)
- Chef.log_deprecation("The on_platform option to node_map has been deprecated") if on_platform
- Chef.log_deprecation("The on_platforms option to node_map has been deprecated") if on_platforms
+ Chef.deprecated(:internal_api, "The on_platform option to node_map has been deprecated") if on_platform
+ Chef.deprecated(:internal_api, "The on_platforms option to node_map has been deprecated") if on_platforms
platform ||= on_platform || on_platforms
filters = {}
filters[:platform] = platform if platform
@@ -49,7 +49,7 @@ class Chef
# our place in it (just before the first value with the same preference level).
insert_at = nil
map[key] ||= []
- map[key].each_with_index do |matcher,index|
+ map[key].each_with_index do |matcher, index|
cmp = compare_matchers(key, new_matcher, matcher)
insert_at ||= index if cmp && cmp <= 0
end
@@ -113,7 +113,7 @@ class Chef
remaining
end
- protected
+ private
#
# Succeeds if:
@@ -128,7 +128,7 @@ class Chef
value = node[attribute]
# Split the blacklist and whitelist
- blacklist, whitelist = filter_values.partition { |v| v.is_a?(String) && v.start_with?('!') }
+ blacklist, whitelist = filter_values.partition { |v| v.is_a?(String) && v.start_with?("!") }
# If any blacklist value matches, we don't match
return false if blacklist.any? { |v| v[1..-1] == value }
@@ -145,16 +145,16 @@ class Chef
value = node[attribute]
filter_values.empty? ||
- Array(filter_values).any? do |v|
- Chef::VersionConstraint::Platform.new(v).include?(value)
- end
+ Array(filter_values).any? do |v|
+ Chef::VersionConstraint::Platform.new(v).include?(value)
+ end
end
def filters_match?(node, filters)
matches_black_white_list?(node, filters, :os) &&
- matches_black_white_list?(node, filters, :platform_family) &&
- matches_black_white_list?(node, filters, :platform) &&
- matches_version_list?(node, filters, :platform_version)
+ matches_black_white_list?(node, filters, :platform_family) &&
+ matches_black_white_list?(node, filters, :platform) &&
+ matches_version_list?(node, filters, :platform_version)
end
def block_matches?(node, block)
@@ -172,7 +172,8 @@ class Chef
!!canonical == !!matcher[:canonical]
end
- def compare_matchers(key, new_matcher, matcher)
+ # @api private
+ def dispatch_compare_matchers(key, new_matcher, matcher)
cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:block] }
return cmp if cmp != 0
cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:platform_version] }
@@ -189,14 +190,29 @@ class Chef
0
end
+ #
+ # "provides" lines with identical filters sort by class name (ascending).
+ #
+ def compare_matchers(key, new_matcher, matcher)
+ cmp = dispatch_compare_matchers(key, new_matcher, matcher)
+ if cmp == 0
+ # Sort by class name (ascending) as well, if all other properties
+ # are exactly equal
+ if new_matcher[:value].is_a?(Class) && !new_matcher[:override]
+ cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:value].name }
+ end
+ end
+ cmp
+ end
+
def compare_matcher_properties(new_matcher, matcher)
a = yield(new_matcher)
b = yield(matcher)
# Check for blcacklists ('!windows'). Those always come *after* positive
# whitelists.
- a_negated = Array(a).any? { |f| f.is_a?(String) && f.start_with?('!') }
- b_negated = Array(b).any? { |f| f.is_a?(String) && f.start_with?('!') }
+ a_negated = Array(a).any? { |f| f.is_a?(String) && f.start_with?("!") }
+ b_negated = Array(b).any? { |f| f.is_a?(String) && f.start_with?("!") }
if a_negated != b_negated
return 1 if a_negated
return -1 if b_negated
diff --git a/lib/chef/null_logger.rb b/lib/chef/null_logger.rb
index 5195cc5ce2..927cfc0c08 100644
--- a/lib/chef/null_logger.rb
+++ b/lib/chef/null_logger.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -42,7 +42,7 @@ class Chef
def debug(message, &block)
end
- def add(severity, message=nil, progname=nil)
+ def add(severity, message = nil, progname = nil)
end
def <<(message)
diff --git a/lib/chef/org.rb b/lib/chef/org.rb
index 41d74b6186..bed5600920 100644
--- a/lib/chef/org.rb
+++ b/lib/chef/org.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (steve@opscode.com)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc
+# Author:: Steven Danna (steve@chef.io)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/json_compat'
-require 'chef/mixin/params_validate'
-require 'chef/rest'
+require "chef/json_compat"
+require "chef/mixin/params_validate"
+require "chef/server_api"
class Chef
class Org
@@ -27,7 +27,7 @@ class Chef
def initialize(name)
@name = name
- @full_name = ''
+ @full_name = ""
# The Chef API returns the private key of the validator
# client on create
@private_key = nil
@@ -35,25 +35,25 @@ class Chef
end
def chef_rest
- @chef_rest ||= Chef::REST.new(Chef::Config[:chef_server_root])
+ @chef_rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root])
end
- def name(arg=nil)
+ def name(arg = nil)
set_or_return(:name, arg,
:regex => /^[a-z0-9\-_]+$/)
end
- def full_name(arg=nil)
+ def full_name(arg = nil)
set_or_return(:full_name,
arg, :kind_of => String)
end
- def private_key(arg=nil)
+ def private_key(arg = nil)
set_or_return(:private_key,
arg, :kind_of => String)
end
- def guid(arg=nil)
+ def guid(arg = nil)
set_or_return(:guid,
arg, :kind_of => String)
end
@@ -61,7 +61,7 @@ class Chef
def to_hash
result = {
"name" => @name,
- "full_name" => @full_name
+ "full_name" => @full_name,
}
result["private_key"] = @private_key if @private_key
result["guid"] = @guid if @guid
@@ -73,50 +73,48 @@ class Chef
end
def create
- payload = {:name => self.name, :full_name => self.full_name}
- new_org = chef_rest.post_rest("organizations", payload)
- Chef::Org.from_hash(self.to_hash.merge(new_org))
+ payload = { :name => name, :full_name => full_name }
+ new_org = chef_rest.post("organizations", payload)
+ Chef::Org.from_hash(to_hash.merge(new_org))
end
def update
- payload = {:name => self.name, :full_name => self.full_name}
- new_org = chef_rest.put_rest("organizations/#{name}", payload)
- Chef::Org.from_hash(self.to_hash.merge(new_org))
+ payload = { :name => name, :full_name => full_name }
+ new_org = chef_rest.put("organizations/#{name}", payload)
+ Chef::Org.from_hash(to_hash.merge(new_org))
end
def destroy
- chef_rest.delete_rest("organizations/#{@name}")
+ chef_rest.delete("organizations/#{@name}")
end
def save
- begin
- create
- rescue Net::HTTPServerException => e
- if e.response.code == "409"
- update
- else
- raise e
- end
+ create
+ rescue Net::HTTPServerException => e
+ if e.response.code == "409"
+ update
+ else
+ raise e
end
end
def associate_user(username)
- request_body = {:user => username}
- response = chef_rest.post_rest "organizations/#{@name}/association_requests", request_body
+ request_body = { :user => username }
+ response = chef_rest.post "organizations/#{@name}/association_requests", request_body
association_id = response["uri"].split("/").last
- chef_rest.put_rest "users/#{username}/association_requests/#{association_id}", { :response => 'accept' }
+ chef_rest.put "users/#{username}/association_requests/#{association_id}", { :response => "accept" }
end
def dissociate_user(username)
- chef_rest.delete_rest "organizations/#{name}/users/#{username}"
+ chef_rest.delete "organizations/#{name}/users/#{username}"
end
# Class methods
def self.from_hash(org_hash)
- org = Chef::Org.new(org_hash['name'])
- org.full_name org_hash['full_name']
- org.private_key org_hash['private_key'] if org_hash.key?('private_key')
- org.guid org_hash['guid'] if org_hash.key?('guid')
+ org = Chef::Org.new(org_hash["name"])
+ org.full_name org_hash["full_name"]
+ org.private_key org_hash["private_key"] if org_hash.key?("private_key")
+ org.guid org_hash["guid"] if org_hash.key?("guid")
org
end
@@ -124,17 +122,18 @@ class Chef
Chef::Org.from_hash(Chef::JSONCompat.from_json(json))
end
- class <<self
- alias_method :json_create, :from_json
+ def self.json_create(json)
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::Org#from_json or Chef::Org#load.")
+ Chef::Org.from_json(json)
end
def self.load(org_name)
- response = Chef::REST.new(Chef::Config[:chef_server_root]).get_rest("organizations/#{org_name}")
+ response = Chef::ServerAPI.new(Chef::Config[:chef_server_root]).get("organizations/#{org_name}")
Chef::Org.from_hash(response)
end
- def self.list(inflate=false)
- orgs = Chef::REST.new(Chef::Config[:chef_server_root]).get_rest('organizations')
+ def self.list(inflate = false)
+ orgs = Chef::ServerAPI.new(Chef::Config[:chef_server_root]).get("organizations")
if inflate
orgs.inject({}) do |org_map, (name, _url)|
org_map[name] = Chef::Org.load(name)
diff --git a/lib/chef/platform.rb b/lib/chef/platform.rb
index 841aa1b46c..165715267b 100644
--- a/lib/chef/platform.rb
+++ b/lib/chef/platform.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
#
# Order of these headers is important: query helpers is needed by many things
-require 'chef/platform/query_helpers'
-require 'chef/platform/provider_mapping'
+require "chef/platform/query_helpers"
+require "chef/platform/provider_mapping"
class Chef
class Platform
diff --git a/lib/chef/platform/priority_map.rb b/lib/chef/platform/priority_map.rb
index 0b050deb59..c36d00ea5c 100644
--- a/lib/chef/platform/priority_map.rb
+++ b/lib/chef/platform/priority_map.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser (<jkeiser@chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/node_map'
+require "chef/node_map"
class Chef
class Platform
diff --git a/lib/chef/platform/provider_handler_map.rb b/lib/chef/platform/provider_handler_map.rb
index 4549d7994e..4f87a36d1d 100644
--- a/lib/chef/platform/provider_handler_map.rb
+++ b/lib/chef/platform/provider_handler_map.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser (<jkeiser@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'singleton'
-require 'chef/platform/handler_map'
+require "singleton"
+require "chef/node_map"
class Chef
class Platform
# @api private
- class ProviderHandlerMap < Chef::Platform::HandlerMap
+ class ProviderHandlerMap < Chef::NodeMap
include Singleton
end
end
diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb
index 9b511f0237..55e831c343 100644
--- a/lib/chef/platform/provider_mapping.rb
+++ b/lib/chef/platform/provider_mapping.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/exceptions'
-require 'chef/mixin/params_validate'
-require 'chef/version_constraint/platform'
-require 'chef/provider'
+require "chef/log"
+require "chef/exceptions"
+require "chef/mixin/params_validate"
+require "chef/version_constraint/platform"
+require "chef/provider"
class Chef
class Platform
@@ -35,6 +35,7 @@ class Chef
include Chef::Mixin::ParamsValidate
def find(name, version)
+ Chef.deprecated(:chef_platform_methods, "#{self.name}.find is deprecated")
provider_map = platforms[:default].clone
name_sym = name
@@ -45,7 +46,7 @@ class Chef
end
if platforms.has_key?(name_sym)
- platform_versions = platforms[name_sym].select {|k, v| k != :default }
+ platform_versions = platforms[name_sym].select { |k, v| k != :default }
if platforms[name_sym].has_key?(:default)
provider_map.merge!(platforms[name_sym][:default])
end
@@ -53,7 +54,7 @@ class Chef
begin
version_constraint = Chef::VersionConstraint::Platform.new(platform_version)
if version_constraint.include?(version)
- Chef::Log.debug("Platform #{name.to_s} version #{version} found")
+ Chef::Log.debug("Platform #{name} version #{version} found")
provider_map.merge!(provider)
end
rescue Chef::Exceptions::InvalidPlatformVersion
@@ -86,10 +87,11 @@ class Chef
raise ArgumentError, "Cannot find a version for #{node}" unless version
- return platform, version
+ [platform, version]
end
- def provider_for_resource(resource, action=:nothing)
+ def provider_for_resource(resource, action = :nothing)
+ Chef.deprecated(:chef_platform_methods, "#{name}.provider_for_resource is deprecated")
node = resource.run_context && resource.run_context.node
raise ArgumentError, "Cannot find the provider for a resource with no run context set" unless node
provider = find_provider_for_node(node, resource).new(resource, resource.run_context)
@@ -98,15 +100,17 @@ class Chef
end
def provider_for_node(node, resource_type)
- raise NotImplementedError, "#{self.class.name} no longer supports #provider_for_node"
+ raise NotImplementedError, "#{name} no longer supports #provider_for_node"
end
def find_provider_for_node(node, resource_type)
+ Chef.deprecated(:chef_platform_methods, "#{name}.find_provider_for_node is deprecated")
platform, version = find_platform_and_version(node)
find_provider(platform, version, resource_type)
end
def set(args)
+ Chef.deprecated(:chef_platform_methods, "#{name}.set is deprecated")
validate(
args,
{
@@ -123,7 +127,7 @@ class Chef
},
:provider => {
:kind_of => [ String, Symbol, Class ],
- }
+ },
}
)
if args.has_key?(:platform)
@@ -133,14 +137,14 @@ class Chef
platforms[args[:platform]][args[:version]][args[:resource].to_sym] = args[:provider]
else
platforms[args[:platform]][args[:version]] = {
- args[:resource].to_sym => args[:provider]
+ args[:resource].to_sym => args[:provider],
}
end
else
platforms[args[:platform]] = {
args[:version] => {
- args[:resource].to_sym => args[:provider]
- }
+ args[:resource].to_sym => args[:provider],
+ },
}
end
else
@@ -155,8 +159,8 @@ class Chef
else
platforms[args[:platform]] = {
:default => {
- args[:resource].to_sym => args[:provider]
- }
+ args[:resource].to_sym => args[:provider],
+ },
}
end
end
@@ -165,16 +169,17 @@ class Chef
platforms[:default][args[:resource].to_sym] = args[:provider]
else
platforms[:default] = {
- args[:resource].to_sym => args[:provider]
+ args[:resource].to_sym => args[:provider],
}
end
end
end
def find_provider(platform, version, resource_type)
+ Chef.deprecated(:chef_platform_methods, "#{name}.find_provider is deprecated")
provider_klass = explicit_provider(platform, version, resource_type) ||
- platform_provider(platform, version, resource_type) ||
- resource_matching_provider(platform, version, resource_type)
+ platform_provider(platform, version, resource_type) ||
+ resource_matching_provider(platform, version, resource_type)
raise Chef::Exceptions::ProviderNotFound, "Cannot find a provider for #{resource_type} on #{platform} version #{version}" if provider_klass.nil?
@@ -183,31 +188,34 @@ class Chef
private
- def explicit_provider(platform, version, resource_type)
- resource_type.kind_of?(Chef::Resource) ? resource_type.provider : nil
- end
+ def explicit_provider(platform, version, resource_type)
+ resource_type.kind_of?(Chef::Resource) ? resource_type.provider : nil
+ end
- def platform_provider(platform, version, resource_type)
- pmap = Chef::Platform.find(platform, version)
- rtkey = resource_type.kind_of?(Chef::Resource) ? resource_type.resource_name.to_sym : resource_type
- pmap.has_key?(rtkey) ? pmap[rtkey] : nil
- end
+ def platform_provider(platform, version, resource_type)
+ pmap = Chef::Platform.find(platform, version)
+ rtkey = resource_type.kind_of?(Chef::Resource) ? resource_type.resource_name.to_sym : resource_type
+ pmap.has_key?(rtkey) ? pmap[rtkey] : nil
+ end
- include Chef::Mixin::ConvertToClassName
+ include Chef::Mixin::ConvertToClassName
- def resource_matching_provider(platform, version, resource_type)
- if resource_type.kind_of?(Chef::Resource)
- class_name = resource_type.class.name ? resource_type.class.name.split('::').last :
- convert_to_class_name(resource_type.resource_name.to_s)
+ def resource_matching_provider(platform, version, resource_type)
+ if resource_type.kind_of?(Chef::Resource)
+ class_name = if resource_type.class.name
+ resource_type.class.name.split("::").last
+ else
+ convert_to_class_name(resource_type.resource_name.to_s)
+ end
- if Chef::Provider.const_defined?(class_name)
- Chef::Log.warn("Class Chef::Provider::#{class_name} does not declare 'provides #{convert_to_snake_case(class_name).to_sym.inspect}'.")
- Chef::Log.warn("This will no longer work in Chef 13: you must use 'provides' to use the resource's DSL.")
- return Chef::Provider.const_get(class_name)
- end
+ if Chef::Provider.const_defined?(class_name, false)
+ Chef::Log.warn("Class Chef::Provider::#{class_name} does not declare 'provides #{convert_to_snake_case(class_name).to_sym.inspect}'.")
+ Chef::Log.warn("This will no longer work in Chef 13: you must use 'provides' to use the resource's DSL.")
+ return Chef::Provider.const_get(class_name, false)
end
- nil
end
+ nil
+ end
end
end
diff --git a/lib/chef/platform/provider_priority_map.rb b/lib/chef/platform/provider_priority_map.rb
index 5599c74c2d..0c8a728618 100644
--- a/lib/chef/platform/provider_priority_map.rb
+++ b/lib/chef/platform/provider_priority_map.rb
@@ -1,5 +1,5 @@
-require 'singleton'
-require 'chef/platform/priority_map'
+require "singleton"
+require "chef/platform/priority_map"
class Chef
class Platform
diff --git a/lib/chef/platform/query_helpers.rb b/lib/chef/platform/query_helpers.rb
index dfb99ed750..624dc05e9c 100644
--- a/lib/chef/platform/query_helpers.rb
+++ b/lib/chef/platform/query_helpers.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,18 +27,18 @@ class Chef
def windows_server_2003?
# WMI startup shouldn't be performed unless we're on Windows.
return false unless windows?
- require 'wmi-lite/wmi'
+ require "wmi-lite/wmi"
wmi = WmiLite::Wmi.new
- host = wmi.first_of('Win32_OperatingSystem')
- is_server_2003 = (host['version'] && host['version'].start_with?("5.2"))
+ host = wmi.first_of("Win32_OperatingSystem")
+ is_server_2003 = (host["version"] && host["version"].start_with?("5.2"))
is_server_2003
end
def windows_nano_server?
return false unless windows?
- require 'win32/registry'
+ require "win32/registry"
# This method may be called before ohai runs (e.g., it may be used to
# determine settings in config.rb). Chef::Win32::Registry.new uses
@@ -55,12 +55,12 @@ class Chef
# If accessing the registry key failed, then we're probably not on
# nano. Fail through.
end
- return nano == 1
+ nano == 1
end
def supports_msi?
return false unless windows?
- require 'win32/registry'
+ require "win32/registry"
key = "System\\CurrentControlSet\\Services\\msiserver"
access = ::Win32::Registry::KEY_QUERY_VALUE
@@ -85,18 +85,28 @@ class Chef
end
def supports_dsc_invoke_resource?(node)
- require 'rubygems'
supports_dsc?(node) &&
- Gem::Version.new(node[:languages][:powershell][:version]) >=
- Gem::Version.new("5.0.10018.0")
+ supported_powershell_version?(node, "5.0.10018.0")
+ end
+
+ def supports_refresh_mode_enabled?(node)
+ supported_powershell_version?(node, "5.0.10586.0")
end
def dsc_refresh_mode_disabled?(node)
- require 'chef/util/powershell/cmdlet'
+ require "chef/util/powershell/cmdlet"
cmdlet = Chef::Util::Powershell::Cmdlet.new(node, "Get-DscLocalConfigurationManager", :object)
metadata = cmdlet.run!.return_value
- metadata['RefreshMode'] == 'Disabled'
+ metadata["RefreshMode"] == "Disabled"
end
+
+ def supported_powershell_version?(node, version_string)
+ return false unless node[:languages] && node[:languages][:powershell]
+ require "rubygems"
+ Gem::Version.new(node[:languages][:powershell][:version]) >=
+ Gem::Version.new(version_string)
+ end
+
end
end
end
diff --git a/lib/chef/platform/rebooter.rb b/lib/chef/platform/rebooter.rb
index b78ac38f0c..6829b66539 100644
--- a/lib/chef/platform/rebooter.rb
+++ b/lib/chef/platform/rebooter.rb
@@ -1,6 +1,6 @@
#
-# Author:: Chris Doherty <cdoherty@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef, Inc.
+# Author:: Chris Doherty <cdoherty@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,10 @@
# limitations under the License.
#
-require 'chef/dsl/reboot_pending'
-require 'chef/log'
-require 'chef/platform'
+require "chef/dsl/reboot_pending"
+require "chef/log"
+require "chef/platform"
+require "chef/application/exit_code"
class Chef
class Platform
@@ -27,19 +28,31 @@ class Chef
class << self
+ include Chef::DSL::RebootPending
+
def reboot!(node)
reboot_info = node.run_context.reboot_info
cmd = if Chef::Platform.windows?
- # should this do /f as well? do we then need a minimum delay to let apps quit?
- "shutdown /r /t #{reboot_info[:delay_mins]*60} /c \"#{reboot_info[:reason]}\""
- else
- # probably Linux-only.
- "shutdown -r +#{reboot_info[:delay_mins]} \"#{reboot_info[:reason]}\""
+ # should this do /f as well? do we then need a minimum delay to let apps quit?
+ # Use explicit path to shutdown.exe, to protect against https://github.com/chef/chef/issues/5594
+ windows_shutdown_path = "#{ENV['SYSTEMROOT']}/System32/shutdown.exe"
+ "#{windows_shutdown_path} /r /t #{reboot_info[:delay_mins] * 60} /c \"#{reboot_info[:reason]}\""
+ else
+ # probably Linux-only.
+ "shutdown -r +#{reboot_info[:delay_mins]} \"#{reboot_info[:reason]}\""
+ end
+
+ msg = "Rebooting server at a recipe's request. Details: #{reboot_info.inspect}"
+ begin
+ Chef::Log.warn msg
+ shell_out!(cmd)
+ rescue Mixlib::ShellOut::ShellCommandFailed => e
+ raise Chef::Exceptions::RebootFailed.new(e.message)
end
- Chef::Log.warn "Rebooting server at a recipe's request. Details: #{reboot_info.inspect}"
- shell_out!(cmd)
+ raise Chef::Exceptions::Reboot.new(msg) if Chef::Application::ExitCode.enforce_rfc_062_exit_codes?
+ Chef::Application::ExitCode.notify_reboot_exit_code_deprecation
end
# this is a wrapper function so Chef::Client only needs a single line of code.
diff --git a/lib/chef/platform/resource_handler_map.rb b/lib/chef/platform/resource_handler_map.rb
index 27a7bb1342..0aab04212f 100644
--- a/lib/chef/platform/resource_handler_map.rb
+++ b/lib/chef/platform/resource_handler_map.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser (<jkeiser@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'singleton'
-require 'chef/platform/handler_map'
+require "singleton"
+require "chef/node_map"
class Chef
class Platform
# @api private
- class ResourceHandlerMap < Chef::Platform::HandlerMap
+ class ResourceHandlerMap < Chef::NodeMap
include Singleton
end
end
diff --git a/lib/chef/platform/resource_priority_map.rb b/lib/chef/platform/resource_priority_map.rb
index 5cc86fd2e7..1871dcd5c6 100644
--- a/lib/chef/platform/resource_priority_map.rb
+++ b/lib/chef/platform/resource_priority_map.rb
@@ -1,5 +1,5 @@
-require 'singleton'
-require 'chef/platform/priority_map'
+require "singleton"
+require "chef/platform/priority_map"
class Chef
class Platform
diff --git a/lib/chef/platform/service_helpers.rb b/lib/chef/platform/service_helpers.rb
index 8365141c6e..87b87d4c72 100644
--- a/lib/chef/platform/service_helpers.rb
+++ b/lib/chef/platform/service_helpers.rb
@@ -1,6 +1,6 @@
#
# Author:: Lamont Granquist (<lamont@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,12 @@
# limitations under the License.
#
-# XXX: mixing shellout into a mixin into classes has to be code smell
-require 'chef/mixin/shell_out'
-require 'chef/mixin/which'
-require 'chef/chef_class'
+require "chef/chef_class"
class Chef
class Platform
class ServiceHelpers
class << self
-
- include Chef::Mixin::ShellOut
- include Chef::Mixin::Which
-
# This helper is mostly used to sort out the mess of different
# linux mechanisms that can be used to start services. It does
# not necessarily need to linux-specific, but currently all our
@@ -53,23 +46,22 @@ class Chef
providers << :invokercd
end
+ if ::File.exist?(Chef.path_to("/sbin/initctl"))
+ providers << :upstart
+ end
+
if ::File.exist?(Chef.path_to("/sbin/insserv"))
providers << :insserv
end
- # debian >= 6.0 has /etc/init but does not have upstart
- if ::File.exist?(Chef.path_to("/etc/init")) && ::File.exist?(Chef.path_to("/sbin/start"))
- providers << :upstart
+ if systemd_is_init?
+ providers << :systemd
end
if ::File.exist?(Chef.path_to("/sbin/chkconfig"))
providers << :redhat
end
- if systemd_sanity_check?
- providers << :systemd
- end
-
providers
end
@@ -96,7 +88,7 @@ class Chef
configs << :usr_local_etc_rcd
end
- if systemd_sanity_check? && platform_has_systemd_unit?(service_name)
+ if has_systemd_service_unit?(service_name) || has_systemd_unit?(service_name)
configs << :systemd
end
@@ -105,34 +97,24 @@ class Chef
private
- def systemctl_path
- which("systemctl")
+ def systemd_is_init?
+ ::File.exist?(Chef.path_to("/proc/1/comm")) &&
+ ::File.open(Chef.path_to("/proc/1/comm")).gets.chomp == "systemd"
end
- def systemd_sanity_check?
- systemctl_path && File.exist?(Chef.path_to("/proc/1/comm")) && File.open(Chef.path_to("/proc/1/comm")).gets.chomp == "systemd"
- end
-
- def extract_systemd_services(command)
- output = shell_out!(command).stdout
- # first line finds e.g. "sshd.service"
- services = []
- output.each_line do |line|
- fields = line.split
- services << fields[0] if fields[1] == "loaded" || fields[1] == "not-found"
+ def has_systemd_service_unit?(svc_name)
+ %w{ /etc /usr/lib /lib /run }.any? do |load_path|
+ ::File.exist?(
+ Chef.path_to("#{load_path}/systemd/system/#{svc_name.gsub(/@.*$/, '@')}.service")
+ )
end
- # this splits off the suffix after the last dot to return "sshd"
- services += services.select {|s| s.match(/\.service$/) }.map { |s| s.sub(/(.*)\.service$/, '\1') }
- rescue Mixlib::ShellOut::ShellCommandFailed
- []
end
- def platform_has_systemd_unit?(service_name)
- services = extract_systemd_services("#{systemctl_path} --all") +
- extract_systemd_services("#{systemctl_path} list-unit-files")
- services.include?(service_name)
- rescue Mixlib::ShellOut::ShellCommandFailed
- false
+ def has_systemd_unit?(svc_name)
+ # TODO: stop supporting non-service units with service resource
+ %w{ /etc /usr/lib /lib /run }.any? do |load_path|
+ ::File.exist?(Chef.path_to("#{load_path}/systemd/system/#{svc_name}"))
+ end
end
end
end
diff --git a/lib/chef/policy_builder.rb b/lib/chef/policy_builder.rb
index 56415dbbd0..56533e9a60 100644
--- a/lib/chef/policy_builder.rb
+++ b/lib/chef/policy_builder.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright 2008-2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/policy_builder/expand_node_object'
-require 'chef/policy_builder/policyfile'
-require 'chef/policy_builder/dynamic'
+require "chef/policy_builder/expand_node_object"
+require "chef/policy_builder/policyfile"
+require "chef/policy_builder/dynamic"
class Chef
diff --git a/lib/chef/policy_builder/dynamic.rb b/lib/chef/policy_builder/dynamic.rb
index c9842ba532..5b6bc40f9e 100644
--- a/lib/chef/policy_builder/dynamic.rb
+++ b/lib/chef/policy_builder/dynamic.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,13 @@
# limitations under the License.
#
-require 'forwardable'
+require "forwardable"
-require 'chef/log'
-require 'chef/rest'
-require 'chef/run_context'
-require 'chef/config'
-require 'chef/node'
-require 'chef/exceptions'
+require "chef/log"
+require "chef/run_context"
+require "chef/config"
+require "chef/node"
+require "chef/exceptions"
class Chef
module PolicyBuilder
@@ -67,7 +66,7 @@ class Chef
Chef::Log.debug("Building node object for #{node_name}")
@node =
- if Chef::Config[:solo]
+ if Chef::Config[:solo_legacy_mode]
Chef::Node.build(node_name)
else
Chef::Node.find_or_create(node_name)
@@ -140,7 +139,7 @@ class Chef
#
# @return [PolicyBuilder::Policyfile, PolicyBuilder::ExpandNodeObject]
def implementation
- @implementation or raise Exceptions::InvalidPolicybuilderCall, "#load_node must be called before other policy builder methods"
+ @implementation || raise(Exceptions::InvalidPolicybuilderCall, "#load_node must be called before other policy builder methods")
end
# @api private
diff --git a/lib/chef/policy_builder/expand_node_object.rb b/lib/chef/policy_builder/expand_node_object.rb
index 2c6d644e42..d8f4f752de 100644
--- a/lib/chef/policy_builder/expand_node_object.rb
+++ b/lib/chef/policy_builder/expand_node_object.rb
@@ -1,9 +1,9 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright 2008-2014 Chef Software, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,12 +19,12 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/rest'
-require 'chef/run_context'
-require 'chef/config'
-require 'chef/node'
-require 'chef/chef_class'
+require "chef/log"
+require "chef/server_api"
+require "chef/run_context"
+require "chef/config"
+require "chef/node"
+require "chef/chef_class"
class Chef
module PolicyBuilder
@@ -68,17 +68,23 @@ class Chef
Chef.set_run_context(run_context)
end
- def setup_run_context(specific_recipes=nil)
- if Chef::Config[:solo]
+ def setup_run_context(specific_recipes = nil)
+ if Chef::Config[:solo_legacy_mode]
Chef::Cookbook::FileVendor.fetch_from_disk(Chef::Config[:cookbook_path])
cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path])
cl.load_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cl)
+ cookbook_collection.validate!
+ cookbook_collection.install_gems(events)
+
run_context = Chef::RunContext.new(node, cookbook_collection, @events)
else
Chef::Cookbook::FileVendor.fetch_from_remote(api_service)
cookbook_hash = sync_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cookbook_hash)
+ cookbook_collection.validate!
+ cookbook_collection.install_gems(events)
+
run_context = Chef::RunContext.new(node, cookbook_collection, @events)
end
@@ -106,13 +112,13 @@ class Chef
# to create a PolicyBuilder::Dynamc policy builder and allow it to select
# the proper implementation.
def load_node
- Chef.log_deprecation("ExpandNodeObject#load_node is deprecated. Please use Chef::PolicyBuilder::Dynamic instead of using ExpandNodeObject directly")
+ Chef.deprecated(:internal_api, "ExpandNodeObject#load_node is deprecated. Please use Chef::PolicyBuilder::Dynamic instead of using ExpandNodeObject directly")
events.node_load_start(node_name, config)
Chef::Log.debug("Building node object for #{node_name}")
@node =
- if Chef::Config[:solo]
+ if Chef::Config[:solo_legacy_mode]
Chef::Node.build(node_name)
else
Chef::Node.find_or_create(node_name)
@@ -161,11 +167,11 @@ class Chef
# Expands the node's run list. Stores the run_list_expansion object for later use.
def expand_run_list
- @run_list_expansion = if Chef::Config[:solo]
- node.expand!('disk')
- else
- node.expand!('server')
- end
+ @run_list_expansion = if Chef::Config[:solo_legacy_mode]
+ node.expand!("disk")
+ else
+ node.expand!("server")
+ end
# @run_list_expansion is a RunListExpansion.
#
@@ -196,7 +202,12 @@ class Chef
begin
events.cookbook_resolution_start(@expanded_run_list_with_versions)
cookbook_hash = api_service.post("environments/#{node.chef_environment}/cookbook_versions",
- {:run_list => @expanded_run_list_with_versions})
+ { :run_list => @expanded_run_list_with_versions })
+
+ cookbook_hash = cookbook_hash.inject({}) do |memo, (key, value)|
+ memo[key] = Chef::CookbookVersion.from_hash(value)
+ memo
+ end
rescue Exception => e
# TODO: wrap/munge exception to provide helpful error output
events.cookbook_resolution_failed(@expanded_run_list_with_versions, e)
@@ -230,7 +241,7 @@ class Chef
def setup_run_list_override
runlist_override_sanity_check!
- unless(override_runlist.empty?)
+ unless override_runlist.empty?
node.override_runlist(*override_runlist)
Chef::Log.warn "Run List override has been provided."
Chef::Log.warn "Original Run List: [#{node.primary_runlist}]"
@@ -242,11 +253,11 @@ class Chef
def runlist_override_sanity_check!
# Convert to array and remove whitespace
if override_runlist.is_a?(String)
- @override_runlist = override_runlist.split(',').map { |e| e.strip }
+ @override_runlist = override_runlist.split(",").map { |e| e.strip }
end
@override_runlist = [override_runlist].flatten.compact
override_runlist.map! do |item|
- if(item.is_a?(Chef::RunList::RunListItem))
+ if item.is_a?(Chef::RunList::RunListItem)
item
else
Chef::RunList::RunListItem.new(item)
@@ -255,7 +266,7 @@ class Chef
end
def api_service
- @api_service ||= Chef::REST.new(config[:chef_server_url])
+ @api_service ||= Chef::ServerAPI.new(config[:chef_server_url])
end
def config
diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb
index d6dcdf67b2..f0009eac6c 100644
--- a/lib/chef/policy_builder/policyfile.rb
+++ b/lib/chef/policy_builder/policyfile.rb
@@ -1,9 +1,9 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright 2008-2014 Chef Software, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,11 +19,11 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/rest'
-require 'chef/run_context'
-require 'chef/config'
-require 'chef/node'
+require "chef/log"
+require "chef/run_context"
+require "chef/config"
+require "chef/node"
+require "chef/server_api"
class Chef
module PolicyBuilder
@@ -68,7 +68,7 @@ class Chef
@node = nil
- if Chef::Config[:solo]
+ if Chef::Config[:solo_legacy_mode]
raise UnsupportedFeature, "Policyfile does not support chef-solo. Use chef-client local mode instead."
end
@@ -136,7 +136,6 @@ class Chef
Chef::Log.info("Run List is [#{run_list}]")
Chef::Log.info("Run List expands to [#{run_list_with_versions_for_display.join(', ')}]")
-
events.node_load_completed(node, run_list_with_versions_for_display, Chef::Config)
node
@@ -149,10 +148,13 @@ class Chef
# run.
#
# @return [Chef::RunContext]
- def setup_run_context(specific_recipes=nil)
+ def setup_run_context(specific_recipes = nil)
Chef::Cookbook::FileVendor.fetch_from_remote(http_api)
sync_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cookbooks_to_sync)
+ cookbook_collection.validate!
+ cookbook_collection.install_gems(events)
+
run_context = Chef::RunContext.new(node, cookbook_collection, events)
setup_chef_class(run_context)
@@ -171,6 +173,7 @@ class Chef
CookbookCacheCleaner.instance.skip_removal = true if named_run_list_requested?
node.run_list(run_list)
+ node.automatic_attrs[:policy_revision] = revision_id
node.automatic_attrs[:roles] = []
node.automatic_attrs[:recipes] = run_list_expansion_ish.recipes
run_list_expansion_ish
@@ -254,10 +257,9 @@ class Chef
# @api private
def run_list
if named_run_list_requested?
- named_run_list or
- raise ConfigurationError,
+ named_run_list || raise(ConfigurationError,
"Policy '#{retrieved_policy_name}' revision '#{revision_id}' does not have named_run_list '#{named_run_list_name}'" +
- "(available named_run_lists: [#{available_named_run_lists.join(', ')}])"
+ "(available named_run_lists: [#{available_named_run_lists.join(', ')}])")
else
policy["run_list"]
end
@@ -319,17 +321,14 @@ class Chef
# @api private
def deployment_group
- Chef::Config[:deployment_group] or
- raise ConfigurationError, "Setting `deployment_group` is not configured."
+ Chef::Config[:deployment_group] || raise(ConfigurationError, "Setting `deployment_group` is not configured.")
end
# @api private
def validate_policy_config!
- policy_group or
- raise ConfigurationError, "Setting `policy_group` is not configured."
+ raise ConfigurationError, "Setting `policy_group` is not configured." unless policy_group
- policy_name or
- raise ConfigurationError, "Setting `policy_name` is not configured."
+ raise ConfigurationError, "Setting `policy_name` is not configured." unless policy_name
end
# @api private
@@ -454,7 +453,7 @@ class Chef
# @api private
def http_api
- @api_service ||= Chef::REST.new(config[:chef_server_url])
+ @api_service ||= Chef::ServerAPI.new(config[:chef_server_url])
end
# @api private
@@ -497,7 +496,7 @@ class Chef
def compat_mode_manifest_for(cookbook_name, lock_data)
xyz_version = lock_data["dotted_decimal_identifier"]
rel_url = "cookbooks/#{cookbook_name}/#{xyz_version}"
- http_api.get(rel_url)
+ inflate_cbv_object(http_api.get(rel_url))
rescue Exception => e
message = "Error loading cookbook #{cookbook_name} at version #{xyz_version} from #{rel_url}: #{e.class} - #{e.message}"
err = Chef::Exceptions::CookbookNotFound.new(message)
diff --git a/lib/chef/property.rb b/lib/chef/property.rb
index e97d8f9607..8fa290251a 100644
--- a/lib/chef/property.rb
+++ b/lib/chef/property.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser <jkeiser@chef.io>
-# Copyright:: Copyright (c) 2015 John Keiser.
+# Copyright:: Copyright 2015-2016, John Keiser.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,10 @@
# limitations under the License.
#
-require 'chef/exceptions'
-require 'chef/delayed_evaluator'
+require "chef/exceptions"
+require "chef/delayed_evaluator"
+require "chef/chef_class"
+require "chef/log"
class Chef
#
@@ -70,6 +72,9 @@ class Chef
# property defaults to the same value as `name`. Equivalent to
# `default: lazy { name }`, except that #property_is_set? will
# return `true` if the property is set *or* if `name` is set.
+ # @option options [Boolean] :nillable `true` opt-in to Chef-13 style behavior where
+ # attempting to set a nil value will really set a nil value instead of issuing
+ # a warning and operating like a getter
# @option options [Object] :default The value this property
# will return if the user does not set one. If this is `lazy`, it will
# be run in the context of the instance (and able to access other
@@ -85,16 +90,20 @@ class Chef
# is fully initialized.
#
def initialize(**options)
- options.each { |k,v| options[k.to_sym] = v if k.is_a?(String) }
+ options = options.inject({}) { |memo, (key, value)| memo[key.to_sym] = value; memo }
+ @options = options
+ options[:name] = options[:name].to_sym if options[:name]
+ options[:instance_variable_name] = options[:instance_variable_name].to_sym if options[:instance_variable_name]
# Replace name_attribute with name_property
if options.has_key?(:name_attribute)
# If we have both name_attribute and name_property and they differ, raise an error
if options.has_key?(:name_property)
- raise ArgumentError, "Cannot specify both name_property and name_attribute together on property #{options[:name]}#{options[:declared_in] ? " of resource #{options[:declared_in].resource_name}" : ""}."
+ raise ArgumentError, "Cannot specify both name_property and name_attribute together on property #{self}."
end
# replace name_property with name_attribute in place
- options = Hash[options.map { |k,v| k == :name_attribute ? [ :name_property, v ] : [ k,v ] }]
+ options = Hash[options.map { |k, v| k == :name_attribute ? [ :name_property, v ] : [ k, v ] }]
+ @options = options
end
# Only pick the first of :default, :name_property and :name_attribute if
@@ -107,13 +116,22 @@ class Chef
options.delete(:name_property)
preferred_default = :default
end
- Chef.log_deprecation("Cannot specify both default and name_property together on property #{options[:name]}#{options[:declared_in] ? " of resource #{options[:declared_in].resource_name}" : ""}. Only one (#{preferred_default}) will be obeyed. In Chef 13, this will become an error.")
+ Chef.deprecated(:custom_resource, "Cannot specify both default and name_property together on property #{self}. Only one (#{preferred_default}) will be obeyed. In Chef 13, this will become an error. Please remove one or the other from the property.")
end
- @options = options
+ # Validate the default early, so the user gets a good error message, and
+ # cache it so we don't do it again if so
+ begin
+ # If we can validate it all the way to output, do it.
+ @stored_default = input_to_stored_value(nil, default, is_default: true)
+ rescue Chef::Exceptions::CannotValidateStaticallyError
+ # If the validation is not static (i.e. has procs), we will have to
+ # coerce and validate the default each time we run
+ end
+ end
- options[:name] = options[:name].to_sym if options[:name]
- options[:instance_variable_name] = options[:instance_variable_name].to_sym if options[:instance_variable_name]
+ def to_s
+ "#{name || "<property type>"}#{declared_in ? " of resource #{declared_in.resource_name}" : ""}"
end
#
@@ -212,14 +230,25 @@ class Chef
end
#
+ # Whether this property is sensitive or not.
+ #
+ # Defaults to false.
+ #
+ # @return [Boolean]
+ #
+ def sensitive?
+ options.fetch(:sensitive, false)
+ end
+
+ #
# Validation options. (See Chef::Mixin::ParamsValidate#validate.)
#
# @return [Hash<Symbol,Object>]
#
def validation_options
- @validation_options ||= options.reject { |k,v|
- [:declared_in,:name,:instance_variable_name,:desired_state,:identity,:default,:name_property,:coerce,:required].include?(k)
- }
+ @validation_options ||= options.reject do |k, v|
+ [:declared_in, :name, :instance_variable_name, :desired_state, :identity, :default, :name_property, :coerce, :required, :nillable, :sensitive].include?(k)
+ end
end
#
@@ -242,21 +271,36 @@ class Chef
# will be returned without running, validating or coercing. If it is a
# `get`, the non-lazy, coerced, validated value will always be returned.
#
- def call(resource, value=NOT_PASSED)
+ def call(resource, value = NOT_PASSED)
if value == NOT_PASSED
return get(resource)
end
- # myprop nil is sometimes a get (backcompat)
- if value.nil? && !explicitly_accepts_nil?(resource)
- # If you say "my_property nil" and the property explicitly accepts
- # nil values, we consider this a get.
- Chef.log_deprecation("#{name} nil currently does not overwrite the value of #{name}. This will change in Chef 13, and the value will be set to nil instead. Please change your code to explicitly accept nil using \"property :#{name}, [MyType, nil]\", or stop setting this value to nil.")
- return get(resource)
- end
+ if value.nil? && !nillable?
+ # In Chef 12, value(nil) does a *get* instead of a set, so we
+ # warn if the value would have been changed. In Chef 13, it will be
+ # equivalent to value = nil.
+ result = get(resource, nil_set: true)
+
+ # Warn about this becoming a set in Chef 13.
+ begin
+ input_to_stored_value(resource, value)
+ # If nil is valid, and it would change the value, warn that this will change to a set.
+ if !result.nil?
+ Chef.deprecated(:custom_resource, "An attempt was made to change #{name} from #{result.inspect} to nil by calling #{name}(nil). In Chef 12, this does a get rather than a set. In Chef 13, this will change to set the value to nil.")
+ end
+ rescue Chef::Exceptions::DeprecatedFeatureError
+ raise
+ rescue
+ # If nil is invalid, warn that this will become an error.
+ Chef.deprecated(:custom_resource, "nil is an invalid value for #{self}. In Chef 13, this warning will change to an error. Error: #{$!}")
+ end
- # Anything else (myprop value) is a set
- set(resource, value)
+ result
+ else
+ # Anything else, such as myprop(value) is a set
+ set(resource, value)
+ end
end
#
@@ -281,26 +325,49 @@ class Chef
# @raise Chef::Exceptions::ValidationFailed If the value is invalid for
# this property, or if the value is required and not set.
#
- def get(resource)
+ def get(resource, nil_set: false)
+ # If it's set, return it (and evaluate any lazy values)
if is_set?(resource)
value = get_value(resource)
- if value.is_a?(DelayedEvaluator)
- value = exec_in_resource(resource, value)
- value = coerce(resource, value)
- validate(resource, value)
- end
- value
+ value = stored_value_to_output(resource, value)
else
+ # We are getting the default value.
+
+ # If the user does something like this:
+ #
+ # ```
+ # class MyResource < Chef::Resource
+ # property :content
+ # action :create do
+ # file '/x.txt' do
+ # content content
+ # end
+ # end
+ # end
+ # ```
+ #
+ # It won't do what they expect. This checks whether you try to *read*
+ # `content` while we are compiling the resource.
+ if !nil_set &&
+ resource.respond_to?(:resource_initializing) &&
+ resource.resource_initializing &&
+ resource.respond_to?(:enclosing_provider) &&
+ resource.enclosing_provider &&
+ resource.enclosing_provider.new_resource &&
+ resource.enclosing_provider.new_resource.respond_to?(name)
+ Chef::Log.warn("#{Chef::Log.caller_location}: property #{name} is declared in both #{resource} and #{resource.enclosing_provider}. Use new_resource.#{name} instead. At #{Chef::Log.caller_location}")
+ end
+
if has_default?
- value = default
- if value.is_a?(DelayedEvaluator)
- value = exec_in_resource(resource, value)
+ # If we were able to cache the stored_default, grab it.
+ if defined?(@stored_default)
+ value = @stored_default
+ else
+ # Otherwise, we have to validate it now.
+ value = input_to_stored_value(resource, default, is_default: true)
end
-
- value = coerce(resource, value)
-
- # We don't validate defaults
+ value = stored_value_to_output(resource, value, is_default: true)
# If the value is mutable (non-frozen), we set it on the instance
# so that people can mutate it. (All constant default values are
@@ -333,11 +400,7 @@ class Chef
# this property.
#
def set(resource, value)
- unless value.is_a?(DelayedEvaluator)
- value = coerce(resource, value)
- validate(resource, value)
- end
- set_value(resource, value)
+ set_value(resource, input_to_stored_value(resource, value))
end
#
@@ -390,7 +453,10 @@ class Chef
#
def coerce(resource, value)
if options.has_key?(:coerce)
- value = exec_in_resource(resource, options[:coerce], value)
+ # If we have no default value, `nil` is never coerced or validated
+ unless !has_default? && value.nil?
+ value = exec_in_resource(resource, options[:coerce], value)
+ end
end
value
end
@@ -409,7 +475,15 @@ class Chef
# this property.
#
def validate(resource, value)
- resource.validate({ name => value }, { name => validation_options })
+ # If we have no default value, `nil` is never coerced or validated
+ unless value.nil? && !has_default?
+ if resource
+ resource.validate({ name => value }, { name => validation_options })
+ else
+ name = self.name || :property_type
+ Chef::Mixin::ParamsValidate.validate({ name => value }, { name => validation_options })
+ end
+ end
end
#
@@ -427,11 +501,11 @@ class Chef
# the original options.
options = self.options
if modified_options.has_key?(:name_property) ||
- modified_options.has_key?(:name_attribute) ||
- modified_options.has_key?(:default)
- options = options.reject { |k,v| k == :name_attribute || k == :name_property || k == :default }
+ modified_options.has_key?(:name_attribute) ||
+ modified_options.has_key?(:default)
+ options = options.reject { |k, v| k == :name_attribute || k == :name_property || k == :default }
end
- Property.new(options.merge(modified_options))
+ self.class.new(options.merge(modified_options))
end
#
@@ -444,28 +518,37 @@ class Chef
# be using the existing getter/setter to manipulate it instead.
return if !instance_variable_name
+ # We deprecate any attempt to create a property that already exists as a
+ # method in some Classes that we know would cause our users problems.
+ # For example, creating a `hash` property could cause issues when adding
+ # a Chef::Resource instance to an data structure that expects to be able
+ # to call the `#hash` method and get back an appropriate Fixnum.
+ emit_property_redefinition_deprecations
+
# We prefer this form because the property name won't show up in the
# stack trace if you use `define_method`.
- declared_in.class_eval <<-EOM, __FILE__, __LINE__+1
+ declared_in.class_eval <<-EOM, __FILE__, __LINE__ + 1
def #{name}(value=NOT_PASSED)
+ raise "Property `#{name}` of `\#{self}` was incorrectly passed a block. Possible property-resource collision. To call a resource named `#{name}` either rename the property or else use `declare_resource(:#{name}, ...)`" if block_given?
self.class.properties[#{name.inspect}].call(self, value)
end
def #{name}=(value)
+ raise "Property `#{name}` of `\#{self}` was incorrectly passed a block. Possible property-resource collision. To call a resource named `#{name}` either rename the property or else use `declare_resource(:#{name}, ...)`" if block_given?
self.class.properties[#{name.inspect}].set(self, value)
end
EOM
rescue SyntaxError
# If the name is not a valid ruby name, we use define_method.
- declared_in.define_method(name) do |value=NOT_PASSED|
+ declared_in.define_method(name) do |value = NOT_PASSED, &block|
+ raise "Property `#{name}` of `#{self}` was incorrectly passed a block! Possible property-resource collision. To call a resource named `#{name}` either rename the property or else use `declare_resource(:#{name}, ...)`" if block
self.class.properties[name].call(self, value)
end
- declared_in.define_method("#{name}=") do |value|
+ declared_in.define_method("#{name}=") do |value, &block|
+ raise "Property `#{name}` of `#{self}` was incorrectly passed a block! Possible property-resource collision. To call a resource named `#{name}` either rename the property or else use `declare_resource(:#{name}, ...)`" if block
self.class.properties[name].set(self, value)
end
end
- protected
-
#
# The options this Property will use for get/set behavior and validation.
#
@@ -513,9 +596,10 @@ class Chef
# @api private
def explicitly_accepts_nil?(resource)
options.has_key?(:coerce) ||
- (options.has_key?(:is) && resource.send(:_pv_is, { name => nil }, name, options[:is], raise_error: false))
+ (options.has_key?(:is) && resource.send(:_pv_is, { name => nil }, name, options[:is], raise_error: false))
end
+ # @api private
def get_value(resource)
if instance_variable_name
resource.instance_variable_get(instance_variable_name)
@@ -524,6 +608,7 @@ class Chef
end
end
+ # @api private
def set_value(resource, value)
if instance_variable_name
resource.instance_variable_set(instance_variable_name, value)
@@ -532,6 +617,7 @@ class Chef
end
end
+ # @api private
def value_is_set?(resource)
if instance_variable_name
resource.instance_variable_defined?(instance_variable_name)
@@ -540,6 +626,7 @@ class Chef
end
end
+ # @api private
def reset_value(resource)
if instance_variable_name
if value_is_set?(resource)
@@ -550,6 +637,32 @@ class Chef
end
end
+ private
+
+ def emit_property_redefinition_deprecations
+ # We only emit deprecations if this property already exists as an instance method.
+ # Weeding out class methods avoids unnecessary deprecations such Chef::Resource
+ # defining a `name` property when there's an already-existing `name` method
+ # for a Module.
+ return unless declared_in.instance_methods.include?(name)
+
+ # Only emit deprecations for some well-known classes. This will still
+ # allow more advanced users to subclass their own custom resources and
+ # override their own properties.
+ return unless [ Object, BasicObject, Kernel, Chef::Resource ].include?(declared_in.instance_method(name).owner)
+
+ # Allow top-level Chef::Resource proprties, such as `name`, to be overridden.
+ # As of this writing, `name` is the only Chef::Resource property created with the
+ # `property` definition, but this will allow for future properties to be extended
+ # as needed.
+ return if Chef::Resource.properties.keys.include?(name)
+
+ # Emit the deprecation.
+ resource_name = declared_in.respond_to?(:resource_name) ? declared_in.resource_name : declared_in
+ Chef.deprecated(:property_name_collision, "Property `#{name}` of resource `#{resource_name}` overwrites an existing method. " \
+ "Please use a different property name. This will raise an exception in Chef 13.")
+ end
+
def exec_in_resource(resource, proc, *args)
if resource
if proc.arity > args.size
@@ -558,14 +671,57 @@ class Chef
value = resource.instance_exec(*args, &proc)
end
else
- value = proc.call
+ # If we don't have a resource yet, we can't exec in resource!
+ raise Chef::Exceptions::CannotValidateStaticallyError, "Cannot validate or coerce without a resource"
+ end
+ end
+
+ def input_to_stored_value(resource, value, is_default: false)
+ unless value.is_a?(DelayedEvaluator)
+ value = coerce_and_validate(resource, value, is_default: is_default)
end
+ value
+ end
+ def stored_value_to_output(resource, value, is_default: false)
+ # Crack open lazy values before giving the result to the user
if value.is_a?(DelayedEvaluator)
- value = coerce(resource, value)
- validate(resource, value)
+ value = exec_in_resource(resource, value)
+ value = coerce_and_validate(resource, value, is_default: is_default)
end
value
end
+
+ # Coerces and validates the value. If the value is a default, it will warn
+ # the user that invalid defaults are bad mmkay, and return it as if it were
+ # valid.
+ def coerce_and_validate(resource, value, is_default: false)
+ result = coerce(resource, value)
+ begin
+ # If the input is from a default, we need to emit an invalid default warning on validate.
+ validate(resource, result)
+ rescue Chef::Exceptions::CannotValidateStaticallyError
+ # This one gets re-raised
+ raise
+ rescue
+ # Anything else is just an invalid default: in those cases, we just
+ # warn and return the (possibly coerced) value to the user.
+ if is_default
+ if value.nil?
+ Chef.deprecated(:custom_resource, "Default value nil is invalid for property #{self}. Possible fixes: 1. Remove 'default: nil' if nil means 'undefined'. 2. Set a valid default value if there is a reasonable one. 3. Allow nil as a valid value of your property (for example, 'property #{name.inspect}, [ String, nil ], default: nil'). Error: #{$!}")
+ else
+ Chef.deprecated(:custom_resource, "Default value #{value.inspect} is invalid for property #{self}. In Chef 13 this will become an error: #{$!}.")
+ end
+ else
+ raise
+ end
+ end
+
+ result
+ end
+
+ def nillable?
+ !!options[:nillable]
+ end
end
end
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index e22f11d9be..40c31e4371 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016, 2009-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,31 +17,21 @@
# limitations under the License.
#
-require 'chef/mixin/from_file'
-require 'chef/mixin/convert_to_class_name'
-require 'chef/mixin/enforce_ownership_and_permissions'
-require 'chef/mixin/why_run'
-require 'chef/mixin/shell_out'
-require 'chef/mixin/powershell_out'
-require 'chef/mixin/provides'
-require 'chef/platform/service_helpers'
-require 'chef/node_map'
-require 'forwardable'
+require "chef/mixin/from_file"
+require "chef/mixin/convert_to_class_name"
+require "chef/mixin/enforce_ownership_and_permissions"
+require "chef/mixin/why_run"
+require "chef/mixin/shell_out"
+require "chef/mixin/provides"
+require "chef/dsl/core"
+require "chef/platform/service_helpers"
+require "chef/node_map"
+require "forwardable"
class Chef
class Provider
- require 'chef/mixin/why_run'
- require 'chef/mixin/shell_out'
- require 'chef/mixin/provides'
- include Chef::Mixin::WhyRun
- include Chef::Mixin::ShellOut
- include Chef::Mixin::PowershellOut
- extend Chef::Mixin::Provides
-
- # supports the given resource and action (late binding)
- def self.supports?(resource, action)
- true
- end
+ require "chef/mixin/why_run"
+ require "chef/mixin/provides"
attr_accessor :new_resource
attr_accessor :current_resource
@@ -50,6 +40,17 @@ class Chef
attr_reader :recipe_name
attr_reader :cookbook_name
+ include Chef::Mixin::WhyRun
+ extend Chef::Mixin::Provides
+
+ # includes the "core" DSL and not the "recipe" DSL by design
+ include Chef::DSL::Core
+
+ # supports the given resource and action (late binding)
+ def self.supports?(resource, action)
+ true
+ end
+
#--
# TODO: this should be a reader, and the action should be passed in the
# constructor; however, many/most subclasses override the constructor so
@@ -94,7 +95,7 @@ class Chef
end
def load_current_resource
- raise Chef::Exceptions::Override, "You must override load_current_resource in #{self.to_s}"
+ raise Chef::Exceptions::Override, "You must override load_current_resource in #{self}"
end
def define_resource_requirements
@@ -104,7 +105,7 @@ class Chef
end
def action_nothing
- Chef::Log.debug("Doing nothing for #{@new_resource.to_s}")
+ Chef::Log.debug("Doing nothing for #{@new_resource}")
true
end
@@ -112,7 +113,7 @@ class Chef
run_context.events
end
- def run_action(action=nil)
+ def run_action(action = nil)
@action = action unless action.nil?
# TODO: it would be preferable to get the action to be executed in the
@@ -204,26 +205,39 @@ class Chef
specified_properties = properties.select { |property| new_resource.property_is_set?(property) }
modified = specified_properties.select { |p| new_resource.send(p) != current_resource.send(p) }
if modified.empty?
- Chef::Log.debug("Skipping update of #{new_resource.to_s}: has not changed any of the specified properties #{specified_properties.map { |p| "#{p}=#{new_resource.send(p).inspect}" }.join(", ")}.")
+ properties_str = if new_resource.sensitive
+ specified_properties.join(", ")
+ else
+ specified_properties.map { |p| "#{p}=#{new_resource.send(p).inspect}" }.join(", ")
+ end
+ Chef::Log.debug("Skipping update of #{new_resource}: has not changed any of the specified properties #{properties_str}.")
return false
end
# Print the pretty green text and run the block
property_size = modified.map { |p| p.size }.max
- modified = modified.map { |p| " set #{p.to_s.ljust(property_size)} to #{new_resource.send(p).inspect} (was #{current_resource.send(p).inspect})" }
+ modified.map! do |p|
+ properties_str = if new_resource.sensitive
+ "(suppressed sensitive property)"
+ else
+ "#{new_resource.send(p).inspect} (was #{current_resource.send(p).inspect})"
+ end
+ " set #{p.to_s.ljust(property_size)} to #{properties_str}"
+ end
converge_by([ "update #{current_resource.identity}" ] + modified, &converge_block)
else
# The resource doesn't exist. Mark that we are *creating* this, and
# write down any properties we are setting.
property_size = properties.map { |p| p.size }.max
- created = []
- properties.each do |property|
- if new_resource.property_is_set?(property)
- created << " set #{property.to_s.ljust(property_size)} to #{new_resource.send(property).inspect}"
- else
- created << " set #{property.to_s.ljust(property_size)} to #{new_resource.send(property).inspect} (default value)"
- end
+ created = properties.map do |property|
+ default = " (default value)" unless new_resource.property_is_set?(property)
+ properties_str = if new_resource.sensitive
+ "(suppressed sensitive property)"
+ else
+ new_resource.send(property).inspect
+ end
+ " set #{property.to_s.ljust(property_size)} to #{properties_str}#{default}"
end
converge_by([ "create #{new_resource.identity}" ] + created, &converge_block)
@@ -231,7 +245,7 @@ class Chef
true
end
- def self.provides(short_name, opts={}, &block)
+ def self.provides(short_name, opts = {}, &block)
Chef.provider_handler_map.set(short_name, self, opts, &block)
end
@@ -286,10 +300,10 @@ class Chef
EOM
end
dsl_methods =
- resource.class.public_instance_methods +
- resource.class.protected_instance_methods -
- provider_class.instance_methods -
- resource.class.properties.keys
+ resource.class.public_instance_methods +
+ resource.class.protected_instance_methods -
+ provider_class.instance_methods -
+ resource.class.properties.keys
def_delegators(:new_resource, *dsl_methods)
end
include @included_resource_dsl_module
@@ -338,10 +352,20 @@ class Chef
# @api private
module InlineResources
- # Our run context is a child of the main run context; that gives us a
- # whole new resource collection and notification set.
- def initialize(resource, run_context)
- super(resource, run_context.create_child)
+ # Create a child run_context, compile the block, and converge it.
+ #
+ # @api private
+ def compile_and_converge_action(&block)
+ old_run_context = run_context
+ @run_context = run_context.create_child
+ return_value = instance_eval(&block)
+ Chef::Runner.new(run_context).converge
+ return_value
+ ensure
+ if run_context.resource_collection.any? { |r| r.updated? }
+ new_resource.updated_by_last_action(true)
+ end
+ @run_context = old_run_context
end
# Class methods for InlineResources. Overrides the `action` DSL method
@@ -353,41 +377,20 @@ class Chef
# compile the resources, converging them, and then checking if any
# were updated (and updating new-resource if so)
def action(name, &block)
- # We first try to create the method using "def method_name", which is
- # preferred because it actually shows up in stack traces. If that
- # fails, we try define_method.
+ # We need the block directly in a method so that `super` works
+ define_method("compile_action_#{name}", &block)
+ # We try hard to use `def` because define_method doesn't show the method name in the stack.
begin
- class_eval <<-EOM, __FILE__, __LINE__+1
+ class_eval <<-EOM
def action_#{name}
- return_value = compile_action_#{name}
- Chef::Runner.new(run_context).converge
- return_value
- ensure
- if run_context.resource_collection.any? {|r| r.updated? }
- new_resource.updated_by_last_action(true)
- end
+ compile_and_converge_action { compile_action_#{name} }
end
EOM
rescue SyntaxError
- define_method("action_#{name}") do
- begin
- return_value = send("compile_action_#{name}")
- Chef::Runner.new(run_context).converge
- return_value
- ensure
- if run_context.resource_collection.any? {|r| r.updated? }
- new_resource.updated_by_last_action(true)
- end
- end
- end
+ define_method("action_#{name}") { send("compile_action_#{name}") }
end
- # We put the action in its own method so that super() works.
- define_method("compile_action_#{name}", &block)
end
end
-
- require 'chef/dsl/recipe'
- include Chef::DSL::Recipe::FullDSL
end
protected
@@ -420,9 +423,9 @@ class Chef
module DeprecatedLWRPClass
def const_missing(class_name)
- if deprecated_constants[class_name.to_sym]
- Chef.log_deprecation("Using an LWRP provider by its name (#{class_name}) directly is no longer supported in Chef 12 and will be removed. Use Chef::ProviderResolver.new(node, resource, action) instead.")
- deprecated_constants[class_name.to_sym]
+ if Chef::Provider.deprecated_constants[class_name.to_sym]
+ Chef.deprecated(:custom_resource, "Using an LWRP provider by its name (#{class_name}) directly is no longer supported in Chef 12 and will be removed. Use Chef::ProviderResolver.new(node, resource, action) instead.")
+ Chef::Provider.deprecated_constants[class_name.to_sym]
else
raise NameError, "uninitialized constant Chef::Provider::#{class_name}"
end
@@ -435,13 +438,12 @@ class Chef
if Chef::Provider.const_defined?(class_name, false)
Chef::Log.warn "Chef::Provider::#{class_name} already exists! Cannot create deprecation class for #{provider_class}"
else
- deprecated_constants[class_name.to_sym] = provider_class
+ Chef::Provider.deprecated_constants[class_name.to_sym] = provider_class
end
end
- private
-
def deprecated_constants
+ raise "Deprecated constants should be called only on Chef::Provider" unless self == Chef::Provider
@deprecated_constants ||= {}
end
end
@@ -450,7 +452,7 @@ class Chef
end
# Requiring things at the bottom breaks cycles
-require 'chef/chef_class'
-require 'chef/mixin/why_run'
-require 'chef/resource_collection'
-require 'chef/runner'
+require "chef/chef_class"
+require "chef/mixin/why_run"
+require "chef/resource_collection"
+require "chef/runner"
diff --git a/lib/chef/provider/apt_repository.rb b/lib/chef/provider/apt_repository.rb
new file mode 100644
index 0000000000..9e91b12373
--- /dev/null
+++ b/lib/chef/provider/apt_repository.rb
@@ -0,0 +1,253 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource"
+require "chef/dsl/declare_resource"
+require "chef/mixin/shell_out"
+require "chef/mixin/which"
+require "chef/http/simple"
+require "chef/provider/noop"
+
+class Chef
+ class Provider
+ class AptRepository < Chef::Provider
+ use_inline_resources
+
+ include Chef::Mixin::ShellOut
+ extend Chef::Mixin::Which
+
+ provides :apt_repository do
+ which("apt-get")
+ end
+
+ def whyrun_supported?
+ true
+ end
+
+ def load_current_resource
+ end
+
+ action :add do
+ unless new_resource.key.nil?
+ if is_key_id?(new_resource.key) && !has_cookbook_file?(new_resource.key)
+ install_key_from_keyserver
+ else
+ install_key_from_uri
+ end
+ end
+
+ declare_resource(:execute, "apt-cache gencaches") do
+ ignore_failure true
+ action :nothing
+ end
+
+ declare_resource(:apt_update, new_resource.name) do
+ ignore_failure true
+ action :nothing
+ end
+
+ components = if is_ppa_url?(new_resource.uri) && new_resource.components.empty?
+ "main"
+ else
+ new_resource.components
+ end
+
+ repo = build_repo(
+ new_resource.uri,
+ new_resource.distribution,
+ components,
+ new_resource.trusted,
+ new_resource.arch,
+ new_resource.deb_src
+ )
+
+ declare_resource(:file, "/etc/apt/sources.list.d/#{new_resource.name}.list") do
+ owner "root"
+ group "root"
+ mode "0644"
+ content repo
+ sensitive new_resource.sensitive
+ action :create
+ notifies :run, "execute[apt-cache gencaches]", :immediately
+ notifies :update, "apt_update[#{new_resource.name}]", :immediately if new_resource.cache_rebuild
+ end
+ end
+
+ action :remove do
+ if ::File.exist?("/etc/apt/sources.list.d/#{new_resource.name}.list")
+ converge_by "Removing #{new_resource.name} repository from /etc/apt/sources.list.d/" do
+ declare_resource(:file, "/etc/apt/sources.list.d/#{new_resource.name}.list") do
+ sensitive new_resource.sensitive
+ action :delete
+ notifies :update, "apt_update[#{new_resource.name}]", :immediately if new_resource.cache_rebuild
+ end
+
+ declare_resource(:apt_update, new_resource.name) do
+ ignore_failure true
+ action :nothing
+ end
+
+ end
+ end
+ end
+
+ def is_key_id?(id)
+ id = id[2..-1] if id.start_with?("0x")
+ id =~ /^\h+$/ && [8, 16, 40].include?(id.length)
+ end
+
+ def extract_fingerprints_from_cmd(cmd)
+ so = shell_out(cmd)
+ so.run_command
+ so.stdout.split(/\n/).map do |t|
+ if z = t.match(/^ +Key fingerprint = ([0-9A-F ]+)/)
+ z[1].split.join
+ end
+ end.compact
+ end
+
+ def key_is_valid?(cmd, key)
+ valid = true
+
+ so = shell_out(cmd)
+ so.run_command
+ so.stdout.split(/\n/).map do |t|
+ if t =~ %r{^\/#{key}.*\[expired: .*\]$}
+ Chef::Log.debug "Found expired key: #{t}"
+ valid = false
+ break
+ end
+ end
+
+ Chef::Log.debug "key #{key} #{valid ? "is valid" : "is not valid"}"
+ valid
+ end
+
+ def cookbook_name
+ new_resource.cookbook || new_resource.cookbook_name
+ end
+
+ def has_cookbook_file?(fn)
+ run_context.has_cookbook_file_in_cookbook?(cookbook_name, fn)
+ end
+
+ def no_new_keys?(file)
+ installed_keys = extract_fingerprints_from_cmd("apt-key finger")
+ proposed_keys = extract_fingerprints_from_cmd("gpg --with-fingerprint #{file}")
+ (installed_keys & proposed_keys).sort == proposed_keys.sort
+ end
+
+ def install_key_from_uri
+ key_name = new_resource.key.gsub(/[^0-9A-Za-z\-]/, "_")
+ cached_keyfile = ::File.join(Chef::Config[:file_cache_path], key_name)
+ type = if new_resource.key.start_with?("http")
+ :remote_file
+ elsif has_cookbook_file?(new_resource.key)
+ :cookbook_file
+ else
+ raise Chef::Exceptions::FileNotFound, "Cannot locate key file"
+ end
+
+ declare_resource(type, cached_keyfile) do
+ source new_resource.key
+ mode "0644"
+ sensitive new_resource.sensitive
+ action :create
+ end
+
+ raise "The key #{cached_keyfile} is invalid and cannot be used to verify an apt repository." unless key_is_valid?("gpg #{cached_keyfile}", "")
+
+ declare_resource(:execute, "apt-key add #{cached_keyfile}") do
+ sensitive new_resource.sensitive
+ action :run
+ not_if do
+ no_new_keys?(cached_keyfile)
+ end
+ notifies :run, "execute[apt-cache gencaches]", :immediately
+ end
+ end
+
+ def install_key_from_keyserver(key = new_resource.key, keyserver = new_resource.keyserver)
+ cmd = "apt-key adv --recv"
+ cmd << " --keyserver-options http-proxy=#{new_resource.key_proxy}" if new_resource.key_proxy
+ cmd << " --keyserver "
+ cmd << if keyserver.start_with?("hkp://")
+ keyserver
+ else
+ "hkp://#{keyserver}:80"
+ end
+
+ cmd << " #{key}"
+
+ declare_resource(:execute, "install-key #{key}") do
+ command cmd
+ sensitive new_resource.sensitive
+ not_if do
+ present = extract_fingerprints_from_cmd("apt-key finger").any? do |fp|
+ fp.end_with? key.upcase
+ end
+ present && key_is_valid?("apt-key list", key.upcase)
+ end
+ notifies :run, "execute[apt-cache gencaches]", :immediately
+ end
+
+ raise "The key #{key} is invalid and cannot be used to verify an apt repository." unless key_is_valid?("apt-key list", key.upcase)
+ end
+
+ def install_ppa_key(owner, repo)
+ url = "https://launchpad.net/api/1.0/~#{owner}/+archive/#{repo}"
+ key_id = Chef::HTTP::Simple.new(url).get("signing_key_fingerprint").delete('"')
+ install_key_from_keyserver(key_id, "keyserver.ubuntu.com")
+ rescue Net::HTTPServerException => e
+ raise "Could not access Launchpad ppa API: #{e.message}"
+ end
+
+ def is_ppa_url?(url)
+ url.start_with?("ppa:")
+ end
+
+ def make_ppa_url(ppa)
+ return unless is_ppa_url?(ppa)
+ owner, repo = ppa[4..-1].split("/")
+ repo ||= "ppa"
+
+ install_ppa_key(owner, repo)
+ "http://ppa.launchpad.net/#{owner}/#{repo}/ubuntu"
+ end
+
+ def build_repo(uri, distribution, components, trusted, arch, add_src = false)
+ uri = make_ppa_url(uri) if is_ppa_url?(uri)
+
+ uri = '"' + uri + '"' unless uri.start_with?("'", '"')
+ components = Array(components).join(" ")
+ options = []
+ options << "arch=#{arch}" if arch
+ options << "trusted=yes" if trusted
+ optstr = unless options.empty?
+ "[" + options.join(" ") + "]"
+ end
+ info = [ optstr, uri, distribution, components ].compact.join(" ")
+ repo = "deb #{info}\n"
+ repo << "deb-src #{info}\n" if add_src
+ repo
+ end
+ end
+ end
+end
+
+Chef::Provider::Noop.provides :apt_repository
diff --git a/lib/chef/provider/apt_update.rb b/lib/chef/provider/apt_update.rb
new file mode 100644
index 0000000000..baa763df9d
--- /dev/null
+++ b/lib/chef/provider/apt_update.rb
@@ -0,0 +1,87 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/provider"
+require "chef/provider/noop"
+require "chef/mixin/which"
+
+class Chef
+ class Provider
+ class AptUpdate < Chef::Provider
+ use_inline_resources
+
+ extend Chef::Mixin::Which
+
+ provides :apt_update do
+ which("apt-get")
+ end
+
+ APT_CONF_DIR = "/etc/apt/apt.conf.d"
+ STAMP_DIR = "/var/lib/apt/periodic"
+
+ def whyrun_supported?
+ true
+ end
+
+ def load_current_resource
+ end
+
+ action :periodic do
+ if !apt_up_to_date?
+ converge_by "update new lists of packages" do
+ do_update
+ end
+ end
+ end
+
+ action :update do
+ converge_by "force update new lists of packages" do
+ do_update
+ end
+ end
+
+ private
+
+ # Determines whether we need to run `apt-get update`
+ #
+ # @return [Boolean]
+ def apt_up_to_date?
+ ::File.exist?("#{STAMP_DIR}/update-success-stamp") &&
+ ::File.mtime("#{STAMP_DIR}/update-success-stamp") > Time.now - new_resource.frequency
+ end
+
+ def do_update
+ [STAMP_DIR, APT_CONF_DIR].each do |d|
+ declare_resource(:directory, d) do
+ recursive true
+ end
+ end
+
+ declare_resource(:file, "#{APT_CONF_DIR}/15update-stamp") do
+ content "APT::Update::Post-Invoke-Success {\"touch #{STAMP_DIR}/update-success-stamp 2>/dev/null || true\";};\n"
+ action :create_if_missing
+ end
+
+ declare_resource(:execute, "apt-get -q update")
+ end
+
+ end
+ end
+end
+
+Chef::Provider::Noop.provides :apt_update
diff --git a/lib/chef/provider/batch.rb b/lib/chef/provider/batch.rb
index 5f0134443d..83218e4f76 100644
--- a/lib/chef/provider/batch.rb
+++ b/lib/chef/provider/batch.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/provider/windows_script'
+require "chef/provider/windows_script"
class Chef
class Provider
@@ -24,12 +24,12 @@ class Chef
provides :batch, os: "windows"
- def initialize (new_resource, run_context)
- super(new_resource, run_context, '.bat')
+ def initialize(new_resource, run_context)
+ super(new_resource, run_context, ".bat")
end
def command
- basepath = is_forced_32bit ? wow64_directory : run_context.node.kernel.os_info.system_directory
+ basepath = is_forced_32bit ? wow64_directory : run_context.node["kernel"]["os_info"]["system_directory"]
interpreter_path = Chef::Util::PathHelper.join(basepath, interpreter)
@@ -37,7 +37,7 @@ class Chef
end
def flags
- @new_resource.flags.nil? ? '/c' : new_resource.flags + ' /c'
+ new_resource.flags.nil? ? "/c" : new_resource.flags + " /c"
end
end
diff --git a/lib/chef/provider/breakpoint.rb b/lib/chef/provider/breakpoint.rb
index 663d558f66..0902634a64 100644
--- a/lib/chef/provider/breakpoint.rb
+++ b/lib/chef/provider/breakpoint.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,7 +28,7 @@ class Chef
def action_break
if defined?(Shell) && Shell.running?
run_context.resource_collection.iterator.pause
- @new_resource.updated_by_last_action(true)
+ new_resource.updated_by_last_action(true)
run_context.resource_collection.iterator
end
end
diff --git a/lib/chef/provider/cookbook_file.rb b/lib/chef/provider/cookbook_file.rb
index b501a9b41d..dc900d871b 100644
--- a/lib/chef/provider/cookbook_file.rb
+++ b/lib/chef/provider/cookbook_file.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/provider/file'
-require 'chef/deprecation/provider/cookbook_file'
-require 'chef/deprecation/warnings'
+require "chef/provider/file"
+require "chef/deprecation/provider/cookbook_file"
+require "chef/deprecation/warnings"
class Chef
class Provider
@@ -36,15 +36,15 @@ class Chef
end
def load_current_resource
- @current_resource = Chef::Resource::CookbookFile.new(@new_resource.name)
+ @current_resource = Chef::Resource::CookbookFile.new(new_resource.name)
super
end
private
def managing_content?
- return true if @new_resource.checksum
- return true if !@new_resource.source.nil? && @action != :create_if_missing
+ return true if new_resource.checksum
+ return true if !new_resource.source.nil? && @action != :create_if_missing
false
end
diff --git a/lib/chef/provider/cookbook_file/content.rb b/lib/chef/provider/cookbook_file/content.rb
index 9f49ba885c..1d24dee3e7 100644
--- a/lib/chef/provider/cookbook_file/content.rb
+++ b/lib/chef/provider/cookbook_file/content.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/file_content_management/content_base'
-require 'chef/file_content_management/tempfile'
+require "chef/file_content_management/content_base"
+require "chef/file_content_management/tempfile"
class Chef
class Provider
diff --git a/lib/chef/provider/cron.rb b/lib/chef/provider/cron.rb
index 6d86e336ec..f22367b461 100644
--- a/lib/chef/provider/cron.rb
+++ b/lib/chef/provider/cron.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/mixin/command'
-require 'chef/provider'
+require "chef/log"
+require "chef/mixin/command"
+require "chef/provider"
class Chef
class Provider
@@ -48,15 +48,15 @@ class Chef
def load_current_resource
crontab_lines = []
- @current_resource = Chef::Resource::Cron.new(@new_resource.name)
- @current_resource.user(@new_resource.user)
+ @current_resource = Chef::Resource::Cron.new(new_resource.name)
+ current_resource.user(new_resource.user)
@cron_exists = false
if crontab = read_crontab
cron_found = false
crontab.each_line do |line|
case line.chomp
- when "# Chef Name: #{@new_resource.name}"
- Chef::Log.debug("Found cron '#{@new_resource.name}'")
+ when "# Chef Name: #{new_resource.name}"
+ Chef::Log.debug("Found cron '#{new_resource.name}'")
cron_found = true
@cron_exists = true
next
@@ -65,38 +65,38 @@ class Chef
next
when SPECIAL_PATTERN
if cron_found
- @current_resource.time($2.to_sym)
- @current_resource.command($3)
- cron_found=false
+ current_resource.time($2.to_sym)
+ current_resource.command($3)
+ cron_found = false
end
when CRON_PATTERN
if cron_found
- @current_resource.minute($1)
- @current_resource.hour($2)
- @current_resource.day($3)
- @current_resource.month($4)
- @current_resource.weekday($5)
- @current_resource.command($6)
- cron_found=false
+ current_resource.minute($1)
+ current_resource.hour($2)
+ current_resource.day($3)
+ current_resource.month($4)
+ current_resource.weekday($5)
+ current_resource.command($6)
+ cron_found = false
end
next
else
- cron_found=false # We've got a Chef comment with no following crontab line
+ cron_found = false # We've got a Chef comment with no following crontab line
next
end
end
- Chef::Log.debug("Cron '#{@new_resource.name}' not found") unless @cron_exists
+ Chef::Log.debug("Cron '#{new_resource.name}' not found") unless @cron_exists
else
- Chef::Log.debug("Cron empty for '#{@new_resource.user}'")
+ Chef::Log.debug("Cron empty for '#{new_resource.user}'")
@cron_empty = true
end
- @current_resource
+ current_resource
end
def cron_different?
CRON_ATTRIBUTES.any? do |cron_var|
- @new_resource.send(cron_var) != @current_resource.send(cron_var)
+ new_resource.send(cron_var) != current_resource.send(cron_var)
end
end
@@ -109,12 +109,12 @@ class Chef
if @cron_exists
unless cron_different?
- Chef::Log.debug("Skipping existing cron entry '#{@new_resource.name}'")
+ Chef::Log.debug("Skipping existing cron entry '#{new_resource.name}'")
return
end
read_crontab.each_line do |line|
case line.chomp
- when "# Chef Name: #{@new_resource.name}"
+ when "# Chef Name: #{new_resource.name}"
cron_found = true
next
when ENV_PATTERN
@@ -144,18 +144,18 @@ class Chef
# Handle edge case where the Chef comment is the last line in the current crontab
crontab << newcron if cron_found
- converge_by("update crontab entry for #{@new_resource}") do
+ converge_by("update crontab entry for #{new_resource}") do
write_crontab crontab
- Chef::Log.info("#{@new_resource} updated crontab entry")
+ Chef::Log.info("#{new_resource} updated crontab entry")
end
else
crontab = read_crontab unless @cron_empty
crontab << newcron
- converge_by("add crontab entry for #{@new_resource}") do
+ converge_by("add crontab entry for #{new_resource}") do
write_crontab crontab
- Chef::Log.info("#{@new_resource} added crontab entry")
+ Chef::Log.info("#{new_resource} added crontab entry")
end
end
end
@@ -166,7 +166,7 @@ class Chef
cron_found = false
read_crontab.each_line do |line|
case line.chomp
- when "# Chef Name: #{@new_resource.name}"
+ when "# Chef Name: #{new_resource.name}"
cron_found = true
next
when ENV_PATTERN
@@ -187,11 +187,10 @@ class Chef
end
crontab << line
end
- description = cron_found ? "remove #{@new_resource.name} from crontab" :
- "save unmodified crontab"
+ description = cron_found ? "remove #{new_resource.name} from crontab" : "save unmodified crontab"
converge_by(description) do
write_crontab crontab
- Chef::Log.info("#{@new_resource} deleted crontab entry")
+ Chef::Log.info("#{new_resource} deleted crontab entry")
end
end
end
@@ -199,27 +198,27 @@ class Chef
private
def set_environment_var(attr_name, attr_value)
- if %w(MAILTO PATH SHELL HOME).include?(attr_name)
- @current_resource.send(attr_name.downcase.to_sym, attr_value)
+ if %w{MAILTO PATH SHELL HOME}.include?(attr_name)
+ current_resource.send(attr_name.downcase.to_sym, attr_value.gsub(/^"|"$/, ""))
else
- @current_resource.environment(@current_resource.environment.merge(attr_name => attr_value))
+ current_resource.environment(current_resource.environment.merge(attr_name => attr_value))
end
end
def read_crontab
crontab = nil
- status = popen4("crontab -l -u #{@new_resource.user}") do |pid, stdin, stdout, stderr|
+ status = popen4("crontab -l -u #{new_resource.user}") do |pid, stdin, stdout, stderr|
crontab = stdout.read
end
if status.exitstatus > 1
- raise Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: #{status.exitstatus}"
+ raise Chef::Exceptions::Cron, "Error determining state of #{new_resource.name}, exit: #{status.exitstatus}"
end
crontab
end
def write_crontab(crontab)
write_exception = false
- status = popen4("crontab -u #{@new_resource.user} -", :waitlast => true) do |pid, stdin, stdout, stderr|
+ status = popen4("crontab -u #{new_resource.user} -", :waitlast => true) do |pid, stdin, stdout, stderr|
begin
stdin.write crontab
rescue Errno::EPIPE => e
@@ -229,7 +228,7 @@ class Chef
end
end
if status.exitstatus > 0 || write_exception
- raise Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: #{status.exitstatus}"
+ raise Chef::Exceptions::Cron, "Error updating state of #{new_resource.name}, exit: #{status.exitstatus}"
end
end
@@ -237,23 +236,23 @@ class Chef
newcron = ""
newcron << "# Chef Name: #{new_resource.name}\n"
[ :mailto, :path, :shell, :home ].each do |v|
- newcron << "#{v.to_s.upcase}=#{@new_resource.send(v)}\n" if @new_resource.send(v)
+ newcron << "#{v.to_s.upcase}=\"#{new_resource.send(v)}\"\n" if new_resource.send(v)
end
- @new_resource.environment.each do |name, value|
+ new_resource.environment.each do |name, value|
newcron << "#{name}=#{value}\n"
end
- if @new_resource.time
- newcron << "@#{@new_resource.time} #{@new_resource.command}\n"
+ if new_resource.time
+ newcron << "@#{new_resource.time} #{new_resource.command}\n"
else
- newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n"
+ newcron << "#{new_resource.minute} #{new_resource.hour} #{new_resource.day} #{new_resource.month} #{new_resource.weekday} #{new_resource.command}\n"
end
newcron
end
def weekday_in_crontab
- weekday_in_crontab = WEEKDAY_SYMBOLS.index(@new_resource.weekday)
+ weekday_in_crontab = WEEKDAY_SYMBOLS.index(new_resource.weekday)
if weekday_in_crontab.nil?
- @new_resource.weekday
+ new_resource.weekday
else
weekday_in_crontab.to_s
end
diff --git a/lib/chef/provider/cron/aix.rb b/lib/chef/provider/cron/aix.rb
index 9cacbc6ec9..015c1f2096 100644
--- a/lib/chef/provider/cron/aix.rb
+++ b/lib/chef/provider/cron/aix.rb
@@ -1,6 +1,6 @@
#
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/cron/solaris.rb b/lib/chef/provider/cron/solaris.rb
index 20fa7abcce..58d6637674 100644
--- a/lib/chef/provider/cron/solaris.rb
+++ b/lib/chef/provider/cron/solaris.rb
@@ -1,6 +1,6 @@
#
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/cron/unix.rb b/lib/chef/provider/cron/unix.rb
index 01c61e4253..108e73c9d3 100644
--- a/lib/chef/provider/cron/unix.rb
+++ b/lib/chef/provider/cron/unix.rb
@@ -1,8 +1,8 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
# Author:: Toomas Pelberg (toomasp@gmx.net)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
-# Copyright:: Copyright (c) 2010 Toomas Pelberg
+# Copyright:: Copyright 2009-2016, Bryan McLellan
+# Copyright:: Copyright 2010-2016, Toomas Pelberg
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,9 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/provider'
-require 'chef/provider/cron'
+require "chef/log"
+require "chef/provider"
+require "chef/provider/cron"
class Chef
class Provider
@@ -28,12 +28,12 @@ class Chef
class Unix < Chef::Provider::Cron
include Chef::Mixin::ShellOut
- provides :cron, os: 'solaris2'
+ provides :cron, os: "solaris2"
private
def read_crontab
- crontab = shell_out('/usr/bin/crontab -l', :user => @new_resource.user)
+ crontab = shell_out("/usr/bin/crontab -l", :user => @new_resource.user)
status = crontab.status.exitstatus
Chef::Log.debug crontab.format_for_exception if status > 0
diff --git a/lib/chef/provider/deploy.rb b/lib/chef/provider/deploy.rb
index c59200e717..2cd6ad62c6 100644
--- a/lib/chef/provider/deploy.rb
+++ b/lib/chef/provider/deploy.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -42,7 +42,7 @@ class Chef
# @configuration is not used by Deploy, it is only for backwards compat with
# chef-deploy or capistrano hooks that might use it to get environment information
- @configuration = @new_resource.to_hash
+ @configuration = new_resource.to_hash
@configuration[:environment] = @configuration[:environment] && @configuration[:environment]["RAILS_ENV"]
end
@@ -52,20 +52,20 @@ class Chef
def load_current_resource
@scm_provider.load_current_resource
- @release_path = @new_resource.deploy_to + "/releases/#{release_slug}"
- @shared_path = @new_resource.shared_path
+ @release_path = new_resource.deploy_to + "/releases/#{release_slug}"
+ @shared_path = new_resource.shared_path
end
- def sudo(command,&block)
+ def sudo(command, &block)
execute(command, &block)
end
def run(command, &block)
exec = execute(command, &block)
- exec.user(@new_resource.user) if @new_resource.user
- exec.group(@new_resource.group) if @new_resource.group
+ exec.user(new_resource.user) if new_resource.user
+ exec.group(new_resource.group) if new_resource.group
exec.cwd(release_path) unless exec.cwd
- exec.environment(@new_resource.environment) unless exec.environment
+ exec.environment(new_resource.environment) unless exec.environment
converge_by("execute #{command}") do
exec
end
@@ -78,8 +78,8 @@ class Chef
#There is no reason to assume 2 deployments in a single chef run, hence fails in whyrun.
end
- [ @new_resource.before_migrate, @new_resource.before_symlink,
- @new_resource.before_restart, @new_resource.after_restart ].each do |script|
+ [ new_resource.before_migrate, new_resource.before_symlink,
+ new_resource.before_restart, new_resource.after_restart ].each do |script|
requirements.assert(:deploy, :force_deploy) do |a|
callback_file = "#{release_path}/#{script}"
a.assertion do
@@ -93,14 +93,13 @@ class Chef
a.whyrun("Would assume callback file #{callback_file} included in release")
end
end
-
end
def action_deploy
save_release_state
if deployed?(release_path )
if current_release?(release_path )
- Chef::Log.debug("#{@new_resource} is the latest version")
+ Chef::Log.debug("#{new_resource} is the latest version")
else
rollback_to release_path
end
@@ -117,7 +116,7 @@ class Chef
converge_by("delete deployed app at #{release_path} prior to force-deploy") do
Chef::Log.info("Already deployed app at #{release_path}, forcing.")
FileUtils.rm_rf(release_path)
- Chef::Log.info("#{@new_resource} forcing deploy of already deployed app at #{release_path}")
+ Chef::Log.info("#{new_resource} forcing deploy of already deployed app at #{release_path}")
end
end
@@ -143,7 +142,7 @@ class Chef
releases_to_nuke.each do |i|
converge_by("roll back by removing release #{i}") do
- Chef::Log.info "#{@new_resource} removing release: #{i}"
+ Chef::Log.info "#{new_resource} removing release: #{i}"
FileUtils.rm_rf i
end
release_deleted(i)
@@ -157,29 +156,29 @@ class Chef
copy_cached_repo
install_gems
enforce_ownership
- callback(:before_migrate, @new_resource.before_migrate)
+ callback(:before_migrate, new_resource.before_migrate)
migrate
- callback(:before_symlink, @new_resource.before_symlink)
+ callback(:before_symlink, new_resource.before_symlink)
symlink
- callback(:before_restart, @new_resource.before_restart)
+ callback(:before_restart, new_resource.before_restart)
restart
- callback(:after_restart, @new_resource.after_restart)
+ callback(:after_restart, new_resource.after_restart)
cleanup!
- Chef::Log.info "#{@new_resource} deployed to #{@new_resource.deploy_to}"
+ Chef::Log.info "#{new_resource} deployed to #{new_resource.deploy_to}"
end
def rollback
- Chef::Log.info "#{@new_resource} rolling back to previous release #{release_path}"
+ Chef::Log.info "#{new_resource} rolling back to previous release #{release_path}"
symlink
- Chef::Log.info "#{@new_resource} restarting with previous release"
+ Chef::Log.info "#{new_resource} restarting with previous release"
restart
end
- def callback(what, callback_code=nil)
+ def callback(what, callback_code = nil)
@collection = Chef::ResourceCollection.new
case callback_code
when Proc
- Chef::Log.info "#{@new_resource} running callback #{what}"
+ Chef::Log.info "#{new_resource} running callback #{what}"
recipe_eval(&callback_code)
when String
run_callback_from_file("#{release_path}/#{callback_code}")
@@ -191,17 +190,17 @@ class Chef
def migrate
run_symlinks_before_migrate
- if @new_resource.migrate
+ if new_resource.migrate
enforce_ownership
- environment = @new_resource.environment
+ environment = new_resource.environment
env_info = environment && environment.map do |key_and_val|
"#{key_and_val.first}='#{key_and_val.last}'"
end.join(" ")
- converge_by("execute migration command #{@new_resource.migration_command}") do
- Chef::Log.info "#{@new_resource} migrating #{@new_resource.user} with environment #{env_info}"
- shell_out!(@new_resource.migration_command,run_options(:cwd=>release_path, :log_level => :info))
+ converge_by("execute migration command #{new_resource.migration_command}") do
+ Chef::Log.info "#{new_resource} migrating #{new_resource.user} with environment #{env_info}"
+ shell_out!(new_resource.migration_command, run_options(:cwd => release_path, :log_level => :info))
end
end
end
@@ -210,18 +209,18 @@ class Chef
purge_tempfiles_from_current_release
link_tempfiles_to_current_release
link_current_release_to_production
- Chef::Log.info "#{@new_resource} updated symlinks"
+ Chef::Log.info "#{new_resource} updated symlinks"
end
def restart
- if restart_cmd = @new_resource.restart_command
+ if restart_cmd = new_resource.restart_command
if restart_cmd.kind_of?(Proc)
- Chef::Log.info("#{@new_resource} restarting app with embedded recipe")
+ Chef::Log.info("#{new_resource} restarting app with embedded recipe")
recipe_eval(&restart_cmd)
else
- converge_by("restart app using command #{@new_resource.restart_command}") do
- Chef::Log.info("#{@new_resource} restarting app")
- shell_out!(@new_resource.restart_command,run_options(:cwd=>@new_resource.current_path))
+ converge_by("restart app using command #{new_resource.restart_command}") do
+ Chef::Log.info("#{new_resource} restarting app")
+ shell_out!(new_resource.restart_command, run_options(:cwd => new_resource.current_path))
end
end
end
@@ -232,10 +231,10 @@ class Chef
release_created(release_path)
end
- chop = -1 - @new_resource.keep_releases
+ chop = -1 - new_resource.keep_releases
all_releases[0..chop].each do |old_release|
converge_by("remove old release #{old_release}") do
- Chef::Log.info "#{@new_resource} removing old release #{old_release}"
+ Chef::Log.info "#{new_resource} removing old release #{old_release}"
FileUtils.rm_rf(old_release)
end
release_deleted(old_release)
@@ -243,11 +242,11 @@ class Chef
end
def all_releases
- Dir.glob(Chef::Util::PathHelper.escape_glob(@new_resource.deploy_to) + "/releases/*").sort
+ Dir.glob(Chef::Util::PathHelper.escape_glob_dir(new_resource.deploy_to) + "/releases/*").sort
end
def update_cached_repo
- if @new_resource.svn_force_export
+ if new_resource.svn_force_export
# TODO assertion, non-recoverable - @scm_provider must be svn if force_export?
svn_force_export
else
@@ -260,78 +259,78 @@ class Chef
end
def svn_force_export
- Chef::Log.info "#{@new_resource} exporting source repository"
+ Chef::Log.info "#{new_resource} exporting source repository"
@scm_provider.run_action(:force_export)
end
def copy_cached_repo
- target_dir_path = @new_resource.deploy_to + "/releases"
+ target_dir_path = new_resource.deploy_to + "/releases"
converge_by("deploy from repo to #{target_dir_path} ") do
FileUtils.rm_rf(release_path) if ::File.exist?(release_path)
FileUtils.mkdir_p(target_dir_path)
- FileUtils.cp_r(::File.join(@new_resource.destination, "."), release_path, :preserve => true)
- Chef::Log.info "#{@new_resource} copied the cached checkout to #{release_path}"
+ FileUtils.cp_r(::File.join(new_resource.destination, "."), release_path, :preserve => true)
+ Chef::Log.info "#{new_resource} copied the cached checkout to #{release_path}"
end
end
def enforce_ownership
- converge_by("force ownership of #{@new_resource.deploy_to} to #{@new_resource.group}:#{@new_resource.user}") do
- FileUtils.chown_R(@new_resource.user, @new_resource.group, @new_resource.deploy_to, :force => true)
- Chef::Log.info("#{@new_resource} set user to #{@new_resource.user}") if @new_resource.user
- Chef::Log.info("#{@new_resource} set group to #{@new_resource.group}") if @new_resource.group
+ converge_by("force ownership of #{new_resource.deploy_to} to #{new_resource.group}:#{new_resource.user}") do
+ FileUtils.chown_R(new_resource.user, new_resource.group, new_resource.deploy_to, :force => true)
+ Chef::Log.info("#{new_resource} set user to #{new_resource.user}") if new_resource.user
+ Chef::Log.info("#{new_resource} set group to #{new_resource.group}") if new_resource.group
end
end
def verify_directories_exist
- create_dir_unless_exists(@new_resource.deploy_to)
- create_dir_unless_exists(@new_resource.shared_path)
+ create_dir_unless_exists(new_resource.deploy_to)
+ create_dir_unless_exists(new_resource.shared_path)
end
def link_current_release_to_production
- converge_by(["remove existing link at #{@new_resource.current_path}",
- "link release #{release_path} into production at #{@new_resource.current_path}"]) do
- FileUtils.rm_f(@new_resource.current_path)
+ converge_by(["remove existing link at #{new_resource.current_path}",
+ "link release #{release_path} into production at #{new_resource.current_path}"]) do
+ FileUtils.rm_f(new_resource.current_path)
begin
- FileUtils.ln_sf(release_path, @new_resource.current_path)
+ FileUtils.ln_sf(release_path, new_resource.current_path)
rescue => e
raise Chef::Exceptions::FileNotFound.new("Cannot symlink current release to production: #{e.message}")
end
- Chef::Log.info "#{@new_resource} linked release #{release_path} into production at #{@new_resource.current_path}"
+ Chef::Log.info "#{new_resource} linked release #{release_path} into production at #{new_resource.current_path}"
end
enforce_ownership
end
def run_symlinks_before_migrate
- links_info = @new_resource.symlink_before_migrate.map { |src, dst| "#{src} => #{dst}" }.join(", ")
+ links_info = new_resource.symlink_before_migrate.map { |src, dst| "#{src} => #{dst}" }.join(", ")
converge_by("make pre-migration symlinks: #{links_info}") do
- @new_resource.symlink_before_migrate.each do |src, dest|
+ new_resource.symlink_before_migrate.each do |src, dest|
begin
- FileUtils.ln_sf(@new_resource.shared_path + "/#{src}", release_path + "/#{dest}")
+ FileUtils.ln_sf(new_resource.shared_path + "/#{src}", release_path + "/#{dest}")
rescue => e
- raise Chef::Exceptions::FileNotFound.new("Cannot symlink #{@new_resource.shared_path}/#{src} to #{release_path}/#{dest} before migrate: #{e.message}")
+ raise Chef::Exceptions::FileNotFound.new("Cannot symlink #{new_resource.shared_path}/#{src} to #{release_path}/#{dest} before migrate: #{e.message}")
end
end
- Chef::Log.info "#{@new_resource} made pre-migration symlinks"
+ Chef::Log.info "#{new_resource} made pre-migration symlinks"
end
end
def link_tempfiles_to_current_release
- dirs_info = @new_resource.create_dirs_before_symlink.join(",")
- @new_resource.create_dirs_before_symlink.each do |dir|
+ dirs_info = new_resource.create_dirs_before_symlink.join(",")
+ new_resource.create_dirs_before_symlink.each do |dir|
create_dir_unless_exists(release_path + "/#{dir}")
end
- Chef::Log.info("#{@new_resource} created directories before symlinking: #{dirs_info}")
+ Chef::Log.info("#{new_resource} created directories before symlinking: #{dirs_info}")
- links_info = @new_resource.symlinks.map { |src, dst| "#{src} => #{dst}" }.join(", ")
+ links_info = new_resource.symlinks.map { |src, dst| "#{src} => #{dst}" }.join(", ")
converge_by("link shared paths into current release: #{links_info}") do
- @new_resource.symlinks.each do |src, dest|
+ new_resource.symlinks.each do |src, dest|
begin
- FileUtils.ln_sf(::File.join(@new_resource.shared_path, src), ::File.join(release_path, dest))
+ FileUtils.ln_sf(::File.join(new_resource.shared_path, src), ::File.join(release_path, dest))
rescue => e
- raise Chef::Exceptions::FileNotFound.new("Cannot symlink shared data #{::File.join(@new_resource.shared_path, src)} to #{::File.join(release_path, dest)}: #{e.message}")
+ raise Chef::Exceptions::FileNotFound.new("Cannot symlink shared data #{::File.join(new_resource.shared_path, src)} to #{::File.join(release_path, dest)}: #{e.message}")
end
end
- Chef::Log.info("#{@new_resource} linked shared paths into current release: #{links_info}")
+ Chef::Log.info("#{new_resource} linked shared paths into current release: #{links_info}")
end
run_symlinks_before_migrate
enforce_ownership
@@ -341,10 +340,10 @@ class Chef
end
def purge_tempfiles_from_current_release
- log_info = @new_resource.purge_before_symlink.join(", ")
+ log_info = new_resource.purge_before_symlink.join(", ")
converge_by("purge directories in checkout #{log_info}") do
- @new_resource.purge_before_symlink.each { |dir| FileUtils.rm_rf(release_path + "/#{dir}") }
- Chef::Log.info("#{@new_resource} purged directories in checkout #{log_info}")
+ new_resource.purge_before_symlink.each { |dir| FileUtils.rm_rf(release_path + "/#{dir}") }
+ Chef::Log.info("#{new_resource} purged directories in checkout #{log_info}")
end
end
@@ -365,7 +364,7 @@ class Chef
end
def release_slug
- raise Chef::Exceptions::Override, "You must override release_slug in #{self.to_s}"
+ raise Chef::Exceptions::Override, "You must override release_slug in #{self}"
end
def install_gems
@@ -391,11 +390,11 @@ class Chef
end
end
- def run_options(run_opts={})
- run_opts[:user] = @new_resource.user if @new_resource.user
- run_opts[:group] = @new_resource.group if @new_resource.group
- run_opts[:environment] = @new_resource.environment if @new_resource.environment
- run_opts[:log_tag] = @new_resource.to_s
+ def run_options(run_opts = {})
+ run_opts[:user] = new_resource.user if new_resource.user
+ run_opts[:group] = new_resource.group if new_resource.group
+ run_opts[:environment] = new_resource.environment if new_resource.environment
+ run_opts[:log_tag] = new_resource.to_s
run_opts[:log_level] ||= :debug
if run_opts[:log_level] == :info
if STDOUT.tty? && !Chef::Config[:daemon] && Chef::Log.info?
@@ -406,7 +405,7 @@ class Chef
end
def run_callback_from_file(callback_file)
- Chef::Log.info "#{@new_resource} queueing checkdeploy hook #{callback_file}"
+ Chef::Log.info "#{new_resource} queueing checkdeploy hook #{callback_file}"
recipe_eval do
Dir.chdir(release_path) do
from_file(callback_file) if ::File.exist?(callback_file)
@@ -416,20 +415,20 @@ class Chef
def create_dir_unless_exists(dir)
if ::File.directory?(dir)
- Chef::Log.debug "#{@new_resource} not creating #{dir} because it already exists"
+ Chef::Log.debug "#{new_resource} not creating #{dir} because it already exists"
return false
end
converge_by("create new directory #{dir}") do
begin
FileUtils.mkdir_p(dir)
- Chef::Log.debug "#{@new_resource} created directory #{dir}"
- if @new_resource.user
- FileUtils.chown(@new_resource.user, nil, dir)
- Chef::Log.debug("#{@new_resource} set user to #{@new_resource.user} for #{dir}")
+ Chef::Log.debug "#{new_resource} created directory #{dir}"
+ if new_resource.user
+ FileUtils.chown(new_resource.user, nil, dir)
+ Chef::Log.debug("#{new_resource} set user to #{new_resource.user} for #{dir}")
end
- if @new_resource.group
- FileUtils.chown(nil, @new_resource.group, dir)
- Chef::Log.debug("#{@new_resource} set group to #{@new_resource.group} for #{dir}")
+ if new_resource.group
+ FileUtils.chown(nil, new_resource.group, dir)
+ Chef::Log.debug("#{new_resource} set group to #{new_resource.group} for #{dir}")
end
rescue => e
raise Chef::Exceptions::FileNotFound.new("Cannot create directory #{dir}: #{e.message}")
@@ -440,7 +439,7 @@ class Chef
def with_rollback_on_error
yield
rescue ::Exception => e
- if @new_resource.rollback_on_error
+ if new_resource.rollback_on_error
Chef::Log.warn "Error on deploying #{release_path}: #{e.message}"
failed_release = release_path
@@ -459,8 +458,8 @@ class Chef
end
def save_release_state
- if ::File.exists?(@new_resource.current_path)
- release = ::File.readlink(@new_resource.current_path)
+ if ::File.exists?(new_resource.current_path)
+ release = ::File.readlink(new_resource.current_path)
@previous_release_path = release if ::File.exists?(release)
end
end
diff --git a/lib/chef/provider/deploy/revision.rb b/lib/chef/provider/deploy/revision.rb
index 62aa0e87f6..06138e4f05 100644
--- a/lib/chef/provider/deploy/revision.rb
+++ b/lib/chef/provider/deploy/revision.rb
@@ -1,9 +1,9 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,9 +19,9 @@
# limitations under the License.
#
-require 'chef/provider'
-require 'chef/provider/deploy'
-require 'chef/json_compat'
+require "chef/provider"
+require "chef/provider/deploy"
+require "chef/json_compat"
class Chef
class Provider
@@ -44,7 +44,7 @@ class Chef
known_releases = sorted_releases
- Dir["#{Chef::Util::PathHelper.escape_glob(new_resource.deploy_to)}/releases/*"].each do |release_dir|
+ Dir["#{Chef::Util::PathHelper.escape_glob_dir(new_resource.deploy_to)}/releases/*"].each do |release_dir|
unless known_releases.include?(release_dir)
converge_by("Remove unknown release in #{release_dir}") do
FileUtils.rm_rf(release_dir)
@@ -56,11 +56,11 @@ class Chef
protected
def release_created(release)
- sorted_releases {|r| r.delete(release); r << release }
+ sorted_releases { |r| r.delete(release); r << release }
end
def release_deleted(release)
- sorted_releases { |r| r.delete(release)}
+ sorted_releases { |r| r.delete(release) }
end
def release_slug
@@ -87,15 +87,13 @@ class Chef
end
def sorted_releases_from_filesystem
- Dir.glob(Chef::Util::PathHelper.escape_glob(new_resource.deploy_to) + "/releases/*").sort_by { |d| ::File.ctime(d) }
+ Dir.glob(Chef::Util::PathHelper.escape_glob_dir(new_resource.deploy_to) + "/releases/*").sort_by { |d| ::File.ctime(d) }
end
def load_cache
- begin
- Chef::JSONCompat.parse(Chef::FileCache.load("revision-deploys/#{new_resource.name}"))
- rescue Chef::Exceptions::FileNotFound
- sorted_releases_from_filesystem
- end
+ Chef::JSONCompat.parse(Chef::FileCache.load("revision-deploys/#{new_resource.name}"))
+ rescue Chef::Exceptions::FileNotFound
+ sorted_releases_from_filesystem
end
def save_cache(cache)
diff --git a/lib/chef/provider/deploy/timestamped.rb b/lib/chef/provider/deploy/timestamped.rb
index ba3f6683f0..5486b092d3 100644
--- a/lib/chef/provider/deploy/timestamped.rb
+++ b/lib/chef/provider/deploy/timestamped.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/directory.rb b/lib/chef/provider/directory.rb
index 8892d3a73d..38ee1f241f 100644
--- a/lib/chef/provider/directory.rb
+++ b/lib/chef/provider/directory.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/log'
-require 'chef/resource/directory'
-require 'chef/provider'
-require 'chef/provider/file'
-require 'fileutils'
+require "chef/config"
+require "chef/log"
+require "chef/resource/directory"
+require "chef/provider"
+require "chef/provider/file"
+require "fileutils"
class Chef
class Provider
@@ -34,12 +34,12 @@ class Chef
end
def load_current_resource
- @current_resource = Chef::Resource::Directory.new(@new_resource.name)
- @current_resource.path(@new_resource.path)
- if ::File.exists?(@current_resource.path) && @action != :create_if_missing
- load_resource_attributes_from_file(@current_resource)
+ @current_resource = Chef::Resource::Directory.new(new_resource.name)
+ current_resource.path(new_resource.path)
+ if ::File.exists?(current_resource.path) && @action != :create_if_missing
+ load_resource_attributes_from_file(current_resource)
end
- @current_resource
+ current_resource
end
def define_resource_requirements
@@ -49,17 +49,31 @@ class Chef
requirements.assert(:create) do |a|
# Make sure the parent dir exists, or else fail.
# for why run, print a message explaining the potential error.
- parent_directory = ::File.dirname(@new_resource.path)
- a.assertion { @new_resource.recursive || ::File.directory?(parent_directory) }
- a.failure_message(Chef::Exceptions::EnclosingDirectoryDoesNotExist, "Parent directory #{parent_directory} does not exist, cannot create #{@new_resource.path}")
+ parent_directory = ::File.dirname(new_resource.path)
+ a.assertion do
+ if new_resource.recursive
+ does_parent_exist = lambda do |base_dir|
+ base_dir = ::File.dirname(base_dir)
+ if ::File.exist?(base_dir)
+ ::File.directory?(base_dir)
+ else
+ does_parent_exist.call(base_dir)
+ end
+ end
+ does_parent_exist.call(new_resource.path)
+ else
+ ::File.directory?(parent_directory)
+ end
+ end
+ a.failure_message(Chef::Exceptions::EnclosingDirectoryDoesNotExist, "Parent directory #{parent_directory} does not exist, cannot create #{new_resource.path}")
a.whyrun("Assuming directory #{parent_directory} would have been created")
end
requirements.assert(:create) do |a|
- parent_directory = ::File.dirname(@new_resource.path)
+ parent_directory = ::File.dirname(new_resource.path)
a.assertion do
- if @new_resource.recursive
- # find the lowest-level directory in @new_resource.path that already exists
+ if new_resource.recursive
+ # find the lowest-level directory in new_resource.path that already exists
# make sure we have write permissions to that directory
is_parent_writable = lambda do |base_dir|
base_dir = ::File.dirname(base_dir)
@@ -75,7 +89,7 @@ class Chef
is_parent_writable.call(base_dir)
end
end
- is_parent_writable.call(@new_resource.path)
+ is_parent_writable.call(new_resource.path)
else
# in why run mode & parent directory does not exist no permissions check is required
# If not in why run, permissions must be valid and we rely on prior assertion that dir exists
@@ -83,7 +97,7 @@ class Chef
if Chef::FileAccessControl.writable?(parent_directory)
true
elsif Chef::Util::PathHelper.is_sip_path?(parent_directory, node)
- Chef::Util::PathHelper.writable_sip_path?(@new_resource.path)
+ Chef::Util::PathHelper.writable_sip_path?(new_resource.path)
else
false
end
@@ -93,18 +107,18 @@ class Chef
end
end
a.failure_message(Chef::Exceptions::InsufficientPermissions,
- "Cannot create #{@new_resource} at #{@new_resource.path} due to insufficient permissions")
+ "Cannot create #{new_resource} at #{new_resource.path} due to insufficient permissions")
end
requirements.assert(:delete) do |a|
a.assertion do
- if ::File.exists?(@new_resource.path)
- ::File.directory?(@new_resource.path) && Chef::FileAccessControl.writable?(@new_resource.path)
+ if ::File.exists?(new_resource.path)
+ ::File.directory?(new_resource.path) && Chef::FileAccessControl.writable?(new_resource.path)
else
true
end
end
- a.failure_message(RuntimeError, "Cannot delete #{@new_resource} at #{@new_resource.path}!")
+ a.failure_message(RuntimeError, "Cannot delete #{new_resource} at #{new_resource.path}!")
# No why-run handling here:
# * if we don't have permissions, this is unlikely to be changed earlier in the run
# * if the target is a file (not a dir), there's no reasonable path by which this would have been changed
@@ -112,30 +126,32 @@ class Chef
end
def action_create
- unless ::File.exists?(@new_resource.path)
- converge_by("create new directory #{@new_resource.path}") do
- if @new_resource.recursive == true
- ::FileUtils.mkdir_p(@new_resource.path)
+ unless ::File.exists?(new_resource.path)
+ converge_by("create new directory #{new_resource.path}") do
+ if new_resource.recursive == true
+ ::FileUtils.mkdir_p(new_resource.path)
else
- ::Dir.mkdir(@new_resource.path)
+ ::Dir.mkdir(new_resource.path)
end
- Chef::Log.info("#{@new_resource} created directory #{@new_resource.path}")
+ Chef::Log.info("#{new_resource} created directory #{new_resource.path}")
end
end
do_acl_changes
do_selinux(true)
- load_resource_attributes_from_file(@new_resource)
+ load_resource_attributes_from_file(new_resource) unless Chef::Config[:why_run]
end
def action_delete
- if ::File.exists?(@new_resource.path)
- converge_by("delete existing directory #{@new_resource.path}") do
- if @new_resource.recursive == true
- FileUtils.rm_rf(@new_resource.path)
- Chef::Log.info("#{@new_resource} deleted #{@new_resource.path} recursively")
+ if ::File.exists?(new_resource.path)
+ converge_by("delete existing directory #{new_resource.path}") do
+ if new_resource.recursive == true
+ # we don't use rm_rf here because it masks all errors, including
+ # IO errors or permission errors that would prvent the deletion
+ FileUtils.rm_r(new_resource.path)
+ Chef::Log.info("#{new_resource} deleted #{new_resource.path} recursively")
else
- ::Dir.delete(@new_resource.path)
- Chef::Log.info("#{@new_resource} deleted #{@new_resource.path}")
+ ::Dir.delete(new_resource.path)
+ Chef::Log.info("#{new_resource} deleted #{new_resource.path}")
end
end
end
diff --git a/lib/chef/provider/dsc_resource.rb b/lib/chef/provider/dsc_resource.rb
index 65830131ab..0ad075484f 100644
--- a/lib/chef/provider/dsc_resource.rb
+++ b/lib/chef/provider/dsc_resource.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
+# Author:: Adam Edwards (<adamed@chef.io>)
#
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,29 +15,29 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
-require 'chef/util/powershell/cmdlet'
-require 'chef/util/dsc/local_configuration_manager'
-require 'chef/mixin/powershell_type_coercions'
-require 'chef/util/dsc/resource_store'
+require "chef/util/powershell/cmdlet"
+require "chef/util/dsc/local_configuration_manager"
+require "chef/mixin/powershell_type_coercions"
+require "chef/util/dsc/resource_store"
class Chef
class Provider
class DscResource < Chef::Provider
include Chef::Mixin::PowershellTypeCoercions
-
provides :dsc_resource, os: "windows"
-
def initialize(new_resource, run_context)
super
@new_resource = new_resource
@module_name = new_resource.module_name
+ @module_version = new_resource.module_version
+ @reboot_resource = nil
end
def action_run
if ! test_resource
converge_by(generate_description) do
result = set_resource
+ reboot_if_required
end
end
end
@@ -59,12 +59,20 @@ class Chef
a.block_action!
end
requirements.assert(:run) do |a|
- a.assertion { dsc_refresh_mode_disabled? }
- err = ["The LCM must have its RefreshMode set to Disabled. "]
- a.failure_message Chef::Exceptions::ProviderNotFound, err.join(' ')
+ a.assertion { supports_refresh_mode_enabled? || dsc_refresh_mode_disabled? }
+ err = ["The LCM must have its RefreshMode set to Disabled for" \
+ " PowerShell versions before 5.0.10586.0."]
+ a.failure_message Chef::Exceptions::ProviderNotFound, err.join(" ")
a.whyrun err + ["Assuming a previous resource sets the RefreshMode."]
a.block_action!
end
+ requirements.assert(:run) do |a|
+ a.assertion { module_usage_valid? }
+ err = ["module_name must be supplied along with module_version."]
+ a.failure_message Chef::Exceptions::DSCModuleNameMissing,
+ err
+ a.block_action!
+ end
end
protected
@@ -83,11 +91,19 @@ class Chef
def supports_dsc_invoke_resource?
run_context && Chef::Platform.supports_dsc_invoke_resource?(node)
end
-
+
def dsc_refresh_mode_disabled?
Chef::Platform.dsc_refresh_mode_disabled?(node)
end
+ def supports_refresh_mode_enabled?
+ Chef::Platform.supports_refresh_mode_enabled?(node)
+ end
+
+ def module_usage_valid?
+ !(!@module_name && @module_version)
+ end
+
def generate_description
@converge_description
end
@@ -99,17 +115,16 @@ class Chef
def module_name
@module_name ||= begin
found = resource_store.find(dsc_resource_name)
-
r = case found.length
when 0
raise Chef::Exceptions::ResourceNotFound,
"Could not find #{dsc_resource_name}. Check to make "\
"sure that it shows up when running Get-DscResource"
when 1
- if found[0]['Module'].nil?
- :none
+ if found[0]["Module"].nil?
+ "PSDesiredStateConfiguration" # default DSC module
else
- found[0]['Module']['Name']
+ found[0]["Module"]["Name"]
end
else
raise Chef::Exceptions::MultipleDscResourcesFound, found
@@ -119,42 +134,80 @@ class Chef
def test_resource
result = invoke_resource(:test)
- # We really want this information from the verbose stream,
- # however Invoke-DscResource is not correctly writing to that
- # stream and instead just dumping to stdout
- @converge_description = result.stdout
-
- if result.return_value.is_a?(Array)
- # WMF Feb 2015 Preview
- result.return_value[0]["InDesiredState"]
- else
- # WMF April 2015 Preview
- result.return_value["InDesiredState"]
- end
+ add_dsc_verbose_log(result)
+ return_dsc_resource_result(result, "InDesiredState")
end
def set_resource
result = invoke_resource(:set)
+ add_dsc_verbose_log(result)
+ create_reboot_resource if return_dsc_resource_result(result, "RebootRequired")
result.return_value
end
- def invoke_resource(method, output_format=:object)
- properties = translate_type(@new_resource.properties)
- switches = "-Method #{method.to_s} -Name #{@new_resource.resource}"\
- " -Property #{properties} -Verbose"
+ def add_dsc_verbose_log(result)
+ # We really want this information from the verbose stream,
+ # however in some versions of WMF, Invoke-DscResource is not correctly
+ # writing to that stream and instead just dumping to stdout
+ verbose_output = result.stream(:verbose)
+ verbose_output = result.stdout if verbose_output.empty?
- if module_name != :none
- switches += " -Module #{module_name}"
+ if @converge_description.nil? || @converge_description.empty?
+ @converge_description = verbose_output
+ else
+ @converge_description << "\n"
+ @converge_description << verbose_output
end
+ end
+
+ def module_info_object
+ @module_version.nil? ? module_name : "@{ModuleName='#{module_name}';ModuleVersion='#{@module_version}'}"
+ end
+ def invoke_resource(method, output_format = :object)
+ properties = translate_type(new_resource.properties)
+ switches = "-Method #{method} -Name #{new_resource.resource}"\
+ " -Property #{properties} -Module #{module_info_object} -Verbose"
cmdlet = Chef::Util::Powershell::Cmdlet.new(
node,
"Invoke-DscResource #{switches}",
output_format
)
- cmdlet.run!
+ cmdlet.run!({}, { :timeout => new_resource.timeout })
end
+ def return_dsc_resource_result(result, property_name)
+ if result.return_value.is_a?(Array)
+ # WMF Feb 2015 Preview
+ result.return_value[0][property_name]
+ else
+ # WMF April 2015 Preview
+ result.return_value[property_name]
+ end
+ end
+
+ def create_reboot_resource
+ @reboot_resource = Chef::Resource::Reboot.new(
+ "Reboot for #{new_resource.name}",
+ run_context
+ ).tap do |r|
+ r.reason("Reboot for #{new_resource.resource}.")
+ end
+ end
+
+ def reboot_if_required
+ reboot_action = new_resource.reboot_action
+ unless @reboot_resource.nil?
+ case reboot_action
+ when :nothing
+ Chef::Log.debug("A reboot was requested by the DSC resource, but reboot_action is :nothing.")
+ Chef::Log.debug("This dsc_resource will not reboot the node.")
+ else
+ Chef::Log.debug("Requesting node reboot with #{reboot_action}.")
+ @reboot_resource.run_action(reboot_action)
+ end
+ end
+ end
end
end
end
diff --git a/lib/chef/provider/dsc_script.rb b/lib/chef/provider/dsc_script.rb
index b2432132b7..66783ceb0f 100644
--- a/lib/chef/provider/dsc_script.rb
+++ b/lib/chef/provider/dsc_script.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
+# Author:: Adam Edwards (<adamed@chef.io>)
#
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'chef/util/powershell/cmdlet'
-require 'chef/util/dsc/configuration_generator'
-require 'chef/util/dsc/local_configuration_manager'
-require 'chef/util/path_helper'
+require "chef/util/powershell/cmdlet"
+require "chef/util/dsc/configuration_generator"
+require "chef/util/dsc/local_configuration_manager"
+require "chef/util/path_helper"
class Chef
class Provider
@@ -32,12 +32,12 @@ class Chef
@dsc_resource = dsc_resource
@resource_converged = false
@operations = {
- :set => Proc.new { |config_manager, document, shellout_flags|
+ :set => Proc.new do |config_manager, document, shellout_flags|
config_manager.set_configuration(document, shellout_flags)
- },
- :test => Proc.new { |config_manager, document, shellout_flags|
+ end,
+ :test => Proc.new do |config_manager, document, shellout_flags|
config_manager.test_configuration(document, shellout_flags)
- }}
+ end }
end
def action_run
@@ -65,12 +65,12 @@ class Chef
def define_resource_requirements
requirements.assert(:run) do |a|
err = [
- 'Could not find PowerShell DSC support on the system',
+ "Could not find PowerShell DSC support on the system",
powershell_info_str,
"Powershell 4.0 or higher was not detected on your system and is required to use the dsc_script resource.",
]
a.assertion { supports_dsc? }
- a.failure_message Chef::Exceptions::ProviderNotFound, err.join(' ')
+ a.failure_message Chef::Exceptions::ProviderNotFound, err.join(" ")
a.whyrun err + ["Assuming a previous resource installs Powershell 4.0 or higher."]
a.block_action!
end
@@ -92,14 +92,14 @@ class Chef
shellout_flags = {
:cwd => @dsc_resource.cwd,
:environment => @dsc_resource.environment,
- :timeout => @dsc_resource.timeout
+ :timeout => @dsc_resource.timeout,
}
begin
configuration_document = generate_configuration_document(config_directory, configuration_flags)
@operations[operation].call(config_manager, configuration_document, shellout_flags)
rescue Exception => e
- Chef::Log.error("DSC operation failed: #{e.message.to_s}")
+ Chef::Log.error("DSC operation failed: #{e.message}")
raise e
ensure
::FileUtils.rm_rf(config_directory)
@@ -119,7 +119,7 @@ class Chef
shellout_flags = {
:cwd => @dsc_resource.cwd,
:environment => @dsc_resource.environment,
- :timeout => @dsc_resource.timeout
+ :timeout => @dsc_resource.timeout,
}
generator = Chef::Util::DSC::ConfigurationGenerator.new(@run_context.node, config_directory)
@@ -129,7 +129,7 @@ class Chef
else
# If code is also not provided, we mimic what the other script resources do (execute nothing)
Chef::Log.warn("Neither code or command were provided for dsc_resource[#{@dsc_resource.name}].") unless @dsc_resource.code
- generator.configuration_document_from_script_code(@dsc_resource.code || '', configuration_flags, @dsc_resource.imports, shellout_flags)
+ generator.configuration_document_from_script_code(@dsc_resource.code || "", configuration_flags, @dsc_resource.imports, shellout_flags)
end
end
@@ -138,7 +138,7 @@ class Chef
@dsc_resource.configuration_data_script
elsif @dsc_resource.configuration_data
configuration_data_path = "#{config_directory}/chef_dsc_config_data.psd1"
- ::File.open(configuration_data_path, 'wt') do | script |
+ ::File.open(configuration_data_path, "wt") do |script|
script.write(@dsc_resource.configuration_data)
end
configuration_data_path
@@ -164,8 +164,8 @@ class Chef
@dsc_resources_info.map do |resource|
if resource.changes_state?
# We ignore the last log message because it only contains the time it took, which looks weird
- cleaned_messages = resource.change_log[0..-2].map { |c| c.sub(/^#{Regexp.escape(resource.name)}/, '').strip }
- "converge DSC resource #{resource.name} by #{cleaned_messages.find_all{ |c| c != ''}.join("\n")}"
+ cleaned_messages = resource.change_log[0..-2].map { |c| c.sub(/^#{Regexp.escape(resource.name)}/, "").strip }
+ "converge DSC resource #{resource.name} by #{cleaned_messages.find_all { |c| c != '' }.join("\n")}"
else
# This is needed because a dsc script can have resources that are both converged and not
"converge DSC resource #{resource.name} by doing nothing because it is already converged"
@@ -177,7 +177,7 @@ class Chef
if run_context && run_context.node[:languages] && run_context.node[:languages][:powershell]
install_info = "Powershell #{run_context.node[:languages][:powershell][:version]} was found on the system."
else
- install_info = 'Powershell was not found.'
+ install_info = "Powershell was not found."
end
end
end
diff --git a/lib/chef/provider/env.rb b/lib/chef/provider/env.rb
index cf75ff7d85..5e05fe4798 100644
--- a/lib/chef/provider/env.rb
+++ b/lib/chef/provider/env.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/provider'
-require 'chef/mixin/command'
-require 'chef/resource/env'
+require "chef/provider"
+require "chef/mixin/command"
+require "chef/resource/env"
class Chef
class Provider
@@ -34,21 +34,21 @@ class Chef
end
def load_current_resource
- @current_resource = Chef::Resource::Env.new(@new_resource.name)
- @current_resource.key_name(@new_resource.key_name)
+ @current_resource = Chef::Resource::Env.new(new_resource.name)
+ current_resource.key_name(new_resource.key_name)
- if env_key_exists(@new_resource.key_name)
- @current_resource.value(env_value(@new_resource.key_name))
+ if env_key_exists(new_resource.key_name)
+ current_resource.value(env_value(new_resource.key_name))
else
@key_exists = false
- Chef::Log.debug("#{@new_resource} key does not exist")
+ Chef::Log.debug("#{new_resource} key does not exist")
end
- @current_resource
+ current_resource
end
def env_value(key_name)
- raise Chef::Exceptions::Env, "#{self.to_s} provider does not implement env_value!"
+ raise Chef::Exceptions::Env, "#{self} provider does not implement env_value!"
end
def env_key_exists(key_name)
@@ -61,7 +61,7 @@ class Chef
# <true>:: If a change is required
# <false>:: If a change is not required
def requires_modify_or_create?
- if @new_resource.delim
+ if new_resource.delim
#e.g. check for existing value within PATH
new_values.inject(0) do |index, val|
next_index = current_values.find_index val
@@ -70,7 +70,7 @@ class Chef
end
false
else
- @new_resource.value != @current_resource.value
+ new_resource.value != current_resource.value
end
end
@@ -80,13 +80,13 @@ class Chef
if @key_exists
if requires_modify_or_create?
modify_env
- Chef::Log.info("#{@new_resource} altered")
- @new_resource.updated_by_last_action(true)
+ Chef::Log.info("#{new_resource} altered")
+ new_resource.updated_by_last_action(true)
end
else
create_env
- Chef::Log.info("#{@new_resource} created")
- @new_resource.updated_by_last_action(true)
+ Chef::Log.info("#{new_resource} created")
+ new_resource.updated_by_last_action(true)
end
end
@@ -97,24 +97,24 @@ class Chef
# <false>:: Caller should delete the key, either no :delim was specific or value was empty
# after we removed the element.
def delete_element
- return false unless @new_resource.delim #no delim: delete the key
+ return false unless new_resource.delim #no delim: delete the key
needs_delete = new_values.any? { |v| current_values.include?(v) }
if !needs_delete
- Chef::Log.debug("#{@new_resource} element '#{@new_resource.value}' does not exist")
+ Chef::Log.debug("#{new_resource} element '#{new_resource.value}' does not exist")
return true #do not delete the key
else
new_value =
current_values.select do |item|
not new_values.include?(item)
- end.join(@new_resource.delim)
+ end.join(new_resource.delim)
if new_value.empty?
return false #nothing left here, delete the key
else
- old_value = @new_resource.value(new_value)
+ old_value = new_resource.value(new_value)
create_env
- Chef::Log.debug("#{@new_resource} deleted #{old_value} element")
- @new_resource.updated_by_last_action(true)
+ Chef::Log.debug("#{new_resource} deleted #{old_value} element")
+ new_resource.updated_by_last_action(true)
return true #we removed the element and updated; do not delete the key
end
end
@@ -123,8 +123,8 @@ class Chef
def action_delete
if @key_exists && !delete_element
delete_env
- Chef::Log.info("#{@new_resource} deleted")
- @new_resource.updated_by_last_action(true)
+ Chef::Log.info("#{new_resource} deleted")
+ new_resource.updated_by_last_action(true)
end
end
@@ -132,38 +132,38 @@ class Chef
if @key_exists
if requires_modify_or_create?
modify_env
- Chef::Log.info("#{@new_resource} modified")
- @new_resource.updated_by_last_action(true)
+ Chef::Log.info("#{new_resource} modified")
+ new_resource.updated_by_last_action(true)
end
else
- raise Chef::Exceptions::Env, "Cannot modify #{@new_resource} - key does not exist!"
+ raise Chef::Exceptions::Env, "Cannot modify #{new_resource} - key does not exist!"
end
end
def create_env
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :#{@new_resource.action}"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :#{new_resource.action}"
end
def delete_env
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :delete"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :delete"
end
def modify_env
- if @new_resource.delim
- @new_resource.value((new_values + current_values).uniq.join(@new_resource.delim))
+ if new_resource.delim
+ new_resource.value((new_values + current_values).uniq.join(new_resource.delim))
end
create_env
end
# Returns the current values to split by delimiter
def current_values
- @current_values ||= @current_resource.value.split(@new_resource.delim)
+ @current_values ||= current_resource.value.split(new_resource.delim)
end
# Returns the new values to split by delimiter
def new_values
- @new_values ||= @new_resource.value.split(@new_resource.delim)
+ @new_values ||= new_resource.value.split(new_resource.delim)
end
- end
+ end
end
end
diff --git a/lib/chef/provider/env/windows.rb b/lib/chef/provider/env/windows.rb
index 56cebdb888..e25cab31d2 100644
--- a/lib/chef/provider/env/windows.rb
+++ b/lib/chef/provider/env/windows.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/mixin/windows_env_helper'
+require "chef/mixin/windows_env_helper"
class Chef
class Provider
@@ -36,7 +36,7 @@ class Chef
obj.variablevalue = @new_resource.value
obj.put_
value = @new_resource.value
- value = expand_path(value) if @new_resource.key_name.upcase == 'PATH'
+ value = expand_path(value) if @new_resource.key_name.casecmp("PATH") == 0
ENV[@new_resource.key_name] = value
broadcast_env_change
end
@@ -54,7 +54,7 @@ class Chef
def env_value(key_name)
obj = env_obj(key_name)
- return obj ? obj.variablevalue : ENV[key_name]
+ obj ? obj.variablevalue : ENV[key_name]
end
def env_obj(key_name)
diff --git a/lib/chef/provider/erl_call.rb b/lib/chef/provider/erl_call.rb
index f5855bcce6..50571d5256 100644
--- a/lib/chef/provider/erl_call.rb
+++ b/lib/chef/provider/erl_call.rb
@@ -1,6 +1,6 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/mixin/command'
-require 'chef/provider'
+require "chef/log"
+require "chef/mixin/command"
+require "chef/provider"
class Chef
class Provider
@@ -40,20 +40,20 @@ class Chef
end
def action_run
- case @new_resource.name_type
+ case new_resource.name_type
when "sname"
- node = "-sname #{@new_resource.node_name}"
+ node = "-sname #{new_resource.node_name}"
when "name"
- node = "-name #{@new_resource.node_name}"
+ node = "-name #{new_resource.node_name}"
end
- if @new_resource.cookie
- cookie = "-c #{@new_resource.cookie}"
+ if new_resource.cookie
+ cookie = "-c #{new_resource.cookie}"
else
cookie = ""
end
- if @new_resource.distributed
+ if new_resource.distributed
distributed = "-s"
else
distributed = ""
@@ -65,15 +65,15 @@ class Chef
begin
pid, stdin, stdout, stderr = popen4(command, :waitlast => true)
- Chef::Log.debug("#{@new_resource} running")
- Chef::Log.debug("#{@new_resource} command: #{command}")
- Chef::Log.debug("#{@new_resource} code: #{@new_resource.code}")
+ Chef::Log.debug("#{new_resource} running")
+ Chef::Log.debug("#{new_resource} command: #{command}")
+ Chef::Log.debug("#{new_resource} code: #{new_resource.code}")
- @new_resource.code.each_line { |line| stdin.puts(line.chomp) }
+ new_resource.code.each_line { |line| stdin.puts(line.chomp) }
stdin.close
- Chef::Log.debug("#{@new_resource} output: ")
+ Chef::Log.debug("#{new_resource} output: ")
stdout_output = ""
stdout.each_line { |line| stdout_output << line }
@@ -89,13 +89,13 @@ class Chef
end
# fail if the first 4 characters aren't "{ok,"
- unless stdout_output[0..3].include?('{ok,')
+ unless stdout_output[0..3].include?("{ok,")
raise Chef::Exceptions::ErlCall, stdout_output
end
- @new_resource.updated_by_last_action(true)
+ new_resource.updated_by_last_action(true)
- Chef::Log.debug("#{@new_resource} #{stdout_output}")
+ Chef::Log.debug("#{new_resource} #{stdout_output}")
Chef::Log.info("#{@new_resouce} ran successfully")
ensure
Process.wait(pid) if pid
diff --git a/lib/chef/provider/execute.rb b/lib/chef/provider/execute.rb
index 30de0d3b9e..28dce5d18c 100644
--- a/lib/chef/provider/execute.rb
+++ b/lib/chef/provider/execute.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/provider'
-require 'forwardable'
+require "chef/log"
+require "chef/provider"
+require "forwardable"
class Chef
class Provider
@@ -27,7 +27,7 @@ class Chef
provides :execute
- def_delegators :@new_resource, :command, :returns, :environment, :user, :group, :cwd, :umask, :creates
+ def_delegators :new_resource, :command, :returns, :environment, :user, :domain, :password, :group, :cwd, :umask, :creates
def load_current_resource
current_resource = Chef::Resource::Execute.new(new_resource.name)
@@ -39,10 +39,10 @@ class Chef
end
def define_resource_requirements
- # @todo: this should change to raise in some appropriate major version bump.
- if creates && creates_relative? && !cwd
- Chef::Log.warn "Providing a relative path for the creates attribute without the cwd is deprecated and will be changed to fail in the future (CHEF-3819)"
- end
+ # @todo: this should change to raise in some appropriate major version bump.
+ if creates && creates_relative? && !cwd
+ Chef::Log.warn "Providing a relative path for the creates attribute without the cwd is deprecated and will be changed to fail in the future (CHEF-3819)"
+ end
end
def timeout
@@ -78,19 +78,33 @@ class Chef
!!new_resource.sensitive
end
+ def live_stream?
+ Chef::Config[:stream_execute_output] || !!new_resource.live_stream
+ end
+
+ def stream_to_stdout?
+ STDOUT.tty? && !Chef::Config[:daemon]
+ end
+
def opts
opts = {}
opts[:timeout] = timeout
opts[:returns] = returns if returns
opts[:environment] = environment if environment
opts[:user] = user if user
+ opts[:domain] = domain if domain
+ opts[:password] = password if password
opts[:group] = group if group
opts[:cwd] = cwd if cwd
opts[:umask] = umask if umask
opts[:log_level] = :info
opts[:log_tag] = new_resource.to_s
- if STDOUT.tty? && !Chef::Config[:daemon] && Chef::Log.info? && !sensitive?
- opts[:live_stream] = STDOUT
+ if (Chef::Log.info? || live_stream?) && !sensitive?
+ if run_context.events.formatter?
+ opts[:live_stream] = Chef::EventDispatch::EventsOutputStream.new(run_context.events, :name => :execute)
+ elsif stream_to_stdout?
+ opts[:live_stream] = STDOUT
+ end
end
opts
end
@@ -108,6 +122,7 @@ class Chef
( cwd && creates_relative? ) ? ::File.join(cwd, creates) : creates
))
end
+
end
end
end
diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb
index 5ed7c6ac5b..ecde068751 100644
--- a/lib/chef/provider/file.rb
+++ b/lib/chef/provider/file.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2008-2013 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2008-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,22 +17,22 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/log'
-require 'chef/resource/file'
-require 'chef/provider'
-require 'etc'
-require 'fileutils'
-require 'chef/scan_access_control'
-require 'chef/mixin/checksum'
-require 'chef/mixin/file_class'
-require 'chef/mixin/enforce_ownership_and_permissions'
-require 'chef/util/backup'
-require 'chef/util/diff'
-require 'chef/util/selinux'
-require 'chef/deprecation/provider/file'
-require 'chef/deprecation/warnings'
-require 'chef/file_content_management/deploy'
+require "chef/config"
+require "chef/log"
+require "chef/resource/file"
+require "chef/provider"
+require "etc"
+require "fileutils"
+require "chef/scan_access_control"
+require "chef/mixin/checksum"
+require "chef/mixin/file_class"
+require "chef/mixin/enforce_ownership_and_permissions"
+require "chef/util/backup"
+require "chef/util/diff"
+require "chef/util/selinux"
+require "chef/deprecation/provider/file"
+require "chef/deprecation/warnings"
+require "chef/file_content_management/deploy"
# The Tao of File Providers:
# - the content provider must always return a tempfile that we can delete/mv
@@ -95,7 +95,7 @@ class Chef
# true if we are going to be creating a new file
@needs_creating = !::File.exist?(new_resource.path) || needs_unlinking?
- # Let children resources override constructing the @current_resource
+ # Let children resources override constructing the current_resource
@current_resource ||= Chef::Resource::File.new(new_resource.name)
current_resource.path(new_resource.path)
@@ -120,17 +120,17 @@ class Chef
# Make sure the parent directory exists, otherwise fail. For why-run assume it would have been created.
requirements.assert(:create, :create_if_missing, :touch) do |a|
- parent_directory = ::File.dirname(@new_resource.path)
+ parent_directory = ::File.dirname(new_resource.path)
a.assertion { ::File.directory?(parent_directory) }
a.failure_message(Chef::Exceptions::EnclosingDirectoryDoesNotExist, "Parent directory #{parent_directory} does not exist.")
a.whyrun("Assuming directory #{parent_directory} would have been created")
end
# Make sure the file is deletable if it exists, otherwise fail.
- if ::File.exist?(@new_resource.path)
+ if ::File.exist?(new_resource.path)
requirements.assert(:delete) do |a|
- a.assertion { ::File.writable?(@new_resource.path) }
- a.failure_message(Chef::Exceptions::InsufficientPermissions,"File #{@new_resource.path} exists but is not writable so it cannot be deleted")
+ a.assertion { ::File.writable?(new_resource.path) }
+ a.failure_message(Chef::Exceptions::InsufficientPermissions, "File #{new_resource.path} exists but is not writable so it cannot be deleted")
end
end
@@ -154,33 +154,33 @@ class Chef
do_contents_changes
do_acl_changes
do_selinux
- load_resource_attributes_from_file(@new_resource)
+ load_resource_attributes_from_file(new_resource) unless Chef::Config[:why_run]
end
def action_create_if_missing
- unless ::File.exist?(@new_resource.path)
+ unless ::File.exist?(new_resource.path)
action_create
else
- Chef::Log.debug("#{@new_resource} exists at #{@new_resource.path} taking no action.")
+ Chef::Log.debug("#{new_resource} exists at #{new_resource.path} taking no action.")
end
end
def action_delete
- if ::File.exists?(@new_resource.path)
- converge_by("delete file #{@new_resource.path}") do
- do_backup unless file_class.symlink?(@new_resource.path)
- ::File.delete(@new_resource.path)
- Chef::Log.info("#{@new_resource} deleted file at #{@new_resource.path}")
+ if ::File.exists?(new_resource.path)
+ converge_by("delete file #{new_resource.path}") do
+ do_backup unless file_class.symlink?(new_resource.path)
+ ::File.delete(new_resource.path)
+ Chef::Log.info("#{new_resource} deleted file at #{new_resource.path}")
end
end
end
def action_touch
action_create
- converge_by("update utime on file #{@new_resource.path}") do
+ converge_by("update utime on file #{new_resource.path}") do
time = Time.now
- ::File.utime(time, time, @new_resource.path)
- Chef::Log.info("#{@new_resource} updated atime and mtime to #{time}")
+ ::File.utime(time, time, new_resource.path)
+ Chef::Log.info("#{new_resource} updated atime and mtime to #{time}")
end
end
@@ -197,8 +197,8 @@ class Chef
# content (for things like doing checksums in load_current_resource). Expected to
# be overridden in subclasses.
def managing_content?
- return true if @new_resource.checksum
- return true if !@new_resource.content.nil? && @action != :create_if_missing
+ return true if new_resource.checksum
+ return true if !new_resource.content.nil? && @action != :create_if_missing
false
end
@@ -228,25 +228,25 @@ class Chef
# assertions, which then decide whether or not to raise or issue a
# warning for whyrun mode.
def inspect_existing_fs_entry
- path = @new_resource.path
+ path = new_resource.path
if !l_exist?(path)
[nil, nil, nil]
elsif real_file?(path)
[nil, nil, nil]
- elsif file_class.symlink?(path) && @new_resource.manage_symlink_source
+ elsif file_class.symlink?(path) && new_resource.manage_symlink_source
verify_symlink_sanity(path)
- elsif file_class.symlink?(@new_resource.path) && @new_resource.manage_symlink_source.nil?
- Chef::Log.warn("File #{path} managed by #{@new_resource} is really a symlink. Managing the source file instead.")
+ elsif file_class.symlink?(new_resource.path) && new_resource.manage_symlink_source.nil?
+ Chef::Log.warn("File #{path} managed by #{new_resource} is really a symlink. Managing the source file instead.")
Chef::Log.warn("Disable this warning by setting `manage_symlink_source true` on the resource")
Chef::Log.warn("In a future Chef release, 'manage_symlink_source' will not be enabled by default")
verify_symlink_sanity(path)
- elsif @new_resource.force_unlink
+ elsif new_resource.force_unlink
[nil, nil, nil]
else
[ Chef::Exceptions::FileTypeMismatch,
- "File #{path} exists, but is a #{file_type_string(@new_resource.path)}, set force_unlink to true to remove",
- "Assuming #{file_type_string(@new_resource.path)} at #{@new_resource.path} would have been removed by a previous resource"
+ "File #{path} exists, but is a #{file_type_string(new_resource.path)}, set force_unlink to true to remove",
+ "Assuming #{file_type_string(new_resource.path)} at #{new_resource.path} would have been removed by a previous resource",
]
end
end
@@ -266,8 +266,8 @@ class Chef
else
[ Chef::Exceptions::FileTypeMismatch,
"File #{path} exists, but is a symlink to #{real_path} which is a #{file_type_string(real_path)}. " +
- "Disable manage_symlink_source and set force_unlink to remove it.",
- "Assuming symlink #{path} or source file #{real_path} would have been fixed by a previous resource"
+ "Disable manage_symlink_source and set force_unlink to remove it.",
+ "Assuming symlink #{path} or source file #{real_path} would have been fixed by a previous resource",
]
end
rescue Errno::ELOOP
@@ -282,8 +282,8 @@ class Chef
def content
@content ||= begin
- load_current_resource if @current_resource.nil?
- @content_class.new(@new_resource, @current_resource, @run_context)
+ load_current_resource if current_resource.nil?
+ @content_class.new(new_resource, current_resource, @run_context)
end
end
@@ -312,11 +312,9 @@ class Chef
# like real_file? that follows (sane) symlinks
def symlink_to_real_file?(path)
- begin
- real_file?(::File.realpath(path))
- rescue Errno::ELOOP, Errno::ENOENT
- false
- end
+ real_file?(::File.realpath(path))
+ rescue Errno::ELOOP, Errno::ENOENT
+ false
end
# Similar to File.exist?, but also returns true in the case that the
@@ -344,7 +342,7 @@ class Chef
end
def do_validate_content
- if new_resource.checksum && tempfile && ( new_resource.checksum != tempfile_checksum )
+ if new_resource.checksum && tempfile && ( new_resource.checksum.downcase != tempfile_checksum )
raise Chef::Exceptions::ChecksumMismatch.new(short_cksum(new_resource.checksum), short_cksum(tempfile_checksum))
end
@@ -358,12 +356,12 @@ class Chef
end
def do_unlink
- if @new_resource.force_unlink
+ if new_resource.force_unlink
if needs_unlinking?
# unlink things that aren't normal files
- description = "unlink #{file_type_string(@new_resource.path)} at #{@new_resource.path}"
+ description = "unlink #{file_type_string(new_resource.path)} at #{new_resource.path}"
converge_by(description) do
- unlink(@new_resource.path)
+ unlink(new_resource.path)
end
end
end
@@ -371,15 +369,15 @@ class Chef
def do_create_file
if needs_creating?
- converge_by("create new file #{@new_resource.path}") do
- deployment_strategy.create(@new_resource.path)
- Chef::Log.info("#{@new_resource} created file #{@new_resource.path}")
+ converge_by("create new file #{new_resource.path}") do
+ deployment_strategy.create(new_resource.path)
+ Chef::Log.info("#{new_resource} created file #{new_resource.path}")
end
end
end
def do_backup(file = nil)
- Chef::Util::Backup.new(@new_resource, file).backup!
+ Chef::Util::Backup.new(new_resource, file).backup!
end
def diff
@@ -405,17 +403,17 @@ class Chef
end
# the file? on the next line suppresses the case in why-run when we have a not-file here that would have otherwise been removed
- if ::File.file?(@new_resource.path) && contents_changed?
- description = [ "update content in file #{@new_resource.path} from \
-#{short_cksum(@current_resource.checksum)} to #{short_cksum(tempfile_checksum)}" ]
+ if ::File.file?(new_resource.path) && contents_changed?
+ description = [ "update content in file #{new_resource.path} from \
+#{short_cksum(current_resource.checksum)} to #{short_cksum(tempfile_checksum)}" ]
# Hide the diff output if the resource is marked as a sensitive resource
- if @new_resource.sensitive
- @new_resource.diff("suppressed sensitive resource")
+ if new_resource.sensitive
+ new_resource.diff("suppressed sensitive resource")
description << "suppressed sensitive resource"
else
- diff.diff(@current_resource.path, tempfile.path)
- @new_resource.diff( diff.for_reporting ) unless needs_creating?
+ diff.diff(current_resource.path, tempfile.path)
+ new_resource.diff( diff.for_reporting ) unless needs_creating?
description << diff.for_output
end
@@ -437,7 +435,7 @@ class Chef
if resource_updated? && Chef::Config[:enable_selinux_file_permission_fixup]
if selinux_enabled?
converge_by("restore selinux security context") do
- restore_security_context(::File.realpath(@new_resource.path), recursive)
+ restore_security_context(::File.realpath(new_resource.path), recursive)
end
else
Chef::Log.debug "selinux utilities can not be found. Skipping selinux permission fixup."
@@ -454,19 +452,14 @@ class Chef
end
def contents_changed?
- Chef::Log.debug "calculating checksum of #{tempfile.path} to compare with #{@current_resource.checksum}"
- tempfile_checksum != @current_resource.checksum
+ Chef::Log.debug "calculating checksum of #{tempfile.path} to compare with #{current_resource.checksum}"
+ tempfile_checksum != current_resource.checksum
end
def tempfile
@tempfile ||= content.tempfile
end
- def short_cksum(checksum)
- return "none" if checksum.nil?
- checksum.slice(0,6)
- end
-
def load_resource_attributes_from_file(resource)
if Chef::Platform.windows?
# This is a work around for CHEF-3554.
@@ -475,7 +468,7 @@ class Chef
# reporting won't work for Windows.
return
end
- acl_scanner = ScanAccessControl.new(@new_resource, resource)
+ acl_scanner = ScanAccessControl.new(new_resource, resource)
acl_scanner.set_all!
end
diff --git a/lib/chef/provider/file/content.rb b/lib/chef/provider/file/content.rb
index f82bc49db4..1b60e10fea 100644
--- a/lib/chef/provider/file/content.rb
+++ b/lib/chef/provider/file/content.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/file_content_management/content_base'
-require 'chef/file_content_management/tempfile'
+require "chef/file_content_management/content_base"
+require "chef/file_content_management/tempfile"
class Chef
class Provider
diff --git a/lib/chef/provider/git.rb b/lib/chef/provider/git.rb
index 8418f22933..2907c20211 100644
--- a/lib/chef/provider/git.rb
+++ b/lib/chef/provider/git.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,87 +16,90 @@
# limitations under the License.
#
-require 'chef/exceptions'
-require 'chef/log'
-require 'chef/provider'
-require 'fileutils'
+require "chef/exceptions"
+require "chef/log"
+require "chef/provider"
+require "fileutils"
class Chef
class Provider
class Git < Chef::Provider
+ extend Forwardable
provides :git
+ def_delegator :new_resource, :destination, :cwd
+
def whyrun_supported?
true
end
def load_current_resource
@resolved_reference = nil
- @current_resource = Chef::Resource::Git.new(@new_resource.name)
+ @current_resource = Chef::Resource::Git.new(new_resource.name)
if current_revision = find_current_revision
- @current_resource.revision current_revision
+ current_resource.revision current_revision
end
end
def define_resource_requirements
# Parent directory of the target must exist.
requirements.assert(:checkout, :sync) do |a|
- dirname = ::File.dirname(@new_resource.destination)
+ dirname = ::File.dirname(cwd)
a.assertion { ::File.directory?(dirname) }
a.whyrun("Directory #{dirname} does not exist, this run will fail unless it has been previously created. Assuming it would have been created.")
a.failure_message(Chef::Exceptions::MissingParentDirectory,
- "Cannot clone #{@new_resource} to #{@new_resource.destination}, the enclosing directory #{dirname} does not exist")
+ "Cannot clone #{new_resource} to #{cwd}, the enclosing directory #{dirname} does not exist")
end
requirements.assert(:all_actions) do |a|
- a.assertion { !(@new_resource.revision =~ /^origin\//) }
+ a.assertion { !(new_resource.revision =~ /^origin\//) }
a.failure_message Chef::Exceptions::InvalidRemoteGitReference,
"Deploying remote branches is not supported. " +
- "Specify the remote branch as a local branch for " +
- "the git repository you're deploying from " +
- "(ie: '#{@new_resource.revision.gsub('origin/', '')}' rather than '#{@new_resource.revision}')."
+ "Specify the remote branch as a local branch for " +
+ "the git repository you're deploying from " +
+ "(ie: '#{new_resource.revision.gsub('origin/', '')}' rather than '#{new_resource.revision}')."
end
requirements.assert(:all_actions) do |a|
# this can't be recovered from in why-run mode, because nothing that
# we do in the course of a run is likely to create a valid target_revision
# if we can't resolve it up front.
- a.assertion { target_revision != nil }
+ a.assertion { !target_revision.nil? }
a.failure_message Chef::Exceptions::UnresolvableGitReference,
- "Unable to parse SHA reference for '#{@new_resource.revision}' in repository '#{@new_resource.repository}'. " +
+ "Unable to parse SHA reference for '#{new_resource.revision}' in repository '#{new_resource.repository}'. " +
"Verify your (case-sensitive) repository URL and revision.\n" +
- "`git ls-remote '#{@new_resource.repository}' '#{rev_search_pattern}'` output: #{@resolved_reference}"
+ "`git ls-remote '#{new_resource.repository}' '#{rev_search_pattern}'` output: #{@resolved_reference}"
end
end
def action_checkout
if target_dir_non_existent_or_empty?
clone
- if @new_resource.enable_checkout
+ if new_resource.enable_checkout
checkout
end
enable_submodules
add_remotes
else
- Chef::Log.debug "#{@new_resource} checkout destination #{@new_resource.destination} already exists or is a non-empty directory"
+ Chef::Log.debug "#{new_resource} checkout destination #{cwd} already exists or is a non-empty directory"
end
end
def action_export
action_checkout
- converge_by("complete the export by removing #{@new_resource.destination}.git after checkout") do
- FileUtils.rm_rf(::File.join(@new_resource.destination,".git"))
+ converge_by("complete the export by removing #{cwd}.git after checkout") do
+ FileUtils.rm_rf(::File.join(cwd, ".git"))
end
end
def action_sync
if existing_git_clone?
- Chef::Log.debug "#{@new_resource} current revision: #{@current_resource.revision} target revision: #{target_revision}"
+ Chef::Log.debug "#{new_resource} current revision: #{current_resource.revision} target revision: #{target_revision}"
unless current_revision_matches_target_revision?
fetch_updates
enable_submodules
- Chef::Log.info "#{@new_resource} updated to revision #{target_revision}"
+ Chef::Log.info "#{new_resource} updated to revision #{target_revision}"
end
add_remotes
else
@@ -105,31 +108,31 @@ class Chef
end
def git_minor_version
- @git_minor_version ||= Gem::Version.new(shell_out!('git --version', run_options).stdout.split.last)
+ @git_minor_version ||= Gem::Version.new( git("--version").stdout.split.last )
end
def existing_git_clone?
- ::File.exist?(::File.join(@new_resource.destination, ".git"))
+ ::File.exist?(::File.join(cwd, ".git"))
end
def target_dir_non_existent_or_empty?
- !::File.exist?(@new_resource.destination) || Dir.entries(@new_resource.destination).sort == ['.','..']
+ !::File.exist?(cwd) || Dir.entries(cwd).sort == [".", ".."]
end
def find_current_revision
- Chef::Log.debug("#{@new_resource} finding current git revision")
+ Chef::Log.debug("#{new_resource} finding current git revision")
if ::File.exist?(::File.join(cwd, ".git"))
# 128 is returned when we're not in a git repo. this is fine
- result = shell_out!('git rev-parse HEAD', :cwd => cwd, :returns => [0,128]).stdout.strip
+ result = git("rev-parse", "HEAD", cwd: cwd, returns: [0, 128]).stdout.strip
end
sha_hash?(result) ? result : nil
end
def add_remotes
- if (@new_resource.additional_remotes.length > 0)
- @new_resource.additional_remotes.each_pair do |remote_name, remote_url|
+ if new_resource.additional_remotes.length > 0
+ new_resource.additional_remotes.each_pair do |remote_name, remote_url|
converge_by("add remote #{remote_name} from #{remote_url}") do
- Chef::Log.info "#{@new_resource} adding git remote #{remote_name} = #{remote_url}"
+ Chef::Log.info "#{new_resource} adding git remote #{remote_name} = #{remote_url}"
setup_remote_tracking_branches(remote_name, remote_url)
end
end
@@ -137,62 +140,60 @@ class Chef
end
def clone
- converge_by("clone from #{@new_resource.repository} into #{@new_resource.destination}") do
- remote = @new_resource.remote
-
- args = []
- args << "-o #{remote}" unless remote == 'origin'
- args << "--depth #{@new_resource.depth}" if @new_resource.depth
- args << "--no-single-branch" if @new_resource.depth and git_minor_version >= Gem::Version.new('1.7.10')
-
- Chef::Log.info "#{@new_resource} cloning repo #{@new_resource.repository} to #{@new_resource.destination}"
-
- clone_cmd = "git clone #{args.join(' ')} \"#{@new_resource.repository}\" \"#{@new_resource.destination}\""
- shell_out!(clone_cmd, run_options)
+ converge_by("clone from #{new_resource.repository} into #{cwd}") do
+ remote = new_resource.remote
+
+ clone_cmd = ["clone"]
+ clone_cmd << "-o #{remote}" unless remote == "origin"
+ clone_cmd << "--depth #{new_resource.depth}" if new_resource.depth
+ clone_cmd << "--no-single-branch" if new_resource.depth && git_minor_version >= Gem::Version.new("1.7.10")
+ clone_cmd << "\"#{new_resource.repository}\""
+ clone_cmd << "\"#{cwd}\""
+
+ Chef::Log.info "#{new_resource} cloning repo #{new_resource.repository} to #{cwd}"
+ git clone_cmd
end
end
def checkout
sha_ref = target_revision
- converge_by("checkout ref #{sha_ref} branch #{@new_resource.revision}") do
+ converge_by("checkout ref #{sha_ref} branch #{new_resource.revision}") do
# checkout into a local branch rather than a detached HEAD
- shell_out!("git branch -f #{@new_resource.checkout_branch} #{sha_ref}", run_options(:cwd => @new_resource.destination))
- shell_out!("git checkout #{@new_resource.checkout_branch}", run_options(:cwd => @new_resource.destination))
- Chef::Log.info "#{@new_resource} checked out branch: #{@new_resource.revision} onto: #{@new_resource.checkout_branch} reference: #{sha_ref}"
+ git("branch", "-f", new_resource.checkout_branch, sha_ref, cwd: cwd)
+ git("checkout", new_resource.checkout_branch, cwd: cwd)
+ Chef::Log.info "#{new_resource} checked out branch: #{new_resource.revision} onto: #{new_resource.checkout_branch} reference: #{sha_ref}"
end
end
def enable_submodules
- if @new_resource.enable_submodules
- converge_by("enable git submodules for #{@new_resource}") do
- Chef::Log.info "#{@new_resource} synchronizing git submodules"
- command = "git submodule sync"
- shell_out!(command, run_options(:cwd => @new_resource.destination))
- Chef::Log.info "#{@new_resource} enabling git submodules"
+ if new_resource.enable_submodules
+ converge_by("enable git submodules for #{new_resource}") do
+ Chef::Log.info "#{new_resource} synchronizing git submodules"
+ git("submodule", "sync", cwd: cwd)
+ Chef::Log.info "#{new_resource} enabling git submodules"
# the --recursive flag means we require git 1.6.5+ now, see CHEF-1827
- command = "git submodule update --init --recursive"
- shell_out!(command, run_options(:cwd => @new_resource.destination))
+ git("submodule", "update", "--init", "--recursive", cwd: cwd)
end
end
end
def fetch_updates
- setup_remote_tracking_branches(@new_resource.remote, @new_resource.repository)
- converge_by("fetch updates for #{@new_resource.remote}") do
+ setup_remote_tracking_branches(new_resource.remote, new_resource.repository)
+ converge_by("fetch updates for #{new_resource.remote}") do
# since we're in a local branch already, just reset to specified revision rather than merge
- fetch_command = "git fetch #{@new_resource.remote} && git fetch #{@new_resource.remote} --tags && git reset --hard #{target_revision}"
Chef::Log.debug "Fetching updates from #{new_resource.remote} and resetting to revision #{target_revision}"
- shell_out!(fetch_command, run_options(:cwd => @new_resource.destination))
+ git("fetch", new_resource.remote, cwd: cwd)
+ git("fetch", new_resource.remote, "--tags", cwd: cwd)
+ git("reset", "--hard", target_revision, cwd: cwd)
end
end
def setup_remote_tracking_branches(remote_name, remote_url)
converge_by("set up remote tracking branches for #{remote_url} at #{remote_name}") do
- Chef::Log.debug "#{@new_resource} configuring remote tracking branches for repository #{remote_url} "+
- "at remote #{remote_name}"
- check_remote_command = "git config --get remote.#{remote_name}.url"
- remote_status = shell_out!(check_remote_command, run_options(:cwd => @new_resource.destination, :returns => [0,1,2]))
+ Chef::Log.debug "#{new_resource} configuring remote tracking branches for repository #{remote_url} " + "at remote #{remote_name}"
+ check_remote_command = ["config", "--get", "remote.#{remote_name}.url"]
+ remote_status = git(check_remote_command, cwd: cwd, returns: [0, 1, 2])
case remote_status.exitstatus
when 0, 2
# * Status 0 means that we already have a remote with this name, so we should update the url
@@ -200,13 +201,11 @@ class Chef
# * Status 2 means that we have multiple urls assigned to the same remote (not a good idea)
# which we can fix by replacing them all with our target url (hence the --replace-all option)
- if multiple_remotes?(remote_status) || !remote_matches?(remote_url,remote_status)
- update_remote_url_command = "git config --replace-all remote.#{remote_name}.url #{remote_url}"
- shell_out!(update_remote_url_command, run_options(:cwd => @new_resource.destination))
+ if multiple_remotes?(remote_status) || !remote_matches?(remote_url, remote_status)
+ git("config", "--replace-all", "remote.#{remote_name}.url", remote_url, cwd: cwd)
end
when 1
- add_remote_command = "git remote add #{remote_name} #{remote_url}"
- shell_out!(add_remote_command, run_options(:cwd => @new_resource.destination))
+ git("remote", "add", remote_name, remote_url, cwd: cwd)
end
end
end
@@ -220,13 +219,13 @@ class Chef
end
def current_revision_matches_target_revision?
- (!@current_resource.revision.nil?) && (target_revision.strip.to_i(16) == @current_resource.revision.strip.to_i(16))
+ (!current_resource.revision.nil?) && (target_revision.strip.to_i(16) == current_resource.revision.strip.to_i(16))
end
def target_revision
@target_revision ||= begin
- if sha_hash?(@new_resource.revision)
- @target_revision = @new_resource.revision
+ if sha_hash?(new_resource.revision)
+ @target_revision = new_resource.revision
else
@target_revision = remote_resolve_reference
end
@@ -236,7 +235,7 @@ class Chef
alias :revision_slug :target_revision
def remote_resolve_reference
- Chef::Log.debug("#{@new_resource} resolving remote reference")
+ Chef::Log.debug("#{new_resource} resolving remote reference")
# The sha pointed to by an annotated tag is identified by the
# '^{}' suffix appended to the tag. In order to resolve
# annotated tags, we have to search for "revision*" and
@@ -250,18 +249,18 @@ class Chef
# Using such a degenerate annotated tag would be very
# confusing. We avoid the issue by disallowing the use of
# annotated tags named 'HEAD'.
- if rev_search_pattern != 'HEAD'
- found = find_revision(refs, @new_resource.revision, '^{}')
+ if rev_search_pattern != "HEAD"
+ found = find_revision(refs, new_resource.revision, "^{}")
else
- found = refs_search(refs, 'HEAD')
+ found = refs_search(refs, "HEAD")
end
- found = find_revision(refs, @new_resource.revision) if found.empty?
+ found = find_revision(refs, new_resource.revision) if found.empty?
found.size == 1 ? found.first[0] : nil
end
- def find_revision(refs, revision, suffix="")
- found = refs_search(refs, rev_match_pattern('refs/tags/', revision) + suffix)
- found = refs_search(refs, rev_match_pattern('refs/heads/', revision) + suffix) if found.empty?
+ def find_revision(refs, revision, suffix = "")
+ found = refs_search(refs, rev_match_pattern("refs/tags/", revision) + suffix)
+ found = refs_search(refs, rev_match_pattern("refs/heads/", revision) + suffix) if found.empty?
found = refs_search(refs, revision + suffix) if found.empty?
found
end
@@ -275,16 +274,15 @@ class Chef
end
def rev_search_pattern
- if ['', 'HEAD'].include? @new_resource.revision
- 'HEAD'
+ if ["", "HEAD"].include? new_resource.revision
+ "HEAD"
else
- @new_resource.revision + '*'
+ new_resource.revision + "*"
end
end
def git_ls_remote(rev_pattern)
- command = git(%Q(ls-remote "#{@new_resource.repository}" "#{rev_pattern}"))
- shell_out!(command, run_options).stdout
+ git("ls-remote", "\"#{new_resource.repository}\"", "\"#{rev_pattern}\"").stdout
end
def refs_search(refs, pattern)
@@ -293,36 +291,38 @@ class Chef
private
- def run_options(run_opts={})
+ def run_options(run_opts = {})
env = {}
- if @new_resource.user
- run_opts[:user] = @new_resource.user
+ if new_resource.user
+ run_opts[:user] = new_resource.user
# Certain versions of `git` misbehave if git configuration is
# inaccessible in $HOME. We need to ensure $HOME matches the
# user who is executing `git` not the user running Chef.
- env['HOME'] = begin
- require 'etc'
- Etc.getpwnam(@new_resource.user).dir
+ env["HOME"] = begin
+ require "etc"
+ case new_resource.user
+ when Integer
+ Etc.getpwuid(new_resource.user).dir
+ else
+ Etc.getpwnam(new_resource.user.to_s).dir
+ end
rescue ArgumentError # user not found
- raise Chef::Exceptions::User, "Could not determine HOME for specified user '#{@new_resource.user}' for resource '#{@new_resource.name}'"
+ raise Chef::Exceptions::User, "Could not determine HOME for specified user '#{new_resource.user}' for resource '#{new_resource.name}'"
end
end
- run_opts[:group] = @new_resource.group if @new_resource.group
- env['GIT_SSH'] = @new_resource.ssh_wrapper if @new_resource.ssh_wrapper
- run_opts[:log_tag] = @new_resource.to_s
- run_opts[:timeout] = @new_resource.timeout if @new_resource.timeout
- env.merge!(@new_resource.environment) if @new_resource.environment
+ run_opts[:group] = new_resource.group if new_resource.group
+ env["GIT_SSH"] = new_resource.ssh_wrapper if new_resource.ssh_wrapper
+ run_opts[:log_tag] = new_resource.to_s
+ run_opts[:timeout] = new_resource.timeout if new_resource.timeout
+ env.merge!(new_resource.environment) if new_resource.environment
run_opts[:environment] = env unless env.empty?
run_opts
-
- end
-
- def cwd
- @new_resource.destination
end
- def git(*args)
- ["git", *args].compact.join(" ")
+ def git(*args, **run_opts)
+ git_command = ["git", args].compact.join(" ")
+ Chef::Log.debug "running #{git_command}"
+ shell_out!(git_command, run_options(run_opts))
end
def sha_hash?(string)
diff --git a/lib/chef/provider/group.rb b/lib/chef/provider/group.rb
index a1cf92058d..6751052ae4 100644
--- a/lib/chef/provider/group.rb
+++ b/lib/chef/provider/group.rb
@@ -1,6 +1,6 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'chef/provider'
-require 'chef/mixin/shell_out'
-require 'chef/mixin/command'
-require 'etc'
+require "chef/provider"
+require "chef/mixin/shell_out"
+require "chef/mixin/command"
+require "etc"
class Chef
class Provider
@@ -39,38 +39,38 @@ class Chef
end
def load_current_resource
- @current_resource = Chef::Resource::Group.new(@new_resource.name)
- @current_resource.group_name(@new_resource.group_name)
+ @current_resource = Chef::Resource::Group.new(new_resource.name)
+ current_resource.group_name(new_resource.group_name)
group_info = nil
begin
- group_info = Etc.getgrnam(@new_resource.group_name)
- rescue ArgumentError => e
+ group_info = Etc.getgrnam(new_resource.group_name)
+ rescue ArgumentError
@group_exists = false
- Chef::Log.debug("#{@new_resource} group does not exist")
+ Chef::Log.debug("#{new_resource} group does not exist")
end
if group_info
- @new_resource.gid(group_info.gid) unless @new_resource.gid
- @current_resource.gid(group_info.gid)
- @current_resource.members(group_info.mem)
+ new_resource.gid(group_info.gid) unless new_resource.gid
+ current_resource.gid(group_info.gid)
+ current_resource.members(group_info.mem)
end
- @current_resource
+ current_resource
end
def define_resource_requirements
requirements.assert(:modify) do |a|
a.assertion { @group_exists }
- a.failure_message(Chef::Exceptions::Group, "Cannot modify #{@new_resource} - group does not exist!")
- a.whyrun("Group #{@new_resource} does not exist. Unless it would have been created earlier in this run, this attempt to modify it would fail.")
+ a.failure_message(Chef::Exceptions::Group, "Cannot modify #{new_resource} - group does not exist!")
+ a.whyrun("Group #{new_resource} does not exist. Unless it would have been created earlier in this run, this attempt to modify it would fail.")
end
requirements.assert(:all_actions) do |a|
# Make sure that the resource doesn't contain any common
# user names in the members and exclude_members properties.
- if !@new_resource.members.nil? && !@new_resource.excluded_members.nil?
- common_members = @new_resource.members & @new_resource.excluded_members
+ if !new_resource.members.nil? && !new_resource.excluded_members.nil?
+ common_members = new_resource.members & new_resource.excluded_members
a.assertion { common_members.empty? }
a.failure_message(Chef::Exceptions::ConflictingMembersInGroup, "Attempting to both add and remove users from a group: '#{common_members.join(', ')}'")
# No why-run alternative
@@ -86,83 +86,85 @@ class Chef
# <false>:: If a change is not required
def compare_group
@change_desc = [ ]
- if @new_resource.gid.to_s != @current_resource.gid.to_s
- @change_desc << "change gid #{@current_resource.gid} to #{@new_resource.gid}"
+ if new_resource.gid.to_s != current_resource.gid.to_s
+ @change_desc << "change gid #{current_resource.gid} to #{new_resource.gid}"
end
- if(@new_resource.append)
+ if new_resource.append
missing_members = []
- @new_resource.members.each do |member|
+ new_resource.members.each do |member|
next if has_current_group_member?(member)
+ validate_member!(member)
missing_members << member
end
- if missing_members.length > 0
- @change_desc << "add missing member(s): #{missing_members.join(", ")}"
+ unless missing_members.empty?
+ @change_desc << "add missing member(s): #{missing_members.join(', ')}"
end
members_to_be_removed = []
- @new_resource.excluded_members.each do |member|
+ new_resource.excluded_members.each do |member|
if has_current_group_member?(member)
members_to_be_removed << member
end
end
- if members_to_be_removed.length > 0
- @change_desc << "remove existing member(s): #{members_to_be_removed.join(", ")}"
- end
- else
- if @new_resource.members != @current_resource.members
- @change_desc << "replace group members with new list of members"
+ unless members_to_be_removed.empty?
+ @change_desc << "remove existing member(s): #{members_to_be_removed.join(', ')}"
end
+ elsif new_resource.members != current_resource.members
+ @change_desc << "replace group members with new list of members"
end
!@change_desc.empty?
end
def has_current_group_member?(member)
- @current_resource.members.include?(member)
+ current_resource.members.include?(member)
+ end
+
+ def validate_member!(member)
+ # Sub-classes can do any validation if needed
+ # and raise an error if validation fails
+ true
end
def action_create
case @group_exists
when false
- converge_by("create group #{@new_resource.group_name}") do
+ converge_by("create group #{new_resource.group_name}") do
create_group
- Chef::Log.info("#{@new_resource} created")
+ Chef::Log.info("#{new_resource} created")
end
else
if compare_group
- converge_by(["alter group #{@new_resource.group_name}"] + change_desc) do
+ converge_by(["alter group #{new_resource.group_name}"] + change_desc) do
manage_group
- Chef::Log.info("#{@new_resource} altered")
+ Chef::Log.info("#{new_resource} altered")
end
end
end
end
def action_remove
- if @group_exists
- converge_by("remove group #{@new_resource.group_name}") do
- remove_group
- Chef::Log.info("#{@new_resource} removed")
- end
+ return unless @group_exists
+ converge_by("remove group #{new_resource.group_name}") do
+ remove_group
+ Chef::Log.info("#{new_resource} removed")
end
end
def action_manage
- if @group_exists && compare_group
- converge_by(["manage group #{@new_resource.group_name}"] + change_desc) do
- manage_group
- Chef::Log.info("#{@new_resource} managed")
- end
+ return unless @group_exists && compare_group
+ converge_by(["manage group #{new_resource.group_name}"] + change_desc) do
+ manage_group
+ Chef::Log.info("#{new_resource} managed")
end
end
def action_modify
- if compare_group
- converge_by(["modify group #{@new_resource.group_name}"] + change_desc) do
- manage_group
- Chef::Log.info("#{@new_resource} modified")
- end
+ return unless compare_group
+ converge_by(["modify group #{new_resource.group_name}"] + change_desc) do
+ manage_group
+ Chef::Log.info("#{new_resource} modified")
end
end
diff --git a/lib/chef/provider/group/aix.rb b/lib/chef/provider/group/aix.rb
index 92bb8cb225..2db6dc32a7 100644
--- a/lib/chef/provider/group/aix.rb
+++ b/lib/chef/provider/group/aix.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,13 @@
# limitations under the License.
#
-require 'chef/provider/group/groupadd'
-require 'chef/mixin/shell_out'
+require "chef/provider/group/groupadd"
class Chef
class Provider
class Group
class Aix < Chef::Provider::Group::Groupadd
- provides :group, platform: 'aix'
+ provides :group, platform: "aix"
def required_binaries
[ "/usr/bin/mkgroup",
@@ -33,48 +32,42 @@ class Chef
end
def create_group
- command = "mkgroup"
- command << set_options << " #{@new_resource.group_name}"
- run_command(:command => command)
+ shell_out_compact!("mkgroup", set_options, new_resource.group_name)
modify_group_members
end
def manage_group
- command = "chgroup"
options = set_options
- #Usage: chgroup [-R load_module] "attr=value" ... group
if options.size > 0
- command << options << " #{@new_resource.group_name}"
- run_command(:command => command)
+ shell_out_compact!("chgroup", options, new_resource.group_name)
end
modify_group_members
end
def remove_group
- run_command(:command => "rmgroup #{@new_resource.group_name}")
+ shell_out_compact!("rmgroup", new_resource.group_name)
end
def add_member(member)
- shell_out!("chgrpmem -m + #{member} #{@new_resource.group_name}")
+ shell_out_compact!("chgrpmem", "-m", "+", member, new_resource.group_name)
end
def set_members(members)
return if members.empty?
- shell_out!("chgrpmem -m = #{members.join(',')} #{@new_resource.group_name}")
+ shell_out_compact!("chgrpmem", "-m", "=", members.join(","), new_resource.group_name)
end
def remove_member(member)
- shell_out!("chgrpmem -m - #{member} #{@new_resource.group_name}")
+ shell_out_compact!("chgrpmem", "-m", "-", member, new_resource.group_name)
end
def set_options
- opts = ""
- { :gid => "id" }.sort { |a,b| a[0] <=> b[0] }.each do |field, option|
- if @current_resource.send(field) != @new_resource.send(field)
- if @new_resource.send(field)
- Chef::Log.debug("#{@new_resource} setting #{field.to_s} to #{@new_resource.send(field)}")
- opts << " '#{option}=#{@new_resource.send(field)}'"
- end
+ opts = []
+ { gid: "id" }.sort { |a, b| a[0] <=> b[0] }.each do |field, option|
+ next unless current_resource.send(field) != new_resource.send(field)
+ if new_resource.send(field)
+ Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field)}")
+ opts << "#{option}=#{new_resource.send(field)}"
end
end
opts
diff --git a/lib/chef/provider/group/dscl.rb b/lib/chef/provider/group/dscl.rb
index 9775ac8270..71e42b36ba 100644
--- a/lib/chef/provider/group/dscl.rb
+++ b/lib/chef/provider/group/dscl.rb
@@ -1,6 +1,6 @@
#
# Author:: Dreamcat4 (<dreamcat4@gmail.com>)
-# Copyright:: Copyright (c) 2009 OpsCode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,58 +21,61 @@ class Chef
class Group
class Dscl < Chef::Provider::Group
- provides :group, os: 'darwin'
+ provides :group, os: "darwin"
def dscl(*args)
- host = "."
- stdout_result = ""; stderr_result = ""; cmd = "dscl #{host} -#{args.join(' ')}"
- status = shell_out(cmd)
+ argdup = args.dup
+ cmd = argdup.shift
+ shellcmd = [ "dscl", ".", "-#{cmd}", argdup ]
+ status = shell_out_compact(shellcmd)
+ stdout_result = ""
+ stderr_result = ""
status.stdout.each_line { |line| stdout_result << line }
status.stderr.each_line { |line| stderr_result << line }
- return [cmd, status, stdout_result, stderr_result]
+ [shellcmd.flatten.compact.join(" "), status, stdout_result, stderr_result]
end
def safe_dscl(*args)
result = dscl(*args)
return "" if ( args.first =~ /^delete/ ) && ( result[1].exitstatus != 0 )
- raise(Chef::Exceptions::Group,"dscl error: #{result.inspect}") unless result[1].exitstatus == 0
- raise(Chef::Exceptions::Group,"dscl error: #{result.inspect}") if result[2] =~ /No such key: /
- return result[2]
+ raise(Chef::Exceptions::Group, "dscl error: #{result.inspect}") unless result[1].exitstatus == 0
+ raise(Chef::Exceptions::Group, "dscl error: #{result.inspect}") if result[2] =~ /No such key: /
+ result[2]
end
def load_current_resource
- @current_resource = Chef::Resource::Group.new(@new_resource.name)
- @current_resource.group_name(@new_resource.group_name)
+ @current_resource = Chef::Resource::Group.new(new_resource.name)
+ current_resource.group_name(new_resource.group_name)
group_info = nil
begin
- group_info = safe_dscl("read /Groups/#{@new_resource.group_name}")
+ group_info = safe_dscl("read", "/Groups/#{new_resource.group_name}")
rescue Chef::Exceptions::Group
@group_exists = false
- Chef::Log.debug("#{@new_resource} group does not exist")
+ Chef::Log.debug("#{new_resource} group does not exist")
end
if group_info
group_info.each_line do |line|
- key, val = line.split(': ')
+ key, val = line.split(": ")
val.strip! if val
case key.downcase
- when 'primarygroupid'
- @new_resource.gid(val) unless @new_resource.gid
- @current_resource.gid(val)
- when 'groupmembership'
- @current_resource.members(val.split(' '))
+ when "primarygroupid"
+ new_resource.gid(val) unless new_resource.gid
+ current_resource.gid(val)
+ when "groupmembership"
+ current_resource.members(val.split(" "))
end
end
end
- @current_resource
+ current_resource
end
# get a free GID greater than 200
- def get_free_gid(search_limit=1000)
+ def get_free_gid(search_limit = 1000)
gid = nil; next_gid_guess = 200
- groups_gids = safe_dscl("list /Groups gid")
- while(next_gid_guess < search_limit + 200)
+ groups_gids = safe_dscl("list", "/Groups", "gid")
+ while next_gid_guess < search_limit + 200
if groups_gids =~ Regexp.new("#{Regexp.escape(next_gid_guess.to_s)}\n")
next_gid_guess += 1
else
@@ -80,51 +83,51 @@ class Chef
break
end
end
- return gid || raise("gid not found. Exhausted. Searched #{search_limit} times")
+ gid || raise("gid not found. Exhausted. Searched #{search_limit} times")
end
def gid_used?(gid)
return false unless gid
- groups_gids = safe_dscl("list /Groups gid")
- !! ( groups_gids =~ Regexp.new("#{Regexp.escape(gid.to_s)}\n") )
+ groups_gids = safe_dscl("list", "/Groups", "gid")
+ !!( groups_gids =~ Regexp.new("#{Regexp.escape(gid.to_s)}\n") )
end
def set_gid
- @new_resource.gid(get_free_gid) if [nil,""].include? @new_resource.gid
- raise(Chef::Exceptions::Group,"gid is already in use") if gid_used?(@new_resource.gid)
- safe_dscl("create /Groups/#{@new_resource.group_name} PrimaryGroupID #{@new_resource.gid}")
+ new_resource.gid(get_free_gid) if [nil, ""].include? new_resource.gid
+ raise(Chef::Exceptions::Group, "gid is already in use") if gid_used?(new_resource.gid)
+ safe_dscl("create", "/Groups/#{new_resource.group_name}", "PrimaryGroupID", new_resource.gid)
end
def set_members
# First reset the memberships if the append is not set
- unless @new_resource.append
- Chef::Log.debug("#{@new_resource} removing group members #{@current_resource.members.join(' ')}") unless @current_resource.members.empty?
- safe_dscl("create /Groups/#{@new_resource.group_name} GroupMembers ''") # clear guid list
- safe_dscl("create /Groups/#{@new_resource.group_name} GroupMembership ''") # clear user list
- @current_resource.members([ ])
+ unless new_resource.append
+ Chef::Log.debug("#{new_resource} removing group members #{current_resource.members.join(' ')}") unless current_resource.members.empty?
+ safe_dscl("create", "/Groups/#{new_resource.group_name}", "GroupMembers", "") # clear guid list
+ safe_dscl("create", "/Groups/#{new_resource.group_name}", "GroupMembership", "") # clear user list
+ current_resource.members([ ])
end
# Add any members that need to be added
- if @new_resource.members && !@new_resource.members.empty?
+ if new_resource.members && !new_resource.members.empty?
members_to_be_added = [ ]
- @new_resource.members.each do |member|
- members_to_be_added << member if !@current_resource.members.include?(member)
+ new_resource.members.each do |member|
+ members_to_be_added << member unless current_resource.members.include?(member)
end
unless members_to_be_added.empty?
- Chef::Log.debug("#{@new_resource} setting group members #{members_to_be_added.join(', ')}")
- safe_dscl("append /Groups/#{@new_resource.group_name} GroupMembership #{members_to_be_added.join(' ')}")
+ Chef::Log.debug("#{new_resource} setting group members #{members_to_be_added.join(', ')}")
+ safe_dscl("append", "/Groups/#{new_resource.group_name}", "GroupMembership", *members_to_be_added)
end
end
# Remove any members that need to be removed
- if @new_resource.excluded_members && !@new_resource.excluded_members.empty?
+ if new_resource.excluded_members && !new_resource.excluded_members.empty?
members_to_be_removed = [ ]
- @new_resource.excluded_members.each do |member|
- members_to_be_removed << member if @current_resource.members.include?(member)
+ new_resource.excluded_members.each do |member|
+ members_to_be_removed << member if current_resource.members.include?(member)
end
unless members_to_be_removed.empty?
- Chef::Log.debug("#{@new_resource} removing group members #{members_to_be_removed.join(', ')}")
- safe_dscl("delete /Groups/#{@new_resource.group_name} GroupMembership #{members_to_be_removed.join(' ')}")
+ Chef::Log.debug("#{new_resource} removing group members #{members_to_be_removed.join(', ')}")
+ safe_dscl("delete", "/Groups/#{new_resource.group_name}", "GroupMembership", *members_to_be_removed)
end
end
end
@@ -132,8 +135,8 @@ class Chef
def define_resource_requirements
super
requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/usr/bin/dscl") }
- a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/dscl for #{@new_resource.name}"
+ a.assertion { ::File.exist?("/usr/bin/dscl") }
+ a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/dscl for #{new_resource.name}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
end
@@ -145,24 +148,24 @@ class Chef
end
def manage_group
- if @new_resource.group_name && (@current_resource.group_name != @new_resource.group_name)
+ if new_resource.group_name && (current_resource.group_name != new_resource.group_name)
dscl_create_group
end
- if @new_resource.gid && (@current_resource.gid != @new_resource.gid)
+ if new_resource.gid && (current_resource.gid != new_resource.gid)
set_gid
end
- if @new_resource.members || @new_resource.excluded_members
+ if new_resource.members || new_resource.excluded_members
set_members
end
end
def dscl_create_group
- safe_dscl("create /Groups/#{@new_resource.group_name}")
- safe_dscl("create /Groups/#{@new_resource.group_name} Password '*'")
+ safe_dscl("create", "/Groups/#{new_resource.group_name}")
+ safe_dscl("create", "/Groups/#{new_resource.group_name}", "Password", "*")
end
def remove_group
- safe_dscl("delete /Groups/#{@new_resource.group_name}")
+ safe_dscl("delete", "/Groups/#{new_resource.group_name}")
end
end
end
diff --git a/lib/chef/provider/group/gpasswd.rb b/lib/chef/provider/group/gpasswd.rb
index 432c524acd..d8aff10d5b 100644
--- a/lib/chef/provider/group/gpasswd.rb
+++ b/lib/chef/provider/group/gpasswd.rb
@@ -1,6 +1,6 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/provider/group/groupadd'
+require "chef/provider/group/groupadd"
class Chef
class Provider
@@ -31,26 +31,26 @@ class Chef
def define_resource_requirements
super
requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/usr/bin/gpasswd") }
- a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/gpasswd for #{@new_resource}"
+ a.assertion { ::File.exist?("/usr/bin/gpasswd") }
+ a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/gpasswd for #{new_resource}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
end
def set_members(members)
- unless members.empty?
- shell_out!("gpasswd -M #{members.join(',')} #{@new_resource.group_name}")
+ if members.empty?
+ shell_out_compact!("gpasswd", "-M", "", new_resource.group_name)
else
- shell_out!("gpasswd -M \"\" #{@new_resource.group_name}")
+ shell_out_compact!("gpasswd", "-M", members.join(","), new_resource.group_name)
end
end
def add_member(member)
- shell_out!("gpasswd -a #{member} #{@new_resource.group_name}")
+ shell_out_compact!("gpasswd", "-a", member, new_resource.group_name)
end
def remove_member(member)
- shell_out!("gpasswd -d #{member} #{@new_resource.group_name}")
+ shell_out_compact!("gpasswd", "-d", member, new_resource.group_name)
end
end
end
diff --git a/lib/chef/provider/group/groupadd.rb b/lib/chef/provider/group/groupadd.rb
index cb480aab54..f73c3b3be9 100644
--- a/lib/chef/provider/group/groupadd.rb
+++ b/lib/chef/provider/group/groupadd.rb
@@ -1,6 +1,6 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,8 +35,8 @@ class Chef
super
required_binaries.each do |required_binary|
requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?(required_binary) }
- a.failure_message Chef::Exceptions::Group, "Could not find binary #{required_binary} for #{@new_resource}"
+ a.assertion { ::File.exist?(required_binary) }
+ a.failure_message Chef::Exceptions::Group, "Could not find binary #{required_binary} for #{new_resource}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
end
@@ -44,67 +44,62 @@ class Chef
# Create the group
def create_group
- command = "groupadd"
- command << set_options
- command << groupadd_options
- run_command(:command => command)
+ shell_out_compact!("groupadd", set_options, groupadd_options)
modify_group_members
end
# Manage the group when it already exists
def manage_group
- command = "groupmod"
- command << set_options
- run_command(:command => command)
+ shell_out_compact!("groupmod", set_options)
modify_group_members
end
# Remove the group
def remove_group
- run_command(:command => "groupdel #{@new_resource.group_name}")
+ shell_out_compact!("groupdel", new_resource.group_name)
end
def modify_group_members
- if @new_resource.append
- if @new_resource.members && !@new_resource.members.empty?
+ if new_resource.append
+ if new_resource.members && !new_resource.members.empty?
members_to_be_added = [ ]
- @new_resource.members.each do |member|
- members_to_be_added << member if !@current_resource.members.include?(member)
+ new_resource.members.each do |member|
+ members_to_be_added << member unless current_resource.members.include?(member)
end
members_to_be_added.each do |member|
- Chef::Log.debug("#{@new_resource} appending member #{member} to group #{@new_resource.group_name}")
+ Chef::Log.debug("#{new_resource} appending member #{member} to group #{new_resource.group_name}")
add_member(member)
end
end
- if @new_resource.excluded_members && !@new_resource.excluded_members.empty?
+ if new_resource.excluded_members && !new_resource.excluded_members.empty?
members_to_be_removed = [ ]
- @new_resource.excluded_members.each do |member|
- members_to_be_removed << member if @current_resource.members.include?(member)
+ new_resource.excluded_members.each do |member|
+ members_to_be_removed << member if current_resource.members.include?(member)
end
members_to_be_removed.each do |member|
- Chef::Log.debug("#{@new_resource} removing member #{member} from group #{@new_resource.group_name}")
+ Chef::Log.debug("#{new_resource} removing member #{member} from group #{new_resource.group_name}")
remove_member(member)
end
end
else
- members_description = @new_resource.members.empty? ? "none" : @new_resource.members.join(", ")
- Chef::Log.debug("#{@new_resource} setting group members to: #{members_description}")
- set_members(@new_resource.members)
+ members_description = new_resource.members.empty? ? "none" : new_resource.members.join(", ")
+ Chef::Log.debug("#{new_resource} setting group members to: #{members_description}")
+ set_members(new_resource.members)
end
end
def add_member(member)
- raise Chef::Exceptions::Group, "you must override add_member in #{self.to_s}"
+ raise Chef::Exceptions::Group, "you must override add_member in #{self}"
end
def remove_member(member)
- raise Chef::Exceptions::Group, "you must override remove_member in #{self.to_s}"
+ raise Chef::Exceptions::Group, "you must override remove_member in #{self}"
end
def set_members(members)
- raise Chef::Exceptions::Group, "you must override set_members in #{self.to_s}"
+ raise Chef::Exceptions::Group, "you must override set_members in #{self}"
end
# Little bit of magic as per Adam's useradd provider to pull the assign the command line flags
@@ -112,22 +107,23 @@ class Chef
# ==== Returns
# <string>:: A string containing the option and then the quoted value
def set_options
- opts = ""
- { :gid => "-g" }.sort { |a,b| a[0] <=> b[0] }.each do |field, option|
- if @current_resource.send(field) != @new_resource.send(field)
- if @new_resource.send(field)
- opts << " #{option} '#{@new_resource.send(field)}'"
- Chef::Log.debug("#{@new_resource} set #{field.to_s} to #{@new_resource.send(field)}")
- end
- end
+ opts = []
+ { gid: "-g" }.sort { |a, b| a[0] <=> b[0] }.each do |field, option|
+ next unless current_resource.send(field) != new_resource.send(field)
+ next unless new_resource.send(field)
+ opts << option
+ opts << new_resource.send(field)
+ Chef::Log.debug("#{new_resource} set #{field} to #{new_resource.send(field)}")
end
- opts << " #{@new_resource.group_name}"
+ opts << new_resource.group_name
+ opts
end
def groupadd_options
- opts = ''
- opts << " -r" if @new_resource.system
- opts << " -o" if @new_resource.non_unique
+ opts = []
+ # Solaris doesn't support system groups.
+ opts << "-r" if new_resource.system && !node.platform?("solaris2")
+ opts << "-o" if new_resource.non_unique
opts
end
diff --git a/lib/chef/provider/group/groupmod.rb b/lib/chef/provider/group/groupmod.rb
index 82b68b8672..01581e4863 100644
--- a/lib/chef/provider/group/groupmod.rb
+++ b/lib/chef/provider/group/groupmod.rb
@@ -1,6 +1,6 @@
#
# Author:: Dan Crosta (<dcrosta@late.am>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,33 +21,31 @@ class Chef
class Group
class Groupmod < Chef::Provider::Group
- provides :group, os: 'netbsd'
+ provides :group, os: "netbsd"
def load_current_resource
super
- [ "group", "user" ].each do |binary|
- raise Chef::Exceptions::Group, "Could not find binary /usr/sbin/#{binary} for #{@new_resource}" unless ::File.exists?("/usr/sbin/#{binary}")
+ %w{group user}.each do |binary|
+ raise Chef::Exceptions::Group, "Could not find binary /usr/sbin/#{binary} for #{new_resource}" unless ::File.exist?("/usr/sbin/#{binary}")
end
end
# Create the group
def create_group
- command = "group add"
- command << set_options
- shell_out!(command)
+ shell_out_compact!("group", "add", set_options)
- add_group_members(@new_resource.members)
+ add_group_members(new_resource.members)
end
# Manage the group when it already exists
def manage_group
- if @new_resource.append
+ if new_resource.append
members_to_be_added = [ ]
- if @new_resource.excluded_members && !@new_resource.excluded_members.empty?
+ if new_resource.excluded_members && !new_resource.excluded_members.empty?
# First find out if any member needs to be removed
members_to_be_removed = [ ]
- @new_resource.excluded_members.each do |member|
- members_to_be_removed << member if @current_resource.members.include?(member)
+ new_resource.excluded_members.each do |member|
+ members_to_be_removed << member if current_resource.members.include?(member)
end
unless members_to_be_removed.empty?
@@ -56,39 +54,39 @@ class Chef
# Capture the members we need to add in
# members_to_be_added to be added later on.
- @current_resource.members.each do |member|
+ current_resource.members.each do |member|
members_to_be_added << member unless members_to_be_removed.include?(member)
end
end
end
- if @new_resource.members && !@new_resource.members.empty?
- @new_resource.members.each do |member|
- members_to_be_added << member if !@current_resource.members.include?(member)
+ if new_resource.members && !new_resource.members.empty?
+ new_resource.members.each do |member|
+ members_to_be_added << member unless current_resource.members.include?(member)
end
end
- Chef::Log.debug("#{@new_resource} not changing group members, the group has no members to add") if members_to_be_added.empty?
+ Chef::Log.debug("#{new_resource} not changing group members, the group has no members to add") if members_to_be_added.empty?
add_group_members(members_to_be_added)
else
# We are resetting the members of a group so use the same trick
reset_group_membership
- Chef::Log.debug("#{@new_resource} setting group members to: none") if @new_resource.members.empty?
- add_group_members(@new_resource.members)
+ Chef::Log.debug("#{new_resource} setting group members to: none") if new_resource.members.empty?
+ add_group_members(new_resource.members)
end
end
# Remove the group
def remove_group
- shell_out!("group del #{@new_resource.group_name}")
+ shell_out_compact!("group", "del", new_resource.group_name)
end
# Adds a list of usernames to the group using `user mod`
def add_group_members(members)
- Chef::Log.debug("#{@new_resource} adding members #{members.join(', ')}") if !members.empty?
+ Chef::Log.debug("#{new_resource} adding members #{members.join(', ')}") unless members.empty?
members.each do |user|
- shell_out!("user mod -G #{@new_resource.group_name} #{user}")
+ shell_out_compact!("user", "mod", "-G", new_resource.group_name, user)
end
end
@@ -96,30 +94,27 @@ class Chef
# "<name>_bak", create a new group with the same GID and
# "<name>", then set correct members on that group
def reset_group_membership
- rename = "group mod -n #{@new_resource.group_name}_bak #{@new_resource.group_name}"
- shell_out!(rename)
+ shell_out_compact!("group", "mod", "-n", "#{new_resource.group_name}_bak", new_resource.group_name)
- create = "group add"
- create << set_options(:overwrite_gid => true)
- shell_out!(create)
+ shell_out_compact!("group", "add", set_options(overwrite_gid: true))
- remove = "group del #{@new_resource.group_name}_bak"
- shell_out!(remove)
+ shell_out_compact!("group", "del", "#{new_resource.group_name}_bak")
end
# Little bit of magic as per Adam's useradd provider to pull and assign the command line flags
#
# ==== Returns
# <string>:: A string containing the option and then the quoted value
- def set_options(overwrite_gid=false)
- opts = ""
- if overwrite_gid || @new_resource.gid && (@current_resource.gid != @new_resource.gid)
- opts << " -g '#{@new_resource.gid}'"
+ def set_options(overwrite_gid = false)
+ opts = []
+ if overwrite_gid || new_resource.gid && (current_resource.gid != new_resource.gid)
+ opts << "-g"
+ opts << new_resource.gid
end
if overwrite_gid
- opts << " -o"
+ opts << "-o"
end
- opts << " #{@new_resource.group_name}"
+ opts << new_resource.group_name
opts
end
end
diff --git a/lib/chef/provider/group/pw.rb b/lib/chef/provider/group/pw.rb
index 5b5c8136f1..115ccf3714 100644
--- a/lib/chef/provider/group/pw.rb
+++ b/lib/chef/provider/group/pw.rb
@@ -1,6 +1,6 @@
#
# Author:: Stephen Haynes (<sh@nomitor.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@ class Chef
class Provider
class Group
class Pw < Chef::Provider::Group
- provides :group, platform: 'freebsd'
+ provides :group, platform: "freebsd"
def load_current_resource
super
@@ -30,46 +30,42 @@ class Chef
super
requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/usr/sbin/pw") }
- a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/pw for #{@new_resource}"
+ a.assertion { ::File.exist?("/usr/sbin/pw") }
+ a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/pw for #{new_resource}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
end
# Create the group
def create_group
- command = "pw groupadd"
- command << set_options
-
- unless @new_resource.members.empty?
+ command = [ "pw", "groupadd", set_options ]
+ unless new_resource.members.empty?
# pw group[add|mod] -M is used to set the full membership list on a
# new or existing group. Because pw groupadd does not support the -m
# and -d options used by manage_group, we treat group creation as a
# special case and use -M.
- Chef::Log.debug("#{@new_resource} setting group members: #{@new_resource.members.join(',')}")
- command += " -M #{@new_resource.members.join(',')}"
+ Chef::Log.debug("#{new_resource} setting group members: #{new_resource.members.join(',')}")
+ command += [ "-M", new_resource.members.join(",") ]
end
- run_command(:command => command)
+ shell_out_compact!(command)
end
# Manage the group when it already exists
def manage_group
- command = "pw groupmod"
- command << set_options
member_options = set_members_options
if member_options.empty?
- run_command(:command => command)
+ shell_out_compact!("pw", "groupmod", set_options)
else
member_options.each do |option|
- run_command(:command => command + option)
+ shell_out_compact!("pw", "groupmod", set_options, option)
end
end
end
# Remove the group
def remove_group
- run_command(:command => "pw groupdel #{@new_resource.group_name}")
+ shell_out_compact!("pw", "groupdel", new_resource.group_name)
end
# Little bit of magic as per Adam's useradd provider to pull and assign the command line flags
@@ -77,10 +73,11 @@ class Chef
# ==== Returns
# <string>:: A string containing the option and then the quoted value
def set_options
- opts = " #{@new_resource.group_name}"
- if @new_resource.gid && (@current_resource.gid != @new_resource.gid)
- Chef::Log.debug("#{@new_resource}: current gid (#{@current_resource.gid}) doesnt match target gid (#{@new_resource.gid}), changing it")
- opts << " -g '#{@new_resource.gid}'"
+ opts = [ new_resource.group_name ]
+ if new_resource.gid && (current_resource.gid != new_resource.gid)
+ Chef::Log.debug("#{new_resource}: current gid (#{current_resource.gid}) doesnt match target gid (#{new_resource.gid}), changing it")
+ opts << "-g"
+ opts << new_resource.gid
end
opts
end
@@ -91,26 +88,26 @@ class Chef
members_to_be_added = [ ]
members_to_be_removed = [ ]
- if @new_resource.append
+ if new_resource.append
# Append is set so we will only add members given in the
# members list and remove members given in the
# excluded_members list.
- if @new_resource.members && !@new_resource.members.empty?
- @new_resource.members.each do |member|
- members_to_be_added << member if !@current_resource.members.include?(member)
+ if new_resource.members && !new_resource.members.empty?
+ new_resource.members.each do |member|
+ members_to_be_added << member unless current_resource.members.include?(member)
end
end
- if @new_resource.excluded_members && !@new_resource.excluded_members.empty?
- @new_resource.excluded_members.each do |member|
- members_to_be_removed << member if @current_resource.members.include?(member)
+ if new_resource.excluded_members && !new_resource.excluded_members.empty?
+ new_resource.excluded_members.each do |member|
+ members_to_be_removed << member if current_resource.members.include?(member)
end
end
else
# Append is not set so we're resetting the membership of
# the group to the given members.
- members_to_be_added = @new_resource.members.dup
- @current_resource.members.each do |member|
+ members_to_be_added = new_resource.members.dup
+ current_resource.members.each do |member|
# No need to re-add a member if it's present in the new
# list of members
if members_to_be_added.include? member
@@ -122,13 +119,13 @@ class Chef
end
unless members_to_be_added.empty?
- Chef::Log.debug("#{@new_resource} adding group members: #{members_to_be_added.join(',')}")
- opts << " -m #{members_to_be_added.join(',')}"
+ Chef::Log.debug("#{new_resource} adding group members: #{members_to_be_added.join(',')}")
+ opts << [ "-m", members_to_be_added.join(",") ]
end
unless members_to_be_removed.empty?
- Chef::Log.debug("#{@new_resource} removing group members: #{members_to_be_removed.join(',')}")
- opts << " -d #{members_to_be_removed.join(',')}"
+ Chef::Log.debug("#{new_resource} removing group members: #{members_to_be_removed.join(',')}")
+ opts << [ "-d", members_to_be_removed.join(",") ]
end
opts
diff --git a/lib/chef/provider/group/suse.rb b/lib/chef/provider/group/suse.rb
index b47ea33e80..0790d2c2d9 100644
--- a/lib/chef/provider/group/suse.rb
+++ b/lib/chef/provider/group/suse.rb
@@ -1,6 +1,6 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,15 @@
# limitations under the License.
#
-require 'chef/provider/group/groupadd'
+require "chef/provider/group/groupadd"
+require "etc"
class Chef
class Provider
class Group
class Suse < Chef::Provider::Group::Groupadd
- provides :group, platform: 'opensuse', platform_version: '< 12.3'
- provides :group, platform: 'suse', platform_version: '< 12.0'
+ provides :group, platform: "opensuse", platform_version: "< 12.3"
+ provides :group, platform: "suse", platform_version: "< 12.0"
def load_current_resource
super
@@ -32,28 +33,48 @@ class Chef
def define_resource_requirements
super
requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/usr/sbin/groupmod") }
- a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/groupmod for #{@new_resource.name}"
+ a.assertion { ::File.exist?("/usr/sbin/groupmod") }
+ a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/groupmod for #{new_resource.name}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
+
+ requirements.assert(:create, :manage, :modify) do |a|
+ a.assertion do
+ begin
+ to_add(new_resource.members).all? { |member| Etc.getpwnam(member) }
+ rescue
+ false
+ end
+ end
+ a.failure_message Chef::Exceptions::Group, "Could not add users #{to_add(new_resource.members).join(', ')} to #{new_resource.group_name}: one of these users does not exist"
+ a.whyrun "Could not find one of these users: #{to_add(new_resource.members).join(', ')}. Assuming it will be created by a prior step"
+ end
end
def set_members(members)
- unless @current_resource.members.empty?
- shell_out!("groupmod -R #{@current_resource.members.join(',')} #{@new_resource.group_name}")
+ to_remove(members).each do |member|
+ remove_member(member)
end
- unless members.empty?
- shell_out!("groupmod -A #{members.join(',')} #{@new_resource.group_name}")
+ to_add(members).each do |member|
+ add_member(member)
end
end
+ def to_add(members)
+ members - current_resource.members
+ end
+
def add_member(member)
- shell_out!("groupmod -A #{member} #{@new_resource.group_name}")
+ shell_out_compact!("groupmod", "-A", member, new_resource.group_name)
+ end
+
+ def to_remove(members)
+ current_resource.members - members
end
def remove_member(member)
- shell_out!("groupmod -R #{member} #{@new_resource.group_name}")
+ shell_out_compact!("groupmod", "-R", member, new_resource.group_name)
end
end
diff --git a/lib/chef/provider/group/usermod.rb b/lib/chef/provider/group/usermod.rb
index d78d42d6e1..3874f7b4de 100644
--- a/lib/chef/provider/group/usermod.rb
+++ b/lib/chef/provider/group/usermod.rb
@@ -1,6 +1,6 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'chef/provider/group/groupadd'
+require "chef/provider/group/groupadd"
class Chef
class Provider
class Group
class Usermod < Chef::Provider::Group::Groupadd
- provides :group, os: %w(openbsd solaris2 hpux)
+ provides :group, os: %w{openbsd solaris2 hpux}
provides :group, platform: "opensuse"
def load_current_resource
@@ -34,20 +34,20 @@ class Chef
super
requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/usr/sbin/usermod") }
- a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/usermod for #{@new_resource}"
+ a.assertion { ::File.exist?("/usr/sbin/usermod") }
+ a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/usermod for #{new_resource}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
requirements.assert(:modify, :manage) do |a|
- a.assertion { @new_resource.members.empty? || @new_resource.append }
- a.failure_message Chef::Exceptions::Group, "setting group members directly is not supported by #{self.to_s}, must set append true in group"
+ a.assertion { new_resource.members.empty? || new_resource.append }
+ a.failure_message Chef::Exceptions::Group, "setting group members directly is not supported by #{self}, must set append true in group"
# No whyrun alternative - this action is simply not supported.
end
requirements.assert(:all_actions) do |a|
- a.assertion { @new_resource.excluded_members.empty? }
- a.failure_message Chef::Exceptions::Group, "excluded_members is not supported by #{self.to_s}"
+ a.assertion { new_resource.excluded_members.empty? }
+ a.failure_message Chef::Exceptions::Group, "excluded_members is not supported by #{self}"
# No whyrun alternative - this action is simply not supported.
end
end
@@ -57,23 +57,22 @@ class Chef
# This provider only supports adding members with
# append. Only if the action is create we will go
# ahead and add members.
- if @new_resource.action == :create
- members.each do |member|
- add_member(member)
- end
- else
- raise Chef::Exceptions::UnsupportedAction, "Setting members directly is not supported by #{self.to_s}"
+ unless new_resource.action.include?(:create)
+ raise Chef::Exceptions::UnsupportedAction, "Setting members directly is not supported by #{self}"
+ end
+ members.each do |member|
+ add_member(member)
end
end
def add_member(member)
- shell_out!("usermod #{append_flags} #{@new_resource.group_name} #{member}")
+ shell_out_compact!("usermod", append_flags, new_resource.group_name, member)
end
def remove_member(member)
# This provider only supports adding members with
# append. This function should never be called.
- raise Chef::Exceptions::UnsupportedAction, "Removing members members is not supported by #{self.to_s}"
+ raise Chef::Exceptions::UnsupportedAction, "Removing members members is not supported by #{self}"
end
def append_flags
@@ -81,7 +80,7 @@ class Chef
when "openbsd", "netbsd", "aix", "solaris2", "smartos", "omnios"
"-G"
when "solaris", "suse", "opensuse"
- "-a -G"
+ [ "-a", "-G" ]
end
end
diff --git a/lib/chef/provider/group/windows.rb b/lib/chef/provider/group/windows.rb
index 46d8afc7f6..c0026bf368 100644
--- a/lib/chef/provider/group/windows.rb
+++ b/lib/chef/provider/group/windows.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/provider/user'
+require "chef/provider/user"
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
- require 'chef/util/windows/net_group'
+ require "chef/util/windows/net_group"
end
class Chef
@@ -26,30 +26,30 @@ class Chef
class Group
class Windows < Chef::Provider::Group
- provides :group, os: 'windows'
+ provides :group, os: "windows"
- def initialize(new_resource,run_context)
+ def initialize(new_resource, run_context)
super
- @net_group = Chef::Util::Windows::NetGroup.new(@new_resource.group_name)
+ @net_group = Chef::Util::Windows::NetGroup.new(new_resource.group_name)
end
def load_current_resource
- @current_resource = Chef::Resource::Group.new(@new_resource.name)
- @current_resource.group_name(@new_resource.group_name)
+ @current_resource = Chef::Resource::Group.new(new_resource.name)
+ current_resource.group_name(new_resource.group_name)
members = nil
begin
members = @net_group.local_get_members
- rescue => e
+ rescue
@group_exists = false
- Chef::Log.debug("#{@new_resource} group does not exist")
+ Chef::Log.debug("#{new_resource} group does not exist")
end
if members
- @current_resource.members(members)
+ current_resource.members(members)
end
- @current_resource
+ current_resource
end
def create_group
@@ -58,10 +58,10 @@ class Chef
end
def manage_group
- if @new_resource.append
+ if new_resource.append
members_to_be_added = [ ]
- @new_resource.members.each do |member|
- members_to_be_added << member if ! has_current_group_member?(member)
+ new_resource.members.each do |member|
+ members_to_be_added << member if !has_current_group_member?(member) && validate_member!(member)
end
# local_add_members will raise ERROR_MEMBER_IN_ALIAS if a
@@ -69,29 +69,40 @@ class Chef
@net_group.local_add_members(members_to_be_added) unless members_to_be_added.empty?
members_to_be_removed = [ ]
- @new_resource.excluded_members.each do |member|
- member_sid = local_group_name_to_sid(member)
+ new_resource.excluded_members.each do |member|
+ lookup_account_name(member)
members_to_be_removed << member if has_current_group_member?(member)
end
@net_group.local_delete_members(members_to_be_removed) unless members_to_be_removed.empty?
else
- @net_group.local_set_members(@new_resource.members)
+ @net_group.local_set_members(new_resource.members)
end
end
def has_current_group_member?(member)
- member_sid = local_group_name_to_sid(member)
- @current_resource.members.include?(member_sid)
+ member_sid = lookup_account_name(member)
+ current_resource.members.include?(member_sid)
end
def remove_group
@net_group.local_delete
end
- def local_group_name_to_sid(group_name)
- locally_qualified_name = group_name.include?("\\") ? group_name : "#{ENV['COMPUTERNAME']}\\#{group_name}"
- Chef::ReservedNames::Win32::Security.lookup_account_name(locally_qualified_name)[1].to_s
+ def locally_qualified_name(account_name)
+ account_name.include?("\\") ? account_name : "#{ENV['COMPUTERNAME']}\\#{account_name}"
end
+
+ def validate_member!(member)
+ Chef::ReservedNames::Win32::Security.lookup_account_name(locally_qualified_name(member))[1].to_s
+ end
+
+ def lookup_account_name(account_name)
+ Chef::ReservedNames::Win32::Security.lookup_account_name(locally_qualified_name(account_name))[1].to_s
+ rescue Chef::Exceptions::Win32APIError
+ Chef::Log.warn("SID for '#{locally_qualified_name(account_name)}' could not be found")
+ ""
+ end
+
end
end
end
diff --git a/lib/chef/provider/http_request.rb b/lib/chef/provider/http_request.rb
index 61aff434ed..eaca17a972 100644
--- a/lib/chef/provider/http_request.rb
+++ b/lib/chef/provider/http_request.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'tempfile'
-require 'chef/http/simple'
+require "tempfile"
+require "chef/http/simple"
class Chef
class Provider
@@ -32,90 +32,90 @@ class Chef
end
def load_current_resource
- @http = Chef::HTTP::Simple.new(@new_resource.url)
+ @http = Chef::HTTP::Simple.new(new_resource.url)
end
- # Send a HEAD request to @new_resource.url
+ # Send a HEAD request to new_resource.url
def action_head
- message = check_message(@new_resource.message)
+ message = check_message(new_resource.message)
# CHEF-4762: we expect a nil return value from Chef::HTTP for a "200 Success" response
# and false for a "304 Not Modified" response
modified = @http.head(
- "#{@new_resource.url}",
- @new_resource.headers
+ "#{new_resource.url}",
+ new_resource.headers
)
- Chef::Log.info("#{@new_resource} HEAD to #{@new_resource.url} successful")
- Chef::Log.debug("#{@new_resource} HEAD request response: #{modified}")
+ Chef::Log.info("#{new_resource} HEAD to #{new_resource.url} successful")
+ Chef::Log.debug("#{new_resource} HEAD request response: #{modified}")
# :head is usually used to trigger notifications, which converge_by now does
if modified != false
- converge_by("#{@new_resource} HEAD to #{@new_resource.url} returned modified, trigger notifications") {}
+ converge_by("#{new_resource} HEAD to #{new_resource.url} returned modified, trigger notifications") {}
end
end
- # Send a GET request to @new_resource.url
+ # Send a GET request to new_resource.url
def action_get
- converge_by("#{@new_resource} GET to #{@new_resource.url}") do
+ converge_by("#{new_resource} GET to #{new_resource.url}") do
- message = check_message(@new_resource.message)
+ message = check_message(new_resource.message)
body = @http.get(
- "#{@new_resource.url}",
- @new_resource.headers
+ "#{new_resource.url}",
+ new_resource.headers
)
- Chef::Log.info("#{@new_resource} GET to #{@new_resource.url} successful")
- Chef::Log.debug("#{@new_resource} GET request response: #{body}")
+ Chef::Log.info("#{new_resource} GET to #{new_resource.url} successful")
+ Chef::Log.debug("#{new_resource} GET request response: #{body}")
end
end
- # Send a PUT request to @new_resource.url, with the message as the payload
+ # Send a PUT request to new_resource.url, with the message as the payload
def action_put
- converge_by("#{@new_resource} PUT to #{@new_resource.url}") do
- message = check_message(@new_resource.message)
+ converge_by("#{new_resource} PUT to #{new_resource.url}") do
+ message = check_message(new_resource.message)
body = @http.put(
- "#{@new_resource.url}",
+ "#{new_resource.url}",
message,
- @new_resource.headers
+ new_resource.headers
)
- Chef::Log.info("#{@new_resource} PUT to #{@new_resource.url} successful")
- Chef::Log.debug("#{@new_resource} PUT request response: #{body}")
+ Chef::Log.info("#{new_resource} PUT to #{new_resource.url} successful")
+ Chef::Log.debug("#{new_resource} PUT request response: #{body}")
end
end
- # Send a POST request to @new_resource.url, with the message as the payload
+ # Send a POST request to new_resource.url, with the message as the payload
def action_post
- converge_by("#{@new_resource} POST to #{@new_resource.url}") do
- message = check_message(@new_resource.message)
+ converge_by("#{new_resource} POST to #{new_resource.url}") do
+ message = check_message(new_resource.message)
body = @http.post(
- "#{@new_resource.url}",
+ "#{new_resource.url}",
message,
- @new_resource.headers
+ new_resource.headers
)
- Chef::Log.info("#{@new_resource} POST to #{@new_resource.url} message: #{message.inspect} successful")
- Chef::Log.debug("#{@new_resource} POST request response: #{body}")
+ Chef::Log.info("#{new_resource} POST to #{new_resource.url} message: #{message.inspect} successful")
+ Chef::Log.debug("#{new_resource} POST request response: #{body}")
end
end
- # Send a DELETE request to @new_resource.url
+ # Send a DELETE request to new_resource.url
def action_delete
- converge_by("#{@new_resource} DELETE to #{@new_resource.url}") do
+ converge_by("#{new_resource} DELETE to #{new_resource.url}") do
body = @http.delete(
- "#{@new_resource.url}",
- @new_resource.headers
+ "#{new_resource.url}",
+ new_resource.headers
)
- @new_resource.updated_by_last_action(true)
- Chef::Log.info("#{@new_resource} DELETE to #{@new_resource.url} successful")
- Chef::Log.debug("#{@new_resource} DELETE request response: #{body}")
+ new_resource.updated_by_last_action(true)
+ Chef::Log.info("#{new_resource} DELETE to #{new_resource.url} successful")
+ Chef::Log.debug("#{new_resource} DELETE request response: #{body}")
end
end
private
- def check_message(message)
- if message.kind_of?(Proc)
- message.call
- else
- message
- end
+ def check_message(message)
+ if message.kind_of?(Proc)
+ message.call
+ else
+ message
end
+ end
end
end
diff --git a/lib/chef/provider/ifconfig.rb b/lib/chef/provider/ifconfig.rb
index 7869917307..4f32baaadb 100644
--- a/lib/chef/provider/ifconfig.rb
+++ b/lib/chef/provider/ifconfig.rb
@@ -1,6 +1,6 @@
#
# Author:: Jason K. Jackson (jasonjackson@gmail.com)
-# Copyright:: Copyright (c) 2009 Jason K. Jackson
+# Copyright:: Copyright 2009-2016, Jason K. Jackson
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/mixin/command'
-require 'chef/mixin/shell_out'
-require 'chef/provider'
-require 'chef/resource/file'
-require 'chef/exceptions'
-require 'erb'
+require "chef/log"
+require "chef/mixin/command"
+require "chef/mixin/shell_out"
+require "chef/provider"
+require "chef/resource/file"
+require "chef/exceptions"
+require "erb"
# Recipe example:
#
@@ -58,7 +58,7 @@ class Chef
end
def load_current_resource
- @current_resource = Chef::Resource::Ifconfig.new(@new_resource.name)
+ @current_resource = Chef::Resource::Ifconfig.new(new_resource.name)
@ifconfig_success = true
@interfaces = {}
@@ -67,29 +67,28 @@ class Chef
@status.stdout.each_line do |line|
if !line[0..9].strip.empty?
@int_name = line[0..9].strip
- @interfaces[@int_name] = {"hwaddr" => (line =~ /(HWaddr)/ ? ($') : "nil").strip.chomp }
+ @interfaces[@int_name] = { "hwaddr" => (line =~ /(HWaddr)/ ? ($') : "nil").strip.chomp }
else
- @interfaces[@int_name]["inet_addr"] = (line =~ /inet addr:(\S+)/ ? ($1) : "nil") if line =~ /inet addr:/
- @interfaces[@int_name]["bcast"] = (line =~ /Bcast:(\S+)/ ? ($1) : "nil") if line =~ /Bcast:/
- @interfaces[@int_name]["mask"] = (line =~ /Mask:(\S+)/ ? ($1) : "nil") if line =~ /Mask:/
- @interfaces[@int_name]["mtu"] = (line =~ /MTU:(\S+)/ ? ($1) : "nil") if line =~ /MTU:/
- @interfaces[@int_name]["metric"] = (line =~ /Metric:(\S+)/ ? ($1) : "nil") if line =~ /Metric:/
+ @interfaces[@int_name]["inet_addr"] = (line =~ /inet addr:(\S+)/ ? Regexp.last_match(1) : "nil") if line =~ /inet addr:/
+ @interfaces[@int_name]["bcast"] = (line =~ /Bcast:(\S+)/ ? Regexp.last_match(1) : "nil") if line =~ /Bcast:/
+ @interfaces[@int_name]["mask"] = (line =~ /Mask:(\S+)/ ? Regexp.last_match(1) : "nil") if line =~ /Mask:/
+ @interfaces[@int_name]["mtu"] = (line =~ /MTU:(\S+)/ ? Regexp.last_match(1) : "nil") if line =~ /MTU:/
+ @interfaces[@int_name]["metric"] = (line =~ /Metric:(\S+)/ ? Regexp.last_match(1) : "nil") if line =~ /Metric:/
end
- if @interfaces.has_key?(@new_resource.device)
- @interface = @interfaces.fetch(@new_resource.device)
-
- @current_resource.target(@new_resource.target)
- @current_resource.device(@new_resource.device)
- @current_resource.inet_addr(@interface["inet_addr"])
- @current_resource.hwaddr(@interface["hwaddr"])
- @current_resource.bcast(@interface["bcast"])
- @current_resource.mask(@interface["mask"])
- @current_resource.mtu(@interface["mtu"])
- @current_resource.metric(@interface["metric"])
- end
+ next unless @interfaces.key?(new_resource.device)
+ @interface = @interfaces.fetch(new_resource.device)
+
+ current_resource.target(new_resource.target)
+ current_resource.device(new_resource.device)
+ current_resource.inet_addr(@interface["inet_addr"])
+ current_resource.hwaddr(@interface["hwaddr"])
+ current_resource.bcast(@interface["bcast"])
+ current_resource.mask(@interface["mask"])
+ current_resource.mtu(@interface["mtu"])
+ current_resource.metric(@interface["metric"])
end
- @current_resource
+ current_resource
end
def define_resource_requirements
@@ -104,14 +103,12 @@ class Chef
def action_add
# check to see if load_current_resource found interface in ifconfig
- unless @current_resource.inet_addr
- unless @new_resource.device == loopback_device
+ unless current_resource.inet_addr
+ unless new_resource.device == loopback_device
command = add_command
- converge_by ("run #{command} to add #{@new_resource}") do
- run_command(
- :command => command
- )
- Chef::Log.info("#{@new_resource} added")
+ converge_by("run #{command.join(' ')} to add #{new_resource}") do
+ shell_out_compact!(command)
+ Chef::Log.info("#{new_resource} added")
end
end
end
@@ -122,31 +119,25 @@ class Chef
def action_enable
# check to see if load_current_resource found ifconfig
# enables, but does not manage config files
- unless @current_resource.inet_addr
- unless @new_resource.device == loopback_device
- command = enable_command
- converge_by ("run #{command} to enable #{@new_resource}") do
- run_command(
- :command => command
- )
- Chef::Log.info("#{@new_resource} enabled")
- end
- end
+ return if current_resource.inet_addr
+ return if new_resource.device == loopback_device
+ command = enable_command
+ converge_by("run #{command.join(' ')} to enable #{new_resource}") do
+ shell_out_compact!(command)
+ Chef::Log.info("#{new_resource} enabled")
end
end
def action_delete
# check to see if load_current_resource found the interface
- if @current_resource.device
+ if current_resource.device
command = delete_command
- converge_by ("run #{command} to delete #{@new_resource}") do
- run_command(
- :command => command
- )
- Chef::Log.info("#{@new_resource} deleted")
+ converge_by("run #{command.join(' ')} to delete #{new_resource}") do
+ shell_out_compact!(command)
+ Chef::Log.info("#{new_resource} deleted")
end
else
- Chef::Log.debug("#{@new_resource} does not exist - nothing to do")
+ Chef::Log.debug("#{new_resource} does not exist - nothing to do")
end
delete_config
end
@@ -154,21 +145,19 @@ class Chef
def action_disable
# check to see if load_current_resource found the interface
# disables, but leaves config files in place.
- if @current_resource.device
+ if current_resource.device
command = disable_command
- converge_by ("run #{command} to disable #{@new_resource}") do
- run_command(
- :command => command
- )
- Chef::Log.info("#{@new_resource} disabled")
+ converge_by("run #{command.join(' ')} to disable #{new_resource}") do
+ shell_out_compact!(command)
+ Chef::Log.info("#{new_resource} disabled")
end
else
- Chef::Log.debug("#{@new_resource} does not exist - nothing to do")
+ Chef::Log.debug("#{new_resource} does not exist - nothing to do")
end
end
def can_generate_config?
- ! @config_template.nil? and ! @config_path.nil?
+ !@config_template.nil? && !@config_path.nil?
end
def resource_for_config(path)
@@ -182,43 +171,44 @@ class Chef
config = resource_for_config(@config_path)
config.content(template.result(b))
config.run_action(:create)
- @new_resource.updated_by_last_action(true) if config.updated?
+ new_resource.updated_by_last_action(true) if config.updated?
end
def delete_config
return unless can_generate_config?
config = resource_for_config(@config_path)
config.run_action(:delete)
- @new_resource.updated_by_last_action(true) if config.updated?
+ new_resource.updated_by_last_action(true) if config.updated?
end
private
+
def add_command
- command = "ifconfig #{@new_resource.device} #{@new_resource.target}"
- command << " netmask #{@new_resource.mask}" if @new_resource.mask
- command << " metric #{@new_resource.metric}" if @new_resource.metric
- command << " mtu #{@new_resource.mtu}" if @new_resource.mtu
+ command = [ "ifconfig", new_resource.device, new_resource.target ]
+ command += [ "netmask", new_resource.mask ] if new_resource.mask
+ command += [ "metric", new_resource.metric ] if new_resource.metric
+ command += [ "mtu", new_resource.mtu ] if new_resource.mtu
command
end
def enable_command
- command = "ifconfig #{@new_resource.device} #{@new_resource.target}"
- command << " netmask #{@new_resource.mask}" if @new_resource.mask
- command << " metric #{@new_resource.metric}" if @new_resource.metric
- command << " mtu #{@new_resource.mtu}" if @new_resource.mtu
+ command = [ "ifconfig", new_resource.device, new_resource.target ]
+ command += [ "netmask", new_resource.mask ] if new_resource.mask
+ command += [ "metric", new_resource.metric ] if new_resource.metric
+ command += [ "mtu", new_resource.mtu ] if new_resource.mtu
command
end
def disable_command
- "ifconfig #{@new_resource.device} down"
+ [ "ifconfig", new_resource.device, "down" ]
end
def delete_command
- "ifconfig #{@new_resource.device} down"
+ [ "ifconfig", new_resource.device, "down" ]
end
def loopback_device
- 'lo'
+ "lo"
end
end
end
diff --git a/lib/chef/provider/ifconfig/aix.rb b/lib/chef/provider/ifconfig/aix.rb
index 25c3de3040..788b609fcf 100644
--- a/lib/chef/provider/ifconfig/aix.rb
+++ b/lib/chef/provider/ifconfig/aix.rb
@@ -1,6 +1,6 @@
#
# Author:: Kaustubh Deorukhkar (kaustubh@clogeny.com)
-# Copyright:: Copyright (c) 2013 Opscode, Inc
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,69 +16,65 @@
# limitations under the License.
#
-require 'chef/provider/ifconfig'
+require "chef/provider/ifconfig"
class Chef
class Provider
class Ifconfig
class Aix < Chef::Provider::Ifconfig
- provides :ifconfig, platform: %w(aix)
+ provides :ifconfig, platform: %w{aix}
def load_current_resource
- @current_resource = Chef::Resource::Ifconfig.new(@new_resource.name)
+ @current_resource = Chef::Resource::Ifconfig.new(new_resource.name)
@interface_exists = false
found_interface = false
interface = {}
- @status = shell_out("ifconfig -a")
+ @status = shell_out_compact("ifconfig", "-a")
@status.stdout.each_line do |line|
if !found_interface
if line =~ /^(\S+):\sflags=(\S+)/
- # We have interface name, if this is the interface for @current_resource, load info else skip till next interface is found.
- if $1 == @new_resource.device
+ # We have interface name, if this is the interface for current_resource, load info else skip till next interface is found.
+ if Regexp.last_match(1) == new_resource.device
# Found interface
found_interface = true
@interface_exists = true
- @current_resource.target(@new_resource.target)
- @current_resource.device($1)
- interface[:flags] = $2
- @current_resource.metric($1) if line =~ /metric\s(\S+)/
- end
- end
- else
- # parse interface related information, stop when next interface is found.
- if line =~ /^(\S+):\sflags=(\S+)/
- # we are done parsing interface info and hit another one, so stop.
- found_interface = false
- break
- else
- if found_interface
- # read up interface info
- @current_resource.inet_addr($1) if line =~ /inet\s(\S+)\s/
- @current_resource.bcast($1) if line =~ /broadcast\s(\S+)/
- @current_resource.mask(hex_to_dec_netmask($1)) if line =~ /netmask\s(\S+)\s/
+ current_resource.target(new_resource.target)
+ current_resource.device(Regexp.last_match(1))
+ interface[:flags] = Regexp.last_match(2)
+ current_resource.metric(Regexp.last_match(1)) if line =~ /metric\s(\S+)/
end
end
+ elsif line =~ /^(\S+):\sflags=(\S+)/
+ # we are done parsing interface info and hit another one, so stop.
+ found_interface = false
+ break
+ elsif found_interface
+ # read up interface info
+ current_resource.inet_addr(Regexp.last_match(1)) if line =~ /inet\s(\S+)\s/
+ current_resource.bcast(Regexp.last_match(1)) if line =~ /broadcast\s(\S+)/
+ current_resource.mask(hex_to_dec_netmask(Regexp.last_match(1))) if line =~ /netmask\s(\S+)\s/
end
end
- @current_resource
+ current_resource
end
private
+
def add_command
# ifconfig changes are temporary, chdev persist across reboots.
- raise Chef::Exceptions::Ifconfig, "interface metric attribute cannot be set for :add action" if @new_resource.metric
- command = "chdev -l #{@new_resource.device} -a netaddr=#{@new_resource.name}"
- command << " -a netmask=#{@new_resource.mask}" if @new_resource.mask
- command << " -a mtu=#{@new_resource.mtu}" if @new_resource.mtu
+ raise Chef::Exceptions::Ifconfig, "interface metric attribute cannot be set for :add action" if new_resource.metric
+ command = [ "chdev", "-l", new_resource.device, "-a", "netaddr=#{new_resource.name}" ]
+ command += [ "-a", "netmask=#{new_resource.mask}" ] if new_resource.mask
+ command += [ "-a", "mtu=#{new_resource.mtu}" ] if new_resource.mtu
command
end
def delete_command
# ifconfig changes are temporary, chdev persist across reboots.
- "chdev -l #{@new_resource.device} -a state=down"
+ [ "chdev", "-l", new_resource.device, "-a", "state=down" ]
end
def loopback_device
@@ -88,7 +84,7 @@ class Chef
def hex_to_dec_netmask(netmask)
# example '0xffff0000' -> '255.255.0.0'
dec = netmask[2..3].to_i(16).to_s(10)
- [4,6,8].each { |n| dec = dec + "." + netmask[n..n+1].to_i(16).to_s(10) }
+ [4, 6, 8].each { |n| dec = dec + "." + netmask[n..n + 1].to_i(16).to_s(10) }
dec
end
diff --git a/lib/chef/provider/ifconfig/debian.rb b/lib/chef/provider/ifconfig/debian.rb
index 1e6863c8b5..369c222b7a 100644
--- a/lib/chef/provider/ifconfig/debian.rb
+++ b/lib/chef/provider/ifconfig/debian.rb
@@ -1,6 +1,6 @@
#
# Author:: Xabier de Zuazo (xabier@onddo.com)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,42 +16,42 @@
# limitations under the License.
#
-require 'chef/provider/ifconfig'
-require 'chef/util/file_edit'
+require "chef/provider/ifconfig"
+require "chef/util/file_edit"
class Chef
class Provider
class Ifconfig
class Debian < Chef::Provider::Ifconfig
- provides :ifconfig, platform: %w(ubuntu), platform_version: '>= 11.10'
- provides :ifconfig, platform: %w(debian), platform_version: '>= 7.0'
+ provides :ifconfig, platform: %w{ubuntu}, platform_version: ">= 11.10"
+ provides :ifconfig, platform: %w{debian}, platform_version: ">= 7.0"
- INTERFACES_FILE = "/etc/network/interfaces"
- INTERFACES_DOT_D_DIR = "/etc/network/interfaces.d"
+ INTERFACES_FILE = "/etc/network/interfaces".freeze
+ INTERFACES_DOT_D_DIR = "/etc/network/interfaces.d".freeze
def initialize(new_resource, run_context)
super(new_resource, run_context)
@config_template = %{
-<% if @new_resource.device %>
-<% if @new_resource.onboot == "yes" %>auto <%= @new_resource.device %><% end %>
-<% case @new_resource.bootproto
+<% if new_resource.device %>
+<% if new_resource.onboot == "yes" %>auto <%= new_resource.device %><% end %>
+<% case new_resource.bootproto
when "dhcp" %>
-iface <%= @new_resource.device %> inet dhcp
+iface <%= new_resource.device %> inet dhcp
<% when "bootp" %>
-iface <%= @new_resource.device %> inet bootp
+iface <%= new_resource.device %> inet bootp
<% else %>
-iface <%= @new_resource.device %> inet static
- <% if @new_resource.target %>address <%= @new_resource.target %><% end %>
- <% if @new_resource.mask %>netmask <%= @new_resource.mask %><% end %>
- <% if @new_resource.network %>network <%= @new_resource.network %><% end %>
- <% if @new_resource.bcast %>broadcast <%= @new_resource.bcast %><% end %>
- <% if @new_resource.metric %>metric <%= @new_resource.metric %><% end %>
- <% if @new_resource.hwaddr %>hwaddress <%= @new_resource.hwaddr %><% end %>
- <% if @new_resource.mtu %>mtu <%= @new_resource.mtu %><% end %>
+iface <%= new_resource.device %> inet static
+ <% if new_resource.target %>address <%= new_resource.target %><% end %>
+ <% if new_resource.mask %>netmask <%= new_resource.mask %><% end %>
+ <% if new_resource.network %>network <%= new_resource.network %><% end %>
+ <% if new_resource.bcast %>broadcast <%= new_resource.bcast %><% end %>
+ <% if new_resource.metric %>metric <%= new_resource.metric %><% end %>
+ <% if new_resource.hwaddr %>hwaddress <%= new_resource.hwaddr %><% end %>
+ <% if new_resource.mtu %>mtu <%= new_resource.mtu %><% end %>
<% end %>
<% end %>
}
- @config_path = "#{INTERFACES_DOT_D_DIR}/ifcfg-#{@new_resource.device}"
+ @config_path = "#{INTERFACES_DOT_D_DIR}/ifcfg-#{new_resource.device}"
end
def generate_config
@@ -67,14 +67,15 @@ iface <%= @new_resource.device %> inet static
dir.run_action(:create)
new_resource.updated_by_last_action(true) if dir.updated_by_last_action?
# roll our own file_edit resource, this will not get reported until we have a file_edit resource
- interfaces_dot_d_for_regexp = INTERFACES_DOT_D_DIR.gsub(/\./, '\.') # escape dots for the regexp
+ interfaces_dot_d_for_regexp = INTERFACES_DOT_D_DIR.gsub(/\./, '\.') # escape dots for the regexp
regexp = %r{^\s*source\s+#{interfaces_dot_d_for_regexp}/\*\s*$}
- unless ::File.exists?(INTERFACES_FILE) && regexp.match(IO.read(INTERFACES_FILE))
- converge_by("modifying #{INTERFACES_FILE} to source #{INTERFACES_DOT_D_DIR}") do
- conf = Chef::Util::FileEdit.new(INTERFACES_FILE)
- conf.insert_line_if_no_match(regexp, "source #{INTERFACES_DOT_D_DIR}/*")
- conf.write_file
- end
+
+ return if ::File.exist?(INTERFACES_FILE) && regexp.match(IO.read(INTERFACES_FILE))
+
+ converge_by("modifying #{INTERFACES_FILE} to source #{INTERFACES_DOT_D_DIR}") do
+ conf = Chef::Util::FileEdit.new(INTERFACES_FILE)
+ conf.insert_line_if_no_match(regexp, "source #{INTERFACES_DOT_D_DIR}/*")
+ conf.write_file
end
end
diff --git a/lib/chef/provider/ifconfig/redhat.rb b/lib/chef/provider/ifconfig/redhat.rb
index ee053d1e52..841e725b94 100644
--- a/lib/chef/provider/ifconfig/redhat.rb
+++ b/lib/chef/provider/ifconfig/redhat.rb
@@ -1,6 +1,6 @@
#
# Author:: Xabier de Zuazo (xabier@onddo.com)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,30 +16,30 @@
# limitations under the License.
#
-require 'chef/provider/ifconfig'
+require "chef/provider/ifconfig"
class Chef
class Provider
class Ifconfig
class Redhat < Chef::Provider::Ifconfig
- provides :ifconfig, platform_family: %w(fedora rhel)
+ provides :ifconfig, platform_family: %w{fedora rhel}
def initialize(new_resource, run_context)
super(new_resource, run_context)
@config_template = %{
-<% if @new_resource.device %>DEVICE=<%= @new_resource.device %><% end %>
-<% if @new_resource.onboot == "yes" %>ONBOOT=<%= @new_resource.onboot %><% end %>
-<% if @new_resource.bootproto %>BOOTPROTO=<%= @new_resource.bootproto %><% end %>
-<% if @new_resource.target %>IPADDR=<%= @new_resource.target %><% end %>
-<% if @new_resource.mask %>NETMASK=<%= @new_resource.mask %><% end %>
-<% if @new_resource.network %>NETWORK=<%= @new_resource.network %><% end %>
-<% if @new_resource.bcast %>BROADCAST=<%= @new_resource.bcast %><% end %>
-<% if @new_resource.onparent %>ONPARENT=<%= @new_resource.onparent %><% end %>
-<% if @new_resource.hwaddr %>HWADDR=<%= @new_resource.hwaddr %><% end %>
-<% if @new_resource.metric %>METRIC=<%= @new_resource.metric %><% end %>
-<% if @new_resource.mtu %>MTU=<%= @new_resource.mtu %><% end %>
+<% if new_resource.device %>DEVICE=<%= new_resource.device %><% end %>
+<% if new_resource.onboot == "yes" %>ONBOOT=<%= new_resource.onboot %><% end %>
+<% if new_resource.bootproto %>BOOTPROTO=<%= new_resource.bootproto %><% end %>
+<% if new_resource.target %>IPADDR=<%= new_resource.target %><% end %>
+<% if new_resource.mask %>NETMASK=<%= new_resource.mask %><% end %>
+<% if new_resource.network %>NETWORK=<%= new_resource.network %><% end %>
+<% if new_resource.bcast %>BROADCAST=<%= new_resource.bcast %><% end %>
+<% if new_resource.onparent %>ONPARENT=<%= new_resource.onparent %><% end %>
+<% if new_resource.hwaddr %>HWADDR=<%= new_resource.hwaddr %><% end %>
+<% if new_resource.metric %>METRIC=<%= new_resource.metric %><% end %>
+<% if new_resource.mtu %>MTU=<%= new_resource.mtu %><% end %>
}
- @config_path = "/etc/sysconfig/network-scripts/ifcfg-#{@new_resource.device}"
+ @config_path = "/etc/sysconfig/network-scripts/ifcfg-#{new_resource.device}"
end
end
diff --git a/lib/chef/provider/launchd.rb b/lib/chef/provider/launchd.rb
new file mode 100644
index 0000000000..a58954c707
--- /dev/null
+++ b/lib/chef/provider/launchd.rb
@@ -0,0 +1,208 @@
+#
+# Author:: Mike Dodge (<mikedodge04@gmail.com>)
+# Copyright:: Copyright (c) 2015 Facebook, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/provider"
+require "chef/resource/launchd"
+require "chef/resource/file"
+require "chef/resource/cookbook_file"
+require "chef/resource/macosx_service"
+require "plist"
+require "forwardable"
+
+class Chef
+ class Provider
+ class Launchd < Chef::Provider
+ extend Forwardable
+ provides :launchd, os: "darwin"
+
+ def_delegators :new_resource, *[
+ :backup,
+ :cookbook,
+ :group,
+ :label,
+ :mode,
+ :owner,
+ :path,
+ :source,
+ :session_type,
+ :type,
+ ]
+
+ def load_current_resource
+ current_resource = Chef::Resource::Launchd.new(new_resource.name)
+ @path = path ? path : gen_path_from_type
+ end
+
+ def gen_path_from_type
+ types = {
+ "daemon" => "/Library/LaunchDaemons/#{label}.plist",
+ "agent" => "/Library/LaunchAgents/#{label}.plist",
+ }
+ types[type]
+ end
+
+ def action_create
+ manage_plist(:create)
+ end
+
+ def action_create_if_missing
+ manage_plist(:create_if_missing)
+ end
+
+ def action_delete
+ # If you delete a service you want to make sure its not loaded or
+ # the service will be in memory and you wont be able to stop it.
+ if ::File.exists?(@path)
+ manage_service(:disable)
+ end
+ manage_plist(:delete)
+ end
+
+ def action_enable
+ if manage_plist(:create)
+ manage_service(:restart)
+ else
+ manage_service(:enable)
+ end
+ end
+
+ def action_disable
+ manage_service(:disable)
+ end
+
+ def manage_plist(action)
+ if source
+ res = cookbook_file_resource
+ else
+ res = file_resource
+ end
+ res.run_action(action)
+ new_resource.updated_by_last_action(true) if res.updated?
+ res.updated
+ end
+
+ def manage_service(action)
+ res = service_resource
+ res.run_action(action)
+ new_resource.updated_by_last_action(true) if res.updated?
+ end
+
+ def service_resource
+ res = Chef::Resource::MacosxService.new(label, run_context)
+ res.name(label) if label
+ res.service_name(label) if label
+ res.plist(@path) if @path
+ res.session_type(session_type) if session_type
+ res
+ end
+
+ def file_resource
+ res = Chef::Resource::File.new(@path, run_context)
+ res.name(@path) if @path
+ res.backup(backup) if backup
+ res.content(content) if content?
+ res.group(group) if group
+ res.mode(mode) if mode
+ res.owner(owner) if owner
+ res
+ end
+
+ def cookbook_file_resource
+ res = Chef::Resource::CookbookFile.new(@path, run_context)
+ res.cookbook_name = cookbook if cookbook
+ res.name(@path) if @path
+ res.backup(backup) if backup
+ res.group(group) if group
+ res.mode(mode) if mode
+ res.owner(owner) if owner
+ res.source(source) if source
+ res
+ end
+
+ def define_resource_requirements
+ requirements.assert(
+ :create, :create_if_missing, :delete, :enable, :disable
+ ) do |a|
+ type = new_resource.type
+ a.assertion { %w{daemon agent}.include?(type.to_s) }
+ error_msg = "type must be daemon or agent."
+ a.failure_message Chef::Exceptions::ValidationFailed, error_msg
+ end
+ end
+
+ def content?
+ !!content
+ end
+
+ def content
+ plist_hash = new_resource.plist_hash || gen_hash
+ Plist::Emit.dump(plist_hash) unless plist_hash.nil?
+ end
+
+ def gen_hash
+ return nil unless new_resource.program || new_resource.program_arguments
+ {
+ "label" => "Label",
+ "program" => "Program",
+ "program_arguments" => "ProgramArguments",
+ "abandon_process_group" => "AbandonProcessGroup",
+ "debug" => "Debug",
+ "disabled" => "Disabled",
+ "enable_globbing" => "EnableGlobbing",
+ "enable_transactions" => "EnableTransactions",
+ "environment_variables" => "EnvironmentVariables",
+ "exit_timeout" => "ExitTimeout",
+ "ld_group" => "GroupName",
+ "hard_resource_limits" => "HardreSourceLimits",
+ "inetd_compatibility" => "inetdCompatibility",
+ "init_groups" => "InitGroups",
+ "keep_alive" => "KeepAlive",
+ "launch_only_once" => "LaunchOnlyOnce",
+ "limit_load_from_hosts" => "LimitLoadFromHosts",
+ "limit_load_to_hosts" => "LimitLoadToHosts",
+ "limit_load_to_session_type" => "LimitLoadToSessionType",
+ "low_priority_io" => "LowPriorityIO",
+ "mach_services" => "MachServices",
+ "nice" => "Nice",
+ "on_demand" => "OnDemand",
+ "process_type" => "ProcessType",
+ "queue_directories" => "QueueDirectories",
+ "root_directory" => "RootDirectory",
+ "run_at_load" => "RunAtLoad",
+ "sockets" => "Sockets",
+ "soft_resource_limits" => "SoftResourceLimits",
+ "standard_error_path" => "StandardErrorPath",
+ "standard_in_path" => "StandardInPath",
+ "standard_out_path" => "StandardOutPath",
+ "start_calendar_interval" => "StartCalendarInterval",
+ "start_interval" => "StartInterval",
+ "start_on_mount" => "StartOnMount",
+ "throttle_interval" => "ThrottleInterval",
+ "time_out" => "TimeOut",
+ "umask" => "Umask",
+ "username" => "UserName",
+ "wait_for_debugger" => "WaitForDebugger",
+ "watch_paths" => "WatchPaths",
+ "working_directory" => "WorkingDirectory",
+ }.each_with_object({}) do |(key, val), memo|
+ memo[val] = new_resource.send(key) if new_resource.send(key)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/link.rb b/lib/chef/provider/link.rb
index c811c13cdf..aed60b7c47 100644
--- a/lib/chef/provider/link.rb
+++ b/lib/chef/provider/link.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/log'
-require 'chef/mixin/file_class'
-require 'chef/resource/link'
-require 'chef/provider'
-require 'chef/scan_access_control'
-require 'chef/util/path_helper'
+require "chef/config"
+require "chef/log"
+require "chef/mixin/file_class"
+require "chef/resource/link"
+require "chef/provider"
+require "chef/scan_access_control"
+require "chef/util/path_helper"
class Chef
class Provider
@@ -47,46 +47,46 @@ class Chef
end
def load_current_resource
- @current_resource = Chef::Resource::Link.new(@new_resource.name)
- @current_resource.target_file(@new_resource.target_file)
- if file_class.symlink?(@current_resource.target_file)
- @current_resource.link_type(:symbolic)
- @current_resource.to(
- canonicalize(file_class.readlink(@current_resource.target_file))
+ @current_resource = Chef::Resource::Link.new(new_resource.name)
+ current_resource.target_file(new_resource.target_file)
+ if file_class.symlink?(current_resource.target_file)
+ current_resource.link_type(:symbolic)
+ current_resource.to(
+ canonicalize(file_class.readlink(current_resource.target_file))
)
else
- @current_resource.link_type(:hard)
- if ::File.exists?(@current_resource.target_file)
- if ::File.exists?(@new_resource.to) &&
- file_class.stat(@current_resource.target_file).ino ==
- file_class.stat(@new_resource.to).ino
- @current_resource.to(canonicalize(@new_resource.to))
+ current_resource.link_type(:hard)
+ if ::File.exists?(current_resource.target_file)
+ if ::File.exists?(new_resource.to) &&
+ file_class.stat(current_resource.target_file).ino ==
+ file_class.stat(new_resource.to).ino
+ current_resource.to(canonicalize(new_resource.to))
else
- @current_resource.to("")
+ current_resource.to("")
end
end
end
- ScanAccessControl.new(@new_resource, @current_resource).set_all!
- @current_resource
+ ScanAccessControl.new(new_resource, current_resource).set_all!
+ current_resource
end
def define_resource_requirements
requirements.assert(:delete) do |a|
a.assertion do
- if @current_resource.to
- @current_resource.link_type == @new_resource.link_type and
- (@current_resource.link_type == :symbolic or @current_resource.to != '')
+ if current_resource.to
+ current_resource.link_type == new_resource.link_type &&
+ (current_resource.link_type == :symbolic || current_resource.to != "")
else
true
end
end
- a.failure_message Chef::Exceptions::Link, "Cannot delete #{@new_resource} at #{@new_resource.target_file}! Not a #{@new_resource.link_type.to_s} link."
- a.whyrun("Would assume the link at #{@new_resource.target_file} was previously created")
+ a.failure_message Chef::Exceptions::Link, "Cannot delete #{new_resource} at #{new_resource.target_file}! Not a #{new_resource.link_type} link."
+ a.whyrun("Would assume the link at #{new_resource.target_file} was previously created")
end
end
def canonicalize(path)
- Chef::Platform.windows? ? path.gsub('/', '\\') : path
+ Chef::Platform.windows? ? path.tr("/", '\\') : path
end
def action_create
@@ -95,42 +95,48 @@ class Chef
# to - the location to link to
# target_file - the name of the link
- if @current_resource.to != canonicalize(@new_resource.to) ||
- @current_resource.link_type != @new_resource.link_type
+ if current_resource.to != canonicalize(new_resource.to) ||
+ current_resource.link_type != new_resource.link_type
# Handle the case where the symlink already exists and is pointing at a valid to_file
- if @current_resource.to
+ if current_resource.to
# On Windows, to fix a symlink already pointing at a directory we must first
# ::Dir.unlink the symlink (not the directory), while if we have a symlink
# pointing at file we must use ::File.unlink on the symlink.
# However if the new symlink will point to a file and the current symlink is pointing at a
# directory we want to throw an exception and calling ::File.unlink on the directory symlink
# will throw the correct ones.
- if Chef::Platform.windows? && ::File.directory?(@new_resource.to) &&
- ::File.directory?(@current_resource.target_file)
- converge_by("unlink existing windows symlink to dir at #{@new_resource.target_file}") do
- ::Dir.unlink(@new_resource.target_file)
+ if Chef::Platform.windows? && ::File.directory?(new_resource.to) &&
+ ::File.directory?(current_resource.target_file)
+ converge_by("unlink existing windows symlink to dir at #{new_resource.target_file}") do
+ ::Dir.unlink(new_resource.target_file)
end
else
- converge_by("unlink existing symlink to file at #{@new_resource.target_file}") do
- ::File.unlink(@new_resource.target_file)
+ converge_by("unlink existing symlink to file at #{new_resource.target_file}") do
+ ::File.unlink(new_resource.target_file)
end
end
end
- if @new_resource.link_type == :symbolic
- converge_by("create symlink at #{@new_resource.target_file} to #{@new_resource.to}") do
- file_class.symlink(canonicalize(@new_resource.to),@new_resource.target_file)
- Chef::Log.debug("#{@new_resource} created #{@new_resource.link_type} link from #{@new_resource.target_file} -> #{@new_resource.to}")
- Chef::Log.info("#{@new_resource} created")
+ if new_resource.link_type == :symbolic
+ converge_by("create symlink at #{new_resource.target_file} to #{new_resource.to}") do
+ file_class.symlink(canonicalize(new_resource.to), new_resource.target_file)
+ Chef::Log.debug("#{new_resource} created #{new_resource.link_type} link from #{new_resource.target_file} -> #{new_resource.to}")
+ Chef::Log.info("#{new_resource} created")
+ # file_class.symlink will create the link with default access controls.
+ # This means that the access controls of the file could be different
+ # than those captured during the initial evaluation of current_resource.
+ # We need to re-evaluate the current_resource to ensure that the desired
+ # access controls are applied.
+ ScanAccessControl.new(new_resource, current_resource).set_all!
end
- elsif @new_resource.link_type == :hard
- converge_by("create hard link at #{@new_resource.target_file} to #{@new_resource.to}") do
- file_class.link(@new_resource.to, @new_resource.target_file)
- Chef::Log.debug("#{@new_resource} created #{@new_resource.link_type} link from #{@new_resource.target_file} -> #{@new_resource.to}")
- Chef::Log.info("#{@new_resource} created")
+ elsif new_resource.link_type == :hard
+ converge_by("create hard link at #{new_resource.target_file} to #{new_resource.to}") do
+ file_class.link(new_resource.to, new_resource.target_file)
+ Chef::Log.debug("#{new_resource} created #{new_resource.link_type} link from #{new_resource.target_file} -> #{new_resource.to}")
+ Chef::Log.info("#{new_resource} created")
end
end
end
- if @new_resource.link_type == :symbolic
+ if new_resource.link_type == :symbolic
if access_controls.requires_changes?
converge_by(access_controls.describe_changes) do
access_controls.set_all
@@ -140,10 +146,17 @@ class Chef
end
def action_delete
- if @current_resource.to # Exists
- converge_by("delete link at #{@new_resource.target_file}") do
- ::File.delete(@new_resource.target_file)
- Chef::Log.info("#{@new_resource} deleted")
+ if current_resource.to # Exists
+ if Chef::Platform.windows? && ::File.directory?(current_resource.target_file)
+ converge_by("delete link to dir at #{new_resource.target_file}") do
+ ::Dir.delete(new_resource.target_file)
+ Chef::Log.info("#{new_resource} deleted")
+ end
+ else
+ converge_by("delete link to file at #{new_resource.target_file}") do
+ ::File.delete(new_resource.target_file)
+ Chef::Log.info("#{new_resource} deleted")
+ end
end
end
end
@@ -152,7 +165,7 @@ class Chef
# access control (e.g., use lchmod instead of chmod) if the resource is a
# symlink.
def manage_symlink_access?
- @new_resource.link_type == :symbolic
+ new_resource.link_type == :symbolic
end
end
end
diff --git a/lib/chef/provider/log.rb b/lib/chef/provider/log.rb
index 40eaf0aa28..a0219db753 100644
--- a/lib/chef/provider/log.rb
+++ b/lib/chef/provider/log.rb
@@ -1,6 +1,6 @@
#
# Author:: Cary Penniman (<cary@rightscale.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -44,8 +44,8 @@ class Chef
# === Return
# true:: Always return true
def action_write
- Chef::Log.send(@new_resource.level, @new_resource.message)
- @new_resource.updated_by_last_action(true)
+ Chef::Log.send(new_resource.level, new_resource.message)
+ new_resource.updated_by_last_action(true) if Chef::Config[:count_log_resource_updates]
end
end
diff --git a/lib/chef/provider/lwrp_base.rb b/lib/chef/provider/lwrp_base.rb
index 9c7cd15bbf..cbf25f1e4f 100644
--- a/lib/chef/provider/lwrp_base.rb
+++ b/lib/chef/provider/lwrp_base.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2008-2012 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,9 @@
# limitations under the License.
#
-require 'chef/provider'
-require 'chef/dsl/recipe'
-require 'chef/dsl/include_recipe'
+require "chef/provider"
+require "chef/dsl/recipe"
+require "chef/dsl/include_recipe"
class Chef
class Provider
@@ -34,7 +34,6 @@ class Chef
# These were previously provided by Chef::Mixin::RecipeDefinitionDSLCore.
# They are not included by its replacement, Chef::DSL::Recipe, but
# they may be used in existing LWRPs.
- include Chef::DSL::PlatformIntrospection
include Chef::DSL::DataQuery
# Allow include_recipe from within LWRP provider code
@@ -53,7 +52,7 @@ class Chef
def build_from_file(cookbook_name, filename, run_context)
if LWRPBase.loaded_lwrps[filename]
- Chef::Log.info("LWRP provider #{filename} from cookbook #{cookbook_name} has already been loaded! Skipping the reload.")
+ Chef::Log.debug("LWRP provider #{filename} from cookbook #{cookbook_name} has already been loaded! Skipping the reload.")
return loaded_lwrps[filename]
end
diff --git a/lib/chef/provider/mdadm.rb b/lib/chef/provider/mdadm.rb
index 325f1b5977..88da7b5eff 100644
--- a/lib/chef/provider/mdadm.rb
+++ b/lib/chef/provider/mdadm.rb
@@ -1,6 +1,6 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/provider'
+require "chef/log"
+require "chef/provider"
class Chef
class Provider
@@ -34,56 +34,57 @@ class Chef
end
def load_current_resource
- @current_resource = Chef::Resource::Mdadm.new(@new_resource.name)
- @current_resource.raid_device(@new_resource.raid_device)
- Chef::Log.debug("#{@new_resource} checking for software raid device #{@current_resource.raid_device}")
+ @current_resource = Chef::Resource::Mdadm.new(new_resource.name)
+ current_resource.raid_device(new_resource.raid_device)
+ Chef::Log.debug("#{new_resource} checking for software raid device #{current_resource.raid_device}")
device_not_found = 4
- mdadm = shell_out!("mdadm --detail --test #{@new_resource.raid_device}", :returns => [0,device_not_found])
+ mdadm = shell_out!("mdadm --detail --test #{new_resource.raid_device}", :returns => [0, device_not_found])
exists = (mdadm.status == 0)
- @current_resource.exists(exists)
+ current_resource.exists(exists)
end
def action_create
- unless @current_resource.exists
+ unless current_resource.exists
converge_by("create RAID device #{new_resource.raid_device}") do
- command = "yes | mdadm --create #{@new_resource.raid_device} --level #{@new_resource.level}"
- command << " --chunk=#{@new_resource.chunk}" unless @new_resource.level == 1
- command << " --metadata=#{@new_resource.metadata}"
- command << " --bitmap=#{@new_resource.bitmap}" if @new_resource.bitmap
- command << " --raid-devices #{@new_resource.devices.length} #{@new_resource.devices.join(" ")}"
- Chef::Log.debug("#{@new_resource} mdadm command: #{command}")
+ command = "yes | mdadm --create #{new_resource.raid_device} --level #{new_resource.level}"
+ command << " --chunk=#{new_resource.chunk}" unless new_resource.level == 1
+ command << " --metadata=#{new_resource.metadata}"
+ command << " --bitmap=#{new_resource.bitmap}" if new_resource.bitmap
+ command << " --layout=#{new_resource.layout}" if new_resource.layout
+ command << " --raid-devices #{new_resource.devices.length} #{new_resource.devices.join(" ")}"
+ Chef::Log.debug("#{new_resource} mdadm command: #{command}")
shell_out!(command)
- Chef::Log.info("#{@new_resource} created raid device (#{@new_resource.raid_device})")
+ Chef::Log.info("#{new_resource} created raid device (#{new_resource.raid_device})")
end
else
- Chef::Log.debug("#{@new_resource} raid device already exists, skipping create (#{@new_resource.raid_device})")
+ Chef::Log.debug("#{new_resource} raid device already exists, skipping create (#{new_resource.raid_device})")
end
end
def action_assemble
- unless @current_resource.exists
+ unless current_resource.exists
converge_by("assemble RAID device #{new_resource.raid_device}") do
- command = "yes | mdadm --assemble #{@new_resource.raid_device} #{@new_resource.devices.join(" ")}"
- Chef::Log.debug("#{@new_resource} mdadm command: #{command}")
+ command = "yes | mdadm --assemble #{new_resource.raid_device} #{new_resource.devices.join(" ")}"
+ Chef::Log.debug("#{new_resource} mdadm command: #{command}")
shell_out!(command)
- Chef::Log.info("#{@new_resource} assembled raid device (#{@new_resource.raid_device})")
+ Chef::Log.info("#{new_resource} assembled raid device (#{new_resource.raid_device})")
end
else
- Chef::Log.debug("#{@new_resource} raid device already exists, skipping assemble (#{@new_resource.raid_device})")
+ Chef::Log.debug("#{new_resource} raid device already exists, skipping assemble (#{new_resource.raid_device})")
end
end
def action_stop
- if @current_resource.exists
+ if current_resource.exists
converge_by("stop RAID device #{new_resource.raid_device}") do
- command = "yes | mdadm --stop #{@new_resource.raid_device}"
- Chef::Log.debug("#{@new_resource} mdadm command: #{command}")
+ command = "yes | mdadm --stop #{new_resource.raid_device}"
+ Chef::Log.debug("#{new_resource} mdadm command: #{command}")
shell_out!(command)
- Chef::Log.info("#{@new_resource} stopped raid device (#{@new_resource.raid_device})")
+ Chef::Log.info("#{new_resource} stopped raid device (#{new_resource.raid_device})")
end
else
- Chef::Log.debug("#{@new_resource} raid device doesn't exist (#{@new_resource.raid_device}) - not stopping")
+ Chef::Log.debug("#{new_resource} raid device doesn't exist (#{new_resource.raid_device}) - not stopping")
end
end
diff --git a/lib/chef/provider/mount.rb b/lib/chef/provider/mount.rb
index 6bdfd5b867..5168c93348 100644
--- a/lib/chef/provider/mount.rb
+++ b/lib/chef/provider/mount.rb
@@ -1,7 +1,7 @@
#
-# Author:: Joshua Timberman (<joshua@getchef.com>)
-# Author:: Lamont Granquist (<lamont@getchef.com>)
-# Copyright:: Copyright (c) 2009-2014 Chef Software, Inc.
+# Author:: Joshua Timberman (<joshua@chef.io>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/mixin/shell_out'
-require 'chef/provider'
+require "chef/log"
+require "chef/mixin/shell_out"
+require "chef/provider"
class Chef
class Provider
@@ -42,17 +42,13 @@ class Chef
end
def action_mount
- if current_resource.mounted
- if mount_options_unchanged?
- Chef::Log.debug("#{new_resource} is already mounted")
- else
- action_remount
- end
- else
+ unless current_resource.mounted
converge_by("mount #{current_resource.device} to #{current_resource.mount_point}") do
mount_fs
Chef::Log.info("#{new_resource} mounted")
end
+ else
+ Chef::Log.debug("#{new_resource} is already mounted")
end
end
@@ -112,18 +108,20 @@ class Chef
end
end
+ alias :action_unmount :action_umount
+
#
# Abstract Methods to be implemented by subclasses
#
# should actually check if the filesystem is mounted (not just return current_resource) and return true/false
def mounted?
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not implement #mounted?"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not implement #mounted?"
end
# should check new_resource against current_resource to see if mount options need updating, returns true/false
def mount_options_unchanged?
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not implement #mount_options_unchanged?"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not implement #mount_options_unchanged?"
end
#
@@ -134,28 +132,28 @@ class Chef
# should implement mounting of the filesystem, raises if action does not succeed
def mount_fs
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :mount"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :mount"
end
# should implement unmounting of the filesystem, raises if action does not succeed
def umount_fs
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :umount"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :umount"
end
# should implement remounting of the filesystem (via a -o remount or some other atomic-ish action that isn't
# simply a umount/mount style remount), raises if action does not succeed
def remount_fs
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :remount"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :remount"
end
# should implement enabling of the filesystem (e.g. in /etc/fstab), raises if action does not succeed
def enable_fs
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :enable"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :enable"
end
# should implement disabling of the filesystem (e.g. in /etc/fstab), raises if action does not succeed
def disable_fs
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :disable"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :disable"
end
private
diff --git a/lib/chef/provider/mount/aix.rb b/lib/chef/provider/mount/aix.rb
index 510dfde46d..73460e84a1 100644
--- a/lib/chef/provider/mount/aix.rb
+++ b/lib/chef/provider/mount/aix.rb
@@ -1,6 +1,6 @@
#
# Author::
-# Copyright:: Copyright (c) 2009 Opscode, Inc
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'chef/provider/mount'
+require "chef/provider/mount"
class Chef
class Provider
class Mount
class Aix < Chef::Provider::Mount::Mount
- provides :mount, platform: %w(aix)
+ provides :mount, platform: %w{aix}
# Override for aix specific handling
def initialize(new_resource, run_context)
@@ -42,7 +42,7 @@ class Chef
# lsfs o/p = #MountPoint:Device:Vfs:Nodename:Type:Size:Options:AutoMount:Acct
# search only for current mount point
- shell_out("lsfs -c #{@new_resource.mount_point}").stdout.each_line do | line |
+ shell_out("lsfs -c #{@new_resource.mount_point}").stdout.each_line do |line|
case line
when /^#\s/
next
@@ -61,7 +61,7 @@ class Chef
Chef::Log.debug("Found mount #{device_fstab} to #{@new_resource.mount_point} in /etc/filesystems")
next
when /^#{Regexp.escape(@new_resource.mount_point)}/
- enabled=false
+ enabled = false
Chef::Log.debug("Found conflicting mount point #{@new_resource.mount_point} in /etc/filesystems")
end
end
@@ -99,13 +99,13 @@ class Chef
end
command << case @new_resource.device_type
- when :device
- " #{device_real}"
- when :label
- " -L #{@new_resource.device}"
- when :uuid
- " -U #{@new_resource.device}"
- end
+ when :device
+ " #{device_real}"
+ when :label
+ " -L #{@new_resource.device}"
+ when :uuid
+ " -U #{@new_resource.device}"
+ end
command << " #{@new_resource.mount_point}"
shell_out!(command)
Chef::Log.debug("#{@new_resource} is mounted at #{@new_resource.mount_point}")
@@ -116,9 +116,9 @@ class Chef
def remount_command
if !(@new_resource.options.nil? || @new_resource.options.empty?)
- return "mount -o remount,#{@new_resource.options.join(',')} #{@new_resource.device} #{@new_resource.mount_point}"
+ "mount -o remount,#{@new_resource.options.join(',')} #{@new_resource.device} #{@new_resource.mount_point}"
else
- return "mount -o remount #{@new_resource.device} #{@new_resource.mount_point}"
+ "mount -o remount #{@new_resource.device} #{@new_resource.mount_point}"
end
end
@@ -167,14 +167,14 @@ class Chef
end
end
::File.open("/etc/filesystems", "w") do |fstab|
- contents.each { |line| fstab.puts line}
+ contents.each { |line| fstab.puts line }
end
else
Chef::Log.debug("#{@new_resource} is not enabled - nothing to do")
end
end
+ end
end
- end
end
end
diff --git a/lib/chef/provider/mount/mount.rb b/lib/chef/provider/mount/mount.rb
index ef074166a9..c3b1cc0141 100644
--- a/lib/chef/provider/mount/mount.rb
+++ b/lib/chef/provider/mount/mount.rb
@@ -1,6 +1,6 @@
#
-# Author:: Joshua Timberman (<joshua@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc
+# Author:: Joshua Timberman (<joshua@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/provider/mount'
-require 'chef/log'
+require "chef/provider/mount"
+require "chef/log"
class Chef
class Provider
@@ -42,12 +42,12 @@ class Chef
def mountable?
# only check for existence of non-remote devices
- if (device_should_exist? && !::File.exists?(device_real) )
+ if device_should_exist? && !::File.exists?(device_real)
raise Chef::Exceptions::Mount, "Device #{@new_resource.device} does not exist"
- elsif( @new_resource.mount_point != "none" && !::File.exists?(@new_resource.mount_point) )
+ elsif @new_resource.mount_point != "none" && !::File.exists?(@new_resource.mount_point)
raise Chef::Exceptions::Mount, "Mount point #{@new_resource.mount_point} does not exist"
end
- return true
+ true
end
def enabled?
@@ -104,13 +104,13 @@ class Chef
command = "mount -t #{@new_resource.fstype}"
command << " -o #{@new_resource.options.join(',')}" unless @new_resource.options.nil? || @new_resource.options.empty?
command << case @new_resource.device_type
- when :device
- " #{device_real}"
- when :label
- " -L #{@new_resource.device}"
- when :uuid
- " -U #{@new_resource.device}"
- end
+ when :device
+ " #{device_real}"
+ when :label
+ " -L #{@new_resource.device}"
+ when :uuid
+ " -U #{@new_resource.device}"
+ end
command << " #{@new_resource.mount_point}"
shell_out!(command)
Chef::Log.debug("#{@new_resource} is mounted at #{@new_resource.mount_point}")
@@ -129,11 +129,11 @@ class Chef
end
def remount_command
- return "mount -o remount,#{@new_resource.options.join(',')} #{@new_resource.mount_point}"
+ "mount -o remount,#{@new_resource.options.join(',')} #{@new_resource.mount_point}"
end
def remount_fs
- if @current_resource.mounted and @new_resource.supports[:remount]
+ if @current_resource.mounted && @new_resource.supports[:remount]
shell_out!(remount_command)
@new_resource.updated_by_last_action(true)
Chef::Log.debug("#{@new_resource} is remounted at #{@new_resource.mount_point}")
@@ -179,7 +179,7 @@ class Chef
end
::File.open("/etc/fstab", "w") do |fstab|
- contents.reverse_each { |line| fstab.puts line}
+ contents.reverse_each { |line| fstab.puts line }
end
else
Chef::Log.debug("#{@new_resource} is not enabled - nothing to do")
@@ -193,7 +193,7 @@ class Chef
def device_should_exist?
( @new_resource.device != "none" ) &&
( not network_device? ) &&
- ( not %w[ cgroup tmpfs fuse ].include? @new_resource.fstype )
+ ( not %w{ cgroup tmpfs fuse vboxsf zfs }.include? @new_resource.fstype )
end
private
@@ -210,7 +210,7 @@ class Chef
end
def device_real
- if @real_device == nil
+ if @real_device.nil?
if @new_resource.device_type == :device
@real_device = @new_resource.device
else
@@ -237,13 +237,13 @@ class Chef
def device_mount_regex
if network_device?
# ignore trailing slash
- Regexp.escape(device_real)+"/?"
+ Regexp.escape(device_real) + "/?"
elsif ::File.symlink?(device_real)
# This regular expression tries to match device_real. If that does not match it will try to match the target of device_real.
# So given a symlink like this:
# /dev/mapper/vgroot-tmp.vol -> /dev/dm-9
# First it will try to match "/dev/mapper/vgroot-tmp.vol". If there is no match it will try matching for "/dev/dm-9".
- "(?:#{Regexp.escape(device_real)}|#{Regexp.escape(::File.expand_path(::File.readlink(device_real),::File.dirname(device_real)))})"
+ "(?:#{Regexp.escape(device_real)}|#{Regexp.escape(::File.expand_path(::File.readlink(device_real), ::File.dirname(device_real)))})"
else
Regexp.escape(device_real)
end
@@ -258,10 +258,10 @@ class Chef
end
def mount_options_unchanged?
- @current_resource.fstype == @new_resource.fstype and
- @current_resource.options == @new_resource.options and
- @current_resource.dump == @new_resource.dump and
- @current_resource.pass == @new_resource.pass
+ @current_resource.fstype == @new_resource.fstype &&
+ @current_resource.options == @new_resource.options &&
+ @current_resource.dump == @new_resource.dump &&
+ @current_resource.pass == @new_resource.pass
end
end
diff --git a/lib/chef/provider/mount/solaris.rb b/lib/chef/provider/mount/solaris.rb
index deb04d4d7b..a5a7a327cb 100644
--- a/lib/chef/provider/mount/solaris.rb
+++ b/lib/chef/provider/mount/solaris.rb
@@ -1,8 +1,8 @@
# Encoding: utf-8
# Author:: Hugo Fichter
-# Author:: Lamont Granquist (<lamont@getchef.com>)
-# Author:: Joshua Timberman (<joshua@getchef.com>)
-# Copyright:: Copyright (c) 2009-2014 Chef Software, Inc
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Author:: Joshua Timberman (<joshua@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,20 +18,20 @@
# limitations under the License.
#
-require 'chef/provider/mount'
-require 'chef/log'
-require 'forwardable'
+require "chef/provider/mount"
+require "chef/log"
+require "forwardable"
class Chef
class Provider
class Mount
# Mount Solaris File systems
class Solaris < Chef::Provider::Mount
- provides :mount, platform: %w(openindiana opensolaris nexentacore omnios solaris2 smartos)
+ provides :mount, platform: %w{openindiana opensolaris nexentacore omnios solaris2 smartos}
extend Forwardable
- VFSTAB = '/etc/vfstab'.freeze
+ VFSTAB = "/etc/vfstab".freeze
def_delegator :@new_resource, :device, :device
def_delegator :@new_resource, :device_type, :device_type
@@ -58,7 +58,7 @@ class Chef
a.whyrun("Assuming device #{device} would have been created")
end
- unless fsck_device == '-'
+ unless fsck_device == "-"
requirements.assert(:mount, :remount) do |a|
a.assertion { ::File.exist?(fsck_device) }
a.failure_message(Chef::Exceptions::Mount, "Device #{fsck_device} does not exist")
@@ -75,7 +75,7 @@ class Chef
def mount_fs
actual_options = options || []
- actual_options.delete('noauto')
+ actual_options.delete("noauto")
command = "mount -F #{fstype}"
command << " -o #{actual_options.join(',')}" unless actual_options.empty?
command << " #{device} #{mount_point}"
@@ -89,8 +89,8 @@ class Chef
def remount_fs
# FIXME: Should remount always do the remount or only if the options change?
actual_options = options || []
- actual_options.delete('noauto')
- mount_options = actual_options.empty? ? '' : ",#{actual_options.join(',')}"
+ actual_options.delete("noauto")
+ mount_options = actual_options.empty? ? "" : ",#{actual_options.join(',')}"
shell_out!("mount -o remount#{mount_options} #{mount_point}")
end
@@ -117,7 +117,7 @@ class Chef
end
def etc_tempfile
- yield Tempfile.open('vfstab', '/etc')
+ yield Tempfile.open("vfstab", "/etc")
end
def mount_options_unchanged?
@@ -129,7 +129,7 @@ class Chef
current_options == new_options &&
current_resource.dump == dump &&
current_resource.pass == pass &&
- current_resource.options.include?('noauto') == !mount_at_boot?
+ current_resource.options.include?("noauto") == !mount_at_boot?
end
def update_current_resource_state
@@ -150,7 +150,7 @@ class Chef
# /dev/dsk/c1t0d0s0 on / type ufs read/write/setuid/devices/intr/largefiles/logging/xattr/onerror=panic/dev=700040 on Tue May 1 11:33:55 2012
def mounted?
mounted = false
- shell_out!('mount -v').stdout.each_line do |line|
+ shell_out!("mount -v").stdout.each_line do |line|
case line
when /^#{device_regex}\s+on\s+#{Regexp.escape(mount_point)}\s+/
Chef::Log.debug("Special device #{device} is mounted as #{mount_point}")
@@ -182,14 +182,14 @@ class Chef
options = Regexp.last_match[4]
# Store the 'mount at boot' column from vfstab as the 'noauto' option
# in current_resource.options (linux style)
- if Regexp.last_match[3] == 'no'
+ if Regexp.last_match[3] == "no"
if options.nil? || options.empty?
- options = 'noauto'
+ options = "noauto"
else
- options += ',noauto'
+ options += ",noauto"
end
end
- pass = (Regexp.last_match[2] == '-') ? 0 : Regexp.last_match[2].to_i
+ pass = (Regexp.last_match[2] == "-") ? 0 : Regexp.last_match[2].to_i
Chef::Log.debug("Found mount #{device} to #{mount_point} in #{VFSTAB}")
next
when /^[-\/\w]+\s+[-\/\w]+\s+#{Regexp.escape(mount_point)}\s+/
@@ -202,16 +202,16 @@ class Chef
end
def device_should_exist?
- !%w(tmpfs nfs ctfs proc mntfs objfs sharefs fd smbfs vxfs).include?(fstype)
+ !%w{tmpfs nfs ctfs proc mntfs objfs sharefs fd smbfs vxfs}.include?(fstype)
end
def mount_at_boot?
- options.nil? || !options.include?('noauto')
+ options.nil? || !options.include?("noauto")
end
def vfstab_write(contents)
etc_tempfile do |f|
- f.write(contents.join(''))
+ f.write(contents.join(""))
f.close
# move, preserving modes of destination file
mover = Chef::FileContentManagement::Deploy.strategy(true)
@@ -221,13 +221,13 @@ class Chef
def vfstab_entry
actual_options = unless options.nil?
- tempops = options.dup
- tempops.delete('noauto')
- tempops
- end
- autostr = mount_at_boot? ? 'yes' : 'no'
- passstr = pass == 0 ? '-' : pass
- optstr = (actual_options.nil? || actual_options.empty?) ? '-' : actual_options.join(',')
+ tempops = options.dup
+ tempops.delete("noauto")
+ tempops
+ end
+ autostr = mount_at_boot? ? "yes" : "no"
+ passstr = pass == 0 ? "-" : pass
+ optstr = (actual_options.nil? || actual_options.empty?) ? "-" : actual_options.join(",")
"\n#{device}\t#{fsck_device}\t#{mount_point}\t#{fstype}\t#{passstr}\t#{autostr}\t#{optstr}\n"
end
@@ -254,7 +254,7 @@ class Chef
def options_remove_noauto(temp_options)
new_options = []
new_options += temp_options.nil? ? [] : temp_options
- new_options.delete('noauto')
+ new_options.delete("noauto")
new_options
end
diff --git a/lib/chef/provider/mount/windows.rb b/lib/chef/provider/mount/windows.rb
index 87873474b3..0fb5aa7645 100644
--- a/lib/chef/provider/mount/windows.rb
+++ b/lib/chef/provider/mount/windows.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'chef/provider/mount'
+require "chef/provider/mount"
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
- require 'chef/util/windows/net_use'
- require 'chef/util/windows/volume'
+ require "chef/util/windows/net_use"
+ require "chef/util/windows/volume"
end
class Chef
@@ -80,6 +80,12 @@ class Chef
end
end
+ private
+
+ def mount_options_unchanged?
+ @current_resource.device == @new_resource.device
+ end
+
end
end
end
diff --git a/lib/chef/provider/noop.rb b/lib/chef/provider/noop.rb
new file mode 100644
index 0000000000..207bf7dedb
--- /dev/null
+++ b/lib/chef/provider/noop.rb
@@ -0,0 +1,37 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Provider
+ class Noop < Chef::Provider
+ def load_current_resource; end
+
+ def respond_to_missing?(method_sym, include_private = false)
+ method_sym.to_s.start_with?("action_") || super
+ end
+
+ def method_missing(method_sym, *arguments, &block)
+ if method_sym.to_s =~ /^action_/
+ Chef::Log.debug("NoOp-ing for #{method_sym}")
+ else
+ super
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/ohai.rb b/lib/chef/provider/ohai.rb
index b7f4aa704b..c36655077b 100644
--- a/lib/chef/provider/ohai.rb
+++ b/lib/chef/provider/ohai.rb
@@ -1,6 +1,6 @@
#
# Author:: Michael Leianrtas (<mleinartas@gmail.com>)
-# Copyright:: Copyright (c) 2010 Michael Leinartas
+# Copyright:: Copyright 2010-2016, Michael Leinartas
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,13 @@
# limitations under the License.
#
-require 'ohai'
+require "ohai"
class Chef
class Provider
class Ohai < Chef::Provider
+ use_inline_resources
+
provides :ohai
def whyrun_supported?
@@ -31,17 +33,17 @@ class Chef
true
end
- def action_reload
+ action :reload do
converge_by("re-run ohai and merge results into node attributes") do
ohai = ::Ohai::System.new
- # If @new_resource.plugin is nil, ohai will reload all the plugins
+ # If new_resource.plugin is nil, ohai will reload all the plugins
# Otherwise it will only reload the specified plugin
# Note that any changes to plugins, or new plugins placed on
# the path are picked up by ohai.
- ohai.all_plugins @new_resource.plugin
+ ohai.all_plugins new_resource.plugin
node.automatic_attrs.merge! ohai.data
- Chef::Log.info("#{@new_resource} reloaded")
+ Chef::Log.info("#{new_resource} reloaded")
end
end
end
diff --git a/lib/chef/provider/osx_profile.rb b/lib/chef/provider/osx_profile.rb
new file mode 100644
index 0000000000..9ea68f4c9f
--- /dev/null
+++ b/lib/chef/provider/osx_profile.rb
@@ -0,0 +1,257 @@
+#
+# Author:: Nate Walck (<nate.walck@gmail.com>)
+# Copyright:: Copyright 2015-2016, Facebook, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/log"
+require "chef/provider"
+require "chef/resource"
+require "chef/resource/file"
+require "uuidtools"
+
+class Chef
+ class Provider
+ class OsxProfile < Chef::Provider
+ include Chef::Mixin::Command
+ provides :osx_profile, os: "darwin"
+ provides :osx_config_profile, os: "darwin"
+
+ def whyrun_supported?
+ true
+ end
+
+ def load_current_resource
+ @current_resource = Chef::Resource::OsxProfile.new(new_resource.name)
+ current_resource.profile_name(new_resource.profile_name)
+
+ all_profiles = get_installed_profiles
+ new_resource.profile(
+ new_resource.profile ||
+ new_resource.profile_name
+ )
+
+ @new_profile_hash = get_profile_hash(new_resource.profile)
+ if @new_profile_hash
+ @new_profile_hash["PayloadUUID"] =
+ config_uuid(@new_profile_hash)
+ end
+
+ if @new_profile_hash
+ @new_profile_identifier = @new_profile_hash["PayloadIdentifier"]
+ else
+ @new_profile_identifier = new_resource.identifier ||
+ new_resource.profile_name
+ end
+
+ current_profile = nil
+ if all_profiles && !all_profiles.empty?
+ current_profile = all_profiles["_computerlevel"].find do |item|
+ item["ProfileIdentifier"] == @new_profile_identifier
+ end
+ end
+ current_resource.profile(current_profile)
+ end
+
+ def define_resource_requirements
+ requirements.assert(:remove) do |a|
+ if @new_profile_identifier
+ a.assertion do
+ !@new_profile_identifier.nil? &&
+ !@new_profile_identifier.end_with?(".mobileconfig") &&
+ /^\w+(?:(\.| )\w+)+$/.match(@new_profile_identifier)
+ end
+ a.failure_message RuntimeError, "when removing using the identifier attribute, it must match the profile identifier"
+ else
+ new_profile_name = new_resource.profile_name
+ a.assertion do
+ !new_profile_name.end_with?(".mobileconfig") &&
+ /^\w+(?:(\.| )\w+)+$/.match(new_profile_name)
+ end
+ a.failure_message RuntimeError, "When removing by resource name, it must match the profile identifier "
+ end
+ end
+
+ requirements.assert(:install) do |a|
+ if @new_profile_hash.is_a?(Hash)
+ a.assertion do
+ @new_profile_hash.include?("PayloadIdentifier")
+ end
+ a.failure_message RuntimeError, "The specified profile does not seem to be valid"
+ end
+ if @new_profile_hash.is_a?(String)
+ a.assertion do
+ @new_profile_hash.end_with?(".mobileconfig")
+ end
+ a.failure_message RuntimeError, "#{new_profile_hash}' is not a valid profile"
+ end
+ end
+ end
+
+ def action_install
+ unless profile_installed?
+ converge_by("install profile #{@new_profile_identifier}") do
+ profile_path = write_profile_to_disk
+ install_profile(profile_path)
+ get_installed_profiles(true)
+ end
+ end
+ end
+
+ def action_remove
+ # Clean up profile after removing it
+ if profile_installed?
+ converge_by("remove profile #{@new_profile_identifier}") do
+ remove_profile
+ get_installed_profiles(true)
+ end
+ end
+ end
+
+ def load_profile_hash(new_profile)
+ # file must exist in cookbook
+ if new_profile.end_with?(".mobileconfig")
+ unless cookbook_file_available?(new_profile)
+ error_string = "#{self}: '#{new_profile}' not found in cookbook"
+ raise Chef::Exceptions::FileNotFound, error_string
+ end
+ cookbook_profile = cache_cookbook_profile(new_profile)
+ read_plist(cookbook_profile)
+ else
+ nil
+ end
+ end
+
+ def cookbook_file_available?(cookbook_file)
+ run_context.has_cookbook_file_in_cookbook?(
+ new_resource.cookbook_name, cookbook_file
+ )
+ end
+
+ def get_cache_dir
+ cache_dir = Chef::FileCache.create_cache_path(
+ "profiles/#{new_resource.cookbook_name}"
+ )
+ end
+
+ def cache_cookbook_profile(cookbook_file)
+ Chef::FileCache.create_cache_path(
+ ::File.join(
+ "profiles",
+ new_resource.cookbook_name,
+ ::File.dirname(cookbook_file)
+ )
+ )
+ remote_file = Chef::Resource::CookbookFile.new(
+ ::File.join(
+ get_cache_dir,
+ "#{cookbook_file}.remote"
+ ),
+ run_context
+ )
+ remote_file.cookbook_name = new_resource.cookbook_name
+ remote_file.source(cookbook_file)
+ remote_file.backup(false)
+ remote_file.run_action(:create)
+ remote_file.path
+ end
+
+ def get_profile_hash(new_profile)
+ if new_profile.is_a?(Hash)
+ new_profile
+ elsif new_profile.is_a?(String)
+ load_profile_hash(new_profile)
+ end
+ end
+
+ def config_uuid(profile)
+ # Make a UUID of the profile contents and return as string
+ UUIDTools::UUID.sha1_create(
+ UUIDTools::UUID_DNS_NAMESPACE,
+ profile.to_s
+ ).to_s
+ end
+
+ def write_profile_to_disk
+ new_resource.path(Chef::FileCache.create_cache_path("profiles"))
+ tempfile = Chef::FileContentManagement::Tempfile.new(new_resource).tempfile
+ tempfile.write(@new_profile_hash.to_plist)
+ tempfile.close
+ tempfile.path
+ end
+
+ def install_profile(profile_path)
+ cmd = "profiles -I -F '#{profile_path}'"
+ Chef::Log.debug("cmd: #{cmd}")
+ shellout_results = shell_out(cmd)
+ shellout_results.exitstatus
+ end
+
+ def remove_profile
+ cmd = "profiles -R -p '#{@new_profile_identifier}'"
+ Chef::Log.debug("cmd: #{cmd}")
+ shellout_results = shell_out(cmd)
+ shellout_results.exitstatus
+ end
+
+ def get_installed_profiles(update = nil)
+ if update
+ node.run_state[:config_profiles] = query_installed_profiles
+ else
+ node.run_state[:config_profiles] ||= query_installed_profiles
+ end
+ end
+
+ def query_installed_profiles
+ # Dump all profile metadata to a tempfile
+ tempfile = generate_tempfile
+ write_installed_profiles(tempfile)
+ installed_profiles = read_plist(tempfile)
+ Chef::Log.debug("Saved profiles to run_state")
+ # Clean up the temp file as we do not need it anymore
+ ::File.unlink(tempfile)
+ installed_profiles
+ end
+
+ def generate_tempfile
+ tempfile = ::Dir::Tmpname.create("allprofiles.plist") {}
+ end
+
+ def write_installed_profiles(tempfile)
+ cmd = "profiles -P -o '#{tempfile}'"
+ shell_out!(cmd)
+ end
+
+ def read_plist(xml_file)
+ Plist.parse_xml(xml_file)
+ end
+
+ def profile_installed?
+ # Profile Identifier and UUID must match a currently installed profile
+ if current_resource.profile.nil? || current_resource.profile.empty?
+ false
+ else
+ if new_resource.action.include?(:remove)
+ true
+ else
+ current_resource.profile["ProfileUUID"] ==
+ @new_profile_hash["PayloadUUID"]
+ end
+ end
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb
index 880104bff7..97aefbd559 100644
--- a/lib/chef/provider/package.rb
+++ b/lib/chef/provider/package.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,31 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
-require 'chef/mixin/command'
-require 'chef/log'
-require 'chef/file_cache'
-require 'chef/platform'
+require "chef/mixin/shell_out"
+require "chef/mixin/command"
+require "chef/mixin/subclass_directive"
+require "chef/log"
+require "chef/file_cache"
+require "chef/platform"
+require "chef/decorator/lazy_array"
+require "shellwords"
class Chef
class Provider
class Package < Chef::Provider
include Chef::Mixin::Command
include Chef::Mixin::ShellOut
+ extend Chef::Mixin::SubclassDirective
+
+ use_inline_resources
+
+ # subclasses declare this if they want all their arguments as arrays of packages and names
+ subclass_directive :use_multipackage_api
+ # subclasses declare this if they want sources (filenames) pulled from their package names
+ subclass_directive :use_package_name_for_source
+ # keeps package_names_for_targets and versions_for_targets indexed the same as package_name at
+ # the cost of having the subclass needing to deal with nils
+ subclass_directive :allow_nils
#
# Hook that subclasses use to populate the candidate_version(s)
@@ -39,46 +53,55 @@ class Chef
@candidate_version = nil
end
+ def options
+ if new_resource.options.is_a?(String)
+ new_resource.options.shellsplit
+ else
+ new_resource.options
+ end
+ end
+
def whyrun_supported?
true
end
def check_resource_semantics!
- if new_resource.package_name.is_a?(Array) && new_resource.source != nil
+ # FIXME: this is not universally true and subclasses are needing to override this and no-ops it. It should be turned into
+ # another "subclass_directive" and the apt and yum providers should declare that they need this behavior.
+ if new_resource.package_name.is_a?(Array) && !new_resource.source.nil?
raise Chef::Exceptions::InvalidResourceSpecification, "You may not specify both multipackage and source"
end
end
- def load_current_resource
- end
+ def load_current_resource; end
def define_resource_requirements
# XXX: upgrade with a specific version doesn't make a whole lot of sense, but why don't we throw this anyway if it happens?
# if not, shouldn't we raise to tell the user to use install instead of upgrade if they want to pin a version?
requirements.assert(:install) do |a|
a.assertion { candidates_exist_for_all_forced_changes? }
- a.failure_message(Chef::Exceptions::Package, "No version specified, and no candidate version available for #{forced_packages_missing_candidates.join(", ")}")
- a.whyrun("Assuming a repository that offers #{forced_packages_missing_candidates.join(", ")} would have been configured")
+ a.failure_message(Chef::Exceptions::Package, "No version specified, and no candidate version available for #{forced_packages_missing_candidates.join(', ')}")
+ a.whyrun("Assuming a repository that offers #{forced_packages_missing_candidates.join(', ')} would have been configured")
end
# XXX: Does it make sense to pass in a source with :upgrade? Probably
# not, but as with the above comment, we don't yet enforce such a thing,
# so we'll just leave things as-is for now.
requirements.assert(:upgrade, :install) do |a|
- a.assertion { candidates_exist_for_all_uninstalled? || new_resource.source }
- a.failure_message(Chef::Exceptions::Package, "No candidate version available for #{packages_missing_candidates.join(", ")}")
- a.whyrun("Assuming a repository that offers #{packages_missing_candidates.join(", ")} would have been configured")
+ a.assertion { candidates_exist_for_all_uninstalled? || new_resource.source }
+ a.failure_message(Chef::Exceptions::Package, "No candidate version available for #{packages_missing_candidates.join(', ')}")
+ a.whyrun("Assuming a repository that offers #{packages_missing_candidates.join(', ')} would have been configured")
end
end
- def action_install
+ action :install do
unless target_version_array.any?
- Chef::Log.debug("#{@new_resource} is already installed - nothing to do")
+ Chef::Log.debug("#{new_resource} is already installed - nothing to do")
return
end
# @todo: move the preseed code out of the base class (and complete the fix for Array of preseeds? ugh...)
- if @new_resource.response_file
+ if new_resource.response_file
if preseed_file = get_preseed_file(package_names_for_targets, versions_for_targets)
converge_by("preseed package #{package_names_for_targets}") do
preseed_package(preseed_file)
@@ -86,12 +109,11 @@ class Chef
end
end
- # XXX: mutating the new resource is generally bad
- @new_resource.version(versions_for_new_resource)
-
converge_by(install_description) do
- install_package(package_names_for_targets, versions_for_targets)
- Chef::Log.info("#{@new_resource} installed #{package_names_for_targets} at #{versions_for_targets}")
+ multipackage_api_adapter(package_names_for_targets, versions_for_targets) do |name, version|
+ install_package(name, version)
+ end
+ Chef::Log.info("#{new_resource} installed #{package_names_for_targets} at #{versions_for_targets}")
end
end
@@ -107,24 +129,23 @@ class Chef
private :install_description
- def action_upgrade
- if !target_version_array.any?
- Chef::Log.debug("#{@new_resource} no versions to upgrade - nothing to do")
+ action :upgrade do
+ unless target_version_array.any?
+ Chef::Log.debug("#{new_resource} no versions to upgrade - nothing to do")
return
end
- # XXX: mutating the new resource is generally bad
- @new_resource.version(versions_for_new_resource)
-
converge_by(upgrade_description) do
- upgrade_package(package_names_for_targets, versions_for_targets)
- log_allow_downgrade = allow_downgrade ? '(allow_downgrade)' : ''
- Chef::Log.info("#{@new_resource} upgraded#{log_allow_downgrade} #{package_names_for_targets} to #{versions_for_targets}")
+ multipackage_api_adapter(package_names_for_targets, versions_for_targets) do |name, version|
+ upgrade_package(name, version)
+ end
+ log_allow_downgrade = allow_downgrade ? "(allow_downgrade)" : ""
+ Chef::Log.info("#{new_resource} upgraded#{log_allow_downgrade} #{package_names_for_targets} to #{versions_for_targets}")
end
end
def upgrade_description
- log_allow_downgrade = allow_downgrade ? '(allow_downgrade)' : ''
+ log_allow_downgrade = allow_downgrade ? "(allow_downgrade)" : ""
description = []
target_version_array.each_with_index do |target_version, i|
next if target_version.nil?
@@ -138,16 +159,17 @@ class Chef
private :upgrade_description
- # @todo: ability to remove an array of packages
- def action_remove
+ action :remove do
if removing_package?
- description = @new_resource.version ? "version #{@new_resource.version} of " : ""
- converge_by("remove #{description}package #{@current_resource.package_name}") do
- remove_package(@current_resource.package_name, @new_resource.version)
- Chef::Log.info("#{@new_resource} removed")
+ description = new_resource.version ? "version #{new_resource.version} of " : ""
+ converge_by("remove #{description}package #{current_resource.package_name}") do
+ multipackage_api_adapter(current_resource.package_name, new_resource.version) do |name, version|
+ remove_package(name, version)
+ end
+ Chef::Log.info("#{new_resource} removed")
end
else
- Chef::Log.debug("#{@new_resource} package does not exist - nothing to do")
+ Chef::Log.debug("#{new_resource} package does not exist - nothing to do")
end
end
@@ -172,80 +194,166 @@ class Chef
end
end
- # @todo: ability to purge an array of packages
- def action_purge
+ action :purge do
if removing_package?
- description = @new_resource.version ? "version #{@new_resource.version} of" : ""
- converge_by("purge #{description} package #{@current_resource.package_name}") do
- purge_package(@current_resource.package_name, @new_resource.version)
- Chef::Log.info("#{@new_resource} purged")
+ description = new_resource.version ? "version #{new_resource.version} of" : ""
+ converge_by("purge #{description} package #{current_resource.package_name}") do
+ multipackage_api_adapter(current_resource.package_name, new_resource.version) do |name, version|
+ purge_package(name, version)
+ end
+ Chef::Log.info("#{new_resource} purged")
end
end
end
- # @todo: ability to reconfigure an array of packages
- def action_reconfig
- if @current_resource.version == nil then
- Chef::Log.debug("#{@new_resource} is NOT installed - nothing to do")
+ action :reconfig do
+ if current_resource.version.nil?
+ Chef::Log.debug("#{new_resource} is NOT installed - nothing to do")
return
end
- unless @new_resource.response_file then
- Chef::Log.debug("#{@new_resource} no response_file provided - nothing to do")
+ unless new_resource.response_file
+ Chef::Log.debug("#{new_resource} no response_file provided - nothing to do")
return
end
- if preseed_file = get_preseed_file(@new_resource.package_name, @current_resource.version)
- converge_by("reconfigure package #{@new_resource.package_name}") do
+ if preseed_file = get_preseed_file(new_resource.package_name, current_resource.version)
+ converge_by("reconfigure package #{new_resource.package_name}") do
preseed_package(preseed_file)
- reconfig_package(@new_resource.package_name, @current_resource.version)
- Chef::Log.info("#{@new_resource} reconfigured")
+ multipackage_api_adapter(new_resource.package_name, current_resource.version) do |name, version|
+ reconfig_package(name, version)
+
+ end
+ Chef::Log.info("#{new_resource} reconfigured")
end
else
- Chef::Log.debug("#{@new_resource} preseeding has not changed - nothing to do")
+ Chef::Log.debug("#{new_resource} preseeding has not changed - nothing to do")
end
end
+ def action_lock
+ if package_locked(new_resource.name, new_resource.version) == false
+ description = new_resource.version ? "version #{new_resource.version} of " : ""
+ converge_by("lock #{description}package #{current_resource.package_name}") do
+ multipackage_api_adapter(current_resource.package_name, new_resource.version) do |name, version|
+ lock_package(name, version)
+ Chef::Log.info("#{new_resource} locked")
+ end
+ end
+ else
+ Chef::Log.debug("#{new_resource} is already locked")
+ end
+ end
+
+ def action_unlock
+ if package_locked(new_resource.name, new_resource.version) == true
+ description = new_resource.version ? "version #{new_resource.version} of " : ""
+ converge_by("unlock #{description}package #{current_resource.package_name}") do
+ multipackage_api_adapter(current_resource.package_name, new_resource.version) do |name, version|
+ unlock_package(name, version)
+ Chef::Log.info("#{new_resource} unlocked")
+ end
+ end
+ else
+ Chef::Log.debug("#{new_resource} is already unlocked")
+ end
+ end
+
+ def package_locked(name, version)
+ raise Chef::Exceptions::UnsupportedAction, "#{self} has no way to detect if package is locked"
+ end
+
# @todo use composition rather than inheritance
+
+ def multipackage_api_adapter(name, version)
+ if use_multipackage_api?
+ yield [name].flatten, [version].flatten
+ else
+ yield name, version
+ end
+ end
+
def install_package(name, version)
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :install"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :install"
end
def upgrade_package(name, version)
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :upgrade"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :upgrade"
end
def remove_package(name, version)
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :remove"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :remove"
end
def purge_package(name, version)
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :purge"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :purge"
end
def preseed_package(file)
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support pre-seeding package install/upgrade instructions"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support pre-seeding package install/upgrade instructions"
end
def reconfig_package(name, version)
- raise( Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reconfig" )
+ raise( Chef::Exceptions::UnsupportedAction, "#{self} does not support :reconfig" )
+ end
+
+ def lock_package(name, version)
+ raise( Chef::Exceptions::UnsupportedAction, "#{self} does not support :lock" )
+ end
+
+ def unlock_package(name, version)
+ raise( Chef::Exceptions::UnsupportedAction, "#{self} does not support :unlock" )
end
- # this is heavily used by subclasses
+ # used by subclasses. deprecated. use #a_to_s instead.
def expand_options(options)
+ # its deprecated but still work to do to deprecate it fully
+ #Chef.deprecated(:package_misc, "expand_options is deprecated, use shell_out_compact or shell_out_compact_timeout instead")
options ? " #{options}" : ""
end
- # this is public and overridden by subclasses (rubygems package implements '>=' and '~>' operators)
- def target_version_already_installed?(current_version, new_version)
- new_version == current_version
+ # Check the current_version against either the candidate_version or the new_version
+ #
+ # For some reason the windows provider subclasses this (to implement passing Arrays to
+ # versions for some reason other than multipackage stuff, which is mildly terrifying).
+ #
+ # This MUST have 'equality' semantics -- the exact thing matches the exact thing.
+ #
+ # The current_version should probably be dropped out of the method signature, it should
+ # always be the first argument.
+ #
+ # The name is not just bad, but i find it completely misleading, consider:
+ #
+ # target_version_already_installed?(current_version, new_version)
+ # target_version_already_installed?(current_version, candidate_version)
+ #
+ # which of those is the 'target_version'? i'd say the new_version and i'm confused when
+ # i see it called with the candidate_version.
+ #
+ # `current_version_equals?(version)` would be a better name
+ def target_version_already_installed?(current_version, target_version)
+ return false unless current_version && target_version
+ current_version == target_version
+ end
+
+ # Check the current_version against the new_resource.version, possibly using fuzzy
+ # matching criteria.
+ #
+ # Subclasses MAY override this to provide fuzzy matching on the resource ('>=' and '~>' stuff)
+ #
+ # This should only ever be offered the same arguments (so they should most likely be
+ # removed from the method signature).
+ #
+ # `new_version_satisfied?()` might be a better name
+ def version_requirement_satisfied?(current_version, new_version)
+ target_version_already_installed?(current_version, new_version)
end
# @todo: extract apt/dpkg specific preseeding to a helper class
def get_preseed_file(name, version)
resource = preseed_resource(name, version)
resource.run_action(:create)
- Chef::Log.debug("#{@new_resource} fetched preseed file to #{resource.path}")
+ Chef::Log.debug("#{new_resource} fetched preseed file to #{resource.path}")
if resource.updated_by_last_action?
resource.path
@@ -257,26 +365,26 @@ class Chef
# @todo: extract apt/dpkg specific preseeding to a helper class
def preseed_resource(name, version)
# A directory in our cache to store this cookbook's preseed files in
- file_cache_dir = Chef::FileCache.create_cache_path("preseed/#{@new_resource.cookbook_name}")
+ file_cache_dir = Chef::FileCache.create_cache_path("preseed/#{new_resource.cookbook_name}")
# The full path where the preseed file will be stored
cache_seed_to = "#{file_cache_dir}/#{name}-#{version}.seed"
- Chef::Log.debug("#{@new_resource} fetching preseed file to #{cache_seed_to}")
+ Chef::Log.debug("#{new_resource} fetching preseed file to #{cache_seed_to}")
- if template_available?(@new_resource.response_file)
- Chef::Log.debug("#{@new_resource} fetching preseed file via Template")
+ if template_available?(new_resource.response_file)
+ Chef::Log.debug("#{new_resource} fetching preseed file via Template")
remote_file = Chef::Resource::Template.new(cache_seed_to, run_context)
- remote_file.variables(@new_resource.response_file_variables)
- elsif cookbook_file_available?(@new_resource.response_file)
- Chef::Log.debug("#{@new_resource} fetching preseed file via cookbook_file")
+ remote_file.variables(new_resource.response_file_variables)
+ elsif cookbook_file_available?(new_resource.response_file)
+ Chef::Log.debug("#{new_resource} fetching preseed file via cookbook_file")
remote_file = Chef::Resource::CookbookFile.new(cache_seed_to, run_context)
else
- message = "No template or cookbook file found for response file #{@new_resource.response_file}"
+ message = "No template or cookbook file found for response file #{new_resource.response_file}"
raise Chef::Exceptions::FileNotFound, message
end
- remote_file.cookbook_name = @new_resource.cookbook_name
- remote_file.source(@new_resource.response_file)
+ remote_file.cookbook_name = new_resource.cookbook_name
+ remote_file.source(new_resource.response_file)
remote_file.backup(false)
remote_file
end
@@ -299,9 +407,12 @@ class Chef
def package_names_for_targets
package_names_for_targets = []
target_version_array.each_with_index do |target_version, i|
- next if target_version.nil?
- package_name = package_name_array[i]
- package_names_for_targets.push(package_name)
+ if !target_version.nil?
+ package_name = package_name_array[i]
+ package_names_for_targets.push(package_name)
+ else
+ package_names_for_targets.push(nil) if allow_nils?
+ end
end
multipackage? ? package_names_for_targets : package_names_for_targets[0]
end
@@ -316,24 +427,15 @@ class Chef
def versions_for_targets
versions_for_targets = []
target_version_array.each_with_index do |target_version, i|
- next if target_version.nil?
- versions_for_targets.push(target_version)
+ if !target_version.nil?
+ versions_for_targets.push(target_version)
+ else
+ versions_for_targets.push(nil) if allow_nils?
+ end
end
multipackage? ? versions_for_targets : versions_for_targets[0]
end
- # We need to mutate @new_resource.version() for some reason and this is a helper so that we inject the right
- # class (String or Array) into that attribute based on if we're handling an array of package names or not.
- #
- # @return [String, Array<String>] target_versions coerced into the correct type for back-compat
- def versions_for_new_resource
- if multipackage?
- target_version_array
- else
- target_version_array[0]
- end
- end
-
# Return an array indexed the same as *_version_array which contains either the target version to install/upgrade to
# or else nil if the package is not being modified.
#
@@ -346,12 +448,15 @@ class Chef
each_package do |package_name, new_version, current_version, candidate_version|
case action
when :upgrade
-
- if !candidate_version
- Chef::Log.debug("#{new_resource} #{package_name} has no candidate_version to upgrade to")
+ if target_version_already_installed?(current_version, new_version)
+ # this is an odd use case
+ Chef::Log.debug("#{new_resource} #{package_name} #{new_version} is already installed -- you are equality pinning with an :upgrade action, this may be deprecated in the future")
target_version_array.push(nil)
- elsif current_version == candidate_version
- Chef::Log.debug("#{new_resource} #{package_name} the #{candidate_version} is already installed")
+ elsif target_version_already_installed?(current_version, candidate_version)
+ Chef::Log.debug("#{new_resource} #{package_name} #{candidate_version} is already installed")
+ target_version_array.push(nil)
+ elsif candidate_version.nil?
+ Chef::Log.debug("#{new_resource} #{package_name} has no candidate_version to upgrade to")
target_version_array.push(nil)
else
Chef::Log.debug("#{new_resource} #{package_name} is out of date, will upgrade to #{candidate_version}")
@@ -361,7 +466,7 @@ class Chef
when :install
if new_version
- if target_version_already_installed?(current_version, new_version)
+ if version_requirement_satisfied?(current_version, new_version)
Chef::Log.debug("#{new_resource} #{package_name} #{current_version} satisifies #{new_version} requirement")
target_version_array.push(nil)
else
@@ -403,7 +508,7 @@ class Chef
begin
missing = []
each_package do |package_name, new_version, current_version, candidate_version|
- missing.push(package_name) if candidate_version.nil? && current_version.nil?
+ missing.push(package_name) if current_version.nil? && candidate_version.nil?
end
missing
end
@@ -428,7 +533,7 @@ class Chef
missing = []
each_package do |package_name, new_version, current_version, candidate_version|
next if new_version.nil? || current_version.nil?
- if candidate_version.nil? && !target_version_already_installed?(current_version, new_version)
+ if !version_requirement_satisfied?(current_version, new_version) && candidate_version.nil?
missing.push(package_name)
end
end
@@ -460,7 +565,9 @@ class Chef
# @return [Array] candidate_version(s) as an array
def candidate_version_array
- [ candidate_version ].flatten
+ # NOTE: even with use_multipackage_api candidate_version may be a bare nil and need wrapping
+ # ( looking at you, dpkg provider... )
+ Chef::Decorator::LazyArray.new { [ candidate_version ].flatten }
end
# @return [Array] current_version(s) as an array
@@ -473,6 +580,37 @@ class Chef
[ new_resource.version ].flatten.map { |v| v.to_s.empty? ? nil : v }
end
+ # TIP: less error prone to simply always call resolved_source_array, even if you
+ # don't think that you need to.
+ #
+ # @return [Array] new_resource.source as an array
+ def source_array
+ if new_resource.source.nil?
+ package_name_array.map { nil }
+ else
+ [ new_resource.source ].flatten
+ end
+ end
+
+ # Helper to handle use_package_name_for_source to convert names into local packages to install.
+ #
+ # @return [Array] Array of sources with package_names converted to sources
+ def resolved_source_array
+ @resolved_source_array ||=
+ begin
+ source_array.each_with_index.map do |source, i|
+ package_name = package_name_array[i]
+ # we require at least one '/' in the package_name to avoid [XXX_]package 'foo' breaking due to a random 'foo' file in cwd
+ if use_package_name_for_source? && source.nil? && package_name.match(/#{::File::SEPARATOR}/) && ::File.exist?(package_name)
+ Chef::Log.debug("No package source specified, but #{package_name} exists on filesystem, using #{package_name} as source.")
+ package_name
+ else
+ source
+ end
+ end
+ end
+ end
+
# @todo: extract apt/dpkg specific preseeding to a helper class
def template_available?(path)
run_context.has_template_in_cookbook?(new_resource.cookbook_name, path)
@@ -484,15 +622,13 @@ class Chef
end
def allow_downgrade
- if @new_resource.respond_to?("allow_downgrade")
- @new_resource.allow_downgrade
+ if new_resource.respond_to?("allow_downgrade")
+ new_resource.allow_downgrade
else
false
end
end
- private
-
def shell_out_with_timeout(*command_args)
shell_out(*add_timeout_option(command_args))
end
@@ -502,18 +638,19 @@ class Chef
end
def add_timeout_option(command_args)
+ # this is deprecated but its not quite done yet
+ #Chef.deprecated(:package_misc, "shell_out_with_timeout and add_timeout_option are deprecated methods, use shell_out_compact_timeout instead")
args = command_args.dup
if args.last.is_a?(Hash)
options = args.pop.dup
options[:timeout] = new_resource.timeout if new_resource.timeout
- options[:timeout] = 900 unless options.has_key?(:timeout)
+ options[:timeout] = 900 unless options.key?(:timeout)
args << options
else
- args << { :timeout => new_resource.timeout ? new_resource.timeout : 900 }
+ args << { timeout: new_resource.timeout ? new_resource.timeout : 900 }
end
args
end
-
end
end
end
diff --git a/lib/chef/provider/package/aix.rb b/lib/chef/provider/package/aix.rb
index 5165f4b4ea..5af5f5afad 100644
--- a/lib/chef/provider/package/aix.rb
+++ b/lib/chef/provider/package/aix.rb
@@ -1,6 +1,6 @@
#
# Author:: Deepali Jagtap
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
#
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'chef/mixin/get_source_from_package'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
+require "chef/mixin/get_source_from_package"
class Chef
class Provider
@@ -34,45 +34,45 @@ class Chef
def define_resource_requirements
super
requirements.assert(:install) do |a|
- a.assertion { @new_resource.source }
- a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install"
+ a.assertion { new_resource.source }
+ a.failure_message Chef::Exceptions::Package, "Source for package #{new_resource.name} required for action install"
end
requirements.assert(:all_actions) do |a|
- a.assertion { !@new_resource.source || @package_source_found }
- a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
- a.whyrun "would assume #{@new_resource.source} would be have previously been made available"
+ a.assertion { !new_resource.source || package_source_found? }
+ a.failure_message Chef::Exceptions::Package, "Package #{new_resource.name} not found: #{new_resource.source}"
+ a.whyrun "would assume #{new_resource.source} would be have previously been made available"
end
end
def load_current_resource
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
- @new_resource.version(nil)
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
- if @new_resource.source
- @package_source_found = ::File.exists?(@new_resource.source)
- if @package_source_found
- Chef::Log.debug("#{@new_resource} checking pkg status")
- ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}")
- ret.stdout.each_line do | line |
- case line
- when /#{@new_resource.package_name}:/
- fields = line.split(":")
- @new_resource.version(fields[2])
- end
+ if package_source_found?
+ Chef::Log.debug("#{new_resource} checking pkg status")
+ ret = shell_out_compact_timeout("installp", "-L", "-d", new_resource.source)
+ ret.stdout.each_line do |line|
+ case line
+ when /:#{new_resource.package_name}:/
+ fields = line.split(":")
+ new_resource.version(fields[2])
+ when /^#{new_resource.package_name}:/
+ Chef::Log.warn("You are installing a bff package by product name. For idempotent installs, please install individual filesets")
+ fields = line.split(":")
+ new_resource.version(fields[2])
end
- raise Chef::Exceptions::Package, "package source #{@new_resource.source} does not provide package #{@new_resource.package_name}" unless @new_resource.version
end
+ raise Chef::Exceptions::Package, "package source #{new_resource.source} does not provide package #{new_resource.package_name}" unless new_resource.version
end
- Chef::Log.debug("#{@new_resource} checking install state")
- ret = shell_out_with_timeout("lslpp -lcq #{@current_resource.package_name}")
- ret.stdout.each_line do | line |
+ Chef::Log.debug("#{new_resource} checking install state")
+ ret = shell_out_compact_timeout("lslpp", "-lcq", current_resource.package_name)
+ ret.stdout.each_line do |line|
case line
- when /#{@current_resource.package_name}/
+ when /#{current_resource.package_name}/
fields = line.split(":")
- Chef::Log.debug("#{@new_resource} version #{fields[2]} is already installed")
- @current_resource.version(fields[2])
+ Chef::Log.debug("#{new_resource} version #{fields[2]} is already installed")
+ current_resource.version(fields[2])
end
end
@@ -80,23 +80,25 @@ class Chef
raise Chef::Exceptions::Package, "lslpp failed - #{ret.format_for_exception}!"
end
- @current_resource
+ current_resource
end
def candidate_version
return @candidate_version if @candidate_version
- ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}")
- ret.stdout.each_line do | line |
- case line
- when /\w:#{Regexp.escape(@new_resource.package_name)}:(.*)/
- fields = line.split(":")
- @candidate_version = fields[2]
- @new_resource.version(fields[2])
- Chef::Log.debug("#{@new_resource} setting install candidate version to #{@candidate_version}")
+ if package_source_found?
+ ret = shell_out_compact_timeout("installp", "-L", "-d", new_resource.source)
+ ret.stdout.each_line do |line|
+ case line
+ when /\w:#{Regexp.escape(new_resource.package_name)}:(.*)/
+ fields = line.split(":")
+ @candidate_version = fields[2]
+ new_resource.version(fields[2])
+ Chef::Log.debug("#{new_resource} setting install candidate version to #{@candidate_version}")
+ end
+ end
+ unless ret.exitstatus == 0
+ raise Chef::Exceptions::Package, "installp -L -d #{new_resource.source} - #{ret.format_for_exception}!"
end
- end
- unless ret.exitstatus == 0
- raise Chef::Exceptions::Package, "installp -L -d #{@new_resource.source} - #{ret.format_for_exception}!"
end
@candidate_version
end
@@ -109,28 +111,32 @@ class Chef
# So far, the code has been tested only with standalone packages.
#
def install_package(name, version)
- Chef::Log.debug("#{@new_resource} package install options: #{@new_resource.options}")
- if @new_resource.options.nil?
- shell_out_with_timeout!( "installp -aYF -d #{@new_resource.source} #{@new_resource.package_name}" )
- Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
+ Chef::Log.debug("#{new_resource} package install options: #{options}")
+ if options.nil?
+ shell_out_compact_timeout!("installp", "-aYF", "-d", new_resource.source, new_resource.package_name)
+ Chef::Log.debug("#{new_resource} installed version #{new_resource.version} from: #{new_resource.source}")
else
- shell_out_with_timeout!( "installp -aYF #{expand_options(@new_resource.options)} -d #{@new_resource.source} #{@new_resource.package_name}" )
- Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
+ shell_out_compact_timeout!("installp", "-aYF", options, "-d", new_resource.source, new_resource.package_name)
+ Chef::Log.debug("#{new_resource} installed version #{new_resource.version} from: #{new_resource.source}")
end
end
- alias_method :upgrade_package, :install_package
+ alias upgrade_package install_package
def remove_package(name, version)
- if @new_resource.options.nil?
- shell_out_with_timeout!( "installp -u #{name}" )
- Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
+ if options.nil?
+ shell_out_compact_timeout!("installp", "-u", name)
+ Chef::Log.debug("#{new_resource} removed version #{new_resource.version}")
else
- shell_out_with_timeout!( "installp -u #{expand_options(@new_resource.options)} #{name}" )
- Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
+ shell_out_compact_timeout!("installp", "-u", options, name)
+ Chef::Log.debug("#{new_resource} removed version #{new_resource.version}")
end
end
+ def package_source_found?
+ @package_source_found ||= new_resource.source && ::File.exist?(new_resource.source)
+ end
+
end
end
end
diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb
index e109c9966a..3f8c34f50c 100644
--- a/lib/chef/provider/package/apt.rb
+++ b/lib/chef/provider/package/apt.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,133 +16,77 @@
# limitations under the License.
#
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
+require "chef/provider/package"
+require "chef/resource/apt_package"
class Chef
class Provider
class Package
class Apt < Chef::Provider::Package
+ use_multipackage_api
provides :package, platform_family: "debian"
provides :apt_package, os: "linux"
- # return [Hash] mapping of package name to Boolean value
- attr_accessor :is_virtual_package
-
def initialize(new_resource, run_context)
super
- @is_virtual_package = {}
end
def load_current_resource
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
- check_all_packages_state(@new_resource.package_name)
- @current_resource
+ @current_resource = Chef::Resource::AptPackage.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
+ current_resource.version(get_current_versions)
+ current_resource
end
def define_resource_requirements
super
requirements.assert(:all_actions) do |a|
- a.assertion { !@new_resource.source }
- a.failure_message(Chef::Exceptions::Package, 'apt package provider cannot handle source attribute. Use dpkg provider instead')
+ a.assertion { !new_resource.source }
+ a.failure_message(Chef::Exceptions::Package, "apt package provider cannot handle source attribute. Use dpkg provider instead")
end
end
- def default_release_options
- # Use apt::Default-Release option only if provider supports it
- "-o APT::Default-Release=#{@new_resource.default_release}" if @new_resource.respond_to?(:default_release) && @new_resource.default_release
+ def package_data
+ @package_data ||= Hash.new do |hash, key|
+ hash[key] = package_data_for(key)
+ end
end
- def check_package_state(pkg)
- is_virtual_package = false
- installed = false
- installed_version = nil
- candidate_version = nil
-
- shell_out_with_timeout!("apt-cache#{expand_options(default_release_options)} policy #{pkg}").stdout.each_line do |line|
- case line
- when /^\s{2}Installed: (.+)$/
- installed_version = $1
- if installed_version == '(none)'
- Chef::Log.debug("#{@new_resource} current version is nil")
- installed_version = nil
- else
- Chef::Log.debug("#{@new_resource} current version is #{installed_version}")
- installed = true
- end
- when /^\s{2}Candidate: (.+)$/
- candidate_version = $1
- if candidate_version == '(none)'
- # This may not be an appropriate assumption, but it shouldn't break anything that already worked -- btm
- is_virtual_package = true
- showpkg = shell_out_with_timeout!("apt-cache showpkg #{pkg}").stdout
- providers = Hash.new
- showpkg.rpartition(/Reverse Provides: ?#{$/}/)[2].each_line do |line|
- provider, version = line.split
- providers[provider] = version
- end
- # Check if the package providing this virtual package is installed
- num_providers = providers.length
- raise Chef::Exceptions::Package, "#{@new_resource.package_name} has no candidate in the apt-cache" if num_providers == 0
- # apt will only install a virtual package if there is a single providing package
- raise Chef::Exceptions::Package, "#{@new_resource.package_name} is a virtual package provided by #{num_providers} packages, you must explicitly select one to install" if num_providers > 1
- # Check if the package providing this virtual package is installed
- Chef::Log.info("#{@new_resource} is a virtual package, actually acting on package[#{providers.keys.first}]")
- ret = check_package_state(providers.keys.first)
- installed = ret[:installed]
- installed_version = ret[:installed_version]
- else
- Chef::Log.debug("#{@new_resource} candidate version is #{$1}")
- end
- end
+ def get_current_versions
+ package_name_array.map do |package_name|
+ package_data[package_name][:current_version]
end
-
- return {
- installed_version: installed_version,
- installed: installed,
- candidate_version: candidate_version,
- is_virtual_package: is_virtual_package,
- }
end
- def check_all_packages_state(package)
- installed_version = {}
- candidate_version = {}
- installed = {}
-
- [package].flatten.each do |pkg|
- ret = check_package_state(pkg)
- is_virtual_package[pkg] = ret[:is_virtual_package]
- installed[pkg] = ret[:installed]
- installed_version[pkg] = ret[:installed_version]
- candidate_version[pkg] = ret[:candidate_version]
+ def get_candidate_versions
+ package_name_array.map do |package_name|
+ package_data[package_name][:candidate_version]
end
+ end
+
+ def candidate_version
+ @candidate_version ||= get_candidate_versions
+ end
- if package.is_a?(Array)
- @candidate_version = []
- final_installed_version = []
- [package].flatten.each do |pkg|
- @candidate_version << candidate_version[pkg]
- final_installed_version << installed_version[pkg]
+ def package_locked(name, version)
+ islocked = false
+ locked = shell_out_compact_timeout!("apt-mark", "showhold")
+ locked.stdout.each_line do |line|
+ line_package = line.strip
+ if line_package == name
+ islocked = true
end
- @current_resource.version(final_installed_version)
- else
- @candidate_version = candidate_version[package]
- @current_resource.version(installed_version[package])
end
+ islocked
end
def install_package(name, version)
- name_array = [ name ].flatten
- version_array = [ version ].flatten
- package_name = name_array.zip(version_array).map do |n, v|
- is_virtual_package[n] ? n : "#{n}=#{v}"
- end.join(' ')
- run_noninteractive("apt-get -q -y#{expand_options(default_release_options)}#{expand_options(@new_resource.options)} install #{package_name}")
+ package_name = name.zip(version).map do |n, v|
+ package_data[n][:virtual] ? n : "#{n}=#{v}"
+ end
+ run_noninteractive("apt-get", "-q", "-y", default_release_options, options, "install", package_name)
end
def upgrade_package(name, version)
@@ -150,24 +94,35 @@ class Chef
end
def remove_package(name, version)
- package_name = [ name ].flatten.join(' ')
- run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} remove #{package_name}")
+ package_name = name.map do |n|
+ package_data[n][:virtual] ? resolve_virtual_package_name(n) : n
+ end
+ run_noninteractive("apt-get", "-q", "-y", options, "remove", package_name)
end
def purge_package(name, version)
- package_name = [ name ].flatten.join(' ')
- run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} purge #{package_name}")
+ package_name = name.map do |n|
+ package_data[n][:virtual] ? resolve_virtual_package_name(n) : n
+ end
+ run_noninteractive("apt-get", "-q", "-y", options, "purge", package_name)
end
def preseed_package(preseed_file)
- Chef::Log.info("#{@new_resource} pre-seeding package installation instructions")
- run_noninteractive("debconf-set-selections #{preseed_file}")
+ Chef::Log.info("#{new_resource} pre-seeding package installation instructions")
+ run_noninteractive("debconf-set-selections", preseed_file)
end
def reconfig_package(name, version)
- package_name = [ name ].flatten.join(' ')
- Chef::Log.info("#{@new_resource} reconfiguring")
- run_noninteractive("dpkg-reconfigure #{package_name}")
+ Chef::Log.info("#{new_resource} reconfiguring")
+ run_noninteractive("dpkg-reconfigure", name)
+ end
+
+ def lock_package(name, version)
+ run_noninteractive("apt-mark", options, "hold", name)
+ end
+
+ def unlock_package(name, version)
+ run_noninteractive("apt-mark", options, "unhold", name)
end
private
@@ -175,8 +130,69 @@ class Chef
# Runs command via shell_out with magic environment to disable
# interactive prompts. Command is run with default localization rather
# than forcing locale to "C", so command output may not be stable.
- def run_noninteractive(command)
- shell_out_with_timeout!(command, :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil })
+ def run_noninteractive(*args)
+ shell_out_compact_timeout!(*args, env: { "DEBIAN_FRONTEND" => "noninteractive" })
+ end
+
+ def default_release_options
+ # Use apt::Default-Release option only if provider supports it
+ if new_resource.respond_to?(:default_release) && new_resource.default_release
+ [ "-o", "APT::Default-Release=#{new_resource.default_release}" ]
+ end
+ end
+
+ def resolve_package_versions(pkg)
+ current_version = nil
+ candidate_version = nil
+ run_noninteractive("apt-cache", default_release_options, "policy", pkg).stdout.each_line do |line|
+ case line
+ when /^\s{2}Installed: (.+)$/
+ current_version = ( $1 != "(none)" ) ? $1 : nil
+ Chef::Log.debug("#{new_resource} installed version for #{pkg} is #{$1}")
+ when /^\s{2}Candidate: (.+)$/
+ candidate_version = ( $1 != "(none)" ) ? $1 : nil
+ Chef::Log.debug("#{new_resource} candidate version for #{pkg} is #{$1}")
+ end
+ end
+ [ current_version, candidate_version ]
+ end
+
+ def resolve_virtual_package_name(pkg)
+ showpkg = run_noninteractive("apt-cache", "showpkg", pkg).stdout
+ partitions = showpkg.rpartition(/Reverse Provides: ?#{$/}/)
+ return nil if partitions[0] == "" && partitions[1] == "" # not found in output
+ set = partitions[2].lines.each_with_object(Set.new) do |line, acc|
+ # there may be multiple reverse provides for a single package
+ acc.add(line.split[0])
+ end
+ if set.size > 1
+ raise Chef::Exceptions::Package, "#{new_resource.package_name} is a virtual package provided by multiple packages, you must explicitly select one"
+ end
+ set.to_a.first
+ end
+
+ def package_data_for(pkg)
+ virtual = false
+ current_version = nil
+ candidate_version = nil
+
+ current_version, candidate_version = resolve_package_versions(pkg)
+
+ if candidate_version.nil?
+ newpkg = resolve_virtual_package_name(pkg)
+
+ if newpkg
+ virtual = true
+ Chef::Log.info("#{new_resource} is a virtual package, actually acting on package[#{newpkg}]")
+ current_version, candidate_version = resolve_package_versions(newpkg)
+ end
+ end
+
+ {
+ current_version: current_version,
+ candidate_version: candidate_version,
+ virtual: virtual,
+ }
end
end
diff --git a/lib/chef/provider/package/cab.rb b/lib/chef/provider/package/cab.rb
new file mode 100644
index 0000000000..d6e989eb72
--- /dev/null
+++ b/lib/chef/provider/package/cab.rb
@@ -0,0 +1,179 @@
+#
+# Author:: Vasundhara Jagdale (<vasundhara.jagdale@msystechnologies.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/provider/package"
+require "chef/resource/cab_package"
+require "chef/mixin/shell_out"
+require "chef/mixin/uris"
+require "chef/mixin/checksum"
+
+class Chef
+ class Provider
+ class Package
+ class Cab < Chef::Provider::Package
+ use_inline_resources
+ include Chef::Mixin::ShellOut
+ include Chef::Mixin::Uris
+ include Chef::Mixin::Checksum
+
+ provides :cab_package, os: "windows"
+
+ def load_current_resource
+ @current_resource = Chef::Resource::CabPackage.new(new_resource.name)
+ current_resource.source(cab_file_source)
+ new_resource.version(package_version)
+ current_resource.version(installed_version)
+ current_resource
+ end
+
+ def cab_file_source
+ @cab_file_source ||= uri_scheme?(new_resource.source) ? download_source_file : new_resource.source
+ end
+
+ def download_source_file
+ source_resource.run_action(:create)
+ Chef::Log.debug("#{new_resource} fetched source file to #{source_resource.path}")
+ source_resource.path
+ end
+
+ def source_resource
+ @source_resource ||= declare_resource(:remote_file, new_resource.name) do
+ path default_download_cache_path
+ source new_resource.source
+ backup false
+ end
+ end
+
+ def default_download_cache_path
+ uri = ::URI.parse(new_resource.source)
+ filename = ::File.basename(::URI.unescape(uri.path))
+ file_cache_dir = Chef::FileCache.create_cache_path("package/")
+ Chef::Util::PathHelper.cleanpath("#{file_cache_dir}/#{filename}")
+ end
+
+ def install_package(name, version)
+ dism_command("/Add-Package /PackagePath:\"#{cab_file_source}\"")
+ end
+
+ def remove_package(name, version)
+ dism_command("/Remove-Package /PackagePath:\"#{cab_file_source}\"")
+ end
+
+ def dism_command(command)
+ shellout = Mixlib::ShellOut.new("dism.exe /Online /English #{command} /NoRestart", timeout: new_resource.timeout)
+ with_os_architecture(nil) do
+ shellout.run_command
+ end
+ end
+
+ def installed_version
+ stdout = dism_command("/Get-PackageInfo /PackagePath:\"#{cab_file_source}\"").stdout
+ package_info = parse_dism_get_package_info(stdout)
+ # e.g. Package_for_KB2975719~31bf3856ad364e35~amd64~~6.3.1.8
+ package = split_package_identity(package_info["package_information"]["package_identity"])
+ # Search for just the package name to catch a different version being installed
+ Chef::Log.debug("#{new_resource} searching for installed package #{package['name']}")
+ found_packages = installed_packages.select { |p| p["package_identity"] =~ /^#{package['name']}~/ }
+ if found_packages.empty?
+ nil
+ elsif found_packages.length == 1
+ stdout = dism_command("/Get-PackageInfo /PackageName:\"#{found_packages.first['package_identity']}\"").stdout
+ find_version(stdout)
+ else
+ # Presuming this won't happen, otherwise we need to handle it
+ raise Chef::Exceptions::Package, "Found multiple packages installed matching name #{package['name']}, found: #{found_packages.length} matches"
+ end
+ end
+
+ def package_version
+ Chef::Log.debug("#{new_resource} getting product version for package at #{cab_file_source}")
+ stdout = dism_command("/Get-PackageInfo /PackagePath:\"#{cab_file_source}\"").stdout
+ find_version(stdout)
+ end
+
+ def find_version(stdout)
+ package_info = parse_dism_get_package_info(stdout)
+ package = split_package_identity(package_info["package_information"]["package_identity"])
+ package["version"]
+ end
+
+ # returns a hash of package state information given the output of dism /get-packages
+ # expected keys: package_identity
+ def parse_dism_get_packages(text)
+ packages = []
+ text.each_line do |line|
+ key, value = line.split(":") if line.start_with?("Package Identity")
+ next if key.nil? || value.nil?
+ package = {}
+ package[key.downcase.strip.tr(" ", "_")] = value.strip.chomp
+ packages << package
+ end
+ packages
+ end
+
+ # returns a hash of package information given the output of dism /get-packageinfo
+ def parse_dism_get_package_info(text)
+ package_data = {}
+ errors = []
+ in_section = false
+ section_headers = [ "Package information", "Custom Properties", "Features" ]
+ text.each_line do |line|
+ if line =~ /Error: (.*)/
+ errors << $1.strip
+ elsif section_headers.any? { |header| line =~ /^(#{header})/ }
+ in_section = $1.downcase.tr(" ", "_")
+ elsif line =~ /(.*) ?: (.*)/
+ v = $2 # has to be first or the gsub below replaces this variable
+ k = $1.downcase.strip.tr(" ", "_")
+ if in_section
+ package_data[in_section] = {} unless package_data[in_section]
+ package_data[in_section][k] = v
+ else
+ package_data[k] = v
+ end
+ end
+ end
+ unless errors.empty?
+ if errors.include?("0x80070003") || errors.include?("0x80070002")
+ raise Chef::Exceptions::Package, "DISM: The system cannot find the path or file specified."
+ elsif errors.include?("740")
+ raise Chef::Exceptions::Package, "DISM: Error 740: Elevated permissions are required to run DISM."
+ else
+ raise Chef::Exceptions::Package, "Unknown errors encountered parsing DISM output: #{errors}"
+ end
+ end
+ package_data
+ end
+
+ def split_package_identity(identity)
+ data = {}
+ data["name"], data["publisher"], data["arch"], data["resource_id"], data["version"] = identity.split("~")
+ data
+ end
+
+ def installed_packages
+ @packages ||= begin
+ output = dism_command("/Get-Packages").stdout
+ packages = parse_dism_get_packages(output)
+ packages
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/chocolatey.rb b/lib/chef/provider/package/chocolatey.rb
new file mode 100644
index 0000000000..29b9f0d322
--- /dev/null
+++ b/lib/chef/provider/package/chocolatey.rb
@@ -0,0 +1,275 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/provider/package"
+require "chef/resource/chocolatey_package"
+require "chef/mixin/powershell_out"
+
+class Chef
+ class Provider
+ class Package
+ class Chocolatey < Chef::Provider::Package
+ include Chef::Mixin::PowershellOut
+
+ provides :chocolatey_package, os: "windows"
+
+ # Declare that our arguments should be arrays
+ use_multipackage_api
+
+ PATHFINDING_POWERSHELL_COMMAND = "[System.Environment]::GetEnvironmentVariable('ChocolateyInstall', 'MACHINE')".freeze
+ CHOCO_MISSING_MSG = <<-EOS.freeze
+Could not locate your Chocolatey install. To install chocolatey, we recommend
+the 'chocolatey' cookbook (https://github.com/chocolatey/chocolatey-cookbook).
+If Chocolatey is installed, ensure that the 'ChocolateyInstall' environment
+variable is correctly set. You can verify this with the PowerShell command
+'#{PATHFINDING_POWERSHELL_COMMAND}'.
+EOS
+
+ # Responsible for building the current_resource.
+ #
+ # @return [Chef::Resource::ChocolateyPackage] the current_resource
+ def load_current_resource
+ @current_resource = Chef::Resource::ChocolateyPackage.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
+ current_resource.version(build_current_versions)
+ current_resource
+ end
+
+ def define_resource_requirements
+ super
+
+ # The check that Chocolatey is installed is in #choco_exe.
+
+ # Chocolatey source attribute points to an alternate feed
+ # and not a package specific alternate source like other providers
+ # so we want to assert candidates exist for the alternate source
+ requirements.assert(:upgrade, :install) do |a|
+ a.assertion { candidates_exist_for_all_uninstalled? }
+ a.failure_message(Chef::Exceptions::Package, "No candidate version available for #{packages_missing_candidates.join(', ')}")
+ a.whyrun("Assuming a repository that offers #{packages_missing_candidates.join(', ')} would have been configured")
+ end
+ end
+
+ # Lazy initializer for candidate_version. A nil value means that there is no candidate
+ # version and the package is not installable (generally an error).
+ #
+ # @return [Array] list of candidate_versions indexed same as new_resource.package_name/version
+ def candidate_version
+ @candidate_version ||= build_candidate_versions
+ end
+
+ # Install multiple packages via choco.exe
+ #
+ # @param names [Array<String>] array of package names to install
+ # @param versions [Array<String>] array of versions to install
+ def install_package(names, versions)
+ name_versions_to_install = desired_name_versions.select { |n, v| lowercase_names(names).include?(n) }
+
+ name_nil_versions = name_versions_to_install.select { |n, v| v.nil? }
+ name_has_versions = name_versions_to_install.reject { |n, v| v.nil? }
+
+ # choco does not support installing multiple packages with version pins
+ name_has_versions.each do |name, version|
+ choco_command("install -y --version", version, cmd_args, name)
+ end
+
+ # but we can do all the ones without version pins at once
+ unless name_nil_versions.empty?
+ cmd_names = name_nil_versions.keys
+ choco_command("install -y", cmd_args, *cmd_names)
+ end
+ end
+
+ # Upgrade multiple packages via choco.exe
+ #
+ # @param names [Array<String>] array of package names to install
+ # @param versions [Array<String>] array of versions to install
+ def upgrade_package(names, versions)
+ name_versions_to_install = desired_name_versions.select { |n, v| lowercase_names(names).include?(n) }
+
+ name_nil_versions = name_versions_to_install.select { |n, v| v.nil? }
+ name_has_versions = name_versions_to_install.reject { |n, v| v.nil? }
+
+ # choco does not support installing multiple packages with version pins
+ name_has_versions.each do |name, version|
+ choco_command("upgrade -y --version", version, cmd_args, name)
+ end
+
+ # but we can do all the ones without version pins at once
+ unless name_nil_versions.empty?
+ cmd_names = name_nil_versions.keys
+ choco_command("upgrade -y", cmd_args, *cmd_names)
+ end
+ end
+
+ # Remove multiple packages via choco.exe
+ #
+ # @param names [Array<String>] array of package names to install
+ # @param versions [Array<String>] array of versions to install
+ def remove_package(names, versions)
+ choco_command("uninstall -y", cmd_args(include_source: false), *names)
+ end
+
+ # Support :uninstall as an action in order for users to easily convert
+ # from the `chocolatey` provider in the cookbook. It is, however,
+ # already deprecated.
+ def action_uninstall
+ Chef::Log.deprecation "The use of action :uninstall on the chocolatey_package provider is deprecated, please use :remove"
+ action_remove
+ end
+
+ # Choco does not have dpkg's distinction between purge and remove
+ alias purge_package remove_package
+
+ # Override the superclass check. The semantics for our new_resource.source is not files to
+ # install from, but like the rubygem provider's sources which are more like repos.
+ def check_resource_semantics!; end
+
+ private
+
+ # Magic to find where chocolatey is installed in the system, and to
+ # return the full path of choco.exe
+ #
+ # @return [String] full path of choco.exe
+ def choco_exe
+ @choco_exe ||= begin
+ # if this check is in #define_resource_requirements, it won't get
+ # run before choco.exe gets called from #load_current_resource.
+ exe_path = ::File.join(choco_install_path.to_s, "bin", "choco.exe")
+ raise Chef::Exceptions::MissingLibrary, CHOCO_MISSING_MSG unless ::File.exist?(exe_path)
+ exe_path
+ end
+ end
+
+ # lets us mock out an incorrect value for testing.
+ def choco_install_path
+ @choco_install_path ||= powershell_out!(
+ PATHFINDING_POWERSHELL_COMMAND
+ ).stdout.chomp
+ end
+
+ # Helper to dispatch a choco command through shell_out using the timeout
+ # set on the new resource, with nice command formatting.
+ #
+ # @param args [String] variable number of string arguments
+ # @return [Mixlib::ShellOut] object returned from shell_out!
+ def choco_command(*args)
+ shell_out_with_timeout!(args_to_string(choco_exe, *args), returns: new_resource.returns)
+ end
+
+ # Use the available_packages Hash helper to create an array suitable for
+ # using in candidate_version
+ #
+ # @return [Array] list of candidate_version, same index as new_resource.package_name/version
+ def build_candidate_versions
+ new_resource.package_name.map do |package_name|
+ available_packages[package_name.downcase]
+ end
+ end
+
+ # Use the installed_packages Hash helper to create an array suitable for
+ # using in current_resource.version
+ #
+ # @return [Array] list of candidate_version, same index as new_resource.package_name/version
+ def build_current_versions
+ new_resource.package_name.map do |package_name|
+ installed_packages[package_name.downcase]
+ end
+ end
+
+ # Helper to construct Hash of names-to-versions, requested on the new_resource.
+ # If new_resource.version is nil, then all values will be nil.
+ #
+ # @return [Hash] Mapping of requested names to versions
+ def desired_name_versions
+ desired_versions = new_resource.version || new_resource.package_name.map { nil }
+ Hash[*lowercase_names(new_resource.package_name).zip(desired_versions).flatten]
+ end
+
+ # Helper to construct optional args out of new_resource
+ #
+ # @param include_source [Boolean] should the source parameter be added
+ # @return [String] options from new_resource or empty string
+ def cmd_args(include_source: true)
+ cmd_args = [ new_resource.options ]
+ cmd_args.push( "-source #{new_resource.source}" ) if new_resource.source && include_source
+ args_to_string(*cmd_args)
+ end
+
+ # Helper to nicely convert variable string args into a single command line. It
+ # will compact nulls or empty strings and join arguments with single spaces, without
+ # introducing any double-spaces for missing args.
+ #
+ # @param args [String] variable number of string arguments
+ # @return [String] nicely concatenated string or empty string
+ def args_to_string(*args)
+ args.reject { |i| i.nil? || i == "" }.join(" ")
+ end
+
+ # Available packages in chocolatey as a Hash of names mapped to versions
+ # If pinning a package to a specific version, filter out all non matching versions
+ # (names are downcased for case-insensitive matching)
+ #
+ # @return [Hash] name-to-version mapping of available packages
+ def available_packages
+ @available_packages ||=
+ begin
+ cmd = [ "list -r #{package_name_array.join ' '}" ]
+ cmd.push( "-source #{new_resource.source}" ) if new_resource.source
+ raw = parse_list_output(*cmd)
+ raw.keys.each_with_object({}) do |name, available|
+ available[name] = desired_name_versions[name] || raw[name]
+ end
+ end
+ @available_packages
+ end
+
+ # Installed packages in chocolatey as a Hash of names mapped to versions
+ # (names are downcased for case-insensitive matching)
+ #
+ # @return [Hash] name-to-version mapping of installed packages
+ def installed_packages
+ @installed_packages ||= Hash[*parse_list_output("list -l -r").flatten]
+ @installed_packages
+ end
+
+ # Helper to convert choco.exe list output to a Hash
+ # (names are downcased for case-insenstive matching)
+ #
+ # @param cmd [String] command to run
+ # @return [Hash] list output converted to ruby Hash
+ def parse_list_output(*args)
+ hash = {}
+ choco_command(*args).stdout.each_line do |line|
+ next if line.start_with?("Chocolatey v")
+ name, version = line.split("|")
+ hash[name.downcase] = version.chomp
+ end
+ hash
+ end
+
+ # Helper to downcase all names in an array
+ #
+ # @param names [Array] original mixed case names
+ # @return [Array] same names in lower case
+ def lowercase_names(names)
+ names.map(&:downcase)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/dnf.rb b/lib/chef/provider/package/dnf.rb
new file mode 100644
index 0000000000..c551ae7cb0
--- /dev/null
+++ b/lib/chef/provider/package/dnf.rb
@@ -0,0 +1,185 @@
+#
+# Copyright:: Copyright 2016-2017, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/provider/package"
+require "chef/resource/dnf_package"
+require "chef/mixin/which"
+require "chef/mixin/shell_out"
+require "chef/mixin/get_source_from_package"
+require "chef/provider/package/dnf/python_helper"
+require "chef/provider/package/dnf/version"
+
+class Chef
+ class Provider
+ class Package
+ class Dnf < Chef::Provider::Package
+ extend Chef::Mixin::Which
+ extend Chef::Mixin::ShellOut
+ include Chef::Mixin::GetSourceFromPackage
+
+ allow_nils
+ use_multipackage_api
+ use_package_name_for_source
+
+ provides :package, platform_family: %w{rhel fedora} do
+ which("dnf") && shell_out("rpm -q dnf").stdout =~ /^dnf-[1-9]/
+ end
+
+ provides :dnf_package, os: "linux"
+
+ #
+ # Most of the magic in this class happens in the python helper script. The ruby side of this
+ # provider knows only enough to translate Chef-style new_resource name+package+version into
+ # a request to the python side. The python side is then responsible for knowing everything
+ # about RPMs and what is installed and what is available. The ruby side of this class should
+ # remain a lightweight translation layer to translate Chef requests into RPC requests to
+ # python. This class knows nothing about how to compare RPM versions, and does not maintain
+ # any cached state of installed/available versions and should be kept that way.
+ #
+ def python_helper
+ @python_helper ||= PythonHelper.instance
+ end
+
+ def load_current_resource
+ flushcache if new_resource.flush_cache[:before]
+
+ @current_resource = Chef::Resource::DnfPackage.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
+ current_resource.version(get_current_versions)
+
+ current_resource
+ end
+
+ def define_resource_requirements
+ requirements.assert(:install, :upgrade, :remove, :purge) do |a|
+ a.assertion { !new_resource.source || ::File.exist?(new_resource.source) }
+ a.failure_message Chef::Exceptions::Package, "Package #{new_resource.package_name} not found: #{new_resource.source}"
+ a.whyrun "assuming #{new_resource.source} would have previously been created"
+ end
+
+ super
+ end
+
+ def candidate_version
+ package_name_array.each_with_index.map do |pkg, i|
+ available_version(i).version_with_arch
+ end
+ end
+
+ def get_current_versions
+ package_name_array.each_with_index.map do |pkg, i|
+ installed_version(i).version_with_arch
+ end
+ end
+
+ def install_package(names, versions)
+ if new_resource.source
+ dnf(options, "-y install", new_resource.source)
+ else
+ resolved_names = names.each_with_index.map { |name, i| available_version(i).to_s unless name.nil? }
+ dnf(options, "-y install", resolved_names)
+ end
+ flushcache
+ end
+
+ # dnf upgrade does not work on uninstalled packaged, while install will upgrade
+ alias upgrade_package install_package
+
+ def remove_package(names, versions)
+ resolved_names = names.each_with_index.map { |name, i| installed_version(i).to_s unless name.nil? }
+ dnf(options, "-y remove", resolved_names)
+ flushcache
+ end
+
+ alias purge_package remove_package
+
+ action :flush_cache do
+ flushcache
+ end
+
+ private
+
+ def resolve_source_to_version_obj
+ shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH}\n' #{new_resource.source}").stdout.each_line do |line|
+ # this is another case of committing the sin of doing some lightweight mangling of RPM versions in ruby -- but the output of the rpm command
+ # does not match what the dnf library accepts.
+ case line
+ when /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)$/
+ return Version.new($1, "#{$2 == '(none)' ? '0' : $2}:#{$3}-#{$4}", $5)
+ end
+ end
+ end
+
+ # @returns Array<Version>
+ def available_version(index)
+ @available_version ||= []
+
+ @available_version[index] ||= if new_resource.source
+ resolve_source_to_version_obj
+ else
+ python_helper.query(:whatavailable, package_name_array[index], safe_version_array[index], safe_arch_array[index])
+ end
+
+ @available_version[index]
+ end
+
+ # @returns Array<Version>
+ def installed_version(index)
+ @installed_version ||= []
+ @installed_version[index] ||= if new_resource.source
+ python_helper.query(:whatinstalled, available_version(index).name, safe_version_array[index], safe_arch_array[index])
+ else
+ python_helper.query(:whatinstalled, package_name_array[index], safe_version_array[index], safe_arch_array[index])
+ end
+ @installed_version[index]
+ end
+
+ # cache flushing is accomplished by simply restarting the python helper. this produces a roughly
+ # 15% hit to the runtime of installing/removing/upgrading packages. correctly using multipackage
+ # array installs (and the multipackage cookbook) can produce 600% improvements in runtime.
+ def flushcache
+ python_helper.restart
+ end
+
+ def dnf(*args)
+ shell_out_with_timeout!(a_to_s("dnf", *args))
+ end
+
+ def safe_version_array
+ if new_resource.version.is_a?(Array)
+ new_resource.version
+ elsif new_resource.version.nil?
+ package_name_array.map { nil }
+ else
+ [ new_resource.version ]
+ end
+ end
+
+ def safe_arch_array
+ if new_resource.arch.is_a?(Array)
+ new_resource.arch
+ elsif new_resource.arch.nil?
+ package_name_array.map { nil }
+ else
+ [ new_resource.arch ]
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/dnf/dnf_helper.py b/lib/chef/provider/package/dnf/dnf_helper.py
new file mode 100644
index 0000000000..ef08bb54c2
--- /dev/null
+++ b/lib/chef/provider/package/dnf/dnf_helper.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
+
+import sys
+import dnf
+import hawkey
+import signal
+import os
+import json
+
+base = None
+
+def get_sack():
+ global base
+ if base is None:
+ base = dnf.Base()
+ base.read_all_repos()
+ base.fill_sack()
+ return base.sack
+
+# FIXME: leaks memory and does not work
+def flushcache():
+ try:
+ os.remove('/var/cache/dnf/@System.solv')
+ except OSError:
+ pass
+ get_sack().load_system_repo(build_cache=True)
+
+def query(command):
+ sack = get_sack()
+
+ subj = dnf.subject.Subject(command['provides'])
+ q = subj.get_best_query(sack, with_provides=True)
+
+ if command['action'] == "whatinstalled":
+ q = q.installed()
+
+ if command['action'] == "whatavailable":
+ q = q.available()
+
+ if 'epoch' in command:
+ q = q.filterm(epoch=int(command['epoch']))
+ if 'version' in command:
+ q = q.filterm(version__glob=command['version'])
+ if 'release' in command:
+ q = q.filterm(release__glob=command['release'])
+
+ if 'arch' in command:
+ q = q.filterm(arch__glob=command['arch'])
+
+ # only apply the default arch query filter if it returns something
+ archq = q.filter(arch=[ 'noarch', hawkey.detect_arch() ])
+ if len(archq.run()) > 0:
+ q = archq
+
+ pkgs = q.latest(1).run()
+
+ if not pkgs:
+ sys.stdout.write('{} nil nil\n'.format(command['provides'].split().pop(0)))
+ else:
+ # make sure we picked the package with the highest version
+ pkgs.sort
+ pkg = pkgs.pop()
+ sys.stdout.write('{} {}:{}-{} {}\n'.format(pkg.name, pkg.epoch, pkg.version, pkg.release, pkg.arch))
+
+# the design of this helper is that it should try to be 'brittle' and fail hard and exit in order
+# to keep process tables clean. additional error handling should probably be added to the retry loop
+# on the ruby side.
+def exit_handler(signal, frame):
+ sys.exit(0)
+
+signal.signal(signal.SIGINT, exit_handler)
+signal.signal(signal.SIGHUP, exit_handler)
+signal.signal(signal.SIGPIPE, exit_handler)
+signal.signal(signal.SIGCHLD, exit_handler)
+
+while 1:
+ # kill self if we get orphaned (tragic)
+ ppid = os.getppid()
+ if ppid == 1:
+ sys.exit(0)
+ line = sys.stdin.readline()
+ command = json.loads(line)
+ if command['action'] == "whatinstalled":
+ query(command)
+ elif command['action'] == "whatavailable":
+ query(command)
+ elif command['action'] == "flushcache":
+ flushcache()
+ else:
+ raise RuntimeError("bad command")
diff --git a/lib/chef/provider/package/dnf/python_helper.rb b/lib/chef/provider/package/dnf/python_helper.rb
new file mode 100644
index 0000000000..04f0298861
--- /dev/null
+++ b/lib/chef/provider/package/dnf/python_helper.rb
@@ -0,0 +1,157 @@
+#
+# Copyright:: Copyright 2016-2017, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/mixin/which"
+require "chef/mixin/shell_out"
+require "chef/provider/package/dnf/version"
+require "timeout"
+
+class Chef
+ class Provider
+ class Package
+ class Dnf < Chef::Provider::Package
+ class PythonHelper
+ include Singleton
+ include Chef::Mixin::Which
+ include Chef::Mixin::ShellOut
+
+ attr_accessor :stdin
+ attr_accessor :stdout
+ attr_accessor :stderr
+ attr_accessor :wait_thr
+
+ DNF_HELPER = ::File.expand_path(::File.join(::File.dirname(__FILE__), "dnf_helper.py")).freeze
+
+ def dnf_command
+ @dnf_command ||= which("python", "python3", "python2", "python2.7") do |f|
+ shell_out("#{f} -c 'import dnf'").exitstatus == 0
+ end + " #{DNF_HELPER}"
+ end
+
+ def start
+ ENV["PYTHONUNBUFFERED"] = "1"
+ @stdin, @stdout, @stderr, @wait_thr = Open3.popen3(dnf_command)
+ end
+
+ def reap
+ unless wait_thr.nil?
+ Process.kill("KILL", wait_thr.pid) rescue nil
+ stdin.close unless stdin.nil?
+ stdout.close unless stdout.nil?
+ stderr.close unless stderr.nil?
+ wait_thr.value # this calls waitpit()
+ end
+ end
+
+ def check
+ start if stdin.nil?
+ end
+
+ # @returns Array<Version>
+ def query(action, provides, version = nil, arch = nil)
+ with_helper do
+ json = build_query(action, provides, version, arch)
+ Chef::Log.debug "sending '#{json}' to python helper"
+ stdin.syswrite json + "\n"
+ output = stdout.sysread(4096).chomp
+ Chef::Log.debug "got '#{output}' from python helper"
+ version = parse_response(output)
+ Chef::Log.debug "parsed #{version} from python helper"
+ version
+ end
+ end
+
+ def restart
+ reap
+ start
+ end
+
+ private
+
+ # i couldn't figure out how to decompose an evr on the python side, it seems reasonably
+ # painless to do it in ruby (generally massaging nevras in the ruby side is HIGHLY
+ # discouraged -- this is an "every rule has an exception" exception -- any additional
+ # functionality should probably trigger moving this regexp logic into python)
+ def add_version(hash, version)
+ epoch = nil
+ if version =~ /(\S+):(\S+)/
+ epoch = $1
+ version = $2
+ end
+ if version =~ /(\S+)-(\S+)/
+ version = $1
+ release = $2
+ end
+ hash["epoch"] = epoch unless epoch.nil?
+ hash["release"] = release unless release.nil?
+ hash["version"] = version
+ end
+
+ def build_query(action, provides, version, arch)
+ hash = { "action" => action }
+ hash["provides"] = provides
+ add_version(hash, version) unless version.nil?
+ hash["arch" ] = arch unless arch.nil?
+ FFI_Yajl::Encoder.encode(hash)
+ end
+
+ def parse_response(output)
+ array = output.split.map { |x| x == "nil" ? nil : x }
+ array.each_slice(3).map { |x| Version.new(*x) }.first
+ end
+
+ def drain_stderr
+ output = ""
+ until IO.select([stderr], nil, nil, 0).nil?
+ output += stderr.sysread(4096).chomp
+ end
+ output
+ rescue
+ # we must rescue EOFError, and we don't much care about errors on stderr anyway
+ output
+ end
+
+ def with_helper
+ max_retries ||= 5
+ ret = nil
+ Timeout.timeout(600) do
+ check
+ ret = yield
+ end
+ output = drain_stderr
+ unless output.empty?
+ Chef::Log.debug "discarding output on stderr from python helper: #{output}"
+ end
+ ret
+ rescue EOFError, Errno::EPIPE, Timeout::Error, Errno::ESRCH => e
+ output = drain_stderr
+ if ( max_retries -= 1 ) > 0
+ unless output.empty?
+ Chef::Log.debug "discarding output on stderr from python helper: #{output}"
+ end
+ restart
+ retry
+ else
+ raise e if output.empty?
+ raise "dnf-helper.py had stderr output:\n\n#{output}"
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/dnf/version.rb b/lib/chef/provider/package/dnf/version.rb
new file mode 100644
index 0000000000..3cff5b0437
--- /dev/null
+++ b/lib/chef/provider/package/dnf/version.rb
@@ -0,0 +1,56 @@
+#
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Provider
+ class Package
+ class Dnf < Chef::Provider::Package
+
+ # helper class to assist in passing around name/version/arch triples
+ class Version
+ attr_accessor :name
+ attr_accessor :version
+ attr_accessor :arch
+
+ def initialize(name, version, arch)
+ @name = name
+ @version = version
+ @arch = arch
+ end
+
+ def to_s
+ "#{name}-#{version}.#{arch}"
+ end
+
+ def version_with_arch
+ "#{version}.#{arch}" unless version.nil?
+ end
+
+ def matches_name_and_arch?(other)
+ other.version == version && other.arch == arch
+ end
+
+ def ==(other)
+ name == other.name && version == other.version && arch == other.arch
+ end
+
+ alias eql? ==
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/dpkg.rb b/lib/chef/provider/package/dpkg.rb
index 67e9b903c6..89a57affac 100644
--- a/lib/chef/provider/package/dpkg.rb
+++ b/lib/chef/provider/package/dpkg.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,125 +16,207 @@
# limitations under the License.
#
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'chef/mixin/get_source_from_package'
+require "chef/provider/package"
+require "chef/resource/package"
class Chef
class Provider
class Package
class Dpkg < Chef::Provider::Package
+ DPKG_REMOVED = /^Status: deinstall ok config-files/
DPKG_INSTALLED = /^Status: install ok installed/
- DPKG_VERSION = /^Version: (.+)$/
+ DPKG_VERSION = /^Version: (.+)$/
provides :dpkg_package, os: "linux"
- include Chef::Mixin::GetSourceFromPackage
+ use_multipackage_api
+ use_package_name_for_source
def define_resource_requirements
super
- requirements.assert(:install) do |a|
- a.assertion{ not @new_resource.source.nil? }
- a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install"
+
+ requirements.assert(:install, :upgrade) do |a|
+ a.assertion { !resolved_source_array.compact.empty? }
+ a.failure_message Chef::Exceptions::Package, "#{new_resource} the source property is required for action :install or :upgrade"
end
- # TODO this was originally written for any action in which .source is provided
- # but would it make more sense to only look at source if the action is :install?
- requirements.assert(:all_actions) do |a|
- a.assertion { @source_exists }
- a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
- a.whyrun "Assuming it would have been previously downloaded."
+ requirements.assert(:install, :upgrade) do |a|
+ a.assertion { source_files_exist? }
+ a.failure_message Chef::Exceptions::Package, "#{new_resource} source file(s) do not exist: #{missing_sources}"
+ a.whyrun "Assuming they would have been previously created."
end
end
def load_current_resource
- @source_exists = true
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
-
- if @new_resource.source
- @source_exists = ::File.exists?(@new_resource.source)
- if @source_exists
- # Get information from the package if supplied
- Chef::Log.debug("#{@new_resource} checking dpkg status")
- status = shell_out_with_timeout("dpkg-deb -W #{@new_resource.source}")
- pkginfo = status.stdout.split("\t")
- unless pkginfo.empty?
- @current_resource.package_name(pkginfo[0])
- @candidate_version = pkginfo[1].strip
- end
- else
- # Source provided but not valid means we can't safely do further processing
- return
- end
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
+
+ if source_files_exist?
+ @candidate_version = get_candidate_version
+ current_resource.package_name(get_package_name)
+ # if the source file exists then our package_name is right
+ current_resource.version(get_current_version_from(current_package_name_array))
+ elsif !installing?
+ # we can't do this if we're installing with no source, because our package_name
+ # is probably not right.
+ #
+ # if we're removing or purging we don't use source, and our package_name must
+ # be right so we can do this.
+ #
+ # we don't error here on the dpkg command since we'll handle the exception or
+ # the why-run message in define_resource_requirements.
+ current_resource.version(get_current_version_from(current_package_name_array))
end
- # Check to see if it is installed
- package_installed = nil
- Chef::Log.debug("#{@new_resource} checking install state")
- status = shell_out_with_timeout("dpkg -s #{@current_resource.package_name}")
+ current_resource
+ end
+
+ def install_package(name, version)
+ sources = name.map { |n| name_sources[n] }
+ Chef::Log.info("#{new_resource} installing package(s): #{name.join(' ')}")
+ run_noninteractive("dpkg", "-i", *options, *sources)
+ end
+
+ def remove_package(name, version)
+ Chef::Log.info("#{new_resource} removing package(s): #{name.join(' ')}")
+ run_noninteractive("dpkg", "-r", *options, *name)
+ end
+
+ def purge_package(name, version)
+ Chef::Log.info("#{new_resource} purging packages(s): #{name.join(' ')}")
+ run_noninteractive("dpkg", "-P", *options, *name)
+ end
+
+ def upgrade_package(name, version)
+ install_package(name, version)
+ end
+
+ def preseed_package(preseed_file)
+ Chef::Log.info("#{new_resource} pre-seeding package installation instructions")
+ run_noninteractive("debconf-set-selections", *preseed_file)
+ end
+
+ def reconfig_package(name, version)
+ Chef::Log.info("#{new_resource} reconfiguring")
+ run_noninteractive("dpkg-reconfigure", *name)
+ end
+
+ # Override the superclass check. Multiple sources are required here.
+ def check_resource_semantics!; end
+
+ private
+
+ def read_current_version_of_package(package_name)
+ Chef::Log.debug("#{new_resource} checking install state of #{package_name}")
+ status = shell_out_compact_timeout!("dpkg", "-s", package_name, returns: [0, 1])
+ package_installed = false
status.stdout.each_line do |line|
case line
+ when DPKG_REMOVED
+ # if we are 'purging' then we consider 'removed' to be 'installed'
+ package_installed = true if action == :purge
when DPKG_INSTALLED
package_installed = true
when DPKG_VERSION
if package_installed
- Chef::Log.debug("#{@new_resource} current version is #{$1}")
- @current_resource.version($1)
+ Chef::Log.debug("#{new_resource} current version is #{$1}")
+ return $1
end
end
end
+ nil
+ end
- unless status.exitstatus == 0 || status.exitstatus == 1
- raise Chef::Exceptions::Package, "dpkg failed - #{status.inspect}!"
+ def get_current_version_from(array)
+ array.map do |name|
+ read_current_version_of_package(name)
end
+ end
- @current_resource
+ # Runs command via shell_out_with_timeout with magic environment to disable
+ # interactive prompts.
+ def run_noninteractive(*command)
+ shell_out_compact_timeout!(*command, env: { "DEBIAN_FRONTEND" => "noninteractive" })
end
- def install_package(name, version)
- Chef::Log.info("#{@new_resource} installing #{@new_resource.source}")
- run_noninteractive(
- "dpkg -i#{expand_options(@new_resource.options)} #{@new_resource.source}"
- )
+ # Returns true if all sources exist. Returns false if any do not, or if no
+ # sources were specified.
+ #
+ # @return [Boolean] True if all sources exist
+ def source_files_exist?
+ resolved_source_array.all? { |s| s && ::File.exist?(s) }
end
- def remove_package(name, version)
- Chef::Log.info("#{@new_resource} removing #{@new_resource.package_name}")
- run_noninteractive(
- "dpkg -r#{expand_options(@new_resource.options)} #{@new_resource.package_name}"
- )
+ # Helper to return all the nanes of the missing sources for error messages.
+ #
+ # @return [Array<String>] Array of missing sources
+ def missing_sources
+ resolved_source_array.select { |s| s.nil? || !::File.exist?(s) }
end
- def purge_package(name, version)
- Chef::Log.info("#{@new_resource} purging #{@new_resource.package_name}")
- run_noninteractive(
- "dpkg -P#{expand_options(@new_resource.options)} #{@new_resource.package_name}"
- )
+ def current_package_name_array
+ [ current_resource.package_name ].flatten
end
- def upgrade_package(name, version)
- install_package(name, version)
+ # Helper to construct Hash of names-to-sources.
+ #
+ # @return [Hash] Mapping of package names to sources
+ def name_sources
+ @name_sources =
+ begin
+ Hash[*package_name_array.zip(resolved_source_array).flatten]
+ end
end
- def preseed_package(preseed_file)
- Chef::Log.info("#{@new_resource} pre-seeding package installation instructions")
- run_noninteractive("debconf-set-selections #{preseed_file}")
+ # Helper to construct Hash of names-to-package-information.
+ #
+ # @return [Hash] Mapping of package names to package information
+ def name_pkginfo
+ @name_pkginfo ||=
+ begin
+ pkginfos = resolved_source_array.map do |src|
+ Chef::Log.debug("#{new_resource} checking #{src} dpkg status")
+ status = shell_out_compact_timeout!("dpkg-deb", "-W", src)
+ status.stdout
+ end
+ Hash[*package_name_array.zip(pkginfos).flatten]
+ end
end
- def reconfig_package(name, version)
- Chef::Log.info("#{@new_resource} reconfiguring")
- run_noninteractive("dpkg-reconfigure #{name}")
+ def name_candidate_version
+ @name_candidate_version ||=
+ begin
+ Hash[name_pkginfo.map { |k, v| [k, v ? v.split("\t")[1].strip : nil] }]
+ end
end
- # Runs command via shell_out_with_timeout with magic environment to disable
- # interactive prompts. Command is run with default localization rather
- # than forcing locale to "C", so command output may not be stable.
+ def name_package_name
+ @name_package_name ||=
+ begin
+ Hash[name_pkginfo.map { |k, v| [k, v ? v.split("\t")[0] : nil] }]
+ end
+ end
+
+ # Return candidate version array from pkg-deb -W against the source file(s).
+ #
+ # @return [Array] Array of candidate versions read from the source files
+ def get_candidate_version
+ package_name_array.map { |name| name_candidate_version[name] }
+ end
+
+ # Return package names from the candidate source file(s).
+ #
+ # @return [Array] Array of actual package names read from the source files
+ def get_package_name
+ package_name_array.map { |name| name_package_name[name] }
+ end
+
+ # Since upgrade just calls install, this is a helper to determine
+ # if our action means that we'll be calling install_package.
#
- # FIXME: This should be "LC_ALL" => "en_US.UTF-8" in order to stabilize the output and get UTF-8
- def run_noninteractive(command)
- shell_out_with_timeout!(command, :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil })
+ # @return [Boolean] true if we're doing :install or :upgrade
+ def installing?
+ [:install, :upgrade].include?(action)
end
end
diff --git a/lib/chef/provider/package/easy_install.rb b/lib/chef/provider/package/easy_install.rb
index 2f7880bf08..cc915e606c 100644
--- a/lib/chef/provider/package/easy_install.rb
+++ b/lib/chef/provider/package/easy_install.rb
@@ -1,6 +1,6 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
class Chef
class Provider
@@ -32,11 +32,11 @@ class Chef
begin
# first check to see if we can import it
- output = shell_out_with_timeout!("#{python_binary_path} -c \"import #{name}\"", :returns=>[0,1]).stderr
+ output = shell_out_compact_timeout!(python_binary_path, "-c", "import #{name}", returns: [0, 1]).stderr
if output.include? "ImportError"
# then check to see if its on the path
- output = shell_out_with_timeout!("#{python_binary_path} -c \"import sys; print sys.path\"", :returns=>[0,1]).stdout
- if output.downcase.include? "#{name.downcase}"
+ output = shell_out_compact_timeout!(python_binary_path, "-c", "import sys; print sys.path", returns: [0, 1]).stdout
+ if output.downcase.include? name.downcase.to_s
check = true
end
else
@@ -50,39 +50,38 @@ class Chef
end
def easy_install_binary_path
- path = @new_resource.easy_install_binary
- path ? path : 'easy_install'
+ path = new_resource.easy_install_binary
+ path ? path : "easy_install"
end
def python_binary_path
- path = @new_resource.python_binary
- path ? path : 'python'
+ path = new_resource.python_binary
+ path ? path : "python"
end
def module_name
- m = @new_resource.module_name
- m ? m : @new_resource.name
+ m = new_resource.module_name
+ m ? m : new_resource.name
end
def load_current_resource
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
- @current_resource.version(nil)
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
# get the currently installed version if installed
package_version = nil
if install_check(module_name)
begin
- output = shell_out_with_timeout!("#{python_binary_path} -c \"import #{module_name}; print #{module_name}.__version__\"").stdout
+ output = shell_out_compact_timeout!("#{python_binary_path} -c \"import #{module_name}; print #{module_name}.__version__\"").stdout
package_version = output.strip
rescue
- output = shell_out_with_timeout!("#{python_binary_path} -c \"import sys; print sys.path\"", :returns=>[0,1]).stdout
+ output = shell_out_compact_timeout!("#{python_binary_path} -c \"import sys; print sys.path\"", returns: [0, 1]).stdout
- output_array = output.gsub(/[\[\]]/,'').split(/\s*,\s*/)
+ output_array = output.gsub(/[\[\]]/, "").split(/\s*,\s*/)
package_path = ""
output_array.each do |entry|
- if entry.downcase.include?(@new_resource.package_name)
+ if entry.downcase.include?(new_resource.package_name)
package_path = entry
end
end
@@ -92,28 +91,29 @@ class Chef
end
end
- if package_version == @new_resource.version
- Chef::Log.debug("#{@new_resource} at version #{@new_resource.version}")
- @current_resource.version(@new_resource.version)
+ if package_version == new_resource.version
+ Chef::Log.debug("#{new_resource} at version #{new_resource.version}")
+ current_resource.version(new_resource.version)
else
- Chef::Log.debug("#{@new_resource} at version #{package_version}")
- @current_resource.version(package_version)
+ Chef::Log.debug("#{new_resource} at version #{package_version}")
+ current_resource.version(package_version)
end
- @current_resource
+ current_resource
end
def candidate_version
- return @candidate_version if @candidate_version
+ return @candidate_version if @candidate_version
- # do a dry run to get the latest version
- result = shell_out_with_timeout!("#{easy_install_binary_path} -n #{@new_resource.package_name}", :returns=>[0,1])
- @candidate_version = result.stdout[/(.*)Best match: (.*) (.*)$/, 3]
- @candidate_version
+ # do a dry run to get the latest version
+ result = shell_out_compact_timeout!("#{easy_install_binary_path} -n #{new_resource.package_name}", returns: [0, 1])
+ @candidate_version = result.stdout[/(.*)Best match: (.*) (.*)$/, 3]
+ @candidate_version
end
def install_package(name, version)
- run_command(:command => "#{easy_install_binary_path}#{expand_options(@new_resource.options)} \"#{name}==#{version}\"")
+ Chef.deprecated(:easy_install, "The easy_install package provider is deprecated and will be removed in Chef 13.")
+ shell_out_compact_timeout!(easy_install_binary_path, options, "#{name}==#{version}")
end
def upgrade_package(name, version)
@@ -121,7 +121,8 @@ class Chef
end
def remove_package(name, version)
- run_command(:command => "#{easy_install_binary_path }#{expand_options(@new_resource.options)} -m #{name}")
+ Chef.deprecated(:easy_install, "The easy_install package provider is deprecated and will be removed in Chef 13.")
+ shell_out_compact_timeout!(easy_install_binary_path, options, "-m", name)
end
def purge_package(name, version)
diff --git a/lib/chef/provider/package/freebsd/base.rb b/lib/chef/provider/package/freebsd/base.rb
index 7c032b3787..64efe61bfb 100644
--- a/lib/chef/provider/package/freebsd/base.rb
+++ b/lib/chef/provider/package/freebsd/base.rb
@@ -2,8 +2,8 @@
# Authors:: Bryan McLellan (btm@loftninjas.org)
# Matthew Landauer (matthew@openaustralia.org)
# Richard Manyanza (liseki@nyikacraftsmen.com)
-# Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer
-# Copyright:: Copyright (c) 2014 Richard Manyanza
+# Copyright:: Copyright 2009-2016, Bryan McLellan, Matthew Landauer
+# Copyright:: Copyright 2014-2016, Richard Manyanza
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,9 +19,9 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package'
-require 'chef/mixin/get_source_from_package'
+require "chef/resource/package"
+require "chef/provider/package"
+require "chef/mixin/get_source_from_package"
class Chef
class Provider
@@ -47,7 +47,7 @@ class Chef
# Otherwise look up the path to the ports directory using 'whereis'
else
- whereis = shell_out_with_timeout!("whereis -s #{port}", :env => nil)
+ whereis = shell_out_compact_timeout!("whereis", "-s", port, env: nil)
unless path = whereis.stdout[/^#{Regexp.escape(port)}:\s+(.+)$/, 1]
raise Chef::Exceptions::Package, "Could not find port with the name #{port}"
end
@@ -56,9 +56,9 @@ class Chef
end
def makefile_variable_value(variable, dir = nil)
- options = dir ? { :cwd => dir } : {}
- make_v = shell_out_with_timeout!("make -V #{variable}", options.merge!(:env => nil, :returns => [0,1]))
- make_v.exitstatus.zero? ? make_v.stdout.strip.split($\).first : nil # $\ is the line separator, i.e. newline.
+ options = dir ? { cwd: dir } : {}
+ make_v = shell_out_compact_timeout!("make", "-V", variable, options.merge!(env: nil, returns: [0, 1]))
+ make_v.exitstatus == 0 ? make_v.stdout.strip.split($OUTPUT_RECORD_SEPARATOR).first : nil # $\ is the line separator, i.e. newline.
end
end
@@ -67,19 +67,19 @@ class Chef
def initialize(*args)
super
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
end
def load_current_resource
- @current_resource.package_name(@new_resource.package_name)
+ current_resource.package_name(new_resource.package_name)
- @current_resource.version(current_installed_version)
- Chef::Log.debug("#{@new_resource} current version is #{@current_resource.version}") if @current_resource.version
+ current_resource.version(current_installed_version)
+ Chef::Log.debug("#{new_resource} current version is #{current_resource.version}") if current_resource.version
@candidate_version = candidate_version
- Chef::Log.debug("#{@new_resource} candidate version is #{@candidate_version}") if @candidate_version
+ Chef::Log.debug("#{new_resource} candidate version is #{@candidate_version}") if @candidate_version
- @current_resource
+ current_resource
end
end
diff --git a/lib/chef/provider/package/freebsd/pkg.rb b/lib/chef/provider/package/freebsd/pkg.rb
index 33a8c2c108..1d66d29be6 100644
--- a/lib/chef/provider/package/freebsd/pkg.rb
+++ b/lib/chef/provider/package/freebsd/pkg.rb
@@ -2,8 +2,8 @@
# Authors:: Bryan McLellan (btm@loftninjas.org)
# Matthew Landauer (matthew@openaustralia.org)
# Richard Manyanza (liseki@nyikacraftsmen.com)
-# Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer
-# Copyright:: Copyright (c) 2014 Richard Manyanza
+# Copyright:: Copyright 2009-2016, Bryan McLellan, Matthew Landauer
+# Copyright:: Copyright 2014-2016, Richard Manyanza
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,8 +19,8 @@
# limitations under the License.
#
-require 'chef/provider/package/freebsd/base'
-require 'chef/util/path_helper'
+require "chef/provider/package/freebsd/base"
+require "chef/util/path_helper"
class Chef
class Provider
@@ -30,28 +30,28 @@ class Chef
include PortsHelper
def install_package(name, version)
- unless @current_resource.version
- case @new_resource.source
+ unless current_resource.version
+ case new_resource.source
when /^http/, /^ftp/
- if @new_resource.source =~ /\/$/
- shell_out_with_timeout!("pkg_add -r #{package_name}", :env => { "PACKAGESITE" => @new_resource.source, 'LC_ALL' => nil }).status
+ if new_resource.source =~ /\/$/
+ shell_out_compact_timeout!("pkg_add", "-r", package_name, env: { "PACKAGESITE" => new_resource.source, "LC_ALL" => nil }).status
else
- shell_out_with_timeout!("pkg_add -r #{package_name}", :env => { "PACKAGEROOT" => @new_resource.source, 'LC_ALL' => nil }).status
+ shell_out_compact_timeout!("pkg_add", "-r", package_name, env: { "PACKAGEROOT" => new_resource.source, "LC_ALL" => nil }).status
end
- Chef::Log.debug("#{@new_resource} installed from: #{@new_resource.source}")
+ Chef::Log.debug("#{new_resource} installed from: #{new_resource.source}")
when /^\//
- shell_out_with_timeout!("pkg_add #{file_candidate_version_path}", :env => { "PKG_PATH" => @new_resource.source , 'LC_ALL'=>nil}).status
- Chef::Log.debug("#{@new_resource} installed from: #{@new_resource.source}")
+ shell_out_compact_timeout!("pkg_add", file_candidate_version_path, env: { "PKG_PATH" => new_resource.source, "LC_ALL" => nil }).status
+ Chef::Log.debug("#{new_resource} installed from: #{new_resource.source}")
else
- shell_out_with_timeout!("pkg_add -r #{latest_link_name}", :env => nil).status
+ shell_out_compact_timeout!("pkg_add", "-r", latest_link_name, env: nil).status
end
end
end
def remove_package(name, version)
- shell_out_with_timeout!("pkg_delete #{package_name}-#{version || @current_resource.version}", :env => nil).status
+ shell_out_compact_timeout!("pkg_delete", "#{package_name}-#{version || current_resource.version}", env: nil).status
end
# The name of the package (without the version number) as understood by pkg_add and pkg_info.
@@ -63,7 +63,7 @@ class Chef
raise Chef::Exceptions::Package, "Unexpected form for PKGNAME variable in #{port_path}/Makefile"
end
else
- @new_resource.package_name
+ new_resource.package_name
end
end
@@ -72,12 +72,12 @@ class Chef
end
def current_installed_version
- pkg_info = shell_out_with_timeout!("pkg_info -E \"#{package_name}*\"", :env => nil, :returns => [0,1])
+ pkg_info = shell_out_compact_timeout!("pkg_info", "-E", "#{package_name}*", env: nil, returns: [0, 1])
pkg_info.stdout[/^#{Regexp.escape(package_name)}-(.+)/, 1]
end
def candidate_version
- case @new_resource.source
+ case new_resource.source
when /^http/, /^ftp/
repo_candidate_version
when /^\//
@@ -88,7 +88,7 @@ class Chef
end
def file_candidate_version_path
- Dir[Chef::Util::PathHelper.escape_glob("#{@new_resource.source}/#{@current_resource.package_name}") + "*"][-1].to_s
+ Dir[Chef::Util::PathHelper.escape_glob_dir("#{new_resource.source}/#{current_resource.package_name}") + "*"][-1].to_s
end
def file_candidate_version
@@ -104,7 +104,7 @@ class Chef
end
def port_path
- port_dir @new_resource.package_name
+ port_dir new_resource.package_name
end
end
diff --git a/lib/chef/provider/package/freebsd/pkgng.rb b/lib/chef/provider/package/freebsd/pkgng.rb
index 2fdc9dda71..9a5f0e9472 100644
--- a/lib/chef/provider/package/freebsd/pkgng.rb
+++ b/lib/chef/provider/package/freebsd/pkgng.rb
@@ -1,6 +1,6 @@
#
# Authors:: Richard Manyanza (liseki@nyikacraftsmen.com)
-# Copyright:: Copyright (c) 2014 Richard Manyanza
+# Copyright:: Copyright 2014-2016, Richard Manyanza
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/provider/package/freebsd/base'
+require "chef/provider/package/freebsd/base"
class Chef
class Provider
@@ -25,46 +25,44 @@ class Chef
class Pkgng < Base
def install_package(name, version)
- unless @current_resource.version
- case @new_resource.source
+ unless current_resource.version
+ case new_resource.source
when /^(http|ftp|\/)/
- shell_out_with_timeout!("pkg add#{expand_options(@new_resource.options)} #{@new_resource.source}", :env => { 'LC_ALL' => nil }).status
- Chef::Log.debug("#{@new_resource} installed from: #{@new_resource.source}")
-
+ shell_out_compact_timeout!("pkg", "add", options, new_resource.source, env: { "LC_ALL" => nil }).status
+ Chef::Log.debug("#{new_resource} installed from: #{new_resource.source}")
else
- shell_out_with_timeout!("pkg install -y#{expand_options(@new_resource.options)} #{name}", :env => { 'LC_ALL' => nil }).status
+ shell_out_compact_timeout!("pkg", "install", "-y", options, name, env: { "LC_ALL" => nil }).status
end
end
end
def remove_package(name, version)
- options = @new_resource.options && @new_resource.options.sub(repo_regex, '')
- options && !options.empty? || options = nil
- shell_out_with_timeout!("pkg delete -y#{expand_options(options)} #{name}#{version ? '-' + version : ''}", :env => nil).status
+ options_dup = options && options.map { |str| str.sub(repo_regex, "") }.reject!(&:empty?)
+ shell_out_compact_timeout!("pkg", "delete", "-y", options_dup, "#{name}#{version ? '-' + version : ''}", env: nil).status
end
def current_installed_version
- pkg_info = shell_out_with_timeout!("pkg info \"#{@new_resource.package_name}\"", :env => nil, :returns => [0,70])
+ pkg_info = shell_out_compact_timeout!("pkg", "info", new_resource.package_name, env: nil, returns: [0, 70])
pkg_info.stdout[/^Version +: (.+)$/, 1]
end
def candidate_version
- @new_resource.source ? file_candidate_version : repo_candidate_version
+ new_resource.source ? file_candidate_version : repo_candidate_version
end
private
def file_candidate_version
- @new_resource.source[/#{Regexp.escape(@new_resource.package_name)}-(.+)\.txz/, 1]
+ new_resource.source[/#{Regexp.escape(new_resource.package_name)}-(.+)\.txz/, 1]
end
def repo_candidate_version
- if @new_resource.options && @new_resource.options.match(repo_regex)
- options = $1
+ if options && options.join(" ").match(repo_regex)
+ options = $1.split(" ")
end
- pkg_query = shell_out_with_timeout!("pkg rquery#{expand_options(options)} '%v' #{@new_resource.package_name}", :env => nil)
- pkg_query.exitstatus.zero? ? pkg_query.stdout.strip.split(/\n/).last : nil
+ pkg_query = shell_out_compact_timeout!("pkg", "rquery", options, "%v", new_resource.package_name, env: nil)
+ pkg_query.exitstatus == 0 ? pkg_query.stdout.strip.split(/\n/).last : nil
end
def repo_regex
diff --git a/lib/chef/provider/package/freebsd/port.rb b/lib/chef/provider/package/freebsd/port.rb
index 3fbd002214..e87be4d304 100644
--- a/lib/chef/provider/package/freebsd/port.rb
+++ b/lib/chef/provider/package/freebsd/port.rb
@@ -1,6 +1,6 @@
#
# Authors:: Richard Manyanza (liseki@nyikacraftsmen.com)
-# Copyright:: Copyright (c) 2014 Richard Manyanza
+# Copyright:: Copyright 2014-2016, Richard Manyanza
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/provider/package/freebsd/base'
+require "chef/provider/package/freebsd/base"
class Chef
class Provider
@@ -26,20 +26,20 @@ class Chef
include PortsHelper
def install_package(name, version)
- shell_out_with_timeout!("make -DBATCH install clean", :timeout => 1800, :env => nil, :cwd => port_dir).status
+ shell_out_compact_timeout!("make", "-DBATCH", "install", "clean", timeout: 1800, env: nil, cwd: port_dir).status
end
def remove_package(name, version)
- shell_out_with_timeout!("make deinstall", :timeout => 300, :env => nil, :cwd => port_dir).status
+ shell_out_compact_timeout!("make", "deinstall", timeout: 300, env: nil, cwd: port_dir).status
end
def current_installed_version
- pkg_info = if @new_resource.supports_pkgng?
- shell_out_with_timeout!("pkg info \"#{@new_resource.package_name}\"", :env => nil, :returns => [0,70])
+ pkg_info = if new_resource.supports_pkgng?
+ shell_out_compact_timeout!("pkg", "info", new_resource.package_name, env: nil, returns: [0, 70])
else
- shell_out_with_timeout!("pkg_info -E \"#{@new_resource.package_name}*\"", :env => nil, :returns => [0,1])
+ shell_out_compact_timeout!("pkg_info", "-E", "#{new_resource.package_name}*", env: nil, returns: [0, 1])
end
- pkg_info.stdout[/^#{Regexp.escape(@new_resource.package_name)}-(.+)/, 1]
+ pkg_info.stdout[/^#{Regexp.escape(new_resource.package_name)}-(.+)/, 1]
end
def candidate_version
@@ -51,7 +51,7 @@ class Chef
end
def port_dir
- super(@new_resource.package_name)
+ super(new_resource.package_name)
end
end
end
diff --git a/lib/chef/provider/package/homebrew.rb b/lib/chef/provider/package/homebrew.rb
index e5c45f0a62..f4e19bc857 100644
--- a/lib/chef/provider/package/homebrew.rb
+++ b/lib/chef/provider/package/homebrew.rb
@@ -1,9 +1,9 @@
#
-# Author:: Joshua Timberman (<joshua@getchef.com>)
+# Author:: Joshua Timberman (<joshua@chef.io>)
# Author:: Graeme Mathieson (<mathie@woss.name>)
#
-# Copyright 2011-2013, Opscode, Inc.
-# Copyright 2014, Chef Software, Inc <legal@getchef.com>
+# Copyright 2011-2016, Chef Software Inc.
+# Copyright 2014-2016, Chef Software, Inc <legal@chef.io>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,8 +18,8 @@
# limitations under the License.
#
-require 'etc'
-require 'chef/mixin/homebrew_user'
+require "etc"
+require "chef/mixin/homebrew_user"
class Chef
class Provider
@@ -32,7 +32,7 @@ class Chef
include Chef::Mixin::HomebrewUser
def load_current_resource
- self.current_resource = Chef::Resource::Package.new(new_resource.name)
+ self.current_resource = Chef::Resource::HomebrewPackage.new(new_resource.name)
current_resource.package_name(new_resource.package_name)
current_resource.version(current_installed_version)
Chef::Log.debug("#{new_resource} current version is #{current_resource.version}") if current_resource.version
@@ -46,34 +46,35 @@ class Chef
def install_package(name, version)
unless current_resource.version == version
- brew('install', new_resource.options, name)
+ brew("install", options, name)
end
end
def upgrade_package(name, version)
current_version = current_resource.version
- if current_version.nil? or current_version.empty?
+ if current_version.nil? || current_version.empty?
install_package(name, version)
elsif current_version != version
- brew('upgrade', new_resource.options, name)
+ brew("upgrade", options, name)
end
end
def remove_package(name, version)
if current_resource.version
- brew('uninstall', new_resource.options, name)
+ brew("uninstall", options, name)
end
end
# Homebrew doesn't really have a notion of purging, do a "force remove"
def purge_package(name, version)
- new_resource.options((new_resource.options || '') << ' --force').strip
- remove_package(name, version)
+ if current_resource.version
+ brew("uninstall", "--force", options, name)
+ end
end
def brew(*args)
- get_response_from_command("brew #{args.join(' ')}")
+ get_response_from_command("brew", *args)
end
# We implement a querying method that returns the JSON-as-Hash
@@ -85,7 +86,7 @@ class Chef
#
# https://github.com/Homebrew/homebrew/wiki/Querying-Brew
def brew_info
- @brew_info ||= Chef::JSONCompat.from_json(brew('info', '--json=v1', new_resource.package_name)).first
+ @brew_info ||= Chef::JSONCompat.from_json(brew("info", "--json=v1", new_resource.package_name)).first
end
# Some packages (formula) are "keg only" and aren't linked,
@@ -95,14 +96,14 @@ class Chef
# that brew thinks is linked as the current version.
#
def current_installed_version
- if brew_info['keg_only']
- if brew_info['installed'].empty?
+ if brew_info["keg_only"]
+ if brew_info["installed"].empty?
nil
else
- brew_info['installed'].last['version']
+ brew_info["installed"].last["version"]
end
else
- brew_info['linked_keg']
+ brew_info["linked_keg"]
end
end
@@ -116,18 +117,18 @@ class Chef
#
# https://github.com/Homebrew/homebrew/wiki/Acceptable-Formulae#stable-versions
def candidate_version
- brew_info['versions']['stable']
+ brew_info["versions"]["stable"]
end
private
- def get_response_from_command(command)
+ def get_response_from_command(*command)
homebrew_uid = find_homebrew_uid(new_resource.respond_to?(:homebrew_user) && new_resource.homebrew_user)
homebrew_user = Etc.getpwuid(homebrew_uid)
- Chef::Log.debug "Executing '#{command}' as user '#{homebrew_user.name}'"
+ Chef::Log.debug "Executing '#{command.join(' ')}' as user '#{homebrew_user.name}'"
# FIXME: this 1800 second default timeout should be deprecated
- output = shell_out_with_timeout!(command, :timeout => 1800, :user => homebrew_uid, :environment => { 'HOME' => homebrew_user.dir, 'RUBYOPT' => nil })
+ output = shell_out_compact_timeout!(*command, timeout: 1800, user: homebrew_uid, environment: { "HOME" => homebrew_user.dir, "RUBYOPT" => nil, "TMPDIR" => nil })
output.stdout.chomp
end
diff --git a/lib/chef/provider/package/ips.rb b/lib/chef/provider/package/ips.rb
index 96c2e711d4..9666013cc3 100644
--- a/lib/chef/provider/package/ips.rb
+++ b/lib/chef/provider/package/ips.rb
@@ -1,7 +1,7 @@
#
# Author:: Jason J. W. Williams (<williamsjj@digitar.com>)
-# Author:: Stephen Nelson-Smith (<sns@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Stephen Nelson-Smith (<sns@chef.io>)
+# Copyright:: Copyright 2011-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,17 +17,17 @@
# limitations under the License.
#
-require 'open3'
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
+require "open3"
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
class Chef
class Provider
class Package
class Ips < Chef::Provider::Package
- provides :package, platform: %w(openindiana opensolaris omnios solaris2)
+ provides :package, platform: %w{openindiana opensolaris omnios solaris2}
provides :ips_package, os: "solaris2"
attr_accessor :virtual
@@ -36,45 +36,40 @@ class Chef
super
requirements.assert(:all_actions) do |a|
- a.assertion { ! @candidate_version.nil? }
- a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.package_name} not found"
- a.whyrun "Assuming package #{@new_resource.package_name} would have been made available."
+ a.assertion { !@candidate_version.nil? }
+ a.failure_message Chef::Exceptions::Package, "Package #{new_resource.package_name} not found"
+ a.whyrun "Assuming package #{new_resource.package_name} would have been made available."
end
end
def get_current_version
- shell_out_with_timeout("pkg info #{@new_resource.package_name}").stdout.each_line do |line|
+ shell_out_compact_timeout("pkg", "info", new_resource.package_name).stdout.each_line do |line|
return $1.split[0] if line =~ /^\s+Version: (.*)/
end
- return nil
+ nil
end
def get_candidate_version
- shell_out_with_timeout!("pkg info -r #{new_resource.package_name}").stdout.each_line do |line|
+ shell_out_compact_timeout!("pkg", "info", "-r", new_resource.package_name).stdout.each_line do |line|
return $1.split[0] if line =~ /Version: (.*)/
end
- return nil
+ nil
end
def load_current_resource
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
- Chef::Log.debug("Checking package status for #{@new_resource.name}")
- @current_resource.version(get_current_version)
+ @current_resource = Chef::Resource::IpsPackage.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
+ Chef::Log.debug("Checking package status for #{new_resource.name}")
+ current_resource.version(get_current_version)
@candidate_version = get_candidate_version
- @current_resource
+ current_resource
end
def install_package(name, version)
- package_name = "#{name}@#{version}"
- normal_command = "pkg#{expand_options(@new_resource.options)} install -q #{package_name}"
- command =
- if @new_resource.respond_to?(:accept_license) and @new_resource.accept_license
- normal_command.gsub('-q', '-q --accept')
- else
- normal_command
- end
- shell_out_with_timeout(command)
+ command = [ "pkg", options, "install", "-q" ]
+ command << "--accept" if new_resource.accept_license
+ command << "#{name}@#{version}"
+ shell_out_compact_timeout!(command)
end
def upgrade_package(name, version)
@@ -83,7 +78,7 @@ class Chef
def remove_package(name, version)
package_name = "#{name}@#{version}"
- shell_out_with_timeout!( "pkg#{expand_options(@new_resource.options)} uninstall -q #{package_name}" )
+ shell_out_compact_timeout!( "pkg", options, "uninstall", "-q", package_name )
end
end
end
diff --git a/lib/chef/provider/package/macports.rb b/lib/chef/provider/package/macports.rb
index c7ea71ac8c..ad4be00477 100644
--- a/lib/chef/provider/package/macports.rb
+++ b/lib/chef/provider/package/macports.rb
@@ -7,25 +7,25 @@ class Chef
provides :macports_package
def load_current_resource
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
- @current_resource.version(current_installed_version)
- Chef::Log.debug("#{@new_resource} current version is #{@current_resource.version}") if @current_resource.version
+ current_resource.version(current_installed_version)
+ Chef::Log.debug("#{new_resource} current version is #{current_resource.version}") if current_resource.version
@candidate_version = macports_candidate_version
- if !@new_resource.version and !@candidate_version
- raise Chef::Exceptions::Package, "Could not get a candidate version for this package -- #{@new_resource.name} does not seem to be a valid package!"
+ if !new_resource.version && !@candidate_version
+ raise Chef::Exceptions::Package, "Could not get a candidate version for this package -- #{new_resource.name} does not seem to be a valid package!"
end
- Chef::Log.debug("#{@new_resource} candidate version is #{@candidate_version}") if @candidate_version
+ Chef::Log.debug("#{new_resource} candidate version is #{@candidate_version}") if @candidate_version
- @current_resource
+ current_resource
end
def current_installed_version
- command = "port installed #{@new_resource.package_name}"
+ command = [ "port", "installed", new_resource.package_name ]
output = get_response_from_command(command)
response = nil
@@ -37,7 +37,7 @@ class Chef
end
def macports_candidate_version
- command = "port info --version #{@new_resource.package_name}"
+ command = [ "port", "info", "--version", new_resource.package_name ]
output = get_response_from_command(command)
match = output.match(/^version: (.+)$/)
@@ -46,44 +46,45 @@ class Chef
end
def install_package(name, version)
- unless @current_resource.version == version
- command = "port#{expand_options(@new_resource.options)} install #{name}"
- command << " @#{version}" if version and !version.empty?
- shell_out_with_timeout!(command)
+ unless current_resource.version == version
+ command = [ "port", options, "install", name ]
+ command << "@#{version}" if version && !version.empty?
+ shell_out_compact_timeout!(command)
end
end
def purge_package(name, version)
- command = "port#{expand_options(@new_resource.options)} uninstall #{name}"
- command << " @#{version}" if version and !version.empty?
- shell_out_with_timeout!(command)
+ command = [ "port", options, "uninstall", name ]
+ command << "@#{version}" if version && !version.empty?
+ shell_out_compact_timeout!(command)
end
def remove_package(name, version)
- command = "port#{expand_options(@new_resource.options)} deactivate #{name}"
- command << " @#{version}" if version and !version.empty?
+ command = [ "port", options, "deactivate", name ]
+ command << "@#{version}" if version && !version.empty?
- shell_out_with_timeout!(command)
+ shell_out_compact_timeout!(command)
end
def upgrade_package(name, version)
# Saving this to a variable -- weird rSpec behavior
# happens otherwise...
- current_version = @current_resource.version
+ current_version = current_resource.version
- if current_version.nil? or current_version.empty?
+ if current_version.nil? || current_version.empty?
# Macports doesn't like when you upgrade a package
# that hasn't been installed.
install_package(name, version)
elsif current_version != version
- shell_out_with_timeout!( "port#{expand_options(@new_resource.options)} upgrade #{name} @#{version}" )
+ shell_out_compact_timeout!( "port", options, "upgrade", name, "@#{version}" )
end
end
private
+
def get_response_from_command(command)
output = nil
- status = shell_out_with_timeout(command)
+ status = shell_out_compact_timeout(command)
begin
output = status.stdout
rescue Exception
diff --git a/lib/chef/provider/package/msu.rb b/lib/chef/provider/package/msu.rb
new file mode 100644
index 0000000000..fe4a11461f
--- /dev/null
+++ b/lib/chef/provider/package/msu.rb
@@ -0,0 +1,162 @@
+#
+# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# msu_package leverages cab_package
+# The contents of msu file are extracted, which contains one or more cab files.
+# The extracted cab files are installed using Chef::Resource::Package::CabPackage
+# Reference: https://support.microsoft.com/en-in/kb/934307
+require "chef/provider/package"
+require "chef/resource/msu_package"
+require "chef/mixin/shell_out"
+require "chef/provider/package/cab"
+require "chef/util/path_helper"
+require "chef/mixin/uris"
+require "chef/mixin/checksum"
+
+class Chef
+ class Provider
+ class Package
+ class Msu < Chef::Provider::Package
+ use_inline_resources
+ include Chef::Mixin::ShellOut
+ include Chef::Mixin::Uris
+ include Chef::Mixin::Checksum
+
+ provides :msu_package, os: "windows"
+
+ def load_current_resource
+ @current_resource = Chef::Resource::MsuPackage.new(new_resource.name)
+
+ # download file if source is a url
+ msu_file = uri_scheme?(new_resource.source) ? download_source_file : new_resource.source
+
+ # temp directory where the contents of msu file get extracted
+ @temp_directory = Dir.mktmpdir("chef")
+ extract_msu_contents(msu_file, @temp_directory)
+ @cab_files = read_cab_files_from_xml(@temp_directory)
+
+ if @cab_files.empty?
+ raise Chef::Exceptions::Package, "Corrupt MSU package: MSU package XML does not contain any cab file"
+ else
+ current_resource.version(get_current_versions)
+ end
+ current_resource
+ end
+
+ def get_current_versions
+ @cab_files.map do |cabfile|
+ cab_pkg = get_cab_package(cabfile)
+ cab_pkg.installed_version
+ end
+ end
+
+ def get_candidate_versions
+ @cab_files.map do |cabfile|
+ cab_pkg = get_cab_package(cabfile)
+ cab_pkg.package_version
+ end
+ end
+
+ def candidate_version
+ @candidate_version ||= get_candidate_versions
+ end
+
+ def get_cab_package(cab_file)
+ cab_resource = new_resource
+ cab_resource.source = cab_file
+ cab_pkg = Chef::Provider::Package::Cab.new(cab_resource, nil)
+ end
+
+ def download_source_file
+ source_resource.run_action(:create)
+ Chef::Log.debug("#{new_resource} fetched source file to #{source_resource.path}")
+ source_resource.path
+ end
+
+ def source_resource
+ @source_resource ||= declare_resource(:remote_file, new_resource.name) do
+ path default_download_cache_path
+ source new_resource.source
+ checksum new_resource.checksum
+ backup false
+ end
+ end
+
+ def default_download_cache_path
+ uri = ::URI.parse(new_resource.source)
+ filename = ::File.basename(::URI.unescape(uri.path))
+ file_cache_dir = Chef::FileCache.create_cache_path("package/")
+ Chef::Util::PathHelper.cleanpath("#{file_cache_dir}/#{filename}")
+ end
+
+ def install_package(name, version)
+ # use cab_package resource to install the extracted cab packages
+ @cab_files.each do |cab_file|
+ declare_resource(:cab_package, new_resource.name) do
+ source cab_file
+ action :install
+ end
+ end
+ end
+
+ def remove_package(name, version)
+ # use cab_package provider to remove the extracted cab packages
+ @cab_files.each do |cab_file|
+ declare_resource(:cab_package, new_resource.name) do
+ source cab_file
+ action :remove
+ end
+ end
+ end
+
+ def extract_msu_contents(msu_file, destination)
+ with_os_architecture(nil) do
+ shell_out_with_timeout!("#{ENV['SYSTEMROOT']}\\system32\\expand.exe -f:* #{msu_file} #{destination}")
+ end
+ end
+
+ # msu package can contain multiple cab files
+ # Reading cab files from xml to ensure the order of installation in case of multiple cab files
+ def read_cab_files_from_xml(msu_dir)
+ # get the file with .xml extension
+ xml_files = Dir.glob("#{msu_dir}/*.xml")
+ cab_files = []
+
+ if xml_files.empty?
+ raise Chef::Exceptions::Package, "Corrupt MSU package: MSU package doesn't contain any xml file"
+ else
+ # msu package contains only single xml file. So using xml_files.first is sufficient
+ doc = ::File.open(xml_files.first.to_s) { |f| REXML::Document.new f }
+ locations = doc.elements.each("unattend/servicing/package/source") { |element| puts element.attributes["location"] }
+ locations.each do |loc|
+ cab_files << msu_dir + "/" + loc.attribute("location").value.split("\\")[1]
+ end
+
+ cab_files
+ end
+ cab_files
+ end
+
+ def cleanup_after_converge
+ # delete the temp directory where the contents of msu file are extracted
+ FileUtils.rm_rf(@temp_directory) if Dir.exist?(@temp_directory)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/openbsd.rb b/lib/chef/provider/package/openbsd.rb
index 7a6582363e..2614683fba 100644
--- a/lib/chef/provider/package/openbsd.rb
+++ b/lib/chef/provider/package/openbsd.rb
@@ -3,8 +3,8 @@
# Matthew Landauer (matthew@openaustralia.org)
# Richard Manyanza (liseki@nyikacraftsmen.com)
# Scott Bonds (scott@ggr.com)
-# Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer
-# Copyright:: Copyright (c) 2014 Richard Manyanza, Scott Bonds
+# Copyright:: Copyright 2009-2016, Bryan McLellan, Matthew Landauer
+# Copyright:: Copyright 2014-2016, Richard Manyanza, Scott Bonds
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,10 +20,10 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package'
-require 'chef/mixin/get_source_from_package'
-require 'chef/exceptions'
+require "chef/resource/package"
+require "chef/provider/package"
+require "chef/mixin/get_source_from_package"
+require "chef/exceptions"
class Chef
class Provider
@@ -42,9 +42,9 @@ class Chef
end
def load_current_resource
- @current_resource.package_name(new_resource.package_name)
- @current_resource.version(installed_version)
- @current_resource
+ current_resource.package_name(new_resource.package_name)
+ current_resource.version(installed_version)
+ current_resource
end
def define_resource_requirements
@@ -53,7 +53,7 @@ class Chef
# Below are incomplete/missing features for this package provider
requirements.assert(:all_actions) do |a|
a.assertion { !new_resource.source }
- a.failure_message(Chef::Exceptions::Package, 'The openbsd package provider does not support the source attribute')
+ a.failure_message(Chef::Exceptions::Package, "The openbsd package provider does not support the source attribute")
end
requirements.assert(:all_actions) do |a|
a.assertion do
@@ -63,38 +63,36 @@ class Chef
true
end
end
- a.failure_message(Chef::Exceptions::Package, 'The openbsd package provider does not support providing a version and flavor')
+ a.failure_message(Chef::Exceptions::Package, "The openbsd package provider does not support providing a version and flavor")
end
end
def install_package(name, version)
- unless @current_resource.version
+ unless current_resource.version
if parts = name.match(/^(.+?)--(.+)/) # use double-dash for stems with flavors, see man page for pkg_add
name = parts[1]
end
- shell_out_with_timeout!("pkg_add -r #{name}#{version_string}", :env => {"PKG_PATH" => pkg_path}).status
+ shell_out_compact_timeout!("pkg_add", "-r", package_string(name, version), env: { "PKG_PATH" => pkg_path }).status
Chef::Log.debug("#{new_resource.package_name} installed")
end
end
def remove_package(name, version)
- version_string = ''
- version_string += "-#{version}" if version
if parts = name.match(/^(.+?)--(.+)/)
name = parts[1]
end
- shell_out_with_timeout!("pkg_delete #{name}#{version_string}", :env => nil).status
+ shell_out_compact_timeout!("pkg_delete", package_string(name, version), env: nil).status
end
private
def installed_version
- if parts = new_resource.package_name.match(/^(.+?)--(.+)/)
- name = parts[1]
- else
- name = new_resource.package_name
- end
- pkg_info = shell_out_with_timeout!("pkg_info -e \"#{name}->0\"", :env => nil, :returns => [0,1])
+ name = if parts = new_resource.package_name.match(/^(.+?)--(.+)/)
+ parts[1]
+ else
+ new_resource.package_name
+ end
+ pkg_info = shell_out_compact_timeout!("pkg_info", "-e", "#{name}->0", env: nil, returns: [0, 1])
result = pkg_info.stdout[/^inst:#{Regexp.escape(name)}-(.+?)\s/, 1]
Chef::Log.debug("installed_version of '#{new_resource.package_name}' is '#{result}'")
result
@@ -103,12 +101,12 @@ class Chef
def candidate_version
@candidate_version ||= begin
results = []
- shell_out_with_timeout!("pkg_info -I \"#{new_resource.package_name}#{version_string}\"", :env => nil, :returns => [0,1]).stdout.each_line do |line|
- if parts = new_resource.package_name.match(/^(.+?)--(.+)/)
- results << line[/^#{Regexp.escape(parts[1])}-(.+?)\s/, 1]
- else
- results << line[/^#{Regexp.escape(new_resource.package_name)}-(.+?)\s/, 1]
- end
+ shell_out_compact_timeout!("pkg_info", "-I", package_string(new_resource.package_name, new_resource.version), env: nil, returns: [0, 1]).stdout.each_line do |line|
+ results << if parts = new_resource.package_name.match(/^(.+?)--(.+)/)
+ line[/^#{Regexp.escape(parts[1])}-(.+?)\s/, 1]
+ else
+ line[/^#{Regexp.escape(new_resource.package_name)}-(.+?)\s/, 1]
+ end
end
results = results.reject(&:nil?)
Chef::Log.debug("Candidate versions of '#{new_resource.package_name}' are '#{results}'")
@@ -123,13 +121,16 @@ class Chef
end
end
- def version_string
- ver = ''
- ver += "-#{new_resource.version}" if new_resource.version
+ def package_string(name, version)
+ if version
+ "#{name}-#{version}"
+ else
+ name
+ end
end
def pkg_path
- ENV['PKG_PATH'] || "http://ftp.OpenBSD.org/pub/#{node.kernel.name}/#{node.kernel.release}/packages/#{node.kernel.machine}/"
+ ENV["PKG_PATH"] || "http://ftp.OpenBSD.org/pub/#{node['kernel']['name']}/#{node['kernel']['release']}/packages/#{node['kernel']['machine']}/"
end
end
diff --git a/lib/chef/provider/package/pacman.rb b/lib/chef/provider/package/pacman.rb
index 01e3a9cc01..25683687b2 100644
--- a/lib/chef/provider/package/pacman.rb
+++ b/lib/chef/provider/package/pacman.rb
@@ -1,6 +1,6 @@
#
# Author:: Jan Zimmek (<jan.zimmek@web.de>)
-# Copyright:: Copyright (c) 2010 Jan Zimmek
+# Copyright:: Copyright 2010-2016, Jan Zimmek
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
class Chef
class Provider
@@ -29,18 +29,16 @@ class Chef
provides :pacman_package, os: "linux"
def load_current_resource
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
- @current_resource.version(nil)
-
- Chef::Log.debug("#{@new_resource} checking pacman for #{@new_resource.package_name}")
- status = shell_out_with_timeout("pacman -Qi #{@new_resource.package_name}")
+ Chef::Log.debug("#{new_resource} checking pacman for #{new_resource.package_name}")
+ status = shell_out_compact_timeout("pacman", "-Qi", new_resource.package_name)
status.stdout.each_line do |line|
case line
when /^Version(\s?)*: (.+)$/
- Chef::Log.debug("#{@new_resource} current version is #{$2}")
- @current_resource.version($2)
+ Chef::Log.debug("#{new_resource} current version is #{$2}")
+ current_resource.version($2)
end
end
@@ -48,28 +46,28 @@ class Chef
raise Chef::Exceptions::Package, "pacman failed - #{status.inspect}!"
end
- @current_resource
+ current_resource
end
def candidate_version
return @candidate_version if @candidate_version
- repos = ["extra","core","community"]
+ repos = %w{extra core community}
- if(::File.exists?("/etc/pacman.conf"))
+ if ::File.exist?("/etc/pacman.conf")
pacman = ::File.read("/etc/pacman.conf")
repos = pacman.scan(/\[(.+)\]/).flatten
end
- package_repos = repos.map {|r| Regexp.escape(r) }.join('|')
+ package_repos = repos.map { |r| Regexp.escape(r) }.join("|")
- status = shell_out_with_timeout("pacman -Sl")
+ status = shell_out_compact_timeout("pacman", "-Sl")
status.stdout.each_line do |line|
case line
- when /^(#{package_repos}) #{Regexp.escape(@new_resource.package_name)} (.+)$/
- # $2 contains a string like "4.4.0-1" or "3.10-4 [installed]"
- # simply split by space and use first token
- @candidate_version = $2.split(" ").first
+ when /^(#{package_repos}) #{Regexp.escape(new_resource.package_name)} (.+)$/
+ # $2 contains a string like "4.4.0-1" or "3.10-4 [installed]"
+ # simply split by space and use first token
+ @candidate_version = $2.split(" ").first
end
end
@@ -78,15 +76,14 @@ class Chef
end
unless @candidate_version
- raise Chef::Exceptions::Package, "pacman does not have a version of package #{@new_resource.package_name}"
+ raise Chef::Exceptions::Package, "pacman does not have a version of package #{new_resource.package_name}"
end
@candidate_version
-
end
def install_package(name, version)
- shell_out_with_timeout!( "pacman --sync --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}" )
+ shell_out_compact_timeout!( "pacman", "--sync", "--noconfirm", "--noprogressbar", options, name)
end
def upgrade_package(name, version)
@@ -94,7 +91,7 @@ class Chef
end
def remove_package(name, version)
- shell_out_with_timeout!( "pacman --remove --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}" )
+ shell_out_compact_timeout!( "pacman", "--remove", "--noconfirm", "--noprogressbar", options, name )
end
def purge_package(name, version)
diff --git a/lib/chef/provider/package/paludis.rb b/lib/chef/provider/package/paludis.rb
index 2d6302515b..0b57d05adf 100644
--- a/lib/chef/provider/package/paludis.rb
+++ b/lib/chef/provider/package/paludis.rb
@@ -1,6 +1,6 @@
#
# Author:: Vasiliy Tolstov (<v.tolstov@selfip.ru>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/provider/package'
-require 'chef/resource/package'
+require "chef/provider/package"
+require "chef/resource/package"
class Chef
class Provider
@@ -28,41 +28,37 @@ class Chef
provides :paludis_package, os: "linux"
def load_current_resource
- @current_resource = Chef::Resource::Package.new(@new_resource.package_name)
- @current_resource.package_name(@new_resource.package_name)
+ @current_resource = Chef::Resource::Package.new(new_resource.package_name)
+ current_resource.package_name(new_resource.package_name)
- @current_resource.version(nil)
-
- Chef::Log.debug("Checking package status for #{@new_resource.package_name}")
+ Chef::Log.debug("Checking package status for #{new_resource.package_name}")
installed = false
- re = Regexp.new('(.*)[[:blank:]](.*)[[:blank:]](.*)$')
+ re = Regexp.new("(.*)[[:blank:]](.*)[[:blank:]](.*)$")
- shell_out!("cave -L warning print-ids -M none -m \"#{@new_resource.package_name}\" -f \"%c/%p %v %r\n\"").stdout.each_line do |line|
+ shell_out_compact!("cave", "-L", "warning", "print-ids", "-M", "none", "-m", new_resource.package_name, "-f", "%c/%p %v %r\n").stdout.each_line do |line|
res = re.match(line)
- unless res.nil?
- case res[3]
- when 'accounts', 'installed-accounts'
- next
- when 'installed'
- installed = true
- @current_resource.version(res[2])
- else
- @candidate_version = res[2]
- @current_resource.version(nil)
- end
+ next if res.nil?
+ case res[3]
+ when "accounts", "installed-accounts"
+ next
+ when "installed"
+ installed = true
+ current_resource.version(res[2])
+ else
+ @candidate_version = res[2]
end
end
- @current_resource
+ current_resource
end
def install_package(name, version)
- if(version)
- pkg = "=#{name}-#{version}"
- else
- pkg = "#{@new_resource.package_name}"
- end
- shell_out!("cave -L warning resolve -x#{expand_options(@new_resource.options)} \"#{pkg}\"",:timeout => @new_resource.timeout)
+ pkg = if version
+ "=#{name}-#{version}"
+ else
+ new_resource.package_name.to_s
+ end
+ shell_out_compact_timeout!("cave", "-L", "warning", "resolve", "-x", options, pkg)
end
def upgrade_package(name, version)
@@ -70,13 +66,13 @@ class Chef
end
def remove_package(name, version)
- if(version)
- pkg = "=#{@new_resource.package_name}-#{version}"
- else
- pkg = "#{@new_resource.package_name}"
- end
+ pkg = if version
+ "=#{new_resource.package_name}-#{version}"
+ else
+ new_resource.package_name.to_s
+ end
- shell_out!("cave -L warning uninstall -x#{expand_options(@new_resource.options)} \"#{pkg}\"")
+ shell_out_compact!("cave", "-L", "warning", "uninstall", "-x", options, pkg)
end
def purge_package(name, version)
diff --git a/lib/chef/provider/package/portage.rb b/lib/chef/provider/package/portage.rb
index 95782a6774..fd96dfa47f 100644
--- a/lib/chef/provider/package/portage.rb
+++ b/lib/chef/provider/package/portage.rb
@@ -1,6 +1,6 @@
#
# Author:: Ezra Zygmuntowicz (<ezra@engineyard.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'chef/util/path_helper'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
+require "chef/util/path_helper"
class Chef
class Provider
@@ -32,34 +32,32 @@ class Chef
PACKAGE_NAME_PATTERN = %r{(?:([^/]+)/)?([^/]+)}
def load_current_resource
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
- @current_resource.version(nil)
+ category, pkg = /^#{PACKAGE_NAME_PATTERN}$/.match(new_resource.package_name)[1, 2]
- category, pkg = %r{^#{PACKAGE_NAME_PATTERN}$}.match(@new_resource.package_name)[1,2]
-
- globsafe_category = category ? Chef::Util::PathHelper.escape_glob(category) : nil
- globsafe_pkg = Chef::Util::PathHelper.escape_glob(pkg)
- possibilities = Dir["/var/db/pkg/#{globsafe_category || "*"}/#{globsafe_pkg}-*"].map {|d| d.sub(%r{/var/db/pkg/}, "") }
+ globsafe_category = category ? Chef::Util::PathHelper.escape_glob_dir(category) : nil
+ globsafe_pkg = Chef::Util::PathHelper.escape_glob_dir(pkg)
+ possibilities = Dir["/var/db/pkg/#{globsafe_category || '*'}/#{globsafe_pkg}-*"].map { |d| d.sub(%r{/var/db/pkg/}, "") }
versions = possibilities.map do |entry|
- if(entry =~ %r{[^/]+/#{Regexp.escape(pkg)}\-(\d[\.\d]*((_(alpha|beta|pre|rc|p)\d*)*)?(-r\d+)?)})
+ if entry =~ %r{[^/]+/#{Regexp.escape(pkg)}\-(\d[\.\d]*[a-z]?((_(alpha|beta|pre|rc|p)\d*)*)?(-r\d+)?)}
[$&, $1]
end
end.compact
if versions.size > 1
- atoms = versions.map {|v| v.first }.sort
- categories = atoms.map {|v| v.split('/')[0] }.uniq
+ atoms = versions.map(&:first).sort
+ categories = atoms.map { |v| v.split("/")[0] }.uniq
if !category && categories.size > 1
- raise Chef::Exceptions::Package, "Multiple packages found for #{@new_resource.package_name}: #{atoms.join(" ")}. Specify a category."
+ raise Chef::Exceptions::Package, "Multiple packages found for #{new_resource.package_name}: #{atoms.join(' ')}. Specify a category."
end
elsif versions.size == 1
- @current_resource.version(versions.first.last)
- Chef::Log.debug("#{@new_resource} current version #{$1}")
+ current_resource.version(versions.first.last)
+ Chef::Log.debug("#{new_resource} current version #{$1}")
end
- @current_resource
+ current_resource
end
def parse_emerge(package, txt)
@@ -68,26 +66,26 @@ class Chef
txt.each_line do |line|
if line =~ /\*\s+#{PACKAGE_NAME_PATTERN}/
- found_package_name = $&.gsub(/\*/, '').strip
- if package =~ /\// #the category is specified
+ found_package_name = $&.delete("*").strip
+ if package =~ /\// # the category is specified
if found_package_name == package
availables[found_package_name] = nil
end
- else #the category is not specified
+ else # the category is not specified
if found_package_name.split("/").last == package
availables[found_package_name] = nil
end
end
end
- if line =~ /Latest version available: (.*)/ && availables.has_key?(found_package_name)
+ if line =~ /Latest version available: (.*)/ && availables.key?(found_package_name)
availables[found_package_name] = $1.strip
end
end
if availables.size > 1
# shouldn't happen if a category is specified so just use `package`
- raise Chef::Exceptions::Package, "Multiple emerge results found for #{package}: #{availables.keys.join(" ")}. Specify a category."
+ raise Chef::Exceptions::Package, "Multiple emerge results found for #{package}: #{availables.keys.join(' ')}. Specify a category."
end
availables.values.first
@@ -96,8 +94,8 @@ class Chef
def candidate_version
return @candidate_version if @candidate_version
- status = shell_out("emerge --color n --nospinner --search #{@new_resource.package_name.split('/').last}")
- available, installed = parse_emerge(@new_resource.package_name, status.stdout)
+ status = shell_out_compact("emerge", "--color", "n", "--nospinner", "--search", new_resource.package_name.split("/").last)
+ available, installed = parse_emerge(new_resource.package_name, status.stdout)
@candidate_version = available
unless status.exitstatus == 0
@@ -105,18 +103,17 @@ class Chef
end
@candidate_version
-
end
def install_package(name, version)
pkg = "=#{name}-#{version}"
- if(version =~ /^\~(.+)/)
+ if version =~ /^\~(.+)/
# If we start with a tilde
pkg = "~#{name}-#{$1}"
end
- shell_out!( "emerge -g --color n --nospinner --quiet#{expand_options(@new_resource.options)} #{pkg}" )
+ shell_out_compact!( "emerge", "-g", "--color", "n", "--nospinner", "--quiet", options, pkg )
end
def upgrade_package(name, version)
@@ -124,13 +121,13 @@ class Chef
end
def remove_package(name, version)
- if(version)
- pkg = "=#{@new_resource.package_name}-#{version}"
- else
- pkg = "#{@new_resource.package_name}"
- end
+ pkg = if version
+ "=#{new_resource.package_name}-#{version}"
+ else
+ new_resource.package_name.to_s
+ end
- shell_out!( "emerge --unmerge --color n --nospinner --quiet#{expand_options(@new_resource.options)} #{pkg}" )
+ shell_out_compact!( "emerge", "--unmerge", "--color", "n", "--nospinner", "--quiet", options, pkg )
end
def purge_package(name, version)
diff --git a/lib/chef/provider/package/powershell.rb b/lib/chef/provider/package/powershell.rb
new file mode 100644
index 0000000000..3912dd23af
--- /dev/null
+++ b/lib/chef/provider/package/powershell.rb
@@ -0,0 +1,114 @@
+# Author:: Dheeraj Dubey(dheeraj.dubey@msystechnologies.com)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/provider/package"
+require "chef/resource/powershell_package"
+require "chef/mixin/powershell_out"
+
+class Chef
+ class Provider
+ class Package
+ class Powershell < Chef::Provider::Package
+ include Chef::Mixin::PowershellOut
+
+ provides :powershell_package, os: "windows"
+
+ def load_current_resource
+ @current_resource = Chef::Resource::PowershellPackage.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
+ current_resource.version(build_current_versions)
+ current_resource
+ end
+
+ def define_resource_requirements
+ super
+ if powershell_out("$PSVersionTable.PSVersion.Major").stdout.strip.to_i < 5
+ raise "Minimum installed Powershell Version required is 5"
+ end
+ requirements.assert(:install) do |a|
+ a.assertion { candidates_exist_for_all_uninstalled? }
+ a.failure_message(Chef::Exceptions::Package, "No candidate version available for #{packages_missing_candidates.join(', ')}")
+ a.whyrun("Assuming a repository that offers #{packages_missing_candidates.join(', ')} would have been configured")
+ end
+ end
+
+ def candidate_version
+ @candidate_version ||= build_candidate_versions
+ end
+
+ # Installs the package specified with the version passed else latest version will be installed
+ def install_package(names, versions)
+ names.each_with_index do |name, index|
+ powershell_out("Install-Package '#{name}' -Force -ForceBootstrap -RequiredVersion #{versions[index]}", timeout: new_resource.timeout)
+ end
+ end
+
+ # Removes the package for the version passed and if no version is passed, then all installed versions of the package are removed
+ def remove_package(names, versions)
+ names.each_with_index do |name, index|
+ if versions && !versions[index].nil?
+ powershell_out( "Uninstall-Package '#{name}' -Force -ForceBootstrap -RequiredVersion #{versions[index]}", timeout: new_resource.timeout)
+ else
+ version = "0"
+ until version.empty?
+ version = powershell_out( "(Uninstall-Package '#{name}' -Force -ForceBootstrap | select version | Format-Table -HideTableHeaders | Out-String).Trim()", timeout: new_resource.timeout).stdout.strip
+ unless version.empty?
+ Chef::Log.info("Removed package '#{name}' with version #{version}")
+ end
+ end
+ end
+ end
+ end
+
+ # Returns array of available available online
+ def build_candidate_versions
+ versions = []
+ new_resource.package_name.each_with_index do |name, index|
+ version = if new_resource.version && !new_resource.version[index].nil?
+ powershell_out("(Find-Package '#{name}' -RequiredVersion #{new_resource.version[index]} -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", timeout: new_resource.timeout).stdout.strip
+ else
+ powershell_out("(Find-Package '#{name}' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", timeout: new_resource.timeout).stdout.strip
+ end
+ if version.empty?
+ version = nil
+ end
+ versions.push(version)
+ end
+ versions
+ end
+
+ # Returns version array of installed version on the system
+ def build_current_versions
+ version_list = []
+ new_resource.package_name.each_with_index do |name, index|
+ version = if new_resource.version && !new_resource.version[index].nil?
+ powershell_out("(Get-Package -Name '#{name}' -RequiredVersion #{new_resource.version[index]} -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", timeout: new_resource.timeout).stdout.strip
+ else
+ powershell_out("(Get-Package -Name '#{name}' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", timeout: new_resource.timeout).stdout.strip
+ end
+ if version.empty?
+ version = nil
+ end
+ version_list.push(version)
+ end
+ version_list
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb
index 6ce0dd689f..1701886191 100644
--- a/lib/chef/provider/package/rpm.rb
+++ b/lib/chef/provider/package/rpm.rb
@@ -1,6 +1,6 @@
#
-# Author:: Joshua Timberman (<joshua@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Joshua Timberman (<joshua@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,17 +15,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'chef/mixin/get_source_from_package'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
+require "chef/mixin/get_source_from_package"
class Chef
class Provider
class Package
class Rpm < Chef::Provider::Package
- provides :rpm_package, os: [ "linux", "aix" ]
+ provides :rpm_package, os: %w{linux aix}
include Chef::Mixin::GetSourceFromPackage
@@ -34,13 +34,13 @@ class Chef
requirements.assert(:all_actions) do |a|
a.assertion { @package_source_exists }
- a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
- a.whyrun "Assuming package #{@new_resource.name} would have been made available."
+ a.failure_message Chef::Exceptions::Package, "Package #{new_resource.name} not found: #{new_resource.source}"
+ a.whyrun "Assuming package #{new_resource.name} would have been made available."
end
requirements.assert(:all_actions) do |a|
a.assertion { !@rpm_status.nil? && (@rpm_status.exitstatus == 0 || @rpm_status.exitstatus == 1) }
a.failure_message Chef::Exceptions::Package, "Unable to determine current version due to RPM failure. Detail: #{@rpm_status.inspect}"
- a.whyrun "Assuming current version would have been determined for package#{@new_resource.name}."
+ a.whyrun "Assuming current version would have been determined for package#{new_resource.name}."
end
end
@@ -48,64 +48,63 @@ class Chef
@package_source_provided = true
@package_source_exists = true
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
- @new_resource.version(nil)
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
- if @new_resource.source
- unless uri_scheme?(@new_resource.source) || ::File.exists?(@new_resource.source)
+ if new_resource.source
+ unless uri_scheme?(new_resource.source) || ::File.exist?(new_resource.source)
@package_source_exists = false
return
end
- Chef::Log.debug("#{@new_resource} checking rpm status")
- shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}").stdout.each_line do |line|
+ Chef::Log.debug("#{new_resource} checking rpm status")
+ shell_out_compact_timeout!("rpm", "-qp", "--queryformat", "%{NAME} %{VERSION}-%{RELEASE}\n", new_resource.source).stdout.each_line do |line|
case line
when /^(\S+)\s(\S+)$/
- @current_resource.package_name($1)
- @new_resource.version($2)
+ current_resource.package_name($1)
+ new_resource.version($2)
@candidate_version = $2
end
end
else
- if Array(@new_resource.action).include?(:install)
+ if Array(new_resource.action).include?(:install)
@package_source_exists = false
return
end
end
- Chef::Log.debug("#{@new_resource} checking install state")
- @rpm_status = shell_out_with_timeout("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@current_resource.package_name}")
+ Chef::Log.debug("#{new_resource} checking install state")
+ @rpm_status = shell_out_compact_timeout("rpm", "-q", "--queryformat", "%{NAME} %{VERSION}-%{RELEASE}\n", current_resource.package_name)
@rpm_status.stdout.each_line do |line|
case line
when /^(\S+)\s(\S+)$/
- Chef::Log.debug("#{@new_resource} current version is #{$2}")
- @current_resource.version($2)
+ Chef::Log.debug("#{new_resource} current version is #{$2}")
+ current_resource.version($2)
end
end
- @current_resource
+ current_resource
end
def install_package(name, version)
- unless @current_resource.version
- shell_out_with_timeout!( "rpm #{@new_resource.options} -i #{@new_resource.source}" )
- else
+ if current_resource.version
if allow_downgrade
- shell_out_with_timeout!( "rpm #{@new_resource.options} -U --oldpackage #{@new_resource.source}" )
+ shell_out_compact_timeout!("rpm", options, "-U", "--oldpackage", new_resource.source)
else
- shell_out_with_timeout!( "rpm #{@new_resource.options} -U #{@new_resource.source}" )
+ shell_out_compact_timeout!("rpm", options, "-U", new_resource.source)
end
+ else
+ shell_out_compact_timeout!("rpm", options, "-i", new_resource.source)
end
end
- alias_method :upgrade_package, :install_package
+ alias upgrade_package install_package
def remove_package(name, version)
if version
- shell_out_with_timeout!( "rpm #{@new_resource.options} -e #{name}-#{version}" )
+ shell_out_compact_timeout!("rpm", options, "-e", "#{name}-#{version}")
else
- shell_out_with_timeout!( "rpm #{@new_resource.options} -e #{name}" )
+ shell_out_compact_timeout!("rpm", options, "-e", name)
end
end
@@ -114,7 +113,7 @@ class Chef
def uri_scheme?(str)
scheme = URI.split(str).first
return false unless scheme
- %w(http https ftp file).include?(scheme.downcase)
+ %w{http https ftp file}.include?(scheme.downcase)
rescue URI::InvalidURIError
return false
end
diff --git a/lib/chef/provider/package/rubygems.rb b/lib/chef/provider/package/rubygems.rb
index 729f755b2a..1019b8d3fa 100644
--- a/lib/chef/provider/package/rubygems.rb
+++ b/lib/chef/provider/package/rubygems.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, 2010-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,25 +17,25 @@
# limitations under the License.
#
-require 'uri'
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'chef/mixin/get_source_from_package'
+require "uri"
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
+require "chef/mixin/get_source_from_package"
# Class methods on Gem are defined in rubygems
-require 'rubygems'
+require "rubygems"
# Ruby 1.9's gem_prelude can interact poorly with loading the full rubygems
# explicitly like this. Make sure rubygems/specification is always last in this
# list
-require 'rubygems/version'
-require 'rubygems/dependency'
-require 'rubygems/spec_fetcher'
-require 'rubygems/platform'
-require 'rubygems/package'
-require 'rubygems/dependency_installer'
-require 'rubygems/uninstaller'
-require 'rubygems/specification'
+require "rubygems/version"
+require "rubygems/dependency"
+require "rubygems/spec_fetcher"
+require "rubygems/platform"
+require "rubygems/package"
+require "rubygems/dependency_installer"
+require "rubygems/uninstaller"
+require "rubygems/specification"
class Chef
class Provider
@@ -47,7 +47,7 @@ class Chef
# alternate value and overwrite it with the defaults.
Gem.configuration
- DEFAULT_UNINSTALLER_OPTS = {:ignore => true, :executables => true}
+ DEFAULT_UNINSTALLER_OPTS = { ignore: true, executables: true }.freeze
##
# The paths where rubygems should search for installed gems.
@@ -86,7 +86,7 @@ class Chef
# === Returns
# [Gem::Specification] an array of Gem::Specification objects
def installed_versions(gem_dep)
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0')
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("1.8.0")
gem_specification.find_all_by_name(gem_dep.name, gem_dep.requirement)
else
gem_source_index.search(gem_dep)
@@ -115,7 +115,7 @@ class Chef
# Compatibility note: Rubygems 1.x uses Gem::Format, 2.0 moved this
# code into Gem::Package.
def spec_from_file(file)
- if defined?(Gem::Format) and Gem::Package.respond_to?(:open)
+ if defined?(Gem::Format) && Gem::Package.respond_to?(:open)
Gem::Format.from_file_by_path(file).spec
else
Gem::Package.new(file).spec
@@ -133,11 +133,11 @@ class Chef
def candidate_version_from_file(gem_dependency, source)
spec = spec_from_file(source)
if spec.satisfies_requirement?(gem_dependency)
- logger.debug {"#{@new_resource} found candidate gem version #{spec.version} from local gem package #{source}"}
+ logger.debug { "found candidate gem version #{spec.version} from local gem package #{source}" }
spec.version
else
# This is probably going to end badly...
- logger.warn { "#{@new_resource} gem package #{source} does not satisfy the requirements #{gem_dependency.to_s}" }
+ logger.warn { "gem package #{source} does not satisfy the requirements #{gem_dependency}" }
nil
end
end
@@ -159,27 +159,30 @@ class Chef
# Find the newest gem version available from Gem.sources that satisfies
# the constraints of +gem_dependency+
def find_newest_remote_version(gem_dependency, *sources)
- available_gems = dependency_installer.find_gems_with_sources(gem_dependency)
- spec, source = if available_gems.respond_to?(:last)
- # DependencyInstaller sorts the results such that the last one is
- # always the one it considers best.
- spec_with_source = available_gems.last
- spec_with_source && spec_with_source
- else
- # Rubygems 2.0 returns a Gem::Available set, which is a
- # collection of AvailableSet::Tuple structs
- available_gems.pick_best!
- best_gem = available_gems.set.first
- best_gem && [best_gem.spec, best_gem.source]
- end
+ spec, source =
+ if Chef::Config[:rubygems_cache_enabled]
+ # This code caches every gem on rubygems.org and uses lots of RAM
+ available_gems = dependency_installer.find_gems_with_sources(gem_dependency)
+ available_gems.pick_best!
+ best_gem = available_gems.set.first
+ best_gem && [best_gem.spec, best_gem.source]
+ else
+ # Use the API that 'gem install' calls which does not pull down the rubygems universe
+ begin
+ rs = dependency_installer.resolve_dependencies gem_dependency.name, gem_dependency.requirement
+ rs.specs.select { |s| s.name == gem_dependency.name }.first
+ rescue Gem::UnsatisfiableDependencyError
+ nil
+ end
+ end
version = spec && spec.version
if version
- logger.debug { "#{@new_resource} found gem #{spec.name} version #{version} for platform #{spec.platform} from #{source}" }
+ logger.debug { "found gem #{spec.name} version #{version} for platform #{spec.platform} from #{source}" }
version
else
source_list = sources.compact.empty? ? "[#{Gem.sources.to_a.join(', ')}]" : "[#{sources.join(', ')}]"
- logger.warn { "#{@new_resource} failed to find gem #{gem_dependency} from #{source_list}" }
+ logger.warn { "failed to find gem #{gem_dependency} from #{source_list}" }
nil
end
end
@@ -189,7 +192,7 @@ class Chef
# === Options
# :sources rubygems servers to use
# Other options are passed to Gem::DependencyInstaller.new
- def install(gem_dependency, options={})
+ def install(gem_dependency, options = {})
with_gem_sources(*options.delete(:sources)) do
with_correct_verbosity do
dependency_installer(options).install(gem_dependency)
@@ -203,7 +206,7 @@ class Chef
# Otherwise, all versions are uninstalled.
# === Options
# Options are passed to Gem::Uninstaller.new
- def uninstall(gem_name, gem_version=nil, opts={})
+ def uninstall(gem_name, gem_version = nil, opts = {})
gem_version ? opts[:version] = gem_version : opts[:all] = true
with_correct_verbosity do
uninstaller(gem_name, opts).uninstall
@@ -218,11 +221,11 @@ class Chef
yield
end
- def dependency_installer(opts={})
+ def dependency_installer(opts = {})
Gem::DependencyInstaller.new(opts)
end
- def uninstaller(gem_name, opts={})
+ def uninstaller(gem_name, opts = {})
Gem::Uninstaller.new(gem_name, DEFAULT_UNINSTALLER_OPTS.merge(opts))
end
@@ -282,13 +285,13 @@ class Chef
# shellout! is a fork/exec which won't work on windows
shell_style_paths = shell_out!("#{@gem_binary_location} env gempath").stdout
# on windows, the path separator is (usually? always?) semicolon
- paths = shell_style_paths.split(::File::PATH_SEPARATOR).map { |path| path.strip }
+ paths = shell_style_paths.split(::File::PATH_SEPARATOR).map(&:strip)
self.class.gempath_cache[@gem_binary_location] = paths
end
end
def gem_source_index
- @source_index ||= Gem::SourceIndex.from_gems_in(*gem_paths.map { |p| p + '/specifications' })
+ @source_index ||= Gem::SourceIndex.from_gems_in(*gem_paths.map { |p| p + "/specifications" })
end
def gem_specification
@@ -319,11 +322,11 @@ class Chef
self.class.platform_cache[@gem_binary_location]
else
gem_environment = shell_out!("#{@gem_binary_location} env").stdout
- if jruby = gem_environment[JRUBY_PLATFORM]
- self.class.platform_cache[@gem_binary_location] = ['ruby', Gem::Platform.new(jruby)]
- else
- self.class.platform_cache[@gem_binary_location] = Gem.platforms
- end
+ self.class.platform_cache[@gem_binary_location] = if jruby = gem_environment[JRUBY_PLATFORM]
+ ["ruby", Gem::Platform.new(jruby)]
+ else
+ Gem.platforms
+ end
end
end
@@ -358,21 +361,21 @@ class Chef
include Chef::Mixin::GetSourceFromPackage
- def initialize(new_resource, run_context=nil)
+ def initialize(new_resource, run_context = nil)
super
@cleanup_gem_env = true
if new_resource.gem_binary
- if new_resource.options && new_resource.options.kind_of?(Hash)
+ if new_resource.options && new_resource.options.is_a?(Hash)
msg = "options cannot be given as a hash when using an explicit gem_binary\n"
msg << "in #{new_resource} from #{new_resource.source_line}"
raise ArgumentError, msg
end
@gem_env = AlternateGemEnvironment.new(new_resource.gem_binary)
- Chef::Log.debug("#{@new_resource} using gem '#{new_resource.gem_binary}'")
- elsif is_omnibus? && (!@new_resource.instance_of? Chef::Resource::ChefGem)
+ Chef::Log.debug("#{new_resource} using gem '#{new_resource.gem_binary}'")
+ elsif is_omnibus? && (!new_resource.instance_of? Chef::Resource::ChefGem)
# Opscode Omnibus - The ruby that ships inside omnibus is only used for Chef
# Default to installing somewhere more functional
- if new_resource.options && new_resource.options.kind_of?(Hash)
+ if new_resource.options && new_resource.options.is_a?(Hash)
msg = [
"Gem options must be passed to gem_package as a string instead of a hash when",
"using this installation of Chef because it runs with its own packaged Ruby. A hash",
@@ -383,23 +386,23 @@ class Chef
raise ArgumentError, msg
end
gem_location = find_gem_by_path
- @new_resource.gem_binary gem_location
+ new_resource.gem_binary gem_location
@gem_env = AlternateGemEnvironment.new(gem_location)
- Chef::Log.debug("#{@new_resource} using gem '#{gem_location}'")
+ Chef::Log.debug("#{new_resource} using gem '#{gem_location}'")
else
@gem_env = CurrentGemEnvironment.new
@cleanup_gem_env = false
- Chef::Log.debug("#{@new_resource} using gem from running ruby environment")
+ Chef::Log.debug("#{new_resource} using gem from running ruby environment")
end
end
def is_omnibus?
- if RbConfig::CONFIG['bindir'] =~ %r!/(opscode|chef|chefdk)/embedded/bin!
- Chef::Log.debug("#{@new_resource} detected omnibus installation in #{RbConfig::CONFIG['bindir']}")
+ if RbConfig::CONFIG["bindir"] =~ %r{/(opscode|chef|chefdk)/embedded/bin}
+ Chef::Log.debug("#{new_resource} detected omnibus installation in #{RbConfig::CONFIG['bindir']}")
# Omnibus installs to a static path because of linking on unix, find it.
true
- elsif RbConfig::CONFIG['bindir'].sub(/^[\w]:/, '') == "/opscode/chef/embedded/bin"
- Chef::Log.debug("#{@new_resource} detected omnibus installation in #{RbConfig::CONFIG['bindir']}")
+ elsif RbConfig::CONFIG["bindir"].sub(/^[\w]:/, "") == "/opscode/chef/embedded/bin"
+ Chef::Log.debug("#{new_resource} detected omnibus installation in #{RbConfig::CONFIG['bindir']}")
# windows, with the drive letter removed
true
else
@@ -408,44 +411,50 @@ class Chef
end
def find_gem_by_path
- Chef::Log.debug("#{@new_resource} searching for 'gem' binary in path: #{ENV['PATH']}")
+ Chef::Log.debug("#{new_resource} searching for 'gem' binary in path: #{ENV['PATH']}")
separator = ::File::ALT_SEPARATOR ? ::File::ALT_SEPARATOR : ::File::SEPARATOR
- path_to_first_gem = ENV['PATH'].split(::File::PATH_SEPARATOR).select { |path| ::File.exists?(path + separator + "gem") }.first
+ path_to_first_gem = ENV["PATH"].split(::File::PATH_SEPARATOR).find { |path| ::File.exist?(path + separator + "gem") }
raise Chef::Exceptions::FileNotFound, "Unable to find 'gem' binary in path: #{ENV['PATH']}" if path_to_first_gem.nil?
path_to_first_gem + separator + "gem"
end
def gem_dependency
- Gem::Dependency.new(@new_resource.package_name, @new_resource.version)
+ Gem::Dependency.new(new_resource.package_name, new_resource.version)
end
def source_is_remote?
- return true if @new_resource.source.nil?
- scheme = URI.parse(@new_resource.source).scheme
+ return true if new_resource.source.nil?
+ scheme = URI.parse(new_resource.source).scheme
# URI.parse gets confused by MS Windows paths with forward slashes.
scheme = nil if scheme =~ /^[a-z]$/
%w{http https}.include?(scheme)
rescue URI::InvalidURIError
- Chef::Log.debug("#{@new_resource} failed to parse source '#{@new_resource.source}' as a URI, assuming a local path")
+ Chef::Log.debug("#{new_resource} failed to parse source '#{new_resource.source}' as a URI, assuming a local path")
false
end
def current_version
- #raise 'todo'
+ # rubygems 2.6.3 ensures that gem lists are sorted newest first
+ pos = if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("2.6.3")
+ :first
+ else
+ :last
+ end
+
# If one or more matching versions are installed, the newest of them
# is the current version
if !matching_installed_versions.empty?
- gemspec = matching_installed_versions.last
- logger.debug { "#{@new_resource} found installed gem #{gemspec.name} version #{gemspec.version} matching #{gem_dependency}"}
+ gemspec = matching_installed_versions.send(pos)
+ logger.debug { "#{new_resource} found installed gem #{gemspec.name} version #{gemspec.version} matching #{gem_dependency}" }
gemspec
- # If no version matching the requirements exists, the latest installed
- # version is the current version.
+ # If no version matching the requirements exists, the latest installed
+ # version is the current version.
elsif !all_installed_versions.empty?
- gemspec = all_installed_versions.last
- logger.debug { "#{@new_resource} newest installed version of gem #{gemspec.name} is #{gemspec.version}" }
+ gemspec = all_installed_versions.send(pos)
+ logger.debug { "#{new_resource} newest installed version of gem #{gemspec.name} is #{gemspec.version}" }
gemspec
else
- logger.debug { "#{@new_resource} no installed version found for #{gem_dependency.to_s}"}
+ logger.debug { "#{new_resource} no installed version found for #{gem_dependency}" }
nil
end
end
@@ -456,46 +465,42 @@ class Chef
def all_installed_versions
@all_installed_versions ||= begin
- @gem_env.installed_versions(Gem::Dependency.new(gem_dependency.name, '>= 0'))
- end
+ @gem_env.installed_versions(Gem::Dependency.new(gem_dependency.name, ">= 0"))
+ end
end
def gem_sources
- @new_resource.source ? Array(@new_resource.source) : nil
+ new_resource.source ? Array(new_resource.source) : nil
end
def load_current_resource
- @current_resource = Chef::Resource::Package::GemPackage.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
+ @current_resource = Chef::Resource::Package::GemPackage.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
if current_spec = current_version
- @current_resource.version(current_spec.version.to_s)
+ current_resource.version(current_spec.version.to_s)
end
- @current_resource
+ current_resource
end
def cleanup_after_converge
if @cleanup_gem_env
- logger.debug { "#{@new_resource} resetting gem environment to default" }
+ logger.debug { "#{new_resource} resetting gem environment to default" }
Gem.clear_paths
end
end
def candidate_version
@candidate_version ||= begin
- if target_version_already_installed?(@current_resource.version, @new_resource.version)
- nil
- elsif source_is_remote?
- @gem_env.candidate_version_from_remote(gem_dependency, *gem_sources).to_s
- else
- @gem_env.candidate_version_from_file(gem_dependency, @new_resource.source).to_s
- end
- end
+ if source_is_remote?
+ @gem_env.candidate_version_from_remote(gem_dependency, *gem_sources).to_s
+ else
+ @gem_env.candidate_version_from_file(gem_dependency, new_resource.source).to_s
+ end
+ end
end
- def target_version_already_installed?(current_version, new_version)
- return false unless current_version
- return false if new_version.nil?
-
+ def version_requirement_satisfied?(current_version, new_version)
+ return false unless current_version && new_version
Gem::Requirement.new(new_version).satisfied_by?(Gem::Version.new(current_version))
end
@@ -506,41 +511,41 @@ class Chef
# 2. shell out to `gem install` when a String of options is given
# 3. use gems API with options if a hash of options is given
def install_package(name, version)
- if source_is_remote? && @new_resource.gem_binary.nil?
- if @new_resource.options.nil?
- @gem_env.install(gem_dependency, :sources => gem_sources)
- elsif @new_resource.options.kind_of?(Hash)
- options = @new_resource.options
+ if source_is_remote? && new_resource.gem_binary.nil?
+ if new_resource.options.nil?
+ @gem_env.install(gem_dependency, sources: gem_sources)
+ elsif new_resource.options.is_a?(Hash)
+ options = new_resource.options
options[:sources] = gem_sources
@gem_env.install(gem_dependency, options)
else
install_via_gem_command(name, version)
end
- elsif @new_resource.gem_binary.nil?
- @gem_env.install(@new_resource.source)
+ elsif new_resource.gem_binary.nil?
+ @gem_env.install(new_resource.source)
else
- install_via_gem_command(name,version)
+ install_via_gem_command(name, version)
end
true
end
def gem_binary_path
- @new_resource.gem_binary || 'gem'
+ new_resource.gem_binary || "gem"
end
def install_via_gem_command(name, version)
- if @new_resource.source =~ /\.gem$/i
- name = @new_resource.source
- elsif @new_resource.clear_sources
- src = ' --clear-sources'
- src << (@new_resource.source && " --source=#{@new_resource.source}" || '')
+ if new_resource.source =~ /\.gem$/i
+ name = new_resource.source
+ elsif new_resource.clear_sources
+ src = " --clear-sources"
+ src << (new_resource.source && " --source=#{new_resource.source}" || "")
else
- src = @new_resource.source && " --source=#{@new_resource.source} --source=https://rubygems.org"
+ src = new_resource.source && " --source=#{new_resource.source} --source=#{Chef::Config[:rubygems_url]}"
end
- if !version.nil? && version.length > 0
- shell_out_with_timeout!("#{gem_binary_path} install #{name} -q --no-rdoc --no-ri -v \"#{version}\"#{src}#{opts}", :env=>nil)
+ if !version.nil? && !version.empty?
+ shell_out_with_timeout!("#{gem_binary_path} install #{name} -q --no-rdoc --no-ri -v \"#{version}\"#{src}#{opts}", env: nil)
else
- shell_out_with_timeout!("#{gem_binary_path} install \"#{name}\" -q --no-rdoc --no-ri #{src}#{opts}", :env=>nil)
+ shell_out_with_timeout!("#{gem_binary_path} install \"#{name}\" -q --no-rdoc --no-ri #{src}#{opts}", env: nil)
end
end
@@ -549,11 +554,11 @@ class Chef
end
def remove_package(name, version)
- if @new_resource.gem_binary.nil?
- if @new_resource.options.nil?
+ if new_resource.gem_binary.nil?
+ if new_resource.options.nil?
@gem_env.uninstall(name, version)
- elsif @new_resource.options.kind_of?(Hash)
- @gem_env.uninstall(name, version, @new_resource.options)
+ elsif new_resource.options.is_a?(Hash)
+ @gem_env.uninstall(name, version, new_resource.options)
else
uninstall_via_gem_command(name, version)
end
@@ -564,9 +569,9 @@ class Chef
def uninstall_via_gem_command(name, version)
if version
- shell_out_with_timeout!("#{gem_binary_path} uninstall #{name} -q -x -I -v \"#{version}\"#{opts}", :env=>nil)
+ shell_out_with_timeout!("#{gem_binary_path} uninstall #{name} -q -x -I -v \"#{version}\"#{opts}", env: nil)
else
- shell_out_with_timeout!("#{gem_binary_path} uninstall #{name} -q -x -I -a#{opts}", :env=>nil)
+ shell_out_with_timeout!("#{gem_binary_path} uninstall #{name} -q -x -I -a#{opts}", env: nil)
end
end
@@ -577,7 +582,7 @@ class Chef
private
def opts
- expand_options(@new_resource.options)
+ expand_options(new_resource.options)
end
end
diff --git a/lib/chef/provider/package/smartos.rb b/lib/chef/provider/package/smartos.rb
index 71b8a9b9e1..8e4368f7c1 100644
--- a/lib/chef/provider/package/smartos.rb
+++ b/lib/chef/provider/package/smartos.rb
@@ -3,7 +3,7 @@
# Bryan McLellan (btm@loftninjas.org)
# Matthew Landauer (matthew@openaustralia.org)
# Ben Rockwood (benr@joyent.com)
-# Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer
+# Copyright:: Copyright 2009-2016, Bryan McLellan, Matthew Landauer
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,9 +19,9 @@
# limitations under the License.
#
-require 'chef/provider/package'
-require 'chef/resource/package'
-require 'chef/mixin/get_source_from_package'
+require "chef/provider/package"
+require "chef/resource/package"
+require "chef/mixin/get_source_from_package"
class Chef
class Provider
@@ -33,27 +33,24 @@ class Chef
provides :smartos_package, os: "solaris2", platform_family: "smartos"
def load_current_resource
- Chef::Log.debug("#{@new_resource} loading current resource")
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
- @current_resource.version(nil)
- check_package_state(@new_resource.package_name)
- @current_resource # modified by check_package_state
+ Chef::Log.debug("#{new_resource} loading current resource")
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
+ check_package_state(new_resource.package_name)
+ current_resource # modified by check_package_state
end
def check_package_state(name)
- Chef::Log.debug("#{@new_resource} checking package #{name}")
+ Chef::Log.debug("#{new_resource} checking package #{name}")
version = nil
- info = shell_out_with_timeout!("/opt/local/sbin/pkg_info", "-E", "#{name}*", :env => nil, :returns => [0,1])
+ info = shell_out_compact_timeout!("/opt/local/sbin/pkg_info", "-E", "#{name}*", env: nil, returns: [0, 1])
if info.stdout
- version = info.stdout[/^#{@new_resource.package_name}-(.+)/, 1]
+ version = info.stdout[/^#{new_resource.package_name}-(.+)/, 1]
end
- if !version
- @current_resource.version(nil)
- else
- @current_resource.version(version)
+ if version
+ current_resource.version(version)
end
end
@@ -61,7 +58,7 @@ class Chef
return @candidate_version if @candidate_version
name = nil
version = nil
- pkg = shell_out_with_timeout!("/opt/local/bin/pkgin", "se", new_resource.package_name, :env => nil, :returns => [0,1])
+ pkg = shell_out_compact_timeout!("/opt/local/bin/pkgin", "se", new_resource.package_name, env: nil, returns: [0, 1])
pkg.stdout.each_line do |line|
case line
when /^#{new_resource.package_name}/
@@ -73,20 +70,20 @@ class Chef
end
def install_package(name, version)
- Chef::Log.debug("#{@new_resource} installing package #{name} version #{version}")
+ Chef::Log.debug("#{new_resource} installing package #{name} version #{version}")
package = "#{name}-#{version}"
- out = shell_out_with_timeout!("/opt/local/bin/pkgin", "-y", "install", package, :env => nil)
+ out = shell_out_compact_timeout!("/opt/local/bin/pkgin", "-y", "install", package, env: nil)
end
def upgrade_package(name, version)
- Chef::Log.debug("#{@new_resource} upgrading package #{name} version #{version}")
+ Chef::Log.debug("#{new_resource} upgrading package #{name} version #{version}")
install_package(name, version)
end
def remove_package(name, version)
- Chef::Log.debug("#{@new_resource} removing package #{name} version #{version}")
- package = "#{name}"
- out = shell_out_with_timeout!("/opt/local/bin/pkgin", "-y", "remove", package, :env => nil)
+ Chef::Log.debug("#{new_resource} removing package #{name} version #{version}")
+ package = name.to_s
+ out = shell_out_compact_timeout!("/opt/local/bin/pkgin", "-y", "remove", package, env: nil)
end
end
diff --git a/lib/chef/provider/package/solaris.rb b/lib/chef/provider/package/solaris.rb
index e62f37d27b..5537127310 100644
--- a/lib/chef/provider/package/solaris.rb
+++ b/lib/chef/provider/package/solaris.rb
@@ -1,6 +1,6 @@
#
# Author:: Toomas Pelberg (<toomasp@gmx.net>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,10 +15,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'chef/mixin/get_source_from_package'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
+require "chef/mixin/get_source_from_package"
class Chef
class Provider
@@ -28,51 +28,50 @@ class Chef
include Chef::Mixin::GetSourceFromPackage
provides :package, platform: "nexentacore"
- provides :package, platform: "solaris2", platform_version: '< 5.11'
+ provides :package, platform: "solaris2", platform_version: "< 5.11"
provides :solaris_package, os: "solaris2"
# def initialize(*args)
# super
- # @current_resource = Chef::Resource::Package.new(@new_resource.name)
+ # @current_resource = Chef::Resource::Package.new(new_resource.name)
# end
def define_resource_requirements
super
requirements.assert(:install) do |a|
- a.assertion { @new_resource.source }
- a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install"
+ a.assertion { new_resource.source }
+ a.failure_message Chef::Exceptions::Package, "Source for package #{new_resource.name} required for action install"
end
requirements.assert(:all_actions) do |a|
- a.assertion { !@new_resource.source || @package_source_found }
- a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
- a.whyrun "would assume #{@new_resource.source} would be have previously been made available"
+ a.assertion { !new_resource.source || @package_source_found }
+ a.failure_message Chef::Exceptions::Package, "Package #{new_resource.name} not found: #{new_resource.source}"
+ a.whyrun "would assume #{new_resource.source} would be have previously been made available"
end
end
def load_current_resource
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
- @new_resource.version(nil)
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
- if @new_resource.source
- @package_source_found = ::File.exists?(@new_resource.source)
+ if new_resource.source
+ @package_source_found = ::File.exist?(new_resource.source)
if @package_source_found
- Chef::Log.debug("#{@new_resource} checking pkg status")
- shell_out_with_timeout("pkginfo -l -d #{@new_resource.source} #{@new_resource.package_name}").stdout.each_line do |line|
+ Chef::Log.debug("#{new_resource} checking pkg status")
+ shell_out_compact_timeout("pkginfo", "-l", "-d", new_resource.source, new_resource.package_name).stdout.each_line do |line|
case line
when /VERSION:\s+(.+)/
- @new_resource.version($1)
+ new_resource.version($1)
end
end
end
end
- Chef::Log.debug("#{@new_resource} checking install state")
- status = shell_out_with_timeout("pkginfo -l #{@current_resource.package_name}")
+ Chef::Log.debug("#{new_resource} checking install state")
+ status = shell_out_compact_timeout("pkginfo", "-l", current_resource.package_name)
status.stdout.each_line do |line|
case line
when /VERSION:\s+(.+)/
- Chef::Log.debug("#{@new_resource} version #{$1} is already installed")
- @current_resource.version($1)
+ Chef::Log.debug("#{new_resource} version #{$1} is already installed")
+ current_resource.version($1)
end
end
@@ -80,58 +79,56 @@ class Chef
raise Chef::Exceptions::Package, "pkginfo failed - #{status.inspect}!"
end
- unless @current_resource.version.nil?
- @current_resource.version(nil)
- end
-
- @current_resource
+ current_resource
end
def candidate_version
return @candidate_version if @candidate_version
- status = shell_out_with_timeout("pkginfo -l -d #{@new_resource.source} #{new_resource.package_name}")
+ status = shell_out_compact_timeout("pkginfo", "-l", "-d", new_resource.source, new_resource.package_name)
status.stdout.each_line do |line|
case line
when /VERSION:\s+(.+)/
@candidate_version = $1
- @new_resource.version($1)
- Chef::Log.debug("#{@new_resource} setting install candidate version to #{@candidate_version}")
+ new_resource.version($1)
+ Chef::Log.debug("#{new_resource} setting install candidate version to #{@candidate_version}")
end
end
unless status.exitstatus == 0
- raise Chef::Exceptions::Package, "pkginfo -l -d #{@new_resource.source} - #{status.inspect}!"
+ raise Chef::Exceptions::Package, "pkginfo -l -d #{new_resource.source} - #{status.inspect}!"
end
@candidate_version
end
def install_package(name, version)
- Chef::Log.debug("#{@new_resource} package install options: #{@new_resource.options}")
- if @new_resource.options.nil?
- if ::File.directory?(@new_resource.source) # CHEF-4469
- command = "pkgadd -n -d #{@new_resource.source} #{@new_resource.package_name}"
- else
- command = "pkgadd -n -d #{@new_resource.source} all"
- end
- shell_out_with_timeout!(command)
- Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
+ Chef::Log.debug("#{new_resource} package install options: #{options}")
+ if options.nil?
+ command = if ::File.directory?(new_resource.source) # CHEF-4469
+ [ "pkgadd", "-n", "-d", new_resource.source, new_resource.package_name ]
+ else
+ [ "pkgadd", "-n", "-d", new_resource.source, "all" ]
+ end
+ shell_out_compact_timeout!(command)
+ Chef::Log.debug("#{new_resource} installed version #{new_resource.version} from: #{new_resource.source}")
else
- if ::File.directory?(@new_resource.source) # CHEF-4469
- command = "pkgadd -n#{expand_options(@new_resource.options)} -d #{@new_resource.source} #{@new_resource.package_name}"
- else
- command = "pkgadd -n#{expand_options(@new_resource.options)} -d #{@new_resource.source} all"
- end
- shell_out_with_timeout!(command)
- Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
+ command = if ::File.directory?(new_resource.source) # CHEF-4469
+ [ "pkgadd", "-n", options, "-d", new_resource.source, new_resource.package_name ]
+ else
+ [ "pkgadd", "-n", options, "-d", new_resource.source, "all" ]
+ end
+ shell_out_compact_timeout!(*command)
+ Chef::Log.debug("#{new_resource} installed version #{new_resource.version} from: #{new_resource.source}")
end
end
+ alias upgrade_package install_package
+
def remove_package(name, version)
- if @new_resource.options.nil?
- shell_out_with_timeout!( "pkgrm -n #{name}" )
- Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
+ if options.nil?
+ shell_out_compact_timeout!( "pkgrm", "-n", name )
+ Chef::Log.debug("#{new_resource} removed version #{new_resource.version}")
else
- shell_out_with_timeout!( "pkgrm -n#{expand_options(@new_resource.options)} #{name}" )
- Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
+ shell_out_compact_timeout!( "pkgrm", "-n", options, name )
+ Chef::Log.debug("#{new_resource} removed version #{new_resource.version}")
end
end
diff --git a/lib/chef/provider/package/windows.rb b/lib/chef/provider/package/windows.rb
index 7ff0b71807..ca9d1e813a 100644
--- a/lib/chef/provider/package/windows.rb
+++ b/lib/chef/provider/package/windows.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'chef/mixin/uris'
-require 'chef/resource/windows_package'
-require 'chef/provider/package'
-require 'chef/util/path_helper'
-require 'chef/mixin/checksum'
+require "chef/mixin/uris"
+require "chef/resource/windows_package"
+require "chef/provider/package"
+require "chef/util/path_helper"
+require "chef/mixin/checksum"
class Chef
class Provider
@@ -32,21 +32,24 @@ class Chef
provides :package, os: "windows"
provides :windows_package, os: "windows"
- # Depending on the installer, we may need to examine installer_type or
- # source attributes, or search for text strings in the installer file
- # binary to determine the installer type for the user. Since the file
- # must be on disk to do so, we have to make this choice in the provider.
- require 'chef/provider/package/windows/msi.rb'
+ require "chef/provider/package/windows/registry_uninstall_entry.rb"
+
+ def define_resource_requirements
+ requirements.assert(:install) do |a|
+ a.assertion { new_resource.source || msi? }
+ a.failure_message Chef::Exceptions::NoWindowsPackageSource, "Source for package #{new_resource.name} must be specified in the resource's source property for package to be installed because the package_name property is used to test for the package installation state for this package type."
+ end
+ end
# load_current_resource is run in Chef::Provider#run_action when not in whyrun_mode?
def load_current_resource
- @current_resource = Chef::Resource::WindowsPackage.new(@new_resource.name)
+ @current_resource = Chef::Resource::WindowsPackage.new(new_resource.name)
if downloadable_file_missing?
Chef::Log.debug("We do not know the version of #{new_resource.source} because the file is not downloaded")
current_resource.version(:unknown.to_s)
else
current_resource.version(package_provider.installed_version)
- new_resource.version(package_provider.package_version)
+ new_resource.version(package_provider.package_version) if package_provider.package_version
end
current_resource
@@ -56,24 +59,62 @@ class Chef
@package_provider ||= begin
case installer_type
when :msi
- Chef::Provider::Package::Windows::MSI.new(resource_for_provider)
+ Chef::Log.debug("#{new_resource} is MSI")
+ require "chef/provider/package/windows/msi"
+ Chef::Provider::Package::Windows::MSI.new(resource_for_provider, uninstall_registry_entries)
else
- raise "Unable to find a Chef::Provider::Package::Windows provider for installer_type '#{installer_type}'"
+ Chef::Log.debug("#{new_resource} is EXE with type '#{installer_type}'")
+ require "chef/provider/package/windows/exe"
+ Chef::Provider::Package::Windows::Exe.new(resource_for_provider, installer_type, uninstall_registry_entries)
end
end
end
def installer_type
+ # Depending on the installer, we may need to examine installer_type or
+ # source attributes, or search for text strings in the installer file
+ # binary to determine the installer type for the user. Since the file
+ # must be on disk to do so, we have to make this choice in the provider.
@installer_type ||= begin
- if @new_resource.installer_type
- @new_resource.installer_type
+ return :msi if msi?
+
+ if new_resource.installer_type
+ new_resource.installer_type
+ elsif source_location.nil?
+ inferred_registry_type
else
- file_extension = ::File.basename(@new_resource.source).split(".").last.downcase
+ basename = ::File.basename(source_location)
+ file_extension = basename.split(".").last.downcase
+
+ # search the binary file for installer type
+ ::Kernel.open(::File.expand_path(source_location), "rb") do |io|
+ filesize = io.size
+ bufsize = 4096 # read 4K buffers
+ overlap = 16 # bytes to overlap between buffer reads
+
+ until io.eof
+ contents = io.read(bufsize)
+
+ case contents
+ when /inno/i # Inno Setup
+ return :inno
+ when /wise/i # Wise InstallMaster
+ return :wise
+ when /nullsoft/i # Nullsoft Scriptable Install System
+ return :nsis
+ end
+
+ if io.tell < filesize
+ io.seek(io.tell - overlap)
+ end
+ end
- if file_extension == "msi"
- :msi
- else
- raise ArgumentError, "Installer type for Windows Package '#{@new_resource.name}' not specified and cannot be determined from file extension '#{file_extension}'"
+ # if file is named 'setup.exe' assume installshield
+ if basename == "setup.exe"
+ :installshield
+ else
+ raise Chef::Exceptions::CannotDetermineWindowsInstallerType, "Installer type for Windows Package '#{new_resource.name}' not specified and cannot be determined from file extension '#{file_extension}'"
+ end
end
end
end
@@ -93,11 +134,11 @@ class Chef
# Chef::Provider::Package action_install + action_remove call install_package + remove_package
# Pass those calls to the correct sub-provider
def install_package(name, version)
- package_provider.install_package(name, version)
+ package_provider.install_package
end
def remove_package(name, version)
- package_provider.remove_package(name, version)
+ package_provider.remove_package
end
# @return [Array] new_version(s) as an array
@@ -106,15 +147,62 @@ class Chef
[new_resource.version]
end
+ # @return [String] candidate_version
+ def candidate_version
+ @candidate_version ||= (new_resource.version || "latest")
+ end
+
+ # @return [Array] current_version(s) as an array
+ # this package provider does not support package arrays
+ # However, There may be multiple versions for a single
+ # package so the first element may be a nested array
+ def current_version_array
+ [ current_resource.version ]
+ end
+
+ # @param current_version<String> one or more versions currently installed
+ # @param new_version<String> version of the new resource
+ #
+ # @return [Boolean] true if new_version is equal to or included in current_version
+ def target_version_already_installed?(current_version, new_version)
+ Chef::Log.debug("Checking if #{new_resource} version '#{new_version}' is already installed. #{current_version} is currently installed")
+ if current_version.is_a?(Array)
+ current_version.include?(new_version)
+ else
+ new_version == current_version
+ end
+ end
+
+ def have_any_matching_version?
+ target_version_already_installed?(current_resource.version, new_resource.version)
+ end
+
private
+ def uninstall_registry_entries
+ @uninstall_registry_entries ||= Chef::Provider::Package::Windows::RegistryUninstallEntry.find_entries(new_resource.package_name)
+ end
+
+ def inferred_registry_type
+ @inferred_registry_type ||= begin
+ uninstall_registry_entries.each do |entry|
+ return :inno if entry.key.end_with?("_is1")
+ return :msi if entry.uninstall_string.downcase.start_with?("msiexec.exe ")
+ return :nsis if entry.uninstall_string.downcase.end_with?("uninst.exe\"")
+ end
+ nil
+ end
+ end
+
def downloadable_file_missing?
- uri_scheme?(new_resource.source) && !::File.exists?(source_location)
+ !new_resource.source.nil? && uri_scheme?(new_resource.source) && !::File.exist?(source_location)
end
def resource_for_provider
@resource_for_provider = Chef::Resource::WindowsPackage.new(new_resource.name).tap do |r|
- r.source(Chef::Util::PathHelper.validate_path(source_location))
+ r.source(Chef::Util::PathHelper.validate_path(source_location)) unless source_location.nil?
+ r.cookbook_name = new_resource.cookbook_name
+ r.version(new_resource.version)
r.timeout(new_resource.timeout)
r.returns(new_resource.returns)
r.options(new_resource.options)
@@ -123,17 +211,18 @@ class Chef
def download_source_file
source_resource.run_action(:create)
- Chef::Log.debug("#{@new_resource} fetched source file to #{source_resource.path}")
+ Chef::Log.debug("#{new_resource} fetched source file to #{source_resource.path}")
end
def source_resource
@source_resource ||= Chef::Resource::RemoteFile.new(default_download_cache_path, run_context).tap do |r|
r.source(new_resource.source)
+ r.cookbook_name = new_resource.cookbook_name
r.checksum(new_resource.checksum)
r.backup(false)
if new_resource.remote_file_attributes
- new_resource.remote_file_attributes.each do |(k,v)|
+ new_resource.remote_file_attributes.each do |(k, v)|
r.send(k.to_sym, v)
end
end
@@ -148,22 +237,34 @@ class Chef
end
def source_location
- if uri_scheme?(new_resource.source)
+ if new_resource.source.nil?
+ nil
+ elsif uri_scheme?(new_resource.source)
source_resource.path
else
- Chef::Util::PathHelper.cleanpath(new_resource.source)
+ new_source = Chef::Util::PathHelper.cleanpath(new_resource.source)
+ ::File.exist?(new_source) ? new_source : nil
end
end
def validate_content!
if new_resource.checksum
source_checksum = checksum(source_location)
- if new_resource.checksum != source_checksum
+ if new_resource.checksum.downcase != source_checksum
raise Chef::Exceptions::ChecksumMismatch.new(short_cksum(new_resource.checksum), short_cksum(source_checksum))
end
end
end
+ def msi?
+ return true if new_resource.installer_type == :msi
+
+ if source_location.nil?
+ inferred_registry_type == :msi
+ else
+ ::File.extname(source_location).casecmp(".msi") == 0
+ end
+ end
end
end
end
diff --git a/lib/chef/provider/package/windows/exe.rb b/lib/chef/provider/package/windows/exe.rb
new file mode 100644
index 0000000000..0baea6bccd
--- /dev/null
+++ b/lib/chef/provider/package/windows/exe.rb
@@ -0,0 +1,115 @@
+#
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Author:: Matt Wrock <matt@mattwrock.com>
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/mixin/shell_out"
+
+class Chef
+ class Provider
+ class Package
+ class Windows
+ class Exe
+ include Chef::Mixin::ShellOut
+
+ def initialize(resource, installer_type, uninstall_entries)
+ @new_resource = resource
+ @installer_type = installer_type
+ @uninstall_entries = uninstall_entries
+ end
+
+ attr_reader :new_resource
+ attr_reader :installer_type
+ attr_reader :uninstall_entries
+
+ # From Chef::Provider::Package
+ def expand_options(options)
+ options ? " #{options}" : ""
+ end
+
+ # Returns a version if the package is installed or nil if it is not.
+ def installed_version
+ Chef::Log.debug("#{new_resource} checking package version")
+ current_installed_version
+ end
+
+ def package_version
+ new_resource.version
+ end
+
+ def install_package
+ Chef::Log.debug("#{new_resource} installing #{new_resource.installer_type} package '#{new_resource.source}'")
+ shell_out!(
+ [
+ "start",
+ "\"\"",
+ "/wait",
+ "\"#{new_resource.source}\"",
+ unattended_flags,
+ expand_options(new_resource.options),
+ "& exit %%%%ERRORLEVEL%%%%",
+ ].join(" "), timeout: new_resource.timeout, returns: new_resource.returns
+ )
+ end
+
+ def remove_package
+ uninstall_version = new_resource.version || current_installed_version
+ uninstall_entries.select { |entry| [uninstall_version].flatten.include?(entry.display_version) }
+ .map(&:uninstall_string).uniq.each do |uninstall_string|
+ Chef::Log.debug("Registry provided uninstall string for #{new_resource} is '#{uninstall_string}'")
+ shell_out!(uninstall_command(uninstall_string), timeout: new_resource.timeout, returns: new_resource.returns)
+ end
+ end
+
+ private
+
+ def uninstall_command(uninstall_string)
+ uninstall_string = "\"#{uninstall_string}\"" if ::File.exist?(uninstall_string)
+ uninstall_string = [
+ uninstall_string,
+ expand_options(new_resource.options),
+ " ",
+ unattended_flags,
+ ].join
+ %{start "" /wait #{uninstall_string} & exit %%%%ERRORLEVEL%%%%}
+ end
+
+ def current_installed_version
+ @current_installed_version ||=
+ if uninstall_entries.count != 0
+ uninstall_entries.map(&:display_version).uniq
+ end
+ end
+
+ # http://unattended.sourceforge.net/installers.php
+ def unattended_flags
+ case installer_type
+ when :installshield
+ "/s /sms"
+ when :nsis
+ "/S /NCRC"
+ when :inno
+ "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART"
+ when :wise
+ "/s"
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/windows/msi.rb b/lib/chef/provider/package/windows/msi.rb
index 7fdbbcff35..7e6048ce49 100644
--- a/lib/chef/provider/package/windows/msi.rb
+++ b/lib/chef/provider/package/windows/msi.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-# TODO: Allow @new_resource.source to be a Product Code as a GUID for uninstall / network install
+# TODO: Allow new_resource.source to be a Product Code as a GUID for uninstall / network install
-require 'chef/win32/api/installer' if (RUBY_PLATFORM =~ /mswin|mingw32|windows/) && Chef::Platform.supports_msi?
-require 'chef/mixin/shell_out'
+require "chef/win32/api/installer" if (RUBY_PLATFORM =~ /mswin|mingw32|windows/) && Chef::Platform.supports_msi?
+require "chef/mixin/shell_out"
class Chef
class Provider
@@ -29,10 +29,14 @@ class Chef
include Chef::ReservedNames::Win32::API::Installer if (RUBY_PLATFORM =~ /mswin|mingw32|windows/) && Chef::Platform.supports_msi?
include Chef::Mixin::ShellOut
- def initialize(resource)
+ def initialize(resource, uninstall_entries)
@new_resource = resource
+ @uninstall_entries = uninstall_entries
end
+ attr_reader :new_resource
+ attr_reader :uninstall_entries
+
# From Chef::Provider::Package
def expand_options(options)
options ? " #{options}" : ""
@@ -40,27 +44,48 @@ class Chef
# Returns a version if the package is installed or nil if it is not.
def installed_version
- Chef::Log.debug("#{@new_resource} getting product code for package at #{@new_resource.source}")
- product_code = get_product_property(@new_resource.source, "ProductCode")
- Chef::Log.debug("#{@new_resource} checking package status and version for #{product_code}")
- get_installed_version(product_code)
+ if !new_resource.source.nil? && ::File.exist?(new_resource.source)
+ Chef::Log.debug("#{new_resource} getting product code for package at #{new_resource.source}")
+ product_code = get_product_property(new_resource.source, "ProductCode")
+ Chef::Log.debug("#{new_resource} checking package status and version for #{product_code}")
+ get_installed_version(product_code)
+ else
+ if uninstall_entries.count != 0
+ uninstall_entries.map(&:display_version).uniq
+ end
+ end
end
def package_version
- Chef::Log.debug("#{@new_resource} getting product version for package at #{@new_resource.source}")
- get_product_property(@new_resource.source, "ProductVersion")
+ return new_resource.version if new_resource.version
+ if !new_resource.source.nil? && ::File.exist?(new_resource.source)
+ Chef::Log.debug("#{new_resource} getting product version for package at #{new_resource.source}")
+ get_product_property(new_resource.source, "ProductVersion")
+ end
end
- def install_package(name, version)
+ def install_package
# We could use MsiConfigureProduct here, but we'll start off with msiexec
- Chef::Log.debug("#{@new_resource} installing MSI package '#{@new_resource.source}'")
- shell_out!("msiexec /qn /i \"#{@new_resource.source}\" #{expand_options(@new_resource.options)}", {:timeout => @new_resource.timeout, :returns => @new_resource.returns})
+ Chef::Log.debug("#{new_resource} installing MSI package '#{new_resource.source}'")
+ shell_out!("msiexec /qn /i \"#{new_resource.source}\" #{expand_options(new_resource.options)}", timeout: new_resource.timeout, returns: new_resource.returns)
end
- def remove_package(name, version)
+ def remove_package
# We could use MsiConfigureProduct here, but we'll start off with msiexec
- Chef::Log.debug("#{@new_resource} removing MSI package '#{@new_resource.source}'")
- shell_out!("msiexec /qn /x \"#{@new_resource.source}\" #{expand_options(@new_resource.options)}", {:timeout => @new_resource.timeout, :returns => @new_resource.returns})
+ if !new_resource.source.nil? && ::File.exist?(new_resource.source)
+ Chef::Log.debug("#{new_resource} removing MSI package '#{new_resource.source}'")
+ shell_out!("msiexec /qn /x \"#{new_resource.source}\" #{expand_options(new_resource.options)}", timeout: new_resource.timeout, returns: new_resource.returns)
+ else
+ uninstall_version = new_resource.version || installed_version
+ uninstall_entries.select { |entry| [uninstall_version].flatten.include?(entry.display_version) }
+ .map(&:uninstall_string).uniq.each do |uninstall_string|
+ uninstall_string = "msiexec /x #{uninstall_string.match(/{.*}/)}"
+ uninstall_string += expand_options(new_resource.options)
+ uninstall_string += " /q" unless uninstall_string.downcase =~ / \/q/
+ Chef::Log.debug("#{new_resource} removing MSI package version using '#{uninstall_string}'")
+ shell_out!(uninstall_string, timeout: new_resource.timeout, returns: new_resource.returns)
+ end
+ end
end
end
end
diff --git a/lib/chef/provider/package/windows/registry_uninstall_entry.rb b/lib/chef/provider/package/windows/registry_uninstall_entry.rb
new file mode 100644
index 0000000000..a693558883
--- /dev/null
+++ b/lib/chef/provider/package/windows/registry_uninstall_entry.rb
@@ -0,0 +1,87 @@
+#
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Author:: Matt Wrock <matt@mattwrock.com>
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "win32/registry" if RUBY_PLATFORM =~ /mswin|mingw32|windows/
+
+class Chef
+ class Provider
+ class Package
+ class Windows
+ class RegistryUninstallEntry
+
+ def self.find_entries(package_name)
+ Chef::Log.debug("Finding uninstall entries for #{package_name}")
+ entries = []
+ [
+ [::Win32::Registry::HKEY_LOCAL_MACHINE, (::Win32::Registry::Constants::KEY_READ | 0x0100)],
+ [::Win32::Registry::HKEY_LOCAL_MACHINE, (::Win32::Registry::Constants::KEY_READ | 0x0200)],
+ [::Win32::Registry::HKEY_CURRENT_USER],
+ ].each do |hkey|
+ desired = hkey.length > 1 ? hkey[1] : ::Win32::Registry::Constants::KEY_READ
+ begin
+ ::Win32::Registry.open(hkey[0], UNINSTALL_SUBKEY, desired) do |reg|
+ reg.each_key do |key, _wtime|
+ begin
+ entry = reg.open(key, desired)
+ display_name = read_registry_property(entry, "DisplayName")
+ if display_name == package_name
+ entries.push(RegistryUninstallEntry.new(hkey, key, entry))
+ end
+ rescue ::Win32::Registry::Error => ex
+ Chef::Log.debug("Registry error opening key '#{key}' on node #{desired}: #{ex}")
+ end
+ end
+ end
+ rescue ::Win32::Registry::Error => ex
+ Chef::Log.debug("Registry error opening hive '#{hkey[0]}' :: #{desired}: #{ex}")
+ end
+ end
+ entries
+ end
+
+ def self.read_registry_property(data, property)
+ data[property]
+ rescue ::Win32::Registry::Error => ex
+ Chef::Log.debug("Failure to read property '#{property}'")
+ nil
+ end
+
+ def initialize(hive, key, registry_data)
+ Chef::Log.debug("Creating uninstall entry for #{hive}::#{key}")
+ @hive = hive
+ @key = key
+ @data = registry_data
+ @display_name = RegistryUninstallEntry.read_registry_property(registry_data, "DisplayName")
+ @display_version = RegistryUninstallEntry.read_registry_property(registry_data, "DisplayVersion")
+ @uninstall_string = RegistryUninstallEntry.read_registry_property(registry_data, "UninstallString")
+ end
+
+ attr_reader :hive
+ attr_reader :key
+ attr_reader :display_name
+ attr_reader :display_version
+ attr_reader :uninstall_string
+ attr_reader :data
+
+ UNINSTALL_SUBKEY = 'Software\Microsoft\Windows\CurrentVersion\Uninstall'.freeze
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb
index aff8dc9326..d37aa1fb73 100644
--- a/lib/chef/provider/package/yum.rb
+++ b/lib/chef/provider/package/yum.rb
@@ -1,6 +1,6 @@
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2017, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,1030 +16,257 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/provider/package'
-require 'chef/mixin/which'
-require 'chef/resource/package'
-require 'singleton'
-require 'chef/mixin/get_source_from_package'
+require "chef/config"
+require "chef/provider/package"
+require "chef/resource/yum_package"
+require "chef/mixin/get_source_from_package"
+require "chef/provider/package/yum/rpm_utils"
+require "chef/provider/package/yum/yum_cache"
class Chef
class Provider
class Package
class Yum < Chef::Provider::Package
+ include Chef::Mixin::GetSourceFromPackage
- provides :package, platform_family: %w(rhel fedora)
+ provides :package, platform_family: %w{rhel fedora}
provides :yum_package, os: "linux"
- class RPMUtils
- class << self
-
- # RPM::Version version_parse equivalent
- def version_parse(evr)
- return if evr.nil?
-
- epoch = nil
- # assume this is a version
- version = evr
- release = nil
-
- lead = 0
- tail = evr.size
-
- if evr =~ %r{^([\d]+):}
- epoch = $1.to_i
- lead = $1.length + 1
- elsif evr[0].ord == ":".ord
- epoch = 0
- lead = 1
- end
-
- if evr =~ %r{:?.*-(.*)$}
- release = $1
- tail = evr.length - release.length - lead - 1
-
- if release.empty?
- release = nil
- end
- end
-
- version = evr[lead,tail]
- if version.empty?
- version = nil
- end
-
- [ epoch, version, release ]
- end
-
- # verify
- def isalnum(x)
- isalpha(x) or isdigit(x)
- end
-
- def isalpha(x)
- v = x.ord
- (v >= 65 and v <= 90) or (v >= 97 and v <= 122)
- end
-
- def isdigit(x)
- v = x.ord
- v >= 48 and v <= 57
- end
-
- # based on the reference spec in lib/rpmvercmp.c in rpm 4.9.0
- def rpmvercmp(x, y)
- # easy! :)
- return 0 if x == y
-
- if x.nil?
- x = ""
- end
-
- if y.nil?
- y = ""
- end
-
- # not so easy :(
- #
- # takes 2 strings like
- #
- # x = "1.20.b18.el5"
- # y = "1.20.b17.el5"
- #
- # breaks into purely alpha and numeric segments and compares them using
- # some rules
- #
- # * 10 > 1
- # * 1 > a
- # * z > a
- # * Z > A
- # * z > Z
- # * leading zeros are ignored
- # * separators (periods, commas) are ignored
- # * "1.20.b18.el5.extrastuff" > "1.20.b18.el5"
-
- x_pos = 0 # overall string element reference position
- x_pos_max = x.length - 1 # number of elements in string, starting from 0
- x_seg_pos = 0 # segment string element reference position
- x_comp = nil # segment to compare
-
- y_pos = 0
- y_seg_pos = 0
- y_pos_max = y.length - 1
- y_comp = nil
-
- while (x_pos <= x_pos_max and y_pos <= y_pos_max)
- # first we skip over anything non alphanumeric
- while (x_pos <= x_pos_max) and (isalnum(x[x_pos]) == false)
- x_pos += 1 # +1 over pos_max if end of string
- end
- while (y_pos <= y_pos_max) and (isalnum(y[y_pos]) == false)
- y_pos += 1
- end
-
- # if we hit the end of either we are done matching segments
- if (x_pos == x_pos_max + 1) or (y_pos == y_pos_max + 1)
- break
- end
-
- # we are now at the start of a alpha or numeric segment
- x_seg_pos = x_pos
- y_seg_pos = y_pos
+ # Multipackage API
+ allow_nils
+ use_multipackage_api
+ use_package_name_for_source
- # grab segment so we can compare them
- if isdigit(x[x_seg_pos].ord)
- x_seg_is_num = true
-
- # already know it's a digit
- x_seg_pos += 1
-
- # gather up our digits
- while (x_seg_pos <= x_pos_max) and isdigit(x[x_seg_pos])
- x_seg_pos += 1
- end
- # copy the segment but not the unmatched character that x_seg_pos will
- # refer to
- x_comp = x[x_pos,x_seg_pos - x_pos]
-
- while (y_seg_pos <= y_pos_max) and isdigit(y[y_seg_pos])
- y_seg_pos += 1
- end
- y_comp = y[y_pos,y_seg_pos - y_pos]
- else
- # we are comparing strings
- x_seg_is_num = false
-
- while (x_seg_pos <= x_pos_max) and isalpha(x[x_seg_pos])
- x_seg_pos += 1
- end
- x_comp = x[x_pos,x_seg_pos - x_pos]
-
- while (y_seg_pos <= y_pos_max) and isalpha(y[y_seg_pos])
- y_seg_pos += 1
- end
- y_comp = y[y_pos,y_seg_pos - y_pos]
- end
-
- # if y_seg_pos didn't advance in the above loop it means the segments are
- # different types
- if y_pos == y_seg_pos
- # numbers always win over letters
- return x_seg_is_num ? 1 : -1
- end
-
- # move the ball forward before we mess with the segments
- x_pos += x_comp.length # +1 over pos_max if end of string
- y_pos += y_comp.length
-
- # we are comparing numbers - simply convert them
- if x_seg_is_num
- x_comp = x_comp.to_i
- y_comp = y_comp.to_i
- end
-
- # compares ints or strings
- # don't return if equal - try the next segment
- if x_comp > y_comp
- return 1
- elsif x_comp < y_comp
- return -1
- end
-
- # if we've reached here than the segments are the same - try again
- end
-
- # we must have reached the end of one or both of the strings and they
- # matched up until this point
-
- # segments matched completely but the segment separators were different -
- # rpm reference code treats these as equal.
- if (x_pos == x_pos_max + 1) and (y_pos == y_pos_max + 1)
- return 0
- end
-
- # the most unprocessed characters left wins
- if (x_pos_max - x_pos) > (y_pos_max - y_pos)
- return 1
- else
- return -1
- end
- end
-
- end # self
- end # RPMUtils
-
- class RPMVersion
- include Comparable
-
- def initialize(*args)
- if args.size == 1
- @e, @v, @r = RPMUtils.version_parse(args[0])
- elsif args.size == 3
- @e = args[0].to_i
- @v = args[1]
- @r = args[2]
- else
- raise ArgumentError, "Expecting either 'epoch-version-release' or 'epoch, " +
- "version, release'"
- end
- end
- attr_reader :e, :v, :r
- alias :epoch :e
- alias :version :v
- alias :release :r
-
- def self.parse(*args)
- self.new(*args)
- end
-
- def <=>(y)
- compare_versions(y)
- end
-
- def compare(y)
- compare_versions(y, false)
- end
-
- def partial_compare(y)
- compare_versions(y, true)
- end
-
- # RPM::Version rpm_version_to_s equivalent
- def to_s
- if @r.nil?
- @v
- else
- "#{@v}-#{@r}"
- end
- end
-
- def evr
- "#{@e}:#{@v}-#{@r}"
- end
-
- private
-
- # Rough RPM::Version rpm_version_cmp equivalent - except much slower :)
- #
- # partial lets epoch and version segment equality be good enough to return equal, eg:
- #
- # 2:1.2-1 == 2:1.2
- # 2:1.2-1 == 2:
- #
- def compare_versions(y, partial=false)
- x = self
-
- # compare epoch
- if (x.e.nil? == false and x.e > 0) and y.e.nil?
- return 1
- elsif x.e.nil? and (y.e.nil? == false and y.e > 0)
- return -1
- elsif x.e.nil? == false and y.e.nil? == false
- if x.e < y.e
- return -1
- elsif x.e > y.e
- return 1
- end
- end
-
- # compare version
- if partial and (x.v.nil? or y.v.nil?)
- return 0
- elsif x.v.nil? == false and y.v.nil?
- return 1
- elsif x.v.nil? and y.v.nil? == false
- return -1
- elsif x.v.nil? == false and y.v.nil? == false
- cmp = RPMUtils.rpmvercmp(x.v, y.v)
- return cmp if cmp != 0
- end
-
- # compare release
- if partial and (x.r.nil? or y.r.nil?)
- return 0
- elsif x.r.nil? == false and y.r.nil?
- return 1
- elsif x.r.nil? and y.r.nil? == false
- return -1
- elsif x.r.nil? == false and y.r.nil? == false
- cmp = RPMUtils.rpmvercmp(x.r, y.r)
- return cmp
- end
+ # Overload the Package provider to keep track of the YumCache
+ def initialize(new_resource, run_context)
+ super
- return 0
- end
+ @yum = YumCache.instance
+ @yum.yum_binary = yum_binary
end
- class RPMPackage
- include Comparable
-
- def initialize(*args)
- if args.size == 4
- @n = args[0]
- @version = RPMVersion.new(args[1])
- @a = args[2]
- @provides = args[3]
- elsif args.size == 6
- @n = args[0]
- e = args[1].to_i
- v = args[2]
- r = args[3]
- @version = RPMVersion.new(e,v,r)
- @a = args[4]
- @provides = args[5]
- else
- raise ArgumentError, "Expecting either 'name, epoch-version-release, arch, provides' " +
- "or 'name, epoch, version, release, arch, provides'"
- end
-
- # We always have one, ourselves!
- if @provides.empty?
- @provides = [ RPMProvide.new(@n, @version.evr, :==) ]
- end
- end
- attr_reader :n, :a, :version, :provides
- alias :name :n
- alias :arch :a
-
- def <=>(y)
- compare(y)
- end
-
- def compare(y)
- x = self
-
- # easy! :)
- return 0 if x.nevra == y.nevra
-
- # compare name
- if x.n.nil? == false and y.n.nil?
- return 1
- elsif x.n.nil? and y.n.nil? == false
- return -1
- elsif x.n.nil? == false and y.n.nil? == false
- if x.n < y.n
- return -1
- elsif x.n > y.n
- return 1
- end
- end
-
- # compare version
- if x.version > y.version
- return 1
- elsif x.version < y.version
- return -1
- end
-
- # compare arch
- if x.a.nil? == false and y.a.nil?
- return 1
- elsif x.a.nil? and y.a.nil? == false
- return -1
- elsif x.a.nil? == false and y.a.nil? == false
- if x.a < y.a
- return -1
- elsif x.a > y.a
- return 1
- end
- end
-
- return 0
- end
+ # @see Chef::Provider::Package#check_resource_semantics!
+ def check_resource_semantics!
+ super
- def to_s
- nevra
+ if !new_resource.version.nil? && package_name_array.length != new_version_array.length
+ raise Chef::Exceptions::InvalidResourceSpecification, "Please provide a version for each package. Use `nil` for default version."
end
- def nevra
- "#{@n}-#{@version.evr}.#{@a}"
+ if !new_resource.arch.nil? && package_name_array.length != safe_arch_array.length
+ raise Chef::Exceptions::InvalidResourceSpecification, "Please provide an architecture for each package. Use `nil` for default architecture."
end
end
- # Simple implementation from rpm and ruby-rpm reference code
- class RPMDependency
- def initialize(*args)
- if args.size == 3
- @name = args[0]
- @version = RPMVersion.new(args[1])
- # Our requirement to other dependencies
- @flag = args[2] || :==
- elsif args.size == 5
- @name = args[0]
- e = args[1].to_i
- v = args[2]
- r = args[3]
- @version = RPMVersion.new(e,v,r)
- @flag = args[4] || :==
- else
- raise ArgumentError, "Expecting either 'name, epoch-version-release, flag' or " +
- "'name, epoch, version, release, flag'"
- end
- end
- attr_reader :name, :version, :flag
-
- # Parses 2 forms:
- #
- # "mtr >= 2:0.71-3.0"
- # "mta"
- def self.parse(string)
- if string =~ %r{^(\S+)\s+(>|>=|=|==|<=|<)\s+(\S+)$}
- name = $1
- if $2 == "="
- flag = :==
- else
- flag = :"#{$2}"
- end
- version = $3
+ # @see Chef::Provider#define_resource_requirements
+ def define_resource_requirements
+ super
- return self.new(name, version, flag)
- else
- name = string
- return self.new(name, nil, nil)
- end
+ # Ensure that the source file (if specified) is present on the file system
+ requirements.assert(:install, :upgrade, :remove, :purge) do |a|
+ a.assertion { !new_resource.source || ::File.exist?(new_resource.source) }
+ a.failure_message Chef::Exceptions::Package, "Package #{new_resource.package_name} not found: #{new_resource.source}"
+ a.whyrun "assuming #{new_resource.source} would have previously been created"
end
+ end
- # Test if another RPMDependency satisfies our requirements
- def satisfy?(y)
- unless y.kind_of?(RPMDependency)
- raise ArgumentError, "Expecting an RPMDependency object"
- end
-
- x = self
-
- # Easy!
- if x.name != y.name
- return false
- end
+ # @see Chef::Provider#load_current_resource
+ def load_current_resource
+ @yum.reload if flush_cache[:before]
+ manage_extra_repo_control
- # Partial compare
+ if new_resource.source
+ query_source_file
+ else
+ # At this point package_name could be:
#
- # eg: x.version 2.3 == y.version 2.3-1
- sense = x.version.partial_compare(y.version)
-
- # Thanks to rpmdsCompare() rpmds.c
- if sense < 0 and (x.flag == :> || x.flag == :>=) || (y.flag == :<= || y.flag == :<)
- return true
- elsif sense > 0 and (x.flag == :< || x.flag == :<=) || (y.flag == :>= || y.flag == :>)
- return true
- elsif sense == 0 and (
- ((x.flag == :== or x.flag == :<= or x.flag == :>=) and (y.flag == :== or y.flag == :<= or y.flag == :>=)) or
- (x.flag == :< and y.flag == :<) or
- (x.flag == :> and y.flag == :>)
- )
- return true
- end
+ # 1) a package name, eg: "foo"
+ # 2) a package name.arch, eg: "foo.i386"
+ # 3) or a dependency, eg: "foo >= 1.1"
+ #
+ # In the third case, we want to convert those dependency strings into
+ # packages that we can actually install
+ convert_dependency_strings_into_packages
- return false
+ # Fill out the rest of the details by querying the Yum Cache
+ query_yum_cache
end
- end
- class RPMProvide < RPMDependency; end
- class RPMRequire < RPMDependency; end
-
- class RPMDbPackage < RPMPackage
- # <rpm parts>, installed, available
- def initialize(*args)
- @repoid = args.pop
- # state
- @available = args.pop
- @installed = args.pop
- super(*args)
- end
- attr_reader :repoid, :available, :installed
+ @current_resource = Chef::Resource::YumPackage.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
+ current_resource.version(@installed_version)
+ current_resource
end
- # Simple storage for RPMPackage objects - keeps them unique and sorted
- class RPMDb
- def initialize
- # package name => [ RPMPackage, RPMPackage ] of different versions
- @rpms = Hash.new
- # package nevra => RPMPackage for lookups
- @index = Hash.new
- # provide name (aka feature) => [RPMPackage, RPMPackage] each providing this feature
- @provides = Hash.new
- # RPMPackages listed as available
- @available = Set.new
- # RPMPackages listed as installed
- @installed = Set.new
- end
-
- def [](package_name)
- self.lookup(package_name)
- end
-
- # Lookup package_name and return a descending array of package objects
- def lookup(package_name)
- pkgs = @rpms[package_name]
- if pkgs
- return pkgs.sort.reverse
- else
- return nil
+ # @see Chef::Provider::Package#package_locked
+ def package_locked(name, version)
+ islocked = false
+ locked = shell_out_with_timeout!("yum versionlock")
+ locked.stdout.each_line do |line|
+ line_package = line.sub(/-[^-]*-[^-]*$/, "").split(":").last.strip
+ if line_package == name
+ islocked = true
end
end
+ islocked
+ end
- def lookup_provides(provide_name)
- @provides[provide_name]
- end
-
- # Using the package name as a key, and nevra for an index, keep a unique list of packages.
- # The available/installed state can be overwritten for existing packages.
- def push(*args)
- args.flatten.each do |new_rpm|
- unless new_rpm.kind_of?(RPMDbPackage)
- raise ArgumentError, "Expecting an RPMDbPackage object"
- end
-
- @rpms[new_rpm.n] ||= Array.new
-
- # we may already have this one, like when the installed list is refreshed
- idx = @index[new_rpm.nevra]
- if idx
- # grab the existing package if it's not
- curr_rpm = idx
- else
- @rpms[new_rpm.n] << new_rpm
-
- new_rpm.provides.each do |provide|
- @provides[provide.name] ||= Array.new
- @provides[provide.name] << new_rpm
- end
-
- curr_rpm = new_rpm
- end
-
- # Track the nevra -> RPMPackage association to avoid having to compare versions
- # with @rpms[new_rpm.n] on the next round
- @index[new_rpm.nevra] = curr_rpm
-
- # these are overwritten for existing packages
- if new_rpm.available
- @available << curr_rpm
- end
- if new_rpm.installed
- @installed << curr_rpm
- end
- end
- end
-
- def <<(*args)
- self.push(args)
- end
-
- def clear
- @rpms.clear
- @index.clear
- @provides.clear
- clear_available
- clear_installed
- end
-
- def clear_available
- @available.clear
- end
+ #
+ # Package Action Classes
+ #
- def clear_installed
- @installed.clear
+ # @see Chef::Provider::Package#install_package
+ def install_package(name, version)
+ if new_resource.source
+ yum_command("-d0 -e0 -y#{expand_options(new_resource.options)} localinstall #{new_resource.source}")
+ else
+ install_remote_package(name, version)
end
- def size
- @rpms.size
- end
- alias :length :size
+ flush_cache[:after] ? @yum.reload : @yum.reload_installed
+ end
- def available_size
- @available.size
- end
+ # @see Chef::Provider::Package#upgrade_package
+ def upgrade_package(name, version)
+ install_package(name, version)
+ end
- def installed_size
- @installed.size
- end
+ # @see Chef::Provider::Package#remove_package
+ def remove_package(name, version)
+ remove_str = full_package_name(name, version).join(" ")
+ yum_command("-d0 -e0 -y#{expand_options(new_resource.options)} remove #{remove_str}")
- def available?(package)
- @available.include?(package)
- end
+ flush_cache[:after] ? @yum.reload : @yum.reload_installed
+ end
- def installed?(package)
- @installed.include?(package)
- end
+ # @see Chef::Provider::Package#purge_package
+ def purge_package(name, version)
+ remove_package(name, version)
+ end
- def whatprovides(rpmdep)
- unless rpmdep.kind_of?(RPMDependency)
- raise ArgumentError, "Expecting an RPMDependency object"
- end
+ # @see Chef::Provider::Package#lock_package
+ def lock_package(name, version)
+ lock_str = full_package_name(name, as_array(name).map { nil }).join(" ")
+ yum_command("-d0 -e0 -y#{expand_options(new_resource.options)} versionlock add #{lock_str}")
+ end
- what = []
+ # @see Chef::Provider::Package#unlock_package
+ def unlock_package(name, version)
+ unlock_str = full_package_name(name, as_array(name).map { nil }).join(" ")
+ yum_command("-d0 -e0 -y#{expand_options(new_resource.options)} versionlock delete #{unlock_str}")
+ end
- packages = lookup_provides(rpmdep.name)
- if packages
- packages.each do |pkg|
- pkg.provides.each do |provide|
- if provide.satisfy?(rpmdep)
- what << pkg
- end
+ # Keep upgrades from trying to install an older candidate version. Can happen when a new
+ # version is installed then removed from a repository, now the older available version
+ # shows up as a viable install candidate.
+ #
+ # Can be done in upgrade_package but an upgraded from->to log message slips out
+ #
+ # Hacky - better overall solution? Custom compare in Package provider?
+ def action_upgrade
+ # Could be uninstalled or have no candidate
+ if current_resource.version.nil? || !candidate_version_array.any?
+ super
+ elsif candidate_version_array.zip(current_version_array).any? do |c, i|
+ RPMVersion.parse(c) > RPMVersion.parse(i)
end
- end
- end
-
- return what
+ super
+ else
+ Chef::Log.debug("#{new_resource} is at the latest version - nothing to do")
end
end
- # Cache for our installed and available packages, pulled in from yum-dump.py
- class YumCache
- include Chef::Mixin::Which
- include Chef::Mixin::ShellOut
- include Singleton
-
- attr_accessor :yum_binary
-
- def initialize
- @rpmdb = RPMDb.new
-
- # Next time @rpmdb is accessed:
- # :all - Trigger a run of "yum-dump.py --options --installed-provides", updates
- # yum's cache and parses options from /etc/yum.conf. Pulls in Provides
- # dependency data for installed packages only - this data is slow to
- # gather.
- # :provides - Same as :all but pulls in Provides data for available packages as well.
- # Used as a last resort when we can't find a Provides match.
- # :installed - Trigger a run of "yum-dump.py --installed", only reads the local rpm
- # db. Used between client runs for a quick refresh.
- # :none - Do nothing, a call to one of the reload methods is required.
- @next_refresh = :all
-
- @allow_multi_install = []
-
- @extra_repo_control = nil
-
- # these are for subsequent runs if we are on an interval
- Chef::Client.when_run_starts do
- YumCache.instance.reload
- end
- end
-
- attr_reader :extra_repo_control
-
- # Cache management
- #
-
- def refresh
- case @next_refresh
- when :none
- return nil
- when :installed
- reset_installed
- # fast
- opts=" --installed"
- when :all
- reset
- # medium
- opts=" --options --installed-provides"
- when :provides
- reset
- # slow!
- opts=" --options --all-provides"
- else
- raise ArgumentError, "Unexpected value in next_refresh: #{@next_refresh}"
- end
-
- if @extra_repo_control
- opts << " #{@extra_repo_control}"
- end
-
- opts << " --yum-lock-timeout #{Chef::Config[:yum_lock_timeout]}"
-
- one_line = false
- error = nil
+ private
- helper = ::File.join(::File.dirname(__FILE__), 'yum-dump.py')
- status = nil
+ #
+ # System Level Yum Operations
+ #
+ def yum_binary
+ @yum_binary ||=
begin
- status = shell_out!("#{python_bin} #{helper}#{opts}", :timeout => Chef::Config[:yum_timeout])
- status.stdout.each_line do |line|
- one_line = true
-
- line.chomp!
- if line =~ %r{\[option (.*)\] (.*)}
- if $1 == "installonlypkgs"
- @allow_multi_install = $2.split
- else
- raise Chef::Exceptions::Package, "Strange, unknown option line '#{line}' from yum-dump.py"
- end
- next
- end
-
- if line =~ %r{^(\S+) ([0-9]+) (\S+) (\S+) (\S+) \[(.*)\] ([i,a,r]) (\S+)$}
- name = $1
- epoch = $2
- version = $3
- release = $4
- arch = $5
- provides = parse_provides($6)
- type = $7
- repoid = $8
- else
- Chef::Log.warn("Problem parsing line '#{line}' from yum-dump.py! " +
- "Please check your yum configuration.")
- next
- end
-
- case type
- when "i"
- # if yum-dump was called with --installed this may not be true, but it's okay
- # since we don't touch the @available Set in reload_installed
- available = false
- installed = true
- when "a"
- available = true
- installed = false
- when "r"
- available = true
- installed = true
- end
-
- pkg = RPMDbPackage.new(name, epoch, version, release, arch, provides, installed, available, repoid)
- @rpmdb << pkg
- end
-
- error = status.stderr
- rescue Mixlib::ShellOut::CommandTimeout => e
- Chef::Log.error("#{helper} exceeded timeout #{Chef::Config[:yum_timeout]}")
- raise(e)
- end
-
- if status.exitstatus != 0
- raise Chef::Exceptions::Package, "Yum failed - #{status.inspect} - returns: #{error}"
- else
- unless one_line
- Chef::Log.warn("Odd, no output from yum-dump.py. Please check " +
- "your yum configuration.")
- end
- end
-
- # A reload method must be called before the cache is altered
- @next_refresh = :none
- end
-
- def python_bin
- yum_executable = which(yum_binary)
- if yum_executable && shabang?(yum_executable)
- extract_interpreter(yum_executable)
- else
- Chef::Log.warn("Yum executable not found or doesn't start with #!. Using default python.")
- "/usr/bin/python"
+ yum_binary = new_resource.yum_binary if new_resource.is_a?(Chef::Resource::YumPackage)
+ yum_binary ||= ::File.exist?("/usr/bin/yum-deprecated") ? "yum-deprecated" : "yum"
end
- rescue StandardError => e
- Chef::Log.warn("An error occurred attempting to determine correct python executable. Using default.")
- Chef::Log.debug(e)
- "/usr/bin/python"
- end
-
- def extract_interpreter(file)
- ::File.open(file, 'r', &:readline)[2..-1].chomp
- end
+ end
- def shabang?(file)
- ::File.open(file, 'r') do |f|
- f.read(2) == '#!'
+ # Enable or disable YumCache extra_repo_control
+ def manage_extra_repo_control
+ if new_resource.options
+ repo_control = []
+ new_resource.options.split.each do |opt|
+ repo_control << opt if opt =~ /--(enable|disable)repo=.+/
end
- rescue Errno::ENOENT
- false
- end
-
- def reload
- @next_refresh = :all
- end
-
- def reload_installed
- @next_refresh = :installed
- end
-
- def reload_provides
- @next_refresh = :provides
- end
-
- def reset
- @rpmdb.clear
- end
- def reset_installed
- @rpmdb.clear_installed
- end
-
- # Querying the cache
- #
-
- # Check for package by name or name+arch
- def package_available?(package_name)
- refresh
-
- if @rpmdb.lookup(package_name)
- return true
+ if !repo_control.empty?
+ @yum.enable_extra_repo_control(repo_control.join(" "))
else
- if package_name =~ %r{^(.*)\.(.*)$}
- pkg_name = $1
- pkg_arch = $2
-
- if matches = @rpmdb.lookup(pkg_name)
- matches.each do |m|
- return true if m.arch == pkg_arch
- end
- end
- end
- end
-
- return false
- end
-
- # Returns a array of packages satisfying an RPMDependency
- def packages_from_require(rpmdep)
- refresh
- @rpmdb.whatprovides(rpmdep)
- end
-
- # Check if a package-version.arch is available to install
- def version_available?(package_name, desired_version, arch=nil)
- version(package_name, arch, true, false) do |v|
- return true if desired_version == v
- end
-
- return false
- end
-
- # Return the source repository for a package-version.arch
- def package_repository(package_name, desired_version, arch=nil)
- package(package_name, arch, true, false) do |pkg|
- return pkg.repoid if desired_version == pkg.version.to_s
+ @yum.disable_extra_repo_control
end
-
- return nil
+ else
+ @yum.disable_extra_repo_control
end
+ end
- # Return the latest available version for a package.arch
- def available_version(package_name, arch=nil)
- version(package_name, arch, true, false)
- end
- alias :candidate_version :available_version
+ # Query the Yum cache for information about potential packages
+ def query_yum_cache
+ installed_versions = []
+ candidate_versions = []
- # Return the currently installed version for a package.arch
- def installed_version(package_name, arch=nil)
- version(package_name, arch, false, true)
- end
+ package_name_array.each_with_index do |n, idx|
+ pkg_name, eval_pkg_arch = parse_arch(n)
- # Return an array of packages allowed to be installed multiple times, such as the kernel
- def allow_multi_install
- refresh
- @allow_multi_install
- end
+ # Defer to the arch property for the desired package architecture
+ pkg_arch = safe_arch_array[idx] || eval_pkg_arch
+ set_package_name(idx, pkg_name)
+ set_package_arch(idx, pkg_arch)
- def enable_extra_repo_control(arg)
- # Don't touch cache if it's the same repos as the last load
- unless @extra_repo_control == arg
- @extra_repo_control = arg
- reload
- end
- end
+ Chef::Log.debug("#{new_resource} checking yum info for #{yum_syntax(n, nil, pkg_arch)}")
+ installed_versions << iv = @yum.installed_version(pkg_name, pkg_arch)
+ candidate_versions << cv = @yum.candidate_version(pkg_name, pkg_arch)
- def disable_extra_repo_control
- # Only force reload when set
- if @extra_repo_control
- @extra_repo_control = nil
- reload
- end
+ Chef::Log.debug("Found Yum package: #{pkg_name} installed version: #{iv || '(none)'} candidate version: #{cv || '(none)'}")
end
- private
+ @installed_version = installed_versions.length > 1 ? installed_versions : installed_versions[0]
+ @candidate_version = candidate_versions.length > 1 ? candidate_versions : candidate_versions[0]
+ end
- def version(package_name, arch=nil, is_available=false, is_installed=false)
- package(package_name, arch, is_available, is_installed) do |pkg|
- if block_given?
- yield pkg.version.to_s
- else
- # first match is latest version
- return pkg.version.to_s
+ # Query the provided source file for the package name and version
+ def query_source_file
+ Chef::Log.debug("#{new_resource} checking rpm status")
+ shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE} %{ARCH}\n' #{new_resource.source}", timeout: Chef::Config[:yum_timeout]).stdout.each_line do |line|
+ case line
+ when /^(\S+)\s(\S+)\s(\S+)$/
+ n = $1
+ v = $2
+ a = $3
+
+ unless new_resource.package_name == n
+ Chef::Log.debug("#{new_resource} updating package_name from #{new_resource.package_name} to #{n} (per #{new_resource.source})")
+ new_resource.package_name(n)
end
- end
-
- if block_given?
- return self
- else
- return nil
- end
- end
- def package(package_name, arch=nil, is_available=false, is_installed=false)
- refresh
- packages = @rpmdb[package_name]
- if packages
- packages.each do |pkg|
- if is_available
- next unless @rpmdb.available?(pkg)
- end
- if is_installed
- next unless @rpmdb.installed?(pkg)
- end
- if arch
- next unless pkg.arch == arch
- end
-
- if block_given?
- yield pkg
- else
- # first match is latest version
- return pkg
- end
+ unless new_resource.version == v
+ Chef::Log.debug("#{new_resource} updating version from #{new_resource.version} to #{v} (per #{new_resource.source})")
+ new_resource.version(v)
end
- end
- if block_given?
- return self
- else
- return nil
- end
- end
-
- # Parse provides from yum-dump.py output
- def parse_provides(string)
- ret = []
- # ['atk = 1.12.2-1.fc6', 'libatk-1.0.so.0']
- string.split(", ").each do |seg|
- # 'atk = 1.12.2-1.fc6'
- if seg =~ %r{^'(.*)'$}
- ret << RPMProvide.parse($1)
+ unless new_resource.arch == a
+ Chef::Log.debug("#{new_resource} updating architecture from #{new_resource.arch} to #{a} (per #{new_resource.source})")
+ new_resource.arch(a)
end
end
-
- return ret
- end
-
- end # YumCache
-
- include Chef::Mixin::GetSourceFromPackage
-
- def initialize(new_resource, run_context)
- super
-
- @yum = YumCache.instance
- @yum.yum_binary = yum_binary
- end
-
- def yum_binary
- @yum_binary ||=
- begin
- yum_binary = new_resource.yum_binary if new_resource.is_a?(Chef::Resource::YumPackage)
- yum_binary ||= ::File.exist?("/usr/bin/yum-deprecated") ? "yum-deprecated" : "yum"
- end
- end
-
- # Extra attributes
- #
-
- def arch_for_name(n)
- if @new_resource.respond_to?("arch")
- @new_resource.arch
- elsif @arch
- idx = package_name_array.index(n)
- as_array(@arch)[idx]
- else
- nil
- end
- end
-
- def arch
- if @new_resource.respond_to?("arch")
- @new_resource.arch
- else
- nil
- end
- end
-
- def set_arch(arch)
- if @new_resource.respond_to?("arch")
- @new_resource.arch(arch)
end
- end
- def flush_cache
- if @new_resource.respond_to?("flush_cache")
- @new_resource.flush_cache
- else
- { :before => false, :after => false }
- end
- end
-
- # Helpers
- #
-
- def yum_arch(arch)
- arch ? ".#{arch}" : nil
+ @installed_version = @yum.installed_version(new_resource.package_name, new_resource.arch)
+ @candidate_version = new_resource.version
end
def yum_command(command)
command = "#{yum_binary} #{command}"
- Chef::Log.debug("#{@new_resource}: yum command: \"#{command}\"")
- status = shell_out_with_timeout(command, {:timeout => Chef::Config[:yum_timeout]})
+ Chef::Log.debug("#{new_resource}: yum command: \"#{command}\"")
+ status = shell_out_with_timeout(command, timeout: Chef::Config[:yum_timeout])
# This is fun: rpm can encounter errors in the %post/%postun scripts which aren't
# considered fatal - meaning the rpm is still successfully installed. These issue
@@ -1053,12 +280,11 @@ class Chef
if status.exitstatus == 1
status.stdout.each_line do |l|
# rpm-4.4.2.3 lib/psm.c line 2182
- if l =~ %r{^error: %(post|postun)\(.*\) scriptlet failed, exit status \d+$}
- Chef::Log.warn("#{@new_resource} caught non-fatal scriptlet issue: \"#{l}\". Can't trust yum exit status " +
- "so running install again to verify.")
- status = shell_out_with_timeout(command, {:timeout => Chef::Config[:yum_timeout]})
- break
- end
+ next unless l =~ /^error: %(post|postun)\(.*\) scriptlet failed, exit status \d+$/
+ Chef::Log.warn("#{new_resource} caught non-fatal scriptlet issue: \"#{l}\". Can't trust yum exit status " \
+ "so running install again to verify.")
+ status = shell_out_with_timeout(command, timeout: Chef::Config[:yum_timeout])
+ break
end
end
@@ -1068,130 +294,12 @@ class Chef
end
end
- # Standard Provider methods for Parent
- #
-
- def load_current_resource
- if flush_cache[:before]
- @yum.reload
- end
-
- if @new_resource.options
- repo_control = []
- @new_resource.options.split.each do |opt|
- if opt =~ %r{--(enable|disable)repo=.+}
- repo_control << opt
- end
- end
-
- if repo_control.size > 0
- @yum.enable_extra_repo_control(repo_control.join(" "))
- else
- @yum.disable_extra_repo_control
- end
- else
- @yum.disable_extra_repo_control
- end
-
- # At this point package_name could be:
- #
- # 1) a package name, eg: "foo"
- # 2) a package name.arch, eg: "foo.i386"
- # 3) or a dependency, eg: "foo >= 1.1"
-
- # Check if we have name or name+arch which has a priority over a dependency
- package_name_array.each_with_index do |n, index|
- unless @yum.package_available?(n)
- # If they aren't in the installed packages they could be a dependency
- dep = parse_dependency(n, new_version_array[index])
- if dep
- if @new_resource.package_name.is_a?(Array)
- @new_resource.package_name(package_name_array - [n] + [dep.first])
- @new_resource.version(new_version_array - [new_version_array[index]] + [dep.last]) if dep.last
- else
- @new_resource.package_name(dep.first)
- @new_resource.version(dep.last) if dep.last
- end
- end
- end
- end
-
-
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @current_resource.package_name(@new_resource.package_name)
-
- installed_version = []
- @candidate_version = []
- @arch = []
- if @new_resource.source
- unless ::File.exists?(@new_resource.source)
- raise Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
- end
-
- Chef::Log.debug("#{@new_resource} checking rpm status")
- shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}", :timeout => Chef::Config[:yum_timeout]).stdout.each_line do |line|
- case line
- when /([\w\d_.-]+)\s([\w\d_.-]+)/
- @current_resource.package_name($1)
- @new_resource.version($2)
- end
- end
- @candidate_version << @new_resource.version
- installed_version << @yum.installed_version(@current_resource.package_name, arch)
- else
-
- package_name_array.each_with_index do |pkg, idx|
- # Don't overwrite an existing arch
- if arch
- name, parch = pkg, arch
- else
- name, parch = parse_arch(pkg)
- # if we parsed an arch from the name, update the name
- # to be just the package name.
- if parch
- if @new_resource.package_name.is_a?(Array)
- @new_resource.package_name[idx] = name
- else
- @new_resource.package_name(name)
- # only set the arch if it's a single package
- set_arch(parch)
- end
- end
- end
-
- if @new_resource.version
- new_resource =
- "#{@new_resource.package_name}-#{@new_resource.version}#{yum_arch(parch)}"
- else
- new_resource = "#{@new_resource.package_name}#{yum_arch(parch)}"
- end
- Chef::Log.debug("#{@new_resource} checking yum info for #{new_resource}")
- installed_version << @yum.installed_version(name, parch)
- @candidate_version << @yum.candidate_version(name, parch)
- @arch << parch
- end
- end
-
- if installed_version.size == 1
- @current_resource.version(installed_version[0])
- @candidate_version = @candidate_version[0]
- @arch = @arch[0]
- else
- @current_resource.version(installed_version)
- end
-
- Chef::Log.debug("#{@new_resource} installed version: #{installed_version || "(none)"} candidate version: " +
- "#{@candidate_version || "(none)"}")
-
- @current_resource
- end
-
def install_remote_package(name, version)
- # Work around yum not exiting with an error if a package doesn't exist
- # for CHEF-2062
- all_avail = as_array(name).zip(as_array(version)).any? do |n, v|
- @yum.version_available?(n, v, arch_for_name(n))
+ # Work around yum not exiting with an error if a package doesn't exist for CHEF-2062.
+ all_avail = as_array(name).zip(as_array(version), safe_arch_array).any? do |n, v, a|
+ @yum.version_available?(n, v, a)
end
+
method = log_method = nil
methods = []
if all_avail
@@ -1201,12 +309,14 @@ class Chef
# yum install of an old name+version+arch will exit(0) for some reason
#
# Some packages can be installed multiple times like the kernel
- as_array(name).zip(as_array(version)).each do |n, v|
+ as_array(name).zip(current_version_array, as_array(version), safe_arch_array).each do |n, cv, v, a|
+ next if n.nil?
+
method = "install"
log_method = "installing"
- idx = package_name_array.index(n)
+
unless @yum.allow_multi_install.include?(n)
- if RPMVersion.parse(current_version_array[idx]) > RPMVersion.parse(v)
+ if RPMVersion.parse(cv) > RPMVersion.parse(v)
# We allow downgrading only in the evenit of single-package
# rules where the user explicitly allowed it
if allow_downgrade
@@ -1214,13 +324,13 @@ class Chef
log_method = "downgrading"
else
# we bail like yum when the package is older
- raise Chef::Exceptions::Package, "Installed package #{n}-#{current_version_array[idx]} is newer " +
- "than candidate package #{n}-#{v}"
+ raise Chef::Exceptions::Package, "Installed package #{yum_syntax(n, cv, a)} is newer " \
+ "than candidate package #{yum_syntax(n, v, a)}"
end
end
end
# methods don't count for packages we won't be touching
- next if RPMVersion.parse(current_version_array[idx]) == RPMVersion.parse(v)
+ next if RPMVersion.parse(cv) == RPMVersion.parse(v)
methods << method
end
@@ -1232,95 +342,26 @@ class Chef
repos = []
pkg_string_bits = []
- as_array(name).zip(as_array(version)).each do |n, v|
- idx = package_name_array.index(n)
- a = arch_for_name(n)
- s = ''
- unless v == current_version_array[idx]
- s = "#{n}-#{v}#{yum_arch(a)}"
- repo = @yum.package_repository(n, v, a)
- repos << "#{s} from #{repo} repository"
- pkg_string_bits << s
- end
- end
- pkg_string = pkg_string_bits.join(' ')
- Chef::Log.info("#{@new_resource} #{log_method} #{repos.join(' ')}")
- yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} #{method} #{pkg_string}")
- else
- raise Chef::Exceptions::Package, "Version #{version} of #{name} not found. Did you specify both version " +
- "and release? (version-release, e.g. 1.84-10.fc6)"
- end
- end
-
- def install_package(name, version)
- if @new_resource.source
- yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} localinstall #{@new_resource.source}")
- else
- install_remote_package(name, version)
- end
-
- if flush_cache[:after]
- @yum.reload
+ as_array(name).zip(current_version_array, as_array(version), safe_arch_array).each do |n, cv, v, a|
+ next if n.nil?
+ next if v == cv
+ s = yum_syntax(n, v, a)
+ repo = @yum.package_repository(n, v, a)
+ repos << "#{s} from #{repo} repository"
+ pkg_string_bits << s
+ end
+ pkg_string = pkg_string_bits.join(" ")
+ Chef::Log.info("#{new_resource} #{log_method} #{repos.join(' ')}")
+ yum_command("-d0 -e0 -y#{expand_options(new_resource.options)} #{method} #{pkg_string}")
else
- @yum.reload_installed
+ raise Chef::Exceptions::Package, "Version #{version} of #{name} not found. Did you specify both version " \
+ "and release? (version-release, e.g. 1.84-10.fc6)"
end
end
- # Keep upgrades from trying to install an older candidate version. Can happen when a new
- # version is installed then removed from a repository, now the older available version
- # shows up as a viable install candidate.
- #
- # Can be done in upgrade_package but an upgraded from->to log message slips out
- #
- # Hacky - better overall solution? Custom compare in Package provider?
- def action_upgrade
- # Could be uninstalled or have no candidate
- if @current_resource.version.nil? || !candidate_version_array.any?
- super
- elsif candidate_version_array.zip(current_version_array).any? do |c, i|
- RPMVersion.parse(c) > RPMVersion.parse(i)
- end
- super
- else
- Chef::Log.debug("#{@new_resource} is at the latest version - nothing to do")
- end
- end
-
- def upgrade_package(name, version)
- install_package(name, version)
- end
-
- def remove_package(name, version)
- if version
- remove_str = as_array(name).zip(as_array(version)).map do |n, v|
- a = arch_for_name(n)
- "#{[n, v].join('-')}#{yum_arch(a)}"
- end.join(' ')
- else
- remove_str = as_array(name).map do |n|
- a = arch_for_name(n)
- "#{n}#{yum_arch(a)}"
- end.join(' ')
- end
- yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} remove #{remove_str}")
-
- if flush_cache[:after]
- @yum.reload
- else
- @yum.reload_installed
- end
- end
-
- def purge_package(name, version)
- remove_package(name, version)
- end
-
- private
-
+ # Allow for foo.x86_64 style package_name like yum uses in it's output
def parse_arch(package_name)
- # Allow for foo.x86_64 style package_name like yum uses in it's output
- #
- if package_name =~ %r{^(.*)\.(.*)$}
+ if package_name =~ /^(.*)\.(.*)$/
new_package_name = $1
new_arch = $2
# foo.i386 and foo.beta1 are both valid package names or expressions of an arch.
@@ -1331,12 +372,36 @@ class Chef
old_candidate = @yum.candidate_version(package_name)
new_installed = @yum.installed_version(new_package_name, new_arch)
new_candidate = @yum.candidate_version(new_package_name, new_arch)
- if (old_installed.nil? and old_candidate.nil?) and (new_installed or new_candidate)
+ if (old_installed.nil? && old_candidate.nil?) && (new_installed || new_candidate)
Chef::Log.debug("Parsed out arch #{new_arch}, new package name is #{new_package_name}")
return new_package_name, new_arch
end
end
- return package_name, nil
+ [package_name, nil]
+ end
+
+ #
+ # Dependency String Handling
+ #
+
+ # Iterate through the list of package_names given to us by the user and
+ # see if any of them are in the depenency format ("foo >= 1.1"). Modify
+ # the list of packages and versions to incorporate those values.
+ def convert_dependency_strings_into_packages
+ package_name_array.each_with_index do |n, index|
+ next if @yum.package_available?(n)
+ # If they aren't in the installed packages they could be a dependency.
+ dep = parse_dependency(n, new_version_array[index])
+ if dep
+ if new_resource.package_name.is_a?(Array)
+ new_resource.package_name(package_name_array - [n] + [dep.first])
+ new_resource.version(new_version_array - [new_version_array[index]] + [dep.last]) if dep.last
+ else
+ new_resource.package_name(dep.first)
+ new_resource.version(dep.last) if dep.last
+ end
+ end
+ end
end
# If we don't have the package we could have been passed a 'whatprovides' feature
@@ -1349,18 +414,20 @@ class Chef
# matching them up with an actual package so the standard resource handling can apply.
#
# There is currently no support for filename matching.
- def parse_dependency(name,version)
+ #
+ # Note: This was largely left alone during the multipackage refactor
+ def parse_dependency(name, version)
# Transform the package_name into a requirement
# If we are passed a version or a version constraint we have to assume it's a requirement first. If it can't be
- # parsed only yum_require.name will be set and @new_resource.version will be left intact
- if version
- require_string = "#{name} #{version}"
- else
- # Transform the package_name into a requirement, might contain a version, could just be
- # a match for virtual provides
- require_string = name
- end
+ # parsed only yum_require.name will be set and new_resource.version will be left intact
+ require_string = if version
+ "#{name} #{version}"
+ else
+ # Transform the package_name into a requirement, might contain a version, could just be
+ # a match for virtual provides
+ name
+ end
yum_require = RPMRequire.parse(require_string)
# and gather all the packages that have a Provides feature satisfying the requirement.
# It could be multiple be we can only manage one
@@ -1368,9 +435,9 @@ class Chef
if packages.empty?
# Don't bother if we are just ensuring a package is removed - we don't need Provides data
- actions = Array(@new_resource.action)
- unless actions.size == 1 and (actions[0] == :remove || actions[0] == :purge)
- Chef::Log.debug("#{@new_resource} couldn't match #{@new_resource.package_name} in " +
+ actions = Array(new_resource.action)
+ unless actions.size == 1 && (actions[0] == :remove || actions[0] == :purge)
+ Chef::Log.debug("#{new_resource} couldn't match #{new_resource.package_name} in " \
"installed Provides, loading available Provides - this may take a moment")
@yum.reload_provides
packages = @yum.packages_from_require(yum_require)
@@ -1393,8 +460,8 @@ class Chef
unique_names.uniq!
if unique_names.size > 1
- Chef::Log.warn("#{@new_resource} matched multiple Provides for #{@new_resource.package_name} " +
- "but we can only use the first match: #{new_package_name}. Please use a more " +
+ Chef::Log.warn("#{new_resource} matched multiple Provides for #{new_resource.package_name} " \
+ "but we can only use the first match: #{new_package_name}. Please use a more " \
"specific version.")
end
@@ -1402,10 +469,67 @@ class Chef
new_package_version = nil
end
- [new_package_name,new_package_version]
+ [new_package_name, new_package_version]
+ end
+ end
+
+ #
+ # Misc Helpers
+ #
+
+ # Given an list of names and versions, generate the full yum syntax package name
+ def full_package_name(name, version)
+ as_array(name).zip(as_array(version), safe_arch_array).map do |n, v, a|
+ yum_syntax(n, v, a)
+ end
+ end
+
+ # Generate the yum syntax for the package
+ def yum_syntax(name, version, arch)
+ s = name
+ s += "-#{version}" if version
+ s += ".#{arch}" if arch
+ s
+ end
+
+ # Set the package name correctly based on whether it is a String or Array
+ def set_package_name(idx, name)
+ if new_resource.package_name.is_a?(String)
+ new_resource.package_name(name)
+ else
+ new_resource.package_name[idx] = name
+ end
+ end
+
+ # Set the architecture correcly based on whether it is a String or Array
+ def set_package_arch(idx, arch)
+ if new_resource.package_name.is_a?(String)
+ new_resource.arch(arch) unless arch.nil?
+ else
+ new_resource.arch ||= []
+ new_resource.arch[idx] = arch
end
end
+ # A cousin of package_name_array, return a list of the architectures
+ # defined in the resource.
+ def safe_arch_array
+ if new_resource.arch.is_a?(Array)
+ new_resource.arch
+ elsif new_resource.arch.nil?
+ package_name_array.map { nil }
+ else
+ [ new_resource.arch ]
+ end
+ end
+
+ def flush_cache
+ if new_resource.respond_to?("flush_cache")
+ new_resource.flush_cache
+ else
+ { before: false, after: false }
+ end
+ end
end
end
end
diff --git a/lib/chef/provider/package/yum/rpm_utils.rb b/lib/chef/provider/package/yum/rpm_utils.rb
new file mode 100644
index 0000000000..0709118184
--- /dev/null
+++ b/lib/chef/provider/package/yum/rpm_utils.rb
@@ -0,0 +1,642 @@
+
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/provider/package"
+
+class Chef
+ class Provider
+ class Package
+ class Yum < Chef::Provider::Package
+ class RPMUtils
+ class << self
+
+ # RPM::Version version_parse equivalent
+ def version_parse(evr)
+ return if evr.nil?
+
+ epoch = nil
+ # assume this is a version
+ version = evr
+ release = nil
+
+ lead = 0
+ tail = evr.size
+
+ if /^([\d]+):/.match(evr) # rubocop:disable Performance/RedundantMatch
+ epoch = $1.to_i
+ lead = $1.length + 1
+ elsif evr[0].ord == ":".ord
+ epoch = 0
+ lead = 1
+ end
+
+ if /:?.*-(.*)$/.match(evr) # rubocop:disable Performance/RedundantMatch
+ release = $1
+ tail = evr.length - release.length - lead - 1
+
+ if release.empty?
+ release = nil
+ end
+ end
+
+ version = evr[lead, tail]
+ if version.empty?
+ version = nil
+ end
+
+ [ epoch, version, release ]
+ end
+
+ # verify
+ def isalnum(x)
+ isalpha(x) || isdigit(x)
+ end
+
+ def isalpha(x)
+ v = x.ord
+ (v >= 65 && v <= 90) || (v >= 97 && v <= 122)
+ end
+
+ def isdigit(x)
+ v = x.ord
+ v >= 48 && v <= 57
+ end
+
+ # based on the reference spec in lib/rpmvercmp.c in rpm 4.9.0
+ def rpmvercmp(x, y)
+ # easy! :)
+ return 0 if x == y
+
+ if x.nil?
+ x = ""
+ end
+
+ if y.nil?
+ y = ""
+ end
+
+ # not so easy :(
+ #
+ # takes 2 strings like
+ #
+ # x = "1.20.b18.el5"
+ # y = "1.20.b17.el5"
+ #
+ # breaks into purely alpha and numeric segments and compares them using
+ # some rules
+ #
+ # * 10 > 1
+ # * 1 > a
+ # * z > a
+ # * Z > A
+ # * z > Z
+ # * leading zeros are ignored
+ # * separators (periods, commas) are ignored
+ # * "1.20.b18.el5.extrastuff" > "1.20.b18.el5"
+
+ x_pos = 0 # overall string element reference position
+ x_pos_max = x.length - 1 # number of elements in string, starting from 0
+ x_seg_pos = 0 # segment string element reference position
+ x_comp = nil # segment to compare
+
+ y_pos = 0
+ y_seg_pos = 0
+ y_pos_max = y.length - 1
+ y_comp = nil
+
+ while x_pos <= x_pos_max && y_pos <= y_pos_max
+ # first we skip over anything non alphanumeric
+ while (x_pos <= x_pos_max) && (isalnum(x[x_pos]) == false)
+ x_pos += 1 # +1 over pos_max if end of string
+ end
+ while (y_pos <= y_pos_max) && (isalnum(y[y_pos]) == false)
+ y_pos += 1
+ end
+
+ # if we hit the end of either we are done matching segments
+ if (x_pos == x_pos_max + 1) || (y_pos == y_pos_max + 1)
+ break
+ end
+
+ # we are now at the start of a alpha or numeric segment
+ x_seg_pos = x_pos
+ y_seg_pos = y_pos
+
+ # grab segment so we can compare them
+ if isdigit(x[x_seg_pos].ord)
+ x_seg_is_num = true
+
+ # already know it's a digit
+ x_seg_pos += 1
+
+ # gather up our digits
+ while (x_seg_pos <= x_pos_max) && isdigit(x[x_seg_pos])
+ x_seg_pos += 1
+ end
+ # copy the segment but not the unmatched character that x_seg_pos will
+ # refer to
+ x_comp = x[x_pos, x_seg_pos - x_pos]
+
+ while (y_seg_pos <= y_pos_max) && isdigit(y[y_seg_pos])
+ y_seg_pos += 1
+ end
+ y_comp = y[y_pos, y_seg_pos - y_pos]
+ else
+ # we are comparing strings
+ x_seg_is_num = false
+
+ while (x_seg_pos <= x_pos_max) && isalpha(x[x_seg_pos])
+ x_seg_pos += 1
+ end
+ x_comp = x[x_pos, x_seg_pos - x_pos]
+
+ while (y_seg_pos <= y_pos_max) && isalpha(y[y_seg_pos])
+ y_seg_pos += 1
+ end
+ y_comp = y[y_pos, y_seg_pos - y_pos]
+ end
+
+ # if y_seg_pos didn't advance in the above loop it means the segments are
+ # different types
+ if y_pos == y_seg_pos
+ # numbers always win over letters
+ return x_seg_is_num ? 1 : -1
+ end
+
+ # move the ball forward before we mess with the segments
+ x_pos += x_comp.length # +1 over pos_max if end of string
+ y_pos += y_comp.length
+
+ # we are comparing numbers - simply convert them
+ if x_seg_is_num
+ x_comp = x_comp.to_i
+ y_comp = y_comp.to_i
+ end
+
+ # compares ints or strings
+ # don't return if equal - try the next segment
+ if x_comp > y_comp
+ return 1
+ elsif x_comp < y_comp
+ return -1
+ end
+
+ # if we've reached here than the segments are the same - try again
+ end
+
+ # we must have reached the end of one or both of the strings and they
+ # matched up until this point
+
+ # segments matched completely but the segment separators were different -
+ # rpm reference code treats these as equal.
+ if (x_pos == x_pos_max + 1) && (y_pos == y_pos_max + 1)
+ return 0
+ end
+
+ # the most unprocessed characters left wins
+ if (x_pos_max - x_pos) > (y_pos_max - y_pos)
+ return 1
+ else
+ return -1
+ end
+ end
+
+ end # self
+ end # RPMUtils
+
+ class RPMVersion
+ include Comparable
+
+ def initialize(*args)
+ if args.size == 1
+ @e, @v, @r = RPMUtils.version_parse(args[0])
+ elsif args.size == 3
+ @e = args[0].to_i
+ @v = args[1]
+ @r = args[2]
+ else
+ raise ArgumentError, "Expecting either 'epoch-version-release' or 'epoch, " \
+ "version, release'"
+ end
+ end
+ attr_reader :e, :v, :r
+ alias epoch e
+ alias version v
+ alias release r
+
+ def self.parse(*args)
+ new(*args)
+ end
+
+ def <=>(other)
+ compare_versions(other)
+ end
+
+ def compare(other)
+ compare_versions(other, false)
+ end
+
+ def partial_compare(other)
+ compare_versions(other, true)
+ end
+
+ # RPM::Version rpm_version_to_s equivalent
+ def to_s
+ if @r.nil?
+ @v
+ else
+ "#{@v}-#{@r}"
+ end
+ end
+
+ def evr
+ "#{@e}:#{@v}-#{@r}"
+ end
+
+ private
+
+ # Rough RPM::Version rpm_version_cmp equivalent - except much slower :)
+ #
+ # partial lets epoch and version segment equality be good enough to return equal, eg:
+ #
+ # 2:1.2-1 == 2:1.2
+ # 2:1.2-1 == 2:
+ #
+ def compare_versions(y, partial = false)
+ x = self
+
+ # compare epoch
+ if (x.e.nil? == false && x.e > 0) && y.e.nil?
+ return 1
+ elsif x.e.nil? && (y.e.nil? == false && y.e > 0)
+ return -1
+ elsif x.e.nil? == false && y.e.nil? == false
+ if x.e < y.e
+ return -1
+ elsif x.e > y.e
+ return 1
+ end
+ end
+
+ # compare version
+ if partial && (x.v.nil? || y.v.nil?)
+ return 0
+ elsif x.v.nil? == false && y.v.nil?
+ return 1
+ elsif x.v.nil? && y.v.nil? == false
+ return -1
+ elsif x.v.nil? == false && y.v.nil? == false
+ cmp = RPMUtils.rpmvercmp(x.v, y.v)
+ return cmp if cmp != 0
+ end
+
+ # compare release
+ if partial && (x.r.nil? || y.r.nil?)
+ return 0
+ elsif x.r.nil? == false && y.r.nil?
+ return 1
+ elsif x.r.nil? && y.r.nil? == false
+ return -1
+ elsif x.r.nil? == false && y.r.nil? == false
+ cmp = RPMUtils.rpmvercmp(x.r, y.r)
+ return cmp
+ end
+
+ 0
+ end
+ end
+
+ class RPMPackage
+ include Comparable
+
+ def initialize(*args)
+ if args.size == 4
+ @n = args[0]
+ @version = RPMVersion.new(args[1])
+ @a = args[2]
+ @provides = args[3]
+ elsif args.size == 6
+ @n = args[0]
+ e = args[1].to_i
+ v = args[2]
+ r = args[3]
+ @version = RPMVersion.new(e, v, r)
+ @a = args[4]
+ @provides = args[5]
+ else
+ raise ArgumentError, "Expecting either 'name, epoch-version-release, arch, provides' " \
+ "or 'name, epoch, version, release, arch, provides'"
+ end
+
+ # We always have one, ourselves!
+ if @provides.empty?
+ @provides = [ RPMProvide.new(@n, @version.evr, :==) ]
+ end
+ end
+ attr_reader :n, :a, :version, :provides
+ alias name n
+ alias arch a
+
+ def <=>(other)
+ compare(other)
+ end
+
+ def compare(y)
+ x = self
+
+ # easy! :)
+ return 0 if x.nevra == y.nevra
+
+ # compare name
+ if x.n.nil? == false && y.n.nil?
+ return 1
+ elsif x.n.nil? && y.n.nil? == false
+ return -1
+ elsif x.n.nil? == false && y.n.nil? == false
+ if x.n < y.n
+ return -1
+ elsif x.n > y.n
+ return 1
+ end
+ end
+
+ # compare version
+ if x.version > y.version
+ return 1
+ elsif x.version < y.version
+ return -1
+ end
+
+ # compare arch
+ if x.a.nil? == false && y.a.nil?
+ return 1
+ elsif x.a.nil? && y.a.nil? == false
+ return -1
+ elsif x.a.nil? == false && y.a.nil? == false
+ if x.a < y.a
+ return -1
+ elsif x.a > y.a
+ return 1
+ end
+ end
+
+ 0
+ end
+
+ def to_s
+ nevra
+ end
+
+ def nevra
+ "#{@n}-#{@version.evr}.#{@a}"
+ end
+ end
+
+ # Simple implementation from rpm and ruby-rpm reference code
+ class RPMDependency
+ def initialize(*args)
+ if args.size == 3
+ @name = args[0]
+ @version = RPMVersion.new(args[1])
+ # Our requirement to other dependencies
+ @flag = args[2] || :==
+ elsif args.size == 5
+ @name = args[0]
+ e = args[1].to_i
+ v = args[2]
+ r = args[3]
+ @version = RPMVersion.new(e, v, r)
+ @flag = args[4] || :==
+ else
+ raise ArgumentError, "Expecting either 'name, epoch-version-release, flag' or " \
+ "'name, epoch, version, release, flag'"
+ end
+ end
+ attr_reader :name, :version, :flag
+
+ # Parses 2 forms:
+ #
+ # "mtr >= 2:0.71-3.0"
+ # "mta"
+ def self.parse(string)
+ if /^(\S+)\s+(>|>=|=|==|<=|<)\s+(\S+)$/.match(string) # rubocop:disable Performance/RedundantMatch
+ name = $1
+ flag = if $2 == "="
+ :==
+ else
+ :"#{$2}"
+ end
+ version = $3
+
+ new(name, version, flag)
+ else
+ name = string
+ new(name, nil, nil)
+ end
+ end
+
+ # Test if another RPMDependency satisfies our requirements
+ def satisfy?(y)
+ unless y.is_a?(RPMDependency)
+ raise ArgumentError, "Expecting an RPMDependency object"
+ end
+
+ x = self
+
+ # Easy!
+ if x.name != y.name
+ return false
+ end
+
+ # Partial compare
+ #
+ # eg: x.version 2.3 == y.version 2.3-1
+ sense = x.version.partial_compare(y.version)
+
+ # Thanks to rpmdsCompare() rpmds.c
+ if (sense < 0) && ((x.flag == :> || x.flag == :>=) || (y.flag == :<= || y.flag == :<))
+ return true
+ elsif (sense > 0) && ((x.flag == :< || x.flag == :<=) || (y.flag == :>= || y.flag == :>))
+ return true
+ elsif sense == 0 && (
+ ((x.flag == :== || x.flag == :<= || x.flag == :>=) && (y.flag == :== || y.flag == :<= || y.flag == :>=)) ||
+ (x.flag == :< && y.flag == :<) ||
+ (x.flag == :> && y.flag == :>)
+ )
+ return true
+ end
+
+ false
+ end
+ end
+
+ class RPMProvide < RPMDependency; end
+ class RPMRequire < RPMDependency; end
+
+ class RPMDbPackage < RPMPackage
+ # <rpm parts>, installed, available
+ def initialize(*args)
+ @repoid = args.pop
+ # state
+ @available = args.pop
+ @installed = args.pop
+ super(*args)
+ end
+ attr_reader :repoid, :available, :installed
+ end
+
+ # Simple storage for RPMPackage objects - keeps them unique and sorted
+ class RPMDb
+ def initialize
+ # package name => [ RPMPackage, RPMPackage ] of different versions
+ @rpms = {}
+ # package nevra => RPMPackage for lookups
+ @index = {}
+ # provide name (aka feature) => [RPMPackage, RPMPackage] each providing this feature
+ @provides = {}
+ # RPMPackages listed as available
+ @available = Set.new
+ # RPMPackages listed as installed
+ @installed = Set.new
+ end
+
+ def [](package_name)
+ lookup(package_name)
+ end
+
+ # Lookup package_name and return a descending array of package objects
+ def lookup(package_name)
+ pkgs = @rpms[package_name]
+ if pkgs
+ return pkgs.sort.reverse
+ else
+ return nil
+ end
+ end
+
+ def lookup_provides(provide_name)
+ @provides[provide_name]
+ end
+
+ # Using the package name as a key, and nevra for an index, keep a unique list of packages.
+ # The available/installed state can be overwritten for existing packages.
+ def push(*args)
+ args.flatten.each do |new_rpm|
+ unless new_rpm.is_a?(RPMDbPackage)
+ raise ArgumentError, "Expecting an RPMDbPackage object"
+ end
+
+ @rpms[new_rpm.n] ||= []
+
+ # we may already have this one, like when the installed list is refreshed
+ idx = @index[new_rpm.nevra]
+ if idx
+ # grab the existing package if it's not
+ curr_rpm = idx
+ else
+ @rpms[new_rpm.n] << new_rpm
+
+ new_rpm.provides.each do |provide|
+ @provides[provide.name] ||= []
+ @provides[provide.name] << new_rpm
+ end
+
+ curr_rpm = new_rpm
+ end
+
+ # Track the nevra -> RPMPackage association to avoid having to compare versions
+ # with @rpms[new_rpm.n] on the next round
+ @index[new_rpm.nevra] = curr_rpm
+
+ # these are overwritten for existing packages
+ if new_rpm.available
+ @available << curr_rpm
+ end
+ if new_rpm.installed
+ @installed << curr_rpm
+ end
+ end
+ end
+
+ def <<(*args)
+ push(args)
+ end
+
+ def clear
+ @rpms.clear
+ @index.clear
+ @provides.clear
+ clear_available
+ clear_installed
+ end
+
+ def clear_available
+ @available.clear
+ end
+
+ def clear_installed
+ @installed.clear
+ end
+
+ def size
+ @rpms.size
+ end
+ alias length size
+
+ def available_size
+ @available.size
+ end
+
+ def installed_size
+ @installed.size
+ end
+
+ def available?(package)
+ @available.include?(package)
+ end
+
+ def installed?(package)
+ @installed.include?(package)
+ end
+
+ def whatprovides(rpmdep)
+ unless rpmdep.is_a?(RPMDependency)
+ raise ArgumentError, "Expecting an RPMDependency object"
+ end
+
+ what = []
+
+ packages = lookup_provides(rpmdep.name)
+ if packages
+ packages.each do |pkg|
+ pkg.provides.each do |provide|
+ if provide.satisfy?(rpmdep)
+ what << pkg
+ end
+ end
+ end
+ end
+
+ what
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/yum-dump.py b/lib/chef/provider/package/yum/yum-dump.py
index c9f6a1fcea..6183460195 100644
--- a/lib/chef/provider/package/yum-dump.py
+++ b/lib/chef/provider/package/yum/yum-dump.py
@@ -1,6 +1,6 @@
#
# Author:: Matthew Kent (<mkent@magoazul.com>)
-# Copyright:: Copyright (c) 2009, 2011 Matthew Kent
+# Copyright:: Copyright 2009-2016, Matthew Kent
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/package/yum/yum_cache.rb b/lib/chef/provider/package/yum/yum_cache.rb
new file mode 100644
index 0000000000..9fd95af138
--- /dev/null
+++ b/lib/chef/provider/package/yum/yum_cache.rb
@@ -0,0 +1,376 @@
+
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/config"
+require "chef/provider/package"
+require "chef/mixin/which"
+require "chef/mixin/shell_out"
+require "singleton"
+require "chef/provider/package/yum/rpm_utils"
+
+class Chef
+ class Provider
+ class Package
+ class Yum < Chef::Provider::Package
+ # Cache for our installed and available packages, pulled in from yum-dump.py
+ class YumCache
+ include Chef::Mixin::Which
+ include Chef::Mixin::ShellOut
+ include Singleton
+
+ attr_accessor :yum_binary
+
+ def initialize
+ @rpmdb = RPMDb.new
+
+ # Next time @rpmdb is accessed:
+ # :all - Trigger a run of "yum-dump.py --options --installed-provides", updates
+ # yum's cache and parses options from /etc/yum.conf. Pulls in Provides
+ # dependency data for installed packages only - this data is slow to
+ # gather.
+ # :provides - Same as :all but pulls in Provides data for available packages as well.
+ # Used as a last resort when we can't find a Provides match.
+ # :installed - Trigger a run of "yum-dump.py --installed", only reads the local rpm
+ # db. Used between client runs for a quick refresh.
+ # :none - Do nothing, a call to one of the reload methods is required.
+ @next_refresh = :all
+
+ @allow_multi_install = []
+
+ @extra_repo_control = nil
+
+ # these are for subsequent runs if we are on an interval
+ Chef::Client.when_run_starts do
+ YumCache.instance.reload
+ end
+ end
+
+ attr_reader :extra_repo_control
+
+ # Cache management
+ #
+
+ def yum_dump_path
+ ::File.join(::File.dirname(__FILE__), "yum-dump.py")
+ end
+
+ def refresh
+ case @next_refresh
+ when :none
+ return nil
+ when :installed
+ reset_installed
+ # fast
+ opts = " --installed"
+ when :all
+ reset
+ # medium
+ opts = " --options --installed-provides"
+ when :provides
+ reset
+ # slow!
+ opts = " --options --all-provides"
+ else
+ raise ArgumentError, "Unexpected value in next_refresh: #{@next_refresh}"
+ end
+
+ if @extra_repo_control
+ opts << " #{@extra_repo_control}"
+ end
+
+ opts << " --yum-lock-timeout #{Chef::Config[:yum_lock_timeout]}"
+
+ one_line = false
+ error = nil
+
+ status = nil
+
+ begin
+ status = shell_out!("#{python_bin} #{yum_dump_path}#{opts}", timeout: Chef::Config[:yum_timeout])
+ status.stdout.each_line do |line|
+ one_line = true
+
+ line.chomp!
+ if line =~ /\[option (.*)\] (.*)/
+ if $1 == "installonlypkgs"
+ @allow_multi_install = $2.split
+ else
+ raise Chef::Exceptions::Package, "Strange, unknown option line '#{line}' from yum-dump.py"
+ end
+ next
+ end
+
+ if line =~ /^(\S+) ([0-9]+) (\S+) (\S+) (\S+) \[(.*)\] ([i,a,r]) (\S+)$/
+ name = $1
+ epoch = $2
+ version = $3
+ release = $4
+ arch = $5
+ provides = parse_provides($6)
+ type = $7
+ repoid = $8
+ else
+ Chef::Log.warn("Problem parsing line '#{line}' from yum-dump.py! " \
+ "Please check your yum configuration.")
+ next
+ end
+
+ case type
+ when "i"
+ # if yum-dump was called with --installed this may not be true, but it's okay
+ # since we don't touch the @available Set in reload_installed
+ available = false
+ installed = true
+ when "a"
+ available = true
+ installed = false
+ when "r"
+ available = true
+ installed = true
+ end
+
+ pkg = RPMDbPackage.new(name, epoch, version, release, arch, provides, installed, available, repoid)
+ @rpmdb << pkg
+ end
+
+ error = status.stderr
+ rescue Mixlib::ShellOut::CommandTimeout => e
+ Chef::Log.error("#{yum_dump_path} exceeded timeout #{Chef::Config[:yum_timeout]}")
+ raise(e)
+ end
+
+ if status.exitstatus != 0
+ raise Chef::Exceptions::Package, "Yum failed - #{status.inspect} - returns: #{error}"
+ else
+ unless one_line
+ Chef::Log.warn("Odd, no output from yum-dump.py. Please check " \
+ "your yum configuration.")
+ end
+ end
+
+ # A reload method must be called before the cache is altered
+ @next_refresh = :none
+ end
+
+ def python_bin
+ yum_executable = which(yum_binary)
+ if yum_executable && shabang?(yum_executable)
+ shabang_or_fallback(extract_interpreter(yum_executable))
+ else
+ Chef::Log.warn("Yum executable not found or doesn't start with #!. Using default python.")
+ "/usr/bin/python"
+ end
+ rescue StandardError => e
+ Chef::Log.warn("An error occurred attempting to determine correct python executable. Using default.")
+ Chef::Log.debug(e)
+ "/usr/bin/python"
+ end
+
+ def extract_interpreter(file)
+ ::File.open(file, "r", &:readline)[2..-1].strip
+ end
+
+ # dnf based systems have a yum shim that has /bin/bash as the interpreter. Don't use this.
+ def shabang_or_fallback(interpreter)
+ if interpreter == "/bin/bash"
+ Chef::Log.warn("Yum executable interpreter is /bin/bash. Falling back to default python.")
+ "/usr/bin/python"
+ else
+ interpreter
+ end
+ end
+
+ def shabang?(file)
+ ::File.open(file, "r") do |f|
+ f.read(2) == "#!"
+ end
+ rescue Errno::ENOENT
+ false
+ end
+
+ def reload
+ @next_refresh = :all
+ end
+
+ def reload_installed
+ @next_refresh = :installed
+ end
+
+ def reload_provides
+ @next_refresh = :provides
+ end
+
+ def reset
+ @rpmdb.clear
+ end
+
+ def reset_installed
+ @rpmdb.clear_installed
+ end
+
+ # Querying the cache
+ #
+
+ # Check for package by name or name+arch
+ def package_available?(package_name)
+ refresh
+
+ if @rpmdb.lookup(package_name)
+ return true
+ else
+ if package_name =~ /^(.*)\.(.*)$/
+ pkg_name = $1
+ pkg_arch = $2
+
+ if matches = @rpmdb.lookup(pkg_name)
+ matches.each do |m|
+ return true if m.arch == pkg_arch
+ end
+ end
+ end
+ end
+
+ false
+ end
+
+ # Returns a array of packages satisfying an RPMDependency
+ def packages_from_require(rpmdep)
+ refresh
+ @rpmdb.whatprovides(rpmdep)
+ end
+
+ # Check if a package-version.arch is available to install
+ def version_available?(package_name, desired_version, arch = nil)
+ version(package_name, arch, true, false) do |v|
+ return true if desired_version == v
+ end
+
+ false
+ end
+
+ # Return the source repository for a package-version.arch
+ def package_repository(package_name, desired_version, arch = nil)
+ package(package_name, arch, true, false) do |pkg|
+ return pkg.repoid if desired_version == pkg.version.to_s
+ end
+
+ nil
+ end
+
+ # Return the latest available version for a package.arch
+ def available_version(package_name, arch = nil)
+ version(package_name, arch, true, false)
+ end
+ alias candidate_version available_version
+
+ # Return the currently installed version for a package.arch
+ def installed_version(package_name, arch = nil)
+ version(package_name, arch, false, true)
+ end
+
+ # Return an array of packages allowed to be installed multiple times, such as the kernel
+ def allow_multi_install
+ refresh
+ @allow_multi_install
+ end
+
+ def enable_extra_repo_control(arg)
+ # Don't touch cache if it's the same repos as the last load
+ unless @extra_repo_control == arg
+ @extra_repo_control = arg
+ reload
+ end
+ end
+
+ def disable_extra_repo_control
+ # Only force reload when set
+ if @extra_repo_control
+ @extra_repo_control = nil
+ reload
+ end
+ end
+
+ private
+
+ def version(package_name, arch = nil, is_available = false, is_installed = false)
+ package(package_name, arch, is_available, is_installed) do |pkg|
+ if block_given?
+ yield pkg.version.to_s
+ else
+ # first match is latest version
+ return pkg.version.to_s
+ end
+ end
+
+ if block_given?
+ return self
+ else
+ return nil
+ end
+ end
+
+ def package(package_name, arch = nil, is_available = false, is_installed = false)
+ refresh
+ packages = @rpmdb[package_name]
+ if packages
+ packages.each do |pkg|
+ if is_available
+ next unless @rpmdb.available?(pkg)
+ end
+ if is_installed
+ next unless @rpmdb.installed?(pkg)
+ end
+ if arch
+ next unless pkg.arch == arch
+ end
+
+ if block_given?
+ yield pkg
+ else
+ # first match is latest version
+ return pkg
+ end
+ end
+ end
+
+ if block_given?
+ return self
+ else
+ return nil
+ end
+ end
+
+ # Parse provides from yum-dump.py output
+ def parse_provides(string)
+ ret = []
+ # ['atk = 1.12.2-1.fc6', 'libatk-1.0.so.0']
+ string.split(", ").each do |seg|
+ # 'atk = 1.12.2-1.fc6'
+ if seg =~ /^'(.*)'$/
+ ret << RPMProvide.parse($1)
+ end
+ end
+
+ ret
+ end
+
+ end # YumCache
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/zypper.rb b/lib/chef/provider/package/zypper.rb
index ac42304ffb..45c6c91f60 100644
--- a/lib/chef/provider/package/zypper.rb
+++ b/lib/chef/provider/package/zypper.rb
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
#
-# Authors:: Adam Jacob (<adam@opscode.com>)
+# Authors:: Adam Jacob (<adam@chef.io>)
# Ionuț Arțăriși (<iartarisi@suse.cz>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright (c) 2013 SUSE Linux GmbH
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# Copyright 2013-2016, SUSE Linux GmbH
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,79 +19,95 @@
# limitations under the License.
#
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'singleton'
+require "chef/provider/package"
+require "chef/resource/zypper_package"
class Chef
class Provider
class Package
class Zypper < Chef::Provider::Package
+ use_multipackage_api
provides :package, platform_family: "suse"
provides :zypper_package, os: "linux"
- def load_current_resource
- @current_resource = Chef::Resource::ZypperPackage.new(new_resource.name)
- current_resource.package_name(new_resource.package_name)
-
- is_installed=false
- is_out_of_date=false
- version=''
- oud_version=''
+ def get_versions(package_name)
+ candidate_version = current_version = nil
+ is_installed = false
Chef::Log.debug("#{new_resource} checking zypper")
- status = shell_out_with_timeout("zypper --non-interactive info #{new_resource.package_name}")
+ status = shell_out_compact_timeout!("zypper", "--non-interactive", "info", package_name)
status.stdout.each_line do |line|
case line
- when /^Version: (.+)$/
- version = $1
- Chef::Log.debug("#{new_resource} version #{$1}")
- when /^Installed: Yes$/
- is_installed=true
+ when /^Version *: (.+) *$/
+ candidate_version = $1.strip
+ Chef::Log.debug("#{new_resource} version #{candidate_version}")
+ when /^Installed *: Yes *$/
+ is_installed = true
Chef::Log.debug("#{new_resource} is installed")
+ when /^Status *: out-of-date \(version (.+) installed\) *$/
+ current_version = $1.strip
+ Chef::Log.debug("#{new_resource} out of date version #{current_version}")
+ end
+ end
+ current_version = candidate_version if is_installed
+ { current_version: current_version, candidate_version: candidate_version }
+ end
- when /^Installed: No$/
- is_installed=false
- Chef::Log.debug("#{new_resource} is not installed")
- when /^Status: out-of-date \(version (.+) installed\)$/
- is_out_of_date=true
- oud_version=$1
- Chef::Log.debug("#{new_resource} out of date version #{$1}")
+ def versions
+ @versions ||=
+ begin
+ raw_versions = package_name_array.map do |package_name|
+ get_versions(package_name)
+ end
+ Hash[*package_name_array.zip(raw_versions).flatten]
end
+ end
+
+ def get_candidate_versions
+ package_name_array.map do |package_name|
+ versions[package_name][:candidate_version]
end
+ end
- if is_installed==false
- @candidate_version=version
- current_resource.version(nil)
+ def get_current_versions
+ package_name_array.map do |package_name|
+ versions[package_name][:current_version]
end
+ end
- if is_installed==true
- if is_out_of_date==true
- current_resource.version(oud_version)
- @candidate_version=version
- else
- current_resource.version(version)
- @candidate_version=version
+ def package_locked(name, version)
+ islocked = false
+ locked = shell_out_compact_timeout!("zypper", "locks")
+ locked.stdout.each_line do |line|
+ line_package = line.split("|").shift(2).last.strip
+ if line_package == name
+ islocked = true
end
end
+ islocked
+ end
- unless status.exitstatus == 0
- raise Chef::Exceptions::Package, "zypper failed - #{status.inspect}!"
- end
+ def load_current_resource
+ @current_resource = Chef::Resource::ZypperPackage.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
+
+ @candidate_version = get_candidate_versions
+ current_resource.version(get_current_versions)
current_resource
end
- def zypper_version()
- `zypper -V 2>&1`.scan(/\d+/).join(".").to_f
+ def zypper_version
+ @zypper_version ||=
+ `zypper -V 2>&1`.scan(/\d+/).join(".").to_f
end
def install_package(name, version)
- zypper_package("install --auto-agree-with-licenses", name, version)
+ zypper_package("install", "--auto-agree-with-licenses", name, version)
end
def upgrade_package(name, version)
+ # `zypper install` upgrades packages, we rely on the idempotency checks to get action :install behavior
install_package(name, version)
end
@@ -100,31 +116,45 @@ class Chef
end
def purge_package(name, version)
- zypper_package("remove --clean-deps", name, version)
+ zypper_package("remove", "--clean-deps", name, version)
+ end
+
+ def lock_package(name, version)
+ zypper_package("addlock", name, version)
+ end
+
+ def unlock_package(name, version)
+ zypper_package("removelock", name, version)
end
private
- def zypper_package(command, pkgname, version)
- version = "=#{version}" unless version.nil? || version.empty?
+
+ def zip(names, versions)
+ names.zip(versions).map do |n, v|
+ (v.nil? || v.empty?) ? n : "#{n}=#{v}"
+ end
+ end
+
+ def zypper_package(command, *options, names, versions)
+ zipped_names = zip(names, versions)
if zypper_version < 1.0
- shell_out_with_timeout!("zypper#{gpg_checks} #{command} -y #{pkgname}")
+ shell_out_compact_timeout!("zypper", gpg_checks, command, *options, "-y", names)
else
- shell_out_with_timeout!("zypper --non-interactive#{gpg_checks} "+
- "#{command} #{pkgname}#{version}")
+ shell_out_compact_timeout!("zypper", "--non-interactive", gpg_checks, command, *options, zipped_names)
end
end
- def gpg_checks()
+ def gpg_checks
case Chef::Config[:zypper_check_gpg]
when true
- ""
+ nil
when false
- " --no-gpg-checks"
+ "--no-gpg-checks"
when nil
- Chef::Log.warn("Chef::Config[:zypper_check_gpg] was not set. " +
- "All packages will be installed without gpg signature checks. " +
+ Chef::Log.warn("Chef::Config[:zypper_check_gpg] was not set. " \
+ "All packages will be installed without gpg signature checks. " \
"This is a security hazard.")
- " --no-gpg-checks"
+ "--no-gpg-checks"
end
end
end
diff --git a/lib/chef/provider/powershell_script.rb b/lib/chef/provider/powershell_script.rb
index e04efb6b42..87705ef59a 100644
--- a/lib/chef/provider/powershell_script.rb
+++ b/lib/chef/provider/powershell_script.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/platform/query_helpers'
-require 'chef/provider/windows_script'
+require "chef/platform/query_helpers"
+require "chef/provider/windows_script"
class Chef
class Provider
@@ -25,8 +25,8 @@ class Chef
provides :powershell_script, os: "windows"
- def initialize (new_resource, run_context)
- super(new_resource, run_context, '.ps1')
+ def initialize(new_resource, run_context)
+ super(new_resource, run_context, ".ps1")
add_exit_status_wrapper
end
@@ -36,7 +36,7 @@ class Chef
end
def command
- basepath = is_forced_32bit ? wow64_directory : run_context.node.kernel.os_info.system_directory
+ basepath = is_forced_32bit ? wow64_directory : run_context.node["kernel"]["os_info"]["system_directory"]
# Powershell.exe is always in "v1.0" folder (for backwards compatibility)
interpreter_path = Chef::Util::PathHelper.join(basepath, "WindowsPowerShell", "v1.0", interpreter)
@@ -58,10 +58,10 @@ class Chef
end
def flags
- interpreter_flags = [*default_interpreter_flags].join(' ')
+ interpreter_flags = [*default_interpreter_flags].join(" ")
- if ! (@new_resource.flags.nil?)
- interpreter_flags = [@new_resource.flags, interpreter_flags].join(' ')
+ if ! (new_resource.flags.nil?)
+ interpreter_flags = [new_resource.flags, interpreter_flags].join(" ")
end
interpreter_flags
@@ -73,13 +73,13 @@ class Chef
# special handling to cover common use cases.
def add_exit_status_wrapper
self.code = wrapper_script
- Chef::Log.debug("powershell_script provider called with script code:\n\n#{@new_resource.code}\n")
- Chef::Log.debug("powershell_script provider will execute transformed code:\n\n#{self.code}\n")
+ Chef::Log.debug("powershell_script provider called with script code:\n\n#{new_resource.code}\n")
+ Chef::Log.debug("powershell_script provider will execute transformed code:\n\n#{code}\n")
end
def validate_script_syntax!
- interpreter_arguments = default_interpreter_flags.join(' ')
- Tempfile.open(['chef_powershell_script-user-code', '.ps1']) do | user_script_file |
+ interpreter_arguments = default_interpreter_flags.join(" ")
+ Tempfile.open(["chef_powershell_script-user-code", ".ps1"]) do |user_script_file|
# Wrap the user's code in a PowerShell script block so that
# it isn't executed. However, syntactically invalid script
# in that block will still trigger a syntax error which is
@@ -87,7 +87,7 @@ class Chef
# actually running the script.
user_code_wrapped_in_powershell_script_block = <<-EOH
{
- #{@new_resource.code}
+ #{new_resource.code}
}
EOH
user_script_file.puts user_code_wrapped_in_powershell_script_block
@@ -110,7 +110,7 @@ EOH
# means a non-zero return and thus a syntactically invalid script.
with_os_architecture(node, architecture: new_resource.architecture) do
- shell_out!(validation_command, {returns: [0]})
+ shell_out!(validation_command, { returns: [0] })
end
end
end
@@ -122,7 +122,7 @@ EOH
# user input confirmation for files such as PowerShell modules
# downloaded from the Internet. However, 'Bypass' is not supported
# prior to PowerShell 3.0, so the fallback is 'Unrestricted'
- execution_policy = Chef::Platform.supports_powershell_execution_bypass?(run_context.node) ? 'Bypass' : 'Unrestricted'
+ execution_policy = Chef::Platform.supports_powershell_execution_bypass?(run_context.node) ? "Bypass" : "Unrestricted"
[
"-NoLogo",
@@ -131,7 +131,7 @@ EOH
"-ExecutionPolicy #{execution_policy}",
# Powershell will hang if STDIN is redirected
# http://connect.microsoft.com/PowerShell/feedback/details/572313/powershell-exe-can-hang-if-stdin-is-redirected
- "-InputFormat None"
+ "-InputFormat None",
]
end
@@ -146,9 +146,17 @@ EOH
# executed, otherwise 0 or 1 based on whether $? is set to true
# (success, where we return 0) or false (where we return 1).
def wrapper_script
-<<-EOH
+ <<-EOH
# Chef Client wrapper for powershell_script resources
+# In rare cases, such as when PowerShell is executed
+# as an alternate user, the new-variable cmdlet is not
+# available, so import it just in case
+if ( get-module -ListAvailable Microsoft.PowerShell.Utility )
+{
+ Import-Module Microsoft.PowerShell.Utility
+}
+
# LASTEXITCODE can be uninitialized -- make it explictly 0
# to avoid incorrect detection of failure (non-zero) codes
$global:LASTEXITCODE = 0
@@ -159,7 +167,7 @@ $global:LASTEXITCODE = 0
trap [Exception] {write-error ($_.Exception.Message);exit 1}
# Variable state that should not be accessible to the user code
-new-variable -name interpolatedexitcode -visibility private -value $#{@new_resource.convert_boolean_return}
+new-variable -name interpolatedexitcode -visibility private -value $#{new_resource.convert_boolean_return}
new-variable -name chefscriptresult -visibility private
# Initialize a variable we use to capture $? inside a block
@@ -168,7 +176,7 @@ $global:lastcmdlet = $null
# Execute the user's code in a script block --
$chefscriptresult =
{
- #{@new_resource.code}
+ #{new_resource.code}
# This assignment doesn't affect the block's return value
$global:lastcmdlet = $?
diff --git a/lib/chef/provider/reboot.rb b/lib/chef/provider/reboot.rb
index 22e77dcc13..ff85f7a99a 100644
--- a/lib/chef/provider/reboot.rb
+++ b/lib/chef/provider/reboot.rb
@@ -1,6 +1,6 @@
#
-# Author:: Chris Doherty <cdoherty@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef, Inc.
+# Author:: Chris Doherty <cdoherty@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/provider'
+require "chef/log"
+require "chef/provider"
class Chef
class Provider
@@ -29,31 +29,31 @@ class Chef
end
def load_current_resource
- @current_resource ||= Chef::Resource::Reboot.new(@new_resource.name)
- @current_resource.reason(@new_resource.reason)
- @current_resource.delay_mins(@new_resource.delay_mins)
- @current_resource
+ @current_resource ||= Chef::Resource::Reboot.new(new_resource.name)
+ current_resource.reason(new_resource.reason)
+ current_resource.delay_mins(new_resource.delay_mins)
+ current_resource
end
def request_reboot
node.run_context.request_reboot(
- :delay_mins => @new_resource.delay_mins,
- :reason => @new_resource.reason,
+ :delay_mins => new_resource.delay_mins,
+ :reason => new_resource.reason,
:timestamp => Time.now,
- :requested_by => @new_resource.name
+ :requested_by => new_resource.name
)
end
def action_request_reboot
converge_by("request a system reboot to occur if the run succeeds") do
- Chef::Log.warn "Reboot requested:'#{@new_resource.name}'"
+ Chef::Log.warn "Reboot requested:'#{new_resource.name}'"
request_reboot
end
end
def action_reboot_now
converge_by("rebooting the system immediately") do
- Chef::Log.warn "Rebooting system immediately, requested by '#{@new_resource.name}'"
+ Chef::Log.warn "Rebooting system immediately, requested by '#{new_resource.name}'"
request_reboot
throw :end_client_run_early
end
@@ -61,7 +61,7 @@ class Chef
def action_cancel
converge_by("cancel any existing end-of-run reboot request") do
- Chef::Log.warn "Reboot canceled: '#{@new_resource.name}'"
+ Chef::Log.warn "Reboot canceled: '#{new_resource.name}'"
node.run_context.cancel_reboot
end
end
diff --git a/lib/chef/provider/registry_key.rb b/lib/chef/provider/registry_key.rb
index 948fa6c63f..2443a3d184 100644
--- a/lib/chef/provider/registry_key.rb
+++ b/lib/chef/provider/registry_key.rb
@@ -1,8 +1,8 @@
#
-# Author:: Prajakta Purohit (<prajakta@opscode.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
+# Author:: Prajakta Purohit (<prajakta@chef.io>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
#
-# Copyright:: 2011, Opscode, Inc.
+# Copyright:: Copyright 2011-2017, Chef Software Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,15 +17,15 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/log'
-require 'chef/resource/file'
-require 'chef/mixin/checksum'
-require 'chef/provider'
-require 'etc'
-require 'fileutils'
-require 'chef/scan_access_control'
-require 'chef/win32/registry'
+require "chef/config"
+require "chef/log"
+require "chef/resource/file"
+require "chef/mixin/checksum"
+require "chef/provider"
+require "etc"
+require "fileutils"
+require "chef/scan_access_control"
+require "chef/win32/registry"
class Chef
@@ -47,19 +47,19 @@ class Chef
def load_current_resource
running_on_windows!
- @current_resource ||= Chef::Resource::RegistryKey.new(@new_resource.key, run_context)
- @current_resource.key(@new_resource.key)
- @current_resource.architecture(@new_resource.architecture)
- @current_resource.recursive(@new_resource.recursive)
- if registry.key_exists?(@new_resource.key)
- @current_resource.values(registry.get_values(@new_resource.key))
- end
- values_to_hash(@current_resource.unscrubbed_values)
- @current_resource
+ @current_resource ||= Chef::Resource::RegistryKey.new(new_resource.key, run_context)
+ current_resource.key(new_resource.key)
+ current_resource.architecture(new_resource.architecture)
+ current_resource.recursive(new_resource.recursive)
+ if registry.key_exists?(new_resource.key)
+ current_resource.values(registry.get_values(new_resource.key))
+ end
+ values_to_hash(current_resource.unscrubbed_values)
+ current_resource
end
def registry
- @registry ||= Chef::Win32::Registry.new(@run_context, @new_resource.architecture)
+ @registry ||= Chef::Win32::Registry.new(@run_context, new_resource.architecture)
end
def values_to_hash(values)
@@ -70,72 +70,99 @@ class Chef
end
end
+ def key_missing?(values, name)
+ values.each do |v|
+ return true unless v.has_key?(name)
+ end
+ false
+ end
+
def define_resource_requirements
requirements.assert(:create, :create_if_missing, :delete, :delete_key) do |a|
- a.assertion{ registry.hive_exists?(@new_resource.key) }
- a.failure_message(Chef::Exceptions::Win32RegHiveMissing, "Hive #{@new_resource.key.split("\\").shift} does not exist")
+ a.assertion { registry.hive_exists?(new_resource.key) }
+ a.failure_message(Chef::Exceptions::Win32RegHiveMissing, "Hive #{new_resource.key.split("\\").shift} does not exist")
end
+
requirements.assert(:create) do |a|
- a.assertion{ registry.key_exists?(@new_resource.key) }
- a.whyrun("Key #{@new_resource.key} does not exist. Unless it would have been created before, attempt to modify its values would fail.")
+ a.assertion { registry.key_exists?(new_resource.key) }
+ a.whyrun("Key #{new_resource.key} does not exist. Unless it would have been created before, attempt to modify its values would fail.")
end
+
requirements.assert(:create, :create_if_missing) do |a|
- #If keys missing in the path and recursive == false
- a.assertion{ !registry.keys_missing?(@current_resource.key) || @new_resource.recursive }
+ # If keys missing in the path and recursive == false
+ a.assertion { !registry.keys_missing?(current_resource.key) || new_resource.recursive }
a.failure_message(Chef::Exceptions::Win32RegNoRecursive, "Intermediate keys missing but recursive is set to false")
- a.whyrun("Intermediate keys in #{@new_resource.key} go not exist. Unless they would have been created earlier, attempt to modify them would fail.")
+ a.whyrun("Intermediate keys in #{new_resource.key} do not exist. Unless they would have been created earlier, attempt to modify them would fail.")
end
+
requirements.assert(:delete_key) do |a|
- #If key to be deleted has subkeys but recurssive == false
- a.assertion{ !registry.key_exists?(@new_resource.key) || !registry.has_subkeys?(@new_resource.key) || @new_resource.recursive }
- a.failure_message(Chef::Exceptions::Win32RegNoRecursive, "#{@new_resource.key} has subkeys but recursive is set to false.")
- a.whyrun("#{@current_resource.key} has subkeys, but recursive is set to false. attempt to delete would fails unless subkeys were deleted prior to this action.")
+ # If key to be deleted has subkeys but recurssive == false
+ a.assertion { !registry.key_exists?(new_resource.key) || !registry.has_subkeys?(new_resource.key) || new_resource.recursive }
+ a.failure_message(Chef::Exceptions::Win32RegNoRecursive, "#{new_resource.key} has subkeys but recursive is set to false.")
+ a.whyrun("#{current_resource.key} has subkeys, but recursive is set to false. attempt to delete would fails unless subkeys were deleted prior to this action.")
+ end
+
+ requirements.assert(:create, :create_if_missing) do |a|
+ # If type key missing in the RegistryKey values hash
+ a.assertion { !key_missing?(new_resource.values, :type) }
+ a.failure_message(Chef::Exceptions::RegKeyValuesTypeMissing, "Missing type key in RegistryKey values hash")
+ a.whyrun("Type key does not exist. Attempt would fail unless the complete values hash containing all the keys does not exist for registry_key resource's create action.")
+ end
+
+ requirements.assert(:create, :create_if_missing) do |a|
+ # If data key missing in the RegistryKey values hash
+ a.assertion { !key_missing?(new_resource.values, :data) }
+ a.failure_message(Chef::Exceptions::RegKeyValuesDataMissing, "Missing data key in RegistryKey values hash")
+ a.whyrun("Data key does not exist. Attempt would fail unless the complete values hash containing all the keys does not exist for registry_key resource's create action.")
end
end
def action_create
- unless registry.key_exists?(@current_resource.key)
- converge_by("create key #{@new_resource.key}") do
- registry.create_key(@new_resource.key, @new_resource.recursive)
+ unless registry.key_exists?(current_resource.key)
+ converge_by("create key #{new_resource.key}") do
+ registry.create_key(new_resource.key, new_resource.recursive)
end
end
- @new_resource.unscrubbed_values.each do |value|
+ new_resource.unscrubbed_values.each do |value|
if @name_hash.has_key?(value[:name].downcase)
current_value = @name_hash[value[:name].downcase]
+ if [:dword, :dword_big_endian, :qword].include? value[:type]
+ value[:data] = value[:data].to_i
+ end
unless current_value[:type] == value[:type] && current_value[:data] == value[:data]
converge_by("set value #{value}") do
- registry.set_value(@new_resource.key, value)
+ registry.set_value(new_resource.key, value)
end
end
else
converge_by("set value #{value}") do
- registry.set_value(@new_resource.key, value)
+ registry.set_value(new_resource.key, value)
end
end
end
end
def action_create_if_missing
- unless registry.key_exists?(@new_resource.key)
- converge_by("create key #{@new_resource.key}") do
- registry.create_key(@new_resource.key, @new_resource.recursive)
+ unless registry.key_exists?(new_resource.key)
+ converge_by("create key #{new_resource.key}") do
+ registry.create_key(new_resource.key, new_resource.recursive)
end
end
- @new_resource.unscrubbed_values.each do |value|
+ new_resource.unscrubbed_values.each do |value|
unless @name_hash.has_key?(value[:name].downcase)
converge_by("create value #{value}") do
- registry.set_value(@new_resource.key, value)
+ registry.set_value(new_resource.key, value)
end
end
end
end
def action_delete
- if registry.key_exists?(@new_resource.key)
- @new_resource.unscrubbed_values.each do |value|
+ if registry.key_exists?(new_resource.key)
+ new_resource.unscrubbed_values.each do |value|
if @name_hash.has_key?(value[:name].downcase)
converge_by("delete value #{value}") do
- registry.delete_value(@new_resource.key, value)
+ registry.delete_value(new_resource.key, value)
end
end
end
@@ -143,9 +170,9 @@ class Chef
end
def action_delete_key
- if registry.key_exists?(@new_resource.key)
- converge_by("delete key #{@new_resource.key}") do
- registry.delete_key(@new_resource.key, @new_resource.recursive)
+ if registry.key_exists?(new_resource.key)
+ converge_by("delete key #{new_resource.key}") do
+ registry.delete_key(new_resource.key, new_resource.recursive)
end
end
end
diff --git a/lib/chef/provider/remote_directory.rb b/lib/chef/provider/remote_directory.rb
index 3c1c50b963..d2f90d233b 100644
--- a/lib/chef/provider/remote_directory.rb
+++ b/lib/chef/provider/remote_directory.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,17 @@
# limitations under the License.
#
-require 'chef/provider/directory'
-require 'chef/resource/file'
-require 'chef/resource/directory'
-require 'chef/resource/cookbook_file'
-require 'chef/mixin/file_class'
-require 'chef/platform/query_helpers'
-require 'chef/util/path_helper'
-require 'chef/deprecation/warnings'
-require 'chef/deprecation/provider/remote_directory'
+require "chef/provider/directory"
+require "chef/resource/file"
+require "chef/resource/directory"
+require "chef/resource/cookbook_file"
+require "chef/mixin/file_class"
+require "chef/platform/query_helpers"
+require "chef/util/path_helper"
+require "chef/deprecation/warnings"
+require "chef/deprecation/provider/remote_directory"
-require 'forwardable'
+require "forwardable"
class Chef
class Provider
@@ -36,9 +36,9 @@ class Chef
provides :remote_directory
- def_delegators :@new_resource, :purge, :path, :source, :cookbook, :cookbook_name
- def_delegators :@new_resource, :files_rights, :files_mode, :files_group, :files_owner, :files_backup
- def_delegators :@new_resource, :rights, :mode, :group, :owner
+ def_delegators :new_resource, :purge, :path, :source, :cookbook, :cookbook_name
+ def_delegators :new_resource, :files_rights, :files_mode, :files_group, :files_owner, :files_backup
+ def_delegators :new_resource, :rights, :mode, :group, :owner
# The overwrite property on the resource. Delegates to new_resource but can be mutated.
#
@@ -104,9 +104,9 @@ class Chef
#
def purge_unmanaged_files
if purge
- Dir.glob(::File.join(Chef::Util::PathHelper.escape_glob(path), '**', '*'), ::File::FNM_DOTMATCH).sort!.reverse!.each do |file|
+ Dir.glob(::File.join(Chef::Util::PathHelper.escape_glob_dir(path), "**", "*"), ::File::FNM_DOTMATCH).sort!.reverse!.each do |file|
# skip '.' and '..'
- next if ['.','..'].include?(Pathname.new(file).basename().to_s)
+ next if [".", ".."].include?(Pathname.new(file).basename().to_s)
# Clean the path. This is required because of the ::File.join
file = Chef::Util::PathHelper.cleanpath(file)
@@ -209,6 +209,8 @@ class Chef
def cookbook_file_resource(target_path, relative_source_path)
res = Chef::Resource::CookbookFile.new(target_path, run_context)
res.cookbook_name = resource_cookbook
+ # Set the sensitivity level
+ res.sensitive(new_resource.sensitive)
res.source(::File.join(source, relative_source_path))
if Chef::Platform.windows? && files_rights
files_rights.each_pair do |permission, *args|
@@ -251,7 +253,7 @@ class Chef
# Windows will handle inheritance.
if dir == path
rights.each do |r|
- r = r.dup # do not update the new_resource
+ r = r.dup # do not update the new_resource
permissions = r.delete(:permissions)
principals = r.delete(:principals)
res.rights(permissions, principals, r)
diff --git a/lib/chef/provider/remote_file.rb b/lib/chef/provider/remote_file.rb
index c4643edc0b..05e213e842 100644
--- a/lib/chef/provider/remote_file.rb
+++ b/lib/chef/provider/remote_file.rb
@@ -1,7 +1,7 @@
#
# Author:: Jesse Campbell (<hikeit@gmail.com>)
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
# limitations under the License.
#
-require 'chef/provider/file'
-require 'chef/deprecation/provider/remote_file'
-require 'chef/deprecation/warnings'
+require "chef/provider/file"
+require "chef/deprecation/provider/remote_file"
+require "chef/deprecation/warnings"
class Chef
class Provider
@@ -36,15 +36,15 @@ class Chef
end
def load_current_resource
- @current_resource = Chef::Resource::RemoteFile.new(@new_resource.name)
+ @current_resource = Chef::Resource::RemoteFile.new(new_resource.name)
super
end
private
def managing_content?
- return true if @new_resource.checksum
- return true if !@new_resource.source.nil? && @action != :create_if_missing
+ return true if new_resource.checksum
+ return true if !new_resource.source.nil? && @action != :create_if_missing
false
end
diff --git a/lib/chef/provider/remote_file/cache_control_data.rb b/lib/chef/provider/remote_file/cache_control_data.rb
index f9b729362c..8d7de5c370 100644
--- a/lib/chef/provider/remote_file/cache_control_data.rb
+++ b/lib/chef/provider/remote_file/cache_control_data.rb
@@ -1,9 +1,9 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
# Author:: Jesse Campbell (<hikeit@gmail.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Jesse Campbell
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,11 +19,11 @@
# limitations under the License.
#
-require 'stringio'
-require 'chef/file_cache'
-require 'chef/json_compat'
-require 'chef/digester'
-require 'chef/exceptions'
+require "stringio"
+require "chef/file_cache"
+require "chef/json_compat"
+require "chef/digester"
+require "chef/exceptions"
class Chef
class Provider
@@ -96,7 +96,7 @@ class Chef
end
def validate!(current_copy_checksum)
- if current_copy_checksum.nil? or checksum != current_copy_checksum
+ if current_copy_checksum.nil? || checksum != current_copy_checksum
reset!
false
else
@@ -145,18 +145,50 @@ class Chef
end
def load_json_data
- Chef::FileCache.load("remote_file/#{sanitized_cache_file_basename}")
+ path = sanitized_cache_file_path(sanitized_cache_file_basename)
+ if Chef::FileCache.has_key?(path)
+ Chef::FileCache.load(path)
+ else
+ old_path = sanitized_cache_file_path(sanitized_cache_file_basename_md5)
+ if Chef::FileCache.has_key?(old_path)
+ # We found an old cache control data file. We started using sha256 instead of md5
+ # to name these. Upgrade the file to the new name.
+ Chef::Log.debug("Found old cache control data file at #{old_path}. Moving to #{path}.")
+ Chef::FileCache.load(old_path).tap do |data|
+ Chef::FileCache.store(path, data)
+ Chef::FileCache.delete(old_path)
+ end
+ else
+ raise Chef::Exceptions::FileNotFound
+ end
+ end
end
- def sanitized_cache_file_basename
+ def sanitized_cache_file_path(basename)
+ "remote_file/#{basename}"
+ end
+
+ def scrubbed_uri
# Scrub and truncate in accordance with the goals of keeping the name
# human-readable but within the bounds of local file system
# path length limits
- scrubbed_uri = uri.gsub(/\W/, '_')[0..63]
+ uri.gsub(/\W/, "_")[0..63]
+ end
+
+ def sanitized_cache_file_basename
+ uri_sha2 = Chef::Digester.instance.generate_checksum(StringIO.new(uri))
+ cache_file_basename(uri_sha2[0, 32])
+ end
+
+ def sanitized_cache_file_basename_md5
+ # Old way of creating the file basename
uri_md5 = Chef::Digester.instance.generate_md5_checksum(StringIO.new(uri))
- "#{scrubbed_uri}-#{uri_md5}.json"
+ cache_file_basename(uri_md5)
end
+ def cache_file_basename(checksum)
+ "#{scrubbed_uri}-#{checksum}.json"
+ end
end
end
end
diff --git a/lib/chef/provider/remote_file/content.rb b/lib/chef/provider/remote_file/content.rb
index 4f450ce333..983285307a 100644
--- a/lib/chef/provider/remote_file/content.rb
+++ b/lib/chef/provider/remote_file/content.rb
@@ -1,7 +1,7 @@
#
# Author:: Jesse Campbell (<hikeit@gmail.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
# limitations under the License.
#
-require 'uri'
-require 'tempfile'
-require 'chef/file_content_management/content_base'
-require 'chef/mixin/uris'
+require "uri"
+require "tempfile"
+require "chef/file_content_management/content_base"
+require "chef/mixin/uris"
class Chef
class Provider
@@ -49,13 +49,13 @@ class Chef
source = sources.shift
begin
uri = if Chef::Provider::RemoteFile::Fetcher.network_share?(source)
- source
- else
- as_uri(source)
- end
+ source
+ else
+ as_uri(source)
+ end
raw_file = grab_file_from_uri(uri)
- rescue SocketError, Errno::ECONNREFUSED, Errno::ENOENT, Errno::EACCES, Timeout::Error, Net::HTTPServerException, Net::HTTPFatalError, Net::FTPError => e
- Chef::Log.warn("#{@new_resource} cannot be downloaded from #{source}: #{e.to_s}")
+ rescue SocketError, Errno::ECONNREFUSED, Errno::ENOENT, Errno::EACCES, Timeout::Error, Net::HTTPServerException, Net::HTTPFatalError, Net::FTPError, Errno::ETIMEDOUT => e
+ Chef::Log.warn("#{@new_resource} cannot be downloaded from #{source}: #{e}")
if source = sources.shift
Chef::Log.info("#{@new_resource} trying to download from another mirror")
retry
diff --git a/lib/chef/provider/remote_file/fetcher.rb b/lib/chef/provider/remote_file/fetcher.rb
index 53bfe9935c..563d135d6a 100644
--- a/lib/chef/provider/remote_file/fetcher.rb
+++ b/lib/chef/provider/remote_file/fetcher.rb
@@ -1,7 +1,7 @@
#
# Author:: Jesse Campbell (<hikeit@gmail.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,6 +31,8 @@ class Chef
Chef::Provider::RemoteFile::HTTP.new(uri, new_resource, current_resource)
when "ftp"
Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource)
+ when "sftp"
+ Chef::Provider::RemoteFile::SFTP.new(uri, new_resource, current_resource)
when "file"
Chef::Provider::RemoteFile::LocalFile.new(uri, new_resource, current_resource)
else
diff --git a/lib/chef/provider/remote_file/ftp.rb b/lib/chef/provider/remote_file/ftp.rb
index 3f78286aa3..b382c20c31 100644
--- a/lib/chef/provider/remote_file/ftp.rb
+++ b/lib/chef/provider/remote_file/ftp.rb
@@ -1,6 +1,6 @@
#
# Author:: Jesse Campbell (<hikeit@gmail.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
+# Copyright:: Copyright 2013-2016, Jesse Campbell
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'uri'
-require 'tempfile'
-require 'net/ftp'
-require 'chef/provider/remote_file'
-require 'chef/file_content_management/tempfile'
+require "uri"
+require "tempfile"
+require "net/ftp"
+require "chef/provider/remote_file"
+require "chef/file_content_management/tempfile"
class Chef
class Provider
@@ -59,7 +59,7 @@ class Chef
if uri.userinfo
URI.unescape(uri.user)
else
- 'anonymous'
+ "anonymous"
end
end
@@ -94,11 +94,11 @@ class Chef
private
def with_proxy_env
- saved_socks_env = ENV['SOCKS_SERVER']
- ENV['SOCKS_SERVER'] = proxy_uri(@uri).to_s
+ saved_socks_env = ENV["SOCKS_SERVER"]
+ ENV["SOCKS_SERVER"] = proxy_uri(@uri).to_s
yield
ensure
- ENV['SOCKS_SERVER'] = saved_socks_env
+ ENV["SOCKS_SERVER"] = saved_socks_env
end
def with_connection
@@ -112,7 +112,7 @@ class Chef
def validate_typecode!
# Only support ascii and binary types
- if typecode and /\A[ai]\z/ !~ typecode
+ if typecode && /\A[ai]\z/ !~ typecode
raise ArgumentError, "invalid typecode: #{typecode.inspect}"
end
end
@@ -146,27 +146,16 @@ class Chef
tempfile
end
- #adapted from buildr/lib/buildr/core/transports.rb via chef/rest/rest_client.rb
def proxy_uri(uri)
- proxy = Chef::Config["ftp_proxy"]
- proxy = URI.parse(proxy) if String === proxy
- if Chef::Config["ftp_proxy_user"]
- proxy.user = Chef::Config["ftp_proxy_user"]
- end
- if Chef::Config["ftp_proxy_pass"]
- proxy.password = Chef::Config["ftp_proxy_pass"]
- end
- excludes = Chef::Config[:no_proxy].to_s.split(/\s*,\s*/).compact
- excludes = excludes.map { |exclude| exclude =~ /:\d+$/ ? exclude : "#{exclude}:*" }
- return proxy unless excludes.any? { |exclude| File.fnmatch(exclude, "#{host}:#{port}") }
+ Chef::Config.proxy_uri("ftp", hostname, port)
end
def parse_path
- path = uri.path.sub(%r{\A/}, '%2F') # re-encode the beginning slash because uri library decodes it.
+ path = uri.path.sub(%r{\A/}, "%2F") # re-encode the beginning slash because uri library decodes it.
directories = path.split(%r{/}, -1)
- directories.each {|d|
+ directories.each do |d|
d.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/) { [$1].pack("H2") }
- }
+ end
unless filename = directories.pop
raise ArgumentError, "no filename: #{path.inspect}"
end
diff --git a/lib/chef/provider/remote_file/http.rb b/lib/chef/provider/remote_file/http.rb
index e1f1cb2da7..ad044f9e3c 100644
--- a/lib/chef/provider/remote_file/http.rb
+++ b/lib/chef/provider/remote_file/http.rb
@@ -1,7 +1,7 @@
#
# Author:: Jesse Campbell (<hikeit@gmail.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Jesse Campbell
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
# limitations under the License.
#
-require 'chef/http/simple'
-require 'chef/digester'
-require 'chef/provider/remote_file'
-require 'chef/provider/remote_file/cache_control_data'
+require "chef/http/simple"
+require "chef/digester"
+require "chef/provider/remote_file"
+require "chef/provider/remote_file/cache_control_data"
class Chef
class Provider
@@ -39,16 +39,20 @@ class Chef
@current_resource = current_resource
end
+ def events
+ new_resource.events
+ end
+
def headers
conditional_get_headers.merge(new_resource.headers)
end
def conditional_get_headers
cache_control_headers = {}
- if last_modified = cache_control_data.mtime and want_mtime_cache_control?
+ if (last_modified = cache_control_data.mtime) && want_mtime_cache_control?
cache_control_headers["if-modified-since"] = last_modified
end
- if etag = cache_control_data.etag and want_etag_cache_control?
+ if (etag = cache_control_data.etag) && want_etag_cache_control?
cache_control_headers["if-none-match"] = etag
end
Chef::Log.debug("Cache control headers: #{cache_control_headers.inspect}")
@@ -57,7 +61,13 @@ class Chef
def fetch
http = Chef::HTTP::Simple.new(uri, http_client_opts)
- tempfile = http.streaming_request(uri, headers)
+ if want_progress?
+ tempfile = http.streaming_request_with_progress(uri, headers) do |size, total|
+ events.resource_update_progress(new_resource, size, total, progress_interval)
+ end
+ else
+ tempfile = http.streaming_request(uri, headers)
+ end
if tempfile
update_cache_control_data(tempfile, http.last_response)
tempfile.close
@@ -78,6 +88,14 @@ class Chef
@cache_control_data ||= CacheControlData.load_and_validate(uri, current_resource.checksum)
end
+ def want_progress?
+ events.formatter? && (Chef::Config[:show_download_progress] || !!new_resource.show_progress)
+ end
+
+ def progress_interval
+ Chef::Config[:download_progress_interval]
+ end
+
def want_mtime_cache_control?
new_resource.use_last_modified
end
@@ -87,15 +105,15 @@ class Chef
end
def last_modified_time_from(response)
- response['last_modified'] || response['date']
+ response["last_modified"] || response["date"]
end
def etag_from(response)
- response['etag']
+ response["etag"]
end
def http_client_opts
- opts={}
+ opts = {}
# CHEF-3140
# 1. If it's already compressed, trying to compress it more will
# probably be counter-productive.
diff --git a/lib/chef/provider/remote_file/local_file.rb b/lib/chef/provider/remote_file/local_file.rb
index 026206b64e..613db02337 100644
--- a/lib/chef/provider/remote_file/local_file.rb
+++ b/lib/chef/provider/remote_file/local_file.rb
@@ -1,6 +1,6 @@
#
# Author:: Jesse Campbell (<hikeit@gmail.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
+# Copyright:: Copyright 2013-2016, Jesse Campbell
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'uri'
-require 'tempfile'
-require 'chef/provider/remote_file'
+require "uri"
+require "tempfile"
+require "chef/provider/remote_file"
class Chef
class Provider
@@ -35,7 +35,7 @@ class Chef
# CHEF-4472: Remove the leading slash from windows paths that we receive from a file:// URI
def fix_windows_path(path)
- path.gsub(/^\/([a-zA-Z]:)/,'\1')
+ path.gsub(/^\/([a-zA-Z]:)/, '\1')
end
def source_path
diff --git a/lib/chef/provider/remote_file/network_file.rb b/lib/chef/provider/remote_file/network_file.rb
index 093a388d2a..44046132a9 100644
--- a/lib/chef/provider/remote_file/network_file.rb
+++ b/lib/chef/provider/remote_file/network_file.rb
@@ -1,6 +1,6 @@
#
# Author:: Jesse Campbell (<hikeit@gmail.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
+# Copyright:: Copyright 2013-2016, Jesse Campbell
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'uri'
-require 'tempfile'
-require 'chef/provider/remote_file'
+require "uri"
+require "tempfile"
+require "chef/provider/remote_file"
class Chef
class Provider
diff --git a/lib/chef/provider/remote_file/sftp.rb b/lib/chef/provider/remote_file/sftp.rb
new file mode 100644
index 0000000000..21c5c4ca04
--- /dev/null
+++ b/lib/chef/provider/remote_file/sftp.rb
@@ -0,0 +1,105 @@
+#
+# Author:: John Kerry (<john@kerryhouse.net>)
+# Copyright:: Copyright 2013-2016, John Kerry
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "uri"
+require "tempfile"
+require "net/sftp"
+require "chef/provider/remote_file"
+require "chef/file_content_management/tempfile"
+
+class Chef
+ class Provider
+ class RemoteFile
+ class SFTP
+ attr_reader :uri
+ attr_reader :new_resource
+ attr_reader :current_resource
+
+ def initialize(uri, new_resource, current_resource)
+ @uri = uri
+ @new_resource = new_resource
+ @current_resource = current_resource
+ validate_path!
+ validate_userinfo!
+ end
+
+ def hostname
+ @uri.host
+ end
+
+ def port
+ @uri.port
+ end
+
+ def user
+ URI.unescape(uri.user)
+ end
+
+ def fetch
+ get
+ end
+
+ private
+
+ def sftp
+ host = port ? "#{hostname}:#{port}" : hostname
+ @sftp ||= Net::SFTP.start(host, user, :password => pass)
+ end
+
+ def pass
+ URI.unescape(uri.password)
+ end
+
+ def validate_path!
+ path = uri.path.sub(%r{\A/}, "%2F") # re-encode the beginning slash because uri library decodes it.
+ directories = path.split(%r{/}, -1)
+ directories.each do |d|
+ d.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/) { [$1].pack("H2") }
+ end
+ unless filename = directories.pop
+ raise ArgumentError, "no filename: #{path.inspect}"
+ end
+ if filename.length == 0 || filename.end_with?( "/" )
+ raise ArgumentError, "no filename: #{path.inspect}"
+ end
+ end
+
+ def validate_userinfo!
+ if uri.userinfo
+ unless uri.user
+ raise ArgumentError, "no user name provided in the sftp URI"
+ end
+ unless uri.password
+ raise ArgumentError, "no password provided in the sftp URI"
+ end
+ else
+ raise ArgumentError, "no userinfo provided in the sftp URI"
+ end
+ end
+
+ def get
+ tempfile =
+ Chef::FileContentManagement::Tempfile.new(@new_resource).tempfile
+ sftp.download!(uri.path, tempfile.path)
+ tempfile.close if tempfile
+ tempfile
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/route.rb b/lib/chef/provider/route.rb
index 72a5029a94..5e20fdf11e 100644
--- a/lib/chef/provider/route.rb
+++ b/lib/chef/provider/route.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org), Jesse Nelson (spheromak@gmail.com)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,94 +16,97 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/mixin/command'
-require 'chef/provider'
-require 'ipaddr'
-
-class Chef::Provider::Route < Chef::Provider
- include Chef::Mixin::Command
-
- provides :route
-
- attr_accessor :is_running
-
- MASK = {'0.0.0.0' => '0',
- '128.0.0.0' => '1',
- '192.0.0.0' => '2',
- '224.0.0.0' => '3',
- '240.0.0.0' => '4',
- '248.0.0.0' => '5',
- '252.0.0.0' => '6',
- '254.0.0.0' => '7',
- '255.0.0.0' => '8',
- '255.128.0.0' => '9',
- '255.192.0.0' => '10',
- '255.224.0.0' => '11',
- '255.240.0.0' => '12',
- '255.248.0.0' => '13',
- '255.252.0.0' => '14',
- '255.254.0.0' => '15',
- '255.255.0.0' => '16',
- '255.255.128.0' => '17',
- '255.255.192.0' => '18',
- '255.255.224.0' => '19',
- '255.255.240.0' => '20',
- '255.255.248.0' => '21',
- '255.255.252.0' => '22',
- '255.255.254.0' => '23',
- '255.255.255.0' => '24',
- '255.255.255.128' => '25',
- '255.255.255.192' => '26',
- '255.255.255.224' => '27',
- '255.255.255.240' => '28',
- '255.255.255.248' => '29',
- '255.255.255.252' => '30',
- '255.255.255.254' => '31',
- '255.255.255.255' => '32' }
-
- def hex2ip(hex_data)
- # Cleanup hex data
- hex_ip = hex_data.to_s.downcase.gsub(/[^0-9a-f]/, '')
-
- # Check hex data format (IP is a 32bit integer, so should be 8 chars long)
- return nil if hex_ip.length != hex_data.length || hex_ip.length != 8
-
- # Extract octets from hex data
- octets = hex_ip.scan(/../).reverse.collect { |octet| [octet].pack('H2').unpack("C").first }
-
- # Validate IP
- ip = octets.join('.')
- begin
- IPAddr.new(ip, Socket::AF_INET).to_s
- rescue ArgumentError
- Chef::Log.debug("Invalid IP address data: hex=#{hex_ip}, ip=#{ip}")
- return nil
+require "chef/log"
+require "chef/mixin/command"
+require "chef/provider"
+require "ipaddr"
+
+class Chef
+ class Provider
+ class Route < Chef::Provider
+ include Chef::Mixin::Command
+
+ provides :route
+
+ attr_accessor :is_running
+
+ MASK = { "0.0.0.0" => "0",
+ "128.0.0.0" => "1",
+ "192.0.0.0" => "2",
+ "224.0.0.0" => "3",
+ "240.0.0.0" => "4",
+ "248.0.0.0" => "5",
+ "252.0.0.0" => "6",
+ "254.0.0.0" => "7",
+ "255.0.0.0" => "8",
+ "255.128.0.0" => "9",
+ "255.192.0.0" => "10",
+ "255.224.0.0" => "11",
+ "255.240.0.0" => "12",
+ "255.248.0.0" => "13",
+ "255.252.0.0" => "14",
+ "255.254.0.0" => "15",
+ "255.255.0.0" => "16",
+ "255.255.128.0" => "17",
+ "255.255.192.0" => "18",
+ "255.255.224.0" => "19",
+ "255.255.240.0" => "20",
+ "255.255.248.0" => "21",
+ "255.255.252.0" => "22",
+ "255.255.254.0" => "23",
+ "255.255.255.0" => "24",
+ "255.255.255.128" => "25",
+ "255.255.255.192" => "26",
+ "255.255.255.224" => "27",
+ "255.255.255.240" => "28",
+ "255.255.255.248" => "29",
+ "255.255.255.252" => "30",
+ "255.255.255.254" => "31",
+ "255.255.255.255" => "32" }.freeze
+
+ def hex2ip(hex_data)
+ # Cleanup hex data
+ hex_ip = hex_data.to_s.downcase.gsub(/[^0-9a-f]/, "")
+
+ # Check hex data format (IP is a 32bit integer, so should be 8 chars long)
+ return nil if hex_ip.length != hex_data.length || hex_ip.length != 8
+
+ # Extract octets from hex data
+ octets = hex_ip.scan(/../).reverse.collect { |octet| [octet].pack("H2").unpack("C").first }
+
+ # Validate IP
+ ip = octets.join(".")
+ begin
+ IPAddr.new(ip, Socket::AF_INET).to_s
+ rescue ArgumentError
+ Chef::Log.debug("Invalid IP address data: hex=#{hex_ip}, ip=#{ip}")
+ return nil
+ end
end
- end
- def whyrun_supported?
- true
- end
+ def whyrun_supported?
+ true
+ end
- def load_current_resource
- self.is_running = false
+ def load_current_resource
+ self.is_running = false
- # cidr or quad dot mask
- if @new_resource.netmask
- new_ip = IPAddr.new("#{@new_resource.target}/#{@new_resource.netmask}")
- else
- new_ip = IPAddr.new(@new_resource.target)
- end
+ # cidr or quad dot mask
+ new_ip = if new_resource.netmask
+ IPAddr.new("#{new_resource.target}/#{new_resource.netmask}")
+ else
+ IPAddr.new(new_resource.target)
+ end
+
+ # For linux, we use /proc/net/route file to read proc table info
+ return if node[:os] != "linux"
- # For linux, we use /proc/net/route file to read proc table info
- if node[:os] == "linux"
route_file = ::File.open("/proc/net/route", "r")
# Read all routes
while (line = route_file.gets)
# Get all the fields for a route
- iface,destination,gateway,flags,refcnt,use,metric,mask,mtu,window,irtt = line.split
+ _, destination, gateway, _, _, _, _, mask = line.split
# Convert hex-encoded values to quad-dotted notation (e.g. 0064A8C0 => 192.168.100.0)
destination = hex2ip(destination)
@@ -112,7 +115,7 @@ class Chef::Provider::Route < Chef::Provider
# Skip formatting lines (header, etc)
next unless destination && gateway && mask
- Chef::Log.debug("#{@new_resource} system has route: dest=#{destination} mask=#{mask} gw=#{gateway}")
+ Chef::Log.debug("#{new_resource} system has route: dest=#{destination} mask=#{mask} gw=#{gateway}")
# check if what were trying to configure is already there
# use an ipaddr object with ip/mask this way we can have
@@ -120,110 +123,109 @@ class Chef::Provider::Route < Chef::Provider
# expanding bitmask by hand.
#
running_ip = IPAddr.new("#{destination}/#{mask}")
- Chef::Log.debug("#{@new_resource} new ip: #{new_ip.inspect} running ip: #{running_ip.inspect}")
- self.is_running = true if running_ip == new_ip && gateway == @new_resource.gateway
+ Chef::Log.debug("#{new_resource} new ip: #{new_ip.inspect} running ip: #{running_ip.inspect}")
+ self.is_running = true if running_ip == new_ip && gateway == new_resource.gateway
end
route_file.close
end
- end
- def action_add
- # check to see if load_current_resource found the route
- if is_running
- Chef::Log.debug("#{@new_resource} route already active - nothing to do")
- else
- command = generate_command(:add)
- converge_by ("run #{ command } to add route") do
- run_command( :command => command )
- Chef::Log.info("#{@new_resource} added")
+ def action_add
+ # check to see if load_current_resource found the route
+ if is_running
+ Chef::Log.debug("#{new_resource} route already active - nothing to do")
+ else
+ command = generate_command(:add)
+ converge_by("run #{command.join(' ')} to add route") do
+ shell_out_compact!(command)
+ Chef::Log.info("#{new_resource} added")
+ end
end
- end
- #for now we always write the file (ugly but its what it is)
- generate_config
- end
+ # for now we always write the file (ugly but its what it is)
+ generate_config
+ end
- def action_delete
- if is_running
- command = generate_command(:delete)
- converge_by ("run #{ command } to delete route ") do
- run_command( :command => command )
- Chef::Log.info("#{@new_resource} removed")
+ def action_delete
+ if is_running
+ command = generate_command(:delete)
+ converge_by("run #{command.join(' ')} to delete route ") do
+ shell_out_compact!(command)
+ Chef::Log.info("#{new_resource} removed")
+ end
+ else
+ Chef::Log.debug("#{new_resource} route does not exist - nothing to do")
end
- else
- Chef::Log.debug("#{@new_resource} route does not exist - nothing to do")
- end
- #for now we always write the file (ugly but its what it is)
- generate_config
- end
+ # for now we always write the file (ugly but its what it is)
+ generate_config
+ end
- def generate_config
- conf = Hash.new
- case node[:platform]
- when "centos", "redhat", "fedora"
- # walk the collection
- run_context.resource_collection.each do |resource|
- if resource.is_a? Chef::Resource::Route
+ def generate_config
+ conf = {}
+ case node[:platform]
+ when "centos", "redhat", "fedora"
+ # walk the collection
+ run_context.resource_collection.each do |resource|
+ next unless resource.is_a? Chef::Resource::Route
# default to eth0
- if resource.device
- dev = resource.device
- else
- dev = "eth0"
- end
+ dev = if resource.device
+ resource.device
+ else
+ "eth0"
+ end
- conf[dev] = String.new if conf[dev].nil?
+ conf[dev] = "" if conf[dev].nil?
case @action
when :add
- conf[dev] << config_file_contents(:add, :target => resource.target, :netmask => resource.netmask, :gateway => resource.gateway)
+ conf[dev] << config_file_contents(:add, target: resource.target, netmask: resource.netmask, gateway: resource.gateway) if resource.action == [:add]
when :delete
# need to do this for the case when the last route on an int
# is removed
conf[dev] << config_file_contents(:delete)
end
end
- end
- conf.each do |k, v|
- network_file_name = "/etc/sysconfig/network-scripts/route-#{k}"
- converge_by ("write route route.#{k}\n#{conf[k]} to #{ network_file_name }") do
- network_file = ::File.new(network_file_name, "w")
- network_file.puts(conf[k])
- Chef::Log.debug("#{@new_resource} writing route.#{k}\n#{conf[k]}")
- network_file.close
+ conf.each do |k, v|
+ network_file_name = "/etc/sysconfig/network-scripts/route-#{k}"
+ converge_by("write route route.#{k}\n#{conf[k]} to #{network_file_name}") do
+ network_file = ::File.new(network_file_name, "w")
+ network_file.puts(conf[k])
+ Chef::Log.debug("#{new_resource} writing route.#{k}\n#{conf[k]}")
+ network_file.close
+ end
end
end
end
- end
- def generate_command(action)
- common_route_items = ''
- common_route_items << "/#{MASK[@new_resource.netmask.to_s]}" if @new_resource.netmask
- common_route_items << " via #{@new_resource.gateway} " if @new_resource.gateway
-
- case action
- when :add
- command = "ip route replace #{@new_resource.target}"
- command << common_route_items
- command << " dev #{@new_resource.device} " if @new_resource.device
- when :delete
- command = "ip route delete #{@new_resource.target}"
- command << common_route_items
+ def generate_command(action)
+ target = new_resource.target
+ target = "#{target}/#{MASK[new_resource.netmask.to_s]}" if new_resource.netmask
+
+ case action
+ when :add
+ command = [ "ip", "route", "replace", target ]
+ command += [ "via", new_resource.gateway ] if new_resource.gateway
+ command += [ "dev", new_resource.device ] if new_resource.device
+ when :delete
+ command = [ "ip", "route", "delete", target ]
+ command += [ "via", new_resource.gateway ] if new_resource.gateway
+ end
+
+ command
end
- return command
- end
+ def config_file_contents(action, options = {})
+ content = ""
+ case action
+ when :add
+ content << (options[:target]).to_s
+ content << "/#{MASK[options[:netmask].to_s]}" if options[:netmask]
+ content << " via #{options[:gateway]}" if options[:gateway]
+ content << "\n"
+ end
- def config_file_contents(action, options={})
- content = ''
- case action
- when :add
- content << "#{options[:target]}"
- content << "/#{options[:netmask]}" if options[:netmask]
- content << " via #{options[:gateway]}" if options[:gateway]
- content << "\n"
+ content
end
-
- return content
end
+ end
end
diff --git a/lib/chef/provider/ruby_block.rb b/lib/chef/provider/ruby_block.rb
index eb93fd5708..c44b776661 100644
--- a/lib/chef/provider/ruby_block.rb
+++ b/lib/chef/provider/ruby_block.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,9 +31,9 @@ class Chef
end
def action_run
- converge_by("execute the ruby block #{@new_resource.name}") do
- @new_resource.block.call
- Chef::Log.info("#{@new_resource} called")
+ converge_by("execute the ruby block #{new_resource.name}") do
+ new_resource.block.call
+ Chef::Log.info("#{new_resource} called")
end
end
diff --git a/lib/chef/provider/script.rb b/lib/chef/provider/script.rb
index e8b5235b7a..4046b7c0dd 100644
--- a/lib/chef/provider/script.rb
+++ b/lib/chef/provider/script.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,10 @@
# limitations under the License.
#
-require 'tempfile'
-require 'chef/provider/execute'
-require 'forwardable'
+require "tempfile"
+require "chef/provider/execute"
+require "chef/win32/security" if Chef::Platform.windows?
+require "forwardable"
class Chef
class Provider
@@ -27,12 +28,13 @@ class Chef
provides :bash
provides :csh
+ provides :ksh
provides :perl
provides :python
provides :ruby
provides :script
- def_delegators :@new_resource, :interpreter, :flags
+ def_delegators :new_resource, :interpreter, :flags
attr_accessor :code
@@ -49,7 +51,7 @@ class Chef
super
# @todo Chef-13: change this to an exception
if code.nil?
- Chef::Log.warn "#{@new_resource}: No code attribute was given, resource does nothing, this behavior is deprecated and will be removed in Chef-13"
+ Chef::Log.warn "#{new_resource}: No code attribute was given, resource does nothing, this behavior is deprecated and will be removed in Chef-13"
end
end
@@ -65,10 +67,45 @@ class Chef
end
def set_owner_and_group
- # FileUtils itself implements a no-op if +user+ or +group+ are nil
- # You can prove this by running FileUtils.chown(nil,nil,'/tmp/file')
- # as an unprivileged user.
- FileUtils.chown(new_resource.user, new_resource.group, script_file.path)
+ if Chef::Platform.windows?
+ # And on Windows also this is a no-op if there is no user specified.
+ grant_alternate_user_read_access
+ else
+ # FileUtils itself implements a no-op if +user+ or +group+ are nil
+ # You can prove this by running FileUtils.chown(nil,nil,'/tmp/file')
+ # as an unprivileged user.
+ FileUtils.chown(new_resource.user, new_resource.group, script_file.path)
+ end
+ end
+
+ def grant_alternate_user_read_access
+ # Do nothing if an alternate user isn't specified -- the file
+ # will already have the correct permissions for the user as part
+ # of the default ACL behavior on Windows.
+ return if new_resource.user.nil?
+
+ # Duplicate the script file's existing DACL
+ # so we can add an ACE later
+ securable_object = Chef::ReservedNames::Win32::Security::SecurableObject.new(script_file.path)
+ aces = securable_object.security_descriptor.dacl.reduce([]) { |result, current| result.push(current) }
+
+ username = new_resource.user
+
+ if new_resource.domain
+ username = new_resource.domain + '\\' + new_resource.user
+ end
+
+ # Create an ACE that allows the alternate user read access to the script
+ # file so it can be read and executed.
+ user_sid = Chef::ReservedNames::Win32::Security::SID.from_account(username)
+ read_ace = Chef::ReservedNames::Win32::Security::ACE.access_allowed(user_sid, Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE, 0)
+ aces.push(read_ace)
+ acl = Chef::ReservedNames::Win32::Security::ACL.create(aces)
+
+ # This actually applies the modified DACL to the file
+ # Use parentheses to bypass RuboCop / ChefStyle warning
+ # about useless setter
+ (securable_object.dacl = acl)
end
def script_file
diff --git a/lib/chef/provider/service.rb b/lib/chef/provider/service.rb
index e7bb2a76d7..2f08697ed7 100644
--- a/lib/chef/provider/service.rb
+++ b/lib/chef/provider/service.rb
@@ -1,6 +1,7 @@
#
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: Davide Cavalca (<dcavalca@fb.com>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +17,8 @@
# limitations under the License.
#
-require 'chef/mixin/command'
-require 'chef/provider'
+require "chef/mixin/command"
+require "chef/provider"
class Chef
class Provider
@@ -44,139 +45,188 @@ class Chef
supports[:restart] = false if supports[:restart].nil?
end
- def load_new_resource_state
- # If the user didn't specify a change in enabled state,
- # it will be the same as the old resource
- if ( @new_resource.enabled.nil? )
- @new_resource.enabled(@current_resource.enabled)
- end
- if ( @new_resource.running.nil? )
- @new_resource.running(@current_resource.running)
- end
- end
+ # the new_resource#enabled and #running variables are not user input, but when we
+ # do (e.g.) action_enable we want to set new_resource.enabled so that the comparison
+ # between desired and current state produces the correct change in reporting.
+ # XXX?: the #nil? check below will likely fail if this is a cloned resource or if
+ # we just run multiple actions.
+ def load_new_resource_state
+ if new_resource.enabled.nil?
+ new_resource.enabled(current_resource.enabled)
+ end
+ if new_resource.running.nil?
+ new_resource.running(current_resource.running)
+ end
+ if new_resource.masked.nil?
+ new_resource.masked(current_resource.masked)
+ end
+ end
+
+ # subclasses should override this if they do implement user services
+ def user_services_requirements
+ requirements.assert(:all_actions) do |a|
+ a.assertion { new_resource.user.nil? }
+ a.failure_message Chef::Exceptions::UnsupportedAction, "#{self} does not support user services"
+ end
+ end
def shared_resource_requirements
+ user_services_requirements
end
def define_resource_requirements
- requirements.assert(:reload) do |a|
- a.assertion { supports[:reload] || @new_resource.reload_command }
- a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reload"
- # if a service is not declared to support reload, that won't
- # typically change during the course of a run - so no whyrun
- # alternative here.
- end
+ requirements.assert(:reload) do |a|
+ a.assertion { supports[:reload] || new_resource.reload_command }
+ a.failure_message Chef::Exceptions::UnsupportedAction, "#{self} does not support :reload"
+ # if a service is not declared to support reload, that won't
+ # typically change during the course of a run - so no whyrun
+ # alternative here.
+ end
end
def action_enable
- if @current_resource.enabled
- Chef::Log.debug("#{@new_resource} already enabled - nothing to do")
+ if current_resource.enabled
+ Chef::Log.debug("#{new_resource} already enabled - nothing to do")
else
- converge_by("enable service #{@new_resource}") do
+ converge_by("enable service #{new_resource}") do
enable_service
- Chef::Log.info("#{@new_resource} enabled")
+ Chef::Log.info("#{new_resource} enabled")
end
end
load_new_resource_state
- @new_resource.enabled(true)
+ new_resource.enabled(true)
end
def action_disable
- if @current_resource.enabled
- converge_by("disable service #{@new_resource}") do
+ if current_resource.enabled
+ converge_by("disable service #{new_resource}") do
disable_service
- Chef::Log.info("#{@new_resource} disabled")
+ Chef::Log.info("#{new_resource} disabled")
end
else
- Chef::Log.debug("#{@new_resource} already disabled - nothing to do")
+ Chef::Log.debug("#{new_resource} already disabled - nothing to do")
end
load_new_resource_state
- @new_resource.enabled(false)
+ new_resource.enabled(false)
+ end
+
+ def action_mask
+ if current_resource.masked
+ Chef::Log.debug("#{new_resource} already masked - nothing to do")
+ else
+ converge_by("mask service #{new_resource}") do
+ mask_service
+ Chef::Log.info("#{new_resource} masked")
+ end
+ end
+ load_new_resource_state
+ new_resource.masked(true)
+ end
+
+ def action_unmask
+ if current_resource.masked
+ converge_by("unmask service #{new_resource}") do
+ unmask_service
+ Chef::Log.info("#{new_resource} unmasked")
+ end
+ else
+ Chef::Log.debug("#{new_resource} already unmasked - nothing to do")
+ end
+ load_new_resource_state
+ new_resource.masked(false)
end
def action_start
- unless @current_resource.running
- converge_by("start service #{@new_resource}") do
+ unless current_resource.running
+ converge_by("start service #{new_resource}") do
start_service
- Chef::Log.info("#{@new_resource} started")
+ Chef::Log.info("#{new_resource} started")
end
else
- Chef::Log.debug("#{@new_resource} already running - nothing to do")
+ Chef::Log.debug("#{new_resource} already running - nothing to do")
end
load_new_resource_state
- @new_resource.running(true)
+ new_resource.running(true)
end
def action_stop
- if @current_resource.running
- converge_by("stop service #{@new_resource}") do
+ if current_resource.running
+ converge_by("stop service #{new_resource}") do
stop_service
- Chef::Log.info("#{@new_resource} stopped")
+ Chef::Log.info("#{new_resource} stopped")
end
else
- Chef::Log.debug("#{@new_resource} already stopped - nothing to do")
+ Chef::Log.debug("#{new_resource} already stopped - nothing to do")
end
load_new_resource_state
- @new_resource.running(false)
+ new_resource.running(false)
end
def action_restart
- converge_by("restart service #{@new_resource}") do
+ converge_by("restart service #{new_resource}") do
restart_service
- Chef::Log.info("#{@new_resource} restarted")
+ Chef::Log.info("#{new_resource} restarted")
end
load_new_resource_state
- @new_resource.running(true)
+ new_resource.running(true)
end
def action_reload
- if @current_resource.running
- converge_by("reload service #{@new_resource}") do
+ if current_resource.running
+ converge_by("reload service #{new_resource}") do
reload_service
- Chef::Log.info("#{@new_resource} reloaded")
+ Chef::Log.info("#{new_resource} reloaded")
end
end
load_new_resource_state
end
def enable_service
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :enable"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :enable"
end
def disable_service
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :disable"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :disable"
+ end
+
+ def mask_service
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :mask"
+ end
+
+ def unmask_service
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :unmask"
end
def start_service
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :start"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :start"
end
def stop_service
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :stop"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :stop"
end
def restart_service
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :restart"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :restart"
end
def reload_service
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reload"
+ raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :reload"
end
protected
def default_init_command
- if @new_resource.init_command
- @new_resource.init_command
- elsif self.instance_variable_defined?(:@init_command)
+ if new_resource.init_command
+ new_resource.init_command
+ elsif instance_variable_defined?(:@init_command)
@init_command
end
end
def custom_command_for_action?(action)
method_name = "#{action}_command".to_sym
- @new_resource.respond_to?(method_name) &&
- !!@new_resource.send(method_name)
+ new_resource.respond_to?(method_name) &&
+ !!new_resource.send(method_name)
end
module ServicePriorityInit
@@ -189,20 +239,20 @@ class Chef
# Linux
#
- require 'chef/chef_class'
- require 'chef/provider/service/systemd'
- require 'chef/provider/service/insserv'
- require 'chef/provider/service/redhat'
- require 'chef/provider/service/arch'
- require 'chef/provider/service/gentoo'
- require 'chef/provider/service/upstart'
- require 'chef/provider/service/debian'
- require 'chef/provider/service/invokercd'
-
- Chef.set_provider_priority_array :service, [ Systemd, Arch ], platform_family: 'arch'
- Chef.set_provider_priority_array :service, [ Systemd, Gentoo ], platform_family: 'gentoo'
- Chef.set_provider_priority_array :service, [ Systemd, Upstart, Insserv, Debian, Invokercd ], platform_family: 'debian'
- Chef.set_provider_priority_array :service, [ Systemd, Insserv, Redhat ], platform_family: %w(rhel fedora suse)
+ require "chef/chef_class"
+ require "chef/provider/service/systemd"
+ require "chef/provider/service/insserv"
+ require "chef/provider/service/redhat"
+ require "chef/provider/service/arch"
+ require "chef/provider/service/gentoo"
+ require "chef/provider/service/upstart"
+ require "chef/provider/service/debian"
+ require "chef/provider/service/invokercd"
+
+ Chef.set_provider_priority_array :service, [ Systemd, Arch ], platform_family: "arch"
+ Chef.set_provider_priority_array :service, [ Systemd, Gentoo ], platform_family: "gentoo"
+ Chef.set_provider_priority_array :service, [ Systemd, Upstart, Insserv, Debian, Invokercd ], platform_family: "debian"
+ Chef.set_provider_priority_array :service, [ Systemd, Insserv, Redhat ], platform_family: %w{rhel fedora suse}
end
end
end
diff --git a/lib/chef/provider/service/aix.rb b/lib/chef/provider/service/aix.rb
index 0c95ce2c8e..201f9ff5f9 100644
--- a/lib/chef/provider/service/aix.rb
+++ b/lib/chef/provider/service/aix.rb
@@ -1,6 +1,6 @@
#
# Author:: kaustubh (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/provider/service'
+require "chef/provider/service"
class Chef
class Provider
@@ -90,6 +90,7 @@ class Chef
end
protected
+
def determine_current_status!
Chef::Log.debug "#{@new_resource} using lssrc to check the status"
begin
@@ -98,7 +99,7 @@ class Chef
@current_resource.running false
else
service = shell_out!("lssrc -s #{@new_resource.service_name}").stdout
- if service.split(' ').last == 'active'
+ if service.split(" ").last == "active"
@current_resource.running true
else
@current_resource.running false
@@ -126,4 +127,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/service/aixinit.rb b/lib/chef/provider/service/aixinit.rb
index 19beac79f0..73c5e07715 100644
--- a/lib/chef/provider/service/aixinit.rb
+++ b/lib/chef/provider/service/aixinit.rb
@@ -1,6 +1,6 @@
#
# Author:: kaustubh (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/provider/service/init'
+require "chef/provider/service/init"
class Chef
class Provider
@@ -44,7 +44,7 @@ class Chef
else
priority_ok = @current_resource.priority == @new_resource.priority
end
- if @current_resource.enabled and priority_ok
+ if @current_resource.enabled && priority_ok
Chef::Log.debug("#{@new_resource} already enabled - nothing to do")
else
converge_by("enable service #{@new_resource}") do
@@ -57,17 +57,17 @@ class Chef
end
def enable_service
- Dir.glob(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).each { |f| ::File.delete(f)}
+ Dir.glob(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).each { |f| ::File.delete(f) }
if @new_resource.priority.is_a? Integer
- create_symlink(2, 'S', @new_resource.priority)
+ create_symlink(2, "S", @new_resource.priority)
elsif @new_resource.priority.is_a? Hash
- @new_resource.priority.each do |level,o|
- create_symlink(level,(o[0] == :start ? 'S' : 'K'),o[1])
+ @new_resource.priority.each do |level, o|
+ create_symlink(level, (o[0] == :start ? "S" : "K"), o[1])
end
else
- create_symlink(2, 'S', '')
+ create_symlink(2, "S", "")
end
end
@@ -75,13 +75,13 @@ class Chef
Dir.glob(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).each { |f| ::File.delete(f) }
if @new_resource.priority.is_a? Integer
- create_symlink(2, 'K',100 - @new_resource.priority)
+ create_symlink(2, "K", 100 - @new_resource.priority)
elsif @new_resource.priority.is_a? Hash
- @new_resource.priority.each do |level,o|
- create_symlink(level, 'K', 100 - o[1]) if o[0] == :stop
+ @new_resource.priority.each do |level, o|
+ create_symlink(level, "K", 100 - o[1]) if o[0] == :stop
end
else
- create_symlink(2, 'K', '')
+ create_symlink(2, "K", "")
end
end
@@ -97,8 +97,8 @@ class Chef
priority = {}
files.each do |file|
- if (RC_D_SCRIPT_NAME =~ file)
- priority[2] = [($1 == "S" ? :start : :stop), ($2.empty? ? '' : $2.to_i)]
+ if RC_D_SCRIPT_NAME =~ file
+ priority[2] = [($1 == "S" ? :start : :stop), ($2.empty? ? "" : $2.to_i)]
if $1 == "S"
is_enabled = true
end
diff --git a/lib/chef/provider/service/arch.rb b/lib/chef/provider/service/arch.rb
index e7fbcc820c..e34227036a 100644
--- a/lib/chef/provider/service/arch.rb
+++ b/lib/chef/provider/service/arch.rb
@@ -1,6 +1,6 @@
#
# Author:: Jan Zimmek (<jan.zimmek@web.de>)
-# Copyright:: Copyright (c) 2010 Jan Zimmek
+# Copyright:: Copyright 2010-2016, Jan Zimmek
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/provider/service/init'
+require "chef/provider/service/init"
class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
@@ -32,8 +32,8 @@ class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
end
def load_current_resource
- raise Chef::Exceptions::Service, "Could not find /etc/rc.conf" unless ::File.exists?("/etc/rc.conf")
- raise Chef::Exceptions::Service, "No DAEMONS found in /etc/rc.conf" unless ::File.read("/etc/rc.conf").match(/DAEMONS=\((.*)\)/m)
+ raise Chef::Exceptions::Service, "Could not find /etc/rc.conf" unless ::File.exists?("/etc/rc.conf")
+ raise Chef::Exceptions::Service, "No DAEMONS found in /etc/rc.conf" unless ::File.read("/etc/rc.conf") =~ /DAEMONS=\((.*)\)/m
super
@current_resource.enabled(daemons.include?(@current_resource.service_name))
@@ -49,8 +49,8 @@ class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
# )
def daemons
entries = []
- if ::File.read("/etc/rc.conf").match(/DAEMONS=\((.*)\)/m)
- entries += $1.gsub(/\\?[\r\n]/, ' ').gsub(/# *[^ ]+/,' ').split(' ') if $1.length > 0
+ if ::File.read("/etc/rc.conf") =~ /DAEMONS=\((.*)\)/m
+ entries += $1.gsub(/\\?[\r\n]/, " ").gsub(/# *[^ ]+/, " ").split(" ") if $1.length > 0
end
yield(entries) if block_given?
@@ -66,11 +66,11 @@ class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
end
end
- def enable_service()
+ def enable_service
new_daemons = []
entries = daemons
- if entries.include?(new_resource.service_name) or entries.include?("@#{new_resource.service_name}")
+ if entries.include?(new_resource.service_name) || entries.include?("@#{new_resource.service_name}")
# exists and already enabled (or already enabled as a background service)
# new_daemons += entries
else
@@ -92,7 +92,7 @@ class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
end
end
- def disable_service()
+ def disable_service
new_daemons = []
entries = daemons
@@ -100,7 +100,7 @@ class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
# exists and disabled
# new_daemons += entries
else
- if entries.include?(new_resource.service_name) or entries.include?("@#{new_resource.service_name}")
+ if entries.include?(new_resource.service_name) || entries.include?("@#{new_resource.service_name}")
# exists but enabled (or enabled as a back-ground service)
# FIXME: Does arch support !@foobar ?
entries.each do |daemon|
diff --git a/lib/chef/provider/service/debian.rb b/lib/chef/provider/service/debian.rb
index 7d23e4ac77..9d11032055 100644
--- a/lib/chef/provider/service/debian.rb
+++ b/lib/chef/provider/service/debian.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'chef/provider/service/init'
+require "chef/provider/service/init"
class Chef
class Provider
class Service
class Debian < Chef::Provider::Service::Init
- provides :service, platform_family: 'debian' do |node|
+ provides :service, platform_family: "debian" do |node|
Chef::Platform::ServiceHelpers.service_resource_providers.include?(:debian)
end
@@ -55,18 +55,18 @@ class Chef
requirements.assert(:all_actions) do |a|
a.assertion { @priority_success }
- a.failure_message Chef::Exceptions::Service, "/usr/sbin/update-rc.d -n -f #{current_resource.service_name} failed - #{@rcd_status.inspect}"
+ a.failure_message Chef::Exceptions::Service, "/usr/sbin/update-rc.d -n -f #{current_resource.service_name} failed - #{@rcd_status.inspect}"
# This can happen if the service is not yet installed,so we'll fake it.
a.whyrun ["Unable to determine priority of service, assuming service would have been correctly installed earlier in the run.",
"Assigning temporary priorities to continue.",
"If this service is not properly installed prior to this point, this will fail."] do
- temp_priorities = {"6"=>[:stop, "20"],
- "0"=>[:stop, "20"],
- "1"=>[:stop, "20"],
- "2"=>[:start, "20"],
- "3"=>[:start, "20"],
- "4"=>[:start, "20"],
- "5"=>[:start, "20"]}
+ temp_priorities = { "6" => [:stop, "20"],
+ "0" => [:stop, "20"],
+ "1" => [:stop, "20"],
+ "2" => [:start, "20"],
+ "3" => [:start, "20"],
+ "4" => [:start, "20"],
+ "5" => [:start, "20"] }
current_resource.priority(temp_priorities)
end
end
@@ -106,13 +106,13 @@ class Chef
def service_currently_enabled?(priority)
enabled = false
- priority.each { |runlevel, arguments|
+ priority.each do |runlevel, arguments|
Chef::Log.debug("#{new_resource} runlevel #{runlevel}, action #{arguments[0]}, priority #{arguments[1]}")
# if we are in a update-rc.d default startup runlevel && we start in this runlevel
- if %w[ 1 2 3 4 5 S ].include?(runlevel) && arguments[0] == :start
+ if %w{ 1 2 3 4 5 S }.include?(runlevel) && arguments[0] == :start
enabled = true
end
- }
+ end
enabled
end
@@ -124,7 +124,7 @@ class Chef
else
priority_ok = @current_resource.priority == new_resource.priority
end
- if current_resource.enabled and priority_ok
+ if current_resource.enabled && priority_ok
Chef::Log.debug("#{new_resource} already enabled - nothing to do")
else
converge_by("enable service #{new_resource}") do
@@ -148,7 +148,6 @@ class Chef
shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} remove")
shell_out!("/usr/sbin/update-rc.d #{new_resource.service_name} defaults")
end
-
end
def disable_service
diff --git a/lib/chef/provider/service/freebsd.rb b/lib/chef/provider/service/freebsd.rb
index 78ca0be235..9746dfdef0 100644
--- a/lib/chef/provider/service/freebsd.rb
+++ b/lib/chef/provider/service/freebsd.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/resource/service'
-require 'chef/provider/service/init'
-require 'chef/mixin/command'
+require "chef/resource/service"
+require "chef/provider/service/init"
+require "chef/mixin/command"
class Chef
class Provider
@@ -27,7 +27,7 @@ class Chef
attr_reader :enabled_state_found
- provides :service, os: [ "freebsd", "netbsd" ]
+ provides :service, os: %w{freebsd netbsd}
include Chef::Mixin::ShellOut
@@ -51,7 +51,7 @@ class Chef
Chef::Log.debug("#{current_resource} found at #{init_command}")
@status_load_success = true
- determine_current_status! # see Chef::Provider::Service::Simple
+ determine_current_status! # see Chef::Provider::Service::Simple
determine_enabled_status!
current_resource
@@ -74,7 +74,7 @@ class Chef
end
requirements.assert(:start, :enable, :reload, :restart) do |a|
- a.assertion { service_enable_variable_name != nil }
+ a.assertion { !service_enable_variable_name.nil? }
a.failure_message Chef::Exceptions::Service, "Could not find the service name in #{init_command} and rcvar"
# No recovery in whyrun mode - the init file is present but not correct.
end
@@ -119,11 +119,11 @@ class Chef
private
def read_rc_conf
- ::File.open("/etc/rc.conf", 'r') { |file| file.readlines }
+ ::File.open("/etc/rc.conf", "r") { |file| file.readlines }
end
def write_rc_conf(lines)
- ::File.open("/etc/rc.conf", 'w') do |file|
+ ::File.open("/etc/rc.conf", "w") do |file|
lines.each { |line| file.puts(line) }
end
end
diff --git a/lib/chef/provider/service/gentoo.rb b/lib/chef/provider/service/gentoo.rb
index 903c55af7a..7bb57113ac 100644
--- a/lib/chef/provider/service/gentoo.rb
+++ b/lib/chef/provider/service/gentoo.rb
@@ -1,7 +1,7 @@
#
# Author:: Lee Jensen (<ljensen@engineyard.com>)
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
# limitations under the License.
#
-require 'chef/provider/service/init'
-require 'chef/mixin/command'
-require 'chef/util/path_helper'
+require "chef/provider/service/init"
+require "chef/mixin/command"
+require "chef/util/path_helper"
class Chef::Provider::Service::Gentoo < Chef::Provider::Service::Init
@@ -33,12 +33,12 @@ class Chef::Provider::Service::Gentoo < Chef::Provider::Service::Init
super
@current_resource.enabled(
- Dir.glob("/etc/runlevels/**/#{Chef::Util::PathHelper.escape_glob(@current_resource.service_name)}").any? do |file|
+ Dir.glob("/etc/runlevels/**/#{Chef::Util::PathHelper.escape_glob_dir(@current_resource.service_name)}").any? do |file|
@found_script = true
exists = ::File.exists? file
readable = ::File.readable? file
Chef::Log.debug "#{@new_resource} exists: #{exists}, readable: #{readable}"
- exists and readable
+ exists && readable
end
)
Chef::Log.debug "#{@new_resource} enabled: #{@current_resource.enabled}"
@@ -61,11 +61,11 @@ class Chef::Provider::Service::Gentoo < Chef::Provider::Service::Init
end
end
- def enable_service()
+ def enable_service
shell_out!("/sbin/rc-update add #{@new_resource.service_name} default")
end
- def disable_service()
+ def disable_service
shell_out!("/sbin/rc-update del #{@new_resource.service_name} default")
end
end
diff --git a/lib/chef/provider/service/init.rb b/lib/chef/provider/service/init.rb
index 8fe5b0281f..dff627d016 100644
--- a/lib/chef/provider/service/init.rb
+++ b/lib/chef/provider/service/init.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/provider/service/simple'
-require 'chef/mixin/command'
-require 'chef/platform/service_helpers'
+require "chef/provider/service/simple"
+require "chef/mixin/command"
+require "chef/platform/service_helpers"
class Chef
class Provider
diff --git a/lib/chef/provider/service/insserv.rb b/lib/chef/provider/service/insserv.rb
index dd01f9ab87..c3dca10495 100644
--- a/lib/chef/provider/service/insserv.rb
+++ b/lib/chef/provider/service/insserv.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/provider/service/init'
-require 'chef/util/path_helper'
+require "chef/provider/service/init"
+require "chef/util/path_helper"
class Chef
class Provider
class Service
class Insserv < Chef::Provider::Service::Init
- provides :service, platform_family: %w(debian rhel fedora suse) do |node|
+ provides :service, platform_family: %w{debian rhel fedora suse} do |node|
Chef::Platform::ServiceHelpers.service_resource_providers.include?(:insserv)
end
@@ -36,7 +36,7 @@ class Chef
super
# Look for a /etc/rc.*/SnnSERVICE link to signify that the service would be started in a runlevel
- if Dir.glob("/etc/rc**/S*#{Chef::Util::PathHelper.escape_glob(current_resource.service_name)}").empty?
+ if Dir.glob("/etc/rc**/S*#{Chef::Util::PathHelper.escape_glob_dir(current_resource.service_name)}").empty?
current_resource.enabled false
else
current_resource.enabled true
@@ -45,12 +45,12 @@ class Chef
current_resource
end
- def enable_service()
+ def enable_service
shell_out!("/sbin/insserv -r -f #{new_resource.service_name}")
shell_out!("/sbin/insserv -d -f #{new_resource.service_name}")
end
- def disable_service()
+ def disable_service
shell_out!("/sbin/insserv -r -f #{new_resource.service_name}")
end
end
diff --git a/lib/chef/provider/service/invokercd.rb b/lib/chef/provider/service/invokercd.rb
index 2b045e0e60..9477afec48 100644
--- a/lib/chef/provider/service/invokercd.rb
+++ b/lib/chef/provider/service/invokercd.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'chef/provider/service/init'
+require "chef/provider/service/init"
class Chef
class Provider
class Service
class Invokercd < Chef::Provider::Service::Init
- provides :service, platform_family: 'debian', override: true do |node|
+ provides :service, platform_family: "debian", override: true do |node|
Chef::Platform::ServiceHelpers.service_resource_providers.include?(:invokercd)
end
diff --git a/lib/chef/provider/service/macosx.rb b/lib/chef/provider/service/macosx.rb
index 0a8fca4262..4056b72649 100644
--- a/lib/chef/provider/service/macosx.rb
+++ b/lib/chef/provider/service/macosx.rb
@@ -1,6 +1,6 @@
#
# Author:: Igor Afonov <afonov@gmail.com>
-# Copyright:: Copyright (c) 2011 Igor Afonov
+# Copyright:: Copyright 2011-2016, Igor Afonov
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'etc'
-require 'rexml/document'
-require 'chef/resource/service'
-require 'chef/resource/macosx_service'
-require 'chef/provider/service/simple'
-require 'chef/util/path_helper'
+require "etc"
+require "rexml/document"
+require "chef/resource/service"
+require "chef/resource/macosx_service"
+require "chef/provider/service/simple"
+require "chef/util/path_helper"
class Chef
class Provider
@@ -36,14 +36,14 @@ class Chef
/Library/LaunchDaemons
/System/Library/LaunchAgents
/System/Library/LaunchDaemons }
- Chef::Util::PathHelper.home('Library', 'LaunchAgents') { |p| locations << p }
+ Chef::Util::PathHelper.home("Library", "LaunchAgents") { |p| locations << p }
locations
end
PLIST_DIRS = gather_plist_dirs
def this_version_or_newer?(this_version)
- Gem::Version.new(node['platform_version']) >= Gem::Version.new(this_version)
+ Gem::Version.new(node["platform_version"]) >= Gem::Version.new(this_version)
end
def load_current_resource
@@ -53,17 +53,17 @@ class Chef
@plist = @new_resource.plist ? @new_resource.plist : find_service_plist
@service_label = find_service_label
# LauchAgents should be loaded as the console user.
- @console_user = @plist ? @plist.include?('LaunchAgents') : false
+ @console_user = @plist ? @plist.include?("LaunchAgents") : false
@session_type = @new_resource.session_type
if @console_user
@console_user = Etc.getlogin
Chef::Log.debug("#{new_resource} console_user: '#{@console_user}'")
cmd = "su "
- param = this_version_or_newer?('10.10') ? '' : '-l '
+ param = this_version_or_newer?("10.10") ? "" : "-l "
@base_user_cmd = cmd + param + "#{@console_user} -c"
# Default LauchAgent session should be Aqua
- @session_type = 'Aqua' if @session_type.nil?
+ @session_type = "Aqua" if @session_type.nil?
end
Chef::Log.debug("#{new_resource} Plist: '#{@plist}' service_label: '#{@service_label}'")
@@ -74,7 +74,7 @@ class Chef
def define_resource_requirements
requirements.assert(:reload) do |a|
- a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reload"
+ a.failure_message Chef::Exceptions::UnsupportedAction, "#{self} does not support :reload"
end
requirements.assert(:all_actions) do |a|
@@ -83,7 +83,7 @@ class Chef
end
requirements.assert(:all_actions) do |a|
- a.assertion {::File.exists?(@plist.to_s) }
+ a.assertion { ::File.exists?(@plist.to_s) }
a.failure_message Chef::Exceptions::Service,
"Could not find plist for #{@new_resource}"
end
@@ -160,14 +160,14 @@ class Chef
end
end
- def load_service
- session = @session_type ? "-S #{@session_type} " : ''
- cmd = 'launchctl load -w ' + session + @plist
+ def load_service
+ session = @session_type ? "-S #{@session_type} " : ""
+ cmd = "launchctl load -w " + session + @plist
shell_out_as_user(cmd)
end
def unload_service
- cmd = 'launchctl unload -w ' + @plist
+ cmd = "launchctl unload -w " + @plist
shell_out_as_user(cmd)
end
@@ -181,7 +181,7 @@ class Chef
end
def set_service_status
- return if @plist == nil or @service_label.to_s.empty?
+ return if @plist.nil? || @service_label.to_s.empty?
cmd = "launchctl list #{@service_label}"
res = shell_out_as_user(cmd)
@@ -197,7 +197,7 @@ class Chef
case line.downcase
when /\s+\"pid\"\s+=\s+(\d+).*/
pid = $1
- @current_resource.running(!pid.to_i.zero?)
+ @current_resource.running(pid.to_i != 0)
Chef::Log.debug("Current PID for #{@service_label} is #{pid}")
end
end
@@ -206,7 +206,7 @@ class Chef
end
end
- private
+ private
def find_service_label
# CHEF-5223 "you can't glob for a file that hasn't been converged
@@ -236,7 +236,7 @@ class Chef
plists = PLIST_DIRS.inject([]) do |results, dir|
edir = ::File.expand_path(dir)
entries = Dir.glob(
- "#{edir}/*#{Chef::Util::PathHelper.escape_glob(@current_resource.service_name)}*.plist"
+ "#{edir}/*#{Chef::Util::PathHelper.escape_glob_dir(@current_resource.service_name)}*.plist"
)
entries.any? ? results << entries : results
end
diff --git a/lib/chef/provider/service/openbsd.rb b/lib/chef/provider/service/openbsd.rb
index 36c9e8141e..780337e1b6 100644
--- a/lib/chef/provider/service/openbsd.rb
+++ b/lib/chef/provider/service/openbsd.rb
@@ -1,6 +1,6 @@
#
# Author:: Scott Bonds (<scott@ggr.com>)
-# Copyright:: Copyright (c) 2014 Scott Bonds
+# Copyright:: Copyright 2014-2016, Scott Bonds
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'chef/mixin/command'
-require 'chef/mixin/shell_out'
-require 'chef/provider/service/init'
-require 'chef/resource/service'
+require "chef/mixin/command"
+require "chef/mixin/shell_out"
+require "chef/provider/service/init"
+require "chef/resource/service"
class Chef
class Provider
@@ -32,13 +32,13 @@ class Chef
attr_reader :init_command, :rc_conf, :rc_conf_local, :enabled_state_found
- RC_CONF_PATH = '/etc/rc.conf'
- RC_CONF_LOCAL_PATH = '/etc/rc.conf.local'
+ RC_CONF_PATH = "/etc/rc.conf"
+ RC_CONF_LOCAL_PATH = "/etc/rc.conf.local"
def initialize(new_resource, run_context)
super
- @rc_conf = ::File.read(RC_CONF_PATH) rescue ''
- @rc_conf_local = ::File.read(RC_CONF_LOCAL_PATH) rescue ''
+ @rc_conf = ::File.read(RC_CONF_PATH) rescue ""
+ @rc_conf_local = ::File.read(RC_CONF_LOCAL_PATH) rescue ""
@init_command = ::File.exist?(rcd_script_path) ? rcd_script_path : nil
new_resource.status_command("#{default_init_command} check")
end
@@ -72,7 +72,7 @@ class Chef
end
requirements.assert(:start, :enable, :reload, :restart) do |a|
- a.assertion { init_command && builtin_service_enable_variable_name != nil }
+ a.assertion { init_command && !builtin_service_enable_variable_name.nil? }
a.failure_message Chef::Exceptions::Service, "Could not find the service name in #{init_command} and rcvar"
# No recovery in whyrun mode - the init file is present but not correct.
end
@@ -82,7 +82,7 @@ class Chef
if !is_enabled?
if is_builtin?
if is_enabled_by_default?
- update_rcl rc_conf_local.sub(/^#{Regexp.escape(builtin_service_enable_variable_name)}=.*/, '')
+ update_rcl rc_conf_local.sub(/^#{Regexp.escape(builtin_service_enable_variable_name)}=.*/, "")
else
# add line with blank string, which means enable
update_rcl rc_conf_local + "\n" + "#{builtin_service_enable_variable_name}=\"\"\n"
@@ -90,9 +90,9 @@ class Chef
else
# add to pkg_scripts, most recent addition goes last
old_services_list = rc_conf_local.match(/^pkg_scripts="(.*)"/)
- old_services_list = old_services_list ? old_services_list[1].split(' ') : []
+ old_services_list = old_services_list ? old_services_list[1].split(" ") : []
new_services_list = old_services_list + [new_resource.service_name]
- if rc_conf_local.match(/^pkg_scripts="(.*)"/)
+ if rc_conf_local =~ /^pkg_scripts="(.*)"/
new_rcl = rc_conf_local.sub(/^pkg_scripts="(.*)"/, "pkg_scripts=\"#{new_services_list.join(' ')}\"")
else
new_rcl = rc_conf_local + "\n" + "pkg_scripts=\"#{new_services_list.join(' ')}\"\n"
@@ -110,14 +110,14 @@ class Chef
update_rcl rc_conf_local + "\n" + "#{builtin_service_enable_variable_name}=\"NO\"\n"
else
# remove line to disable
- update_rcl rc_conf_local.sub(/^#{Regexp.escape(builtin_service_enable_variable_name)}=.*/, '')
+ update_rcl rc_conf_local.sub(/^#{Regexp.escape(builtin_service_enable_variable_name)}=.*/, "")
end
else
# remove from pkg_scripts
old_list = rc_conf_local.match(/^pkg_scripts="(.*)"/)
- old_list = old_list ? old_list[1].split(' ') : []
+ old_list = old_list ? old_list[1].split(" ") : []
new_list = old_list - [new_resource.service_name]
- update_rcl rc_conf_local.sub(/^pkg_scripts="(.*)"/, pkg_scripts="#{new_list.join(' ')}")
+ update_rcl rc_conf_local.sub(/^pkg_scripts="(.*)"/, pkg_scripts = "#{new_list.join(' ')}")
end
end
end
@@ -159,7 +159,7 @@ class Chef
result = false
var_name = builtin_service_enable_variable_name
if var_name
- if rc_conf.match(/^#{Regexp.escape(var_name)}=(.*)/)
+ if rc_conf =~ /^#{Regexp.escape(var_name)}=(.*)/
result = true
end
end
diff --git a/lib/chef/provider/service/redhat.rb b/lib/chef/provider/service/redhat.rb
index 3ad11a7672..21ab678706 100644
--- a/lib/chef/provider/service/redhat.rb
+++ b/lib/chef/provider/service/redhat.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/provider/service/init'
+require "chef/provider/service/init"
class Chef
class Provider
@@ -28,7 +28,7 @@ class Chef
# @api private
attr_accessor :current_run_levels
- provides :service, platform_family: %w(rhel fedora suse) do |node|
+ provides :service, platform_family: %w{rhel fedora suse} do |node|
Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat)
end
@@ -57,15 +57,21 @@ class Chef
requirements.assert(:all_actions) do |a|
chkconfig_file = "/sbin/chkconfig"
a.assertion { ::File.exists? chkconfig_file }
- a.failure_message Chef::Exceptions::Service, "#{chkconfig_file} dbleoes not exist!"
+ a.failure_message Chef::Exceptions::Service, "#{chkconfig_file} does not exist!"
end
- requirements.assert(:start, :enable, :reload, :restart) do |a|
+ requirements.assert(:enable) do |a|
+ a.assertion { !@service_missing }
+ a.failure_message Chef::Exceptions::Service, "#{new_resource}: Service is not known to chkconfig."
+ a.whyrun "Assuming service would be enabled. The init script is not presently installed."
+ end
+
+ requirements.assert(:start, :reload, :restart) do |a|
a.assertion do
- custom_command_for_action?(action) || !@service_missing
+ new_resource.init_command || custom_command_for_action?(action) || !@service_missing
end
a.failure_message Chef::Exceptions::Service, "#{new_resource}: No custom command for #{action} specified and unable to locate the init.d script!"
- a.whyrun "Assuming service would be disabled. The init script is not presently installed."
+ a.whyrun "Assuming service would be enabled. The init script is not presently installed."
end
end
@@ -75,12 +81,12 @@ class Chef
super
if ::File.exists?("/sbin/chkconfig")
- chkconfig = shell_out!("/sbin/chkconfig --list #{current_resource.service_name}", :returns => [0,1])
- unless run_levels.nil? or run_levels.empty?
+ chkconfig = shell_out!("/sbin/chkconfig --list #{current_resource.service_name}", :returns => [0, 1])
+ unless run_levels.nil? || run_levels.empty?
all_levels_match = true
chkconfig.stdout.split(/\s+/)[1..-1].each do |level|
- index = level.split(':').first
- status = level.split(':').last
+ index = level.split(":").first
+ status = level.split(":").last
if level =~ CHKCONFIG_ON
@current_run_levels << index.to_i
all_levels_match = false unless run_levels.include?(index.to_i)
@@ -100,18 +106,18 @@ class Chef
# @api private
def levels
- (run_levels.nil? or run_levels.empty?) ? "" : "--level #{run_levels.join('')} "
+ (run_levels.nil? || run_levels.empty?) ? "" : "--level #{run_levels.join('')} "
end
- def enable_service()
- unless run_levels.nil? or run_levels.empty?
+ def enable_service
+ unless run_levels.nil? || run_levels.empty?
disable_levels = current_run_levels - run_levels
shell_out! "/sbin/chkconfig --level #{disable_levels.join('')} #{new_resource.service_name} off" unless disable_levels.empty?
end
shell_out! "/sbin/chkconfig #{levels}#{new_resource.service_name} on"
end
- def disable_service()
+ def disable_service
shell_out! "/sbin/chkconfig #{levels}#{new_resource.service_name} off"
end
end
diff --git a/lib/chef/provider/service/simple.rb b/lib/chef/provider/service/simple.rb
index d295513b42..d75e85989f 100644
--- a/lib/chef/provider/service/simple.rb
+++ b/lib/chef/provider/service/simple.rb
@@ -1,6 +1,6 @@
#
# Author:: Mathieu Sauve-Frankel <msf@kisoku.net>
-# Copyright:: Copyright (c) 2009 Mathieu Sauve-Frankel
+# Copyright:: Copyright 2009-2016, Mathieu Sauve-Frankel
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/provider/service'
-require 'chef/resource/service'
-require 'chef/mixin/command'
+require "chef/provider/service"
+require "chef/resource/service"
+require "chef/mixin/command"
class Chef
class Provider
@@ -58,26 +58,27 @@ class Chef
shared_resource_requirements
requirements.assert(:start) do |a|
a.assertion { @new_resource.start_command }
- a.failure_message Chef::Exceptions::Service, "#{self.to_s} requires that start_command be set"
+ a.failure_message Chef::Exceptions::Service, "#{self} requires that start_command be set"
end
requirements.assert(:stop) do |a|
a.assertion { @new_resource.stop_command }
- a.failure_message Chef::Exceptions::Service, "#{self.to_s} requires that stop_command be set"
+ a.failure_message Chef::Exceptions::Service, "#{self} requires that stop_command be set"
end
requirements.assert(:restart) do |a|
- a.assertion { @new_resource.restart_command || ( @new_resource.start_command && @new_resource.stop_command ) }
- a.failure_message Chef::Exceptions::Service, "#{self.to_s} requires a restart_command or both start_command and stop_command be set in order to perform a restart"
+ a.assertion { @new_resource.restart_command || ( @new_resource.start_command && @new_resource.stop_command ) }
+ a.failure_message Chef::Exceptions::Service, "#{self} requires a restart_command or both start_command and stop_command be set in order to perform a restart"
end
requirements.assert(:reload) do |a|
a.assertion { @new_resource.reload_command }
- a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} requires a reload_command be set in order to perform a reload"
+ a.failure_message Chef::Exceptions::UnsupportedAction, "#{self} requires a reload_command be set in order to perform a reload"
end
requirements.assert(:all_actions) do |a|
- a.assertion { @new_resource.status_command or supports[:status] or
- (!ps_cmd.nil? and !ps_cmd.empty?) }
+ a.assertion do
+ @new_resource.status_command || supports[:status] ||
+ (!ps_cmd.nil? && !ps_cmd.empty?) end
a.failure_message Chef::Exceptions::Service, "#{@new_resource} could not determine how to inspect the process table, please set this node's 'command.ps' attribute"
end
requirements.assert(:all_actions) do |a|
@@ -108,7 +109,8 @@ class Chef
shell_out_with_systems_locale!(@new_resource.reload_command)
end
- protected
+ protected
+
def determine_current_status!
if @new_resource.status_command
Chef::Log.debug("#{@new_resource} you have specified a status command, running..")
diff --git a/lib/chef/provider/service/solaris.rb b/lib/chef/provider/service/solaris.rb
index 7040503c6b..f7f8eaf31b 100644
--- a/lib/chef/provider/service/solaris.rb
+++ b/lib/chef/provider/service/solaris.rb
@@ -1,6 +1,6 @@
#
# Author:: Toomas Pelberg (<toomasp@gmx.net>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/provider/service'
-require 'chef/resource/service'
-require 'chef/mixin/command'
+require "chef/provider/service"
+require "chef/resource/service"
+require "chef/mixin/command"
class Chef
class Provider
@@ -28,7 +28,7 @@ class Chef
provides :service, os: "solaris2"
- def initialize(new_resource, run_context=nil)
+ def initialize(new_resource, run_context = nil)
super
@init_command = "/usr/sbin/svcadm"
@status_command = "/bin/svcs"
@@ -40,7 +40,7 @@ class Chef
@current_resource.service_name(@new_resource.service_name)
[@init_command, @status_command].each do |cmd|
- unless ::File.executable? cmd then
+ unless ::File.executable? cmd
raise Chef::Exceptions::Service, "#{cmd} not executable!"
end
end
@@ -49,6 +49,11 @@ class Chef
@current_resource
end
+ def define_resource_requirements
+ # FIXME? need reload from service.rb
+ shared_resource_requirements
+ end
+
def enable_service
shell_out!(default_init_command, "clear", @new_resource.service_name) if @maintenance
shell_out!(default_init_command, "enable", "-s", @new_resource.service_name)
@@ -68,7 +73,7 @@ class Chef
def restart_service
## svcadm restart doesn't supports sync(-s) option
disable_service
- return enable_service
+ enable_service
end
def service_status
@@ -96,11 +101,11 @@ class Chef
# check service state
@maintenance = false
- case status['state']
- when 'online'
+ case status["state"]
+ when "online"
@current_resource.enabled(true)
@current_resource.running(true)
- when 'maintenance'
+ when "maintenance"
@maintenance = true
end
diff --git a/lib/chef/provider/service/systemd.rb b/lib/chef/provider/service/systemd.rb
index d41f6248c2..deec25b187 100644
--- a/lib/chef/provider/service/systemd.rb
+++ b/lib/chef/provider/service/systemd.rb
@@ -1,6 +1,7 @@
#
# Author:: Stephen Haynes (<sh@nomitor.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Davide Cavalca (<dcavalca@fb.com>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +17,9 @@
# limitations under the License.
#
-require 'chef/resource/service'
-require 'chef/provider/service/simple'
-require 'chef/mixin/which'
+require "chef/resource/service"
+require "chef/provider/service/simple"
+require "chef/mixin/which"
class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
@@ -48,15 +49,21 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
@status_check_success = false
current_resource.running(false)
current_resource.enabled(false)
+ current_resource.masked(false)
end
else
current_resource.running(is_active?)
end
current_resource.enabled(is_enabled?)
+ current_resource.masked(is_masked?)
current_resource
end
+ # systemd supports user services just fine
+ def user_services_requirements
+ end
+
def define_resource_requirements
shared_resource_requirements
requirements.assert(:all_actions) do |a|
@@ -67,6 +74,24 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
end
end
+ def get_systemctl_options_args
+ if new_resource.user
+ uid = node["etc"]["passwd"][new_resource.user]["uid"]
+ options = {
+ :environment => {
+ "DBUS_SESSION_BUS_ADDRESS" => "unix:path=/run/user/#{uid}/bus",
+ },
+ :user => new_resource.user,
+ }
+ args = "--user"
+ else
+ options = {}
+ args = "--system"
+ end
+
+ [options, args]
+ end
+
def start_service
if current_resource.running
Chef::Log.debug("#{new_resource} already running, not starting")
@@ -74,7 +99,8 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
if new_resource.start_command
super
else
- shell_out_with_systems_locale!("#{systemctl_path} start #{new_resource.service_name}")
+ options, args = get_systemctl_options_args
+ shell_out_with_systems_locale!("#{systemctl_path} #{args} start #{new_resource.service_name}", options)
end
end
end
@@ -86,7 +112,8 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
if new_resource.stop_command
super
else
- shell_out_with_systems_locale!("#{systemctl_path} stop #{new_resource.service_name}")
+ options, args = get_systemctl_options_args
+ shell_out_with_systems_locale!("#{systemctl_path} #{args} stop #{new_resource.service_name}", options)
end
end
end
@@ -95,7 +122,8 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
if new_resource.restart_command
super
else
- shell_out_with_systems_locale!("#{systemctl_path} restart #{new_resource.service_name}")
+ options, args = get_systemctl_options_args
+ shell_out_with_systems_locale!("#{systemctl_path} #{args} restart #{new_resource.service_name}", options)
end
end
@@ -104,7 +132,8 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
super
else
if current_resource.running
- shell_out_with_systems_locale!("#{systemctl_path} reload #{new_resource.service_name}")
+ options, args = get_systemctl_options_args
+ shell_out_with_systems_locale!("#{systemctl_path} #{args} reload #{new_resource.service_name}", options)
else
start_service
end
@@ -112,19 +141,39 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
end
def enable_service
- shell_out!("#{systemctl_path} enable #{new_resource.service_name}")
+ options, args = get_systemctl_options_args
+ shell_out!("#{systemctl_path} #{args} enable #{new_resource.service_name}", options)
end
def disable_service
- shell_out!("#{systemctl_path} disable #{new_resource.service_name}")
+ options, args = get_systemctl_options_args
+ shell_out!("#{systemctl_path} #{args} disable #{new_resource.service_name}", options)
+ end
+
+ def mask_service
+ options, args = get_systemctl_options_args
+ shell_out!("#{systemctl_path} #{args} mask #{new_resource.service_name}", options)
+ end
+
+ def unmask_service
+ options, args = get_systemctl_options_args
+ shell_out!("#{systemctl_path} #{args} unmask #{new_resource.service_name}", options)
end
def is_active?
- shell_out("#{systemctl_path} is-active #{new_resource.service_name} --quiet").exitstatus == 0
+ options, args = get_systemctl_options_args
+ shell_out("#{systemctl_path} #{args} is-active #{new_resource.service_name} --quiet", options).exitstatus == 0
end
def is_enabled?
- shell_out("#{systemctl_path} is-enabled #{new_resource.service_name} --quiet").exitstatus == 0
+ options, args = get_systemctl_options_args
+ shell_out("#{systemctl_path} #{args} is-enabled #{new_resource.service_name} --quiet", options).exitstatus == 0
+ end
+
+ def is_masked?
+ options, args = get_systemctl_options_args
+ s = shell_out("#{systemctl_path} #{args} is-enabled #{new_resource.service_name}", options)
+ s.exitstatus != 0 && s.stdout.include?("masked")
end
private
diff --git a/lib/chef/provider/service/upstart.rb b/lib/chef/provider/service/upstart.rb
index c08a5f8636..9c0d97d376 100644
--- a/lib/chef/provider/service/upstart.rb
+++ b/lib/chef/provider/service/upstart.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2010 Bryan McLellan
+# Copyright:: Copyright 2010-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,24 @@
# limitations under the License.
#
-require 'chef/resource/service'
-require 'chef/provider/service/simple'
-require 'chef/mixin/command'
-require 'chef/util/file_edit'
+require "chef/resource/service"
+require "chef/provider/service/simple"
+require "chef/mixin/command"
+require "chef/util/file_edit"
class Chef
class Provider
class Service
class Upstart < Chef::Provider::Service::Simple
- provides :service, platform_family: 'debian', override: true do |node|
+ # to maintain a local state of service across restart's internal calls
+ attr_accessor :upstart_service_running
+
+ provides :service, platform_family: "debian", override: true do |node|
Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart)
end
- UPSTART_STATE_FORMAT = /\w+ \(?(\w+)\)?[\/ ](\w+)/
+ UPSTART_STATE_FORMAT = /\S+ \(?(start|stop)?\)? ?[\/ ](\w+)/
def self.supports?(resource, action)
Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:upstart)
@@ -62,7 +65,7 @@ class Chef
end
platform, version = Chef::Platform.find_platform_and_version(run_context.node)
- if platform == "ubuntu" && (8.04..9.04).include?(version.to_f)
+ if platform == "ubuntu" && (8.04..9.04).cover?(version.to_f)
@upstart_job_dir = "/etc/event.d"
@upstart_conf_suffix = ""
else
@@ -80,8 +83,11 @@ class Chef
shared_resource_requirements
requirements.assert(:all_actions) do |a|
if !@command_success
- whyrun_msg = @new_resource.status_command ? "Provided status command #{@new_resource.status_command} failed." :
- "Could not determine upstart state for service"
+ whyrun_msg = if @new_resource.status_command
+ "Provided status command #{@new_resource.status_command} failed."
+ else
+ "Could not determine upstart state for service"
+ end
end
a.assertion { @command_success }
# no failure here, just document the assumptions made.
@@ -89,7 +95,7 @@ class Chef
end
requirements.assert(:all_actions) do |a|
- a.assertion { @config_file_found }
+ a.assertion { @config_file_found }
# no failure here, just document the assumptions made.
a.whyrun "Could not find #{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}. Assuming service is disabled."
end
@@ -107,30 +113,30 @@ class Chef
begin
if shell_out!(@new_resource.status_command).exitstatus == 0
- @current_resource.running true
+ @upstart_service_running = true
end
rescue
@command_success = false
- @current_resource.running false
+ @upstart_service_running = false
nil
end
else
begin
- if upstart_state == "running"
- @current_resource.running true
+ if upstart_goal_state == "start"
+ @upstart_service_running = true
else
- @current_resource.running false
+ @upstart_service_running = false
end
rescue Chef::Exceptions::Exec
@command_success = false
- @current_resource.running false
+ @upstart_service_running = false
nil
end
end
# Get enabled/disabled state by reading job configuration file
if ::File.exists?("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}")
Chef::Log.debug("#{@new_resource} found #{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}")
- ::File.open("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}",'r') do |file|
+ ::File.open("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}", "r") do |file|
while line = file.gets
case line
when /^start on/
@@ -150,13 +156,14 @@ class Chef
@current_resource.enabled false
end
+ @current_resource.running @upstart_service_running
@current_resource
end
def start_service
# Calling start on a service that is already started will return 1
# Our 'goal' when we call start is to ensure the service is started
- if @current_resource.running
+ if @upstart_service_running
Chef::Log.debug("#{@new_resource} already running, not starting")
else
if @new_resource.start_command
@@ -165,12 +172,14 @@ class Chef
shell_out_with_systems_locale!("/sbin/start #{@job}")
end
end
+
+ @upstart_service_running = true
end
def stop_service
# Calling stop on a service that is already stopped will return 1
# Our 'goal' when we call stop is to ensure the service is stopped
- unless @current_resource.running
+ unless @upstart_service_running
Chef::Log.debug("#{@new_resource} not running, not stopping")
else
if @new_resource.stop_command
@@ -179,6 +188,8 @@ class Chef
shell_out_with_systems_locale!("/sbin/stop #{@job}")
end
end
+
+ @upstart_service_running = false
end
def restart_service
@@ -186,13 +197,19 @@ class Chef
super
# Upstart always provides restart functionality so we don't need to mimic it with stop/sleep/start.
# Older versions of upstart would fail on restart if the service was currently stopped, check for that. LP:430883
+ # But for safe working of latest upstart job config being loaded, 'restart' can't be used as per link
+ # http://upstart.ubuntu.com/cookbook/#restart (it doesn't uses latest jon config from disk but retains old)
else
- if @current_resource.running
- shell_out_with_systems_locale!("/sbin/restart #{@job}")
+ if @upstart_service_running
+ stop_service
+ sleep 1
+ start_service
else
start_service
end
end
+
+ @upstart_service_running = true
end
def reload_service
@@ -202,6 +219,8 @@ class Chef
# upstart >= 0.6.3-4 supports reload (HUP)
shell_out_with_systems_locale!("/sbin/reload #{@job}")
end
+
+ @upstart_service_running = true
end
# https://bugs.launchpad.net/upstart/+bug/94065
@@ -220,18 +239,18 @@ class Chef
conf.write_file
end
- def upstart_state
+ def upstart_goal_state
command = "/sbin/status #{@job}"
status = popen4(command) do |pid, stdin, stdout, stderr|
stdout.each_line do |line|
- # rsyslog stop/waiting
# service goal/state
# OR
- # rsyslog (stop) waiting
+ # service (instance) goal/state
+ # OR
# service (goal) state
line =~ UPSTART_STATE_FORMAT
data = Regexp.last_match
- return data[2]
+ return data[1]
end
end
end
diff --git a/lib/chef/provider/service/windows.rb b/lib/chef/provider/service/windows.rb
index 355ffafc2a..9bfd9238cd 100644
--- a/lib/chef/provider/service/windows.rb
+++ b/lib/chef/provider/service/windows.rb
@@ -1,8 +1,8 @@
#
-# Author:: Nuo Yan <nuo@opscode.com>
+# Author:: Nuo Yan <nuo@chef.io>
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Author:: Seth Chisamore <schisamo@opscode.com>
-# Copyright:: Copyright (c) 2010-2011 Opscode, Inc
+# Author:: Seth Chisamore <schisamo@chef.io>
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,10 @@
# limitations under the License.
#
-require 'chef/provider/service/simple'
+require "chef/provider/service/simple"
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
- require 'chef/win32/error'
- require 'win32/service'
+ require "chef/win32/error"
+ require "win32/service"
end
class Chef::Provider::Service::Windows < Chef::Provider::Service
@@ -32,20 +32,22 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
include Chef::ReservedNames::Win32::API::Error rescue LoadError
#Win32::Service.get_start_type
- AUTO_START = 'auto start'
- MANUAL = 'demand start'
- DISABLED = 'disabled'
+ AUTO_START = "auto start"
+ MANUAL = "demand start"
+ DISABLED = "disabled"
#Win32::Service.get_current_state
- RUNNING = 'running'
- STOPPED = 'stopped'
- CONTINUE_PENDING = 'continue pending'
- PAUSE_PENDING = 'pause pending'
- PAUSED = 'paused'
- START_PENDING = 'start pending'
- STOP_PENDING = 'stop pending'
+ RUNNING = "running"
+ STOPPED = "stopped"
+ CONTINUE_PENDING = "continue pending"
+ PAUSE_PENDING = "pause pending"
+ PAUSED = "paused"
+ START_PENDING = "start pending"
+ STOP_PENDING = "stop pending"
- TIMEOUT = 60
+ TIMEOUT = 60
+
+ SERVICE_RIGHT = "SeServiceLogonRight"
def whyrun_supported?
false
@@ -73,15 +75,15 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
service_name: @new_resource.service_name,
service_start_name: @new_resource.run_as_user,
password: @new_resource.run_as_password,
- }.reject { |k,v| v.nil? || v.length == 0 }
+ }.reject { |k, v| v.nil? || v.length == 0 }
Win32::Service.configure(new_config)
Chef::Log.info "#{@new_resource} configured with #{new_config.inspect}"
- # it would be nice to check if the user already has the logon privilege, but that turns out to be
- # nontrivial.
if new_config.has_key?(:service_start_name)
- grant_service_logon(new_config[:service_start_name])
+ unless Chef::ReservedNames::Win32::Security.get_account_right(canonicalize_username(new_config[:service_start_name])).include?(SERVICE_RIGHT)
+ grant_service_logon(new_config[:service_start_name])
+ end
end
state = current_state
@@ -236,74 +238,26 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
end
private
- def make_policy_text(username)
- text = <<-EOS
-[Unicode]
-Unicode=yes
-[Privilege Rights]
-SeServiceLogonRight = \\\\#{canonicalize_username(username)},*S-1-5-80-0
-[Version]
-signature="$CHICAGO$"
-Revision=1
-EOS
- end
-
- def grant_logfile_name(username)
- Chef::Util::PathHelper.canonical_path("#{Dir.tmpdir}/logon_grant-#{clean_username_for_path(username)}-#{$$}.log", prefix=false)
- end
-
- def grant_policyfile_name(username)
- Chef::Util::PathHelper.canonical_path("#{Dir.tmpdir}/service_logon_policy-#{clean_username_for_path(username)}-#{$$}.inf", prefix=false)
- end
-
- def grant_dbfile_name(username)
- "#{ENV['TEMP']}\\secedit.sdb"
- end
def grant_service_logon(username)
- logfile = grant_logfile_name(username)
- policy_file = ::File.new(grant_policyfile_name(username), 'w')
- policy_text = make_policy_text(username)
- dbfile = grant_dbfile_name(username) # this is just an audit file.
-
begin
- Chef::Log.debug "Policy file text:\n#{policy_text}"
- policy_file.puts(policy_text)
- policy_file.close # need to flush the buffer.
-
- # it would be nice to do this with APIs instead, but the LSA_* APIs are
- # particularly onerous and life is short.
- cmd = %Q{secedit.exe /configure /db "#{dbfile}" /cfg "#{policy_file.path}" /areas USER_RIGHTS SECURITYPOLICY SERVICES /log "#{logfile}"}
- Chef::Log.debug "Granting logon-as-service privilege with: #{cmd}"
- runner = shell_out(cmd)
-
- if runner.exitstatus != 0
- Chef::Log.fatal "Logon-as-service grant failed with output: #{runner.stdout}"
- raise Chef::Exceptions::Service, <<-EOS
-Logon-as-service grant failed with policy file #{policy_file.path}.
-You can look at #{logfile} for details, or do `secedit /analyze #{dbfile}`.
-The failed command was `#{cmd}`.
-EOS
- end
-
- Chef::Log.info "Grant logon-as-service to user '#{username}' successful."
-
- ::File.delete(dbfile) rescue nil
- ::File.delete(policy_file)
- ::File.delete(logfile) rescue nil # logfile is not always present at end.
+ Chef::ReservedNames::Win32::Security.add_account_right(canonicalize_username(username), SERVICE_RIGHT)
+ rescue Chef::Exceptions::Win32APIError => err
+ Chef::Log.fatal "Logon-as-service grant failed with output: #{err}"
+ raise Chef::Exceptions::Service, "Logon-as-service grant failed for #{username}: #{err}"
end
+
+ Chef::Log.info "Grant logon-as-service to user '#{username}' successful."
true
end
# remove characters that make for broken or wonky filenames.
def clean_username_for_path(username)
- username.gsub(/[\/\\. ]+/, '_')
+ username.gsub(/[\/\\. ]+/, "_")
end
- # the security policy file only seems to accept \\username, so fix .\username or .\\username.
- # TODO: this probably has to be fixed to handle various valid Windows names correctly.
def canonicalize_username(username)
- username.sub(/^\.?\\+/, '')
+ username.sub(/^\.?\\+/, "")
end
def current_state
diff --git a/lib/chef/provider/subversion.rb b/lib/chef/provider/subversion.rb
index e3e3d5158a..ee8ea7c495 100644
--- a/lib/chef/provider/subversion.rb
+++ b/lib/chef/provider/subversion.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,11 @@
#TODO subversion and git should both extend from a base SCM provider.
-require 'chef/log'
-require 'chef/provider'
-require 'chef/mixin/command'
-require 'fileutils'
+require "chef/log"
+require "chef/provider"
+require "chef/mixin/command"
+require "chef-config/mixin/fuzzy_hostname_matcher"
+require "fileutils"
class Chef
class Provider
@@ -32,40 +33,41 @@ class Chef
SVN_INFO_PATTERN = /^([\w\s]+): (.+)$/
include Chef::Mixin::Command
+ include ChefConfig::Mixin::FuzzyHostnameMatcher
def whyrun_supported?
true
end
def load_current_resource
- @current_resource = Chef::Resource::Subversion.new(@new_resource.name)
+ @current_resource = Chef::Resource::Subversion.new(new_resource.name)
- unless [:export, :force_export].include?(Array(@new_resource.action).first)
+ unless [:export, :force_export].include?(Array(new_resource.action).first)
if current_revision = find_current_revision
- @current_resource.revision current_revision
+ current_resource.revision current_revision
end
end
end
def define_resource_requirements
- requirements.assert(:all_actions) do |a|
+ requirements.assert(:all_actions) do |a|
# Make sure the parent dir exists, or else fail.
# for why run, print a message explaining the potential error.
- parent_directory = ::File.dirname(@new_resource.destination)
+ parent_directory = ::File.dirname(new_resource.destination)
a.assertion { ::File.directory?(parent_directory) }
a.failure_message(Chef::Exceptions::MissingParentDirectory,
- "Cannot clone #{@new_resource} to #{@new_resource.destination}, the enclosing directory #{parent_directory} does not exist")
+ "Cannot clone #{new_resource} to #{new_resource.destination}, the enclosing directory #{parent_directory} does not exist")
a.whyrun("Directory #{parent_directory} does not exist, assuming it would have been created")
end
end
def action_checkout
if target_dir_non_existent_or_empty?
- converge_by("perform checkout of #{@new_resource.repository} into #{@new_resource.destination}") do
+ converge_by("perform checkout of #{new_resource.repository} into #{new_resource.destination}") do
shell_out!(checkout_command, run_options)
end
else
- Chef::Log.debug "#{@new_resource} checkout destination #{@new_resource.destination} already exists or is a non-empty directory - nothing to do"
+ Chef::Log.debug "#{new_resource} checkout destination #{new_resource.destination} already exists or is a non-empty directory - nothing to do"
end
end
@@ -73,25 +75,25 @@ class Chef
if target_dir_non_existent_or_empty?
action_force_export
else
- Chef::Log.debug "#{@new_resource} export destination #{@new_resource.destination} already exists or is a non-empty directory - nothing to do"
+ Chef::Log.debug "#{new_resource} export destination #{new_resource.destination} already exists or is a non-empty directory - nothing to do"
end
end
def action_force_export
- converge_by("export #{@new_resource.repository} into #{@new_resource.destination}") do
+ converge_by("export #{new_resource.repository} into #{new_resource.destination}") do
shell_out!(export_command, run_options)
end
end
def action_sync
assert_target_directory_valid!
- if ::File.exist?(::File.join(@new_resource.destination, ".svn"))
+ if ::File.exist?(::File.join(new_resource.destination, ".svn"))
current_rev = find_current_revision
- Chef::Log.debug "#{@new_resource} current revision: #{current_rev} target revision: #{revision_int}"
+ Chef::Log.debug "#{new_resource} current revision: #{current_rev} target revision: #{revision_int}"
unless current_revision_matches_target_revision?
- converge_by("sync #{@new_resource.destination} from #{@new_resource.repository}") do
+ converge_by("sync #{new_resource.destination} from #{new_resource.repository}") do
shell_out!(sync_command, run_options)
- Chef::Log.info "#{@new_resource} updated to revision: #{revision_int}"
+ Chef::Log.info "#{new_resource} updated to revision: #{revision_int}"
end
end
else
@@ -100,24 +102,24 @@ class Chef
end
def sync_command
- c = scm :update, @new_resource.svn_arguments, verbose, authentication, "-r#{revision_int}", @new_resource.destination
- Chef::Log.debug "#{@new_resource} updated working copy #{@new_resource.destination} to revision #{@new_resource.revision}"
+ c = scm :update, new_resource.svn_arguments, verbose, authentication, proxy, "-r#{revision_int}", new_resource.destination
+ Chef::Log.debug "#{new_resource} updated working copy #{new_resource.destination} to revision #{new_resource.revision}"
c
end
def checkout_command
- c = scm :checkout, @new_resource.svn_arguments, verbose, authentication,
- "-r#{revision_int}", @new_resource.repository, @new_resource.destination
- Chef::Log.info "#{@new_resource} checked out #{@new_resource.repository} at revision #{@new_resource.revision} to #{@new_resource.destination}"
+ c = scm :checkout, new_resource.svn_arguments, verbose, authentication, proxy,
+ "-r#{revision_int}", new_resource.repository, new_resource.destination
+ Chef::Log.info "#{new_resource} checked out #{new_resource.repository} at revision #{new_resource.revision} to #{new_resource.destination}"
c
end
def export_command
args = ["--force"]
- args << @new_resource.svn_arguments << verbose << authentication <<
- "-r#{revision_int}" << @new_resource.repository << @new_resource.destination
+ args << new_resource.svn_arguments << verbose << authentication << proxy <<
+ "-r#{revision_int}" << new_resource.repository << new_resource.destination
c = scm :export, *args
- Chef::Log.info "#{@new_resource} exported #{@new_resource.repository} at revision #{@new_resource.revision} to #{@new_resource.destination}"
+ Chef::Log.info "#{new_resource} exported #{new_resource.repository} at revision #{new_resource.revision} to #{new_resource.destination}"
c
end
@@ -126,11 +128,11 @@ class Chef
# If the specified revision is an integer, trust it.
def revision_int
@revision_int ||= begin
- if @new_resource.revision =~ /^\d+$/
- @new_resource.revision
+ if new_resource.revision =~ /^\d+$/
+ new_resource.revision
else
- command = scm(:info, @new_resource.repository, @new_resource.svn_info_args, authentication, "-r#{@new_resource.revision}")
- svn_info = shell_out!(command, run_options(:cwd => cwd, :returns => [0,1])).stdout
+ command = scm(:info, new_resource.repository, new_resource.svn_info_args, authentication, "-r#{new_resource.revision}")
+ svn_info = shell_out!(command, run_options(:cwd => cwd, :returns => [0, 1])).stdout
extract_revision_info(svn_info)
end
@@ -140,28 +142,28 @@ class Chef
alias :revision_slug :revision_int
def find_current_revision
- return nil unless ::File.exist?(::File.join(@new_resource.destination, ".svn"))
+ return nil unless ::File.exist?(::File.join(new_resource.destination, ".svn"))
command = scm(:info)
- svn_info = shell_out!(command, run_options(:cwd => cwd, :returns => [0,1])).stdout
+ svn_info = shell_out!(command, run_options(:cwd => cwd, :returns => [0, 1])).stdout
extract_revision_info(svn_info)
end
def current_revision_matches_target_revision?
- (!@current_resource.revision.nil?) && (revision_int.strip.to_i == @current_resource.revision.strip.to_i)
+ (!current_resource.revision.nil?) && (revision_int.strip.to_i == current_resource.revision.strip.to_i)
end
- def run_options(run_opts={})
- run_opts[:user] = @new_resource.user if @new_resource.user
- run_opts[:group] = @new_resource.group if @new_resource.group
- run_opts[:timeout] = @new_resource.timeout if @new_resource.timeout
+ def run_options(run_opts = {})
+ run_opts[:user] = new_resource.user if new_resource.user
+ run_opts[:group] = new_resource.group if new_resource.group
+ run_opts[:timeout] = new_resource.timeout if new_resource.timeout
run_opts
end
private
def cwd
- @new_resource.destination
+ new_resource.destination
end
def verbose
@@ -176,10 +178,10 @@ class Chef
end
attrs
end
- rev = (repo_attrs['Last Changed Rev'] || repo_attrs['Revision'])
+ rev = (repo_attrs["Last Changed Rev"] || repo_attrs["Revision"])
rev.strip! if rev
raise "Could not parse `svn info` data: #{svn_info}" if repo_attrs.empty?
- Chef::Log.debug "#{@new_resource} resolved revision #{@new_resource.revision} to #{rev}"
+ Chef::Log.debug "#{new_resource} resolved revision #{new_resource.revision} to #{rev}"
rev
end
@@ -188,9 +190,19 @@ class Chef
# switch, since Capistrano will check for that prompt in the output
# and will respond appropriately.
def authentication
- return "" unless @new_resource.svn_username
- result = "--username #{@new_resource.svn_username} "
- result << "--password #{@new_resource.svn_password} "
+ return "" unless new_resource.svn_username
+ result = "--username #{new_resource.svn_username} "
+ result << "--password #{new_resource.svn_password} "
+ result
+ end
+
+ def proxy
+ repo_uri = URI.parse(new_resource.repository)
+ proxy_uri = Chef::Config.proxy_uri(repo_uri.scheme, repo_uri.host, repo_uri.port)
+ return "" if proxy_uri.nil?
+
+ result = "--config-option servers:global:http-proxy-host=#{proxy_uri.host} "
+ result << "--config-option servers:global:http-proxy-port=#{proxy_uri.port} "
result
end
@@ -201,18 +213,18 @@ class Chef
end
def target_dir_non_existent_or_empty?
- !::File.exist?(@new_resource.destination) || Dir.entries(@new_resource.destination).sort == ['.','..']
+ !::File.exist?(new_resource.destination) || Dir.entries(new_resource.destination).sort == [".", ".."]
end
def svn_binary
- @new_resource.svn_binary ||
- (Chef::Platform.windows? ? 'svn.exe' : 'svn')
+ new_resource.svn_binary ||
+ (Chef::Platform.windows? ? "svn.exe" : "svn")
end
def assert_target_directory_valid!
- target_parent_directory = ::File.dirname(@new_resource.destination)
+ target_parent_directory = ::File.dirname(new_resource.destination)
unless ::File.directory?(target_parent_directory)
- msg = "Cannot clone #{@new_resource} to #{@new_resource.destination}, the enclosing directory #{target_parent_directory} does not exist"
+ msg = "Cannot clone #{new_resource} to #{new_resource.destination}, the enclosing directory #{target_parent_directory} does not exist"
raise Chef::Exceptions::MissingParentDirectory, msg
end
end
diff --git a/lib/chef/provider/support/yum_repo.erb b/lib/chef/provider/support/yum_repo.erb
new file mode 100644
index 0000000000..6f1325573d
--- /dev/null
+++ b/lib/chef/provider/support/yum_repo.erb
@@ -0,0 +1,132 @@
+# This file was generated by Chef
+# Do NOT modify this file by hand.
+
+[<%= @config.repositoryid %>]
+name=<%= @config.description %>
+<% if @config.baseurl %>
+baseurl=<%= case @config.baseurl
+ when Array
+ @config.baseurl.join("\n")
+ else
+ @config.baseurl
+ end %>
+<% end -%>
+<% if @config.cost %>
+cost=<%= @config.cost %>
+<% end %>
+<% if @config.enabled %>
+enabled=1
+<% else %>
+enabled=0
+<% end %>
+<% if @config.enablegroups %>
+enablegroups=1
+<% end %>
+<% if @config.exclude %>
+exclude=<%= @config.exclude %>
+<% end %>
+<% if @config.failovermethod %>
+failovermethod=<%= @config.failovermethod %>
+<% end %>
+<% if @config.fastestmirror_enabled %>
+fastestmirror_enabled=1
+<% else %>
+fastestmirror_enabled=0
+<% end %>
+<% if @config.gpgcheck %>
+gpgcheck=1
+<% else %>
+gpgcheck=0
+<% end %>
+<% if @config.gpgkey %>
+gpgkey=<%= case @config.gpgkey
+ when Array
+ @config.gpgkey.join("\n ")
+ else
+ @config.gpgkey
+ end %>
+<% end -%>
+<% if @config.http_caching %>
+http_caching=<%= @config.http_caching %>
+<% end %>
+<% if @config.include_config %>
+include=<%= @config.include_config %>
+<% end %>
+<% if @config.includepkgs %>
+includepkgs=<%= @config.includepkgs %>
+<% end %>
+<% if @config.keepalive %>
+keepalive=1
+<% end %>
+<% if @config.metadata_expire %>
+metadata_expire=<%= @config.metadata_expire %>
+<% end %>
+<% if @config.mirrorlist %>
+mirrorlist=<%= @config.mirrorlist %>
+<% end %>
+<% if @config.mirror_expire %>
+mirror_expire=<%= @config.mirror_expire %>
+<% end %>
+<% if @config.mirrorlist_expire %>
+mirrorlist_expire=<%= @config.mirrorlist_expire %>
+<% end %>
+<% if @config.priority %>
+priority=<%= @config.priority %>
+<% end %>
+<% if @config.proxy %>
+proxy=<%= @config.proxy %>
+<% end %>
+<% if @config.proxy_username %>
+proxy_username=<%= @config.proxy_username %>
+<% end %>
+<% if @config.proxy_password %>
+proxy_password=<%= @config.proxy_password %>
+<% end %>
+<% if @config.username %>
+username=<%= @config.username %>
+<% end %>
+<% if @config.password %>
+password=<%= @config.password %>
+<% end %>
+<% if @config.repo_gpgcheck %>
+repo_gpgcheck=1
+<% end %>
+<% if @config.max_retries %>
+retries=<%= @config.max_retries %>
+<% end %>
+<% if @config.report_instanceid %>
+report_instanceid=<%= @config.report_instanceid %>
+<% end %>
+<% if @config.skip_if_unavailable %>
+skip_if_unavailable=1
+<% end %>
+<% if @config.sslcacert %>
+sslcacert=<%= @config.sslcacert %>
+<% end %>
+<% if @config.sslclientcert %>
+sslclientcert=<%= @config.sslclientcert %>
+<% end %>
+<% if @config.sslclientkey %>
+sslclientkey=<%= @config.sslclientkey %>
+<% end %>
+<% unless @config.sslverify.nil? %>
+sslverify=<%= ( @config.sslverify ) ? 'true' : 'false' %>
+<% end %>
+<% if @config.timeout %>
+timeout=<%= @config.timeout %>
+<% end %>
+<% if @config.options -%>
+<% @config.options.each do |key, value| -%>
+<%= key %>=<%=
+ case value
+ when Array
+ value.join("\n ")
+ when TrueClass
+ '1'
+ when FalseClass
+ '0'
+ else
+ value
+ end %>
+<% end -%>
+<% end -%>
diff --git a/lib/chef/provider/systemd_unit.rb b/lib/chef/provider/systemd_unit.rb
new file mode 100644
index 0000000000..5175dc6be9
--- /dev/null
+++ b/lib/chef/provider/systemd_unit.rb
@@ -0,0 +1,240 @@
+#
+# Author:: Nathan Williams (<nath.e.will@gmail.com>)
+# Copyright:: Copyright 2016, Nathan Williams
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/provider"
+require "chef/mixin/which"
+require "chef/mixin/shell_out"
+require "chef/resource/file"
+require "chef/resource/file/verification/systemd_unit"
+require "iniparse"
+
+class Chef
+ class Provider
+ class SystemdUnit < Chef::Provider
+ include Chef::Mixin::Which
+ include Chef::Mixin::ShellOut
+
+ provides :systemd_unit, os: "linux"
+
+ def load_current_resource
+ @current_resource = Chef::Resource::SystemdUnit.new(new_resource.name)
+
+ current_resource.content(::File.read(unit_path)) if ::File.exist?(unit_path)
+ current_resource.user(new_resource.user)
+ current_resource.enabled(enabled?)
+ current_resource.active(active?)
+ current_resource.masked(masked?)
+ current_resource.static(static?)
+ current_resource.triggers_reload(new_resource.triggers_reload)
+
+ current_resource
+ end
+
+ def define_resource_requirements
+ super
+
+ requirements.assert(:create) do |a|
+ a.assertion { IniParse.parse(new_resource.to_ini) }
+ a.failure_message "Unit content is not valid INI text"
+ end
+ end
+
+ def action_create
+ if current_resource.content != new_resource.to_ini
+ converge_by("creating unit: #{new_resource.name}") do
+ manage_unit_file(:create)
+ daemon_reload if new_resource.triggers_reload
+ end
+ end
+ end
+
+ def action_delete
+ if ::File.exist?(unit_path)
+ converge_by("deleting unit: #{new_resource.name}") do
+ manage_unit_file(:delete)
+ daemon_reload if new_resource.triggers_reload
+ end
+ end
+ end
+
+ def action_enable
+ if current_resource.static
+ Chef::Log.debug("#{new_resource.name} is a static unit, enabling is a NOP.")
+ end
+
+ unless current_resource.enabled || current_resource.static
+ converge_by("enabling unit: #{new_resource.name}") do
+ systemctl_execute!(:enable, new_resource.name)
+ end
+ end
+ end
+
+ def action_disable
+ if current_resource.static
+ Chef::Log.debug("#{new_resource.name} is a static unit, disabling is a NOP.")
+ end
+
+ if current_resource.enabled && !current_resource.static
+ converge_by("disabling unit: #{new_resource.name}") do
+ systemctl_execute!(:disable, new_resource.name)
+ end
+ end
+ end
+
+ def action_mask
+ unless current_resource.masked
+ converge_by("masking unit: #{new_resource.name}") do
+ systemctl_execute!(:mask, new_resource.name)
+ end
+ end
+ end
+
+ def action_unmask
+ if current_resource.masked
+ converge_by("unmasking unit: #{new_resource.name}") do
+ systemctl_execute!(:unmask, new_resource.name)
+ end
+ end
+ end
+
+ def action_start
+ unless current_resource.active
+ converge_by("starting unit: #{new_resource.name}") do
+ systemctl_execute!(:start, new_resource.name)
+ end
+ end
+ end
+
+ def action_stop
+ if current_resource.active
+ converge_by("stopping unit: #{new_resource.name}") do
+ systemctl_execute!(:stop, new_resource.name)
+ end
+ end
+ end
+
+ def action_restart
+ converge_by("restarting unit: #{new_resource.name}") do
+ systemctl_execute!(:restart, new_resource.name)
+ end
+ end
+
+ def action_reload
+ if current_resource.active
+ converge_by("reloading unit: #{new_resource.name}") do
+ systemctl_execute!(:reload, new_resource.name)
+ end
+ else
+ Chef::Log.debug("#{new_resource.name} is not active, skipping reload.")
+ end
+ end
+
+ def action_try_restart
+ converge_by("try-restarting unit: #{new_resource.name}") do
+ systemctl_execute!("try-restart", new_resource.name)
+ end
+ end
+
+ def action_reload_or_restart
+ converge_by("reload-or-restarting unit: #{new_resource.name}") do
+ systemctl_execute!("reload-or-restart", new_resource.name)
+ end
+ end
+
+ def action_reload_or_try_restart
+ converge_by("reload-or-try-restarting unit: #{new_resource.name}") do
+ systemctl_execute!("reload-or-try-restart", new_resource.name)
+ end
+ end
+
+ def active?
+ systemctl_execute("is-active", new_resource.name).exitstatus == 0
+ end
+
+ def enabled?
+ systemctl_execute("is-enabled", new_resource.name).exitstatus == 0
+ end
+
+ def masked?
+ systemctl_execute(:status, new_resource.name).stdout.include?("masked")
+ end
+
+ def static?
+ systemctl_execute("is-enabled", new_resource.name).stdout.include?("static")
+ end
+
+ private
+
+ def unit_path
+ if new_resource.user
+ "/etc/systemd/user/#{new_resource.name}"
+ else
+ "/etc/systemd/system/#{new_resource.name}"
+ end
+ end
+
+ def manage_unit_file(action = :nothing)
+ Chef::Resource::File.new(unit_path, run_context).tap do |f|
+ f.owner "root"
+ f.group "root"
+ f.mode "0644"
+ f.content new_resource.to_ini
+ f.verify :systemd_unit
+ end.run_action(action)
+ end
+
+ def daemon_reload
+ shell_out_with_systems_locale!("#{systemctl_path} daemon-reload")
+ end
+
+ def systemctl_execute!(action, unit)
+ shell_out_with_systems_locale!("#{systemctl_cmd} #{action} #{unit}", systemctl_opts)
+ end
+
+ def systemctl_execute(action, unit)
+ shell_out("#{systemctl_cmd} #{action} #{unit}", systemctl_opts)
+ end
+
+ def systemctl_cmd
+ @systemctl_cmd ||= "#{systemctl_path} #{systemctl_args}"
+ end
+
+ def systemctl_path
+ @systemctl_path ||= which("systemctl")
+ end
+
+ def systemctl_args
+ @systemctl_args ||= new_resource.user ? "--user" : "--system"
+ end
+
+ def systemctl_opts
+ @systemctl_opts ||=
+ if new_resource.user
+ {
+ :user => new_resource.user,
+ :environment => {
+ "DBUS_SESSION_BUS_ADDRESS" => "unix:path=/run/user/#{node['etc']['passwd'][new_resource.user]['uid']}/bus",
+ },
+ }
+ else
+ {}
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/template.rb b/lib/chef/provider/template.rb
index 1e759074b9..7cb0ba008d 100644
--- a/lib/chef/provider/template.rb
+++ b/lib/chef/provider/template.rb
@@ -1,7 +1,7 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
# limitations under the License.
#
-require 'chef/provider/template_finder'
-require 'chef/provider/file'
-require 'chef/deprecation/provider/template'
-require 'chef/deprecation/warnings'
+require "chef/provider/template_finder"
+require "chef/provider/file"
+require "chef/deprecation/provider/template"
+require "chef/deprecation/warnings"
class Chef
class Provider
@@ -37,7 +37,7 @@ class Chef
end
def load_current_resource
- @current_resource = Chef::Resource::Template.new(@new_resource.name)
+ @current_resource = Chef::Resource::Template.new(new_resource.name)
super
end
@@ -45,7 +45,7 @@ class Chef
super
requirements.assert(:create, :create_if_missing) do |a|
- a.assertion { ::File::exists?(content.template_location) }
+ a.assertion { ::File.exists?(content.template_location) }
a.failure_message "Template source #{content.template_location} could not be found."
a.whyrun "Template source #{content.template_location} does not exist. Assuming it would have been created."
a.block_action!
@@ -55,8 +55,8 @@ class Chef
private
def managing_content?
- return true if @new_resource.checksum
- return true if !@new_resource.source.nil? && @action != :create_if_missing
+ return true if new_resource.checksum
+ return true if !new_resource.source.nil? && @action != :create_if_missing
false
end
diff --git a/lib/chef/provider/template/content.rb b/lib/chef/provider/template/content.rb
index 693b19a8c6..acf200621d 100644
--- a/lib/chef/provider/template/content.rb
+++ b/lib/chef/provider/template/content.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/mixin/template'
-require 'chef/file_content_management/content_base'
+require "chef/mixin/template"
+require "chef/file_content_management/content_base"
class Chef
class Provider
diff --git a/lib/chef/provider/template_finder.rb b/lib/chef/provider/template_finder.rb
index 1596a320c4..1e8b925071 100644
--- a/lib/chef/provider/template_finder.rb
+++ b/lib/chef/provider/template_finder.rb
@@ -1,6 +1,6 @@
#--
# Author:: Andrea Campi (<andrea.campi@zephirworks.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -40,7 +40,8 @@ class Chef
cookbook.preferred_filename_on_disk_location(@node, :templates, template_name)
end
- protected
+ protected
+
def template_source_name(name, options)
if options[:source]
options[:source]
diff --git a/lib/chef/provider/user.rb b/lib/chef/provider/user.rb
index 76aefbf1c8..c44adbf818 100644
--- a/lib/chef/provider/user.rb
+++ b/lib/chef/provider/user.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/provider'
-require 'chef/mixin/command'
-require 'etc'
+require "chef/provider"
+require "chef/mixin/command"
+require "etc"
class Chef
class Provider
@@ -36,10 +36,10 @@ class Chef
end
def convert_group_name
- if @new_resource.gid.is_a? String
- @new_resource.gid(Etc.getgrnam(@new_resource.gid).gid)
+ if new_resource.gid.is_a? String
+ new_resource.gid(Etc.getgrnam(new_resource.gid).gid)
end
- rescue ArgumentError => e
+ rescue ArgumentError
@group_name_resolved = false
end
@@ -48,62 +48,62 @@ class Chef
end
def load_current_resource
- @current_resource = Chef::Resource::User.new(@new_resource.name)
- @current_resource.username(@new_resource.username)
+ @current_resource = Chef::Resource::User.new(new_resource.name)
+ current_resource.username(new_resource.username)
begin
- user_info = Etc.getpwnam(@new_resource.username)
- rescue ArgumentError => e
+ user_info = Etc.getpwnam(new_resource.username)
+ rescue ArgumentError
@user_exists = false
- Chef::Log.debug("#{@new_resource} user does not exist")
+ Chef::Log.debug("#{new_resource} user does not exist")
user_info = nil
end
if user_info
- @current_resource.uid(user_info.uid)
- @current_resource.gid(user_info.gid)
- @current_resource.home(user_info.dir)
- @current_resource.shell(user_info.shell)
- @current_resource.password(user_info.passwd)
-
- if @new_resource.comment
- user_info.gecos.force_encoding(@new_resource.comment.encoding)
+ current_resource.uid(user_info.uid)
+ current_resource.gid(user_info.gid)
+ current_resource.home(user_info.dir)
+ current_resource.shell(user_info.shell)
+ current_resource.password(user_info.passwd)
+
+ if new_resource.comment
+ user_info.gecos.force_encoding(new_resource.comment.encoding)
end
- @current_resource.comment(user_info.gecos)
+ current_resource.comment(user_info.gecos)
- if @new_resource.password && @current_resource.password == 'x'
+ if new_resource.password && current_resource.password == "x"
begin
- require 'shadow'
+ require "shadow"
rescue LoadError
@shadow_lib_ok = false
else
- shadow_info = Shadow::Passwd.getspnam(@new_resource.username)
- @current_resource.password(shadow_info.sp_pwdp)
+ shadow_info = Shadow::Passwd.getspnam(new_resource.username)
+ current_resource.password(shadow_info.sp_pwdp)
end
end
- convert_group_name if @new_resource.gid
+ convert_group_name if new_resource.gid
end
- @current_resource
+ current_resource
end
def define_resource_requirements
requirements.assert(:create, :modify, :manage, :lock, :unlock) do |a|
a.assertion { @group_name_resolved }
- a.failure_message Chef::Exceptions::User, "Couldn't lookup integer GID for group name #{@new_resource.gid}"
- a.whyrun "group name #{@new_resource.gid} does not exist. This will cause group assignment to fail. Assuming this group will have been created previously."
+ a.failure_message Chef::Exceptions::User, "Couldn't lookup integer GID for group name #{new_resource.gid}"
+ a.whyrun "group name #{new_resource.gid} does not exist. This will cause group assignment to fail. Assuming this group will have been created previously."
end
requirements.assert(:all_actions) do |a|
a.assertion { @shadow_lib_ok }
a.failure_message Chef::Exceptions::MissingLibrary, "You must have ruby-shadow installed for password support!"
- a.whyrun "ruby-shadow is not installed. Attempts to set user password will cause failure. Assuming that this gem will have been previously installed." +
- "Note that user update converge may report false-positive on the basis of mismatched password. "
+ a.whyrun "ruby-shadow is not installed. Attempts to set user password will cause failure. Assuming that this gem will have been previously installed." \
+ "Note that user update converge may report false-positive on the basis of mismatched password. "
end
requirements.assert(:modify, :lock, :unlock) do |a|
a.assertion { @user_exists }
- a.failure_message(Chef::Exceptions::User, "Cannot modify user #{@new_resource.username} - does not exist!")
- a.whyrun("Assuming user #{@new_resource.username} would have been created")
+ a.failure_message(Chef::Exceptions::User, "Cannot modify user #{new_resource.username} - does not exist!")
+ a.whyrun("Assuming user #{new_resource.username} would have been created")
end
end
@@ -113,100 +113,108 @@ class Chef
# <true>:: If a change is required
# <false>:: If the users are identical
def compare_user
- changed = [ :comment, :home, :shell, :password ].select do |user_attrib|
- !@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib) != @current_resource.send(user_attrib)
- end
+ return true if !new_resource.home.nil? && Pathname.new(new_resource.home).cleanpath != Pathname.new(current_resource.home).cleanpath
- changed += [ :uid, :gid ].select do |user_attrib|
- !@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib).to_s != @current_resource.send(user_attrib).to_s
+ [ :comment, :shell, :password, :uid, :gid ].each do |user_attrib|
+ return true if !new_resource.send(user_attrib).nil? && new_resource.send(user_attrib).to_s != current_resource.send(user_attrib).to_s
end
- changed.any?
+ false
end
def action_create
-
if !@user_exists
- converge_by("create user #{@new_resource.username}") do
+ converge_by("create user #{new_resource.username}") do
create_user
- Chef::Log.info("#{@new_resource} created")
+ Chef::Log.info("#{new_resource} created")
end
elsif compare_user
- converge_by("alter user #{@new_resource.username}") do
+ converge_by("alter user #{new_resource.username}") do
manage_user
- Chef::Log.info("#{@new_resource} altered")
+ Chef::Log.info("#{new_resource} altered")
end
end
end
def action_remove
- if @user_exists
- converge_by("remove user #{@new_resource.username}") do
- remove_user
- Chef::Log.info("#{@new_resource} removed")
- end
+ return unless @user_exists
+ converge_by("remove user #{new_resource.username}") do
+ remove_user
+ Chef::Log.info("#{new_resource} removed")
end
end
- def remove_user
- raise NotImplementedError
- end
-
def action_manage
- if @user_exists && compare_user
- converge_by("manage user #{@new_resource.username}") do
- manage_user
- Chef::Log.info("#{@new_resource} managed")
- end
+ return unless @user_exists && compare_user
+ converge_by("manage user #{new_resource.username}") do
+ manage_user
+ Chef::Log.info("#{new_resource} managed")
end
end
- def manage_user
- raise NotImplementedError
- end
-
def action_modify
- if compare_user
- converge_by("modify user #{@new_resource.username}") do
- manage_user
- Chef::Log.info("#{@new_resource} modified")
- end
+ return unless compare_user
+ converge_by("modify user #{new_resource.username}") do
+ manage_user
+ Chef::Log.info("#{new_resource} modified")
end
end
def action_lock
- if check_lock() == false
- converge_by("lock the user #{@new_resource.username}") do
+ if check_lock == false
+ converge_by("lock the user #{new_resource.username}") do
lock_user
- Chef::Log.info("#{@new_resource} locked")
+ Chef::Log.info("#{new_resource} locked")
end
- else
- Chef::Log.debug("#{@new_resource} already locked - nothing to do")
+ else
+ Chef::Log.debug("#{new_resource} already locked - nothing to do")
end
end
- def check_lock
+ def action_unlock
+ if check_lock == true
+ converge_by("unlock user #{new_resource.username}") do
+ unlock_user
+ Chef::Log.info("#{new_resource} unlocked")
+ end
+ else
+ Chef::Log.debug("#{new_resource} already unlocked - nothing to do")
+ end
+ end
+
+ def create_user
raise NotImplementedError
end
- def lock_user
+ def remove_user
raise NotImplementedError
end
- def action_unlock
- if check_lock() == true
- converge_by("unlock user #{@new_resource.username}") do
- unlock_user
- Chef::Log.info("#{@new_resource} unlocked")
- end
- else
- Chef::Log.debug("#{@new_resource} already unlocked - nothing to do")
- end
+ def manage_user
+ raise NotImplementedError
+ end
+
+ def lock_user
+ raise NotImplementedError
end
def unlock_user
raise NotImplementedError
end
+
+ def check_lock
+ raise NotImplementedError
+ end
+
+ def non_unique?
+ # XXX: THIS GOES AWAY IN CHEF-13 AND BECOMES JUST new_resource.non_unique
+ new_resource.non_unique || new_resource.supports[:non_unique]
+ end
+
+ def managing_home_dir?
+ # XXX: THIS GOES AWAY IN CHEF-13 AND BECOMES JUST new_resource.manage_home
+ new_resource.manage_home || new_resource.supports[:manage_home]
+ end
end
end
end
diff --git a/lib/chef/provider/user/aix.rb b/lib/chef/provider/user/aix.rb
index a575a41e54..0e81c76bbc 100644
--- a/lib/chef/provider/user/aix.rb
+++ b/lib/chef/provider/user/aix.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,13 +14,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+require "chef/provider/user/useradd"
+
class Chef
class Provider
class User
class Aix < Chef::Provider::User::Useradd
- provides :user, platform: %w(aix)
+ provides :user, os: "aix"
+ provides :aix_user
- UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]]
+ UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]].freeze
def create_user
super
@@ -41,52 +44,52 @@ class Chef
end
def check_lock
- lock_info = shell_out!("lsuser -a account_locked #{new_resource.username}")
+ lock_info = shell_out_compact!("lsuser", "-a", "account_locked", new_resource.username)
if whyrun_mode? && passwd_s.stdout.empty? && lock_info.stderr.match(/does not exist/)
# if we're in whyrun mode and the user is not yet created we assume it would be
return false
end
- raise Chef::Exceptions::User, "Cannot determine if #{@new_resource} is locked!" if lock_info.stdout.empty?
+ raise Chef::Exceptions::User, "Cannot determine if #{new_resource} is locked!" if lock_info.stdout.empty?
- status = /\S+\s+account_locked=(\S+)/.match(lock_info.stdout)
- if status && status[1] == "true"
- @locked = true
- else
- @locked = false
- end
+ status = /\S+\s+account_locked=(\S+)/.match(lock_info.stdout)
+ @locked =
+ if status && status[1] == "true"
+ true
+ else
+ false
+ end
@locked
end
def lock_user
- shell_out!("chuser account_locked=true #{new_resource.username}")
+ shell_out_compact!("chuser", "account_locked=true", new_resource.username)
end
def unlock_user
- shell_out!("chuser account_locked=false #{new_resource.username}")
+ shell_out_compact!("chuser", "account_locked=false", new_resource.username)
end
- private
+ private
+
def add_password
- if @current_resource.password != @new_resource.password && @new_resource.password
- Chef::Log.debug("#{@new_resource.username} setting password to #{@new_resource.password}")
- command = "echo '#{@new_resource.username}:#{@new_resource.password}' | chpasswd -e"
- shell_out!(command)
- end
+ return unless current_resource.password != new_resource.password && new_resource.password
+ Chef::Log.debug("#{new_resource.username} setting password to #{new_resource.password}")
+ command = "echo '#{new_resource.username}:#{new_resource.password}' | chpasswd -e"
+ shell_out!(command)
end
# Aix specific handling to update users home directory.
def manage_home
+ return unless updating_home? && managing_home_dir?
# -m option does not work on aix, so move dir.
- if updating_home? and managing_home_dir?
- universal_options.delete("-m")
- if ::File.directory?(@current_resource.home)
- Chef::Log.debug("Changing users home directory from #{@current_resource.home} to #{new_resource.home}")
- shell_out!("mv #{@current_resource.home} #{new_resource.home}")
- else
- Chef::Log.debug("Creating users home directory #{new_resource.home}")
- shell_out!("mkdir -p #{new_resource.home}")
- end
+ universal_options.delete("-m")
+ if ::File.directory?(current_resource.home)
+ Chef::Log.debug("Changing users home directory from #{current_resource.home} to #{new_resource.home}")
+ FileUtils.mv current_resource.home, new_resource.home
+ else
+ Chef::Log.debug("Creating users home directory #{new_resource.home}")
+ FileUtils.mkdir_p new_resource.home
end
end
diff --git a/lib/chef/provider/user/dscl.rb b/lib/chef/provider/user/dscl.rb
index 1faf2438ac..2302a874e2 100644
--- a/lib/chef/provider/user/dscl.rb
+++ b/lib/chef/provider/user/dscl.rb
@@ -1,6 +1,6 @@
#
# Author:: Dreamcat4 (<dreamcat4@gmail.com>)
-# Copyright:: Copyright (c) 2009 OpsCode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'mixlib/shellout'
-require 'chef/provider/user'
-require 'openssl'
-require 'plist'
-require 'chef/util/path_helper'
+require "mixlib/shellout"
+require "chef/provider/user"
+require "openssl"
+require "plist"
+require "chef/util/path_helper"
class Chef
class Provider
@@ -48,8 +48,14 @@ class Chef
attr_accessor :authentication_authority
attr_accessor :password_shadow_conversion_algorithm
+ provides :dscl_user
provides :user, os: "darwin"
+ # Just-in-case a recipe calls the user dscl provider without specifying
+ # a gid property. Avoids chown issues in move_home when the manage_home
+ # property is in use. #5393
+ STAFF_GROUP_ID = 20
+
def define_resource_requirements
super
@@ -59,12 +65,12 @@ class Chef
end
requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/usr/bin/dscl") }
+ a.assertion { ::File.exist?("/usr/bin/dscl") }
a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/dscl' on the system for #{new_resource}!")
end
requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/usr/bin/plutil") }
+ a.assertion { ::File.exist?("/usr/bin/plutil") }
a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/plutil' on the system for #{new_resource}!")
end
@@ -109,7 +115,6 @@ in 'password', with the associated 'salt' and 'iterations'.")
Mac OS X version 10.7. Please specify a SALTED-SHA512 shadow hash in 'password' attribute to set the \
user password using shadow hash.")
end
-
end
def load_current_resource
@@ -131,21 +136,21 @@ user password using shadow hash.")
# Calling shell_out directly since we want to give an input stream
shadow_hash_xml = convert_binary_plist_to_xml(shadow_hash_binary.string)
- shadow_hash = Plist::parse_xml(shadow_hash_xml)
+ shadow_hash = Plist.parse_xml(shadow_hash_xml)
if shadow_hash["SALTED-SHA512"]
# Convert the shadow value from Base64 encoding to hex before consuming them
@password_shadow_conversion_algorithm = "SALTED-SHA512"
- current_resource.password(shadow_hash["SALTED-SHA512"].string.unpack('H*').first)
+ current_resource.password(shadow_hash["SALTED-SHA512"].string.unpack("H*").first)
elsif shadow_hash["SALTED-SHA512-PBKDF2"]
@password_shadow_conversion_algorithm = "SALTED-SHA512-PBKDF2"
# Convert the entropy from Base64 encoding to hex before consuming them
- current_resource.password(shadow_hash["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack('H*').first)
+ current_resource.password(shadow_hash["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack("H*").first)
current_resource.iterations(shadow_hash["SALTED-SHA512-PBKDF2"]["iterations"])
# Convert the salt from Base64 encoding to hex before consuming them
- current_resource.salt(shadow_hash["SALTED-SHA512-PBKDF2"]["salt"].string.unpack('H*').first)
+ current_resource.salt(shadow_hash["SALTED-SHA512-PBKDF2"]["salt"].string.unpack("H*").first)
else
- raise(Chef::Exceptions::User,"Unknown shadow_hash format: #{shadow_hash.keys.join(' ')}")
+ raise(Chef::Exceptions::User, "Unknown shadow_hash format: #{shadow_hash.keys.join(' ')}")
end
end
@@ -194,7 +199,7 @@ user password using shadow hash.")
# Create a user using dscl
#
def dscl_create_user
- run_dscl("create /Users/#{new_resource.username}")
+ run_dscl("create", "/Users/#{new_resource.username}")
end
#
@@ -203,7 +208,7 @@ user password using shadow hash.")
#
def dscl_create_comment
comment = new_resource.comment || new_resource.username
- run_dscl("create /Users/#{new_resource.username} RealName '#{comment}'")
+ run_dscl("create", "/Users/#{new_resource.username}", "RealName", comment)
end
#
@@ -213,25 +218,25 @@ user password using shadow hash.")
#
def dscl_set_uid
# XXX: mutates the new resource
- new_resource.uid(get_free_uid) if (new_resource.uid.nil? || new_resource.uid == '')
+ new_resource.uid(get_free_uid) if new_resource.uid.nil? || new_resource.uid == ""
if uid_used?(new_resource.uid)
raise(Chef::Exceptions::RequestedUIDUnavailable, "uid #{new_resource.uid} is already in use")
end
- run_dscl("create /Users/#{new_resource.username} UniqueID #{new_resource.uid}")
+ run_dscl("create", "/Users/#{new_resource.username}", "UniqueID", new_resource.uid)
end
#
# Find the next available uid on the system. starting with 200 if `system` is set,
# 500 otherwise.
#
- def get_free_uid(search_limit=1000)
+ def get_free_uid(search_limit = 1000)
uid = nil
base_uid = new_resource.system ? 200 : 500
next_uid_guess = base_uid
- users_uids = run_dscl("list /Users uid")
- while(next_uid_guess < search_limit + base_uid)
+ users_uids = run_dscl("list", "/Users", "uid")
+ while next_uid_guess < search_limit + base_uid
if users_uids =~ Regexp.new("#{Regexp.escape(next_uid_guess.to_s)}\n")
next_uid_guess += 1
else
@@ -239,7 +244,7 @@ user password using shadow hash.")
break
end
end
- return uid || raise("uid not found. Exhausted. Searched #{search_limit} times")
+ uid || raise("uid not found. Exhausted. Searched #{search_limit} times")
end
#
@@ -247,39 +252,39 @@ user password using shadow hash.")
#
def uid_used?(uid)
return false unless uid
- users_uids = run_dscl("list /Users uid").split("\n")
- uid_map = users_uids.inject({}) do |tmap, tuid|
+ users_uids = run_dscl("list", "/Users", "uid").split("\n")
+ uid_map = users_uids.each_with_object({}) do |tuid, tmap|
x = tuid.split
tmap[x[1]] = x[0]
tmap
end
if uid_map[uid.to_s]
- unless uid_map[uid.to_s] == new_resource.username.to_s
+ unless uid_map[uid.to_s] == new_resource.username
return true
end
end
- return false
+ false
end
#
# Sets the group id for the user using dscl. Fails if a group doesn't
# exist on the system with given group id. If `gid` is not specified, it
- # sets a default Mac user group "staff", with id 20.
+ # sets a default Mac user group "staff", with id 20 using the CONSTANT
#
def dscl_set_gid
if new_resource.gid.nil?
# XXX: mutates the new resource
- new_resource.gid(20)
+ new_resource.gid(STAFF_GROUP_ID)
elsif !new_resource.gid.to_s.match(/^\d+$/)
begin
- possible_gid = run_dscl("read /Groups/#{new_resource.gid} PrimaryGroupID").split(" ").last
- rescue Chef::Exceptions::DsclCommandFailed => e
- raise Chef::Exceptions::GroupIDNotFound.new("Group not found for #{new_resource.gid} when creating user #{new_resource.username}")
+ possible_gid = run_dscl("read", "/Groups/#{new_resource.gid}", "PrimaryGroupID").split(" ").last
+ rescue Chef::Exceptions::DsclCommandFailed
+ raise Chef::Exceptions::GroupIDNotFound, "Group not found for #{new_resource.gid} when creating user #{new_resource.username}"
end
# XXX: mutates the new resource
new_resource.gid(possible_gid) if possible_gid && possible_gid.match(/^\d+$/)
end
- run_dscl("create /Users/#{new_resource.username} PrimaryGroupID '#{new_resource.gid}'")
+ run_dscl("create", "/Users/#{new_resource.username}", "PrimaryGroupID", new_resource.gid)
end
#
@@ -288,11 +293,11 @@ user password using shadow hash.")
#
def dscl_set_home
if new_resource.home.nil? || new_resource.home.empty?
- run_dscl("delete /Users/#{new_resource.username} NFSHomeDirectory")
+ run_dscl("delete", "/Users/#{new_resource.username}", "NFSHomeDirectory")
return
end
- if new_resource.supports[:manage_home]
+ if managing_home_dir?
validate_home_dir_specification!
if (current_resource.home == new_resource.home) && !new_home_exists?
@@ -303,49 +308,49 @@ user password using shadow hash.")
move_home
end
end
- run_dscl("create /Users/#{new_resource.username} NFSHomeDirectory '#{new_resource.home}'")
+ run_dscl("create", "/Users/#{new_resource.username}", "NFSHomeDirectory", new_resource.home)
end
def validate_home_dir_specification!
unless new_resource.home =~ /^\//
- raise(Chef::Exceptions::InvalidHomeDirectory,"invalid path spec for User: '#{new_resource.username}', home directory: '#{new_resource.home}'")
+ raise(Chef::Exceptions::InvalidHomeDirectory, "invalid path spec for User: '#{new_resource.username}', home directory: '#{new_resource.home}'")
end
end
def current_home_exists?
- ::File.exist?("#{current_resource.home}")
+ ::File.exist?(current_resource.home)
end
def new_home_exists?
- ::File.exist?("#{new_resource.home}")
+ ::File.exist?(new_resource.home)
end
def ditto_home
skel = "/System/Library/User Template/English.lproj"
- raise(Chef::Exceptions::User,"can't find skel at: #{skel}") unless ::File.exists?(skel)
- shell_out! "ditto '#{skel}' '#{new_resource.home}'"
- ::FileUtils.chown_R(new_resource.username,new_resource.gid.to_s,new_resource.home)
+ raise(Chef::Exceptions::User, "can't find skel at: #{skel}") unless ::File.exist?(skel)
+ shell_out_compact!("ditto", skel, new_resource.home)
+ ::FileUtils.chown_R(new_resource.username, new_resource.gid.to_s, new_resource.home)
end
def move_home
Chef::Log.debug("#{new_resource} moving #{self} home from #{current_resource.home} to #{new_resource.home}")
-
+ new_resource.gid(STAFF_GROUP_ID) if new_resource.gid.nil?
src = current_resource.home
FileUtils.mkdir_p(new_resource.home)
- files = ::Dir.glob("#{Chef::Util::PathHelper.escape_glob(src)}/*", ::File::FNM_DOTMATCH) - ["#{src}/.","#{src}/.."]
- ::FileUtils.mv(files,new_resource.home, :force => true)
+ files = ::Dir.glob("#{Chef::Util::PathHelper.escape_glob_dir(src)}/*", ::File::FNM_DOTMATCH) - ["#{src}/.", "#{src}/.."]
+ ::FileUtils.mv(files, new_resource.home, force: true)
::FileUtils.rmdir(src)
- ::FileUtils.chown_R(new_resource.username,new_resource.gid.to_s,new_resource.home)
+ ::FileUtils.chown_R(new_resource.username, new_resource.gid.to_s, new_resource.home)
end
#
# Sets the shell for the user using dscl.
#
def dscl_set_shell
- if new_resource.shell || ::File.exists?("#{new_resource.shell}")
- run_dscl("create /Users/#{new_resource.username} UserShell '#{new_resource.shell}'")
+ if new_resource.shell
+ run_dscl("create", "/Users/#{new_resource.username}", "UserShell", new_resource.shell)
else
- run_dscl("create /Users/#{new_resource.username} UserShell '/usr/bin/false'")
+ run_dscl("create", "/Users/#{new_resource.username}", "UserShell", "/usr/bin/false")
end
end
@@ -362,9 +367,8 @@ user password using shadow hash.")
# Shadow info is saved as binary plist. Convert the info to binary plist.
shadow_info_binary = StringIO.new
- command = Mixlib::ShellOut.new("plutil -convert binary1 -o - -",
- :input => shadow_info.to_plist, :live_stream => shadow_info_binary)
- command.run_command
+ shell_out_compact("plutil", "-convert", "binary1", "-o", "-", "-",
+ input: shadow_info.to_plist, live_stream: shadow_info_binary)
if user_info.nil?
# User is just created. read_user_info() will read the fresh information
@@ -384,20 +388,20 @@ user password using shadow hash.")
# Prepares the password shadow info based on the platform version.
#
def prepare_password_shadow_info
- shadow_info = { }
+ shadow_info = {}
entropy = nil
salt = nil
iterations = nil
if mac_osx_version_10_7?
hash_value = if salted_sha512?(new_resource.password)
- new_resource.password
- else
- # Create a random 4 byte salt
- salt = OpenSSL::Random.random_bytes(4)
- encoded_password = OpenSSL::Digest::SHA512.hexdigest(salt + new_resource.password)
- hash_value = salt.unpack('H*').first + encoded_password
- end
+ new_resource.password
+ else
+ # Create a random 4 byte salt
+ salt = OpenSSL::Random.random_bytes(4)
+ encoded_password = OpenSSL::Digest::SHA512.hexdigest(salt + new_resource.password)
+ salt.unpack("H*").first + encoded_password
+ end
shadow_info["SALTED-SHA512"] = StringIO.new
shadow_info["SALTED-SHA512"].string = convert_to_binary(hash_value)
@@ -411,7 +415,7 @@ user password using shadow hash.")
salt = OpenSSL::Random.random_bytes(32)
iterations = new_resource.iterations # Use the default if not specified by the user
- entropy = OpenSSL::PKCS5::pbkdf2_hmac(
+ entropy = OpenSSL::PKCS5.pbkdf2_hmac(
new_resource.password,
salt,
iterations,
@@ -420,7 +424,7 @@ user password using shadow hash.")
)
end
- pbkdf_info = { }
+ pbkdf_info = {}
pbkdf_info["entropy"] = StringIO.new
pbkdf_info["entropy"].string = entropy
pbkdf_info["salt"] = StringIO.new
@@ -438,35 +442,35 @@ user password using shadow hash.")
# and deleting home directory if needed.
#
def remove_user
- if new_resource.supports[:manage_home]
+ if managing_home_dir?
# Remove home directory
FileUtils.rm_rf(current_resource.home)
end
# Remove the user from its groups
- run_dscl("list /Groups").each_line do |group|
+ run_dscl("list", "/Groups").each_line do |group|
if member_of_group?(group.chomp)
- run_dscl("delete /Groups/#{group.chomp} GroupMembership '#{new_resource.username}'")
+ run_dscl("delete", "/Groups/#{group.chomp}", "GroupMembership", new_resource.username)
end
end
# Remove user account
- run_dscl("delete /Users/#{new_resource.username}")
+ run_dscl("delete", "/Users/#{new_resource.username}")
end
#
# Locks the user.
#
def lock_user
- run_dscl("append /Users/#{new_resource.username} AuthenticationAuthority ';DisabledUser;'")
+ run_dscl("append", "/Users/#{new_resource.username}", "AuthenticationAuthority", ";DisabledUser;")
end
#
# Unlocks the user
#
def unlock_user
- auth_string = authentication_authority.gsub(/AuthenticationAuthority: /,"").gsub(/;DisabledUser;/,"").strip
- run_dscl("create /Users/#{new_resource.username} AuthenticationAuthority '#{auth_string}'")
+ auth_string = authentication_authority.gsub(/AuthenticationAuthority: /, "").gsub(/;DisabledUser;/, "").strip
+ run_dscl("create", "/Users/#{new_resource.username}", "AuthenticationAuthority", auth_string)
end
#
@@ -484,7 +488,7 @@ user password using shadow hash.")
# This is the interface base User provider requires to provide idempotency.
#
def check_lock
- return @locked = locked?
+ @locked = locked?
end
#
@@ -496,11 +500,11 @@ user password using shadow hash.")
# given attribute.
#
def diverged?(parameter)
- parameter_updated?(parameter) && (not new_resource.send(parameter).nil?)
+ parameter_updated?(parameter) && !new_resource.send(parameter).nil?
end
def parameter_updated?(parameter)
- not (new_resource.send(parameter) == current_resource.send(parameter))
+ !(new_resource.send(parameter) == current_resource.send(parameter))
end
#
@@ -546,7 +550,7 @@ user password using shadow hash.")
def member_of_group?(group_name)
membership_info = ""
begin
- membership_info = run_dscl("read /Groups/#{group_name}")
+ membership_info = run_dscl("read", "/Groups/#{group_name}")
rescue Chef::Exceptions::DsclCommandFailed
# Raised if the group doesn't contain any members
end
@@ -563,14 +567,14 @@ user password using shadow hash.")
# A simple map of Chef's terms to DSCL's terms.
DSCL_PROPERTY_MAP = {
- :uid => "uid",
- :gid => "gid",
- :home => "home",
- :shell => "shell",
- :comment => "realname",
- :password => "passwd",
- :auth_authority => "authentication_authority",
- :shadow_hash => "ShadowHashData"
+ uid: "uid",
+ gid: "gid",
+ home: "home",
+ shell: "shell",
+ comment: "realname",
+ password: "passwd",
+ auth_authority: "authentication_authority",
+ shadow_hash: "ShadowHashData",
}.freeze
# Directory where the user plist files are stored for versions 10.7 and above
@@ -585,12 +589,12 @@ user password using shadow hash.")
# We flush the cache here in order to make sure that we read fresh information
# for the user.
- shell_out("dscacheutil '-flushcache'")
+ shell_out_compact("dscacheutil", "-flushcache") # FIXME: this is MacOS version dependent
begin
user_plist_file = "#{USER_PLIST_DIRECTORY}/#{new_resource.username}.plist"
- user_plist_info = run_plutil("convert xml1 -o - #{user_plist_file}")
- user_info = Plist::parse_xml(user_plist_info)
+ user_plist_info = run_plutil("convert", "xml1", "-o", "-", user_plist_file)
+ user_info = Plist.parse_xml(user_plist_info)
rescue Chef::Exceptions::PlistUtilCommandFailed
end
@@ -604,7 +608,7 @@ user password using shadow hash.")
def save_user_info(user_info)
user_plist_file = "#{USER_PLIST_DIRECTORY}/#{new_resource.username}.plist"
Plist::Emit.save_plist(user_info, user_plist_file)
- run_plutil("convert binary1 #{user_plist_file}")
+ run_plutil("convert", "binary1", user_plist_file)
end
#
@@ -653,29 +657,33 @@ user password using shadow hash.")
end
def run_dscl(*args)
- result = shell_out("dscl . -#{args.join(' ')}")
+ argdup = args.dup
+ cmd = argdup.shift
+ result = shell_out_compact("dscl", ".", "-#{cmd}", argdup)
return "" if ( args.first =~ /^delete/ ) && ( result.exitstatus != 0 )
- raise(Chef::Exceptions::DsclCommandFailed,"dscl error: #{result.inspect}") unless result.exitstatus == 0
- raise(Chef::Exceptions::DsclCommandFailed,"dscl error: #{result.inspect}") if result.stdout =~ /No such key: /
+ raise(Chef::Exceptions::DsclCommandFailed, "dscl error: #{result.inspect}") unless result.exitstatus == 0
+ raise(Chef::Exceptions::DsclCommandFailed, "dscl error: #{result.inspect}") if result.stdout =~ /No such key: /
result.stdout
end
def run_plutil(*args)
- result = shell_out("plutil -#{args.join(' ')}")
- raise(Chef::Exceptions::PlistUtilCommandFailed,"plutil error: #{result.inspect}") unless result.exitstatus == 0
+ argdup = args.dup
+ cmd = argdup.shift
+ result = shell_out_compact("plutil", "-#{cmd}", argdup)
+ raise(Chef::Exceptions::PlistUtilCommandFailed, "plutil error: #{result.inspect}") unless result.exitstatus == 0
if result.stdout.encoding == Encoding::ASCII_8BIT
- result.stdout.encode("utf-8", "binary", :undef => :replace, :invalid => :replace, :replace => '?')
+ result.stdout.encode("utf-8", "binary", undef: :replace, invalid: :replace, replace: "?")
else
result.stdout
end
end
def convert_binary_plist_to_xml(binary_plist_string)
- Mixlib::ShellOut.new("plutil -convert xml1 -o - -", :input => binary_plist_string).run_command.stdout
+ shell_out_compact("plutil", "-convert", "xml1", "-o", "-", "-", input: binary_plist_string).stdout
end
def convert_to_binary(string)
- string.unpack('a2'*(string.size/2)).collect { |i| i.hex.chr }.join
+ string.unpack("a2" * (string.size / 2)).collect { |i| i.hex.chr }.join
end
def salted_sha512?(string)
@@ -684,7 +692,7 @@ user password using shadow hash.")
def salted_sha512_password_match?
# Salt is included in the first 4 bytes of shadow data
- salt = current_resource.password.slice(0,8)
+ salt = current_resource.password.slice(0, 8)
shadow = OpenSSL::Digest::SHA512.hexdigest(convert_to_binary(salt) + new_resource.password)
current_resource.password == salt + shadow
end
@@ -696,13 +704,13 @@ user password using shadow hash.")
def salted_sha512_pbkdf2_password_match?
salt = convert_to_binary(current_resource.salt)
- OpenSSL::PKCS5::pbkdf2_hmac(
+ OpenSSL::PKCS5.pbkdf2_hmac(
new_resource.password,
salt,
current_resource.iterations,
128,
OpenSSL::Digest::SHA512.new
- ).unpack('H*').first == current_resource.password
+ ).unpack("H*").first == current_resource.password
end
end
diff --git a/lib/chef/provider/user/linux.rb b/lib/chef/provider/user/linux.rb
new file mode 100644
index 0000000000..445421ad38
--- /dev/null
+++ b/lib/chef/provider/user/linux.rb
@@ -0,0 +1,125 @@
+#
+# Copyright:: Copyright 2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "chef/provider/user"
+
+class Chef
+ class Provider
+ class User
+ class Linux < Chef::Provider::User
+ provides :linux_user
+ provides :user, os: "linux"
+
+ def create_user
+ shell_out_compact!("useradd", universal_options, useradd_options, new_resource.username)
+ end
+
+ def manage_user
+ shell_out_compact!("usermod", universal_options, usermod_options, new_resource.username)
+ end
+
+ def remove_user
+ shell_out_compact!("userdel", userdel_options, new_resource.username)
+ end
+
+ def lock_user
+ shell_out_compact!("usermod", "-L", new_resource.username)
+ end
+
+ def unlock_user
+ shell_out_compact!("usermod", "-U", new_resource.username)
+ end
+
+ # common to usermod and useradd
+ def universal_options
+ opts = []
+ opts << "-c" << new_resource.comment if should_set?(:comment)
+ opts << "-g" << new_resource.gid if should_set?(:gid)
+ opts << "-p" << new_resource.password if should_set?(:password)
+ opts << "-s" << new_resource.shell if should_set?(:shell)
+ opts << "-u" << new_resource.uid if should_set?(:uid)
+ opts << "-d" << new_resource.home if updating_home?
+ opts << "-o" if non_unique?
+ opts
+ end
+
+ def usermod_options
+ opts = []
+ if updating_home?
+ if managing_home_dir?
+ opts << "-m"
+ end
+ end
+ opts
+ end
+
+ def useradd_options
+ opts = []
+ opts << "-r" if new_resource.system
+ opts << if managing_home_dir?
+ "-m"
+ else
+ "-M"
+ end
+ opts
+ end
+
+ def userdel_options
+ opts = []
+ opts << "-r" if managing_home_dir?
+ opts << "-f" if new_resource.force
+ opts
+ end
+
+ def should_set?(sym)
+ current_resource.send(sym).to_s != new_resource.send(sym).to_s && new_resource.send(sym)
+ end
+
+ def updating_home?
+ return false unless new_resource.home
+ return true unless current_resource.home
+ new_resource.home && Pathname.new(current_resource.home).cleanpath != Pathname.new(new_resource.home).cleanpath
+ end
+
+ def check_lock
+ # there's an old bug in rhel (https://bugzilla.redhat.com/show_bug.cgi?id=578534)
+ # which means that both 0 and 1 can be success.
+ passwd_s = shell_out_compact("passwd", "-S", new_resource.username, returns: [ 0, 1 ])
+
+ # checking "does not exist" has to come before exit code handling since centos and ubuntu differ in exit codes
+ if passwd_s.stderr =~ /does not exist/
+ return false if whyrun_mode?
+ raise Chef::Exceptions::User, "User #{new_resource.username} does not exist when checking lock status for #{new_resource}"
+ end
+
+ # now raise if we didn't get a 0 or 1 (see above)
+ passwd_s.error!
+
+ # now the actual output parsing
+ @locked = nil
+ status_line = passwd_s.stdout.split(" ")
+ @locked = false if status_line[1] =~ /^[PN]/
+ @locked = true if status_line[1] =~ /^L/
+
+ raise Chef::Exceptions::User, "Cannot determine if user #{new_resource.username} is locked for #{new_resource}" if @locked.nil?
+
+ # FIXME: should probably go on the current_resource
+ @locked
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/user/pw.rb b/lib/chef/provider/user/pw.rb
index 810ffb9a8d..42d862a983 100644
--- a/lib/chef/provider/user/pw.rb
+++ b/lib/chef/provider/user/pw.rb
@@ -1,6 +1,6 @@
#
# Author:: Stephen Haynes (<sh@nomitor.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,89 +16,86 @@
# limitations under the License.
#
-require 'chef/provider/user'
+require "chef/provider/user"
class Chef
class Provider
class User
class Pw < Chef::Provider::User
- provides :user, platform: %w(freebsd)
+ provides :pw_user
+ provides :user, os: "freebsd"
def load_current_resource
super
- raise Chef::Exceptions::User, "Could not find binary /usr/sbin/pw for #{@new_resource}" unless ::File.exists?("/usr/sbin/pw")
+ raise Chef::Exceptions::User, "Could not find binary /usr/sbin/pw for #{new_resource}" unless ::File.exist?("/usr/sbin/pw")
end
def create_user
- command = "pw useradd"
- command << set_options
- run_command(:command => command)
+ shell_out_compact!("pw", "useradd", set_options)
modify_password
end
def manage_user
- command = "pw usermod"
- command << set_options
- run_command(:command => command)
+ shell_out_compact!("pw", "usermod", set_options)
modify_password
end
def remove_user
- command = "pw userdel #{@new_resource.username}"
- command << " -r" if @new_resource.supports[:manage_home]
- run_command(:command => command)
+ command = [ "pw", "userdel", new_resource.username ]
+ command << "-r" if managing_home_dir?
+ shell_out_compact!(command)
end
def check_lock
- case @current_resource.password
- when /^\*LOCKED\*/
- @locked = true
- else
- @locked = false
- end
+ @locked = case current_resource.password
+ when /^\*LOCKED\*/
+ true
+ else
+ false
+ end
@locked
end
def lock_user
- run_command(:command => "pw lock #{@new_resource.username}")
+ shell_out_compact!("pw", "lock", new_resource.username)
end
def unlock_user
- run_command(:command => "pw unlock #{@new_resource.username}")
+ shell_out_compact!("pw", "unlock", new_resource.username)
end
def set_options
- opts = " #{@new_resource.username}"
+ opts = [ new_resource.username ]
field_list = {
- 'comment' => "-c",
- 'home' => "-d",
- 'gid' => "-g",
- 'uid' => "-u",
- 'shell' => "-s"
+ "comment" => "-c",
+ "home" => "-d",
+ "gid" => "-g",
+ "uid" => "-u",
+ "shell" => "-s",
}
- field_list.sort{ |a,b| a[0] <=> b[0] }.each do |field, option|
+ field_list.sort { |a, b| a[0] <=> b[0] }.each do |field, option|
field_symbol = field.to_sym
- if @current_resource.send(field_symbol) != @new_resource.send(field_symbol)
- if @new_resource.send(field_symbol)
- Chef::Log.debug("#{@new_resource} setting #{field} to #{@new_resource.send(field_symbol)}")
- opts << " #{option} '#{@new_resource.send(field_symbol)}'"
- end
+ next unless current_resource.send(field_symbol) != new_resource.send(field_symbol)
+ if new_resource.send(field_symbol)
+ Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field_symbol)}")
+ opts << option
+ opts << new_resource.send(field_symbol)
end
end
- if @new_resource.supports[:manage_home]
- Chef::Log.debug("#{@new_resource} is managing the users home directory")
- opts << " -m"
+ if managing_home_dir?
+ Chef::Log.debug("#{new_resource} is managing the users home directory")
+ opts << "-m"
end
opts
end
def modify_password
- if (not @new_resource.password.nil?) && (@current_resource.password != @new_resource.password)
+ if !new_resource.password.nil? && (current_resource.password != new_resource.password)
Chef::Log.debug("#{new_resource} updating password")
- command = "pw usermod #{@new_resource.username} -H 0"
- status = popen4(command, :waitlast => true) do |pid, stdin, stdout, stderr|
- stdin.puts "#{@new_resource.password}"
+ command = "pw usermod #{new_resource.username} -H 0"
+ status = popen4(command, waitlast: true) do |pid, stdin, stdout, stderr|
+ stdin.puts new_resource.password.to_s
end
unless status.exitstatus == 0
diff --git a/lib/chef/provider/user/solaris.rb b/lib/chef/provider/user/solaris.rb
index c16db22ad4..4e772312ae 100644
--- a/lib/chef/provider/user/solaris.rb
+++ b/lib/chef/provider/user/solaris.rb
@@ -1,9 +1,9 @@
#
-# Author:: Stephen Nelson-Smith (<sns@opscode.com>)
+# Author:: Stephen Nelson-Smith (<sns@chef.io>)
# Author:: Jon Ramsey (<jonathon.ramsey@gmail.com>)
# Author:: Dave Eddy (<dave@daveeddy.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# Copyright:: Copyright 2015, Dave Eddy
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# Copyright:: Copyright 2015-2016, Dave Eddy
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/provider/user/useradd'
+require "chef/provider/user/useradd"
class Chef
class Provider
class User
class Solaris < Chef::Provider::User::Useradd
- provides :user, platform: %w(omnios solaris2)
- UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]]
+ provides :solaris_user
+ provides :user, os: %w{omnios solaris2}
+ UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]].freeze
attr_writer :password_file
@@ -45,38 +46,45 @@ class Chef
end
def check_lock
- shadow_line = shell_out!('getent', 'shadow', new_resource.username).stdout.strip rescue nil
+ user = IO.read(@password_file).match(/^#{Regexp.escape(new_resource.username)}:([^:]*):/)
- # if the command fails we return nil, this can happen if the user
- # in question doesn't exist
- return nil if shadow_line.nil?
+ # If we're in whyrun mode, and the user is not created, we assume it will be
+ return false if whyrun_mode? && user.nil?
- # convert "dave:NP:16507::::::\n" to "NP"
- fields = shadow_line.split(':')
+ raise Chef::Exceptions::User, "Cannot determine if #{new_resource} is locked!" if user.nil?
- # '*LK*...' and 'LK' are both considered locked,
- # so look for LK at the beginning of the shadow entry
- # optionally surrounded by '*'
- @locked = !!fields[1].match(/^\*?LK\*?/)
-
- @locked
+ @locked = user[1].start_with?("*LK*")
end
def lock_user
- shell_out!('passwd', '-l', new_resource.username)
+ shell_out_compact!("passwd", "-l", new_resource.username)
end
def unlock_user
- shell_out!('passwd', '-u', new_resource.username)
+ shell_out_compact!("passwd", "-u", new_resource.username)
end
- private
+ private
+
+ # Override the version from {#Useradd} because Solaris doesn't support
+ # system users and therefore has no `-r` option. This also inverts the
+ # logic for manage_home as Solaris defaults to no-manage-home and only
+ # offers `-m`.
+ #
+ # @since 12.15
+ # @api private
+ # @see Useradd#useradd_options
+ # @return [Array<String>]
+ def useradd_options
+ opts = []
+ opts << "-m" if managing_home_dir?
+ opts
+ end
def manage_password
- if @current_resource.password != @new_resource.password && @new_resource.password
- Chef::Log.debug("#{@new_resource} setting password to #{@new_resource.password}")
- write_shadow_file
- end
+ return unless current_resource.password != new_resource.password && new_resource.password
+ Chef::Log.debug("#{new_resource} setting password to #{new_resource.password}")
+ write_shadow_file
end
def write_shadow_file
@@ -84,7 +92,7 @@ class Chef
::File.open(@password_file) do |shadow_file|
shadow_file.each do |entry|
user = entry.split(":").first
- if user == @new_resource.username
+ if user == new_resource.username
buffer.write(updated_password(entry))
else
buffer.write(entry)
@@ -95,7 +103,7 @@ class Chef
# FIXME: mostly duplicates code with file provider deploying a file
s = ::File.stat(@password_file)
- mode = s.mode & 07777
+ mode = s.mode & 0o7777
uid = s.uid
gid = s.gid
@@ -107,7 +115,7 @@ class Chef
def updated_password(entry)
fields = entry.split(":")
- fields[1] = @new_resource.password
+ fields[1] = new_resource.password
fields[2] = days_since_epoch
fields.join(":")
end
diff --git a/lib/chef/provider/user/useradd.rb b/lib/chef/provider/user/useradd.rb
index a1b5b3459c..cf6f4e727f 100644
--- a/lib/chef/provider/user/useradd.rb
+++ b/lib/chef/provider/user/useradd.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,32 +16,32 @@
# limitations under the License.
#
-require 'pathname'
-require 'chef/provider/user'
+require "pathname"
+require "chef/provider/user"
class Chef
class Provider
class User
class Useradd < Chef::Provider::User
- provides :user
+ # the linux version of this has been forked off, this is the base class now of solaris and AIX and should be abandoned
+ # and those provider should be rewritten like the linux version.
- UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:password, "-p"], [:shell, "-s"], [:uid, "-u"]]
+ UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:password, "-p"], [:shell, "-s"], [:uid, "-u"]].freeze
def create_user
command = compile_command("useradd") do |useradd|
useradd.concat(universal_options)
useradd.concat(useradd_options)
end
- shell_out!(*command)
+ shell_out_compact!(command)
end
def manage_user
- unless universal_options.empty?
- command = compile_command("usermod") do |u|
- u.concat(universal_options)
- end
- shell_out!(*command)
+ return if universal_options.empty?
+ command = compile_command("usermod") do |u|
+ u.concat(universal_options)
end
+ shell_out_compact!(command)
end
def remove_user
@@ -49,21 +49,21 @@ class Chef
command << "-r" if managing_home_dir?
command << "-f" if new_resource.force
command << new_resource.username
- shell_out!(*command)
+ shell_out_compact!(command)
end
def check_lock
# we can get an exit code of 1 even when it's successful on
# rhel/centos (redhat bug 578534). See additional error checks below.
- passwd_s = shell_out!("passwd", "-S", new_resource.username, :returns => [0,1])
+ passwd_s = shell_out_compact!("passwd", "-S", new_resource.username, returns: [0, 1])
if whyrun_mode? && passwd_s.stdout.empty? && passwd_s.stderr.match(/does not exist/)
# if we're in whyrun mode and the user is not yet created we assume it would be
return false
end
- raise Chef::Exceptions::User, "Cannot determine if #{@new_resource} is locked!" if passwd_s.stdout.empty?
+ raise Chef::Exceptions::User, "Cannot determine if #{new_resource} is locked!" if passwd_s.stdout.empty?
- status_line = passwd_s.stdout.split(' ')
+ status_line = passwd_s.stdout.split(" ")
case status_line[1]
when /^P/
@locked = false
@@ -75,11 +75,11 @@ class Chef
unless passwd_s.exitstatus == 0
raise_lock_error = false
- if ['redhat', 'centos'].include?(node[:platform])
- passwd_version_check = shell_out!('rpm -q passwd')
+ if %w{redhat centos}.include?(node[:platform])
+ passwd_version_check = shell_out_compact!("rpm", "-q", "passwd")
passwd_version = passwd_version_check.stdout.chomp
- unless passwd_version == 'passwd-0.73-1'
+ unless passwd_version == "passwd-0.73-1"
raise_lock_error = true
end
else
@@ -93,11 +93,11 @@ class Chef
end
def lock_user
- shell_out!("usermod", "-L", new_resource.username)
+ shell_out_compact!("usermod", "-L", new_resource.username)
end
def unlock_user
- shell_out!("usermod", "-U", new_resource.username)
+ shell_out_compact!("usermod", "-U", new_resource.username)
end
def compile_command(base_command)
@@ -116,31 +116,30 @@ class Chef
update_options(field, option, opts)
end
if updating_home?
+ opts << "-d" << new_resource.home
if managing_home_dir?
Chef::Log.debug("#{new_resource} managing the users home directory")
- opts << "-d" << new_resource.home << "-m"
+ opts << "-m"
else
Chef::Log.debug("#{new_resource} setting home to #{new_resource.home}")
- opts << "-d" << new_resource.home
end
end
- opts << "-o" if new_resource.non_unique || new_resource.supports[:non_unique]
+ opts << "-o" if non_unique?
opts
end
end
def update_options(field, option, opts)
- if @current_resource.send(field).to_s != new_resource.send(field).to_s
- if new_resource.send(field)
- Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field)}")
- opts << option << new_resource.send(field).to_s
- end
- end
+ return unless current_resource.send(field).to_s != new_resource.send(field).to_s
+ return unless new_resource.send(field)
+ Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field)}")
+ opts << option << new_resource.send(field).to_s
end
def useradd_options
opts = []
opts << "-r" if new_resource.system
+ opts << "-M" unless managing_home_dir?
opts
end
@@ -149,12 +148,8 @@ class Chef
# Pathname#cleanpath does a better job than ::File::expand_path (on both unix and windows)
# ::File.expand_path("///tmp") == ::File.expand_path("/tmp") => false
# ::File.expand_path("\\tmp") => "C:/tmp"
- return true if @current_resource.home.nil? && new_resource.home
- new_resource.home and Pathname.new(@current_resource.home).cleanpath != Pathname.new(new_resource.home).cleanpath
- end
-
- def managing_home_dir?
- new_resource.manage_home || new_resource.supports[:manage_home]
+ return true if current_resource.home.nil? && new_resource.home
+ new_resource.home && Pathname.new(current_resource.home).cleanpath != Pathname.new(new_resource.home).cleanpath
end
end
diff --git a/lib/chef/provider/user/windows.rb b/lib/chef/provider/user/windows.rb
index 76519bb498..0afa8fa14a 100644
--- a/lib/chef/provider/user/windows.rb
+++ b/lib/chef/provider/user/windows.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,46 +16,45 @@
# limitations under the License.
#
-require 'chef/provider/user'
-require 'chef/exceptions'
+require "chef/provider/user"
+require "chef/exceptions"
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
- require 'chef/util/windows/net_user'
+ require "chef/util/windows/net_user"
end
class Chef
class Provider
class User
class Windows < Chef::Provider::User
-
+ provides :windows_user
provides :user, os: "windows"
- def initialize(new_resource,run_context)
+ def initialize(new_resource, run_context)
super
- @net_user = Chef::Util::Windows::NetUser.new(@new_resource.username)
+ @net_user = Chef::Util::Windows::NetUser.new(new_resource.username)
end
def load_current_resource
- if @new_resource.gid
+ if new_resource.gid
Chef::Log.warn("The 'gid' attribute is not implemented by the Windows platform. Please use the 'group' resource to assign a user to a group.")
- end
+ end
- @current_resource = Chef::Resource::User.new(@new_resource.name)
- @current_resource.username(@new_resource.username)
- user_info = nil
+ @current_resource = Chef::Resource::User.new(new_resource.name)
+ current_resource.username(new_resource.username)
begin
user_info = @net_user.get_info
- @current_resource.uid(user_info[:user_id])
- @current_resource.comment(user_info[:full_name])
- @current_resource.home(user_info[:home_dir])
- @current_resource.shell(user_info[:script_path])
+ current_resource.uid(user_info[:user_id])
+ current_resource.comment(user_info[:full_name])
+ current_resource.home(user_info[:home_dir])
+ current_resource.shell(user_info[:script_path])
rescue Chef::Exceptions::UserIDNotFound => e
# e.message should be "The user name could not be found" but checking for that could cause a localization bug
@user_exists = false
- Chef::Log.debug("#{@new_resource} does not exist (#{e.message})")
+ Chef::Log.debug("#{new_resource} does not exist (#{e.message})")
end
- @current_resource
+ current_resource
end
# Check to see if the user needs any changes
@@ -64,12 +63,12 @@ class Chef
# <true>:: If a change is required
# <false>:: If the users are identical
def compare_user
- unless @net_user.validate_credentials(@new_resource.password)
- Chef::Log.debug("#{@new_resource} password has changed")
+ unless @net_user.validate_credentials(new_resource.password)
+ Chef::Log.debug("#{new_resource} password has changed")
return true
end
[ :uid, :comment, :home, :shell ].any? do |user_attrib|
- !@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib) != @current_resource.send(user_attrib)
+ !new_resource.send(user_attrib).nil? && new_resource.send(user_attrib) != current_resource.send(user_attrib)
end
end
@@ -98,26 +97,24 @@ class Chef
end
def set_options
- opts = {:name => @new_resource.username}
+ opts = { name: new_resource.username }
field_list = {
- 'comment' => 'full_name',
- 'home' => 'home_dir',
- 'uid' => 'user_id',
- 'shell' => 'script_path',
- 'password' => 'password'
+ "comment" => "full_name",
+ "home" => "home_dir",
+ "uid" => "user_id",
+ "shell" => "script_path",
+ "password" => "password",
}
- field_list.sort{ |a,b| a[0] <=> b[0] }.each do |field, option|
+ field_list.sort { |a, b| a[0] <=> b[0] }.each do |field, option|
field_symbol = field.to_sym
- if @current_resource.send(field_symbol) != @new_resource.send(field_symbol)
- if @new_resource.send(field_symbol)
- unless field_symbol == :password
- Chef::Log.debug("#{@new_resource} setting #{field} to #{@new_resource.send(field_symbol)}")
- end
- opts[option.to_sym] = @new_resource.send(field_symbol)
- end
+ next unless current_resource.send(field_symbol) != new_resource.send(field_symbol)
+ next unless new_resource.send(field_symbol)
+ unless field_symbol == :password
+ Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field_symbol)}")
end
+ opts[option.to_sym] = new_resource.send(field_symbol)
end
opts
end
diff --git a/lib/chef/provider/whyrun_safe_ruby_block.rb b/lib/chef/provider/whyrun_safe_ruby_block.rb
index 3b95752cc4..6e43dd4766 100644
--- a/lib/chef/provider/whyrun_safe_ruby_block.rb
+++ b/lib/chef/provider/whyrun_safe_ruby_block.rb
@@ -1,6 +1,6 @@
#
# Author:: Phil Dibowitz (<phild@fb.com>)
-# Copyright:: Copyright (c) 2013 Facebook
+# Copyright:: Copyright 2013-2016, Facebook
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,10 +22,10 @@ class Chef
provides :whyrun_safe_ruby_block
def action_run
- @new_resource.block.call
- @new_resource.updated_by_last_action(true)
- @run_context.events.resource_update_applied(@new_resource, :create, "execute the whyrun_safe_ruby_block #{@new_resource.name}")
- Chef::Log.info("#{@new_resource} called")
+ new_resource.block.call
+ new_resource.updated_by_last_action(true)
+ @run_context.events.resource_update_applied(new_resource, :create, "execute the whyrun_safe_ruby_block #{new_resource.name}")
+ Chef::Log.info("#{new_resource} called")
end
end
end
diff --git a/lib/chef/provider/windows_script.rb b/lib/chef/provider/windows_script.rb
index 62b49bd833..3b0202790c 100644
--- a/lib/chef/provider/windows_script.rb
+++ b/lib/chef/provider/windows_script.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/provider/script'
-require 'chef/mixin/windows_architecture_helper'
+require "chef/provider/script"
+require "chef/mixin/windows_architecture_helper"
class Chef
class Provider
@@ -29,12 +29,15 @@ class Chef
include Chef::Mixin::WindowsArchitectureHelper
- def initialize( new_resource, run_context, script_extension='')
+ def initialize( new_resource, run_context, script_extension = "")
super( new_resource, run_context )
@script_extension = script_extension
- target_architecture = new_resource.architecture.nil? ?
- node_windows_architecture(run_context.node) : new_resource.architecture
+ target_architecture = if new_resource.architecture.nil?
+ node_windows_architecture(run_context.node)
+ else
+ new_resource.architecture
+ end
@is_wow64 = wow64_architecture_override_required?(run_context.node, target_architecture)
diff --git a/lib/chef/provider/yum_repository.rb b/lib/chef/provider/yum_repository.rb
new file mode 100644
index 0000000000..be4d43f7ad
--- /dev/null
+++ b/lib/chef/provider/yum_repository.rb
@@ -0,0 +1,120 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource"
+require "chef/dsl/declare_resource"
+require "chef/mixin/shell_out"
+require "chef/mixin/which"
+require "chef/http/simple"
+require "chef/provider/noop"
+
+class Chef
+ class Provider
+ class YumRepository < Chef::Provider
+ use_inline_resources
+
+ extend Chef::Mixin::Which
+
+ provides :yum_repository do
+ which "yum"
+ end
+
+ def whyrun_supported?; true; end
+
+ def load_current_resource; end
+
+ action :create do
+ declare_resource(:template, "/etc/yum.repos.d/#{new_resource.repositoryid}.repo") do
+ if template_available?(new_resource.source)
+ source new_resource.source
+ else
+ source ::File.expand_path("../support/yum_repo.erb", __FILE__)
+ local true
+ end
+ sensitive new_resource.sensitive
+ variables(config: new_resource)
+ mode new_resource.mode
+ if new_resource.make_cache
+ notifies :run, "execute[yum clean metadata #{new_resource.repositoryid}]", :immediately if new_resource.clean_metadata || new_resource.clean_headers
+ notifies :run, "execute[yum-makecache-#{new_resource.repositoryid}]", :immediately
+ notifies :create, "ruby_block[yum-cache-reload-#{new_resource.repositoryid}]", :immediately
+ end
+ end
+
+ declare_resource(:execute, "yum clean metadata #{new_resource.repositoryid}") do
+ command "yum clean metadata --disablerepo=* --enablerepo=#{new_resource.repositoryid}"
+ action :nothing
+ end
+
+ # get the metadata for this repo only
+ declare_resource(:execute, "yum-makecache-#{new_resource.repositoryid}") do
+ command "yum -q -y makecache --disablerepo=* --enablerepo=#{new_resource.repositoryid}"
+ action :nothing
+ only_if { new_resource.enabled }
+ end
+
+ # reload internal Chef yum cache
+ declare_resource(:ruby_block, "yum-cache-reload-#{new_resource.repositoryid}") do
+ block { Chef::Provider::Package::Yum::YumCache.instance.reload }
+ action :nothing
+ end
+ end
+
+ action :delete do
+ # clean the repo cache first
+ declare_resource(:execute, "yum clean all #{new_resource.repositoryid}") do
+ command "yum clean all --disablerepo=* --enablerepo=#{new_resource.repositoryid}"
+ only_if "yum repolist all | grep -P '^#{new_resource.repositoryid}([ \t]|$)'"
+ end
+
+ declare_resource(:file, "/etc/yum.repos.d/#{new_resource.repositoryid}.repo") do
+ action :delete
+ notifies :create, "ruby_block[yum-cache-reload-#{new_resource.repositoryid}]", :immediately
+ end
+
+ declare_resource(:ruby_block, "yum-cache-reload-#{new_resource.repositoryid}") do
+ block { Chef::Provider::Package::Yum::YumCache.instance.reload }
+ action :nothing
+ end
+ end
+
+ action :makecache do
+ declare_resource(:execute, "yum-makecache-#{new_resource.repositoryid}") do
+ command "yum -q -y makecache --disablerepo=* --enablerepo=#{new_resource.repositoryid}"
+ action :run
+ only_if { new_resource.enabled }
+ end
+
+ declare_resource(:ruby_block, "yum-cache-reload-#{new_resource.repositoryid}") do
+ block { Chef::Provider::Package::Yum::YumCache.instance.reload }
+ action :run
+ end
+ end
+
+ alias_method :action_add, :action_create
+ alias_method :action_remove, :action_delete
+
+ def template_available?(path)
+ !path.nil? && run_context.has_template_in_cookbook?(new_resource.cookbook_name, path)
+ end
+
+ end
+ end
+end
+
+Chef::Provider::Noop.provides :yum_repository
diff --git a/lib/chef/provider_resolver.rb b/lib/chef/provider_resolver.rb
index 82a24fc078..2eb4d72ba5 100644
--- a/lib/chef/provider_resolver.rb
+++ b/lib/chef/provider_resolver.rb
@@ -1,6 +1,6 @@
#
# Author:: Richard Manyanza (<liseki@nyikacraftsmen.com>)
-# Copyright:: Copyright (c) 2014 Richard Manyanza.
+# Copyright:: Copyright 2014-2016, Richard Manyanza.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/exceptions'
-require 'chef/platform/priority_map'
+require "chef/exceptions"
+require "chef/platform/priority_map"
class Chef
#
@@ -90,8 +90,10 @@ class Chef
@prioritized_handlers ||= begin
supported_handlers = self.supported_handlers
if supported_handlers.empty?
- # if none of the providers specifically support the resource, we still need to pick one of the providers that are
- # enabled on the node to handle the why-run use case. FIXME we should only do this in why-run mode then.
+ # We always require a provider to be able to call define_resource_requirements on. In the why-run case we need
+ # a provider to say "assuming /etc/init.d/whatever would have been installed" and in the non-why-run case we
+ # need to make a best guess at "cannot find /etc/init.d/whatever". We are essentially defining a "default" provider
+ # for the platform, which is the best we can do, but which might give misleading errors, but we cannot read minds.
Chef::Log.debug "No providers responded true to `supports?` for action #{action} on resource #{resource}, falling back to enabled handlers so we can return something anyway."
supported_handlers = enabled_handlers
end
@@ -157,8 +159,8 @@ class Chef
# perf concern otherwise.)
handlers = providers.select { |handler| overrode_provides?(handler) && handler.provides?(node, resource) }
handlers.each do |handler|
- Chef.log_deprecation("#{handler}.provides? returned true when asked if it provides DSL #{resource.resource_name}, but provides #{resource.resource_name.inspect} was never called!")
- Chef.log_deprecation("In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself.")
+ message = "#{handler}.provides? returned true when asked if it provides DSL #{resource.resource_name}, but provides #{resource.resource_name.inspect} was never called! In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself."
+ Chef.deprecated(:custom_resource, message)
end
end
handlers
diff --git a/lib/chef/providers.rb b/lib/chef/providers.rb
index 18500d4669..35722840e6 100644
--- a/lib/chef/providers.rb
+++ b/lib/chef/providers.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,123 +16,137 @@
# limitations under the License.
#
-require 'chef/provider/batch'
-require 'chef/provider/breakpoint'
-require 'chef/provider/cookbook_file'
-require 'chef/provider/cron'
-require 'chef/provider/cron/solaris'
-require 'chef/provider/cron/aix'
-require 'chef/provider/deploy'
-require 'chef/provider/directory'
-require 'chef/provider/dsc_script'
-require 'chef/provider/dsc_resource'
-require 'chef/provider/env'
-require 'chef/provider/erl_call'
-require 'chef/provider/execute'
-require 'chef/provider/file'
-require 'chef/provider/git'
-require 'chef/provider/group'
-require 'chef/provider/http_request'
-require 'chef/provider/ifconfig'
-require 'chef/provider/link'
-require 'chef/provider/log'
-require 'chef/provider/ohai'
-require 'chef/provider/mdadm'
-require 'chef/provider/mount'
-require 'chef/provider/package'
-require 'chef/provider/powershell_script'
-require 'chef/provider/reboot'
-require 'chef/provider/remote_directory'
-require 'chef/provider/remote_file'
-require 'chef/provider/route'
-require 'chef/provider/ruby_block'
-require 'chef/provider/script'
-require 'chef/provider/service'
-require 'chef/provider/subversion'
-require 'chef/provider/template'
-require 'chef/provider/user'
-require 'chef/provider/whyrun_safe_ruby_block'
+require "chef/provider/apt_update"
+require "chef/provider/apt_repository"
+require "chef/provider/batch"
+require "chef/provider/breakpoint"
+require "chef/provider/cookbook_file"
+require "chef/provider/cron"
+require "chef/provider/cron/solaris"
+require "chef/provider/cron/aix"
+require "chef/provider/deploy"
+require "chef/provider/directory"
+require "chef/provider/dsc_script"
+require "chef/provider/dsc_resource"
+require "chef/provider/env"
+require "chef/provider/erl_call"
+require "chef/provider/execute"
+require "chef/provider/file"
+require "chef/provider/git"
+require "chef/provider/group"
+require "chef/provider/http_request"
+require "chef/provider/ifconfig"
+require "chef/provider/launchd"
+require "chef/provider/link"
+require "chef/provider/log"
+require "chef/provider/ohai"
+require "chef/provider/mdadm"
+require "chef/provider/mount"
+require "chef/provider/noop"
+require "chef/provider/package"
+require "chef/provider/powershell_script"
+require "chef/provider/osx_profile"
+require "chef/provider/reboot"
+require "chef/provider/remote_directory"
+require "chef/provider/remote_file"
+require "chef/provider/route"
+require "chef/provider/ruby_block"
+require "chef/provider/script"
+require "chef/provider/service"
+require "chef/provider/subversion"
+require "chef/provider/systemd_unit"
+require "chef/provider/template"
+require "chef/provider/user"
+require "chef/provider/whyrun_safe_ruby_block"
+require "chef/provider/yum_repository"
-require 'chef/provider/env/windows'
+require "chef/provider/env/windows"
-require 'chef/provider/package/apt'
-require 'chef/provider/package/dpkg'
-require 'chef/provider/package/easy_install'
-require 'chef/provider/package/freebsd/port'
-require 'chef/provider/package/freebsd/pkg'
-require 'chef/provider/package/freebsd/pkgng'
-require 'chef/provider/package/homebrew'
-require 'chef/provider/package/ips'
-require 'chef/provider/package/macports'
-require 'chef/provider/package/openbsd'
-require 'chef/provider/package/pacman'
-require 'chef/provider/package/portage'
-require 'chef/provider/package/paludis'
-require 'chef/provider/package/rpm'
-require 'chef/provider/package/rubygems'
-require 'chef/provider/package/yum'
-require 'chef/provider/package/zypper'
-require 'chef/provider/package/solaris'
-require 'chef/provider/package/smartos'
-require 'chef/provider/package/aix'
+require "chef/provider/package/apt"
+require "chef/provider/package/chocolatey"
+require "chef/provider/package/dpkg"
+require "chef/provider/package/dnf"
+require "chef/provider/package/easy_install"
+require "chef/provider/package/freebsd/port"
+require "chef/provider/package/freebsd/pkg"
+require "chef/provider/package/freebsd/pkgng"
+require "chef/provider/package/homebrew"
+require "chef/provider/package/ips"
+require "chef/provider/package/macports"
+require "chef/provider/package/openbsd"
+require "chef/provider/package/pacman"
+require "chef/provider/package/portage"
+require "chef/provider/package/paludis"
+require "chef/provider/package/rpm"
+require "chef/provider/package/rubygems"
+require "chef/provider/package/yum"
+require "chef/provider/package/zypper"
+require "chef/provider/package/solaris"
+require "chef/provider/package/smartos"
+require "chef/provider/package/aix"
+require "chef/provider/package/cab"
+require "chef/provider/package/powershell"
+require "chef/provider/package/msu"
-require 'chef/provider/service/arch'
-require 'chef/provider/service/freebsd'
-require 'chef/provider/service/gentoo'
-require 'chef/provider/service/init'
-require 'chef/provider/service/invokercd'
-require 'chef/provider/service/debian'
-require 'chef/provider/service/openbsd'
-require 'chef/provider/service/redhat'
-require 'chef/provider/service/insserv'
-require 'chef/provider/service/simple'
-require 'chef/provider/service/systemd'
-require 'chef/provider/service/upstart'
-require 'chef/provider/service/windows'
-require 'chef/provider/service/solaris'
-require 'chef/provider/service/macosx'
-require 'chef/provider/service/aixinit'
-require 'chef/provider/service/aix'
+require "chef/provider/service/arch"
+require "chef/provider/service/freebsd"
+require "chef/provider/service/gentoo"
+require "chef/provider/service/init"
+require "chef/provider/service/invokercd"
+require "chef/provider/service/debian"
+require "chef/provider/service/openbsd"
+require "chef/provider/service/redhat"
+require "chef/provider/service/insserv"
+require "chef/provider/service/simple"
+require "chef/provider/service/systemd"
+require "chef/provider/service/upstart"
+require "chef/provider/service/windows"
+require "chef/provider/service/solaris"
+require "chef/provider/service/macosx"
+require "chef/provider/service/aixinit"
+require "chef/provider/service/aix"
-require 'chef/provider/user/dscl'
-require 'chef/provider/user/pw'
-require 'chef/provider/user/useradd'
-require 'chef/provider/user/windows'
-require 'chef/provider/user/solaris'
-require 'chef/provider/user/aix'
+require "chef/provider/user/aix"
+require "chef/provider/user/dscl"
+require "chef/provider/user/linux"
+require "chef/provider/user/pw"
+require "chef/provider/user/solaris"
+require "chef/provider/user/useradd"
+require "chef/provider/user/windows"
-require 'chef/provider/group/aix'
-require 'chef/provider/group/dscl'
-require 'chef/provider/group/gpasswd'
-require 'chef/provider/group/groupadd'
-require 'chef/provider/group/groupmod'
-require 'chef/provider/group/pw'
-require 'chef/provider/group/suse'
-require 'chef/provider/group/usermod'
-require 'chef/provider/group/windows'
+require "chef/provider/group/aix"
+require "chef/provider/group/dscl"
+require "chef/provider/group/gpasswd"
+require "chef/provider/group/groupadd"
+require "chef/provider/group/groupmod"
+require "chef/provider/group/pw"
+require "chef/provider/group/suse"
+require "chef/provider/group/usermod"
+require "chef/provider/group/windows"
-require 'chef/provider/mount/mount'
-require 'chef/provider/mount/aix'
-require 'chef/provider/mount/solaris'
-require 'chef/provider/mount/windows'
+require "chef/provider/mount/mount"
+require "chef/provider/mount/aix"
+require "chef/provider/mount/solaris"
+require "chef/provider/mount/windows"
-require 'chef/provider/deploy/revision'
-require 'chef/provider/deploy/timestamped'
+require "chef/provider/deploy/revision"
+require "chef/provider/deploy/timestamped"
-require 'chef/provider/remote_file/ftp'
-require 'chef/provider/remote_file/http'
-require 'chef/provider/remote_file/local_file'
-require 'chef/provider/remote_file/network_file'
-require 'chef/provider/remote_file/fetcher'
+require "chef/provider/remote_file/ftp"
+require "chef/provider/remote_file/sftp"
+require "chef/provider/remote_file/http"
+require "chef/provider/remote_file/local_file"
+require "chef/provider/remote_file/network_file"
+require "chef/provider/remote_file/fetcher"
require "chef/provider/lwrp_base"
-require 'chef/provider/registry_key'
+require "chef/provider/registry_key"
-require 'chef/provider/file/content'
-require 'chef/provider/remote_file/content'
-require 'chef/provider/cookbook_file/content'
-require 'chef/provider/template/content'
+require "chef/provider/file/content"
+require "chef/provider/remote_file/content"
+require "chef/provider/cookbook_file/content"
+require "chef/provider/template/content"
-require 'chef/provider/ifconfig/redhat'
-require 'chef/provider/ifconfig/debian'
-require 'chef/provider/ifconfig/aix'
+require "chef/provider/ifconfig/redhat"
+require "chef/provider/ifconfig/debian"
+require "chef/provider/ifconfig/aix"
diff --git a/lib/chef/recipe.rb b/lib/chef/recipe.rb
index 262560f754..77d82f83ab 100644
--- a/lib/chef/recipe.rb
+++ b/lib/chef/recipe.rb
@@ -1,7 +1,7 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,32 +17,21 @@
# limitations under the License.
#
-
-require 'chef/dsl/recipe'
-require 'chef/dsl/data_query'
-require 'chef/dsl/platform_introspection'
-require 'chef/dsl/include_recipe'
-require 'chef/dsl/registry_helper'
-require 'chef/dsl/reboot_pending'
-require 'chef/dsl/audit'
-require 'chef/dsl/powershell'
-
-require 'chef/mixin/from_file'
-
-require 'chef/mixin/deprecation'
+require "chef/dsl/recipe"
+require "chef/mixin/from_file"
+require "chef/mixin/deprecation"
class Chef
# == Chef::Recipe
# A Recipe object is the context in which Chef recipes are evaluated.
class Recipe
+ attr_accessor :cookbook_name, :recipe_name, :recipe, :params, :run_context
- include Chef::DSL::Recipe::FullDSL
+ include Chef::DSL::Recipe
include Chef::Mixin::FromFile
include Chef::Mixin::Deprecation
- attr_accessor :cookbook_name, :recipe_name, :recipe, :params, :run_context
-
# Parses a potentially fully-qualified recipe name into its
# cookbook name and recipe short name.
#
@@ -97,10 +86,8 @@ class Chef
# true<TrueClass>:: If all the parameters are present
# false<FalseClass>:: If any of the parameters are missing
def tagged?(*tags)
- return false if run_context.node[:tags].nil?
-
tags.each do |tag|
- return false unless run_context.node[:tags].include?(tag)
+ return false unless run_context.node.tags.include?(tag)
end
true
end
@@ -111,12 +98,11 @@ class Chef
# tags<Array>:: A list of tags
#
# === Returns
- # tags<Array>:: The current list of run_context.node[:tags]
+ # tags<Array>:: The current list of run_context.node.tags
def untag(*tags)
tags.each do |tag|
- run_context.node.normal[:tags].delete(tag)
+ run_context.node.tags.delete(tag)
end
end
-
end
end
diff --git a/lib/chef/request_id.rb b/lib/chef/request_id.rb
index 2c7af01879..33e54d9edc 100644
--- a/lib/chef/request_id.rb
+++ b/lib/chef/request_id.rb
@@ -1,5 +1,5 @@
-# Author:: Prajakta Purohit (<prajakta@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010, 2013, 2014 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
# limitations under the License.
#
-require 'securerandom'
-require 'singleton'
+require "securerandom"
+require "singleton"
class Chef
class RequestID
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index 90453bd00e..40911cd2cc 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
# Author:: John Keiser (<jkeiser@chef.io)
-# Copyright:: Copyright (c) 2008-2015 Chef, Inc.
+# Copyright:: Copyright 2008-2016, Chef, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,31 +18,30 @@
# limitations under the License.
#
-require 'chef/exceptions'
-require 'chef/dsl/platform_introspection'
-require 'chef/dsl/data_query'
-require 'chef/dsl/registry_helper'
-require 'chef/dsl/reboot_pending'
-require 'chef/dsl/resources'
-require 'chef/mixin/convert_to_class_name'
-require 'chef/guard_interpreter/resource_guard_interpreter'
-require 'chef/resource/conditional'
-require 'chef/resource/conditional_action_not_nothing'
-require 'chef/resource/action_class'
-require 'chef/resource_collection'
-require 'chef/node_map'
-require 'chef/node'
-require 'chef/platform'
-require 'chef/resource/resource_notification'
-require 'chef/provider_resolver'
-require 'chef/resource_resolver'
-require 'set'
-
-require 'chef/mixin/deprecation'
-require 'chef/mixin/properties'
-require 'chef/mixin/provides'
-require 'chef/mixin/shell_out'
-require 'chef/mixin/powershell_out'
+require "chef/exceptions"
+require "chef/dsl/data_query"
+require "chef/dsl/registry_helper"
+require "chef/dsl/reboot_pending"
+require "chef/dsl/resources"
+require "chef/mixin/convert_to_class_name"
+require "chef/guard_interpreter/resource_guard_interpreter"
+require "chef/resource/conditional"
+require "chef/resource/conditional_action_not_nothing"
+require "chef/resource/action_class"
+require "chef/resource_collection"
+require "chef/node_map"
+require "chef/node"
+require "chef/platform"
+require "chef/resource/resource_notification"
+require "chef/provider_resolver"
+require "chef/resource_resolver"
+require "chef/provider"
+require "set"
+
+require "chef/mixin/deprecation"
+require "chef/mixin/properties"
+require "chef/mixin/provides"
+require "chef/dsl/universal"
class Chef
class Resource
@@ -52,14 +51,11 @@ class Chef
#
include Chef::DSL::DataQuery
- include Chef::DSL::PlatformIntrospection
include Chef::DSL::RegistryHelper
include Chef::DSL::RebootPending
extend Chef::Mixin::Provides
- # This lets user code do things like `not_if { shell_out!("command") }`
- include Chef::Mixin::ShellOut
- include Chef::Mixin::PowershellOut
+ include Chef::DSL::Universal
# Bring in `property` and `property_type`
include Chef::Mixin::Properties
@@ -87,7 +83,7 @@ class Chef
# @param name [Object] The name to set, typically a String or Array
# @return [String] The name of this Resource.
#
- property :name, String, coerce: proc { |v| v.is_a?(Array) ? v.join(', ') : v.to_s }, desired_state: false
+ property :name, String, coerce: proc { |v| v.is_a?(Array) ? v.join(", ") : v.to_s }, desired_state: false
#
# The node the current Chef run is using.
@@ -131,7 +127,7 @@ class Chef
# used for notifications to this resource).
# @param run_context The context of the Chef run. Corresponds to #run_context.
#
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
name(name) unless name.nil?
@run_context = run_context
@noop = nil
@@ -166,7 +162,7 @@ class Chef
# @param arg [Array[Symbol], Symbol] A list of actions (e.g. `:create`)
# @return [Array[Symbol]] the list of actions.
#
- def action(arg=nil)
+ def action(arg = nil)
if arg
arg = Array(arg).map(&:to_sym)
arg.each do |action|
@@ -185,6 +181,25 @@ class Chef
alias_method :action=, :action
#
+ # Force a delayed notification into this resource's run_context.
+ #
+ # This should most likely be paired with action :nothing
+ #
+ # @param arg [Array[Symbol], Symbol] A list of actions (e.g. `:create`)
+ #
+ def delayed_action(arg)
+ arg = Array(arg).map(&:to_sym)
+ arg.map do |action|
+ validate(
+ { action: action },
+ { action: { kind_of: Symbol, equal_to: allowed_actions } }
+ )
+ # the resource effectively sends a delayed notification to itself
+ run_context.add_delayed_action(Notification.new(self, action, self))
+ end
+ end
+
+ #
# Sets up a notification that will run a particular action on another resource
# if and when *this* resource is updated by an action.
#
@@ -208,6 +223,8 @@ class Chef
# actions have been run. This is the default.
# - `immediate`, `immediately`: Will run the action on the other resource
# immediately (before any other action is run).
+ # - `before`: Will run the action on the other resource
+ # immediately *before* the action is actually run.
#
# @example Resource by string
# file '/foo.txt' do
@@ -237,7 +254,7 @@ class Chef
# notifies :create, bar
# end
#
- def notifies(action, resource_spec, timing=:delayed)
+ def notifies(action, resource_spec, timing = :delayed)
# when using old-style resources(:template => "/foo.txt") style, you
# could end up with multiple resources.
validate_resource_spec!(resource_spec)
@@ -246,13 +263,15 @@ class Chef
resources.each do |resource|
case timing.to_s
- when 'delayed'
+ when "delayed"
notifies_delayed(action, resource)
- when 'immediate', 'immediately'
+ when "immediate", "immediately"
notifies_immediately(action, resource)
+ when "before"
+ notifies_before(action, resource)
else
raise ArgumentError, "invalid timing: #{timing} for notifies(#{action}, #{resources.inspect}, #{timing}) resource #{self} "\
- "Valid timings are: :delayed, :immediate, :immediately"
+ "Valid timings are: :delayed, :immediate, :immediately, :before"
end
end
@@ -260,6 +279,18 @@ class Chef
end
#
+ # Token class to hold an unresolved subscribes call with an associated
+ # run context.
+ #
+ # @api private
+ # @see Resource#subscribes
+ class UnresolvedSubscribes < self
+ # The full key ise given as the name in {Resource#subscribes}
+ alias_method :to_s, :name
+ alias_method :declared_key, :name
+ end
+
+ #
# Subscribes to updates from other resources, causing a particular action to
# run on *this* resource when the other resource is updated.
#
@@ -276,6 +307,8 @@ class Chef
# actions have been run. This is the default.
# - `immediate`, `immediately`: The action will run immediately following
# the other resource being updated.
+ # - `before`: The action will run immediately before the
+ # other resource is updated.
#
# @example Resources by string
# file '/foo.txt' do
@@ -320,11 +353,11 @@ class Chef
# subscribes :create, [ bar, baz ]
# end
#
- def subscribes(action, resources, timing=:delayed)
+ def subscribes(action, resources, timing = :delayed)
resources = [resources].flatten
resources.each do |resource|
if resource.is_a?(String)
- resource = Chef::Resource.new(resource, run_context)
+ resource = UnresolvedSubscribes.new(resource, run_context)
end
if resource.run_context.nil?
resource.run_context = run_context
@@ -357,7 +390,7 @@ class Chef
# @param opts [Hash] Options control the execution of the command
# @param block [Proc] A ruby block to run. Ignored if a command is given.
#
- def only_if(command=nil, opts={}, &block)
+ def only_if(command = nil, opts = {}, &block)
if command || block_given?
@only_if << Conditional.only_if(self, command, opts, &block)
end
@@ -387,7 +420,7 @@ class Chef
# @param opts [Hash] Options control the execution of the command
# @param block [Proc] A ruby block to run. Ignored if a command is given.
#
- def not_if(command=nil, opts={}, &block)
+ def not_if(command = nil, opts = {}, &block)
if command || block_given?
@not_if << Conditional.not_if(self, command, opts, &block)
end
@@ -404,7 +437,7 @@ class Chef
# @param arg [Integer] The number of retries.
# @return [Integer] The number of retries.
#
- def retries(arg=nil)
+ def retries(arg = nil)
set_or_return(:retries, arg, kind_of: Integer)
end
attr_writer :retries
@@ -415,7 +448,7 @@ class Chef
# @param arg [Integer] The number of seconds to wait between retries.
# @return [Integer] The number of seconds to wait between retries.
#
- def retry_delay(arg=nil)
+ def retry_delay(arg = nil)
set_or_return(:retry_delay, arg, kind_of: Integer)
end
attr_writer :retry_delay
@@ -427,7 +460,7 @@ class Chef
# @param arg [Boolean] Whether this resource is sensitive or not.
# @return [Boolean] Whether this resource is sensitive or not.
#
- def sensitive(arg=nil)
+ def sensitive(arg = nil)
set_or_return(:sensitive, arg, :kind_of => [ TrueClass, FalseClass ])
end
attr_writer :sensitive
@@ -461,7 +494,7 @@ class Chef
# symbol/name.
# @return [Class, Symbol, String] The Guard interpreter resource.
#
- def guard_interpreter(arg=nil)
+ def guard_interpreter(arg = nil)
if arg.nil?
@guard_interpreter || @default_guard_interpreter
else
@@ -483,7 +516,7 @@ class Chef
state_properties = self.class.state_properties
state_properties.each do |property|
if property.identity? || property.is_set?(self)
- state[property.name] = send(property.name)
+ state[property.name] = property.sensitive? ? "*sensitive value suppressed*" : send(property.name)
end
end
state
@@ -528,7 +561,7 @@ class Chef
# @param arg [Boolean] Whether to ignore failures.
# @return Whether this resource will ignore failures.
#
- def ignore_failure(arg=nil)
+ def ignore_failure(arg = nil)
set_or_return(:ignore_failure, arg, kind_of: [ TrueClass, FalseClass ])
end
attr_writer :ignore_failure
@@ -546,7 +579,7 @@ class Chef
def load_from(resource)
resource.instance_variables.each do |iv|
unless iv == :@source_line || iv == :@action || iv == :@not_if || iv == :@only_if
- self.instance_variable_set(iv, resource.instance_variable_get(iv))
+ instance_variable_set(iv, resource.instance_variable_get(iv))
end
end
end
@@ -560,7 +593,7 @@ class Chef
#
# @raise Any error that occurs during the actual action.
#
- def run_action(action, notification_type=nil, notifying_resource=nil)
+ def run_action(action, notification_type = nil, notifying_resource = nil)
# reset state in case of multiple actions on the same resource.
@elapsed_time = 0
start_time = Time.now
@@ -601,12 +634,26 @@ class Chef
events.resource_failed(self, action, e)
raise customize_exception(e)
end
- ensure
- @elapsed_time = Time.now - start_time
- # Reporting endpoint doesn't accept a negative resource duration so set it to 0.
- # A negative value can occur when a resource changes the system time backwards
- @elapsed_time = 0 if @elapsed_time < 0
- events.resource_completed(self)
+ end
+ ensure
+ @elapsed_time = Time.now - start_time
+ # Reporting endpoint doesn't accept a negative resource duration so set it to 0.
+ # A negative value can occur when a resource changes the system time backwards
+ @elapsed_time = 0 if @elapsed_time < 0
+ events.resource_completed(self)
+ end
+
+ #
+ # If we are currently initializing the resource, this will be true.
+ #
+ # Do NOT use this. It may be removed. It is for internal purposes only.
+ # @api private
+ attr_reader :resource_initializing
+ def resource_initializing=(value)
+ if value
+ @resource_initializing = true
+ else
+ remove_instance_variable(:@resource_initializing)
end
end
@@ -620,24 +667,37 @@ class Chef
def to_text
return "suppressed sensitive resource output" if sensitive
- ivars = instance_variables.map { |ivar| ivar.to_sym } - HIDDEN_IVARS
text = "# Declared in #{@source_line}\n\n"
text << "#{resource_name}(\"#{name}\") do\n"
+
+ all_props = {}
+ self.class.state_properties.map do |p|
+ all_props[p.name.to_s] = p.sensitive? ? '"*sensitive value suppressed*"' : value_to_text(p.get(self))
+ end
+
+ ivars = instance_variables.map { |ivar| ivar.to_sym } - HIDDEN_IVARS
ivars.each do |ivar|
- if (value = instance_variable_get(ivar)) && !(value.respond_to?(:empty?) && value.empty?)
- value_string = value.respond_to?(:to_text) ? value.to_text : value.inspect
- text << " #{ivar.to_s.sub(/^@/,'')} #{value_string}\n"
+ iv = ivar.to_s.sub(/^@/, "")
+ if all_props.keys.include?(iv)
+ text << " #{iv} #{all_props[iv]}\n"
+ elsif (value = instance_variable_get(ivar)) && !(value.respond_to?(:empty?) && value.empty?)
+ text << " #{iv} #{value_to_text(value)}\n"
end
end
+
[@not_if, @only_if].flatten.each do |conditional|
text << " #{conditional.to_text}\n"
end
text << "end\n"
end
+ def value_to_text(value)
+ value.respond_to?(:to_text) ? value.to_text : value.inspect
+ end
+
def inspect
ivars = instance_variables.map { |ivar| ivar.to_sym } - FORBIDDEN_IVARS
- ivars.inject("<#{to_s}") do |str, ivar|
+ ivars.inject("<#{self}") do |str, ivar|
str << " #{ivar}: #{instance_variable_get(ivar).inspect}"
end << ">"
end
@@ -649,11 +709,11 @@ class Chef
safe_ivars = instance_variables.map { |ivar| ivar.to_sym } - FORBIDDEN_IVARS
instance_vars = Hash.new
safe_ivars.each do |iv|
- instance_vars[iv.to_s.sub(/^@/, '')] = instance_variable_get(iv)
+ instance_vars[iv.to_s.sub(/^@/, "")] = instance_variable_get(iv)
end
{
- 'json_class' => self.class.name,
- 'instance_vars' => instance_vars
+ "json_class" => self.class.name,
+ "instance_vars" => instance_vars,
}
end
@@ -664,18 +724,23 @@ class Chef
end
def to_hash
+ # Grab all current state, then any other ivars (backcompat)
+ result = {}
+ self.class.state_properties.each do |p|
+ result[p.name] = p.get(self)
+ end
safe_ivars = instance_variables.map { |ivar| ivar.to_sym } - FORBIDDEN_IVARS
- instance_vars = Hash.new
safe_ivars.each do |iv|
- key = iv.to_s.sub(/^@/,'').to_sym
- instance_vars[key] = instance_variable_get(iv)
+ key = iv.to_s.sub(/^@/, "").to_sym
+ next if result.has_key?(key)
+ result[key] = instance_variable_get(iv)
end
- instance_vars
+ result
end
def self.json_create(o)
- resource = self.new(o["instance_vars"]["@name"])
- o["instance_vars"].each do |k,v|
+ resource = new(o["instance_vars"]["@name"])
+ o["instance_vars"].each do |k, v|
resource.instance_variable_set("@#{k}".to_sym, v)
end
resource
@@ -704,15 +769,16 @@ class Chef
#
# @see Chef::Resource.action_class
#
- def provider(arg=nil)
+ def provider(arg = nil)
klass = if arg.kind_of?(String) || arg.kind_of?(Symbol)
- lookup_provider_constant(arg)
- else
- arg
- end
+ lookup_provider_constant(arg)
+ else
+ arg
+ end
set_or_return(:provider, klass, kind_of: [ Class ]) ||
self.class.action_class
end
+
def provider=(arg)
provider(arg)
end
@@ -765,7 +831,7 @@ class Chef
# @raise [ArgumentError] If no arguments are passed and the resource has
# more than one identity property.
#
- def self.identity_property(name=nil)
+ def self.identity_property(name = nil)
result = identity_properties(*Array(name))
if result.size > 1
raise Chef::Exceptions::MultipleIdentityError, "identity_property cannot be called on an object with more than one identity property (#{result.map { |r| r.name }.join(", ")})."
@@ -787,7 +853,7 @@ class Chef
# @raise [ArgumentError] If no arguments are passed and the resource has
# more than one identity property.
#
- def self.identity_attr(name=nil)
+ def self.identity_attr(name = nil)
property = identity_property(name)
return nil if !property
property.name
@@ -816,7 +882,7 @@ class Chef
# have.
#
attr_accessor :allowed_actions
- def allowed_actions(value=NOT_PASSED)
+ def allowed_actions(value = NOT_PASSED)
if value != NOT_PASSED
self.allowed_actions = value
end
@@ -872,9 +938,7 @@ class Chef
# @deprecated Multiple actions are supported by resources. Please call {}#updated_by_last_action} instead.
#
def updated=(true_or_false)
- Chef::Log.warn("Chef::Resource#updated=(true|false) is deprecated. Please call #updated_by_last_action(true|false) instead.")
- Chef::Log.warn("Called from:")
- caller[0..3].each {|line| Chef::Log.warn(line)}
+ Chef.deprecated(:custom_resource, "Chef::Resource#updated=(true|false) is deprecated. Please call #updated_by_last_action(true|false) instead.")
updated_by_last_action(true_or_false)
@updated = true_or_false
end
@@ -901,13 +965,14 @@ class Chef
# this resource. Default: {}
# @return Hash{Symbol=>Boolean} An array of things this resource supports.
#
- def supports(args={})
+ def supports(args = {})
if args.any?
@supports = args
else
@supports
end
end
+
def supports=(args)
supports(args)
end
@@ -928,9 +993,9 @@ class Chef
# @deprecated Use resource_name instead.
#
def self.dsl_name
- Chef.log_deprecation "Resource.dsl_name is deprecated and will be removed in Chef 13. Use resource_name instead."
+ Chef.deprecated(:custom_resource, "Resource.dsl_name is deprecated and will be removed in Chef 13. Use resource_name instead.")
if name
- name = self.name.split('::')[-1]
+ name = self.name.split("::")[-1]
convert_to_snake_case(name)
end
end
@@ -951,7 +1016,7 @@ class Chef
#
# @return [Symbol] The name of this resource type (e.g. `:execute`).
#
- def self.resource_name(name=NOT_PASSED)
+ def self.resource_name(name = NOT_PASSED)
# Setter
if name != NOT_PASSED
remove_canonical_dsl
@@ -970,6 +1035,7 @@ class Chef
end
@resource_name
end
+
def self.resource_name=(name)
resource_name(name)
end
@@ -983,7 +1049,7 @@ class Chef
# A::B::BlahDBlah -> blah_d_blah
#
def self.use_automatic_resource_name
- automatic_name = convert_to_snake_case(self.name.split('::')[-1])
+ automatic_name = convert_to_snake_case(name.split("::")[-1])
resource_name automatic_name
end
@@ -1003,9 +1069,9 @@ class Chef
#
# @deprecated Use `provides` on the provider, or `provider` on the resource, instead.
#
- def self.provider_base(arg=nil)
+ def self.provider_base(arg = nil)
if arg
- Chef.log_deprecation("Resource.provider_base is deprecated and will be removed in Chef 13. Use provides on the provider, or provider on the resource, instead.")
+ Chef.deprecated(:custom_resource, "Resource.provider_base is deprecated and will be removed in Chef 13. Use provides on the provider, or provider on the resource, instead.")
end
@provider_base ||= arg || Chef::Provider
end
@@ -1026,6 +1092,7 @@ class Chef
end
@allowed_actions |= actions.flatten
end
+
def self.allowed_actions=(value)
@allowed_actions = value.uniq
end
@@ -1043,7 +1110,7 @@ class Chef
#
# @return [Array<Symbol>] The default actions for the resource.
#
- def self.default_action(action_name=NOT_PASSED)
+ def self.default_action(action_name = NOT_PASSED)
unless action_name.equal?(NOT_PASSED)
@default_action = Array(action_name).map(&:to_sym)
self.allowed_actions |= @default_action
@@ -1057,6 +1124,7 @@ class Chef
[:nothing]
end
end
+
def self.default_action=(action_name)
default_action action_name
end
@@ -1149,14 +1217,18 @@ class Chef
# using `action :x do ... end`, then there is no need for this class and
# `action_class` will be `nil`.
#
+ # If a block is passed, the action_class is always created and the block is
+ # run inside it.
+ #
# @api private
#
- def self.action_class
- @action_class ||
- # If the superclass needed one, then we need one as well.
- if superclass.respond_to?(:action_class) && superclass.action_class
- declare_action_class
- end
+ def self.action_class(&block)
+ return @action_class if @action_class && !block
+ # If the superclass needed one, then we need one as well.
+ if block || (superclass.respond_to?(:action_class) && superclass.action_class)
+ @action_class = declare_action_class(&block)
+ end
+ @action_class
end
#
@@ -1166,19 +1238,21 @@ class Chef
# If a block is passed, it is run inside the action_class.
#
# @api private
- def self.declare_action_class
- return @action_class if @action_class
+ def self.declare_action_class(&block)
+ @action_class ||= begin
+ if superclass.respond_to?(:action_class)
+ base_provider = superclass.action_class
+ end
+ base_provider ||= Chef::Provider
- if superclass.respond_to?(:action_class)
- base_provider = superclass.action_class
- end
- base_provider ||= Chef::Provider
-
- resource_class = self
- @action_class = Class.new(base_provider) do
- include ActionClass
- self.resource_class = resource_class
- end
+ resource_class = self
+ Class.new(base_provider) do
+ include ActionClass
+ self.resource_class = resource_class
+ end
+ end
+ @action_class.class_eval(&block) if block
+ @action_class
end
#
@@ -1232,12 +1306,20 @@ class Chef
# resolve_resource_reference on each in turn, causing them to
# resolve lazy/forward references.
def resolve_notification_references
- run_context.immediate_notifications(self).each { |n|
+ run_context.before_notifications(self).each do |n|
n.resolve_resource_reference(run_context.resource_collection)
- }
- run_context.delayed_notifications(self).each {|n|
+ end
+ run_context.immediate_notifications(self).each do |n|
n.resolve_resource_reference(run_context.resource_collection)
- }
+ end
+ run_context.delayed_notifications(self).each do |n|
+ n.resolve_resource_reference(run_context.resource_collection)
+ end
+ end
+
+ # Helper for #notifies
+ def notifies_before(action, resource_spec)
+ run_context.notifies_before(Notification.new(resource_spec, action, self))
end
# Helper for #notifies
@@ -1273,6 +1355,7 @@ class Chef
def self.sorted_descendants
@@sorted_descendants ||= descendants.sort_by { |x| x.to_s }
end
+
def self.inherited(child)
super
@@sorted_descendants = nil
@@ -1284,7 +1367,6 @@ class Chef
end
end
-
# If an unknown method is invoked, determine whether the enclosing Provider's
# lexical scope can fulfill the request. E.g. This happens when the Resource's
# block invokes new_resource.
@@ -1292,7 +1374,7 @@ class Chef
if enclosing_provider && enclosing_provider.respond_to?(method_symbol)
enclosing_provider.send(method_symbol, *args, &block)
else
- raise NoMethodError, "undefined method `#{method_symbol.to_s}' for #{self.class.to_s}"
+ raise NoMethodError, "undefined method `#{method_symbol}' for #{self.class}"
end
end
@@ -1335,6 +1417,10 @@ class Chef
"#{declared_type}[#{@name}]"
end
+ def before_notifications
+ run_context.before_notifications(self)
+ end
+
def immediate_notifications
run_context.immediate_notifications(self)
end
@@ -1400,7 +1486,7 @@ class Chef
end
# ??? TODO Seems unused. Delete?
- def noop(tf=nil)
+ def noop(tf = nil)
if !tf.nil?
raise ArgumentError, "noop must be true or false!" unless tf == true || tf == false
@noop = tf
@@ -1413,7 +1499,7 @@ class Chef
if args.size == 1
args.first
else
- return *args
+ args
end
end
@@ -1475,6 +1561,13 @@ class Chef
#
# Returns the class with the given resource_name.
#
+ # NOTE: Chef::Resource.resource_matching_short_name(:package) returns
+ # Chef::Resource::Package, while on rhel the API call
+ # Chef::Resource.resource_for_node(:package, node) will return
+ # Chef::Resource::YumPackage -- which is probably what you really
+ # want. This API should most likely be removed or changed to call
+ # resource_for_node.
+ #
# ==== Parameters
# short_name<Symbol>:: short_name of the resource (ie :directory)
#
@@ -1486,37 +1579,36 @@ class Chef
end
# @api private
- def self.register_deprecated_lwrp_class(resource_class, class_name)
- if Chef::Resource.const_defined?(class_name, false)
- Chef::Log.warn "#{class_name} already exists! Deprecation class overwrites #{resource_class}"
- Chef::Resource.send(:remove_const, class_name)
- end
-
- if !Chef::Config[:treat_deprecation_warnings_as_errors]
- Chef::Resource.const_set(class_name, resource_class)
- deprecated_constants[class_name.to_sym] = resource_class
+ def lookup_provider_constant(name, action = :nothing)
+ self.class.provider_base.const_get(convert_to_class_name(name.to_s))
+ rescue NameError => e
+ if e.to_s =~ /#{Regexp.escape(self.class.provider_base.to_s)}/
+ raise ArgumentError, "No provider found to match '#{name}'"
+ else
+ raise e
end
-
end
- def self.deprecated_constants
- @deprecated_constants ||= {}
- end
+ module DeprecatedLWRPClass
- # @api private
- def lookup_provider_constant(name, action=:nothing)
- begin
- self.class.provider_base.const_get(convert_to_class_name(name.to_s))
- rescue NameError => e
- if e.to_s =~ /#{Regexp.escape(self.class.provider_base.to_s)}/
- raise ArgumentError, "No provider found to match '#{name}'"
- else
- raise e
+ # @api private
+ def register_deprecated_lwrp_class(resource_class, class_name)
+ if Chef::Resource.const_defined?(class_name, false)
+ Chef::Log.warn "#{class_name} already exists! Deprecation class overwrites #{resource_class}"
+ Chef::Resource.send(:remove_const, class_name)
+ end
+
+ if !Chef::Config[:treat_deprecation_warnings_as_errors]
+ Chef::Resource.const_set(class_name, resource_class)
+ Chef::Resource.deprecated_constants[class_name.to_sym] = resource_class
end
end
- end
- private
+ def deprecated_constants
+ raise "Deprecated constants should be called only on Chef::Resource" unless self == Chef::Resource
+ @deprecated_constants ||= {}
+ end
+ end
def self.remove_canonical_dsl
if @resource_name
@@ -1526,8 +1618,9 @@ class Chef
end
end
end
+ extend DeprecatedLWRPClass
end
end
# Requiring things at the bottom breaks cycles
-require 'chef/chef_class'
+require "chef/chef_class"
diff --git a/lib/chef/resource/action_class.rb b/lib/chef/resource/action_class.rb
index 12211418e9..98b4d87ef1 100644
--- a/lib/chef/resource/action_class.rb
+++ b/lib/chef/resource/action_class.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser (<jkeiser@chef.io)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,22 @@
# limitations under the License.
#
-require 'chef/exceptions'
+require "chef/exceptions"
+require "chef/dsl/recipe"
class Chef
class Resource
module ActionClass
+ include Chef::DSL::Recipe
+
+ def to_s
+ "#{new_resource || "<no resource>"} action #{action ? action.inspect : "<no action>"}"
+ end
+
+ def whyrun_supported?
+ true
+ end
+
#
# If load_current_value! is defined on the resource, use that.
#
@@ -32,7 +43,7 @@ class Chef
# We clear desired state in the copy, because it is supposed to be actual state.
# We keep identity properties and non-desired-state, which are assumed to be
# "control" values like `recurse: true`
- current_resource.class.properties.each do |name,property|
+ current_resource.class.properties.each do |name, property|
if property.desired_state? && !property.identity? && !property.name_property?
property.reset(current_resource)
end
diff --git a/lib/chef/resource/apt_package.rb b/lib/chef/resource/apt_package.rb
index ca119b50c4..069fefcb2b 100644
--- a/lib/chef/resource/apt_package.rb
+++ b/lib/chef/resource/apt_package.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,27 +16,16 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package/apt'
+require "chef/resource/package"
+require "chef/provider/package/apt"
class Chef
class Resource
class AptPackage < Chef::Resource::Package
-
+ resource_name :apt_package
provides :package, os: "linux", platform_family: [ "debian" ]
- def initialize(name, run_context=nil)
- super
- @default_release = nil
- end
-
- def default_release(arg=nil)
- set_or_return(
- :default_release,
- arg,
- :kind_of => [ String ]
- )
- end
+ property :default_release, String, desired_state: false
end
end
diff --git a/lib/chef/resource/apt_repository.rb b/lib/chef/resource/apt_repository.rb
new file mode 100644
index 0000000000..b38bd1c8ec
--- /dev/null
+++ b/lib/chef/resource/apt_repository.rb
@@ -0,0 +1,46 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource"
+
+class Chef
+ class Resource
+ class AptRepository < Chef::Resource
+ resource_name :apt_repository
+ provides :apt_repository
+
+ property :repo_name, String, name_property: true
+ property :uri, String
+ property :distribution, [ String, nil, false ], default: lazy { node["lsb"]["codename"] }, nillable: true, coerce: proc { |x| x ? x : nil }
+ property :components, Array, default: []
+ property :arch, [String, nil, false], default: nil, nillable: true, coerce: proc { |x| x ? x : nil }
+ property :trusted, [TrueClass, FalseClass], default: false
+ # whether or not to add the repository as a source repo, too
+ property :deb_src, [TrueClass, FalseClass], default: false
+ property :keyserver, [String, nil, false], default: "keyserver.ubuntu.com", nillable: true, coerce: proc { |x| x ? x : nil }
+ property :key, [String, nil, false], default: nil, nillable: true, coerce: proc { |x| x ? x : nil }
+ property :key_proxy, [String, nil, false], default: nil, nillable: true, coerce: proc { |x| x ? x : nil }
+
+ property :cookbook, [String, nil, false], default: nil, desired_state: false, nillable: true, coerce: proc { |x| x ? x : nil }
+ property :cache_rebuild, [TrueClass, FalseClass], default: true, desired_state: false
+
+ default_action :add
+ allowed_actions :add, :remove
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/file_system_error.rb b/lib/chef/resource/apt_update.rb
index 80aff35893..1a25ec2ef5 100644
--- a/lib/chef/chef_fs/file_system/file_system_error.rb
+++ b/lib/chef/resource/apt_update.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,18 @@
# limitations under the License.
#
+require "chef/resource"
+
class Chef
- module ChefFS
- module FileSystem
- class FileSystemError < StandardError
- def initialize(entry, cause = nil)
- @entry = entry
- @cause = cause
- end
+ class Resource
+ class AptUpdate < Chef::Resource
+ resource_name :apt_update
+ provides :apt_update
+
+ property :frequency, Integer, default: 86_400
- attr_reader :entry
- attr_reader :cause
- end
+ default_action :periodic
+ allowed_actions :update, :periodic
end
end
end
diff --git a/lib/chef/resource/bash.rb b/lib/chef/resource/bash.rb
index 025687e879..1238eedc42 100644
--- a/lib/chef/resource/bash.rb
+++ b/lib/chef/resource/bash.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'chef/resource/script'
-require 'chef/provider/script'
+require "chef/resource/script"
+require "chef/provider/script"
class Chef
class Resource
class Bash < Chef::Resource::Script
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@interpreter = "bash"
end
diff --git a/lib/chef/resource/batch.rb b/lib/chef/resource/batch.rb
index efe3f2205f..10e96839fb 100644
--- a/lib/chef/resource/batch.rb
+++ b/lib/chef/resource/batch.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/resource/windows_script'
+require "chef/resource/windows_script"
class Chef
class Resource
@@ -24,7 +24,7 @@ class Chef
provides :batch, os: "windows"
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super(name, run_context, nil, "cmd.exe")
end
diff --git a/lib/chef/resource/bff_package.rb b/lib/chef/resource/bff_package.rb
index 7c1496a46b..b14591876a 100644
--- a/lib/chef/resource/bff_package.rb
+++ b/lib/chef/resource/bff_package.rb
@@ -1,6 +1,6 @@
#
# Author:: Deepali Jagtap (<deepali.jagtap@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package/aix'
+require "chef/resource/package"
+require "chef/provider/package/aix"
class Chef
class Resource
diff --git a/lib/chef/resource/breakpoint.rb b/lib/chef/resource/breakpoint.rb
index 69dbc48050..a5eed0da94 100644
--- a/lib/chef/resource/breakpoint.rb
+++ b/lib/chef/resource/breakpoint.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,14 @@
# limitations under the License.
#
-
-require 'chef/resource'
+require "chef/resource"
class Chef
class Resource
class Breakpoint < Chef::Resource
default_action :break
- def initialize(action="break", *args)
+ def initialize(action = "break", *args)
super(caller.first, *args)
end
diff --git a/lib/chef/resource/cab_package.rb b/lib/chef/resource/cab_package.rb
new file mode 100644
index 0000000000..b7acfb0ec9
--- /dev/null
+++ b/lib/chef/resource/cab_package.rb
@@ -0,0 +1,44 @@
+#
+# Author:: Vasundhara Jagdale (<vasundhara.jagdale@msystechnologies.com>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource/package"
+require "chef/mixin/uris"
+
+class Chef
+ class Resource
+ class CabPackage < Chef::Resource::Package
+ include Chef::Mixin::Uris
+
+ provides :cab_package, os: "windows"
+
+ allowed_actions :install, :remove
+
+ def initialize(name, run_context = nil)
+ super
+ @resource_name = :cab_package
+ end
+
+ property :source, String,
+ coerce: (proc do |s|
+ unless s.nil?
+ uri_scheme?(s) ? s : Chef::Util::PathHelper.canonical_path(s, false)
+ end
+ end)
+ end
+ end
+end
diff --git a/lib/chef/resource/chef_gem.rb b/lib/chef/resource/chef_gem.rb
index 7e9d21ebd2..5f51c9e208 100644
--- a/lib/chef/resource/chef_gem.rb
+++ b/lib/chef/resource/chef_gem.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,48 +16,31 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/resource/gem_package'
+require "chef/resource/package"
+require "chef/resource/gem_package"
class Chef
class Resource
class ChefGem < Chef::Resource::Package::GemPackage
+ resource_name :chef_gem
- def initialize(name, run_context=nil)
- super
- @compile_time = Chef::Config[:chef_gem_compile_time]
- @gem_binary = RbConfig::CONFIG['bindir'] + "/gem"
- end
-
- # The chef_gem resources is for installing gems to the current gem environment only for use by Chef cookbooks.
- def gem_binary(arg=nil)
- if arg
- raise ArgumentError, "The chef_gem resource is restricted to the current gem environment, use gem_package to install to other environments."
- end
-
- @gem_binary
- end
-
- def compile_time(arg=nil)
- set_or_return(
- :compile_time,
- arg,
- :kind_of => [ TrueClass, FalseClass ]
- )
- end
+ property :gem_binary, default: "#{RbConfig::CONFIG['bindir']}/gem",
+ callbacks: {
+ "The chef_gem resource is restricted to the current gem environment, use gem_package to install to other environments." => proc { |v| v == "#{RbConfig::CONFIG['bindir']}/gem" },
+ }
+ property :compile_time, [ true, false, nil ], default: lazy { Chef::Config[:chef_gem_compile_time] }, desired_state: false
def after_created
# Chef::Resource.run_action: Caveat: this skips Chef::Runner.run_action, where notifications are handled
# Action could be an array of symbols, but probably won't (think install + enable for a package)
if compile_time.nil?
- Chef.log_deprecation "#{self} chef_gem compile_time installation is deprecated"
- Chef.log_deprecation "#{self} Please set `compile_time false` on the resource to use the new behavior."
- Chef.log_deprecation "#{self} or set `compile_time true` on the resource if compile_time behavior is required."
+ message = "#{self} chef_gem compile_time installation is deprecated. Please set `compile_time false` on the resource to use the new behavior, or set `compile_time true` on the resource if compile_time behavior is required."
+ Chef.deprecated :chef_gem_compile_time, message
end
if compile_time || compile_time.nil?
Array(action).each do |action|
- self.run_action(action)
+ run_action(action)
end
Gem.clear_paths
end
diff --git a/lib/chef/resource/chocolatey_package.rb b/lib/chef/resource/chocolatey_package.rb
new file mode 100644
index 0000000000..5460661f6d
--- /dev/null
+++ b/lib/chef/resource/chocolatey_package.rb
@@ -0,0 +1,40 @@
+#
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource/package"
+
+class Chef
+ class Resource
+ class ChocolateyPackage < Chef::Resource::Package
+
+ provides :chocolatey_package, os: "windows"
+
+ allowed_actions :install, :upgrade, :remove, :uninstall, :purge, :reconfig
+
+ def initialize(name, run_context = nil)
+ super
+ @resource_name = :chocolatey_package
+ end
+
+ property :package_name, [String, Array], coerce: proc { |x| [x].flatten }
+
+ property :version, [String, Array], coerce: proc { |x| [x].flatten }
+ property :returns, [Integer, Array], default: [ 0 ], desired_state: false
+ end
+ end
+end
diff --git a/lib/chef/resource/conditional.rb b/lib/chef/resource/conditional.rb
index 35bdae8d69..452718cae8 100644
--- a/lib/chef/resource/conditional.rb
+++ b/lib/chef/resource/conditional.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
-require 'chef/guard_interpreter'
+require "chef/mixin/shell_out"
+require "chef/guard_interpreter"
class Chef
class Resource
@@ -30,11 +30,11 @@ class Chef
private :new
end
- def self.not_if(parent_resource, command=nil, command_opts={}, &block)
+ def self.not_if(parent_resource, command = nil, command_opts = {}, &block)
new(:not_if, parent_resource, command, command_opts, &block)
end
- def self.only_if(parent_resource, command=nil, command_opts={}, &block)
+ def self.only_if(parent_resource, command = nil, command_opts = {}, &block)
new(:only_if, parent_resource, command, command_opts, &block)
end
@@ -43,7 +43,7 @@ class Chef
attr_reader :command_opts
attr_reader :block
- def initialize(positivity, parent_resource, command=nil, command_opts={}, &block)
+ def initialize(positivity, parent_resource, command = nil, command_opts = {}, &block)
@positivity = positivity
@command, @command_opts = command, command_opts
@block = block
@@ -55,7 +55,7 @@ class Chef
def configure
case @command
- when String,Array
+ when String, Array
@guard_interpreter = Chef::GuardInterpreter.for_resource(@parent_resource, @command, @command_opts)
@block = nil
when nil
@@ -103,7 +103,15 @@ class Chef
end
def evaluate_block
- @block.call
+ @block.call.tap do |rv|
+ if rv.is_a?(String) && !rv.empty?
+ # This is probably a mistake:
+ # not_if { "command" }
+ sanitized_rv = @parent_resource.sensitive ? "a string" : rv.inspect
+ Chef::Log.warn("#{@positivity} block for #{@parent_resource} returned #{sanitized_rv}, did you mean to run a command?" +
+ (@parent_resource.sensitive ? "" : " If so use '#{@positivity} #{sanitized_rv}' in your code."))
+ end
+ end
end
def short_description
diff --git a/lib/chef/resource/conditional_action_not_nothing.rb b/lib/chef/resource/conditional_action_not_nothing.rb
index f6c34b20b5..94b542e33e 100644
--- a/lib/chef/resource/conditional_action_not_nothing.rb
+++ b/lib/chef/resource/conditional_action_not_nothing.rb
@@ -1,6 +1,6 @@
#
# Author:: Xabier de Zuazo (<xabier@onddo.com>)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/resource/cookbook_file.rb b/lib/chef/resource/cookbook_file.rb
index 42f16e6db6..785cf693be 100644
--- a/lib/chef/resource/cookbook_file.rb
+++ b/lib/chef/resource/cookbook_file.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,9 @@
# limitations under the License.
#
-require 'chef/resource/file'
-require 'chef/provider/cookbook_file'
-require 'chef/mixin/securable'
+require "chef/resource/file"
+require "chef/provider/cookbook_file"
+require "chef/mixin/securable"
class Chef
class Resource
@@ -29,18 +29,18 @@ class Chef
default_action :create
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@provider = Chef::Provider::CookbookFile
@source = ::File.basename(name)
@cookbook = nil
end
- def source(source_filename=nil)
+ def source(source_filename = nil)
set_or_return(:source, source_filename, :kind_of => [ String, Array ])
end
- def cookbook(cookbook_name=nil)
+ def cookbook(cookbook_name = nil)
set_or_return(:cookbook, cookbook_name, :kind_of => String)
end
diff --git a/lib/chef/resource/cron.rb b/lib/chef/resource/cron.rb
index 93cf41bc37..a76d454bf0 100644
--- a/lib/chef/resource/cron.rb
+++ b/lib/chef/resource/cron.rb
@@ -1,7 +1,7 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2009-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'chef/resource'
+require "chef/resource"
class Chef
class Resource
@@ -30,7 +30,7 @@ class Chef
default_action :create
allowed_actions :create, :delete
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@minute = "*"
@hour = "*"
@@ -47,7 +47,7 @@ class Chef
@environment = {}
end
- def minute(arg=nil)
+ def minute(arg = nil)
if arg.is_a?(Integer)
converted_arg = arg.to_s
else
@@ -64,7 +64,7 @@ class Chef
)
end
- def hour(arg=nil)
+ def hour(arg = nil)
if arg.is_a?(Integer)
converted_arg = arg.to_s
else
@@ -81,7 +81,7 @@ class Chef
)
end
- def day(arg=nil)
+ def day(arg = nil)
if arg.is_a?(Integer)
converted_arg = arg.to_s
else
@@ -98,7 +98,7 @@ class Chef
)
end
- def month(arg=nil)
+ def month(arg = nil)
if arg.is_a?(Integer)
converted_arg = arg.to_s
else
@@ -115,7 +115,7 @@ class Chef
)
end
- def weekday(arg=nil)
+ def weekday(arg = nil)
if arg.is_a?(Integer)
converted_arg = arg.to_s
else
@@ -123,11 +123,11 @@ class Chef
end
begin
error_message = "You provided '#{arg}' as a weekday, acceptable values are "
- error_message << Provider::Cron::WEEKDAY_SYMBOLS.map {|sym| ":#{sym.to_s}"}.join(', ')
+ error_message << Provider::Cron::WEEKDAY_SYMBOLS.map { |sym| ":#{sym}" }.join(", ")
error_message << " and a string in crontab format"
if (arg.is_a?(Symbol) && !Provider::Cron::WEEKDAY_SYMBOLS.include?(arg)) ||
- (!arg.is_a?(Symbol) && integerize(arg) > 7) ||
- (!arg.is_a?(Symbol) && integerize(arg) < 0)
+ (!arg.is_a?(Symbol) && integerize(arg) > 7) ||
+ (!arg.is_a?(Symbol) && integerize(arg) < 0)
raise RangeError, error_message
end
rescue ArgumentError
@@ -139,7 +139,7 @@ class Chef
)
end
- def time(arg=nil)
+ def time(arg = nil)
set_or_return(
:time,
arg,
@@ -147,7 +147,7 @@ class Chef
)
end
- def mailto(arg=nil)
+ def mailto(arg = nil)
set_or_return(
:mailto,
arg,
@@ -155,7 +155,7 @@ class Chef
)
end
- def path(arg=nil)
+ def path(arg = nil)
set_or_return(
:path,
arg,
@@ -163,7 +163,7 @@ class Chef
)
end
- def home(arg=nil)
+ def home(arg = nil)
set_or_return(
:home,
arg,
@@ -171,7 +171,7 @@ class Chef
)
end
- def shell(arg=nil)
+ def shell(arg = nil)
set_or_return(
:shell,
arg,
@@ -179,7 +179,7 @@ class Chef
)
end
- def command(arg=nil)
+ def command(arg = nil)
set_or_return(
:command,
arg,
@@ -187,7 +187,7 @@ class Chef
)
end
- def user(arg=nil)
+ def user(arg = nil)
set_or_return(
:user,
arg,
@@ -195,7 +195,7 @@ class Chef
)
end
- def environment(arg=nil)
+ def environment(arg = nil)
set_or_return(
:environment,
arg,
diff --git a/lib/chef/resource/csh.rb b/lib/chef/resource/csh.rb
index d5e9c910b1..4e7c22b660 100644
--- a/lib/chef/resource/csh.rb
+++ b/lib/chef/resource/csh.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'chef/resource/script'
-require 'chef/provider/script'
+require "chef/resource/script"
+require "chef/provider/script"
class Chef
class Resource
class Csh < Chef::Resource::Script
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@interpreter = "csh"
end
diff --git a/lib/chef/resource/deploy.rb b/lib/chef/resource/deploy.rb
index 5df46fff60..b8e6a26f97 100644
--- a/lib/chef/resource/deploy.rb
+++ b/lib/chef/resource/deploy.rb
@@ -1,7 +1,7 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -59,17 +59,17 @@ class Chef
default_action :deploy
allowed_actions :force_deploy, :deploy, :rollback
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@deploy_to = name
@environment = nil
- @repository_cache = 'cached-copy'
+ @repository_cache = "cached-copy"
@copy_exclude = []
@purge_before_symlink = %w{log tmp/pids public/system}
@create_dirs_before_symlink = %w{tmp public config}
- @symlink_before_migrate = {"config/database.yml" => "config/database.yml"}
- @symlinks = {"system" => "public/system", "pids" => "tmp/pids", "log" => "log"}
- @revision = 'HEAD'
+ @symlink_before_migrate = { "config/database.yml" => "config/database.yml" }
+ @symlinks = { "system" => "public/system", "pids" => "tmp/pids", "log" => "log" }
+ @revision = "HEAD"
@migrate = false
@rollback_on_error = false
@remote = "origin"
@@ -99,7 +99,7 @@ class Chef
@current_path ||= @deploy_to + "/current"
end
- def depth(arg=@shallow_clone ? 5 : nil)
+ def depth(arg = @shallow_clone ? 5 : nil)
set_or_return(
:depth,
arg,
@@ -108,7 +108,7 @@ class Chef
end
# note: deploy_to is your application "meta-root."
- def deploy_to(arg=nil)
+ def deploy_to(arg = nil)
set_or_return(
:deploy_to,
arg,
@@ -116,7 +116,7 @@ class Chef
)
end
- def repo(arg=nil)
+ def repo(arg = nil)
set_or_return(
:repo,
arg,
@@ -125,7 +125,7 @@ class Chef
end
alias :repository :repo
- def remote(arg=nil)
+ def remote(arg = nil)
set_or_return(
:remote,
arg,
@@ -133,7 +133,7 @@ class Chef
)
end
- def role(arg=nil)
+ def role(arg = nil)
set_or_return(
:role,
arg,
@@ -141,7 +141,7 @@ class Chef
)
end
- def restart_command(arg=nil, &block)
+ def restart_command(arg = nil, &block)
arg ||= block
set_or_return(
:restart_command,
@@ -151,7 +151,7 @@ class Chef
end
alias :restart :restart_command
- def migrate(arg=nil)
+ def migrate(arg = nil)
set_or_return(
:migrate,
arg,
@@ -159,7 +159,7 @@ class Chef
)
end
- def migration_command(arg=nil)
+ def migration_command(arg = nil)
set_or_return(
:migration_command,
arg,
@@ -167,7 +167,7 @@ class Chef
)
end
- def rollback_on_error(arg=nil)
+ def rollback_on_error(arg = nil)
set_or_return(
:rollback_on_error,
arg,
@@ -175,7 +175,7 @@ class Chef
)
end
- def user(arg=nil)
+ def user(arg = nil)
set_or_return(
:user,
arg,
@@ -183,7 +183,7 @@ class Chef
)
end
- def group(arg=nil)
+ def group(arg = nil)
set_or_return(
:group,
arg,
@@ -191,7 +191,7 @@ class Chef
)
end
- def enable_submodules(arg=nil)
+ def enable_submodules(arg = nil)
set_or_return(
:enable_submodules,
arg,
@@ -199,7 +199,7 @@ class Chef
)
end
- def shallow_clone(arg=nil)
+ def shallow_clone(arg = nil)
set_or_return(
:shallow_clone,
arg,
@@ -207,7 +207,7 @@ class Chef
)
end
- def repository_cache(arg=nil)
+ def repository_cache(arg = nil)
set_or_return(
:repository_cache,
arg,
@@ -215,7 +215,7 @@ class Chef
)
end
- def copy_exclude(arg=nil)
+ def copy_exclude(arg = nil)
set_or_return(
:copy_exclude,
arg,
@@ -223,7 +223,7 @@ class Chef
)
end
- def revision(arg=nil)
+ def revision(arg = nil)
set_or_return(
:revision,
arg,
@@ -232,7 +232,7 @@ class Chef
end
alias :branch :revision
- def git_ssh_wrapper(arg=nil)
+ def git_ssh_wrapper(arg = nil)
set_or_return(
:git_ssh_wrapper,
arg,
@@ -241,7 +241,7 @@ class Chef
end
alias :ssh_wrapper :git_ssh_wrapper
- def svn_username(arg=nil)
+ def svn_username(arg = nil)
set_or_return(
:svn_username,
arg,
@@ -249,7 +249,7 @@ class Chef
)
end
- def svn_password(arg=nil)
+ def svn_password(arg = nil)
set_or_return(
:svn_password,
arg,
@@ -257,7 +257,7 @@ class Chef
)
end
- def svn_arguments(arg=nil)
+ def svn_arguments(arg = nil)
set_or_return(
:svn_arguments,
arg,
@@ -265,14 +265,14 @@ class Chef
)
end
- def svn_info_args(arg=nil)
+ def svn_info_args(arg = nil)
set_or_return(
:svn_arguments,
arg,
:kind_of => [ String ])
end
- def scm_provider(arg=nil)
+ def scm_provider(arg = nil)
klass = if arg.kind_of?(String) || arg.kind_of?(Symbol)
lookup_provider_constant(arg)
else
@@ -291,7 +291,7 @@ class Chef
Chef::Provider::Deploy
end
- def svn_force_export(arg=nil)
+ def svn_force_export(arg = nil)
set_or_return(
:svn_force_export,
arg,
@@ -299,11 +299,11 @@ class Chef
)
end
- def environment(arg=nil)
+ def environment(arg = nil)
if arg.is_a?(String)
Chef::Log.debug "Setting RAILS_ENV, RACK_ENV, and MERB_ENV to `#{arg}'"
Chef::Log.warn "[DEPRECATED] please modify your deploy recipe or attributes to set the environment using a hash"
- arg = {"RAILS_ENV"=>arg,"MERB_ENV"=>arg,"RACK_ENV"=>arg}
+ arg = { "RAILS_ENV" => arg, "MERB_ENV" => arg, "RACK_ENV" => arg }
end
set_or_return(
:environment,
@@ -313,7 +313,7 @@ class Chef
end
# The number of old release directories to keep around after cleanup
- def keep_releases(arg=nil)
+ def keep_releases(arg = nil)
[set_or_return(
:keep_releases,
arg,
@@ -324,7 +324,7 @@ class Chef
# SCM clone/checkout before symlinking. Use this to get rid of files and
# directories you want to be shared between releases.
# Default: ["log", "tmp/pids", "public/system"]
- def purge_before_symlink(arg=nil)
+ def purge_before_symlink(arg = nil)
set_or_return(
:purge_before_symlink,
arg,
@@ -340,7 +340,7 @@ class Chef
# then specify tmp here so that the tmp directory will exist when you
# symlink the pids directory in to the current release.
# Default: ["tmp", "public", "config"]
- def create_dirs_before_symlink(arg=nil)
+ def create_dirs_before_symlink(arg = nil)
set_or_return(
:create_dirs_before_symlink,
arg,
@@ -354,7 +354,7 @@ class Chef
# $shared/pids that you would like to symlink as $current_release/tmp/pids
# you specify it as "pids" => "tmp/pids"
# Default {"system" => "public/system", "pids" => "tmp/pids", "log" => "log"}
- def symlinks(arg=nil)
+ def symlinks(arg = nil)
set_or_return(
:symlinks,
arg,
@@ -369,7 +369,7 @@ class Chef
# For a rails/merb app, this is used to link in a known good database.yml
# (with the production db password) before running migrate.
# Default {"config/database.yml" => "config/database.yml"}
- def symlink_before_migrate(arg=nil)
+ def symlink_before_migrate(arg = nil)
set_or_return(
:symlink_before_migrate,
arg,
@@ -378,30 +378,30 @@ class Chef
end
# Callback fires before migration is run.
- def before_migrate(arg=nil, &block)
+ def before_migrate(arg = nil, &block)
arg ||= block
set_or_return(:before_migrate, arg, :kind_of => [Proc, String])
end
# Callback fires before symlinking
- def before_symlink(arg=nil, &block)
+ def before_symlink(arg = nil, &block)
arg ||= block
set_or_return(:before_symlink, arg, :kind_of => [Proc, String])
end
# Callback fires before restart
- def before_restart(arg=nil, &block)
+ def before_restart(arg = nil, &block)
arg ||= block
set_or_return(:before_restart, arg, :kind_of => [Proc, String])
end
# Callback fires after restart
- def after_restart(arg=nil, &block)
+ def after_restart(arg = nil, &block)
arg ||= block
set_or_return(:after_restart, arg, :kind_of => [Proc, String])
end
- def additional_remotes(arg=nil)
+ def additional_remotes(arg = nil)
set_or_return(
:additional_remotes,
arg,
@@ -409,7 +409,7 @@ class Chef
)
end
- def enable_checkout(arg=nil)
+ def enable_checkout(arg = nil)
set_or_return(
:enable_checkout,
arg,
@@ -417,7 +417,7 @@ class Chef
)
end
- def checkout_branch(arg=nil)
+ def checkout_branch(arg = nil)
set_or_return(
:checkout_branch,
arg,
@@ -430,7 +430,7 @@ class Chef
# timeout for SCM operations. The deploy resource must therefore support
# a timeout method, but the timeout it describes is for SCM operations,
# not the overall deployment. This is potentially confusing.
- def timeout(arg=nil)
+ def timeout(arg = nil)
set_or_return(
:timeout,
arg,
diff --git a/lib/chef/resource/deploy_revision.rb b/lib/chef/resource/deploy_revision.rb
index 1397359ac8..41046ec288 100644
--- a/lib/chef/resource/deploy_revision.rb
+++ b/lib/chef/resource/deploy_revision.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/resource/directory.rb b/lib/chef/resource/directory.rb
index 9cac2ce243..faad659668 100644
--- a/lib/chef/resource/directory.rb
+++ b/lib/chef/resource/directory.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,9 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/provider/directory'
-require 'chef/mixin/securable'
+require "chef/resource"
+require "chef/provider/directory"
+require "chef/mixin/securable"
class Chef
class Resource
@@ -35,13 +35,13 @@ class Chef
default_action :create
allowed_actions :create, :delete
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@path = name
@recursive = false
end
- def recursive(arg=nil)
+ def recursive(arg = nil)
set_or_return(
:recursive,
arg,
@@ -49,7 +49,7 @@ class Chef
)
end
- def path(arg=nil)
+ def path(arg = nil)
set_or_return(
:path,
arg,
diff --git a/lib/chef/resource/dnf_package.rb b/lib/chef/resource/dnf_package.rb
new file mode 100644
index 0000000000..f10c282f19
--- /dev/null
+++ b/lib/chef/resource/dnf_package.rb
@@ -0,0 +1,67 @@
+#
+# Copyright:: Copyright 2016-2017, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource/package"
+require "chef/mixin/which"
+require "chef/mixin/shell_out"
+
+class Chef
+ class Resource
+ class DnfPackage < Chef::Resource::Package
+ extend Chef::Mixin::Which
+ extend Chef::Mixin::ShellOut
+
+ resource_name :dnf_package
+
+ allowed_actions :install, :upgrade, :remove, :purge, :reconfig, :lock, :unlock, :flush_cache
+
+ provides :package, platform_family: %w{rhel fedora} do
+ which("dnf") && shell_out("rpm -q dnf").stdout =~ /^dnf-[1-9]/
+ end
+
+ provides :dnf_package
+
+ # Install a specific arch
+ property :arch, [String, Array], coerce: proc { |x| [x].flatten }
+
+ # Flush the in-memory available/installed cache, this does not flush the dnf caches on disk
+ property :flush_cache,
+ Hash,
+ default: { before: false, after: false },
+ coerce: proc { |v|
+ if v.is_a?(Hash)
+ v
+ elsif v.is_a?(Array)
+ v.each_with_object({}) { |arg, obj| obj[arg] = true }
+ elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
+ { before: v, after: v }
+ elsif v == :before
+ { before: true, after: false }
+ elsif v == :after
+ { after: true, before: false }
+ end
+ }
+
+ def allow_downgrade(arg = nil)
+ if !arg.nil?
+ Chef.deprecated(:dnf_package_allow_downgrade, "the allow_downgrade property on the dnf_package provider is not used, DNF supports downgrades by default.")
+ end
+ false
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/dpkg_package.rb b/lib/chef/resource/dpkg_package.rb
index 38adf24cf6..9ff3239884 100644
--- a/lib/chef/resource/dpkg_package.rb
+++ b/lib/chef/resource/dpkg_package.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package/dpkg'
+require "chef/resource/package"
class Chef
class Resource
class DpkgPackage < Chef::Resource::Package
-
+ resource_name :dpkg_package
provides :dpkg_package, os: "linux"
+ property :source, [ String, Array, nil ]
end
end
end
diff --git a/lib/chef/resource/dsc_resource.rb b/lib/chef/resource/dsc_resource.rb
index 5db00f49ca..d3b579e428 100644
--- a/lib/chef/resource/dsc_resource.rb
+++ b/lib/chef/resource/dsc_resource.rb
@@ -1,82 +1,129 @@
-#
-# Author:: Adam Edwards (<adamed@getchef.com>)
-#
-# Copyright:: 2014, Opscode, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-require 'chef/dsl/powershell'
-
-class Chef
- class Resource
- class DscResource < Chef::Resource
-
- provides :dsc_resource, os: "windows"
-
- include Chef::DSL::Powershell
-
- default_action :run
-
- def initialize(name, run_context)
- super
- @properties = {}
- @resource = nil
- end
-
- def resource(value=nil)
- if value
- @resource = value
- else
- @resource
- end
- end
-
- def module_name(value=nil)
- if value
- @module_name = value
- else
- @module_name
- end
- end
-
- def property(property_name, value=nil)
- if not property_name.is_a?(Symbol)
- raise TypeError, "A property name of type Symbol must be specified, '#{property_name.to_s}' of type #{property_name.class.to_s} was given"
- end
-
- if value.nil?
- value_of(@properties[property_name])
- else
- @properties[property_name] = value
- end
- end
-
- def properties
- @properties.reduce({}) do |memo, (k, v)|
- memo[k] = value_of(v)
- memo
- end
- end
-
- private
-
- def value_of(value)
- if value.is_a?(DelayedEvaluator)
- value.call
- else
- value
- end
- end
- end
- end
-end
+#
+# Author:: Adam Edwards (<adamed@chef.io>)
+#
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+require "chef/dsl/powershell"
+
+class Chef
+ class Resource
+ class DscResource < Chef::Resource
+ provides :dsc_resource, os: "windows"
+
+ # This class will check if the object responds to
+ # to_text. If it does, it will call that as opposed
+ # to inspect. This is useful for properties that hold
+ # objects such as PsCredential, where we do not want
+ # to dump the actual ivars
+ class ToTextHash < Hash
+ def to_text
+ descriptions = map do |(property, obj)|
+ obj_text = if obj.respond_to?(:to_text)
+ obj.to_text
+ else
+ obj.inspect
+ end
+ "#{property}=>#{obj_text}"
+ end
+ "{#{descriptions.join(', ')}}"
+ end
+ end
+
+ include Chef::DSL::Powershell
+
+ default_action :run
+
+ def initialize(name, run_context)
+ super
+ @properties = ToTextHash.new
+ @resource = nil
+ @reboot_action = :nothing
+ end
+
+ def resource(value = nil)
+ if value
+ @resource = value
+ else
+ @resource
+ end
+ end
+
+ def module_name(value = nil)
+ if value
+ @module_name = value
+ else
+ @module_name
+ end
+ end
+
+ def module_version(arg = nil)
+ set_or_return(
+ :module_version,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
+ def property(property_name, value = nil)
+ if not property_name.is_a?(Symbol)
+ raise TypeError, "A property name of type Symbol must be specified, '#{property_name}' of type #{property_name.class} was given"
+ end
+
+ if value.nil?
+ value_of(@properties[property_name])
+ else
+ @properties[property_name] = value
+ end
+ end
+
+ def properties
+ @properties.reduce({}) do |memo, (k, v)|
+ memo[k] = value_of(v)
+ memo
+ end
+ end
+
+ # This property takes the action message for the reboot resource
+ # If the set method of the DSC resource indicate that a reboot
+ # is necessary, reboot_action provides the mechanism for a reboot to
+ # be requested.
+ def reboot_action(value = nil)
+ if value
+ @reboot_action = value
+ else
+ @reboot_action
+ end
+ end
+
+ def timeout(arg = nil)
+ set_or_return(
+ :timeout,
+ arg,
+ :kind_of => [ Integer ]
+ )
+ end
+
+ private
+
+ def value_of(value)
+ if value.is_a?(DelayedEvaluator)
+ value.call
+ else
+ value
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/dsc_script.rb b/lib/chef/resource/dsc_script.rb
index c3602fa60e..7da29a651a 100644
--- a/lib/chef/resource/dsc_script.rb
+++ b/lib/chef/resource/dsc_script.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/exceptions'
-require 'chef/dsl/powershell'
+require "chef/exceptions"
+require "chef/dsl/powershell"
class Chef
class Resource
@@ -28,12 +28,12 @@ class Chef
default_action :run
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@imports = {}
end
- def code(arg=nil)
+ def code(arg = nil)
if arg && command
raise ArgumentError, "Only one of 'code' and 'command' attributes may be specified"
end
@@ -47,7 +47,7 @@ class Chef
)
end
- def configuration_name(arg=nil)
+ def configuration_name(arg = nil)
if arg && code
raise ArgumentError, "Attribute `configuration_name` may not be set if `code` is set"
end
@@ -58,7 +58,7 @@ class Chef
)
end
- def command(arg=nil)
+ def command(arg = nil)
if arg && code
raise ArgumentError, "The 'code' and 'command' attributes may not be used together"
end
@@ -69,7 +69,7 @@ class Chef
)
end
- def configuration_data(arg=nil)
+ def configuration_data(arg = nil)
if arg && configuration_data_script
raise ArgumentError, "The 'configuration_data' and 'configuration_data_script' attributes may not be used together"
end
@@ -80,7 +80,7 @@ class Chef
)
end
- def configuration_data_script(arg=nil)
+ def configuration_data_script(arg = nil)
if arg && configuration_data
raise ArgumentError, "The 'configuration_data' and 'configuration_data_script' attributes may not be used together"
end
@@ -91,11 +91,11 @@ class Chef
)
end
- def imports(module_name=nil, *args)
+ def imports(module_name = nil, *args)
if module_name
@imports[module_name] ||= []
if args.length == 0
- @imports[module_name] << '*'
+ @imports[module_name] << "*"
else
@imports[module_name].push(*args)
end
@@ -104,7 +104,7 @@ class Chef
end
end
- def flags(arg=nil)
+ def flags(arg = nil)
set_or_return(
:flags,
arg,
@@ -112,7 +112,7 @@ class Chef
)
end
- def cwd(arg=nil)
+ def cwd(arg = nil)
set_or_return(
:cwd,
arg,
@@ -120,7 +120,7 @@ class Chef
)
end
- def environment(arg=nil)
+ def environment(arg = nil)
set_or_return(
:environment,
arg,
@@ -128,7 +128,7 @@ class Chef
)
end
- def timeout(arg=nil)
+ def timeout(arg = nil)
set_or_return(
:timeout,
arg,
diff --git a/lib/chef/resource/easy_install_package.rb b/lib/chef/resource/easy_install_package.rb
index df4cee1ab3..dc5073a6f7 100644
--- a/lib/chef/resource/easy_install_package.rb
+++ b/lib/chef/resource/easy_install_package.rb
@@ -1,6 +1,6 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,35 +16,16 @@
# limitations under the License.
#
-require 'chef/resource/package'
+require "chef/resource/package"
class Chef
class Resource
class EasyInstallPackage < Chef::Resource::Package
+ resource_name :easy_install_package
- def easy_install_binary(arg=nil)
- set_or_return(
- :easy_install_binary,
- arg,
- :kind_of => [ String ]
- )
- end
-
- def python_binary(arg=nil)
- set_or_return(
- :python_install_binary,
- arg,
- :kind_of => [ String ]
- )
- end
-
- def module_name(arg=nil)
- set_or_return(
- :module_name,
- arg,
- :kind_of => [ String ]
- )
- end
+ property :easy_install_binary, String, desired_state: false
+ property :python_binary, String, desired_state: false
+ property :module_name, String, desired_state: false
end
end
diff --git a/lib/chef/resource/env.rb b/lib/chef/resource/env.rb
index 025bfc72b7..7fac8af40b 100644
--- a/lib/chef/resource/env.rb
+++ b/lib/chef/resource/env.rb
@@ -1,7 +1,7 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,14 +30,14 @@ class Chef
default_action :create
allowed_actions :create, :delete, :modify
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@key_name = name
@value = nil
@delim = nil
end
- def key_name(arg=nil)
+ def key_name(arg = nil)
set_or_return(
:key_name,
arg,
@@ -45,7 +45,7 @@ class Chef
)
end
- def value(arg=nil)
+ def value(arg = nil)
set_or_return(
:value,
arg,
@@ -53,7 +53,7 @@ class Chef
)
end
- def delim(arg=nil)
+ def delim(arg = nil)
set_or_return(
:delim,
arg,
diff --git a/lib/chef/resource/erl_call.rb b/lib/chef/resource/erl_call.rb
index 1976c54c45..3e317676a5 100644
--- a/lib/chef/resource/erl_call.rb
+++ b/lib/chef/resource/erl_call.rb
@@ -1,7 +1,7 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/provider/erl_call'
+require "chef/resource"
+require "chef/provider/erl_call"
class Chef
class Resource
@@ -30,7 +30,7 @@ class Chef
default_action :run
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@code = "q()." # your erlang code goes here
@@ -40,7 +40,7 @@ class Chef
@node_name = "chef@localhost" # the erlang node hostname
end
- def code(arg=nil)
+ def code(arg = nil)
set_or_return(
:code,
arg,
@@ -48,7 +48,7 @@ class Chef
)
end
- def cookie(arg=nil)
+ def cookie(arg = nil)
set_or_return(
:cookie,
arg,
@@ -56,7 +56,7 @@ class Chef
)
end
- def distributed(arg=nil)
+ def distributed(arg = nil)
set_or_return(
:distributed,
arg,
@@ -64,7 +64,7 @@ class Chef
)
end
- def name_type(arg=nil)
+ def name_type(arg = nil)
set_or_return(
:name_type,
arg,
@@ -72,7 +72,7 @@ class Chef
)
end
- def node_name(arg=nil)
+ def node_name(arg = nil)
set_or_return(
:node_name,
arg,
diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb
index 11c4ae045c..677c4608b3 100644
--- a/lib/chef/resource/execute.rb
+++ b/lib/chef/resource/execute.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/provider/execute'
+require "chef/resource"
+require "chef/provider/execute"
class Chef
class Resource
@@ -34,7 +34,7 @@ class Chef
default_action :run
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@command = name
@backup = 5
@@ -49,9 +49,10 @@ class Chef
@umask = nil
@default_guard_interpreter = :execute
@is_guard_interpreter = false
+ @live_stream = false
end
- def umask(arg=nil)
+ def umask(arg = nil)
set_or_return(
:umask,
arg,
@@ -59,7 +60,7 @@ class Chef
)
end
- def command(arg=nil)
+ def command(arg = nil)
set_or_return(
:command,
arg,
@@ -67,7 +68,7 @@ class Chef
)
end
- def creates(arg=nil)
+ def creates(arg = nil)
set_or_return(
:creates,
arg,
@@ -75,7 +76,7 @@ class Chef
)
end
- def cwd(arg=nil)
+ def cwd(arg = nil)
set_or_return(
:cwd,
arg,
@@ -83,7 +84,7 @@ class Chef
)
end
- def environment(arg=nil)
+ def environment(arg = nil)
set_or_return(
:environment,
arg,
@@ -93,7 +94,7 @@ class Chef
alias :env :environment
- def group(arg=nil)
+ def group(arg = nil)
set_or_return(
:group,
arg,
@@ -101,7 +102,14 @@ class Chef
)
end
- def path(arg=nil)
+ def live_stream(arg = nil)
+ set_or_return(
+ :live_stream,
+ arg,
+ :kind_of => [ TrueClass, FalseClass ])
+ end
+
+ def path(arg = nil)
Chef::Log.warn "The 'path' attribute of 'execute' is not used by any provider in Chef 11 or Chef 12. Use 'environment' attribute to configure 'PATH'. This attribute will be removed in Chef 13."
set_or_return(
@@ -111,7 +119,7 @@ class Chef
)
end
- def returns(arg=nil)
+ def returns(arg = nil)
set_or_return(
:returns,
arg,
@@ -119,7 +127,7 @@ class Chef
)
end
- def timeout(arg=nil)
+ def timeout(arg = nil)
set_or_return(
:timeout,
arg,
@@ -127,12 +135,18 @@ class Chef
)
end
- def user(arg=nil)
- set_or_return(
- :user,
- arg,
- :kind_of => [ String, Integer ]
- )
+ property :user, [ String, Integer ]
+
+ property :domain, String
+
+ property :password, String, sensitive: true
+
+ def sensitive(args = nil)
+ if password
+ true
+ else
+ super
+ end
end
def self.set_guard_inherited_attributes(*inherited_attributes)
@@ -151,6 +165,64 @@ class Chef
ancestor_attributes.concat(@class_inherited_attributes ? @class_inherited_attributes : []).uniq
end
+ def after_created
+ validate_identity_platform(user, password, domain)
+ identity = qualify_user(user, password, domain)
+ domain(identity[:domain])
+ user(identity[:user])
+ end
+
+ def validate_identity_platform(specified_user, password = nil, specified_domain = nil)
+ if node[:platform_family] == "windows"
+ if specified_user && password.nil?
+ raise ArgumentError, "A value for `password` must be specified when a value for `user` is specified on the Windows platform"
+ end
+ else
+ if password || specified_domain
+ raise Exceptions::UnsupportedPlatform, "Values for `domain` and `password` are only supported on the Windows platform"
+ end
+ end
+ end
+
+ def qualify_user(specified_user, password = nil, specified_domain = nil)
+ domain = specified_domain
+ user = specified_user
+
+ if specified_user.nil? && ! specified_domain.nil?
+ raise ArgumentError, "The domain `#{specified_domain}` was specified, but no user name was given"
+ end
+
+ # if domain is provided in both username and domain
+ if specified_user && ((specified_user.include? '\\') || (specified_user.include? "@")) && specified_domain
+ raise ArgumentError, "The domain is provided twice. Username: `#{specified_user}`, Domain: `#{specified_domain}`. Please specify domain only once."
+ end
+
+ if ! specified_user.nil? && specified_domain.nil?
+ # Splitting username of format: Domain\Username
+ domain_and_user = user.split('\\')
+
+ if domain_and_user.length == 2
+ domain = domain_and_user[0]
+ user = domain_and_user[1]
+ elsif domain_and_user.length == 1
+ # Splitting username of format: Username@Domain
+ domain_and_user = user.split("@")
+ if domain_and_user.length == 2
+ domain = domain_and_user[1]
+ user = domain_and_user[0]
+ elsif domain_and_user.length != 1
+ raise ArgumentError, "The specified user name `#{user}` is not a syntactically valid user name"
+ end
+ end
+ end
+
+ if ( password || domain ) && user.nil?
+ raise ArgumentError, "A value for `password` or `domain` was specified without specification of a value for `user`"
+ end
+
+ { domain: domain, user: user }
+ end
+
set_guard_inherited_attributes(
:cwd,
:environment,
diff --git a/lib/chef/resource/file.rb b/lib/chef/resource/file.rb
index d278652cc3..5c275a574f 100644
--- a/lib/chef/resource/file.rb
+++ b/lib/chef/resource/file.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,17 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/platform/query_helpers'
-require 'chef/mixin/securable'
-require 'chef/resource/file/verification'
+require "chef/resource"
+require "chef/platform/query_helpers"
+require "chef/mixin/securable"
+require "chef/resource/file/verification"
+require "pathname"
class Chef
class Resource
class File < Chef::Resource
include Chef::Mixin::Securable
- identity_attr :path
-
if Platform.windows?
# Use Windows rights instead of standard *nix permissions
state_attrs :checksum, :rights, :deny_rights
@@ -50,90 +49,25 @@ class Chef
default_action :create
allowed_actions :create, :delete, :touch, :create_if_missing
- def initialize(name, run_context=nil)
- super
- @path = name
- @backup = 5
- @atomic_update = Chef::Config[:file_atomic_update]
- @force_unlink = false
- @manage_symlink_source = nil
- @diff = nil
- @verifications = []
- end
-
- def content(arg=nil)
- set_or_return(
- :content,
- arg,
- :kind_of => String
- )
- end
-
- def backup(arg=nil)
- set_or_return(
- :backup,
- arg,
- :kind_of => [ Integer, FalseClass ]
- )
- end
-
- def checksum(arg=nil)
- set_or_return(
- :checksum,
- arg,
- :regex => /^[a-zA-Z0-9]{64}$/
- )
- end
-
- def path(arg=nil)
- set_or_return(
- :path,
- arg,
- :kind_of => String
- )
- end
-
- def diff(arg=nil)
- set_or_return(
- :diff,
- arg,
- :kind_of => String
- )
- end
-
- def atomic_update(arg=nil)
- set_or_return(
- :atomic_update,
- arg,
- :kind_of => [ TrueClass, FalseClass ]
- )
- end
-
- def force_unlink(arg=nil)
- set_or_return(
- :force_unlink,
- arg,
- :kind_of => [ TrueClass, FalseClass ]
- )
- end
-
- def manage_symlink_source(arg=nil)
- set_or_return(
- :manage_symlink_source,
- arg,
- :kind_of => [ TrueClass, FalseClass ]
- )
- end
-
- def verify(command=nil, opts={}, &block)
+ property :path, String, name_property: true, identity: true
+ property :atomic_update, [ true, false ], desired_state: false, default: lazy { |r| r.docker? && r.special_docker_files?(r.path) ? false : Chef::Config[:file_atomic_update] }
+ property :backup, [ Integer, false ], desired_state: false, default: 5
+ property :checksum, [ /^[a-zA-Z0-9]{64}$/, nil ]
+ property :content, [ String, nil ], desired_state: false
+ property :diff, [ String, nil ], desired_state: false
+ property :force_unlink, [ true, false ], desired_state: false, default: false
+ property :manage_symlink_source, [ true, false ], desired_state: false
+ property :verifications, Array, default: lazy { [] }
+
+ def verify(command = nil, opts = {}, &block)
if ! (command.nil? || [String, Symbol].include?(command.class))
raise ArgumentError, "verify requires either a string, symbol, or a block"
end
if command || block_given?
- @verifications << Verification.new(self, command, opts, &block)
+ verifications << Verification.new(self, command, opts, &block)
else
- @verifications
+ verifications
end
end
@@ -145,6 +79,10 @@ class Chef
end
state_attrs
end
+
+ def special_docker_files?(file)
+ %w{/etc/hosts /etc/hostname /etc/resolv.conf}.include?(Pathname(file.scrub).cleanpath.to_path)
+ end
end
end
end
diff --git a/lib/chef/resource/file/verification.rb b/lib/chef/resource/file/verification.rb
index ba0bb08201..3400684bc5 100644
--- a/lib/chef/resource/file/verification.rb
+++ b/lib/chef/resource/file/verification.rb
@@ -1,6 +1,6 @@
#
# Author:: Steven Danna (<steve@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc
+# Copyright:: Copyright 2014-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/exceptions'
-require 'chef/guard_interpreter'
-require 'chef/mixin/descendants_tracker'
+require "chef/exceptions"
+require "chef/guard_interpreter"
+require "chef/mixin/descendants_tracker"
class Chef
class Resource
@@ -28,7 +28,7 @@ class Chef
# See RFC 027 for a full specification
#
# File verifications allow user-supplied commands a means of
- # preventing file reosurce content deploys. Their intended use
+ # preventing file resource content deploys. Their intended use
# is to verify the contents of a temporary file before it is
# deployed onto the system.
#
@@ -73,7 +73,7 @@ class Chef
end
def self.lookup(name)
- c = descendants.find {|d| d.provides?(name) }
+ c = descendants.find { |d| d.provides?(name) }
if c.nil?
raise Chef::Exceptions::VerificationNotFound.new "No file verification for #{name} found."
end
@@ -86,7 +86,7 @@ class Chef
@parent_resource = parent_resource
end
- def verify(path, opts={})
+ def verify(path, opts = {})
Chef::Log.debug("Running verification[#{self}] on #{path}")
if @block
verify_block(path, opts)
@@ -108,11 +108,13 @@ class Chef
def verify_command(path, opts)
# First implementation interpolated `file`; docs & RFC claim `path`
# is interpolated. Until `file` can be deprecated, interpolate both.
- Chef.log_deprecation(
- '%{file} is deprecated in verify command and will not be '\
- 'supported in Chef 13. Please use %{path} instead.'
- ) if @command.include?('%{file}')
- command = @command % {:file => path, :path => path}
+ if @command.include?("%{file}")
+ Chef.deprecated(:verify_file,
+ "%{file} is deprecated in verify command and will not be "\
+ "supported in Chef 13. Please use %{path} instead."
+ )
+ end
+ command = @command % { :file => path, :path => path }
interpreter = Chef::GuardInterpreter.for_resource(@parent_resource, command, @command_opts)
interpreter.evaluate
end
diff --git a/lib/chef/resource/file/verification/systemd_unit.rb b/lib/chef/resource/file/verification/systemd_unit.rb
new file mode 100644
index 0000000000..b492b32d39
--- /dev/null
+++ b/lib/chef/resource/file/verification/systemd_unit.rb
@@ -0,0 +1,67 @@
+#
+# Author:: Mal Graty (<mal.graty@googlemail.com>)
+# Copyright:: Copyright 2013-2017, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/mixin/which"
+
+class Chef
+ class Resource
+ class File
+ class Verification
+
+ #
+ # Systemd provides a binary for verifying the correctness of
+ # unit files. Unfortunately some units have constraints on the
+ # filename meaning that normal verification against temp files
+ # won't work.
+ #
+ # Working around that requires placing a copy of the temp file
+ # in a temp directory, under its real name and running the
+ # verification tool against that file.
+ #
+
+ class SystemdUnit < Chef::Resource::File::Verification
+ include Chef::Mixin::Which
+
+ provides :systemd_unit
+
+ def initialize(parent_resource, command, opts, &block)
+ super
+ @command = systemd_analyze_cmd
+ end
+
+ def verify(path, opts = {})
+ return true unless systemd_analyze_path
+ Dir.mktmpdir("chef-systemd-unit") do |dir|
+ temp = "#{dir}/#{::File.basename(@parent_resource.path)}"
+ ::FileUtils.cp(path, temp)
+ verify_command(temp, opts)
+ end
+ end
+
+ def systemd_analyze_cmd
+ @systemd_analyze_cmd ||= "#{systemd_analyze_path} verify %{path}"
+ end
+
+ def systemd_analyze_path
+ @systemd_analyze_path ||= which("systemd-analyze")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/freebsd_package.rb b/lib/chef/resource/freebsd_package.rb
index c7c43450ba..ecaff95244 100644
--- a/lib/chef/resource/freebsd_package.rb
+++ b/lib/chef/resource/freebsd_package.rb
@@ -1,8 +1,8 @@
#
-# Authors:: AJ Christensen (<aj@opscode.com>)
+# Authors:: AJ Christensen (<aj@chef.io>)
# Richard Manyanza (<liseki@nyikacraftsmen.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2014 Richard Manyanza.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2014-2016, Richard Manyanza.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,17 +18,18 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package/freebsd/port'
-require 'chef/provider/package/freebsd/pkg'
-require 'chef/provider/package/freebsd/pkgng'
-require 'chef/mixin/shell_out'
+require "chef/resource/package"
+require "chef/provider/package/freebsd/port"
+require "chef/provider/package/freebsd/pkg"
+require "chef/provider/package/freebsd/pkgng"
+require "chef/mixin/shell_out"
class Chef
class Resource
class FreebsdPackage < Chef::Resource::Package
include Chef::Mixin::ShellOut
+ resource_name :freebsd_package
provides :package, platform: "freebsd"
def after_created
@@ -36,7 +37,7 @@ class Chef
end
def supports_pkgng?
- ships_with_pkgng? || !!shell_out!("make -V WITH_PKGNG", :env => nil).stdout.match(/yes/i)
+ ships_with_pkgng? || !!shell_out_compact!("make", "-V", "WITH_PKGNG", :env => nil).stdout.match(/yes/i)
end
private
@@ -44,11 +45,11 @@ class Chef
def ships_with_pkgng?
# It was not until __FreeBSD_version 1000017 that pkgng became
# the default binary package manager. See '/usr/ports/Mk/bsd.port.mk'.
- node.automatic[:os_version].to_i >= 1000017
+ node[:os_version].to_i >= 1000017
end
def assign_provider
- @provider = if @source.to_s =~ /^ports$/i
+ @provider = if source.to_s =~ /^ports$/i
Chef::Provider::Package::Freebsd::Port
elsif supports_pkgng?
Chef::Provider::Package::Freebsd::Pkgng
diff --git a/lib/chef/resource/gem_package.rb b/lib/chef/resource/gem_package.rb
index b981797876..5511d3c580 100644
--- a/lib/chef/resource/gem_package.rb
+++ b/lib/chef/resource/gem_package.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,29 +16,17 @@
# limitations under the License.
#
-require 'chef/resource/package'
+require "chef/resource/package"
class Chef
class Resource
class GemPackage < Chef::Resource::Package
+ resource_name :gem_package
- def initialize(name, run_context=nil)
- super
- @clear_sources = false
- end
-
- def source(arg=nil)
- set_or_return(:source, arg, :kind_of => [ String, Array ])
- end
-
- def clear_sources(arg=nil)
- set_or_return(:clear_sources, arg, :kind_of => [ TrueClass, FalseClass ])
- end
-
+ property :source, [ String, Array ]
+ property :clear_sources, [ true, false ], default: false, desired_state: false
# Sets a custom gem_binary to run for gem commands.
- def gem_binary(gem_cmd=nil)
- set_or_return(:gem_binary,gem_cmd,:kind_of => [ String ])
- end
+ property :gem_binary, String, desired_state: false
##
# Options for the gem install, either a Hash or a String. When a hash is
@@ -46,10 +34,7 @@ class Chef
# gem will be installed via the gems API. When a String is given, the gem
# will be installed by shelling out to the gem command. Using a Hash of
# options with an explicit gem_binary will result in undefined behavior.
- def options(opts=nil)
- set_or_return(:options,opts,:kind_of => [String,Hash])
- end
-
+ property :options, [ String, Hash, Array, nil ], desired_state: false
end
end
diff --git a/lib/chef/resource/git.rb b/lib/chef/resource/git.rb
index 393a0689fe..4799b54d3d 100644
--- a/lib/chef/resource/git.rb
+++ b/lib/chef/resource/git.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,12 +22,12 @@ class Chef
class Resource
class Git < Chef::Resource::Scm
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@additional_remotes = Hash[]
end
- def additional_remotes(arg=nil)
+ def additional_remotes(arg = nil)
set_or_return(
:additional_remotes,
arg,
diff --git a/lib/chef/resource/group.rb b/lib/chef/resource/group.rb
index 2e80f32fea..d3a4a1ce89 100644
--- a/lib/chef/resource/group.rb
+++ b/lib/chef/resource/group.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,7 +28,7 @@ class Chef
allowed_actions :create, :remove, :modify, :manage
default_action :create
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@group_name = name
@gid = nil
@@ -38,7 +38,7 @@ class Chef
@non_unique = false
end
- def group_name(arg=nil)
+ def group_name(arg = nil)
set_or_return(
:group_name,
arg,
@@ -46,7 +46,7 @@ class Chef
)
end
- def gid(arg=nil)
+ def gid(arg = nil)
set_or_return(
:gid,
arg,
@@ -54,8 +54,8 @@ class Chef
)
end
- def members(arg=nil)
- converted_members = arg.is_a?(String) ? [].push(arg) : arg
+ def members(arg = nil)
+ converted_members = arg.is_a?(String) ? arg.split(",") : arg
set_or_return(
:members,
converted_members,
@@ -65,8 +65,8 @@ class Chef
alias_method :users, :members
- def excluded_members(arg=nil)
- converted_members = arg.is_a?(String) ? [].push(arg) : arg
+ def excluded_members(arg = nil)
+ converted_members = arg.is_a?(String) ? arg.split(",") : arg
set_or_return(
:excluded_members,
converted_members,
@@ -74,8 +74,7 @@ class Chef
)
end
-
- def append(arg=nil)
+ def append(arg = nil)
set_or_return(
:append,
arg,
@@ -83,7 +82,7 @@ class Chef
)
end
- def system(arg=nil)
+ def system(arg = nil)
set_or_return(
:system,
arg,
@@ -91,7 +90,7 @@ class Chef
)
end
- def non_unique(arg=nil)
+ def non_unique(arg = nil)
set_or_return(
:non_unique,
arg,
diff --git a/lib/chef/resource/homebrew_package.rb b/lib/chef/resource/homebrew_package.rb
index 048ba6b3aa..c2d0a65c5b 100644
--- a/lib/chef/resource/homebrew_package.rb
+++ b/lib/chef/resource/homebrew_package.rb
@@ -1,9 +1,9 @@
#
-# Author:: Joshua Timberman (<joshua@getchef.com>)
+# Author:: Joshua Timberman (<joshua@chef.io>)
# Author:: Graeme Mathieson (<mathie@woss.name>)
#
-# Copyright 2011-2013, Opscode, Inc.
-# Copyright 2014, Chef Software, Inc <legal@getchef.com>
+# Copyright 2011-2016, Chef Software Inc.
+# Copyright 2014-2016, Chef Software, Inc <legal@chef.io>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,27 +18,16 @@
# limitations under the License.
#
-require 'chef/provider/package'
-require 'chef/resource/package'
+require "chef/provider/package"
+require "chef/resource/package"
class Chef
class Resource
class HomebrewPackage < Chef::Resource::Package
-
+ resource_name :homebrew_package
provides :package, os: "darwin"
- def initialize(name, run_context=nil)
- super
- @homebrew_user = nil
- end
-
- def homebrew_user(arg=nil)
- set_or_return(
- :homebrew_user,
- arg,
- :kind_of => [ String, Integer ]
- )
- end
+ property :homebrew_user, [ String, Integer ]
end
end
diff --git a/lib/chef/resource/http_request.rb b/lib/chef/resource/http_request.rb
index f9f056325a..fcc48470bc 100644
--- a/lib/chef/resource/http_request.rb
+++ b/lib/chef/resource/http_request.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/provider/http_request'
+require "chef/resource"
+require "chef/provider/http_request"
class Chef
class Resource
@@ -29,14 +29,14 @@ class Chef
default_action :get
allowed_actions :get, :put, :post, :delete, :head, :options
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@message = name
@url = nil
@headers = {}
end
- def url(args=nil)
+ def url(args = nil)
set_or_return(
:url,
args,
@@ -44,7 +44,7 @@ class Chef
)
end
- def message(args=nil, &block)
+ def message(args = nil, &block)
args = block if block_given?
set_or_return(
:message,
@@ -53,7 +53,7 @@ class Chef
)
end
- def headers(args=nil)
+ def headers(args = nil)
set_or_return(
:headers,
args,
diff --git a/lib/chef/resource/ifconfig.rb b/lib/chef/resource/ifconfig.rb
index 527eb0e515..fd523d9580 100644
--- a/lib/chef/resource/ifconfig.rb
+++ b/lib/chef/resource/ifconfig.rb
@@ -1,7 +1,7 @@
#
# Author:: Jason K. Jackson (jasonjackson@gmail.com)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2009 Jason K. Jackson
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2009-2016, Jason K. Jackson
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'chef/resource'
+require "chef/resource"
class Chef
class Resource
@@ -30,7 +30,7 @@ class Chef
default_action :add
allowed_actions :add, :delete, :enable, :disable
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@target = name
@hwaddr = nil
@@ -46,7 +46,7 @@ class Chef
@onparent = nil
end
- def target(arg=nil)
+ def target(arg = nil)
set_or_return(
:target,
arg,
@@ -54,7 +54,7 @@ class Chef
)
end
- def device(arg=nil)
+ def device(arg = nil)
set_or_return(
:device,
arg,
@@ -62,7 +62,7 @@ class Chef
)
end
- def hwaddr(arg=nil)
+ def hwaddr(arg = nil)
set_or_return(
:hwaddr,
arg,
@@ -70,7 +70,7 @@ class Chef
)
end
- def inet_addr(arg=nil)
+ def inet_addr(arg = nil)
set_or_return(
:inet_addr,
arg,
@@ -78,7 +78,7 @@ class Chef
)
end
- def bcast(arg=nil)
+ def bcast(arg = nil)
set_or_return(
:bcast,
arg,
@@ -86,7 +86,7 @@ class Chef
)
end
- def mask(arg=nil)
+ def mask(arg = nil)
set_or_return(
:mask,
arg,
@@ -94,7 +94,7 @@ class Chef
)
end
- def mtu(arg=nil)
+ def mtu(arg = nil)
set_or_return(
:mtu,
arg,
@@ -102,7 +102,7 @@ class Chef
)
end
- def metric(arg=nil)
+ def metric(arg = nil)
set_or_return(
:metric,
arg,
@@ -110,7 +110,7 @@ class Chef
)
end
- def onboot(arg=nil)
+ def onboot(arg = nil)
set_or_return(
:onboot,
arg,
@@ -118,7 +118,7 @@ class Chef
)
end
- def network(arg=nil)
+ def network(arg = nil)
set_or_return(
:network,
arg,
@@ -126,7 +126,7 @@ class Chef
)
end
- def bootproto(arg=nil)
+ def bootproto(arg = nil)
set_or_return(
:bootproto,
arg,
@@ -134,7 +134,7 @@ class Chef
)
end
- def onparent(arg=nil)
+ def onparent(arg = nil)
set_or_return(
:onparent,
arg,
diff --git a/lib/chef/resource/ips_package.rb b/lib/chef/resource/ips_package.rb
index 2bf8e1dba8..4d2c957e17 100644
--- a/lib/chef/resource/ips_package.rb
+++ b/lib/chef/resource/ips_package.rb
@@ -1,6 +1,6 @@
#
# Author:: Jason Williams (<williamsjj@digitar.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,30 +16,19 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package/ips'
+require "chef/resource/package"
+require "chef/provider/package/ips"
class Chef
class Resource
class IpsPackage < ::Chef::Resource::Package
-
+ resource_name :ips_package
provides :package, os: "solaris2"
provides :ips_package, os: "solaris2"
allowed_actions :install, :remove, :upgrade
- def initialize(name, run_context = nil)
- super(name, run_context)
- @accept_license = false
- end
-
- def accept_license(arg=nil)
- set_or_return(
- :purge,
- arg,
- :kind_of => [ TrueClass, FalseClass ]
- )
- end
+ property :accept_license, [ true, false ], default: false, desired_state: false
end
end
end
diff --git a/lib/chef/chef_fs/file_system/not_found_error.rb b/lib/chef/resource/ksh.rb
index 9eab3d6131..3097156329 100644
--- a/lib/chef/chef_fs/file_system/not_found_error.rb
+++ b/lib/chef/resource/ksh.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Nolan Davidson (<nolan.davidson@gmail.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,17 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/file_system_error'
+require "chef/resource/script"
class Chef
- module ChefFS
- module FileSystem
- class NotFoundError < FileSystemError
- def initialize(entry, cause = nil)
- super(entry, cause)
- end
+ class Resource
+ class Ksh < Chef::Resource::Script
+
+ def initialize(name, run_context = nil)
+ super
+ @interpreter = "ksh"
end
+
end
end
end
diff --git a/lib/chef/resource/launchd.rb b/lib/chef/resource/launchd.rb
new file mode 100644
index 0000000000..c78ffa3f0e
--- /dev/null
+++ b/lib/chef/resource/launchd.rb
@@ -0,0 +1,156 @@
+#
+# Author:: Mike Dodge (<mikedodge04@gmail.com>)
+# Copyright:: Copyright (c) 2015 Facebook, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource"
+require "chef/provider/launchd"
+
+class Chef
+ class Resource
+ class Launchd < Chef::Resource
+ provides :launchd, os: "darwin"
+
+ identity_attr :label
+
+ default_action :create
+ allowed_actions :create, :create_if_missing, :delete, :enable, :disable
+
+ property :label, String, default: lazy { name }, identity: true
+ property :backup, [Integer, FalseClass]
+ property :cookbook, String
+ property :group, [String, Integer]
+ property :plist_hash, Hash
+ property :mode, [String, Integer]
+ property :owner, [String, Integer]
+ property :path, String
+ property :source, String
+ property :session_type, String
+
+ # StartCalendarInterval has some gotchas so we coerce it to help sanity
+ # check. According to `man 5 launchd.plist`:
+ # StartCalendarInterval <dictionary of integers or array of dictionaries of integers>
+ # ... Missing arguments are considered to be wildcard.
+ # What the man page doesn't state, but what was observed (OSX 10.11.5, launchctrl v3.4.0)
+ # Is that keys that are specified, but invalid, will also be treated as a wildcard
+ # this means that an entry like:
+ # { "Hour"=>0, "Weekday"=>"6-7"}
+ # will not just run on midnight of Sat and Sun, rather it will run _every_ midnight.
+ property :start_calendar_interval, [Hash, Array], coerce: proc { |type|
+ # Coerce into an array of hashes to make validation easier
+ array = if type.is_a?(Array)
+ type
+ else
+ [type]
+ end
+
+ # Check to make sure that our array only has hashes
+ unless array.all? { |obj| obj.is_a?(Hash) }
+ error_msg = "start_calendar_interval must be a single hash or an array of hashes!"
+ raise Chef::Exceptions::ValidationFailed, error_msg
+ end
+
+ # Make sure the hashes don't have any incorrect keys/values
+ array.each do |entry|
+ allowed_keys = %w{Minute Hour Day Weekday Month}
+ unless entry.keys.all? { |key| allowed_keys.include?(key) }
+ failed_keys = entry.keys.reject { |k| allowed_keys.include?(k) }.join(", ")
+ error_msg = "The following key(s): #{failed_keys} are invalid for start_calendar_interval, must be one of: #{allowed_keys.join(", ")}"
+ raise Chef::Exceptions::ValidationFailed, error_msg
+ end
+
+ unless entry.values.all? { |val| val.is_a?(Integer) }
+ failed_values = entry.values.reject { |val| val.is_a?(Integer) }.join(", ")
+ error_msg = "Invalid value(s) (#{failed_values}) for start_calendar_interval item. Values must be integers!"
+ raise Chef::Exceptions::ValidationFailed, error_msg
+ end
+ end
+
+ # Don't return array if we only have one entry
+ if array.size == 1
+ array.first
+ else
+ array
+ end
+ }
+
+ property :type, String, default: "daemon", coerce: proc { |type|
+ type = type ? type.downcase : "daemon"
+ types = %w{daemon agent}
+
+ unless types.include?(type)
+ error_msg = "type must be daemon or agent"
+ raise Chef::Exceptions::ValidationFailed, error_msg
+ end
+ type
+ }
+
+ # Apple LaunchD Keys
+ property :abandon_process_group, [ TrueClass, FalseClass ]
+ property :debug, [ TrueClass, FalseClass ]
+ property :disabled, [ TrueClass, FalseClass ], default: false
+ property :enable_globbing, [ TrueClass, FalseClass ]
+ property :enable_transactions, [ TrueClass, FalseClass ]
+ property :environment_variables, Hash
+ property :exit_timeout, Integer
+ property :hard_resource_limits, Hash
+ property :inetd_compatibility, Hash
+ property :init_groups, [ TrueClass, FalseClass ]
+ property :keep_alive, [ TrueClass, FalseClass, Hash ]
+ property :launch_only_once, [ TrueClass, FalseClass ]
+ property :ld_group, String
+ property :limit_load_from_hosts, Array
+ property :limit_load_to_hosts, Array
+ property :limit_load_to_session_type, Array
+ property :low_priority_io, [ TrueClass, FalseClass ]
+ property :mach_services, Hash
+ property :nice, Integer
+ property :on_demand, [ TrueClass, FalseClass ]
+ property :process_type, String
+ property :program, String
+ property :program_arguments, Array
+ property :queue_directories, Array
+ property :root_directory, String
+ property :run_at_load, [ TrueClass, FalseClass ]
+ property :sockets, Hash
+ property :soft_resource_limits, Array
+ property :standard_error_path, String
+ property :standard_in_path, String
+ property :standard_out_path, String
+ property :start_interval, Integer
+ property :start_on_mount, [ TrueClass, FalseClass ]
+ property :throttle_interval, Integer
+ property :time_out, Integer
+ property :umask, Integer
+ property :username, String
+ property :wait_for_debugger, [ TrueClass, FalseClass ]
+ property :watch_paths, Array
+ property :working_directory, String
+
+ # hash is an instance method on Object and needs to return a Fixnum.
+ def hash(arg = nil)
+ Chef.deprecated(:launchd_hash_property, "Property `hash` on the `launchd` resource has changed to `plist_hash`." \
+ "Please use `plist_hash` instead. This will raise an exception in Chef 13.")
+
+ set_or_return(
+ :plist_hash,
+ arg,
+ :kind_of => Hash
+ )
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/link.rb b/lib/chef/resource/link.rb
index f932383cc1..5717ec7bad 100644
--- a/lib/chef/resource/link.rb
+++ b/lib/chef/resource/link.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/mixin/securable'
+require "chef/resource"
+require "chef/mixin/securable"
class Chef
class Resource
@@ -32,7 +32,7 @@ class Chef
default_action :create
allowed_actions :create, :delete
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
verify_links_supported!
super
@to = nil
@@ -40,7 +40,7 @@ class Chef
@target_file = name
end
- def to(arg=nil)
+ def to(arg = nil)
set_or_return(
:to,
arg,
@@ -48,7 +48,7 @@ class Chef
)
end
- def target_file(arg=nil)
+ def target_file(arg = nil)
set_or_return(
:target_file,
arg,
@@ -56,7 +56,7 @@ class Chef
)
end
- def link_type(arg=nil)
+ def link_type(arg = nil)
real_arg = arg.kind_of?(String) ? arg.to_sym : arg
set_or_return(
:link_type,
@@ -65,7 +65,7 @@ class Chef
)
end
- def group(arg=nil)
+ def group(arg = nil)
set_or_return(
:group,
arg,
@@ -73,7 +73,7 @@ class Chef
)
end
- def owner(arg=nil)
+ def owner(arg = nil)
set_or_return(
:owner,
arg,
@@ -87,12 +87,13 @@ class Chef
end
private
+
def verify_links_supported!
# On certain versions of windows links are not supported. Make
# sure we are not on such a platform.
if Chef::Platform.windows?
- require 'chef/win32/file'
+ require "chef/win32/file"
begin
Chef::ReservedNames::Win32::File.verify_links_supported!
rescue Chef::Exceptions::Win32APIFunctionNotImplemented => e
diff --git a/lib/chef/resource/log.rb b/lib/chef/resource/log.rb
index 9adffb26bb..8f7879872f 100644
--- a/lib/chef/resource/log.rb
+++ b/lib/chef/resource/log.rb
@@ -1,7 +1,7 @@
#
# Author:: Cary Penniman (<cary@rightscale.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/provider/log'
+require "chef/resource"
+require "chef/provider/log"
class Chef
class Resource
@@ -48,13 +48,13 @@ class Chef
# name<String>:: Message to log
# collection<Array>:: Collection of included recipes
# node<Chef::Node>:: Node where resource will be used
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@level = :info
@message = name
end
- def message(arg=nil)
+ def message(arg = nil)
set_or_return(
:message,
arg,
@@ -63,7 +63,7 @@ class Chef
end
# <Symbol> Log level, one of :debug, :info, :warn, :error or :fatal
- def level(arg=nil)
+ def level(arg = nil)
set_or_return(
:level,
arg,
diff --git a/lib/chef/resource/lwrp_base.rb b/lib/chef/resource/lwrp_base.rb
index a9a669f18c..7dfe147341 100644
--- a/lib/chef/resource/lwrp_base.rb
+++ b/lib/chef/resource/lwrp_base.rb
@@ -2,7 +2,7 @@
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Christopher Walters (<cw@chef.io>)
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,14 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/resource_resolver'
-require 'chef/node'
-require 'chef/log'
-require 'chef/exceptions'
-require 'chef/mixin/convert_to_class_name'
-require 'chef/mixin/from_file'
-require 'chef/mixin/params_validate' # for DelayedEvaluator
+require "chef/resource"
+require "chef/resource_resolver"
+require "chef/node"
+require "chef/log"
+require "chef/exceptions"
+require "chef/mixin/convert_to_class_name"
+require "chef/mixin/from_file"
+require "chef/mixin/params_validate" # for DelayedEvaluator
class Chef
class Resource
@@ -45,7 +45,7 @@ class Chef
def build_from_file(cookbook_name, filename, run_context)
if LWRPBase.loaded_lwrps[filename]
- Chef::Log.info("Custom resource #{filename} from cookbook #{cookbook_name} has already been loaded! Skipping the reload.")
+ Chef::Log.debug("Custom resource #{filename} from cookbook #{cookbook_name} has already been loaded! Skipping the reload.")
return loaded_lwrps[filename]
end
@@ -102,10 +102,6 @@ class Chef
run_context ? run_context.node : nil
end
- def lazy(&block)
- DelayedEvaluator.new(&block)
- end
-
protected
def loaded_lwrps
diff --git a/lib/chef/resource/macosx_service.rb b/lib/chef/resource/macosx_service.rb
index f1ed4051cb..08c748bead 100644
--- a/lib/chef/resource/macosx_service.rb
+++ b/lib/chef/resource/macosx_service.rb
@@ -1,6 +1,6 @@
#
# Author:: Mike Dodge (<mikedodge04@gmail.com>)
-# Copyright:: Copyright (c) 2015 Facebook, Inc.
+# Copyright:: Copyright 2015-2016, Facebook, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/resource/service'
+require "chef/resource/service"
class Chef
class Resource
@@ -29,7 +29,7 @@ class Chef
state_attrs :enabled, :running
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@plist = nil
@session_type = nil
@@ -37,7 +37,7 @@ class Chef
# This will enable user to pass a plist in the case
# that the filename and label for the service dont match
- def plist(arg=nil)
+ def plist(arg = nil)
set_or_return(
:plist,
arg,
@@ -45,7 +45,7 @@ class Chef
)
end
- def session_type(arg=nil)
+ def session_type(arg = nil)
set_or_return(
:session_type,
arg,
diff --git a/lib/chef/resource/macports_package.rb b/lib/chef/resource/macports_package.rb
index 5843016897..3685334c17 100644
--- a/lib/chef/resource/macports_package.rb
+++ b/lib/chef/resource/macports_package.rb
@@ -1,6 +1,6 @@
#
# Author:: David Balatero (<dbalatero@gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,12 @@
# limitations under the License.
#
-require 'chef/resource/package'
+require "chef/resource/package"
class Chef
class Resource
class MacportsPackage < Chef::Resource::Package
+ resource_name :macports_package
end
end
end
diff --git a/lib/chef/resource/mdadm.rb b/lib/chef/resource/mdadm.rb
index b789fab155..df6e705f15 100644
--- a/lib/chef/resource/mdadm.rb
+++ b/lib/chef/resource/mdadm.rb
@@ -1,7 +1,7 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'chef/resource'
+require "chef/resource"
class Chef
class Resource
@@ -30,7 +30,7 @@ class Chef
default_action :create
allowed_actions :create, :assemble, :stop
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@chunk = 16
@@ -40,9 +40,10 @@ class Chef
@metadata = "0.90"
@bitmap = nil
@raid_device = name
+ @layout = nil
end
- def chunk(arg=nil)
+ def chunk(arg = nil)
set_or_return(
:chunk,
arg,
@@ -50,7 +51,7 @@ class Chef
)
end
- def devices(arg=nil)
+ def devices(arg = nil)
set_or_return(
:devices,
arg,
@@ -58,7 +59,7 @@ class Chef
)
end
- def exists(arg=nil)
+ def exists(arg = nil)
set_or_return(
:exists,
arg,
@@ -66,7 +67,7 @@ class Chef
)
end
- def level(arg=nil)
+ def level(arg = nil)
set_or_return(
:level,
arg,
@@ -74,7 +75,7 @@ class Chef
)
end
- def metadata(arg=nil)
+ def metadata(arg = nil)
set_or_return(
:metadata,
arg,
@@ -82,7 +83,7 @@ class Chef
)
end
- def bitmap(arg=nil)
+ def bitmap(arg = nil)
set_or_return(
:bitmap,
arg,
@@ -90,7 +91,7 @@ class Chef
)
end
- def raid_device(arg=nil)
+ def raid_device(arg = nil)
set_or_return(
:raid_device,
arg,
@@ -98,6 +99,13 @@ class Chef
)
end
+ def layout(arg = nil)
+ set_or_return(
+ :layout,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
end
end
diff --git a/lib/chef/resource/mount.rb b/lib/chef/resource/mount.rb
index a5da0ba329..3e35325246 100644
--- a/lib/chef/resource/mount.rb
+++ b/lib/chef/resource/mount.rb
@@ -1,7 +1,7 @@
#
-# Author:: Joshua Timberman (<joshua@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc
+# Author:: Joshua Timberman (<joshua@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'chef/resource'
+require "chef/resource"
class Chef
class Resource
@@ -28,14 +28,14 @@ class Chef
state_attrs :mount_point, :device_type, :fstype, :username, :password, :domain
default_action :mount
- allowed_actions :mount, :umount, :remount, :enable, :disable
+ allowed_actions :mount, :umount, :unmount, :remount, :enable, :disable
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@mount_point = name
@device = nil
@device_type = :device
- @fsck_device = '-'
+ @fsck_device = "-"
@fstype = "auto"
@options = ["defaults"]
@dump = 0
@@ -48,7 +48,7 @@ class Chef
@domain = nil
end
- def mount_point(arg=nil)
+ def mount_point(arg = nil)
set_or_return(
:mount_point,
arg,
@@ -56,7 +56,7 @@ class Chef
)
end
- def device(arg=nil)
+ def device(arg = nil)
set_or_return(
:device,
arg,
@@ -64,7 +64,7 @@ class Chef
)
end
- def device_type(arg=nil)
+ def device_type(arg = nil)
real_arg = arg.kind_of?(String) ? arg.to_sym : arg
valid_devices = if RUBY_PLATFORM =~ /solaris/i
[ :device ]
@@ -78,7 +78,7 @@ class Chef
)
end
- def fsck_device(arg=nil)
+ def fsck_device(arg = nil)
set_or_return(
:fsck_device,
arg,
@@ -86,7 +86,7 @@ class Chef
)
end
- def fstype(arg=nil)
+ def fstype(arg = nil)
set_or_return(
:fstype,
arg,
@@ -94,7 +94,7 @@ class Chef
)
end
- def options(arg=nil)
+ def options(arg = nil)
ret = set_or_return(
:options,
arg,
@@ -102,13 +102,13 @@ class Chef
)
if ret.is_a? String
- ret.gsub(/,/, ' ').split(/ /)
+ ret.tr(",", " ").split(/ /)
else
ret
end
end
- def dump(arg=nil)
+ def dump(arg = nil)
set_or_return(
:dump,
arg,
@@ -116,7 +116,7 @@ class Chef
)
end
- def pass(arg=nil)
+ def pass(arg = nil)
set_or_return(
:pass,
arg,
@@ -124,7 +124,7 @@ class Chef
)
end
- def mounted(arg=nil)
+ def mounted(arg = nil)
set_or_return(
:mounted,
arg,
@@ -132,7 +132,7 @@ class Chef
)
end
- def enabled(arg=nil)
+ def enabled(arg = nil)
set_or_return(
:enabled,
arg,
@@ -140,7 +140,7 @@ class Chef
)
end
- def supports(args={})
+ def supports(args = {})
if args.is_a? Array
args.each { |arg| @supports[arg] = true }
elsif args.any?
@@ -150,7 +150,7 @@ class Chef
end
end
- def username(arg=nil)
+ def username(arg = nil)
set_or_return(
:username,
arg,
@@ -158,7 +158,7 @@ class Chef
)
end
- def password(arg=nil)
+ def password(arg = nil)
set_or_return(
:password,
arg,
@@ -166,7 +166,7 @@ class Chef
)
end
- def domain(arg=nil)
+ def domain(arg = nil)
set_or_return(
:domain,
arg,
diff --git a/lib/chef/resource/msu_package.rb b/lib/chef/resource/msu_package.rb
new file mode 100644
index 0000000000..753992c185
--- /dev/null
+++ b/lib/chef/resource/msu_package.rb
@@ -0,0 +1,47 @@
+#
+# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource/package"
+require "chef/mixin/uris"
+
+class Chef
+ class Resource
+ class MsuPackage < Chef::Resource::Package
+ include Chef::Mixin::Uris
+
+ provides :msu_package, os: "windows"
+
+ allowed_actions :install, :remove
+
+ def initialize(name, run_context = nil)
+ super
+ @resource_name = :msu_package
+ @source = name
+ @action = :install
+ end
+
+ property :source, String,
+ coerce: (proc do |s|
+ unless s.nil?
+ uri_scheme?(s) ? s : Chef::Util::PathHelper.canonical_path(s, false)
+ end
+ end)
+ property :checksum, String, desired_state: false
+ end
+ end
+end
diff --git a/lib/chef/resource/ohai.rb b/lib/chef/resource/ohai.rb
index 9425e55c0c..6fffecf16e 100644
--- a/lib/chef/resource/ohai.rb
+++ b/lib/chef/resource/ohai.rb
@@ -1,7 +1,7 @@
#
# Author:: Michael Leinartas (<mleinartas@gmail.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2010 Michael Leinartas
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2010-2016, Michael Leinartas
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,34 +20,14 @@
class Chef
class Resource
class Ohai < Chef::Resource
+ resource_name :ohai
+ provides :ohai
- identity_attr :name
-
- state_attrs :plugin
+ property :ohai_name, name_property: true
+ property :plugin, [String]
default_action :reload
-
- def initialize(name, run_context=nil)
- super
- @name = name
- @plugin = nil
- end
-
- def plugin(arg=nil)
- set_or_return(
- :plugin,
- arg,
- :kind_of => [ String ]
- )
- end
-
- def name(arg=nil)
- set_or_return(
- :name,
- arg,
- :kind_of => [ String ]
- )
- end
+ allowed_actions :reload
end
end
end
diff --git a/lib/chef/resource/openbsd_package.rb b/lib/chef/resource/openbsd_package.rb
index 9ae8813d69..d0f9fe877f 100644
--- a/lib/chef/resource/openbsd_package.rb
+++ b/lib/chef/resource/openbsd_package.rb
@@ -1,9 +1,9 @@
#
-# Authors:: AJ Christensen (<aj@opscode.com>)
+# Authors:: AJ Christensen (<aj@chef.io>)
# Richard Manyanza (<liseki@nyikacraftsmen.com>)
# Scott Bonds (<scott@ggr.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2014 Richard Manyanza, Scott Bonds
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2014-2016, Richard Manyanza, Scott Bonds
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,15 +19,16 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package/openbsd'
-require 'chef/mixin/shell_out'
+require "chef/resource/package"
+require "chef/provider/package/openbsd"
+require "chef/mixin/shell_out"
class Chef
class Resource
class OpenbsdPackage < Chef::Resource::Package
include Chef::Mixin::ShellOut
+ resource_name :openbsd_package
provides :package, os: "openbsd"
end
end
diff --git a/lib/chef/resource/osx_profile.rb b/lib/chef/resource/osx_profile.rb
new file mode 100644
index 0000000000..8142e1fd96
--- /dev/null
+++ b/lib/chef/resource/osx_profile.rb
@@ -0,0 +1,74 @@
+#
+# Author:: Nate Walck (<nate.walck@gmail.com>)
+# Copyright:: Copyright 2015-2016, Facebook, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource"
+
+class Chef
+ class Resource
+ class OsxProfile < Chef::Resource
+ provides :osx_profile, os: "darwin"
+ provides :osx_config_profile, os: "darwin"
+
+ identity_attr :profile_name
+
+ default_action :install
+ allowed_actions :install, :remove
+
+ def initialize(name, run_context = nil)
+ super
+ @profile_name = name
+ @profile = nil
+ @identifier = nil
+ @path = nil
+ end
+
+ def profile_name(arg = nil)
+ set_or_return(
+ :profile_name,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
+ def profile(arg = nil)
+ set_or_return(
+ :profile,
+ arg,
+ :kind_of => [ String, Hash ]
+ )
+ end
+
+ def identifier(arg = nil)
+ set_or_return(
+ :identifier,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
+ def path(arg = nil)
+ set_or_return(
+ :path,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/resource/package.rb b/lib/chef/resource/package.rb
index 5be1c34b89..a1f174a6f3 100644
--- a/lib/chef/resource/package.rb
+++ b/lib/chef/resource/package.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,85 +17,30 @@
# limitations under the License.
#
-require 'chef/resource'
+require "chef/resource"
class Chef
class Resource
class Package < Chef::Resource
- identity_attr :package_name
-
- state_attrs :version, :options
+ resource_name :package
default_action :install
- allowed_actions :install, :upgrade, :remove, :purge, :reconfig
+ allowed_actions :install, :upgrade, :remove, :purge, :reconfig, :lock, :unlock
- def initialize(name, run_context=nil)
+ def initialize(name, *args)
+ # We capture name here, before it gets coerced to name
+ package_name name
super
- @candidate_version = nil
- @options = nil
- @package_name = name
- @response_file = nil
- @response_file_variables = Hash.new
- @source = nil
- @version = nil
- @timeout = nil
- end
-
- def package_name(arg=nil)
- set_or_return(
- :package_name,
- arg,
- :kind_of => [ String, Array ]
- )
end
- def version(arg=nil)
- set_or_return(
- :version,
- arg,
- :kind_of => [ String, Array ]
- )
- end
+ property :package_name, [ String, Array ], identity: true
- def response_file(arg=nil)
- set_or_return(
- :response_file,
- arg,
- :kind_of => [ String ]
- )
- end
-
- def response_file_variables(arg=nil)
- set_or_return(
- :response_file_variables,
- arg,
- :kind_of => [ Hash ]
- )
- end
-
- def source(arg=nil)
- set_or_return(
- :source,
- arg,
- :kind_of => [ String ]
- )
- end
-
- def options(arg=nil)
- set_or_return(
- :options,
- arg,
- :kind_of => [ String ]
- )
- end
-
- def timeout(arg=nil)
- set_or_return(
- :timeout,
- arg,
- :kind_of => [String, Integer]
- )
- end
+ property :version, [ String, Array ]
+ property :options, [ String, Array ]
+ property :response_file, String, desired_state: false
+ property :response_file_variables, Hash, default: lazy { {} }, desired_state: false
+ property :source, String, desired_state: false
+ property :timeout, [ String, Integer ], desired_state: false
end
end
diff --git a/lib/chef/resource/pacman_package.rb b/lib/chef/resource/pacman_package.rb
index 54b8efc4c2..66b39d164d 100644
--- a/lib/chef/resource/pacman_package.rb
+++ b/lib/chef/resource/pacman_package.rb
@@ -1,6 +1,6 @@
#
# Author:: Jan Zimmek (<jan.zimmek@web.de>)
-# Copyright:: Copyright (c) 2010 Jan Zimmek
+# Copyright:: Copyright 2010-2016, Jan Zimmek
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,12 @@
# limitations under the License.
#
-require 'chef/resource/package'
+require "chef/resource/package"
class Chef
class Resource
class PacmanPackage < Chef::Resource::Package
+ resource_name :pacman_package
provides :pacman_package, os: "linux"
end
end
diff --git a/lib/chef/resource/paludis_package.rb b/lib/chef/resource/paludis_package.rb
index 56c47bc141..31c0f31b8c 100644
--- a/lib/chef/resource/paludis_package.rb
+++ b/lib/chef/resource/paludis_package.rb
@@ -1,6 +1,6 @@
#
# Author:: Vasiliy Tolstov (<v.tolstov@selfip.ru>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,20 +16,18 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package/paludis'
+require "chef/resource/package"
+require "chef/provider/package/paludis"
class Chef
class Resource
class PaludisPackage < Chef::Resource::Package
+ resource_name :paludis_package
provides :paludis_package, os: "linux"
allowed_actions :install, :remove, :upgrade
- def initialize(name, run_context=nil)
- super(name, run_context)
- @timeout = 3600
- end
+ property :timeout, default: 3600
end
end
end
diff --git a/lib/chef/resource/perl.rb b/lib/chef/resource/perl.rb
index 773eba6571..60af0e92da 100644
--- a/lib/chef/resource/perl.rb
+++ b/lib/chef/resource/perl.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'chef/resource/script'
-require 'chef/provider/script'
+require "chef/resource/script"
+require "chef/provider/script"
class Chef
class Resource
class Perl < Chef::Resource::Script
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@interpreter = "perl"
end
diff --git a/lib/chef/resource/portage_package.rb b/lib/chef/resource/portage_package.rb
index 1af48702fa..ad66c7b42b 100644
--- a/lib/chef/resource/portage_package.rb
+++ b/lib/chef/resource/portage_package.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,13 @@
# limitations under the License.
#
-require 'chef/resource/package'
+require "chef/resource/package"
class Chef
class Resource
class PortagePackage < Chef::Resource::Package
- def initialize(name, run_context=nil)
+ resource_name :portage_package
+ def initialize(name, run_context = nil)
super
@provider = Chef::Provider::Package::Portage
end
diff --git a/lib/chef/resource/powershell_package.rb b/lib/chef/resource/powershell_package.rb
new file mode 100644
index 0000000000..4d658d3cc5
--- /dev/null
+++ b/lib/chef/resource/powershell_package.rb
@@ -0,0 +1,41 @@
+# Author:: Dheeraj Dubey(dheeraj.dubey@msystechnologies.com)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource/package"
+require "chef/mixin/uris"
+
+class Chef
+ class Resource
+ class PowershellPackage < Chef::Resource::Package
+ include Chef::Mixin::Uris
+
+ provides :powershell_package, os: "windows"
+
+ allowed_actions :install, :remove
+
+ def initialize(name, run_context = nil)
+ super
+ @resource_name = :powershell_package
+ end
+
+ property :package_name, [String, Array], coerce: proc { |x| [x].flatten }
+
+ property :version, [String, Array], coerce: proc { |x| [x].flatten }
+
+ end
+ end
+end
diff --git a/lib/chef/resource/powershell_script.rb b/lib/chef/resource/powershell_script.rb
index 7d432883e4..a530a9116c 100644
--- a/lib/chef/resource/powershell_script.rb
+++ b/lib/chef/resource/powershell_script.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,19 +15,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/resource/windows_script'
+require "chef/resource/windows_script"
class Chef
class Resource
class PowershellScript < Chef::Resource::WindowsScript
provides :powershell_script, os: "windows"
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super(name, run_context, nil, "powershell.exe")
@convert_boolean_return = false
end
- def convert_boolean_return(arg=nil)
+ def convert_boolean_return(arg = nil)
set_or_return(
:convert_boolean_return,
arg,
@@ -43,7 +43,7 @@ class Chef
# guard context and recipe resource context will have the
# same behavior.
def self.get_default_attributes(opts)
- {:convert_boolean_return => true}
+ { :convert_boolean_return => true }
end
end
end
diff --git a/lib/chef/resource/python.rb b/lib/chef/resource/python.rb
index 432ee46b85..bcad3d090b 100644
--- a/lib/chef/resource/python.rb
+++ b/lib/chef/resource/python.rb
@@ -1,5 +1,5 @@
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,13 +15,13 @@
# limitations under the License.
#
-require 'chef/resource/script'
-require 'chef/provider/script'
+require "chef/resource/script"
+require "chef/provider/script"
class Chef
class Resource
class Python < Chef::Resource::Script
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@interpreter = "python"
end
diff --git a/lib/chef/resource/reboot.rb b/lib/chef/resource/reboot.rb
index 401f2f338f..519defa602 100644
--- a/lib/chef/resource/reboot.rb
+++ b/lib/chef/resource/reboot.rb
@@ -1,6 +1,6 @@
#
-# Author:: Chris Doherty <cdoherty@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef, Inc.
+# Author:: Chris Doherty <cdoherty@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/resource'
+require "chef/resource"
# In using this resource via notifications, it's important to *only* use
# immediate notifications. Delayed notifications produce unintuitive and
@@ -26,7 +26,7 @@ class Chef
class Reboot < Chef::Resource
allowed_actions :request_reboot, :reboot_now, :cancel
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@provider = Chef::Provider::Reboot
@@ -36,12 +36,12 @@ class Chef
# no default action.
end
- def reason(arg=nil)
+ def reason(arg = nil)
set_or_return(:reason, arg, :kind_of => String)
end
- def delay_mins(arg=nil)
- set_or_return(:delay_mins, arg, :kind_of => Fixnum)
+ def delay_mins(arg = nil)
+ set_or_return(:delay_mins, arg, :kind_of => Integer)
end
end
end
diff --git a/lib/chef/resource/registry_key.rb b/lib/chef/resource/registry_key.rb
index f1bf7954ce..549897bb1d 100644
--- a/lib/chef/resource/registry_key.rb
+++ b/lib/chef/resource/registry_key.rb
@@ -1,7 +1,7 @@
-# Author:: Prajakta Purohit (<prajakta@opscode.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
+# Author:: Prajakta Purohit (<prajakta@chef.io>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
#
-# Copyright:: 2011, Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,9 +15,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/provider/registry_key'
-require 'chef/resource'
-require 'chef/digester'
+require "chef/provider/registry_key"
+require "chef/resource"
+require "chef/digester"
class Chef
class Resource
@@ -59,7 +59,7 @@ class Chef
# See lib/chef/resource_reporter.rb for more information.
attr_reader :unscrubbed_values
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@architecture = :machine
@recursive = false
@@ -67,7 +67,7 @@ class Chef
@values, @unscrubbed_values = [], []
end
- def key(arg=nil)
+ def key(arg = nil)
set_or_return(
:key,
arg,
@@ -75,7 +75,7 @@ class Chef
)
end
- def values(arg=nil)
+ def values(arg = nil)
if not arg.nil?
if arg.is_a?(Hash)
@values = [ arg ]
@@ -87,21 +87,21 @@ class Chef
@values.each do |v|
raise ArgumentError, "Missing name key in RegistryKey values hash" unless v.has_key?(:name)
- raise ArgumentError, "Missing type key in RegistryKey values hash" unless v.has_key?(:type)
- raise ArgumentError, "Missing data key in RegistryKey values hash" unless v.has_key?(:data)
v.each_key do |key|
- raise ArgumentError, "Bad key #{key} in RegistryKey values hash" unless [:name,:type,:data].include?(key)
+ raise ArgumentError, "Bad key #{key} in RegistryKey values hash" unless [:name, :type, :data].include?(key)
end
raise ArgumentError, "Type of name => #{v[:name]} should be string" unless v[:name].is_a?(String)
- raise ArgumentError, "Type of type => #{v[:type]} should be symbol" unless v[:type].is_a?(Symbol)
+ if v[:type]
+ raise ArgumentError, "Type of type => #{v[:type]} should be symbol" unless v[:type].is_a?(Symbol)
+ end
end
@unscrubbed_values = @values
- elsif self.instance_variable_defined?(:@values)
+ elsif instance_variable_defined?(:@values)
scrub_values(@values)
end
end
- def recursive(arg=nil)
+ def recursive(arg = nil)
set_or_return(
:recursive,
arg,
@@ -109,7 +109,7 @@ class Chef
)
end
- def architecture(arg=nil)
+ def architecture(arg = nil)
set_or_return(
:architecture,
arg,
diff --git a/lib/chef/resource/remote_directory.rb b/lib/chef/resource/remote_directory.rb
index b731f7b201..6e2928f3eb 100644
--- a/lib/chef/resource/remote_directory.rb
+++ b/lib/chef/resource/remote_directory.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
# limitations under the License.
#
-require 'chef/resource/directory'
-require 'chef/provider/remote_directory'
-require 'chef/mixin/securable'
+require "chef/resource/directory"
+require "chef/provider/remote_directory"
+require "chef/mixin/securable"
class Chef
class Resource
@@ -33,7 +33,7 @@ class Chef
default_action :create
allowed_actions :create, :create_if_missing, :delete
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@path = name
@source = ::File.basename(name)
@@ -53,8 +53,7 @@ class Chef
rights_attribute(:files_rights)
end
-
- def source(args=nil)
+ def source(args = nil)
set_or_return(
:source,
args,
@@ -62,7 +61,7 @@ class Chef
)
end
- def files_backup(arg=nil)
+ def files_backup(arg = nil)
set_or_return(
:files_backup,
arg,
@@ -70,7 +69,7 @@ class Chef
)
end
- def purge(arg=nil)
+ def purge(arg = nil)
set_or_return(
:purge,
arg,
@@ -78,7 +77,7 @@ class Chef
)
end
- def files_group(arg=nil)
+ def files_group(arg = nil)
set_or_return(
:files_group,
arg,
@@ -86,7 +85,7 @@ class Chef
)
end
- def files_mode(arg=nil)
+ def files_mode(arg = nil)
set_or_return(
:files_mode,
arg,
@@ -94,7 +93,7 @@ class Chef
)
end
- def files_owner(arg=nil)
+ def files_owner(arg = nil)
set_or_return(
:files_owner,
arg,
@@ -102,7 +101,7 @@ class Chef
)
end
- def overwrite(arg=nil)
+ def overwrite(arg = nil)
set_or_return(
:overwrite,
arg,
@@ -110,7 +109,7 @@ class Chef
)
end
- def cookbook(args=nil)
+ def cookbook(args = nil)
set_or_return(
:cookbook,
args,
diff --git a/lib/chef/resource/remote_file.rb b/lib/chef/resource/remote_file.rb
index b7a553cbe8..4a1d1c6cff 100644
--- a/lib/chef/resource/remote_file.rb
+++ b/lib/chef/resource/remote_file.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,18 @@
# limitations under the License.
#
-require 'uri'
-require 'chef/resource/file'
-require 'chef/provider/remote_file'
-require 'chef/mixin/securable'
-require 'chef/mixin/uris'
+require "uri"
+require "chef/resource/file"
+require "chef/provider/remote_file"
+require "chef/mixin/securable"
+require "chef/mixin/uris"
class Chef
class Resource
class RemoteFile < Chef::Resource::File
include Chef::Mixin::Securable
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@source = []
@use_etag = true
@@ -51,8 +51,8 @@ class Chef
ret = set_or_return(:source,
arg,
{ :callbacks => {
- :validate_source => method(:validate_source)
- }})
+ :validate_source => method(:validate_source),
+ } })
if ret.is_a? String
Array(ret)
else
@@ -65,14 +65,14 @@ class Chef
nil
elsif args[0].is_a?(Chef::DelayedEvaluator) && args.count == 1
args[0]
- elsif args.any? {|a| a.is_a?(Chef::DelayedEvaluator)} && args.count > 1
+ elsif args.any? { |a| a.is_a?(Chef::DelayedEvaluator) } && args.count > 1
raise Exceptions::InvalidRemoteFileURI, "Only 1 source argument allowed when using a lazy evaluator"
else
Array(args).flatten
end
end
- def checksum(args=nil)
+ def checksum(args = nil)
set_or_return(
:checksum,
args,
@@ -88,7 +88,7 @@ class Chef
use_last_modified(true_or_false)
end
- def use_etag(args=nil)
+ def use_etag(args = nil)
set_or_return(
:use_etag,
args,
@@ -98,7 +98,7 @@ class Chef
alias :use_etags :use_etag
- def use_last_modified(args=nil)
+ def use_last_modified(args = nil)
set_or_return(
:use_last_modified,
args,
@@ -106,7 +106,7 @@ class Chef
)
end
- def ftp_active_mode(args=nil)
+ def ftp_active_mode(args = nil)
set_or_return(
:ftp_active_mode,
args,
@@ -114,7 +114,7 @@ class Chef
)
end
- def headers(args=nil)
+ def headers(args = nil)
set_or_return(
:headers,
args,
@@ -122,6 +122,15 @@ class Chef
)
end
+ def show_progress(args = nil)
+ set_or_return(
+ :show_progress,
+ args,
+ :default => false,
+ :kind_of => [ TrueClass, FalseClass ]
+ )
+ end
+
private
include Chef::Mixin::Uris
@@ -139,7 +148,7 @@ class Chef
end
def absolute_uri?(source)
- Chef::Provider::RemoteFile::Fetcher.network_share?(source) or (source.kind_of?(String) and as_uri(source).absolute?)
+ Chef::Provider::RemoteFile::Fetcher.network_share?(source) || (source.kind_of?(String) && as_uri(source).absolute?)
rescue URI::InvalidURIError
false
end
diff --git a/lib/chef/resource/resource_notification.rb b/lib/chef/resource/resource_notification.rb
index 4fd61ad1f8..ee90064a17 100644
--- a/lib/chef/resource/resource_notification.rb
+++ b/lib/chef/resource/resource_notification.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/resource'
+require "chef/resource"
class Chef
class Resource
diff --git a/lib/chef/resource/route.rb b/lib/chef/resource/route.rb
index 3ba8f6215b..0117a8bfc0 100644
--- a/lib/chef/resource/route.rb
+++ b/lib/chef/resource/route.rb
@@ -1,7 +1,7 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2009-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'chef/resource'
+require "chef/resource"
class Chef
class Resource
@@ -29,7 +29,7 @@ class Chef
default_action :add
allowed_actions :add, :delete
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@target = name
@netmask = nil
@@ -44,7 +44,7 @@ class Chef
@domain = nil
end
- def networking(arg=nil)
+ def networking(arg = nil)
set_or_return(
:networking,
arg,
@@ -52,7 +52,7 @@ class Chef
)
end
- def networking_ipv6(arg=nil)
+ def networking_ipv6(arg = nil)
set_or_return(
:networking_ipv6,
arg,
@@ -60,7 +60,7 @@ class Chef
)
end
- def hostname(arg=nil)
+ def hostname(arg = nil)
set_or_return(
:hostname,
arg,
@@ -68,7 +68,7 @@ class Chef
)
end
- def domainname(arg=nil)
+ def domainname(arg = nil)
set_or_return(
:domainname,
arg,
@@ -76,7 +76,7 @@ class Chef
)
end
- def domain(arg=nil)
+ def domain(arg = nil)
set_or_return(
:domain,
arg,
@@ -84,7 +84,7 @@ class Chef
)
end
- def target(arg=nil)
+ def target(arg = nil)
set_or_return(
:target,
arg,
@@ -92,7 +92,7 @@ class Chef
)
end
- def netmask(arg=nil)
+ def netmask(arg = nil)
set_or_return(
:netmask,
arg,
@@ -100,7 +100,7 @@ class Chef
)
end
- def gateway(arg=nil)
+ def gateway(arg = nil)
set_or_return(
:gateway,
arg,
@@ -108,7 +108,7 @@ class Chef
)
end
- def metric(arg=nil)
+ def metric(arg = nil)
set_or_return(
:metric,
arg,
@@ -116,7 +116,7 @@ class Chef
)
end
- def device(arg=nil)
+ def device(arg = nil)
set_or_return(
:device,
arg,
@@ -124,7 +124,7 @@ class Chef
)
end
- def route_type(arg=nil)
+ def route_type(arg = nil)
real_arg = arg.kind_of?(String) ? arg.to_sym : arg
set_or_return(
:route_type,
diff --git a/lib/chef/resource/rpm_package.rb b/lib/chef/resource/rpm_package.rb
index b8b5144a42..c93dfecaf5 100644
--- a/lib/chef/resource/rpm_package.rb
+++ b/lib/chef/resource/rpm_package.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2010 Thomas Bishop
+# Copyright:: Copyright 2010-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,26 +16,16 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package/rpm'
+require "chef/resource/package"
+require "chef/provider/package/rpm"
class Chef
class Resource
class RpmPackage < Chef::Resource::Package
- provides :rpm_package, os: [ "linux", "aix" ]
+ resource_name :rpm_package
+ provides :rpm_package, os: %w{linux aix}
- def initialize(name, run_context=nil)
- super
- @allow_downgrade = false
- end
-
- def allow_downgrade(arg=nil)
- set_or_return(
- :allow_downgrade,
- arg,
- :kind_of => [ TrueClass, FalseClass ]
- )
- end
+ property :allow_downgrade, [ true, false ], default: false, desired_state: false
end
end
diff --git a/lib/chef/resource/ruby.rb b/lib/chef/resource/ruby.rb
index 3c3909043d..91805a1db6 100644
--- a/lib/chef/resource/ruby.rb
+++ b/lib/chef/resource/ruby.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'chef/resource/script'
-require 'chef/provider/script'
+require "chef/resource/script"
+require "chef/provider/script"
class Chef
class Resource
class Ruby < Chef::Resource::Script
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@interpreter = "ruby"
end
diff --git a/lib/chef/resource/ruby_block.rb b/lib/chef/resource/ruby_block.rb
index ae8e4cb7cd..87a4cfb7c5 100644
--- a/lib/chef/resource/ruby_block.rb
+++ b/lib/chef/resource/ruby_block.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/provider/ruby_block'
+require "chef/resource"
+require "chef/provider/ruby_block"
class Chef
class Resource
@@ -28,20 +28,20 @@ class Chef
identity_attr :block_name
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@block_name = name
end
def block(&block)
- if block_given? and block
+ if block_given? && block
@block = block
else
@block
end
end
- def block_name(arg=nil)
+ def block_name(arg = nil)
set_or_return(
:block_name,
arg,
diff --git a/lib/chef/resource/scm.rb b/lib/chef/resource/scm.rb
index 85028c266b..533723c2c4 100644
--- a/lib/chef/resource/scm.rb
+++ b/lib/chef/resource/scm.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,7 @@
# limitations under the License.
#
-
-require 'chef/resource'
+require "chef/resource"
class Chef
class Resource
@@ -29,7 +28,7 @@ class Chef
default_action :sync
allowed_actions :checkout, :export, :sync, :diff, :log
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@destination = name
@enable_submodules = false
@@ -42,7 +41,7 @@ class Chef
@environment = nil
end
- def destination(arg=nil)
+ def destination(arg = nil)
set_or_return(
:destination,
arg,
@@ -50,7 +49,7 @@ class Chef
)
end
- def repository(arg=nil)
+ def repository(arg = nil)
set_or_return(
:repository,
arg,
@@ -58,7 +57,7 @@ class Chef
)
end
- def revision(arg=nil)
+ def revision(arg = nil)
set_or_return(
:revision,
arg,
@@ -66,7 +65,7 @@ class Chef
)
end
- def user(arg=nil)
+ def user(arg = nil)
set_or_return(
:user,
arg,
@@ -74,7 +73,7 @@ class Chef
)
end
- def group(arg=nil)
+ def group(arg = nil)
set_or_return(
:group,
arg,
@@ -82,7 +81,7 @@ class Chef
)
end
- def svn_username(arg=nil)
+ def svn_username(arg = nil)
set_or_return(
:svn_username,
arg,
@@ -90,15 +89,9 @@ class Chef
)
end
- def svn_password(arg=nil)
- set_or_return(
- :svn_password,
- arg,
- :kind_of => String
- )
- end
+ property :svn_password, String, sensitive: true, desired_state: false
- def svn_arguments(arg=nil)
+ def svn_arguments(arg = nil)
@svn_arguments, arg = nil, nil if arg == false
set_or_return(
:svn_arguments,
@@ -107,7 +100,7 @@ class Chef
)
end
- def svn_info_args(arg=nil)
+ def svn_info_args(arg = nil)
@svn_info_args, arg = nil, nil if arg == false
set_or_return(
:svn_info_args,
@@ -116,7 +109,7 @@ class Chef
end
# Capistrano and git-deploy use ``shallow clone''
- def depth(arg=nil)
+ def depth(arg = nil)
set_or_return(
:depth,
arg,
@@ -124,7 +117,7 @@ class Chef
)
end
- def enable_submodules(arg=nil)
+ def enable_submodules(arg = nil)
set_or_return(
:enable_submodules,
arg,
@@ -132,7 +125,7 @@ class Chef
)
end
- def enable_checkout(arg=nil)
+ def enable_checkout(arg = nil)
set_or_return(
:enable_checkout,
arg,
@@ -140,7 +133,7 @@ class Chef
)
end
- def remote(arg=nil)
+ def remote(arg = nil)
set_or_return(
:remote,
arg,
@@ -148,7 +141,7 @@ class Chef
)
end
- def ssh_wrapper(arg=nil)
+ def ssh_wrapper(arg = nil)
set_or_return(
:ssh_wrapper,
arg,
@@ -156,7 +149,7 @@ class Chef
)
end
- def timeout(arg=nil)
+ def timeout(arg = nil)
set_or_return(
:timeout,
arg,
@@ -164,7 +157,7 @@ class Chef
)
end
- def checkout_branch(arg=nil)
+ def checkout_branch(arg = nil)
set_or_return(
:checkout_branch,
arg,
@@ -172,7 +165,7 @@ class Chef
)
end
- def environment(arg=nil)
+ def environment(arg = nil)
set_or_return(
:environment,
arg,
diff --git a/lib/chef/resource/script.rb b/lib/chef/resource/script.rb
index 5081adf918..5173a76542 100644
--- a/lib/chef/resource/script.rb
+++ b/lib/chef/resource/script.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/resource/execute'
-require 'chef/provider/script'
+require "chef/resource/execute"
+require "chef/provider/script"
class Chef
class Resource
@@ -26,7 +26,7 @@ class Chef
# Chef-13: go back to using :name as the identity attr
identity_attr :command
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
# Chef-13: the command variable should be initialized to nil
@command = name
@@ -36,7 +36,7 @@ class Chef
@default_guard_interpreter = :default
end
- def command(arg=nil)
+ def command(arg = nil)
unless arg.nil?
# Chef-13: change this to raise if the user is trying to set a value here
Chef::Log.warn "Specifying command attribute on a script resource is a coding error, use the 'code' attribute, or the execute resource"
@@ -45,7 +45,7 @@ class Chef
super
end
- def code(arg=nil)
+ def code(arg = nil)
set_or_return(
:code,
arg,
@@ -53,7 +53,7 @@ class Chef
)
end
- def interpreter(arg=nil)
+ def interpreter(arg = nil)
set_or_return(
:interpreter,
arg,
@@ -61,7 +61,7 @@ class Chef
)
end
- def flags(arg=nil)
+ def flags(arg = nil)
set_or_return(
:flags,
arg,
diff --git a/lib/chef/resource/service.rb b/lib/chef/resource/service.rb
index 6d1b81f9cb..1ca4b84af0 100644
--- a/lib/chef/resource/service.rb
+++ b/lib/chef/resource/service.rb
@@ -1,7 +1,7 @@
#
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,23 +17,25 @@
# limitations under the License.
#
-require 'chef/resource'
+require "chef/resource"
class Chef
class Resource
class Service < Chef::Resource
identity_attr :service_name
- state_attrs :enabled, :running
+ state_attrs :enabled, :running, :masked
default_action :nothing
- allowed_actions :enable, :disable, :start, :stop, :restart, :reload
+ allowed_actions :enable, :disable, :start, :stop, :restart, :reload,
+ :mask, :unmask
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@service_name = name
@enabled = nil
@running = nil
+ @masked = nil
@parameters = nil
@pattern = service_name
@start_command = nil
@@ -45,10 +47,11 @@ class Chef
@priority = nil
@timeout = nil
@run_levels = nil
+ @user = nil
@supports = { :restart => nil, :reload => nil, :status => nil }
end
- def service_name(arg=nil)
+ def service_name(arg = nil)
set_or_return(
:service_name,
arg,
@@ -57,7 +60,7 @@ class Chef
end
# regex for match against ps -ef when !supports[:has_status] && status == nil
- def pattern(arg=nil)
+ def pattern(arg = nil)
set_or_return(
:pattern,
arg,
@@ -66,7 +69,7 @@ class Chef
end
# command to call to start service
- def start_command(arg=nil)
+ def start_command(arg = nil)
set_or_return(
:start_command,
arg,
@@ -75,7 +78,7 @@ class Chef
end
# command to call to stop service
- def stop_command(arg=nil)
+ def stop_command(arg = nil)
set_or_return(
:stop_command,
arg,
@@ -84,7 +87,7 @@ class Chef
end
# command to call to get status of service
- def status_command(arg=nil)
+ def status_command(arg = nil)
set_or_return(
:status_command,
arg,
@@ -93,7 +96,7 @@ class Chef
end
# command to call to restart service
- def restart_command(arg=nil)
+ def restart_command(arg = nil)
set_or_return(
:restart_command,
arg,
@@ -101,7 +104,7 @@ class Chef
)
end
- def reload_command(arg=nil)
+ def reload_command(arg = nil)
set_or_return(
:reload_command,
arg,
@@ -114,7 +117,7 @@ class Chef
# non-standard configurations setting this value will save having to
# specify overrides for the start_command, stop_command and
# restart_command attributes.
- def init_command(arg=nil)
+ def init_command(arg = nil)
set_or_return(
:init_command,
arg,
@@ -123,7 +126,7 @@ class Chef
end
# if the service is enabled or not
- def enabled(arg=nil)
+ def enabled(arg = nil)
set_or_return(
:enabled,
arg,
@@ -132,7 +135,7 @@ class Chef
end
# if the service is running or not
- def running(arg=nil)
+ def running(arg = nil)
set_or_return(
:running,
arg,
@@ -140,6 +143,15 @@ class Chef
)
end
+ # if the service is masked or not
+ def masked(arg = nil)
+ set_or_return(
+ :masked,
+ arg,
+ :kind_of => [ TrueClass, FalseClass ]
+ )
+ end
+
# Priority arguments can have two forms:
#
# - a simple number, in which the default start runlevels get
@@ -150,7 +162,7 @@ class Chef
# runlevel 2, stopped in 3 with priority 55 and no symlinks or
# similar for other runlevels
#
- def priority(arg=nil)
+ def priority(arg = nil)
set_or_return(
:priority,
arg,
@@ -159,7 +171,7 @@ class Chef
end
# timeout only applies to the windows service manager
- def timeout(arg=nil)
+ def timeout(arg = nil)
set_or_return(
:timeout,
arg,
@@ -167,7 +179,7 @@ class Chef
)
end
- def parameters(arg=nil)
+ def parameters(arg = nil)
set_or_return(
:parameters,
arg,
@@ -175,14 +187,22 @@ class Chef
)
end
- def run_levels(arg=nil)
+ def run_levels(arg = nil)
set_or_return(
:run_levels,
arg,
:kind_of => [ Array ] )
end
- def supports(args={})
+ def user(arg = nil)
+ set_or_return(
+ :user,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
+ def supports(args = {})
if args.is_a? Array
args.each { |arg| @supports[arg] = true }
elsif args.any?
diff --git a/lib/chef/resource/smartos_package.rb b/lib/chef/resource/smartos_package.rb
index b8bd940c24..87173ccfa9 100644
--- a/lib/chef/resource/smartos_package.rb
+++ b/lib/chef/resource/smartos_package.rb
@@ -1,6 +1,6 @@
#
# Author:: Toomas Pelberg (<toomasp@gmx.net>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,13 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package/smartos'
+require "chef/resource/package"
+require "chef/provider/package/smartos"
class Chef
class Resource
class SmartosPackage < Chef::Resource::Package
+ resource_name :smartos_package
provides :package, os: "solaris2", platform_family: "smartos"
end
end
diff --git a/lib/chef/resource/solaris_package.rb b/lib/chef/resource/solaris_package.rb
index a98fb8b4fa..d0f8c144af 100644
--- a/lib/chef/resource/solaris_package.rb
+++ b/lib/chef/resource/solaris_package.rb
@@ -1,7 +1,7 @@
#
# Author:: Toomas Pelberg (<toomasp@gmx.net>)
# Author:: Prabhu Das (<prabhu.das@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,12 +17,13 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package/solaris'
+require "chef/resource/package"
+require "chef/provider/package/solaris"
class Chef
class Resource
class SolarisPackage < Chef::Resource::Package
+ resource_name :solaris_package
provides :package, os: "solaris2", platform_family: "nexentacore"
provides :package, os: "solaris2", platform_family: "solaris2", platform_version: "<= 5.10"
end
diff --git a/lib/chef/resource/subversion.rb b/lib/chef/resource/subversion.rb
index a6f4cb4897..9966614eeb 100644
--- a/lib/chef/resource/subversion.rb
+++ b/lib/chef/resource/subversion.rb
@@ -1,7 +1,7 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,10 +24,10 @@ class Chef
class Subversion < Chef::Resource::Scm
allowed_actions :force_export
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
- @svn_arguments = '--no-auth-cache'
- @svn_info_args = '--no-auth-cache'
+ @svn_arguments = "--no-auth-cache"
+ @svn_info_args = "--no-auth-cache"
@svn_binary = nil
end
@@ -36,7 +36,7 @@ class Chef
"#{self} (#{defined_at}) had an error: #{e.class.name}: #{svn_password ? e.message.gsub(svn_password, "[hidden_password]") : e.message}"
end
- def svn_binary(arg=nil)
+ def svn_binary(arg = nil)
set_or_return(:svn_binary, arg, :kind_of => [String])
end
end
diff --git a/lib/chef/resource/systemd_unit.rb b/lib/chef/resource/systemd_unit.rb
new file mode 100644
index 0000000000..688f2e9dcd
--- /dev/null
+++ b/lib/chef/resource/systemd_unit.rb
@@ -0,0 +1,63 @@
+#
+# Author:: Nathan Williams (<nath.e.will@gmail.com>)
+# Copyright:: Copyright 2016, Nathan Williams
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource"
+require "iniparse"
+
+class Chef
+ class Resource
+ class SystemdUnit < Chef::Resource
+ resource_name :systemd_unit
+
+ default_action :nothing
+ allowed_actions :create, :delete,
+ :enable, :disable,
+ :mask, :unmask,
+ :start, :stop,
+ :restart, :reload,
+ :try_restart, :reload_or_restart,
+ :reload_or_try_restart
+
+ property :enabled, [TrueClass, FalseClass]
+ property :active, [TrueClass, FalseClass]
+ property :masked, [TrueClass, FalseClass]
+ property :static, [TrueClass, FalseClass]
+ property :user, String, desired_state: false
+ property :content, [String, Hash]
+ property :triggers_reload, [TrueClass, FalseClass],
+ default: true, desired_state: false
+
+ def to_ini
+ case content
+ when Hash
+ IniParse.gen do |doc|
+ content.each_pair do |sect, opts|
+ doc.section(sect) do |section|
+ opts.each_pair do |opt, val|
+ section.option(opt, val)
+ end
+ end
+ end
+ end.to_s
+ else
+ content.to_s
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/template.rb b/lib/chef/resource/template.rb
index 5a7f7efd6f..896aa71340 100644
--- a/lib/chef/resource/template.rb
+++ b/lib/chef/resource/template.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,9 @@
# limitations under the License.
#
-require 'chef/resource/file'
-require 'chef/provider/template'
-require 'chef/mixin/securable'
+require "chef/resource/file"
+require "chef/provider/template"
+require "chef/mixin/securable"
class Chef
class Resource
@@ -30,7 +30,7 @@ class Chef
attr_reader :inline_helper_blocks
attr_reader :inline_helper_modules
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@source = "#{::File.basename(name)}.erb"
@cookbook = nil
@@ -41,7 +41,7 @@ class Chef
@helper_modules = []
end
- def source(file=nil)
+ def source(file = nil)
set_or_return(
:source,
file,
@@ -49,7 +49,7 @@ class Chef
)
end
- def variables(args=nil)
+ def variables(args = nil)
set_or_return(
:variables,
args,
@@ -57,7 +57,7 @@ class Chef
)
end
- def cookbook(args=nil)
+ def cookbook(args = nil)
set_or_return(
:cookbook,
args,
@@ -65,7 +65,7 @@ class Chef
)
end
- def local(args=nil)
+ def local(args = nil)
set_or_return(
:local,
args,
@@ -160,8 +160,8 @@ class Chef
# And in the template resource:
# helpers(MyTemplateHelper)
# The template code in the above example will work unmodified.
- def helpers(module_name=nil,&block)
- if block_given? and !module_name.nil?
+ def helpers(module_name = nil, &block)
+ if block_given? && !module_name.nil?
raise Exceptions::ValidationFailed,
"Passing both a module and block to #helpers is not supported. Call #helpers multiple times instead"
elsif block_given?
diff --git a/lib/chef/resource/timestamped_deploy.rb b/lib/chef/resource/timestamped_deploy.rb
index 344f8b0a5e..1d6b07a719 100644
--- a/lib/chef/resource/timestamped_deploy.rb
+++ b/lib/chef/resource/timestamped_deploy.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/resource/user.rb b/lib/chef/resource/user.rb
index b85b648c92..fc7720bc25 100644
--- a/lib/chef/resource/user.rb
+++ b/lib/chef/resource/user.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,12 @@
# limitations under the License.
#
-require 'chef/resource'
+require "chef/resource"
class Chef
class Resource
class User < Chef::Resource
+ resource_name :user_resource_abstract_base_class # this prevents magickal class name DSL wiring
identity_attr :username
state_attrs :uid, :gid, :home
@@ -28,7 +29,7 @@ class Chef
default_action :create
allowed_actions :create, :remove, :modify, :manage, :lock, :unlock
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@username = name
@comment = nil
@@ -42,14 +43,14 @@ class Chef
@force = false
@non_unique = false
@supports = {
- :manage_home => false,
- :non_unique => false
+ manage_home: false,
+ non_unique: false,
}
@iterations = 27855
@salt = nil
end
- def username(arg=nil)
+ def username(arg = nil)
set_or_return(
:username,
arg,
@@ -57,7 +58,7 @@ class Chef
)
end
- def comment(arg=nil)
+ def comment(arg = nil)
set_or_return(
:comment,
arg,
@@ -65,7 +66,7 @@ class Chef
)
end
- def uid(arg=nil)
+ def uid(arg = nil)
set_or_return(
:uid,
arg,
@@ -73,7 +74,7 @@ class Chef
)
end
- def gid(arg=nil)
+ def gid(arg = nil)
set_or_return(
:gid,
arg,
@@ -83,7 +84,7 @@ class Chef
alias_method :group, :gid
- def home(arg=nil)
+ def home(arg = nil)
set_or_return(
:home,
arg,
@@ -91,7 +92,7 @@ class Chef
)
end
- def shell(arg=nil)
+ def shell(arg = nil)
set_or_return(
:shell,
arg,
@@ -99,7 +100,7 @@ class Chef
)
end
- def password(arg=nil)
+ def password(arg = nil)
set_or_return(
:password,
arg,
@@ -107,7 +108,7 @@ class Chef
)
end
- def salt(arg=nil)
+ def salt(arg = nil)
set_or_return(
:salt,
arg,
@@ -115,7 +116,7 @@ class Chef
)
end
- def iterations(arg=nil)
+ def iterations(arg = nil)
set_or_return(
:iterations,
arg,
@@ -123,7 +124,7 @@ class Chef
)
end
- def system(arg=nil)
+ def system(arg = nil)
set_or_return(
:system,
arg,
@@ -131,7 +132,7 @@ class Chef
)
end
- def manage_home(arg=nil)
+ def manage_home(arg = nil)
set_or_return(
:manage_home,
arg,
@@ -139,7 +140,7 @@ class Chef
)
end
- def force(arg=nil)
+ def force(arg = nil)
set_or_return(
:force,
arg,
@@ -147,7 +148,7 @@ class Chef
)
end
- def non_unique(arg=nil)
+ def non_unique(arg = nil)
set_or_return(
:non_unique,
arg,
@@ -155,6 +156,19 @@ class Chef
)
end
+ def supports(args = {})
+ if args.key?(:manage_home)
+ Chef.deprecated(:supports_property, "supports { manage_home: #{args[:manage_home]} } on the user resource is deprecated and will be removed in Chef 13, set manage_home #{args[:manage_home]} instead")
+ end
+ if args.key?(:non_unique)
+ Chef.deprecated(:supports_property, "supports { non_unique: #{args[:non_unique]} } on the user resource is deprecated and will be removed in Chef 13, set non_unique #{args[:non_unique]} instead")
+ end
+ super
+ end
+
+ def supports=(args)
+ supports(args)
+ end
end
end
end
diff --git a/lib/chef/shell/shell_rest.rb b/lib/chef/resource/user/aix_user.rb
index a485a0a1a8..7c07db2e25 100644
--- a/lib/chef/shell/shell_rest.rb
+++ b/lib/chef/resource/user/aix_user.rb
@@ -1,6 +1,5 @@
-#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+#
+# Copyright:: Copyright 2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +15,17 @@
# limitations under the License.
#
-module Shell
- class ShellREST < Chef::REST
+require "chef/resource/user"
- alias :get :get_rest
- alias :put :put_rest
- alias :post :post_rest
- alias :delete :delete_rest
+class Chef
+ class Resource
+ class User
+ class AixUser < Chef::Resource::User
+ resource_name :aix_user
+ provides :aix_user
+ provides :user, os: "aix"
+ end
+ end
end
end
diff --git a/lib/chef/chef_fs/file_system/file_system_root_dir.rb b/lib/chef/resource/user/dscl_user.rb
index afbf7b1901..61517d8b44 100644
--- a/lib/chef/chef_fs/file_system/file_system_root_dir.rb
+++ b/lib/chef/resource/user/dscl_user.rb
@@ -1,6 +1,5 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +15,16 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/file_system_entry'
+require "chef/resource/user"
class Chef
- module ChefFS
- module FileSystem
- class FileSystemRootDir < FileSystemEntry
- def initialize(file_path)
- super("", nil, file_path)
- end
+ class Resource
+ class User
+ class DsclUser < Chef::Resource::User
+ resource_name :dscl_user
+
+ provides :dscl_user
+ provides :user, os: "darwin"
end
end
end
diff --git a/lib/chef/resource/user/linux_user.rb b/lib/chef/resource/user/linux_user.rb
new file mode 100644
index 0000000000..ec60ac89bf
--- /dev/null
+++ b/lib/chef/resource/user/linux_user.rb
@@ -0,0 +1,41 @@
+#
+# Copyright:: Copyright 2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource/user"
+
+class Chef
+ class Resource
+ class User
+ class LinuxUser < Chef::Resource::User
+ resource_name :linux_user
+
+ provides :linux_user
+ provides :user, os: "linux"
+
+ def initialize(name, run_context = nil)
+ super
+ @supports = {
+ manage_home: false,
+ non_unique: false,
+ }
+ @manage_home = false
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/must_delete_recursively_error.rb b/lib/chef/resource/user/pw_user.rb
index bfa8ba28ce..873be19d59 100644
--- a/lib/chef/chef_fs/file_system/must_delete_recursively_error.rb
+++ b/lib/chef/resource/user/pw_user.rb
@@ -1,6 +1,5 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +15,16 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system/file_system_error'
+require "chef/resource/user"
class Chef
- module ChefFS
- module FileSystem
- class MustDeleteRecursivelyError < FileSystemError
- def initialize(entry, cause = nil)
- super(entry, cause)
- end
+ class Resource
+ class User
+ class PwUser < Chef::Resource::User
+ resource_name :pw_user
+
+ provides :pw_user
+ provides :user, os: "freebsd"
end
end
end
diff --git a/lib/chef/resource/user/solaris_user.rb b/lib/chef/resource/user/solaris_user.rb
new file mode 100644
index 0000000000..bb897228b9
--- /dev/null
+++ b/lib/chef/resource/user/solaris_user.rb
@@ -0,0 +1,31 @@
+#
+# Copyright:: Copyright 2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource/user"
+
+class Chef
+ class Resource
+ class User
+ class SolarisUser < Chef::Resource::User
+ resource_name :solaris_user
+
+ provides :solaris_user
+ provides :user, os: %w{omnios solaris2}
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/user/windows_user.rb b/lib/chef/resource/user/windows_user.rb
new file mode 100644
index 0000000000..d1a249fb50
--- /dev/null
+++ b/lib/chef/resource/user/windows_user.rb
@@ -0,0 +1,31 @@
+#
+# Copyright:: Copyright 2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource/user"
+
+class Chef
+ class Resource
+ class User
+ class WindowsUser < Chef::Resource::User
+ resource_name :windows_user
+
+ provides :windows_user
+ provides :user, os: "windows"
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/whyrun_safe_ruby_block.rb b/lib/chef/resource/whyrun_safe_ruby_block.rb
index f289f15001..db11ba34d2 100644
--- a/lib/chef/resource/whyrun_safe_ruby_block.rb
+++ b/lib/chef/resource/whyrun_safe_ruby_block.rb
@@ -1,6 +1,6 @@
#
# Author:: Phil Dibowitz (<phild@fb.com>)
-# Copyright:: Copyright (c) 2013 Facebook
+# Copyright:: Copyright 2013-2016, Facebook
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/resource/windows_package.rb b/lib/chef/resource/windows_package.rb
index a76765cc36..0e8dd39672 100644
--- a/lib/chef/resource/windows_package.rb
+++ b/lib/chef/resource/windows_package.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,85 +16,40 @@
# limitations under the License.
#
-require 'chef/mixin/uris'
-require 'chef/resource/package'
-require 'chef/provider/package/windows'
-require 'chef/win32/error' if RUBY_PLATFORM =~ /mswin|mingw|windows/
+require "chef/mixin/uris"
+require "chef/resource/package"
+require "chef/provider/package/windows"
+require "chef/win32/error" if RUBY_PLATFORM =~ /mswin|mingw|windows/
class Chef
class Resource
class WindowsPackage < Chef::Resource::Package
include Chef::Mixin::Uris
+ resource_name :windows_package
provides :windows_package, os: "windows"
provides :package, os: "windows"
allowed_actions :install, :remove
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
- @source ||= source(@package_name)
-
- # Unique to this resource
- @installer_type = nil
- @timeout = 600
- # In the past we accepted return code 127 for an unknown reason and 42 because of a bug
- @returns = [ 0 ]
- end
-
- def installer_type(arg=nil)
- set_or_return(
- :installer_type,
- arg,
- :kind_of => [ Symbol ]
- )
- end
-
- def timeout(arg=nil)
- set_or_return(
- :timeout,
- arg,
- :kind_of => [ String, Integer ]
- )
- end
-
- def returns(arg=nil)
- set_or_return(
- :returns,
- arg,
- :kind_of => [ String, Integer, Array ]
- )
- end
-
- def source(arg=nil)
- if arg == nil && self.instance_variable_defined?(:@source) == true
- @source
- else
- raise ArgumentError, "Bad type for WindowsPackage resource, use a String" unless arg.is_a?(String)
- if uri_scheme?(arg)
- @source = arg
- else
- @source = Chef::Util::PathHelper.canonical_path(arg, false)
- end
- end
- end
-
- def checksum(arg=nil)
- set_or_return(
- :checksum,
- arg,
- :kind_of => [ String ]
- )
- end
-
- def remote_file_attributes(arg=nil)
- set_or_return(
- :remote_file_attributes,
- arg,
- :kind_of => [ Hash ]
- )
+ @source ||= source(@package_name) if @package_name.downcase.end_with?(".msi")
end
+ # Unique to this resource
+ property :installer_type, Symbol
+ property :timeout, [ String, Integer ], default: 600
+ # In the past we accepted return code 127 for an unknown reason and 42 because of a bug
+ property :returns, [ String, Integer, Array ], default: [ 0 ], desired_state: false
+ property :source, String,
+ coerce: (proc do |s|
+ unless s.nil?
+ uri_scheme?(s) ? s : Chef::Util::PathHelper.canonical_path(s, false)
+ end
+ end)
+ property :checksum, String, desired_state: false
+ property :remote_file_attributes, Hash, desired_state: false
end
end
end
diff --git a/lib/chef/resource/windows_script.rb b/lib/chef/resource/windows_script.rb
index 2bbd01d5aa..7c39d9fba0 100644
--- a/lib/chef/resource/windows_script.rb
+++ b/lib/chef/resource/windows_script.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/platform/query_helpers'
-require 'chef/resource/script'
-require 'chef/mixin/windows_architecture_helper'
+require "chef/platform/query_helpers"
+require "chef/resource/script"
+require "chef/mixin/windows_architecture_helper"
class Chef
class Resource
@@ -40,7 +40,7 @@ class Chef
public
- def architecture(arg=nil)
+ def architecture(arg = nil)
assert_architecture_compatible!(arg) if ! arg.nil?
result = set_or_return(
:architecture,
@@ -57,7 +57,7 @@ class Chef
"cannot execute script with requested architecture 'i386' on Windows Nano Server"
elsif ! node_supports_windows_architecture?(node, desired_architecture)
raise Chef::Exceptions::Win32ArchitectureIncorrect,
- "cannot execute script with requested architecture '#{desired_architecture.to_s}' on a system with architecture '#{node_windows_architecture(node)}'"
+ "cannot execute script with requested architecture '#{desired_architecture}' on a system with architecture '#{node_windows_architecture(node)}'"
end
end
end
diff --git a/lib/chef/resource/windows_service.rb b/lib/chef/resource/windows_service.rb
index a77690652e..405f7f6dbe 100644
--- a/lib/chef/resource/windows_service.rb
+++ b/lib/chef/resource/windows_service.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/resource/service'
+require "chef/resource/service"
class Chef
class Resource
@@ -34,14 +34,14 @@ class Chef
state_attrs :enabled, :running
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@startup_type = :automatic
@run_as_user = ""
@run_as_password = ""
end
- def startup_type(arg=nil)
+ def startup_type(arg = nil)
# Set-Service arguments are automatic and manual
# Win32::Service returns 'auto start' or 'demand start' respectively, which the provider currently uses
set_or_return(
@@ -51,7 +51,7 @@ class Chef
)
end
- def run_as_user(arg=nil)
+ def run_as_user(arg = nil)
set_or_return(
:run_as_user,
arg,
@@ -59,7 +59,7 @@ class Chef
)
end
- def run_as_password(arg=nil)
+ def run_as_password(arg = nil)
set_or_return(
:run_as_password,
arg,
diff --git a/lib/chef/resource/yum_package.rb b/lib/chef/resource/yum_package.rb
index 50ba13ce65..2fc5db5cc3 100644
--- a/lib/chef/resource/yum_package.rb
+++ b/lib/chef/resource/yum_package.rb
@@ -1,6 +1,6 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,56 +16,46 @@
# limitations under the License.
#
-require 'chef/resource/package'
-require 'chef/provider/package/yum'
+require "chef/resource/package"
class Chef
class Resource
class YumPackage < Chef::Resource::Package
- provides :package, os: "linux", platform_family: [ "rhel", "fedora" ]
-
- def initialize(name, run_context=nil)
- super
- @flush_cache = { :before => false, :after => false }
- @allow_downgrade = false
- @yum_binary = nil
- end
-
- # Install a specific arch
- def arch(arg=nil)
- set_or_return(
- :arch,
- arg,
- :kind_of => [ String, Array ]
- )
- end
-
- def flush_cache(args={})
- if args.is_a? Array
- args.each { |arg| @flush_cache[arg] = true }
- elsif args.any?
- @flush_cache = args
- else
- @flush_cache
- end
- end
-
- def allow_downgrade(arg=nil)
- set_or_return(
- :allow_downgrade,
- arg,
- :kind_of => [ TrueClass, FalseClass ]
- )
- end
-
- def yum_binary(arg=nil)
- set_or_return(
- :yum_binary,
- arg,
- :kind_of => [ String ]
- )
- end
-
+ resource_name :yum_package
+ provides :package, os: "linux", platform_family: %w{rhel fedora}
+
+ # XXX: the coercions here are due to the provider promiscuously updating the properties on the
+ # new_resource which causes immutable modification exceptions when passed an immutable node array.
+ #
+ # <lecture>
+ # THIS is why updating the new_resource in a provider is so terrible, and is equivalent to methods scribbling over
+ # its own arguments as unintended side-effects (and why functional languages that don't allow modifcations
+ # of variables eliminate entire classes of bugs).
+ # </lecture>
+ property :package_name, [ String, Array ], identity: true, coerce: proc { |x| x.is_a?(Array) ? x.to_a : x }
+ property :version, [ String, Array ], coerce: proc { |x| x.is_a?(Array) ? x.to_a : x }
+ property :arch, [ String, Array ], coerce: proc { |x| x.is_a?(Array) ? x.to_a : x }
+
+ property :flush_cache,
+ Hash,
+ default: { before: false, after: false },
+ coerce: proc { |v|
+ if v.is_a?(Hash)
+ v
+ elsif v.is_a?(Array)
+ v.each_with_object({}) { |arg, obj| obj[arg] = true }
+ elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
+ { before: v, after: v }
+ elsif v == :before
+ { before: true, after: false }
+ elsif v == :after
+ { after: true, before: false }
+ end
+ }
+
+ property :allow_downgrade, [ true, false ], default: false
+
+ property :yum_binary, String
end
end
end
diff --git a/lib/chef/resource/yum_repository.rb b/lib/chef/resource/yum_repository.rb
new file mode 100644
index 0000000000..f59ad56d16
--- /dev/null
+++ b/lib/chef/resource/yum_repository.rb
@@ -0,0 +1,78 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource"
+
+class Chef
+ class Resource
+ class YumRepository < Chef::Resource
+ resource_name :yum_repository
+ provides :yum_repository
+
+ # http://linux.die.net/man/5/yum.conf
+ property :baseurl, [String, Array], regex: /.*/
+ property :cost, String, regex: /^\d+$/
+ property :clean_headers, [TrueClass, FalseClass], default: false # deprecated
+ property :clean_metadata, [TrueClass, FalseClass], default: true
+ property :description, String, regex: /.*/, default: "Yum Repository"
+ property :enabled, [TrueClass, FalseClass], default: true
+ property :enablegroups, [TrueClass, FalseClass]
+ property :exclude, String, regex: /.*/
+ property :failovermethod, String, equal_to: %w{priority roundrobin}
+ property :fastestmirror_enabled, [TrueClass, FalseClass]
+ property :gpgcheck, [TrueClass, FalseClass], default: true
+ property :gpgkey, [String, Array], regex: /.*/
+ property :http_caching, String, equal_to: %w{packages all none}
+ property :include_config, String, regex: /.*/
+ property :includepkgs, String, regex: /.*/
+ property :keepalive, [TrueClass, FalseClass]
+ property :make_cache, [TrueClass, FalseClass], default: true
+ property :max_retries, [String, Integer]
+ property :metadata_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/, /never/]
+ property :mirrorexpire, String, regex: /.*/
+ property :mirrorlist, String, regex: /.*/
+ property :mirror_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/]
+ property :mirrorlist_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/]
+ property :mode, default: "0644"
+ property :priority, String, regex: /^(\d?[0-9]|[0-9][0-9])$/
+ property :proxy, String, regex: /.*/
+ property :proxy_username, String, regex: /.*/
+ property :proxy_password, String, regex: /.*/
+ property :username, String, regex: /.*/
+ property :password, String, regex: /.*/
+ property :repo_gpgcheck, [TrueClass, FalseClass]
+ property :report_instanceid, [TrueClass, FalseClass]
+ property :repositoryid, String, regex: /.*/, name_property: true
+ property :skip_if_unavailable, [TrueClass, FalseClass]
+ property :source, String, regex: /.*/
+ property :sslcacert, String, regex: /.*/
+ property :sslclientcert, String, regex: /.*/
+ property :sslclientkey, String, regex: /.*/
+ property :sslverify, [TrueClass, FalseClass]
+ property :timeout, String, regex: /^\d+$/
+ property :options, Hash
+
+ default_action :create
+ allowed_actions :create, :remove, :makecache, :add, :delete
+
+ # provide compatibility with the yum cookbook < 3.0 properties
+ alias_method :url, :baseurl
+ alias_method :keyurl, :gpgkey
+ end
+ end
+end
diff --git a/lib/chef/resource/zypper_package.rb b/lib/chef/resource/zypper_package.rb
index f09a20e2c6..f9e3eef49e 100644
--- a/lib/chef/resource/zypper_package.rb
+++ b/lib/chef/resource/zypper_package.rb
@@ -1,6 +1,6 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,12 @@
# limitations under the License.
#
-require 'chef/resource/package'
+require "chef/resource/package"
class Chef
class Resource
class ZypperPackage < Chef::Resource::Package
+ resource_name :zypper_package
provides :package, platform_family: "suse"
end
end
diff --git a/lib/chef/resource_builder.rb b/lib/chef/resource_builder.rb
index 9e9f7047a4..1aee852f5d 100644
--- a/lib/chef/resource_builder.rb
+++ b/lib/chef/resource_builder.rb
@@ -1,6 +1,6 @@
#
# Author:: Lamont Granquist (<lamont@chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,6 @@
# NOTE: this was extracted from the Recipe DSL mixin, relevant specs are in spec/unit/recipe_spec.rb
-require 'chef/exceptions'
-require 'chef/resource'
-require 'chef/log'
-
class Chef
class ResourceBuilder
attr_reader :type
@@ -35,7 +31,7 @@ class Chef
attr_reader :resource
# FIXME (ruby-2.1 syntax): most of these are mandatory
- def initialize(type:nil, name:nil, created_at: nil, params: nil, run_context: nil, cookbook_name: nil, recipe_name: nil, enclosing_provider: nil)
+ def initialize(type: nil, name: nil, created_at: nil, params: nil, run_context: nil, cookbook_name: nil, recipe_name: nil, enclosing_provider: nil)
@type = type
@name = name
@created_at = created_at
@@ -60,7 +56,7 @@ class Chef
# This behavior is very counter-intuitive and should be removed.
# See CHEF-3694, https://tickets.opscode.com/browse/CHEF-3694
# Moved to this location to resolve CHEF-5052, https://tickets.opscode.com/browse/CHEF-5052
- if prior_resource
+ if prior_resource && Chef::Config[:resource_cloning]
resource.load_from(prior_resource)
end
@@ -74,10 +70,17 @@ class Chef
resource.params = params
# Evaluate resource attribute DSL
- resource.instance_eval(&block) if block_given?
+ if block_given?
+ resource.resource_initializing = true
+ begin
+ resource.instance_eval(&block)
+ ensure
+ resource.resource_initializing = false
+ end
+ end
# emit a cloned resource warning if it is warranted
- if prior_resource
+ if prior_resource && Chef::Config[:resource_cloning]
if is_trivial_resource?(prior_resource) && identicalish_resources?(prior_resource, resource)
emit_harmless_cloning_debug
else
@@ -101,7 +104,11 @@ class Chef
end
def is_trivial_resource?(resource)
- identicalish_resources?(resource_class.new(name, run_context), resource)
+ trivial_resource = resource_class.new(name, run_context)
+ # force un-lazy the name property on the created trivial resource
+ name_property = resource_class.properties.find { |sym, p| p.name_property? }
+ trivial_resource.send(name_property[0]) unless name_property.nil?
+ identicalish_resources?(trivial_resource, resource)
end
# this is an equality test specific to checking for 3694 cloning warnings
@@ -121,9 +128,10 @@ class Chef
end
def emit_cloned_resource_warning
- Chef::Log.warn("Cloning resource attributes for #{resource} from prior resource (CHEF-3694)")
- Chef::Log.warn("Previous #{prior_resource}: #{prior_resource.source_line}") if prior_resource.source_line
- Chef::Log.warn("Current #{resource}: #{resource.source_line}") if resource.source_line
+ message = "Cloning resource attributes for #{resource} from prior resource"
+ message << "\nPrevious #{prior_resource}: #{prior_resource.source_line}" if prior_resource.source_line
+ message << "\nCurrent #{resource}: #{resource.source_line}" if resource.source_line
+ Chef.deprecated(:resource_cloning, message)
end
def emit_harmless_cloning_debug
@@ -134,7 +142,7 @@ class Chef
@prior_resource ||=
begin
key = "#{type}[#{name}]"
- prior_resource = run_context.resource_collection.lookup(key)
+ run_context.resource_collection.lookup_local(key)
rescue Chef::Exceptions::ResourceNotFound
nil
end
@@ -142,3 +150,7 @@ class Chef
end
end
+
+require "chef/exceptions"
+require "chef/resource"
+require "chef/log"
diff --git a/lib/chef/resource_collection.rb b/lib/chef/resource_collection.rb
index 4fd6fcad24..8eaa2961c4 100644
--- a/lib/chef/resource_collection.rb
+++ b/lib/chef/resource_collection.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +17,11 @@
# limitations under the License.
#
-require 'chef/resource_collection/resource_set'
-require 'chef/resource_collection/resource_list'
-require 'chef/resource_collection/resource_collection_serialization'
-require 'chef/log'
-require 'forwardable'
+require "chef/resource_collection/resource_set"
+require "chef/resource_collection/resource_list"
+require "chef/resource_collection/resource_collection_serialization"
+require "chef/log"
+require "forwardable"
##
# ResourceCollection currently handles two tasks:
@@ -33,9 +33,12 @@ class Chef
extend Forwardable
attr_reader :resource_set, :resource_list
- private :resource_set, :resource_list
+ attr_accessor :run_context
- def initialize
+ protected :resource_set, :resource_list
+
+ def initialize(run_context = nil)
+ @run_context = run_context
@resource_set = ResourceSet.new
@resource_list = ResourceList.new
end
@@ -45,7 +48,7 @@ class Chef
# @param instance_name [String] If known, the recource name as used in the recipe, IE `vim` in `package 'vim'`
# This method is meant to be the 1 insert method necessary in the future. It should support all known use cases
# for writing into the ResourceCollection.
- def insert(resource, opts={})
+ def insert(resource, opts = {})
resource_type ||= opts[:resource_type] # Would rather use Ruby 2.x syntax, but oh well
instance_name ||= opts[:instance_name]
resource_list.insert(resource)
@@ -56,6 +59,11 @@ class Chef
end
end
+ def delete(key)
+ resource_list.delete(key)
+ resource_set.delete(key)
+ end
+
# @deprecated
def []=(index, resource)
Chef::Log.warn("`[]=` is deprecated, use `insert` (which only inserts at the end)")
@@ -78,12 +86,51 @@ class Chef
# Read-only methods are simple to delegate - doing that below
resource_list_methods = Enumerable.instance_methods +
- [:iterator, :all_resources, :[], :each, :execute_each_resource, :each_index, :empty?] -
- [:find] # find needs to run on the set
- resource_set_methods = [:lookup, :find, :resources, :keys, :validate_lookup_spec!]
+ [:iterator, :all_resources, :[], :each, :execute_each_resource, :each_index, :empty?] -
+ [:find] # find overridden below
+ resource_set_methods = [:resources, :keys, :validate_lookup_spec!]
def_delegators :resource_list, *resource_list_methods
def_delegators :resource_set, *resource_set_methods
+ def lookup_local(key)
+ resource_set.lookup(key)
+ end
+
+ def find_local(*args)
+ resource_set.find(*args)
+ end
+
+ def lookup(key)
+ if run_context.nil?
+ lookup_local(key)
+ else
+ lookup_recursive(run_context, key)
+ end
+ end
+
+ def find(*args)
+ if run_context.nil?
+ find_local(*args)
+ else
+ find_recursive(run_context, *args)
+ end
+ end
+
+ private
+
+ def lookup_recursive(rc, key)
+ rc.resource_collection.resource_set.lookup(key)
+ rescue Chef::Exceptions::ResourceNotFound
+ raise if rc.parent_run_context.nil?
+ lookup_recursive(rc.parent_run_context, key)
+ end
+
+ def find_recursive(rc, *args)
+ rc.resource_collection.resource_set.find(*args)
+ rescue Chef::Exceptions::ResourceNotFound
+ raise if rc.parent_run_context.nil?
+ find_recursive(rc.parent_run_context, *args)
+ end
end
end
diff --git a/lib/chef/resource_collection/resource_collection_serialization.rb b/lib/chef/resource_collection/resource_collection_serialization.rb
index 3651fb2a2a..647d28dfd0 100644
--- a/lib/chef/resource_collection/resource_collection_serialization.rb
+++ b/lib/chef/resource_collection/resource_collection_serialization.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tyler Ball (<tball@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Tyler Ball (<tball@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,12 +21,12 @@ class Chef
# Serialize this object as a hash
def to_hash
instance_vars = Hash.new
- self.instance_variables.each do |iv|
- instance_vars[iv] = self.instance_variable_get(iv)
+ instance_variables.each do |iv|
+ instance_vars[iv] = instance_variable_get(iv)
end
{
- 'json_class' => self.class.name,
- 'instance_vars' => instance_vars
+ "json_class" => self.class.name,
+ "instance_vars" => instance_vars,
}
end
@@ -40,8 +40,8 @@ class Chef
module ClassMethods
def json_create(o)
- collection = self.new()
- o["instance_vars"].each do |k,v|
+ collection = new()
+ o["instance_vars"].each do |k, v|
collection.instance_variable_set(k.to_sym, v)
end
collection
diff --git a/lib/chef/resource_collection/resource_list.rb b/lib/chef/resource_collection/resource_list.rb
index a26bd347aa..9fe012d4c3 100644
--- a/lib/chef/resource_collection/resource_list.rb
+++ b/lib/chef/resource_collection/resource_list.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tyler Ball (<tball@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Tyler Ball (<tball@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/resource_collection/stepable_iterator'
-require 'chef/resource_collection/resource_collection_serialization'
-require 'forwardable'
+require "chef/resource"
+require "chef/resource_collection/stepable_iterator"
+require "chef/resource_collection/resource_collection_serialization"
+require "forwardable"
# This class keeps the list of all known Resources in the order they are to be executed in. It also keeps a pointer
# to the most recently executed resource so we can add resources-to-execute after this point.
@@ -67,6 +67,16 @@ class Chef
end
end
+ def delete(key)
+ raise ArgumentError, "Must pass a Chef::Resource or String to delete" unless key.is_a?(String) || key.is_a?(Chef::Resource)
+ key = key.to_s
+ ret = @resources.reject! { |r| r.to_s == key }
+ if ret.nil?
+ raise Chef::Exceptions::ResourceNotFound, "Cannot find a resource matching #{key} (did you define it first?)"
+ end
+ ret
+ end
+
# @deprecated - can be removed when it is removed from resource_collection.rb
def []=(index, resource)
@resources[index] = resource
@@ -76,7 +86,8 @@ class Chef
@resources
end
- def execute_each_resource(&resource_exec_block)
+ # FIXME: yard with @yield
+ def execute_each_resource
@iterator = ResourceCollection::StepableIterator.for_collection(@resources)
@iterator.each_with_index do |resource, idx|
@insert_after_idx = idx
diff --git a/lib/chef/resource_collection/resource_set.rb b/lib/chef/resource_collection/resource_set.rb
index 1b39298cb4..1a73818790 100644
--- a/lib/chef/resource_collection/resource_set.rb
+++ b/lib/chef/resource_collection/resource_set.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tyler Ball (<tball@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Tyler Ball (<tball@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/resource_collection/resource_collection_serialization'
+require "chef/resource"
+require "chef/resource_collection/resource_collection_serialization"
class Chef
class ResourceCollection
@@ -40,7 +40,7 @@ class Chef
@resources_by_key.keys
end
- def insert_as(resource, resource_type=nil, instance_name=nil)
+ def insert_as(resource, resource_type = nil, instance_name = nil)
is_chef_resource!(resource)
resource_type ||= resource.resource_name
instance_name ||= resource.name
@@ -49,18 +49,22 @@ class Chef
end
def lookup(key)
- case
- when key.kind_of?(String)
- lookup_by = key
- when key.kind_of?(Chef::Resource)
- lookup_by = create_key(key.resource_name, key.name)
- else
- raise ArgumentError, "Must pass a Chef::Resource or String to lookup"
+ raise ArgumentError, "Must pass a Chef::Resource or String to lookup" unless key.is_a?(String) || key.is_a?(Chef::Resource)
+ key = key.to_s
+ res = @resources_by_key[key]
+ unless res
+ raise Chef::Exceptions::ResourceNotFound, "Cannot find a resource matching #{key} (did you define it first?)"
end
+ res
+ end
- res = @resources_by_key[lookup_by]
- unless res
- raise Chef::Exceptions::ResourceNotFound, "Cannot find a resource matching #{lookup_by} (did you define it first?)"
+ def delete(key)
+ raise ArgumentError, "Must pass a Chef::Resource or String to delete" unless key.is_a?(String) || key.is_a?(Chef::Resource)
+ key = key.to_s
+ res = @resources_by_key.delete(key)
+
+ if res == @resources_by_key.default
+ raise Chef::Exceptions::ResourceNotFound, "Cannot find a resource matching #{key} (did you define it first?)"
end
res
end
@@ -124,7 +128,7 @@ class Chef
else
raise Chef::Exceptions::InvalidResourceSpecification,
"The object `#{query_object.inspect}' is not valid for resource collection lookup. " +
- "Use a String like `resource_type[resource_name]' or a Chef::Resource object"
+ "Use a String like `resource_type[resource_name]' or a Chef::Resource object"
end
end
@@ -142,7 +146,7 @@ class Chef
results << lookup(create_key(resource_type, instance_name))
end
end
- return results
+ results
end
def find_resource_by_string(arg)
@@ -162,9 +166,8 @@ class Chef
else
raise ArgumentError, "Bad string format #{arg}, you must have a string like resource_type[name]!"
end
- return results
+ results
end
-
end
end
end
diff --git a/lib/chef/resource_collection/stepable_iterator.rb b/lib/chef/resource_collection/stepable_iterator.rb
index 4d5fc1f497..958ffa28cb 100644
--- a/lib/chef/resource_collection/stepable_iterator.rb
+++ b/lib/chef/resource_collection/stepable_iterator.rb
@@ -1,5 +1,5 @@
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,7 +27,7 @@ class Chef
attr_accessor :collection
attr_reader :position
- def initialize(collection=[])
+ def initialize(collection = [])
@position = 0
@paused = false
@collection = collection
@@ -72,11 +72,11 @@ class Chef
@position = 0
end
- def skip_back(skips=1)
+ def skip_back(skips = 1)
@position -= skips
end
- def skip_forward(skips=1)
+ def skip_forward(skips = 1)
@position += skips
end
@@ -100,9 +100,7 @@ class Chef
end
def iterate
- while @position < size && !paused?
- step
- end
+ step while @position < size && !paused?
collection
end
diff --git a/lib/chef/resource_definition.rb b/lib/chef/resource_definition.rb
index cffabb6786..aa114af46c 100644
--- a/lib/chef/resource_definition.rb
+++ b/lib/chef/resource_definition.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/mixin/from_file'
-require 'chef/mixin/params_validate'
+require "chef/mixin/from_file"
+require "chef/mixin/params_validate"
class Chef
class ResourceDefinition
@@ -27,14 +27,14 @@ class Chef
attr_accessor :name, :params, :recipe, :node
- def initialize(node=nil)
+ def initialize(node = nil)
@name = nil
@params = Hash.new
@recipe = nil
@node = node
end
- def define(resource_name, prototype_params=nil, &block)
+ def define(resource_name, prototype_params = nil, &block)
unless resource_name.kind_of?(Symbol)
raise ArgumentError, "You must use a symbol when defining a new resource!"
end
@@ -62,7 +62,7 @@ class Chef
end
def to_s
- "#{name.to_s}"
+ "#{name}"
end
end
end
diff --git a/lib/chef/resource_definition_list.rb b/lib/chef/resource_definition_list.rb
index 55014090d4..22751249e4 100644
--- a/lib/chef/resource_definition_list.rb
+++ b/lib/chef/resource_definition_list.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/mixin/from_file'
-require 'chef/resource_definition'
+require "chef/mixin/from_file"
+require "chef/resource_definition"
class Chef
class ResourceDefinitionList
@@ -29,7 +29,7 @@ class Chef
@defines = Hash.new
end
- def define(resource_name, prototype_params=nil, &block)
+ def define(resource_name, prototype_params = nil, &block)
@defines[resource_name] = ResourceDefinition.new
@defines[resource_name].define(resource_name, prototype_params, &block)
true
diff --git a/lib/chef/resource_reporter.rb b/lib/chef/resource_reporter.rb
index 1175b0afb3..afc8500a2a 100644
--- a/lib/chef/resource_reporter.rb
+++ b/lib/chef/resource_reporter.rb
@@ -1,9 +1,9 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: Prajakta Purohit (prajakta@opscode.com>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Prajakta Purohit (prajakta@chef.io>)
# Auther:: Tyler Cloke (<tyler@opscode.com>)
#
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,18 +19,18 @@
# limitations under the License.
#
-require 'uri'
-require 'securerandom'
-require 'chef/event_dispatch/base'
+require "uri"
+require "securerandom"
+require "chef/event_dispatch/base"
class Chef
class ResourceReporter < EventDispatch::Base
- class ResourceReport < Struct.new(:new_resource,
- :current_resource,
- :action,
- :exception,
- :elapsed_time)
+ ResourceReport = Struct.new(:new_resource,
+ :current_resource,
+ :action,
+ :exception,
+ :elapsed_time) do
def self.new_with_current_state(new_resource, action, current_resource)
report = new
@@ -87,7 +87,7 @@ class Chef
end
def success?
- !self.exception
+ !exception
end
end # End class ResouceReport
@@ -97,7 +97,7 @@ class Chef
attr_reader :run_id
attr_reader :error_descriptions
- PROTOCOL_VERSION = '0.1.0'
+ PROTOCOL_VERSION = "0.1.0"
def initialize(rest_client)
if Chef::Config[:enable_reporting] && !Chef::Config[:why_run]
@@ -121,8 +121,8 @@ class Chef
if reporting_enabled?
begin
resource_history_url = "reports/nodes/#{node_name}/runs"
- server_response = @rest_client.post_rest(resource_history_url, {:action => :start, :run_id => run_id,
- :start_time => start_time.to_s}, headers)
+ server_response = @rest_client.post(resource_history_url, { :action => :start, :run_id => run_id,
+ :start_time => start_time.to_s }, headers)
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
handle_error_starting_run(e, resource_history_url)
end
@@ -198,6 +198,17 @@ class Chef
def resource_completed(new_resource)
if @pending_update && !nested_resource?(new_resource)
@pending_update.finish
+
+ # Verify if the resource has sensitive data
+ # and create a new blank resource with only
+ # the name so we can report it back without
+ # sensitive data
+ if @pending_update.new_resource.sensitive
+ klass = @pending_update.new_resource.class
+ resource_name = @pending_update.new_resource.name
+ @pending_update.new_resource = klass.new(resource_name)
+ end
+
@updated_resources << @pending_update
@pending_update = nil
end
@@ -230,10 +241,9 @@ class Chef
Chef::Log.debug run_data.inspect
compressed_data = encode_gzip(Chef::JSONCompat.to_json(run_data))
Chef::Log.debug("Sending compressed run data...")
- # Since we're posting compressed data we can not directly call post_rest which expects JSON
- reporting_url = @rest_client.create_url(resource_history_url)
+ # Since we're posting compressed data we can not directly call post which expects JSON
begin
- @rest_client.raw_http_request(:POST, reporting_url, headers({'Content-Encoding' => 'gzip'}), compressed_data)
+ @rest_client.raw_request(:POST, resource_history_url, headers({ "Content-Encoding" => "gzip" }), compressed_data)
rescue StandardError => e
if e.respond_to? :response
Chef::FileCache.store("failed-reporting-data.json", Chef::JSONCompat.to_json_pretty(run_data), 0640)
@@ -248,7 +258,7 @@ class Chef
end
def headers(additional_headers = {})
- options = {'X-Ops-Reporting-Protocol-Version' => PROTOCOL_VERSION}
+ options = { "X-Ops-Reporting-Protocol-Version" => PROTOCOL_VERSION }
options.merge(additional_headers)
end
@@ -283,7 +293,7 @@ class Chef
exception_data["class"] = exception.inspect
exception_data["message"] = exception.message
exception_data["backtrace"] = Chef::JSONCompat.to_json(exception.backtrace)
- exception_data["description"] = @error_descriptions
+ exception_data["description"] = @error_descriptions
run_data["data"]["exception"] = exception_data
end
run_data
@@ -320,7 +330,7 @@ class Chef
def encode_gzip(data)
"".tap do |out|
- Zlib::GzipWriter.wrap(StringIO.new(out)){|gz| gz << data }
+ Zlib::GzipWriter.wrap(StringIO.new(out)) { |gz| gz << data }
end
end
diff --git a/lib/chef/resource_resolver.rb b/lib/chef/resource_resolver.rb
index 67cf134c62..fca6c6db81 100644
--- a/lib/chef/resource_resolver.rb
+++ b/lib/chef/resource_resolver.rb
@@ -1,6 +1,6 @@
#
# Author:: Lamont Granquist (<lamont@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/exceptions'
-require 'chef/platform/resource_priority_map'
-require 'chef/mixin/convert_to_class_name'
+require "chef/exceptions"
+require "chef/platform/resource_priority_map"
+require "chef/mixin/convert_to_class_name"
class Chef
class ResourceResolver
@@ -47,7 +47,6 @@ class Chef
new(node, resource_name, canonical: canonical).list
end
-
include Chef::Mixin::ConvertToClassName
# @api private
@@ -56,7 +55,7 @@ class Chef
attr_reader :resource_name
# @api private
def resource
- Chef.log_deprecation("Chef::ResourceResolver.resource deprecated. Use resource_name instead.")
+ Chef.deprecated(:custom_resource, "Chef::ResourceResolver.resource deprecated. Use resource_name instead.")
resource_name
end
# @api private
@@ -174,8 +173,7 @@ class Chef
if handlers.empty?
handlers = resources.select { |handler| overrode_provides?(handler) && handler.provides?(node, resource_name) }
handlers.each do |handler|
- Chef.log_deprecation("#{handler}.provides? returned true when asked if it provides DSL #{resource_name}, but provides #{resource_name.inspect} was never called!")
- Chef.log_deprecation("In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself.")
+ Chef.deprecated(:custom_resource, "#{handler}.provides? returned true when asked if it provides DSL #{resource_name}, but provides #{resource_name.inspect} was never called! In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself.")
end
end
handlers
diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb
index af4dd8a642..ab89ce66e0 100644
--- a/lib/chef/resources.rb
+++ b/lib/chef/resources.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,75 +16,86 @@
# limitations under the License.
#
-require 'chef/resource/apt_package'
-require 'chef/resource/bash'
-require 'chef/resource/batch'
-require 'chef/resource/breakpoint'
-require 'chef/resource/cookbook_file'
-require 'chef/resource/chef_gem'
-require 'chef/resource/cron'
-require 'chef/resource/csh'
-require 'chef/resource/deploy'
-require 'chef/resource/deploy_revision'
-require 'chef/resource/directory'
-require 'chef/resource/dpkg_package'
-require 'chef/resource/dsc_script'
-require 'chef/resource/dsc_resource'
-require 'chef/resource/easy_install_package'
-require 'chef/resource/env'
-require 'chef/resource/erl_call'
-require 'chef/resource/execute'
-require 'chef/resource/file'
-require 'chef/resource/freebsd_package'
-require 'chef/resource/ips_package'
-require 'chef/resource/gem_package'
-require 'chef/resource/git'
-require 'chef/resource/group'
-require 'chef/resource/http_request'
-require 'chef/resource/homebrew_package'
-require 'chef/resource/ifconfig'
-require 'chef/resource/link'
-require 'chef/resource/log'
-require 'chef/resource/macports_package'
-require 'chef/resource/mdadm'
-require 'chef/resource/mount'
-require 'chef/resource/ohai'
-require 'chef/resource/openbsd_package'
-require 'chef/resource/package'
-require 'chef/resource/pacman_package'
-require 'chef/resource/paludis_package'
-require 'chef/resource/perl'
-require 'chef/resource/portage_package'
-require 'chef/resource/powershell_script'
-require 'chef/resource/python'
-require 'chef/resource/reboot'
-require 'chef/resource/registry_key'
-require 'chef/resource/remote_directory'
-require 'chef/resource/remote_file'
-require 'chef/resource/rpm_package'
-require 'chef/resource/solaris_package'
-require 'chef/resource/route'
-require 'chef/resource/ruby'
-require 'chef/resource/ruby_block'
-require 'chef/resource/scm'
-require 'chef/resource/script'
-require 'chef/resource/service'
-require 'chef/resource/windows_service'
-require 'chef/resource/subversion'
-require 'chef/resource/smartos_package'
-require 'chef/resource/template'
-require 'chef/resource/timestamped_deploy'
-require 'chef/resource/user'
-require 'chef/resource/whyrun_safe_ruby_block'
-require 'chef/resource/windows_package'
-require 'chef/resource/yum_package'
-require 'chef/resource/lwrp_base'
-require 'chef/resource/bff_package'
-require 'chef/resource/zypper_package'
-
-begin
- # Optional resources chef_node, chef_client, machine, machine_image, etc.
- require 'cheffish'
- require 'chef/provisioning'
-rescue LoadError
-end
+require "chef/resource/apt_package"
+require "chef/resource/apt_repository"
+require "chef/resource/apt_update"
+require "chef/resource/bash"
+require "chef/resource/batch"
+require "chef/resource/breakpoint"
+require "chef/resource/cookbook_file"
+require "chef/resource/chef_gem"
+require "chef/resource/chocolatey_package"
+require "chef/resource/cron"
+require "chef/resource/csh"
+require "chef/resource/deploy"
+require "chef/resource/deploy_revision"
+require "chef/resource/directory"
+require "chef/resource/dpkg_package"
+require "chef/resource/dnf_package"
+require "chef/resource/dsc_script"
+require "chef/resource/dsc_resource"
+require "chef/resource/easy_install_package"
+require "chef/resource/env"
+require "chef/resource/erl_call"
+require "chef/resource/execute"
+require "chef/resource/file"
+require "chef/resource/freebsd_package"
+require "chef/resource/ips_package"
+require "chef/resource/gem_package"
+require "chef/resource/git"
+require "chef/resource/group"
+require "chef/resource/http_request"
+require "chef/resource/homebrew_package"
+require "chef/resource/ifconfig"
+require "chef/resource/ksh"
+require "chef/resource/launchd"
+require "chef/resource/link"
+require "chef/resource/log"
+require "chef/resource/macports_package"
+require "chef/resource/mdadm"
+require "chef/resource/mount"
+require "chef/resource/ohai"
+require "chef/resource/openbsd_package"
+require "chef/resource/package"
+require "chef/resource/pacman_package"
+require "chef/resource/paludis_package"
+require "chef/resource/perl"
+require "chef/resource/portage_package"
+require "chef/resource/powershell_script"
+require "chef/resource/osx_profile"
+require "chef/resource/python"
+require "chef/resource/reboot"
+require "chef/resource/registry_key"
+require "chef/resource/remote_directory"
+require "chef/resource/remote_file"
+require "chef/resource/rpm_package"
+require "chef/resource/solaris_package"
+require "chef/resource/route"
+require "chef/resource/ruby"
+require "chef/resource/ruby_block"
+require "chef/resource/scm"
+require "chef/resource/script"
+require "chef/resource/service"
+require "chef/resource/systemd_unit"
+require "chef/resource/windows_service"
+require "chef/resource/subversion"
+require "chef/resource/smartos_package"
+require "chef/resource/template"
+require "chef/resource/timestamped_deploy"
+require "chef/resource/user"
+require "chef/resource/user/aix_user"
+require "chef/resource/user/dscl_user"
+require "chef/resource/user/linux_user"
+require "chef/resource/user/pw_user"
+require "chef/resource/user/solaris_user"
+require "chef/resource/user/windows_user"
+require "chef/resource/whyrun_safe_ruby_block"
+require "chef/resource/windows_package"
+require "chef/resource/yum_package"
+require "chef/resource/yum_repository"
+require "chef/resource/lwrp_base"
+require "chef/resource/bff_package"
+require "chef/resource/zypper_package"
+require "chef/resource/cab_package"
+require "chef/resource/powershell_package"
+require "chef/resource/msu_package"
diff --git a/lib/chef/rest.rb b/lib/chef/rest.rb
index 4106a01077..0705ca9f5a 100644
--- a/lib/chef/rest.rb
+++ b/lib/chef/rest.rb
@@ -1,10 +1,10 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Thom May (<thom@clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,23 +20,24 @@
# limitations under the License.
#
-require 'tempfile'
-require 'chef/http'
+require "tempfile"
+require "chef/http"
class Chef
class HTTP; end
class REST < HTTP; end
end
-require 'chef/http/authenticator'
-require 'chef/http/decompressor'
-require 'chef/http/json_input'
-require 'chef/http/json_to_model_output'
-require 'chef/http/cookie_manager'
-require 'chef/http/validate_content_length'
-require 'chef/config'
-require 'chef/exceptions'
-require 'chef/platform/query_helpers'
-require 'chef/http/remote_request_id'
+require "chef/http/authenticator"
+require "chef/http/decompressor"
+require "chef/http/json_input"
+require "chef/http/json_to_model_output"
+require "chef/http/cookie_manager"
+require "chef/http/validate_content_length"
+require "chef/config"
+require "chef/exceptions"
+require "chef/platform/query_helpers"
+require "chef/http/remote_request_id"
+require "chef/chef_class"
class Chef
@@ -57,7 +58,8 @@ class Chef
# all subsequent requests. For example, when initialized with a base url
# http://localhost:4000, a call to +get_rest+ with 'nodes' will make an
# HTTP GET request to http://localhost:4000/nodes
- def initialize(url, client_name=Chef::Config[:node_name], signing_key_filename=Chef::Config[:client_key], options={})
+ def initialize(url, client_name = Chef::Config[:node_name], signing_key_filename = Chef::Config[:client_key], options = {})
+ Chef.deprecated(:chef_rest, "Chef::REST is deprecated. Please use Chef::ServerAPI, or investigate Ridley or ChefAPI.")
signing_key_filename = nil if chef_zero_uri?(url)
@@ -82,7 +84,6 @@ class Chef
# because the order of middlewares is reversed when handling
# responses.
@middlewares << ValidateContentLength.new(options)
-
end
def signing_key_filename
@@ -113,7 +114,7 @@ class Chef
# path:: The path to GET
# raw:: Whether you want the raw body returned, or JSON inflated. Defaults
# to JSON inflated.
- def get(path, raw=false, headers={})
+ def get(path, raw = false, headers = {})
if raw
streaming_request(path, headers)
else
@@ -134,8 +135,8 @@ class Chef
# If you rename the tempfile, it will not be deleted.
# Beware that if the server streams infinite content, this method will
# stream it until you run out of disk space.
- def fetch(path, headers={})
- streaming_request(create_url(path), headers) {|tmp_file| yield tmp_file }
+ def fetch(path, headers = {})
+ streaming_request(create_url(path), headers) { |tmp_file| yield tmp_file }
end
alias :api_request :request
@@ -201,7 +202,7 @@ class Chef
@decompressor.decompress_body(body)
end
- def authentication_headers(method, url, json_body=nil)
+ def authentication_headers(method, url, json_body = nil)
authenticator.authentication_headers(method, url, json_body)
end
diff --git a/lib/chef/role.rb b/lib/chef/role.rb
index c085d1d714..218894ef03 100644
--- a/lib/chef/role.rb
+++ b/lib/chef/role.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,13 +18,14 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/run_list'
-require 'chef/mash'
-require 'chef/json_compat'
-require 'chef/search/query'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/run_list"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/server_api"
+require "chef/search/query"
class Chef
class Role
@@ -36,23 +37,23 @@ class Chef
# Create a new Chef::Role object.
def initialize(chef_server_rest: nil)
- @name = ''
- @description = ''
+ @name = ""
+ @description = ""
@default_attributes = Mash.new
@override_attributes = Mash.new
- @env_run_lists = {"_default" => Chef::RunList.new}
+ @env_run_lists = { "_default" => Chef::RunList.new }
@chef_server_rest = chef_server_rest
end
def chef_server_rest
- @chef_server_rest ||= Chef::REST.new(Chef::Config[:chef_server_url])
+ @chef_server_rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url])
end
def self.chef_server_rest
- Chef::REST.new(Chef::Config[:chef_server_url])
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url])
end
- def name(arg=nil)
+ def name(arg = nil)
set_or_return(
:name,
arg,
@@ -60,7 +61,7 @@ class Chef
)
end
- def description(arg=nil)
+ def description(arg = nil)
set_or_return(
:description,
arg,
@@ -69,7 +70,7 @@ class Chef
end
def run_list(*args)
- if (args.length > 0)
+ if args.length > 0
@env_run_lists["_default"].reset!(args)
end
@env_run_lists["_default"]
@@ -87,36 +88,35 @@ class Chef
end
def active_run_list_for(environment)
- @env_run_lists.has_key?(environment) ? environment : '_default'
+ @env_run_lists.has_key?(environment) ? environment : "_default"
end
# Per environment run lists
- def env_run_lists(env_run_lists=nil)
- if (!env_run_lists.nil?)
+ def env_run_lists(env_run_lists = nil)
+ if !env_run_lists.nil?
unless env_run_lists.key?("_default")
msg = "_default key is required in env_run_lists.\n"
msg << "(env_run_lists: #{env_run_lists.inspect})"
raise Chef::Exceptions::InvalidEnvironmentRunListSpecification, msg
end
@env_run_lists.clear
- env_run_lists.each { |k,v| @env_run_lists[k] = Chef::RunList.new(*Array(v))}
+ env_run_lists.each { |k, v| @env_run_lists[k] = Chef::RunList.new(*Array(v)) }
end
@env_run_lists
end
alias :env_run_list :env_run_lists
- def env_run_lists_add(env_run_lists=nil)
- if (!env_run_lists.nil?)
- env_run_lists.each { |k,v| @env_run_lists[k] = Chef::RunList.new(*Array(v))}
+ def env_run_lists_add(env_run_lists = nil)
+ if !env_run_lists.nil?
+ env_run_lists.each { |k, v| @env_run_lists[k] = Chef::RunList.new(*Array(v)) }
end
@env_run_lists
end
alias :env_run_list_add :env_run_lists_add
-
- def default_attributes(arg=nil)
+ def default_attributes(arg = nil)
set_or_return(
:default_attributes,
arg,
@@ -124,7 +124,7 @@ class Chef
)
end
- def override_attributes(arg=nil)
+ def override_attributes(arg = nil)
set_or_return(
:override_attributes,
arg,
@@ -138,7 +138,7 @@ class Chef
result = {
"name" => @name,
"description" => @description,
- 'json_class' => self.class.name,
+ "json_class" => self.class.name,
"default_attributes" => @default_attributes,
"override_attributes" => @override_attributes,
"chef_type" => "role",
@@ -149,7 +149,7 @@ class Chef
"env_run_lists" => env_run_lists_without_default.inject({}) do |accumulator, (k, v)|
accumulator[k] = v.map { |x| x.to_s }
accumulator
- end
+ end,
}
result
end
@@ -170,6 +170,11 @@ class Chef
# Create a Chef::Role from JSON
def self.json_create(o)
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::Role#from_hash")
+ from_hash(o)
+ end
+
+ def self.from_hash(o)
role = new
role.name(o["name"])
role.description(o["description"])
@@ -178,7 +183,7 @@ class Chef
# _default run_list is in 'run_list' for newer clients, and
# 'recipes' for older clients.
- env_run_list_hash = {"_default" => (o.has_key?("run_list") ? o["run_list"] : o["recipes"])}
+ env_run_list_hash = { "_default" => (o.has_key?("run_list") ? o["run_list"] : o["recipes"]) }
# Clients before 0.10 do not include env_run_lists, so only
# merge if it's there.
@@ -191,7 +196,7 @@ class Chef
end
# Get the list of all roles from the API.
- def self.list(inflate=false)
+ def self.list(inflate = false)
if inflate
response = Hash.new
Chef::Search::Query.new.search(:role) do |n|
@@ -199,42 +204,42 @@ class Chef
end
response
else
- chef_server_rest.get_rest("roles")
+ chef_server_rest.get("roles")
end
end
# Load a role by name from the API
def self.load(name)
- chef_server_rest.get_rest("roles/#{name}")
+ from_hash(chef_server_rest.get("roles/#{name}"))
end
def environment(env_name)
- chef_server_rest.get_rest("roles/#{@name}/environments/#{env_name}")
+ chef_server_rest.get("roles/#{@name}/environments/#{env_name}")
end
def environments
- chef_server_rest.get_rest("roles/#{@name}/environments")
+ chef_server_rest.get("roles/#{@name}/environments")
end
# Remove this role via the REST API
def destroy
- chef_server_rest.delete_rest("roles/#{@name}")
+ chef_server_rest.delete("roles/#{@name}")
end
# Save this role via the REST API
def save
begin
- chef_server_rest.put_rest("roles/#{@name}", self)
+ chef_server_rest.put("roles/#{@name}", self)
rescue Net::HTTPServerException => e
raise e unless e.response.code == "404"
- chef_server_rest.post_rest("roles", self)
+ chef_server_rest.post("roles", self)
end
self
end
# Create the role via the REST API
def create
- chef_server_rest.post_rest("roles", self)
+ chef_server_rest.post("roles", self)
self
end
@@ -248,17 +253,18 @@ class Chef
def self.from_disk(name)
paths = Array(Chef::Config[:role_path])
paths.each do |path|
- roles_files = Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(path), "**", "**"))
+ roles_files = Dir.glob(File.join(Chef::Util::PathHelper.escape_glob_dir(path), "**", "**"))
js_files = roles_files.select { |file| file.match(/\/#{name}\.json$/) }
rb_files = roles_files.select { |file| file.match(/\/#{name}\.rb$/) }
- if js_files.count > 1 or rb_files.count > 1
+ if js_files.count > 1 || rb_files.count > 1
raise Chef::Exceptions::DuplicateRole, "Multiple roles of same type found named #{name}"
end
js_path, rb_path = js_files.first, rb_files.first
if js_path && File.exists?(js_path)
# from_json returns object.class => json_class in the JSON.
- return Chef::JSONCompat.from_json(IO.read(js_path))
+ hsh = Chef::JSONCompat.parse(IO.read(js_path))
+ return from_hash(hsh)
elsif rb_path && File.exists?(rb_path)
role = Chef::Role.new
role.name(name)
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb
index f7ab88f7e0..6d84b7773d 100644
--- a/lib/chef/run_context.rb
+++ b/lib/chef/run_context.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2008-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/resource_collection'
-require 'chef/cookbook_version'
-require 'chef/node'
-require 'chef/role'
-require 'chef/log'
-require 'chef/recipe'
-require 'chef/run_context/cookbook_compiler'
-require 'chef/event_dispatch/events_output_stream'
-require 'forwardable'
+require "chef/resource_collection"
+require "chef/cookbook_version"
+require "chef/node"
+require "chef/role"
+require "chef/log"
+require "chef/recipe"
+require "chef/run_context/cookbook_compiler"
+require "chef/event_dispatch/events_output_stream"
+require "forwardable"
class Chef
@@ -85,6 +85,17 @@ class Chef
attr_reader :parent_run_context
#
+ # The root run context.
+ #
+ # @return [Chef::RunContext] The root run context.
+ #
+ def root_run_context
+ rc = self
+ rc = rc.parent_run_context until rc.parent_run_context.nil?
+ rc
+ end
+
+ #
# The collection of resources intended to be converged (and able to be
# notified).
#
@@ -104,6 +115,15 @@ class Chef
#
#
+ # A Hash containing the before notifications triggered by resources
+ # during the converge phase of the chef run.
+ #
+ # @return [Hash[String, Array[Chef::Resource::Notification]]] A hash from
+ # <notifying resource name> => <list of notifications it sent>
+ #
+ attr_reader :before_notification_collection
+
+ #
# A Hash containing the immediate notifications triggered by resources
# during the converge phase of the chef run.
#
@@ -121,6 +141,14 @@ class Chef
#
attr_reader :delayed_notification_collection
+ #
+ # An Array containing the delayed (end of run) notifications triggered by
+ # resources during the converge phase of the chef run.
+ #
+ # @return [Array[Chef::Resource::Notification]] An array of notification objects
+ #
+ attr_reader :delayed_actions
+
# Creates a new Chef::RunContext object and populates its fields. This object gets
# used by the Chef Server to generate a fully compiled recipe list for a node.
#
@@ -143,6 +171,7 @@ class Chef
@loaded_attributes_hash = {}
@reboot_info = {}
@cookbook_compiler = nil
+ @delayed_actions = []
initialize_child_state
end
@@ -163,9 +192,23 @@ class Chef
#
def initialize_child_state
@audits = {}
- @resource_collection = Chef::ResourceCollection.new
- @immediate_notification_collection = Hash.new {|h,k| h[k] = []}
- @delayed_notification_collection = Hash.new {|h,k| h[k] = []}
+ @resource_collection = Chef::ResourceCollection.new(self)
+ @before_notification_collection = Hash.new { |h, k| h[k] = [] }
+ @immediate_notification_collection = Hash.new { |h, k| h[k] = [] }
+ @delayed_notification_collection = Hash.new { |h, k| h[k] = [] }
+ @delayed_actions = []
+ end
+
+ #
+ # Adds an before notification to the +before_notification_collection+.
+ #
+ # @param [Chef::Resource::Notification] The notification to add.
+ #
+ def notifies_before(notification)
+ # Note for the future, notification.notifying_resource may be an instance
+ # of Chef::Resource::UnresolvedSubscribes when calling {Resource#subscribes}
+ # with a string value.
+ before_notification_collection[notification.notifying_resource.declared_key] << notification
end
#
@@ -174,12 +217,10 @@ class Chef
# @param [Chef::Resource::Notification] The notification to add.
#
def notifies_immediately(notification)
- nr = notification.notifying_resource
- if nr.instance_of?(Chef::Resource)
- immediate_notification_collection[nr.name] << notification
- else
- immediate_notification_collection[nr.declared_key] << notification
- end
+ # Note for the future, notification.notifying_resource may be an instance
+ # of Chef::Resource::UnresolvedSubscribes when calling {Resource#subscribes}
+ # with a string value.
+ immediate_notification_collection[notification.notifying_resource.declared_key] << notification
end
#
@@ -188,45 +229,50 @@ class Chef
# @param [Chef::Resource::Notification] The notification to add.
#
def notifies_delayed(notification)
- nr = notification.notifying_resource
- if nr.instance_of?(Chef::Resource)
- delayed_notification_collection[nr.name] << notification
+ # Note for the future, notification.notifying_resource may be an instance
+ # of Chef::Resource::UnresolvedSubscribes when calling {Resource#subscribes}
+ # with a string value.
+ delayed_notification_collection[notification.notifying_resource.declared_key] << notification
+ end
+
+ #
+ # Adds a delayed action to the +delayed_actions+.
+ #
+ def add_delayed_action(notification)
+ if delayed_actions.any? { |existing_notification| existing_notification.duplicates?(notification) }
+ Chef::Log.info( "#{notification.notifying_resource} not queuing delayed action #{notification.action} on #{notification.resource}"\
+ " (delayed), as it's already been queued")
else
- delayed_notification_collection[nr.declared_key] << notification
+ delayed_actions << notification
end
end
#
- # Get the list of immediate notifications sent by the given resource.
+ # Get the list of before notifications sent by the given resource.
+ #
+ # @return [Array[Notification]]
+ #
+ def before_notifications(resource)
+ before_notification_collection[resource.declared_key]
+ end
+
#
- # TODO seriously, this is actually wrong. resource.name is not unique,
- # you need the type as well.
+ # Get the list of immediate notifications sent by the given resource.
#
# @return [Array[Notification]]
#
def immediate_notifications(resource)
- if resource.instance_of?(Chef::Resource)
- return immediate_notification_collection[resource.name]
- else
- return immediate_notification_collection[resource.declared_key]
- end
+ immediate_notification_collection[resource.declared_key]
end
#
# Get the list of delayed (end of run) notifications sent by the given
# resource.
#
- # TODO seriously, this is actually wrong. resource.name is not unique,
- # you need the type as well.
- #
# @return [Array[Notification]]
#
def delayed_notifications(resource)
- if resource.instance_of?(Chef::Resource)
- return delayed_notification_collection[resource.name]
- else
- return delayed_notification_collection[resource.declared_key]
- end
+ delayed_notification_collection[resource.declared_key]
end
#
@@ -282,7 +328,6 @@ including it from in that cookbook's metadata.
ERROR_MESSAGE
end
-
if loaded_fully_qualified_recipe?(cookbook_name, recipe_short_name)
Chef::Log.debug("I am not loading #{recipe_name}, because I have already seen it.")
false
@@ -309,7 +354,7 @@ ERROR_MESSAGE
end
Chef::Log.debug("Loading recipe file #{recipe_file}")
- recipe = Chef::Recipe.new('@recipe_files', recipe_file, self)
+ recipe = Chef::Recipe.new("@recipe_files", recipe_file, self)
recipe.from_file(recipe_file)
recipe
end
@@ -502,12 +547,12 @@ ERROR_MESSAGE
# 5. raise an exception on any second call.
# 6. ?
def request_reboot(reboot_info)
- Chef::Log::info "Changing reboot status from #{self.reboot_info.inspect} to #{reboot_info.inspect}"
+ Chef::Log.info "Changing reboot status from #{self.reboot_info.inspect} to #{reboot_info.inspect}"
@reboot_info = reboot_info
end
def cancel_reboot
- Chef::Log::info "Changing reboot status from #{reboot_info.inspect} to {}"
+ Chef::Log.info "Changing reboot status from #{reboot_info.inspect} to {}"
@reboot_info = {}
end
@@ -536,23 +581,22 @@ ERROR_MESSAGE
# These need to be settable so deploy can run a resource_collection
# independent of any cookbooks via +recipe_eval+
def audits=(value)
- Chef.log_deprecation("Setting run_context.audits will be removed in a future Chef. Use run_context.create_child to create a new RunContext instead.")
+ Chef.deprecated(:internal_api, "Setting run_context.audits will be removed in a future Chef. Use run_context.create_child to create a new RunContext instead.")
@audits = value
end
def immediate_notification_collection=(value)
- Chef.log_deprecation("Setting run_context.immediate_notification_collection will be removed in a future Chef. Use run_context.create_child to create a new RunContext instead.")
+ Chef.deprecated(:internal_api, "Setting run_context.immediate_notification_collection will be removed in a future Chef. Use run_context.create_child to create a new RunContext instead.")
@immediate_notification_collection = value
end
def delayed_notification_collection=(value)
- Chef.log_deprecation("Setting run_context.delayed_notification_collection will be removed in a future Chef. Use run_context.create_child to create a new RunContext instead.")
+ Chef.deprecated(:internal_api, "Setting run_context.delayed_notification_collection will be removed in a future Chef. Use run_context.create_child to create a new RunContext instead.")
@delayed_notification_collection = value
end
end
prepend Deprecated
-
#
# A child run context. Delegates all root context calls to its parent.
#
@@ -560,7 +604,7 @@ ERROR_MESSAGE
#
class ChildRunContext < RunContext
extend Forwardable
- def_delegators :parent_run_context, *%w(
+ def_delegators :parent_run_context, *%w{
cancel_reboot
config
cookbook_collection
@@ -587,7 +631,7 @@ ERROR_MESSAGE
request_reboot
resolve_attribute
unreachable_cookbook?
- )
+ }
def initialize(parent_run_context)
@parent_run_context = parent_run_context
@@ -598,31 +642,39 @@ ERROR_MESSAGE
initialize_child_state
end
- CHILD_STATE = %w(
+ CHILD_STATE = %w{
audits
audits=
create_child
+ add_delayed_action
+ delayed_actions
delayed_notification_collection
delayed_notification_collection=
delayed_notifications
immediate_notification_collection
immediate_notification_collection=
immediate_notifications
+ before_notification_collection
+ before_notifications
include_recipe
initialize_child_state
load_recipe
load_recipe_file
+ notifies_before
notifies_immediately
notifies_delayed
parent_run_context
+ root_run_context
resource_collection
resource_collection=
- ).map { |x| x.to_sym }
+ }.map { |x| x.to_sym }
# Verify that we didn't miss any methods
- missing_methods = superclass.instance_methods(false) - instance_methods(false) - CHILD_STATE
- if !missing_methods.empty?
- raise "ERROR: not all methods of RunContext accounted for in ChildRunContext! All methods must be marked as child methods with CHILD_STATE or delegated to the parent_run_context. Missing #{missing_methods.join(", ")}."
+ unless @__skip_method_checking # hook specifically for compat_resource
+ missing_methods = superclass.instance_methods(false) - instance_methods(false) - CHILD_STATE
+ if !missing_methods.empty?
+ raise "ERROR: not all methods of RunContext accounted for in ChildRunContext! All methods must be marked as child methods with CHILD_STATE or delegated to the parent_run_context. Missing #{missing_methods.join(", ")}."
+ end
end
end
end
diff --git a/lib/chef/run_context/cookbook_compiler.rb b/lib/chef/run_context/cookbook_compiler.rb
index abe5afa7ae..b2a8d236a3 100644
--- a/lib/chef/run_context/cookbook_compiler.rb
+++ b/lib/chef/run_context/cookbook_compiler.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'set'
-require 'chef/log'
-require 'chef/recipe'
-require 'chef/resource/lwrp_base'
-require 'chef/provider/lwrp_base'
-require 'chef/resource_definition_list'
+require "set"
+require "chef/log"
+require "chef/recipe"
+require "chef/resource/lwrp_base"
+require "chef/provider/lwrp_base"
+require "chef/resource_definition_list"
class Chef
class RunContext
@@ -137,13 +137,14 @@ class Chef
@events.recipe_load_start(run_list_expansion.recipes.size)
run_list_expansion.recipes.each do |recipe|
begin
+ path = resolve_recipe(recipe)
@run_context.load_recipe(recipe)
+ @events.recipe_file_loaded(path, recipe)
rescue Chef::Exceptions::RecipeNotFound => e
@events.recipe_not_found(e)
raise
rescue Exception => e
- path = resolve_recipe(recipe)
- @events.recipe_file_load_failed(path, e)
+ @events.recipe_file_load_failed(path, e, recipe)
raise
end
end
@@ -165,7 +166,7 @@ class Chef
def load_attributes_from_cookbook(cookbook_name)
list_of_attr_files = files_in_cookbook_by_segment(cookbook_name, :attributes).dup
- if default_file = list_of_attr_files.find {|path| File.basename(path) == "default.rb" }
+ if default_file = list_of_attr_files.find { |path| File.basename(path) == "default.rb" }
list_of_attr_files.delete(default_file)
load_attribute_file(cookbook_name.to_s, default_file)
end
@@ -186,6 +187,7 @@ class Chef
def load_libraries_from_cookbook(cookbook_name)
files_in_cookbook_by_segment(cookbook_name, :libraries).each do |filename|
+ next unless File.extname(filename) == ".rb"
begin
Chef::Log.debug("Loading cookbook #{cookbook_name}'s library file: #{filename}")
Kernel.load(filename)
@@ -224,7 +226,6 @@ class Chef
raise
end
-
def load_resource_definitions_from_cookbook(cookbook_name)
files_in_cookbook_by_segment(cookbook_name, :definitions).each do |filename|
begin
@@ -258,7 +259,6 @@ class Chef
ordered_cookbooks << cookbook
end
-
def count_files_by_segment(segment)
cookbook_collection.inject(0) do |count, cookbook_by_name|
count + cookbook_by_name[1].segment_filenames(segment).size
@@ -275,7 +275,7 @@ class Chef
# +cookbook_name+ in lexical sort order.
def each_cookbook_dep(cookbook_name, &block)
cookbook = cookbook_collection[cookbook_name]
- cookbook.metadata.dependencies.keys.sort.map{|x| x.to_sym}.each(&block)
+ cookbook.metadata.dependencies.keys.sort.map { |x| x.to_sym }.each(&block)
end
# Given a +recipe_name+, finds the file associated with the recipe.
@@ -285,7 +285,6 @@ class Chef
cookbook.recipe_filenames_by_name[recipe_short_name]
end
-
end
end
diff --git a/lib/chef/run_list.rb b/lib/chef/run_list.rb
index 01e32ffc98..3ac5fab07b 100644
--- a/lib/chef/run_list.rb
+++ b/lib/chef/run_list.rb
@@ -1,10 +1,10 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Nuo Yan (<nuoyan@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Nuo Yan (<nuoyan@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,10 +19,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/run_list/run_list_item'
-require 'chef/run_list/run_list_expansion'
-require 'chef/run_list/versioned_recipe_list'
-require 'chef/mixin/params_validate'
+require "chef/run_list/run_list_item"
+require "chef/run_list/run_list_expansion"
+require "chef/run_list/versioned_recipe_list"
+require "chef/mixin/params_validate"
class Chef
class RunList
@@ -47,13 +47,13 @@ class Chef
end
def role_names
- @run_list_items.inject([]){|memo, run_list_item| memo << run_list_item.name if run_list_item.role? ; memo}
+ @run_list_items.inject([]) { |memo, run_list_item| memo << run_list_item.name if run_list_item.role?; memo }
end
alias :roles :role_names
def recipe_names
- @run_list_items.inject([]){|memo, run_list_item| memo << run_list_item.name if run_list_item.recipe? ; memo}
+ @run_list_items.inject([]) { |memo, run_list_item| memo << run_list_item.name if run_list_item.recipe?; memo }
end
alias :recipes :recipe_names
@@ -105,12 +105,14 @@ class Chef
@run_list_items[pos] = parse_entry(item)
end
- def each(&block)
- @run_list_items.each { |i| block.call(i) }
+ # FIXME: yard with @yield
+ def each
+ @run_list_items.each { |i| yield(i) }
end
- def each_index(&block)
- @run_list_items.each_index { |i| block.call(i) }
+ # FIXME: yard with @yield
+ def each_index
+ @run_list_items.each_index { |i| yield(i) }
end
def include?(item)
@@ -130,7 +132,7 @@ class Chef
end
def remove(item)
- @run_list_items.delete_if{|i| i == item}
+ @run_list_items.delete_if { |i| i == item }
self
end
alias :delete :remove
@@ -138,7 +140,7 @@ class Chef
# Expands this run_list: recursively expand roles into their included
# recipes.
# Returns a RunListExpansion object.
- def expand(environment, data_source='server', expansion_opts={})
+ def expand(environment, data_source = "server", expansion_opts = {})
expansion = expansion_for_data_source(environment, data_source, expansion_opts)
expansion.expand
expansion
@@ -153,11 +155,11 @@ class Chef
item.kind_of?(RunListItem) ? item : parse_entry(item)
end
- def expansion_for_data_source(environment, data_source, opts={})
+ def expansion_for_data_source(environment, data_source, opts = {})
case data_source.to_s
- when 'disk'
+ when "disk"
RunListExpansionFromDisk.new(environment, @run_list_items)
- when 'server'
+ when "server"
RunListExpansionFromAPI.new(environment, @run_list_items, opts[:rest])
end
end
diff --git a/lib/chef/run_list/run_list_expansion.rb b/lib/chef/run_list/run_list_expansion.rb
index 64e4326fb8..b895b53523 100644
--- a/lib/chef/run_list/run_list_expansion.rb
+++ b/lib/chef/run_list/run_list_expansion.rb
@@ -1,7 +1,7 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2010, 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/mash'
+require "chef/mash"
-require 'chef/mixin/deep_merge'
+require "chef/mixin/deep_merge"
-require 'chef/role'
-require 'chef/rest'
-require 'chef/json_compat'
+require "chef/role"
+require "chef/server_api"
+require "chef/json_compat"
class Chef
class RunList
@@ -45,7 +45,7 @@ class Chef
attr_reader :missing_roles_with_including_role
# The data source passed to the constructor. Not used in this class.
- # In subclasses, this is a couchdb or Chef::REST object pre-configured
+ # In subclasses, this is a Chef::ServerAPI object pre-configured
# to fetch roles from their correct location.
attr_reader :source
@@ -62,7 +62,7 @@ class Chef
attr_reader :all_missing_roles
attr_reader :role_errors
- def initialize(environment, run_list_items, source=nil)
+ def initialize(environment, run_list_items, source = nil)
@environment = environment
@missing_roles_with_including_role = Array.new
@@ -75,8 +75,8 @@ class Chef
@recipes = Chef::RunList::VersionedRecipeList.new
@applied_roles = {}
- @run_list_trace = Hash.new {|h, key| h[key] = [] }
- @better_run_list_trace = Hash.new {|h, key| h[key] = [] }
+ @run_list_trace = Hash.new { |h, key| h[key] = [] }
+ @better_run_list_trace = Hash.new { |h, key| h[key] = [] }
@all_missing_roles = {}
@role_errors = {}
end
@@ -140,7 +140,7 @@ class Chef
end
def errors
- @missing_roles_with_including_role.map {|item| item.first }
+ @missing_roles_with_including_role.map { |item| item.first }
end
def to_json(*a)
@@ -148,8 +148,8 @@ class Chef
end
def to_hash
- seen_items = {:recipe => {}, :role => {}}
- {:id => @environment, :run_list => convert_run_list_trace('top level', seen_items)}
+ seen_items = { :recipe => {}, :role => {} }
+ { :id => @environment, :run_list => convert_run_list_trace("top level", seen_items) }
end
private
@@ -160,11 +160,10 @@ class Chef
@applied_roles[role_name] = true
end
- def expand_run_list_items(items, included_by="top level")
-
+ def expand_run_list_items(items, included_by = "top level")
if entry = items.shift
@run_list_trace[included_by.to_s] << entry.to_s
- @better_run_list_trace[included_by.to_s] << entry
+ @better_run_list_trace[included_by.to_s] << entry
case entry.type
when :recipe
@@ -186,19 +185,18 @@ class Chef
seen_items[item.type][item.name] = true
case item.type
when :recipe
- {:type => 'recipe', :name => item.name, :version => item.version, :skipped => !!skipped}
+ { :type => "recipe", :name => item.name, :version => item.version, :skipped => !!skipped }
when :role
error = @role_errors[item.name]
missing = @all_missing_roles[item.name]
- {:type => :role, :name => item.name, :children => (missing || error || skipped) ? [] : convert_run_list_trace(item.to_s, seen_items),
- :missing => missing, :error => error, :skipped => skipped}
+ { :type => :role, :name => item.name, :children => (missing || error || skipped) ? [] : convert_run_list_trace(item.to_s, seen_items),
+ :missing => missing, :error => error, :skipped => skipped }
end
end
end
end
-
# Expand a run list from disk. Suitable for chef-solo
class RunListExpansionFromDisk < RunListExpansion
@@ -214,11 +212,11 @@ class Chef
class RunListExpansionFromAPI < RunListExpansion
def rest
- @rest ||= (source || Chef::REST.new(Chef::Config[:chef_server_url]))
+ @rest ||= (source || Chef::ServerAPI.new(Chef::Config[:chef_server_url]))
end
def fetch_role(name, included_by)
- rest.get_rest("roles/#{name}")
+ Chef::Role.from_hash(rest.get("roles/#{name}"))
rescue Net::HTTPServerException => e
if e.message == '404 "Not Found"'
role_not_found(name, included_by)
@@ -234,5 +232,3 @@ class Chef
end
end
-
-
diff --git a/lib/chef/run_list/run_list_item.rb b/lib/chef/run_list/run_list_item.rb
index 43bb239754..1c75907dd8 100644
--- a/lib/chef/run_list/run_list_item.rb
+++ b/lib/chef/run_list/run_list_item.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,16 +25,15 @@ class Chef
attr_reader :name, :type, :version
-
def initialize(item)
@version = nil
case item
when Hash
assert_hash_is_valid_run_list_item!(item)
- @type = (item['type'] || item[:type]).to_sym
- @name = item['name'] || item[:name]
- if (item.has_key?('version') || item.has_key?(:version))
- @version = item['version'] || item[:version]
+ @type = (item["type"] || item[:type]).to_sym
+ @name = item["name"] || item[:name]
+ if item.has_key?("version") || item.has_key?(:version)
+ @version = item["version"] || item[:version]
end
when String
if match = QUALIFIED_RECIPE.match(item)
@@ -69,7 +68,7 @@ class Chef
end
def to_s
- "#{@type}[#{@name}#{@version ? "@#{@version}" :""}]"
+ "#{@type}[#{@name}#{@version ? "@#{@version}" : ""}]"
end
def role?
@@ -82,14 +81,14 @@ class Chef
def ==(other)
if other.kind_of?(String)
- self.to_s == other.to_s
+ to_s == other.to_s
else
other.respond_to?(:type) && other.respond_to?(:name) && other.respond_to?(:version) && other.type == @type && other.name == @name && other.version == @version
end
end
def assert_hash_is_valid_run_list_item!(item)
- unless (item.key?('type')|| item.key?(:type)) && (item.key?('name') || item.key?(:name))
+ unless (item.key?("type") || item.key?(:type)) && (item.key?("name") || item.key?(:name))
raise ArgumentError, "Initializing a #{self.class} from a hash requires that it have a 'type' and 'name' key"
end
end
diff --git a/lib/chef/run_list/versioned_recipe_list.rb b/lib/chef/run_list/versioned_recipe_list.rb
index 803156aef9..ccd7351eeb 100644
--- a/lib/chef/run_list/versioned_recipe_list.rb
+++ b/lib/chef/run_list/versioned_recipe_list.rb
@@ -1,7 +1,7 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/version_class'
-require 'chef/version_constraint'
+require "chef/version_class"
+require "chef/version_constraint"
# Why does this class exist?
# Why did we not just modify RunList/RunListItem?
@@ -29,24 +29,24 @@ class Chef
@versions = Hash.new
end
- def add_recipe(name, version=nil)
+ def add_recipe(name, version = nil)
if version && @versions.has_key?(name)
unless Chef::Version.new(@versions[name]) == Chef::Version.new(version)
raise Chef::Exceptions::CookbookVersionConflict, "Run list requires #{name} at versions #{@versions[name]} and #{version}"
end
end
@versions[name] = version if version
- self << name unless self.include?(name)
+ self << name unless include?(name)
end
def with_versions
- self.map {|recipe_name| {:name => recipe_name, :version => @versions[recipe_name]}}
+ map { |recipe_name| { :name => recipe_name, :version => @versions[recipe_name] } }
end
# Return an Array of Hashes, each of the form:
# {:name => RECIPE_NAME, :version_constraint => Chef::VersionConstraint }
def with_version_constraints
- self.map do |recipe_name|
+ map do |recipe_name|
constraint = Chef::VersionConstraint.new(@versions[recipe_name])
{ :name => recipe_name, :version_constraint => constraint }
end
@@ -55,7 +55,7 @@ class Chef
# Return an Array of Strings, each of the form:
# "NAME@VERSION"
def with_version_constraints_strings
- self.map do |recipe_name|
+ map do |recipe_name|
if @versions[recipe_name]
"#{recipe_name}@#{@versions[recipe_name]}"
else
@@ -69,12 +69,12 @@ class Chef
#
# @return [Array] Array of strings with fully-qualified recipe names
def with_fully_qualified_names_and_version_constraints
- self.map do |recipe_name|
- qualified_recipe = if recipe_name.include?('::')
- recipe_name
- else
- "#{recipe_name}::default"
- end
+ map do |recipe_name|
+ qualified_recipe = if recipe_name.include?("::")
+ recipe_name
+ else
+ "#{recipe_name}::default"
+ end
version = @versions[recipe_name]
qualified_recipe = "#{qualified_recipe}@#{version}" if version
@@ -89,8 +89,8 @@ class Chef
#
# @return [Array] Array of strings with fully-qualified and unexpanded recipe names
def with_duplicate_names
- self.map do |recipe_name|
- if recipe_name.include?('::')
+ map do |recipe_name|
+ if recipe_name.include?("::")
recipe_name
else
[recipe_name, "#{recipe_name}::default"]
diff --git a/lib/chef/run_lock.rb b/lib/chef/run_lock.rb
index 9e0952bdcb..08d58fd164 100644
--- a/lib/chef/run_lock.rb
+++ b/lib/chef/run_lock.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,14 +15,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/mixin/create_path'
-require 'fcntl'
+require "chef/mixin/create_path"
+require "fcntl"
if Chef::Platform.windows?
- require 'chef/win32/mutex'
+ require "chef/win32/mutex"
end
-require 'chef/config'
-require 'chef/exceptions'
-require 'timeout'
+require "chef/config"
+require "chef/exceptions"
+require "timeout"
class Chef
@@ -63,7 +63,7 @@ class Chef
def acquire
if timeout_given?
begin
- Timeout::timeout(time_to_wait) do
+ Timeout.timeout(time_to_wait) do
unless test
if time_to_wait > 0.0
wait
@@ -72,7 +72,7 @@ class Chef
end
end
end
- rescue Timeout::Error => e
+ rescue Timeout::Error
exit_from_timeout
end
else
@@ -132,7 +132,7 @@ class Chef
def create_lock
# ensure the runlock_file path exists
create_path(File.dirname(runlock_file))
- @runlock = File.open(runlock_file,'a+')
+ @runlock = File.open(runlock_file, "a+")
end
# @api private solely for race condition tests
@@ -143,12 +143,12 @@ class Chef
# If we support FD_CLOEXEC, then use it.
# NB: ruby-2.0.0-p195 sets FD_CLOEXEC by default, but not
# ruby-1.8.7/1.9.3
- if Fcntl.const_defined?('F_SETFD') && Fcntl.const_defined?('FD_CLOEXEC')
+ if Fcntl.const_defined?("F_SETFD") && Fcntl.const_defined?("FD_CLOEXEC")
runlock.fcntl(Fcntl::F_SETFD, runlock.fcntl(Fcntl::F_GETFD, 0) | Fcntl::FD_CLOEXEC)
end
# Flock will return 0 if it can acquire the lock otherwise it
# will return false
- if runlock.flock(File::LOCK_NB|File::LOCK_EX) == 0
+ if runlock.flock(File::LOCK_NB | File::LOCK_EX) == 0
true
else
false
diff --git a/lib/chef/run_status.rb b/lib/chef/run_status.rb
index ce8ff296f4..c3b7945bc9 100644
--- a/lib/chef/run_status.rb
+++ b/lib/chef/run_status.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -113,7 +113,7 @@ class Chef::RunStatus
:updated_resources => updated_resources,
:exception => formatted_exception,
:backtrace => backtrace,
- :run_id => run_id}
+ :run_id => run_id }
end
# Returns a string of the format "ExceptionClass: message" or +nil+ if no
diff --git a/lib/chef/runner.rb b/lib/chef/runner.rb
index 6125fe59e1..cd5615bcec 100644
--- a/lib/chef/runner.rb
+++ b/lib/chef/runner.rb
@@ -1,8 +1,8 @@
#--
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,10 @@
# limitations under the License.
#
-require 'chef/exceptions'
-require 'chef/mixin/params_validate'
-require 'chef/node'
-require 'chef/resource_collection'
+require "chef/exceptions"
+require "chef/mixin/params_validate"
+require "chef/node"
+require "chef/resource_collection"
class Chef
# == Chef::Runner
@@ -30,13 +30,14 @@ class Chef
attr_reader :run_context
- attr_reader :delayed_actions
-
include Chef::Mixin::ParamsValidate
def initialize(run_context)
- @run_context = run_context
- @delayed_actions = []
+ @run_context = run_context
+ end
+
+ def delayed_actions
+ @run_context.delayed_actions
end
def events
@@ -45,7 +46,26 @@ class Chef
# Determine the appropriate provider for the given resource, then
# execute it.
- def run_action(resource, action, notification_type=nil, notifying_resource=nil)
+ def run_action(resource, action, notification_type = nil, notifying_resource = nil)
+ # If there are any before notifications, why-run the resource
+ # and notify anyone who needs notifying
+ before_notifications = run_context.before_notifications(resource) || []
+ unless before_notifications.empty?
+ forced_why_run do
+ Chef::Log.info("#{resource} running why-run #{action} action to support before action")
+ resource.run_action(action, notification_type, notifying_resource)
+ end
+
+ if resource.updated_by_last_action?
+ before_notifications.each do |notification|
+ Chef::Log.info("#{resource} sending #{notification.action} action to #{notification.resource} (before)")
+ run_action(notification.resource, notification.action, :before, resource)
+ end
+ resource.updated_by_last_action(false)
+ end
+ end
+
+ # Actually run the action for realsies
resource.run_action(action, notification_type, notifying_resource)
# Execute any immediate and queue up any delayed notifications
@@ -58,12 +78,8 @@ class Chef
end
run_context.delayed_notifications(resource).each do |notification|
- if delayed_actions.any? { |existing_notification| existing_notification.duplicates?(notification) }
- Chef::Log.info( "#{resource} not queuing delayed action #{notification.action} on #{notification.resource}"\
- " (delayed), as it's already been queued")
- else
- delayed_actions << notification
- end
+ # send the notification to the run_context of the receiving resource
+ notification.resource.run_context.add_delayed_action(notification)
end
end
end
@@ -78,7 +94,7 @@ class Chef
# Execute each resource.
run_context.resource_collection.execute_each_resource do |resource|
- Array(resource.action).each {|action| run_action(resource, action)}
+ Array(resource.action).each { |action| run_action(resource, action) }
end
rescue Exception => e
@@ -92,7 +108,7 @@ class Chef
private
# Run all our :delayed actions
- def run_delayed_notifications(error=nil)
+ def run_delayed_notifications(error = nil)
collected_failures = Exceptions::MultipleFailures.new
collected_failures.client_run_failure(error) unless error.nil?
delayed_actions.each do |notification|
@@ -113,5 +129,15 @@ class Chef
rescue Exception => e
e
end
+
+ # helper to run a block of code with why_run forced to true and then restore it correctly
+ def forced_why_run
+ saved = Chef::Config[:why_run]
+ Chef::Config[:why_run] = true
+ yield
+ ensure
+ Chef::Config[:why_run] = saved
+ end
+
end
end
diff --git a/lib/chef/scan_access_control.rb b/lib/chef/scan_access_control.rb
index 01630a7254..0e6df30303 100644
--- a/lib/chef/scan_access_control.rb
+++ b/lib/chef/scan_access_control.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -70,7 +70,7 @@ class Chef
when Integer
stat.uid
else
- Chef::Log.error("The `owner` parameter of the #@new_resource resource is set to an invalid value (#{new_resource.owner.inspect})")
+ Chef::Log.error("The `owner` parameter of the #{@new_resource} resource is set to an invalid value (#{new_resource.owner.inspect})")
raise ArgumentError, "cannot resolve #{new_resource.owner.inspect} to uid, owner must be a string or integer"
end
end
@@ -97,7 +97,7 @@ class Chef
when Integer
stat.gid
else
- Chef::Log.error("The `group` parameter of the #@new_resource resource is set to an invalid value (#{new_resource.owner.inspect})")
+ Chef::Log.error("The `group` parameter of the #{@new_resource} resource is set to an invalid value (#{new_resource.owner.inspect})")
raise ArgumentError, "cannot resolve #{new_resource.group.inspect} to gid, group must be a string or integer"
end
end
@@ -121,18 +121,18 @@ class Chef
when String, Integer, nil
"0#{(stat.mode & 07777).to_s(8)}"
else
- Chef::Log.error("The `mode` parameter of the #@new_resource resource is set to an invalid value (#{new_resource.mode.inspect})")
- raise ArgumentError, "Invalid value #{new_resource.mode.inspect} for `mode` on resource #@new_resource"
+ Chef::Log.error("The `mode` parameter of the #{@new_resource} resource is set to an invalid value (#{new_resource.mode.inspect})")
+ raise ArgumentError, "Invalid value #{new_resource.mode.inspect} for `mode` on resource #{@new_resource}"
end
end
def stat
@stat ||= if @new_resource.instance_of?(Chef::Resource::Link)
- ::File.lstat(@new_resource.path)
- else
- realpath = ::File.realpath(@new_resource.path)
- ::File.stat(realpath)
- end
+ ::File.lstat(@new_resource.path)
+ else
+ realpath = ::File.realpath(@new_resource.path)
+ ::File.stat(realpath)
+ end
end
end
end
diff --git a/lib/chef/search/query.rb b/lib/chef/search/query.rb
index 658af8779c..bea8205935 100644
--- a/lib/chef/search/query.rb
+++ b/lib/chef/search/query.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,12 @@
# limitations under the License.
#
-require 'chef/config'
-require 'chef/exceptions'
-require 'chef/rest'
+require "chef/config"
+require "chef/exceptions"
+require "chef/server_api"
-require 'uri'
+require "uri"
+require "addressable/uri"
class Chef
class Search
@@ -29,18 +30,18 @@ class Chef
attr_accessor :rest
attr_reader :config
- def initialize(url=nil, config:Chef::Config)
+ def initialize(url = nil, config: Chef::Config)
@config = config
@url = url
end
def rest
- @rest ||= Chef::REST.new(@url || @config[:chef_server_url])
+ @rest ||= Chef::ServerAPI.new(@url || @config[:chef_server_url])
end
# Backwards compatability for cookbooks.
# This can be removed in Chef > 12.
- def partial_search(type, query='*:*', *args, &block)
+ def partial_search(type, query = "*:*", *args, &block)
Chef::Log.warn(<<-WARNDEP)
DEPRECATED: The 'partial_search' API is deprecated and will be removed in
future releases. Please use 'search' with a :filter_result argument to get
@@ -80,14 +81,14 @@ WARNDEP
# an example of the returned json may be:
# {"ip_address":"127.0.0.1", "ruby_version": "1.9.3"}
#
- def search(type, query='*:*', *args, &block)
+ def search(type, query = "*:*", *args, &block)
validate_type(type)
args_h = hashify_args(*args)
response = call_rest_service(type, query: query, **args_h)
if block
- response["rows"].each { |row| block.call(row) if row }
+ response["rows"].each { |row| yield(row) if row }
#
# args_h[:rows] and args_h[:start] are the page size and
# start position requested of the search index backing the
@@ -116,8 +117,8 @@ WARNDEP
def validate_type(t)
unless t.kind_of?(String) || t.kind_of?(Symbol)
msg = "Invalid search object type #{t.inspect} (#{t.class}), must be a String or Symbol." +
- "Usage: search(:node, QUERY[, OPTIONAL_ARGS])" +
- " `knife search environment QUERY (options)`"
+ "Usage: search(:node, QUERY[, OPTIONAL_ARGS])" +
+ " `knife search environment QUERY (options)`"
raise Chef::Exceptions::InvalidSearchQuery, msg
end
end
@@ -134,28 +135,44 @@ WARNDEP
args_h
end
- def escape(s)
- s && URI.escape(s.to_s)
+ QUERY_PARAM_VALUE = Addressable::URI::CharacterClasses::QUERY + "\\&\\;"
+
+ def escape_value(s)
+ s && Addressable::URI.encode_component(s.to_s, QUERY_PARAM_VALUE)
end
def create_query_string(type, query, rows, start, sort)
- qstr = "search/#{type}?q=#{escape(query)}"
- qstr += "&sort=#{escape(sort)}" if sort
- qstr += "&start=#{escape(start)}" if start
- qstr += "&rows=#{escape(rows)}" if rows
+ qstr = "search/#{type}?q=#{escape_value(query)}"
+ qstr += "&sort=#{escape_value(sort)}" if sort
+ qstr += "&start=#{escape_value(start)}" if start
+ qstr += "&rows=#{escape_value(rows)}" if rows
qstr
end
- def call_rest_service(type, query:'*:*', rows:nil, start:0, sort:'X_CHEF_id_CHEF_X asc', filter_result:nil)
+ def call_rest_service(type, query: "*:*", rows: nil, start: 0, sort: "X_CHEF_id_CHEF_X asc", filter_result: nil)
query_string = create_query_string(type, query, rows, start, sort)
if filter_result
- response = rest.post_rest(query_string, filter_result)
+ response = rest.post(query_string, filter_result)
# response returns rows in the format of
# { "url" => url_to_node, "data" => filter_result_hash }
- response['rows'].map! { |row| row['data'] }
+ response["rows"].map! { |row| row["data"] }
else
- response = rest.get_rest(query_string)
+ response = rest.get(query_string)
+ response["rows"].map! do |row|
+ case type.to_s
+ when "node"
+ Chef::Node.from_hash(row)
+ when "role"
+ Chef::Role.from_hash(row)
+ when "environment"
+ Chef::Environment.from_hash(row)
+ when "client"
+ Chef::ApiClient.from_hash(row)
+ else
+ Chef::DataBagItem.from_hash(row)
+ end
+ end
end
response
diff --git a/lib/chef/server_api.rb b/lib/chef/server_api.rb
index 764296f8c8..2bdc5d9fe8 100644
--- a/lib/chef/server_api.rb
+++ b/lib/chef/server_api.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,24 @@
# limitations under the License.
#
-require 'chef/http'
-require 'chef/http/authenticator'
-require 'chef/http/cookie_manager'
-require 'chef/http/decompressor'
-require 'chef/http/json_input'
-require 'chef/http/json_output'
-require 'chef/http/remote_request_id'
+require "chef/http"
+require "chef/http/authenticator"
+require "chef/http/cookie_manager"
+require "chef/http/decompressor"
+require "chef/http/json_input"
+require "chef/http/json_output"
+require "chef/http/remote_request_id"
+require "chef/http/validate_content_length"
+require "chef/http/api_versions"
class Chef
class ServerAPI < Chef::HTTP
def initialize(url = Chef::Config[:chef_server_url], options = {})
options[:client_name] ||= Chef::Config[:node_name]
- options[:signing_key_filename] ||= Chef::Config[:client_key]
+ options[:signing_key_filename] ||= Chef::Config[:client_key] unless options[:raw_key]
options[:signing_key_filename] = nil if chef_zero_uri?(url)
+ options[:inflate_json_class] = false
super(url, options)
end
@@ -40,7 +43,38 @@ class Chef
use Chef::HTTP::Decompressor
use Chef::HTTP::Authenticator
use Chef::HTTP::RemoteRequestID
+ use Chef::HTTP::APIVersions
+
+ # ValidateContentLength should come after Decompressor
+ # because the order of middlewares is reversed when handling
+ # responses.
+ use Chef::HTTP::ValidateContentLength
+
+ # for back compat with Chef::REST, expose `<verb>_rest` as an alias to `<verb>`
+ alias :get_rest :get
+ alias :delete_rest :delete
+ alias :post_rest :post
+ alias :put_rest :put
+
+ # Makes an HTTP request to +path+ with the given +method+, +headers+, and
+ # +data+ (if applicable). Does not apply any middleware, besides that
+ # needed for Authentication.
+ def raw_request(method, path, headers = {}, data = false)
+ url = create_url(path)
+ method, url, headers, data = Chef::HTTP::Authenticator.new(options).handle_request(method, url, headers, data)
+ method, url, headers, data = Chef::HTTP::RemoteRequestID.new(options).handle_request(method, url, headers, data)
+ response, rest_request, return_value = send_http_request(method, url, headers, data)
+ response.error! unless success_response?(response)
+ return_value
+ rescue Exception => exception
+ log_failed_request(response, return_value) unless response.nil?
+
+ if exception.respond_to?(:chef_rest_request=)
+ exception.chef_rest_request = rest_request
+ end
+ raise
+ end
end
end
-require 'chef/config'
+require "chef/config"
diff --git a/lib/chef/server_api_versions.rb b/lib/chef/server_api_versions.rb
new file mode 100644
index 0000000000..68dfd5ac90
--- /dev/null
+++ b/lib/chef/server_api_versions.rb
@@ -0,0 +1,40 @@
+#--
+# Copyright:: Copyright 2017, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "singleton"
+
+class Chef
+ class ServerAPIVersions
+ include Singleton
+
+ def set_versions(versions)
+ @versions ||= versions
+ end
+
+ def min_server_version
+ !@versions.nil? ? @versions["min_version"] : nil
+ end
+
+ def max_server_version
+ !@versions.nil? ? @versions["max_version"] : nil
+ end
+
+ def reset!
+ @versions = nil
+ end
+ end
+end
diff --git a/lib/chef/shell.rb b/lib/chef/shell.rb
index 3a68785ce9..e8c3704553 100644
--- a/lib/chef/shell.rb
+++ b/lib/chef/shell.rb
@@ -1,5 +1,5 @@
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,21 +15,21 @@
# limitations under the License.
#
-require 'singleton'
-require 'pp'
-require 'etc'
-require 'mixlib/cli'
+require "singleton"
+require "pp"
+require "etc"
+require "mixlib/cli"
-require 'chef'
-require 'chef/version'
-require 'chef/client'
-require 'chef/config'
-require 'chef/config_fetcher'
+require "chef"
+require "chef/version"
+require "chef/client"
+require "chef/config"
+require "chef/config_fetcher"
-require 'chef/shell/shell_session'
-require 'chef/shell/ext'
-require 'chef/json_compat'
-require 'chef/util/path_helper'
+require "chef/shell/shell_session"
+require "chef/shell/ext"
+require "chef/json_compat"
+require "chef/util/path_helper"
# = Shell
# Shell is Chef in an IRB session. Shell can interact with a Chef server via the
@@ -64,7 +64,6 @@ module Shell
init(irb.context.main)
-
irb_conf[:IRB_RC].call(irb.context) if irb_conf[:IRB_RC]
irb_conf[:MAIN_CONTEXT] = irb.context
@@ -149,7 +148,7 @@ module Shell
end
def self.greeting
- " #{Etc.getlogin}@#{Shell.session.node.fqdn}"
+ " #{Etc.getlogin}@#{Shell.session.node["fqdn"]}"
rescue NameError, ArgumentError
""
end
@@ -180,13 +179,13 @@ module Shell
end
def self.editor
- @editor || Chef::Config[:editor] || ENV['EDITOR']
+ @editor || Chef::Config[:editor] || ENV["EDITOR"]
end
class Options
include Mixlib::CLI
- def self.footer(text=nil)
+ def self.footer(text = nil)
@footer = text if text
@footer
end
@@ -216,7 +215,7 @@ FOOTER
option :log_level,
:short => "-l LOG_LEVEL",
- :long => '--log-level LOG_LEVEL',
+ :long => "--log-level LOG_LEVEL",
:description => "Set the logging level",
:proc => proc { |level| Chef::Config.log_level = level.to_sym; Shell.setup_logger }
@@ -232,7 +231,7 @@ FOOTER
:long => "--solo",
:description => "chef-solo session",
:boolean => true,
- :proc => proc {Chef::Config[:solo] = true}
+ :proc => proc { Chef::Config[:solo] = true }
option :client,
:short => "-z",
@@ -257,14 +256,19 @@ FOOTER
:long => "--version",
:description => "Show chef version",
:boolean => true,
- :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+ :proc => lambda { |v| puts "Chef: #{::Chef::VERSION}" },
:exit => 0
option :override_runlist,
:short => "-o RunlistItem,RunlistItem...",
:long => "--override-runlist RunlistItem,RunlistItem...",
:description => "Replace current run list with specified items",
- :proc => lambda { |items| items.split(',').map { |item| Chef::RunList::RunListItem.new(item) }}
+ :proc => lambda { |items| items.split(",").map { |item| Chef::RunList::RunListItem.new(item) } }
+
+ option :skip_cookbook_sync,
+ :long => "--[no-]skip-cookbook-sync",
+ :description => "Use cached cookbooks without overwriting local differences from the server",
+ :boolean => false
def self.print_help
instance = new
@@ -277,7 +281,7 @@ FOOTER
end
def self.setup!
- self.new.parse_opts
+ new.parse_opts
end
def parse_opts
@@ -296,19 +300,19 @@ FOOTER
private
def config_file_for_shell_mode(environment)
- dot_chef_dir = Chef::Util::PathHelper.home('.chef')
+ dot_chef_dir = Chef::Util::PathHelper.home(".chef")
if config[:config_file]
config[:config_file]
elsif environment
Shell.env = environment
- config_file_to_try = ::File.join(dot_chef_dir, environment, 'chef_shell.rb')
+ config_file_to_try = ::File.join(dot_chef_dir, environment, "chef_shell.rb")
unless ::File.exist?(config_file_to_try)
puts "could not find chef-shell config for environment #{environment} at #{config_file_to_try}"
exit 1
end
config_file_to_try
- elsif dot_chef_dir && ::File.exist?(File.join(dot_chef_dir, 'chef_shell.rb'))
- File.join(dot_chef_dir, 'chef_shell.rb')
+ elsif dot_chef_dir && ::File.exist?(File.join(dot_chef_dir, "chef_shell.rb"))
+ File.join(dot_chef_dir, "chef_shell.rb")
elsif config[:solo]
Chef::Config.platform_specific_path("/etc/chef/solo.rb")
elsif config[:client]
diff --git a/lib/chef/shell/ext.rb b/lib/chef/shell/ext.rb
index d516524765..fb0733e96e 100644
--- a/lib/chef/shell/ext.rb
+++ b/lib/chef/shell/ext.rb
@@ -1,6 +1,6 @@
#--
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'tempfile'
-require 'chef/recipe'
-require 'fileutils'
-require 'chef/dsl/platform_introspection'
-require 'chef/version'
-require 'chef/shell/shell_session'
-require 'chef/shell/model_wrapper'
-require 'chef/shell/shell_rest'
-require 'chef/json_compat'
+require "tempfile"
+require "chef/recipe"
+require "fileutils"
+require "chef/dsl/platform_introspection"
+require "chef/version"
+require "chef/shell/shell_session"
+require "chef/shell/model_wrapper"
+require "chef/server_api"
+require "chef/json_compat"
module Shell
module Extensions
@@ -39,18 +39,18 @@ module Shell
# irb breaks if you prematurely define IRB::JobMangager
# so these methods need to be defined at the latest possible time.
unless jobs.respond_to?(:select_session_by_context)
- def jobs.select_session_by_context(&block)
- @jobs.select { |job| block.call(job[1].context.main)}
+ def jobs.select_session_by_context(&block) # rubocop:disable Lint/NestedMethodDefinition
+ @jobs.select { |job| block.call(job[1].context.main) }
end
end
unless jobs.respond_to?(:session_select)
- def jobs.select_shell_session(target_context)
+ def jobs.select_shell_session(target_context) # rubocop:disable Lint/NestedMethodDefinition
session = if target_context.kind_of?(Class)
- select_session_by_context { |main| main.kind_of?(target_context) }
- else
- select_session_by_context { |main| main.equal?(target_context) }
- end
+ select_session_by_context { |main| main.kind_of?(target_context) }
+ else
+ select_session_by_context { |main| main.equal?(target_context) }
+ end
Array(session.first)[1]
end
end
@@ -73,7 +73,7 @@ module Shell
banner << "| " + "Command".ljust(25) + "| " + "Description"
banner << "".ljust(80, "=")
- self.all_help_descriptions.each do |help_text|
+ all_help_descriptions.each do |help_text|
banner << "| " + help_text.cmd.ljust(25) + "| " + help_text.desc
end
banner << "".ljust(80, "=")
@@ -84,7 +84,7 @@ module Shell
end
def explain_command(method_name)
- help = self.all_help_descriptions.find { |h| h.cmd.to_s == method_name.to_s }
+ help = all_help_descriptions.find { |h| h.cmd.to_s == method_name.to_s }
if help
puts ""
puts "Command: #{method_name}"
@@ -125,7 +125,7 @@ module Shell
@explain = explain_text
end
- def subcommands(subcommand_help={})
+ def subcommands(subcommand_help = {})
@subcommand_help = subcommand_help
end
@@ -159,7 +159,7 @@ module Shell
module Symbol
def on_off_to_bool
- self.to_s.on_off_to_bool
+ to_s.on_off_to_bool
end
end
@@ -196,8 +196,8 @@ module Shell
chef-shell commands. When called with an argument COMMAND, +help+
prints a detailed explanation of the command if available, or the
description if no explanation is available.
-E
- def help(commmand=nil)
+ E
+ def help(commmand = nil)
if commmand
explain_command(commmand)
else
@@ -209,10 +209,10 @@ E
desc "prints information about chef"
def version
- puts "This is the chef-shell.\n" +
- " Chef Version: #{::Chef::VERSION}\n" +
- " http://www.chef.io/\n" +
- " http://docs.chef.io/"
+ puts "This is the chef-shell.\n" +
+ " Chef Version: #{::Chef::VERSION}\n" +
+ " https://www.chef.io/\n" +
+ " https://docs.chef.io/"
:ucanhaz_automation
end
alias :shell :version
@@ -295,7 +295,7 @@ E
end
desc "pretty print the node's attributes"
- def ohai(key=nil)
+ def ohai(key = nil)
pp(key ? node.attribute[key] : node.attribute)
end
end
@@ -314,7 +314,7 @@ E
1. Looks for an EDITOR set by Shell.editor = "EDITOR"
2. Looks for an EDITOR configured in your chef-shell config file
3. Uses the value of the EDITOR environment variable
-E
+ E
def edit(object)
unless Shell.editor
puts "Please set your editor with Shell.editor = \"vim|emacs|mate|ed\""
@@ -331,7 +331,7 @@ E
edited_data = Tempfile.open([filename, ".js"]) do |tempfile|
tempfile.sync = true
tempfile.puts Chef::JSONCompat.to_json(object)
- system("#{Shell.editor.to_s} #{tempfile.path}")
+ system("#{Shell.editor} #{tempfile.path}")
tempfile.rewind
tempfile.read
end
@@ -392,7 +392,7 @@ E
end
This will strip the admin privileges from any client named after borat.
-E
+ E
subcommands :all => "list all api clients",
:show => "load an api client by name",
:search => "search for API clients",
@@ -454,7 +454,7 @@ E
end
This will assign the attribute to every node with a FQDN matching the regex.
-E
+ E
subcommands :all => "list all nodes",
:show => "load a node by name",
:search => "search for nodes",
@@ -476,7 +476,7 @@ E
## SEE ALSO ##
See the help for +nodes+ for more information about the subcommands.
-E
+ E
subcommands :all => "list all roles",
:show => "load a role by name",
:search => "search for roles",
@@ -502,7 +502,7 @@ E
## SEE ALSO ##
See the help for +nodes+ for more information about the subcommands.
-E
+ E
subcommands :all => "list all items in the data bag",
:show => "load a data bag item by id",
:search => "search for items in the data bag",
@@ -525,7 +525,7 @@ E
## SEE ALSO ##
See the help for +nodes+ for more information about the subcommands.
-E
+ E
subcommands :all => "list all environments",
:show => "load an environment by name",
:search => "search for environments",
@@ -536,7 +536,7 @@ E
desc "A REST Client configured to authenticate with the API"
def api
- @rest = Shell::ShellREST.new(Chef::Config[:chef_server_url])
+ @rest = Chef::ServerAPI.new(Chef::Config[:chef_server_url])
end
end
diff --git a/lib/chef/shell/model_wrapper.rb b/lib/chef/shell/model_wrapper.rb
index 7ee39de7eb..8c3e456a9b 100644
--- a/lib/chef/shell/model_wrapper.rb
+++ b/lib/chef/shell/model_wrapper.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/mixin/convert_to_class_name'
-require 'chef/mixin/language'
+require "chef/mixin/convert_to_class_name"
+require "chef/mixin/language"
module Shell
class ModelWrapper
@@ -26,7 +26,7 @@ module Shell
attr_reader :model_symbol
- def initialize(model_class, symbol=nil)
+ def initialize(model_class, symbol = nil)
@model_class = model_class
@model_symbol = symbol || convert_to_snake_case(model_class.name, "Chef").to_sym
end
@@ -59,7 +59,8 @@ module Shell
alias :load :show
- def transform(what_to_transform, &block)
+ # FIXME: yard with @yield
+ def transform(what_to_transform)
if what_to_transform == :all
objects_to_transform = list_objects
else
@@ -79,8 +80,8 @@ module Shell
# paper over inconsistencies in the model classes APIs, and return the objects
# the user wanted instead of the URI=>object stuff
def list_objects
- objects = @model_class.method(:list).arity == 0? @model_class.list : @model_class.list(true)
- objects.map { |obj| Array(obj).find {|o| o.kind_of?(@model_class)} }
+ objects = @model_class.method(:list).arity == 0 ? @model_class.list : @model_class.list(true)
+ objects.map { |obj| Array(obj).find { |o| o.kind_of?(@model_class) } }
end
def format_query(query)
@@ -98,7 +99,6 @@ module Shell
@model_symbol = @databag_name = databag_name
end
-
alias :list :all
def show(item)
diff --git a/lib/chef/shell/shell_session.rb b/lib/chef/shell/shell_session.rb
index 73e6c34ebb..3034e1cf5d 100644
--- a/lib/chef/shell/shell_session.rb
+++ b/lib/chef/shell/shell_session.rb
@@ -1,8 +1,8 @@
#--
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,22 +18,22 @@
# limitations under the License.
#
-require 'chef/recipe'
-require 'chef/run_context'
-require 'chef/config'
-require 'chef/client'
-require 'chef/cookbook/cookbook_collection'
-require 'chef/cookbook_loader'
-require 'chef/run_list/run_list_expansion'
-require 'chef/formatters/base'
-require 'chef/formatters/doc'
-require 'chef/formatters/minimal'
+require "chef/recipe"
+require "chef/run_context"
+require "chef/config"
+require "chef/client"
+require "chef/cookbook/cookbook_collection"
+require "chef/cookbook_loader"
+require "chef/run_list/run_list_expansion"
+require "chef/formatters/base"
+require "chef/formatters/doc"
+require "chef/formatters/minimal"
module Shell
class ShellSession
include Singleton
- def self.session_type(type=nil)
+ def self.session_type(type = nil)
@session_type = type if type
@session_type
end
@@ -126,8 +126,8 @@ module Shell
end
def shorten_node_inspect
- def @node.inspect
- "<Chef::Node:0x#{self.object_id.to_s(16)} @name=\"#{self.name}\">"
+ def @node.inspect # rubocop:disable Lint/NestedMethodDefinition
+ "<Chef::Node:0x#{object_id.to_s(16)} @name=\"#{name}\">"
end
end
@@ -150,7 +150,7 @@ module Shell
private
def rebuild_node
- Chef::Config[:solo] = true
+ Chef::Config[:solo_legacy_mode] = true
@client = Chef::Client.new(nil, Chef::Config[:shell_config])
@client.run_ohai
@client.load_node
@@ -182,7 +182,7 @@ module Shell
def rebuild_node
# Tell the client we're chef solo so it won't try to contact the server
- Chef::Config[:solo] = true
+ Chef::Config[:solo_legacy_mode] = true
@client = Chef::Client.new(nil, Chef::Config[:shell_config])
@client.run_ohai
@client.load_node
@@ -201,7 +201,7 @@ module Shell
def rebuild_context
@run_status = Chef::RunStatus.new(@node, @events)
- Chef::Cookbook::FileVendor.fetch_from_remote(Chef::REST.new(Chef::Config[:chef_server_url]))
+ Chef::Cookbook::FileVendor.fetch_from_remote(Chef::ServerAPI.new(Chef::Config[:chef_server_url]))
cookbook_hash = @client.sync_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cookbook_hash)
@run_context = Chef::RunContext.new(node, cookbook_collection, @events)
@@ -213,7 +213,7 @@ module Shell
def rebuild_node
# Make sure the client knows this is not chef solo
- Chef::Config[:solo] = false
+ Chef::Config[:solo_legacy_mode] = false
@client = Chef::Client.new(nil, Chef::Config[:shell_config])
@client.run_ohai
@client.register
@@ -235,7 +235,7 @@ module Shell
# Run the very smallest amount of ohai we can get away with and still
# hope to have things work. Otherwise we're not very good doppelgangers
def run_ohai
- @ohai.require_plugin('os')
+ @ohai.require_plugin("os")
end
# DoppelGanger implementation of build_node. preserves as many of the node's
@@ -244,8 +244,8 @@ module Shell
Chef::Log.debug("Building node object for #{@node_name}")
@node = Chef::Node.find_or_create(node_name)
ohai_data = @ohai.data.merge(@node.automatic_attrs)
- @node.consume_external_attrs(ohai_data,nil)
- @run_list_expansion = @node.expand!('server')
+ @node.consume_external_attrs(ohai_data, nil)
+ @run_list_expansion = @node.expand!("server")
@expanded_run_list_with_versions = @run_list_expansion.recipes.with_version_constraints_strings
Chef::Log.info("Run List is [#{@node.run_list}]")
Chef::Log.info("Run List expands to [#{@expanded_run_list_with_versions.join(', ')}]")
@@ -253,7 +253,8 @@ module Shell
end
def register
- @rest = Chef::REST.new(Chef::Config[:chef_server_url], Chef::Config[:node_name], Chef::Config[:client_key])
+ @rest = Chef::ServerAPI.new(Chef::Config[:chef_server_url], :client_name => Chef::Config[:node_name],
+ :signing_key_filename => Chef::Config[:client_key])
end
end
diff --git a/lib/chef/shell_out.rb b/lib/chef/shell_out.rb
index 3febe366bd..54ff718e8e 100644
--- a/lib/chef/shell_out.rb
+++ b/lib/chef/shell_out.rb
@@ -1,11 +1,11 @@
-require 'mixlib/shellout'
+require "mixlib/shellout"
class Chef
class ShellOut < Mixlib::ShellOut
def initialize(*args)
Chef::Log.warn("Chef::ShellOut is deprecated, please use Mixlib::ShellOut")
- called_from = caller[0..3].inject("Called from:\n") {|msg, trace_line| msg << " #{trace_line}\n" }
+ called_from = caller[0..3].inject("Called from:\n") { |msg, trace_line| msg << " #{trace_line}\n" }
Chef::Log.warn(called_from)
super
end
diff --git a/lib/chef/tasks/chef_repo.rake b/lib/chef/tasks/chef_repo.rake
index 14a5bcc0c1..543bd8d864 100644
--- a/lib/chef/tasks/chef_repo.rake
+++ b/lib/chef/tasks/chef_repo.rake
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2014, Chef Software, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-TOPDIR = '.'
-require 'rake'
+TOPDIR = "."
+require "rake"
desc "By default, print deprecation notice"
task :default do
@@ -27,37 +27,37 @@ end
desc "Install the latest copy of the repository on this Chef Server"
task :install do
puts deprecation_notice
- puts 'The `install` rake task, which included the `update`, `roles`, and'
- puts '`upload_cookbooks` rake tasks is replaced by the `knife upload`'
+ puts "The `install` rake task, which included the `update`, `roles`, and"
+ puts "`upload_cookbooks` rake tasks is replaced by the `knife upload`"
puts 'sub-command. The notion of "installing" the chef-repo to the Chef'
- puts 'Server. Previously the `install` task would manage server and'
- puts 'client configuration. This will not work at all on Chef Server 11+'
- puts 'and client configuration should be managed with the `chef-client`'
- puts 'cookbook.'
+ puts "Server. Previously the `install` task would manage server and"
+ puts "client configuration. This will not work at all on Chef Server 11+"
+ puts "and client configuration should be managed with the `chef-client`"
+ puts "cookbook."
end
desc "Update your repository from source control"
task :update do
puts deprecation_notice
- puts 'The `update` rake task previously updated the chef-repo from'
- puts 'the detected version control system, either svn or git. However,'
- puts 'it has not been recommended for users for years. Most users in'
- puts 'the community use `git`, so the Subversion functionality is not'
- puts 'required, and `git pull` is sufficient for many workflows. The'
- puts 'world of git workflows is rather different now than it was when'
- puts 'this rake task was created.'
+ puts "The `update` rake task previously updated the chef-repo from"
+ puts "the detected version control system, either svn or git. However,"
+ puts "it has not been recommended for users for years. Most users in"
+ puts "the community use `git`, so the Subversion functionality is not"
+ puts "required, and `git pull` is sufficient for many workflows. The"
+ puts "world of git workflows is rather different now than it was when"
+ puts "this rake task was created."
end
desc "Create a new cookbook (with COOKBOOK=name, optional CB_PREFIX=site-)"
task :new_cookbook do
- cb = ENV['COOKBOOK'] || 'my_cookbook_name'
+ cb = ENV["COOKBOOK"] || "my_cookbook_name"
puts deprecation_notice
- puts 'The `new_cookbook` rake task is replaced by the ChefDK cookbook'
- puts 'generator. To generate a new cookbook run:'
+ puts "The `new_cookbook` rake task is replaced by the ChefDK cookbook"
+ puts "generator. To generate a new cookbook run:"
puts
puts "chef generate cookbook #{ENV['COOKBOOK']}"
puts
- puts 'Or, if you are not using ChefDK, use `knife cookbook create`:'
+ puts "Or, if you are not using ChefDK, use `knife cookbook create`:"
puts
puts "knife cookbook create #{ENV['COOKBOOK']}"
end
@@ -65,46 +65,46 @@ end
desc "Create a new self-signed SSL certificate for FQDN=foo.example.com"
task :ssl_cert do
puts deprecation_notice
- puts 'The `ssl_cert` rake task is superseded by using the CHEF-maintained'
+ puts "The `ssl_cert` rake task is superseded by using the CHEF-maintained"
puts '`openssl` cookbook\'s `openssl_x509` resource which can generate'
- puts 'self-signed certificate chains as convergent resources.'
+ puts "self-signed certificate chains as convergent resources."
puts
- puts 'https://supermarket.getchef.com/cookbooks/openssl'
+ puts "https://supermarket.getchef.com/cookbooks/openssl"
end
desc "Build cookbook metadata.json from metadata.rb"
task :metadata do
puts deprecation_notice
- puts 'The `metadata` rake task is not recommended. Cookbook'
- puts '`metadata.json` is automatically generated from `metadata.rb`'
- puts 'by `knife` when uploading cookbooks to the Chef Server.'
+ puts "The `metadata` rake task is not recommended. Cookbook"
+ puts "`metadata.json` is automatically generated from `metadata.rb`"
+ puts "by `knife` when uploading cookbooks to the Chef Server."
end
desc "Update roles"
task :roles do
puts deprecation_notice
- puts 'The `roles` rake task is not recommended. If you are using Ruby'
- puts 'role files (roles/*.rb), you can upload them all with:'
+ puts "The `roles` rake task is not recommended. If you are using Ruby"
+ puts "role files (roles/*.rb), you can upload them all with:"
puts
- puts 'knife role from file roles/*'
+ puts "knife role from file roles/*"
puts
- puts 'If you are using JSON role files (roles/*.json), you can upload'
- puts 'them all with:'
+ puts "If you are using JSON role files (roles/*.json), you can upload"
+ puts "them all with:"
puts
- puts 'knife upload roles/*.json'
+ puts "knife upload roles/*.json"
end
desc "Update a specific role"
task :role do
puts deprecation_notice
- puts 'The `role` rake task is not recommended. If you are using Ruby'
- puts 'role files, you can upload a single role with:'
+ puts "The `role` rake task is not recommended. If you are using Ruby"
+ puts "role files, you can upload a single role with:"
puts
- puts 'knife role from file rolename.rb'
+ puts "knife role from file rolename.rb"
puts
- puts 'If you are using JSON role files, you can upload a single role with'
+ puts "If you are using JSON role files, you can upload a single role with"
puts
- puts 'knife upload roles/rolename.json'
+ puts "knife upload roles/rolename.json"
end
desc "Upload all cookbooks"
@@ -122,18 +122,18 @@ end
desc "Test all cookbooks"
task :test_cookbooks do
puts deprecation_notice
- puts 'The `test_cookbooks` rake task is no longer recommended. Previously'
- puts 'it only performed a syntax check, and did no other kind of testing,'
- puts 'and the Chef Community has a rich ecosystem of testing tools for'
- puts 'various purposes:'
+ puts "The `test_cookbooks` rake task is no longer recommended. Previously"
+ puts "it only performed a syntax check, and did no other kind of testing,"
+ puts "and the Chef Community has a rich ecosystem of testing tools for"
+ puts "various purposes:"
puts
- puts '- knife cookbook test will perform a syntax check, as this task did'
- puts ' before.'
- puts '- rubocop and foodcritic will perform lint checking for Ruby and'
- puts ' Chef cookbook style according to community standards.'
- puts '- ChefSpec will perform unit testing'
- puts '- Test Kitchen will perform convergence and post-convergence'
- puts ' testing on virtual machines.'
+ puts "- knife cookbook test will perform a syntax check, as this task did"
+ puts " before."
+ puts "- rubocop and foodcritic will perform lint checking for Ruby and"
+ puts " Chef cookbook style according to community standards."
+ puts "- ChefSpec will perform unit testing"
+ puts "- Test Kitchen will perform convergence and post-convergence"
+ puts " testing on virtual machines."
end
desc "Test a single cookbook"
@@ -143,19 +143,19 @@ namespace :databag do
desc "Upload a single databag"
task :upload do
puts deprecation_notice
- puts 'The `data_bags:upload` task is not recommended. You should use'
- puts 'the `knife upload` sub-command for uploading data bag items.'
+ puts "The `data_bags:upload` task is not recommended. You should use"
+ puts "the `knife upload` sub-command for uploading data bag items."
puts
- puts 'knife upload data_bags/bagname/itemname.json'
+ puts "knife upload data_bags/bagname/itemname.json"
end
desc "Upload all databags"
task :upload_all do
puts deprecation_notice
- puts 'The `data_bags:upload_all` task is not recommended. You should'
- puts 'use the `knife upload` sub-command for uploading data bag items.'
+ puts "The `data_bags:upload_all` task is not recommended. You should"
+ puts "use the `knife upload` sub-command for uploading data bag items."
puts
- puts 'knife upload data_bags/*'
+ puts "knife upload data_bags/*"
end
desc "Create a databag"
@@ -172,23 +172,22 @@ namespace :databag do
end
def deprecation_notice
- %Q[*************************************************
+ %Q{*************************************************
NOTICE: Chef Repository Rake Tasks Are Deprecated
*************************************************
-]
-
+}
end
def deprecated_cookbook_upload
- %Q[
+ %Q{
The `upload_cookbook` and `upload_cookbooks` rake tasks are not
recommended. These tasks are replaced by other, better workflow
tools, such as `knife cookbook upload`, `knife upload`, or `berks`
-]
+}
end
def deprecated_data_bag_creation
- %Q[
+ %Q{
The `data_bags:create` and `data_bags:create_item` tasks are not
recommended. You should create data bag items as JSON files in the data_bags
directory, with a sub-directory for each bag, and use `knife upload` to
@@ -197,5 +196,5 @@ upload them. For example, if you have a data bags named `users`, with
./data_bags/users/finn.json
./data-bags/users/jake.json
-]
+}
end
diff --git a/lib/chef/user.rb b/lib/chef/user.rb
index 31ebeda86f..fffaa106f8 100644
--- a/lib/chef/user.rb
+++ b/lib/chef/user.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (steve@opscode.com)
-# Copyright:: Copyright 2012 Opscode, Inc.
+# Author:: Steven Danna (steve@chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,24 +15,24 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/mash'
-require 'chef/json_compat'
-require 'chef/search/query'
-require 'chef/server_api'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/search/query"
+require "chef/server_api"
# TODO
# DEPRECATION NOTE
# This class will be replaced by Chef::UserV1 in Chef 13. It is the code to support the User object
-# corrosponding to the Open Source Chef Server 11 and only still exists to support
+# corresponding to the Open Source Chef Server 11 and only still exists to support
# users still on OSC 11.
#
# Chef::UserV1 now supports Chef Server 12 and will be moved to this namespace in Chef 13.
#
# New development should occur in Chef::UserV1.
-# This file and corrosponding osc_user knife files
+# This file and corresponding osc_user knife files
# should be removed once client support for Open Source Chef Server 11 expires.
class Chef
class User
@@ -41,7 +41,7 @@ class Chef
include Chef::Mixin::ParamsValidate
def initialize
- @name = ''
+ @name = ""
@public_key = nil
@private_key = nil
@password = nil
@@ -49,30 +49,30 @@ class Chef
end
def chef_rest_v0
- @chef_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0"})
+ @chef_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" })
end
- def name(arg=nil)
+ def name(arg = nil)
set_or_return(:name, arg,
:regex => /^[a-z0-9\-_]+$/)
end
- def admin(arg=nil)
+ def admin(arg = nil)
set_or_return(:admin,
arg, :kind_of => [TrueClass, FalseClass])
end
- def public_key(arg=nil)
+ def public_key(arg = nil)
set_or_return(:public_key,
arg, :kind_of => String)
end
- def private_key(arg=nil)
+ def private_key(arg = nil)
set_or_return(:private_key,
arg, :kind_of => String)
end
- def password(arg=nil)
+ def password(arg = nil)
set_or_return(:password,
arg, :kind_of => String)
end
@@ -81,7 +81,7 @@ class Chef
result = {
"name" => @name,
"public_key" => @public_key,
- "admin" => @admin
+ "admin" => @admin,
}
result["private_key"] = @private_key if @private_key
result["password"] = @password if @password
@@ -97,29 +97,27 @@ class Chef
end
def create
- payload = {:name => self.name, :admin => self.admin, :password => self.password }
+ payload = { :name => name, :admin => admin, :password => password }
payload[:public_key] = public_key if public_key
new_user = chef_rest_v0.post("users", payload)
- Chef::User.from_hash(self.to_hash.merge(new_user))
+ Chef::User.from_hash(to_hash.merge(new_user))
end
- def update(new_key=false)
- payload = {:name => name, :admin => admin}
+ def update(new_key = false)
+ payload = { :name => name, :admin => admin }
payload[:private_key] = new_key if new_key
payload[:password] = password if password
updated_user = chef_rest_v0.put("users/#{name}", payload)
- Chef::User.from_hash(self.to_hash.merge(updated_user))
+ Chef::User.from_hash(to_hash.merge(updated_user))
end
- def save(new_key=false)
- begin
- create
- rescue Net::HTTPServerException => e
- if e.response.code == "409"
- update(new_key)
- else
- raise e
- end
+ def save(new_key = false)
+ create
+ rescue Net::HTTPServerException => e
+ if e.response.code == "409"
+ update(new_key)
+ else
+ raise e
end
end
@@ -135,18 +133,18 @@ class Chef
def inspect
"Chef::User name:'#{name}' admin:'#{admin.inspect}'" +
- "public_key:'#{public_key}' private_key:#{private_key}"
+ "public_key:'#{public_key}' private_key:#{private_key}"
end
# Class Methods
def self.from_hash(user_hash)
user = Chef::User.new
- user.name user_hash['name']
- user.private_key user_hash['private_key'] if user_hash.key?('private_key')
- user.password user_hash['password'] if user_hash.key?('password')
- user.public_key user_hash['public_key']
- user.admin user_hash['admin']
+ user.name user_hash["name"]
+ user.private_key user_hash["private_key"] if user_hash.key?("private_key")
+ user.password user_hash["password"] if user_hash.key?("password")
+ user.public_key user_hash["public_key"]
+ user.admin user_hash["admin"]
user
end
@@ -154,17 +152,18 @@ class Chef
Chef::User.from_hash(Chef::JSONCompat.from_json(json))
end
- class << self
- alias_method :json_create, :from_json
+ def self.json_create(json)
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::User#from_json or Chef::User#load.")
+ Chef::User.from_json(json)
end
- def self.list(inflate=false)
- response = Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0"}).get('users')
+ def self.list(inflate = false)
+ response = Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" }).get("users")
users = if response.is_a?(Array)
- transform_ohc_list_response(response) # OHC/OPC
- else
- response # OSC
- end
+ transform_ohc_list_response(response) # OHC/OPC
+ else
+ response # OSC
+ end
if inflate
users.inject({}) do |user_map, (name, _url)|
user_map[name] = Chef::User.load(name)
@@ -176,7 +175,7 @@ class Chef
end
def self.load(name)
- response = Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0"}).get("users/#{name}")
+ response = Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" }).get("users/#{name}")
Chef::User.from_hash(response)
end
@@ -187,7 +186,7 @@ class Chef
def self.transform_ohc_list_response(response)
new_response = Hash.new
response.each do |u|
- name = u['user']['username']
+ name = u["user"]["username"]
new_response[name] = Chef::Config[:chef_server_url] + "/users/#{name}"
end
new_response
diff --git a/lib/chef/user_v1.rb b/lib/chef/user_v1.rb
index 31cb0576a2..b408bbe667 100644
--- a/lib/chef/user_v1.rb
+++ b/lib/chef/user_v1.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (steve@opscode.com)
-# Copyright:: Copyright 2012 Opscode, Inc.
+# Author:: Steven Danna (steve@chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,15 +15,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/mash'
-require 'chef/json_compat'
-require 'chef/search/query'
-require 'chef/mixin/api_version_request_handling'
-require 'chef/exceptions'
-require 'chef/server_api'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/search/query"
+require "chef/mixin/api_version_request_handling"
+require "chef/exceptions"
+require "chef/server_api"
# OSC 11 BACKWARDS COMPATIBILITY NOTE (remove after OSC 11 support ends)
#
@@ -39,7 +39,7 @@ class Chef
include Chef::Mixin::ParamsValidate
include Chef::Mixin::ApiVersionRequestHandling
- SUPPORTED_API_VERSIONS = [0,1]
+ SUPPORTED_API_VERSIONS = [0, 1]
def initialize
@username = nil
@@ -52,75 +52,69 @@ class Chef
@public_key = nil
@private_key = nil
@create_key = nil
- @password = nil
end
def chef_root_rest_v0
- @chef_root_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], {:api_version => "0"})
+ @chef_root_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], { :api_version => "0" })
end
def chef_root_rest_v1
- @chef_root_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], {:api_version => "1"})
+ @chef_root_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], { :api_version => "1" })
end
- def username(arg=nil)
+ def username(arg = nil)
set_or_return(:username, arg,
:regex => /^[a-z0-9\-_]+$/)
end
- def display_name(arg=nil)
+ def display_name(arg = nil)
set_or_return(:display_name,
arg, :kind_of => String)
end
- def first_name(arg=nil)
+ def first_name(arg = nil)
set_or_return(:first_name,
arg, :kind_of => String)
end
- def middle_name(arg=nil)
+ def middle_name(arg = nil)
set_or_return(:middle_name,
arg, :kind_of => String)
end
- def last_name(arg=nil)
+ def last_name(arg = nil)
set_or_return(:last_name,
arg, :kind_of => String)
end
- def email(arg=nil)
+ def email(arg = nil)
set_or_return(:email,
arg, :kind_of => String)
end
- def password(arg=nil)
- set_or_return(:password,
- arg, :kind_of => String)
- end
-
- def create_key(arg=nil)
+ def create_key(arg = nil)
set_or_return(:create_key, arg,
:kind_of => [TrueClass, FalseClass])
end
- def public_key(arg=nil)
+ def public_key(arg = nil)
set_or_return(:public_key,
arg, :kind_of => String)
end
- def private_key(arg=nil)
+ def private_key(arg = nil)
set_or_return(:private_key,
arg, :kind_of => String)
end
- def password(arg=nil)
+ def password(arg = nil)
set_or_return(:password,
arg, :kind_of => String)
end
def to_hash
result = {
- "username" => @username
+ "username" => @username,
}
result["display_name"] = @display_name unless @display_name.nil?
result["first_name"] = @first_name unless @first_name.nil?
@@ -140,7 +134,7 @@ class Chef
def destroy
# will default to the current API version (Chef::Authenticator::DEFAULT_SERVER_API_VERSION)
- Chef::REST.new(Chef::Config[:chef_server_url]).delete("users/#{@username}")
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url]).delete("users/#{@username}")
end
def create
@@ -152,7 +146,7 @@ class Chef
:first_name => @first_name,
:last_name => @last_name,
:email => @email,
- :password => @password
+ :password => @password,
}
payload[:public_key] = @public_key unless @public_key.nil?
payload[:create_key] = @create_key unless @create_key.nil?
@@ -161,12 +155,12 @@ class Chef
new_user = chef_root_rest_v1.post("users", payload)
# get the private_key out of the chef_key hash if it exists
- if new_user['chef_key']
- if new_user['chef_key']['private_key']
- new_user['private_key'] = new_user['chef_key']['private_key']
+ if new_user["chef_key"]
+ if new_user["chef_key"]["private_key"]
+ new_user["private_key"] = new_user["chef_key"]["private_key"]
end
- new_user['public_key'] = new_user['chef_key']['public_key']
- new_user.delete('chef_key')
+ new_user["public_key"] = new_user["chef_key"]["public_key"]
+ new_user.delete("chef_key")
end
rescue Net::HTTPServerException => e
# rescue API V0 if 406 and the server supports V0
@@ -178,7 +172,7 @@ class Chef
:first_name => @first_name,
:last_name => @last_name,
:email => @email,
- :password => @password
+ :password => @password,
}
payload[:middle_name] = @middle_name unless @middle_name.nil?
payload[:public_key] = @public_key unless @public_key.nil?
@@ -186,12 +180,12 @@ class Chef
new_user = chef_root_rest_v0.post("users", payload)
end
- Chef::UserV1.from_hash(self.to_hash.merge(new_user))
+ Chef::UserV1.from_hash(to_hash.merge(new_user))
end
- def update(new_key=false)
+ def update(new_key = false)
begin
- payload = {:username => username}
+ payload = { :username => username }
payload[:display_name] = display_name unless display_name.nil?
payload[:first_name] = first_name unless first_name.nil?
payload[:middle_name] = middle_name unless middle_name.nil?
@@ -219,25 +213,23 @@ class Chef
end
updated_user = chef_root_rest_v0.put("users/#{username}", payload)
end
- Chef::UserV1.from_hash(self.to_hash.merge(updated_user))
+ Chef::UserV1.from_hash(to_hash.merge(updated_user))
end
- def save(new_key=false)
- begin
- create
- rescue Net::HTTPServerException => e
- if e.response.code == "409"
- update(new_key)
- else
- raise e
- end
+ def save(new_key = false)
+ create
+ rescue Net::HTTPServerException => e
+ if e.response.code == "409"
+ update(new_key)
+ else
+ raise e
end
end
# Note: remove after API v0 no longer supported by client (and knife command).
def reregister
begin
- payload = self.to_hash.merge({"private_key" => true})
+ payload = to_hash.merge({ "private_key" => true })
reregistered_self = chef_root_rest_v0.put("users/#{username}", payload)
private_key(reregistered_self["private_key"])
# only V0 supported for reregister
@@ -265,16 +257,16 @@ class Chef
def self.from_hash(user_hash)
user = Chef::UserV1.new
- user.username user_hash['username']
- user.display_name user_hash['display_name'] if user_hash.key?('display_name')
- user.first_name user_hash['first_name'] if user_hash.key?('first_name')
- user.middle_name user_hash['middle_name'] if user_hash.key?('middle_name')
- user.last_name user_hash['last_name'] if user_hash.key?('last_name')
- user.email user_hash['email'] if user_hash.key?('email')
- user.password user_hash['password'] if user_hash.key?('password')
- user.public_key user_hash['public_key'] if user_hash.key?('public_key')
- user.private_key user_hash['private_key'] if user_hash.key?('private_key')
- user.create_key user_hash['create_key'] if user_hash.key?('create_key')
+ user.username user_hash["username"]
+ user.display_name user_hash["display_name"] if user_hash.key?("display_name")
+ user.first_name user_hash["first_name"] if user_hash.key?("first_name")
+ user.middle_name user_hash["middle_name"] if user_hash.key?("middle_name")
+ user.last_name user_hash["last_name"] if user_hash.key?("last_name")
+ user.email user_hash["email"] if user_hash.key?("email")
+ user.password user_hash["password"] if user_hash.key?("password")
+ user.public_key user_hash["public_key"] if user_hash.key?("public_key")
+ user.private_key user_hash["private_key"] if user_hash.key?("private_key")
+ user.create_key user_hash["create_key"] if user_hash.key?("create_key")
user
end
@@ -282,12 +274,13 @@ class Chef
Chef::UserV1.from_hash(Chef::JSONCompat.from_json(json))
end
- class << self
- alias_method :json_create, :from_json
+ def self.json_create(json)
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::UserV1#from_json or Chef::UserV1#load.")
+ Chef::UserV1.from_json(json)
end
- def self.list(inflate=false)
- response = Chef::REST.new(Chef::Config[:chef_server_url]).get('users')
+ def self.list(inflate = false)
+ response = Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("users")
users = if response.is_a?(Array)
# EC 11 / CS 12 V0, V1
# GET /organizations/<org>/users
@@ -312,7 +305,7 @@ class Chef
def self.load(username)
# will default to the current API version (Chef::Authenticator::DEFAULT_SERVER_API_VERSION)
- response = Chef::REST.new(Chef::Config[:chef_server_url]).get("users/#{username}")
+ response = Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("users/#{username}")
Chef::UserV1.from_hash(response)
end
@@ -323,7 +316,7 @@ class Chef
def self.transform_list_response(response)
new_response = Hash.new
response.each do |u|
- name = u['user']['username']
+ name = u["user"]["username"]
new_response[name] = Chef::Config[:chef_server_url] + "/users/#{name}"
end
new_response
diff --git a/lib/chef/util/backup.rb b/lib/chef/util/backup.rb
index 6c95cedad7..8bf2b3f25b 100644
--- a/lib/chef/util/backup.rb
+++ b/lib/chef/util/backup.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/util/path_helper'
+require "chef/util/path_helper"
class Chef
class Util
@@ -49,7 +49,7 @@ class Chef
def backup_filename
@backup_filename ||= begin
time = Time.now
- nanoseconds = sprintf("%6f", time.to_f).split('.')[1]
+ nanoseconds = sprintf("%6f", time.to_f).split(".")[1]
savetime = time.strftime("%Y%m%d%H%M%S.#{nanoseconds}")
backup_filename = "#{path}.chef-#{savetime}"
backup_filename = backup_filename.sub(/^([A-Za-z]:)/, "") #strip drive letter on Windows
@@ -83,11 +83,11 @@ class Chef
fn = Regexp.escape(::File.basename(path))
Dir.entries(::File.dirname(backup_path)).select do |f|
!!(f =~ /\A#{fn}.chef-[0-9.]*\B/)
- end.map {|f| ::File.join(::File.dirname(backup_path), f)}
+ end.map { |f| ::File.join(::File.dirname(backup_path), f) }
end
def sorted_backup_files
- unsorted_backup_files.sort { |a,b| b <=> a }
+ unsorted_backup_files.sort { |a, b| b <=> a }
end
end
end
diff --git a/lib/chef/util/diff.rb b/lib/chef/util/diff.rb
index b8336b5135..61bc2bf666 100644
--- a/lib/chef/util/diff.rb
+++ b/lib/chef/util/diff.rb
@@ -1,5 +1,5 @@
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# Some portions of this file are derived from material in the diff-lcs
# project licensed under the terms of the MIT license, provided below.
#
-# Copyright:: Copyright (c) 2004-2013 Austin Ziegler
+# Copyright:: Copyright 2004-2016, Austin Ziegler
# License:: MIT
#
# Permission is hereby granted, free of charge, to any person
@@ -40,8 +40,8 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OF OTHER DEALINGS IN THE
# SOFTWARE.
-require 'diff/lcs'
-require 'diff/lcs/hunk'
+require "diff/lcs"
+require "diff/lcs/hunk"
class Chef
class Util
@@ -97,9 +97,9 @@ class Chef
return "No differences encountered\n" if diff_data.empty?
# write diff header (standard unified format)
- ft = File.stat(old_file).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.%N %z')
+ ft = File.stat(old_file).mtime.localtime.strftime("%Y-%m-%d %H:%M:%S.%N %z")
diff_str << "--- #{old_file}\t#{ft}\n"
- ft = File.stat(new_file).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.%N %z')
+ ft = File.stat(new_file).mtime.localtime.strftime("%Y-%m-%d %H:%M:%S.%N %z")
diff_str << "+++ #{new_file}\t#{ft}\n"
# loop over diff hunks. if a hunk overlaps with the last hunk,
@@ -117,7 +117,7 @@ class Chef
end
end
diff_str << old_hunk.diff(:unified) << "\n"
- return diff_str
+ diff_str
end
private
@@ -176,7 +176,7 @@ class Chef
end
def encode_diff_for_json(diff_str)
- diff_str.encode!('UTF-8', :invalid => :replace, :undef => :replace, :replace => '?')
+ diff_str.encode!("UTF-8", :invalid => :replace, :undef => :replace, :replace => "?")
end
end
diff --git a/lib/chef/util/dsc/configuration_generator.rb b/lib/chef/util/dsc/configuration_generator.rb
index 0d7296eae9..8b492d483a 100644
--- a/lib/chef/util/dsc/configuration_generator.rb
+++ b/lib/chef/util/dsc/configuration_generator.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
+# Author:: Adam Edwards (<adamed@chef.io>)
#
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/util/powershell/cmdlet'
+require "chef/util/powershell/cmdlet"
class Chef::Util::DSC
class ConfigurationGenerator
@@ -27,9 +27,9 @@ class Chef::Util::DSC
def configuration_document_from_script_code(code, configuration_flags, imports, shellout_flags)
Chef::Log.debug("DSC: DSC code:\n '#{code}'")
- generated_script_path = write_document_generation_script(code, 'chef_dsc', imports)
+ generated_script_path = write_document_generation_script(code, "chef_dsc", imports)
begin
- configuration_document_from_script_path(generated_script_path, 'chef_dsc', configuration_flags, shellout_flags)
+ configuration_document_from_script_path(generated_script_path, "chef_dsc", configuration_flags, shellout_flags)
ensure
::FileUtils.rm(generated_script_path)
end
@@ -48,7 +48,7 @@ class Chef::Util::DSC
configuration_document_location = find_configuration_document(configuration_name)
if ! configuration_document_location
- raise RuntimeError, "No DSC configuration for '#{configuration_name}' was generated from supplied DSC script"
+ raise "No DSC configuration for '#{configuration_name}' was generated from supplied DSC script"
end
configuration_document = get_configuration_document(configuration_document_location)
@@ -68,11 +68,11 @@ class Chef::Util::DSC
end
def get_merged_configuration_flags!(configuration_flags, configuration_name)
- merged_configuration_flags = { :outputpath => configuration_document_directory(configuration_name) }
+ merged_configuration_flags = { :outputpath => configuration_document_directory(configuration_name) }
if configuration_flags
- configuration_flags.map do | switch, value |
+ configuration_flags.map do |switch, value|
if merged_configuration_flags.key?(switch.to_s.downcase.to_sym)
- raise ArgumentError, "The `flags` attribute for the dsc_script resource contained a command line switch :#{switch.to_s} that is disallowed."
+ raise ArgumentError, "The `flags` attribute for the dsc_script resource contained a command line switch :#{switch} that is disallowed."
end
merged_configuration_flags[switch.to_s.downcase.to_sym] = value
end
@@ -97,7 +97,7 @@ Configuration '#{configuration_name}'
def generate_import_resource_statements(imports)
if imports
imports.map do |resource_module, resources|
- if resources.length == 0 || resources.include?('*')
+ if resources.length == 0 || resources.include?("*")
"Import-DscResource -ModuleName #{resource_module}"
else
"Import-DscResource -ModuleName #{resource_module} -Name #{resources.join(',')}"
@@ -114,7 +114,7 @@ Configuration '#{configuration_name}'
def write_document_generation_script(code, configuration_name, imports)
script_path = "#{@config_directory}/chef_dsc_config.ps1"
- ::File.open(script_path, 'wt') do | script |
+ ::File.open(script_path, "wt") do |script|
script.write(configuration_code(code, configuration_name, imports))
end
script_path
@@ -122,7 +122,7 @@ Configuration '#{configuration_name}'
def find_configuration_document(configuration_name)
document_directory = configuration_document_directory(configuration_name)
- document_file_name = ::Dir.entries(document_directory).find { | path | path =~ /.*.mof/ }
+ document_file_name = ::Dir.entries(document_directory).find { |path| path =~ /.*.mof/ }
::File.join(document_directory, document_file_name) if document_file_name
end
@@ -131,7 +131,7 @@ Configuration '#{configuration_name}'
end
def get_configuration_document(document_path)
- ::File.open(document_path, 'rb') do | file |
+ ::File.open(document_path, "rb") do |file|
file.read
end
end
diff --git a/lib/chef/util/dsc/lcm_output_parser.rb b/lib/chef/util/dsc/lcm_output_parser.rb
index 754fde3e8b..9473ca8a86 100644
--- a/lib/chef/util/dsc/lcm_output_parser.rb
+++ b/lib/chef/util/dsc/lcm_output_parser.rb
@@ -1,7 +1,7 @@
#
-# Author:: Jay Mundrawala (<jdm@getchef.com>)
+# Author:: Jay Mundrawala (<jdm@chef.io>)
#
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/util/dsc/resource_info'
-require 'chef/exceptions'
+require "chef/log"
+require "chef/util/dsc/resource_info"
+require "chef/exceptions"
class Chef
class Util
@@ -73,13 +73,13 @@ class Chef
if current_resource[:name]
resources.push(current_resource)
end
- current_resource = {:name => info}
+ current_resource = { :name => info }
else
Chef::Log.debug("Ignoring op_action #{op_action}: Read line #{line}")
end
when :end
# Make sure we log the last line
- if current_resource[:context] == :logging and info.include? current_resource[:name]
+ if current_resource[:context] == :logging && info.include?(current_resource[:name])
current_resource[:logs].push(info)
end
current_resource[:context] = nil
@@ -108,8 +108,8 @@ class Chef
# If the line looks like
# What If: [machinename]: LCM: [op_action op_type] message
# extract op_action, op_type, and message
- operation, info = match.captures
- op_action, op_type = operation.strip.split(' ').map {|m| m.downcase.to_sym}
+ operation, info = match.captures
+ op_action, op_type = operation.strip.split(" ").map { |m| m.downcase.to_sym }
else
op_action = op_type = :info
if match = line.match(/^.*?:.*?: \s+(.*)/)
@@ -119,7 +119,7 @@ class Chef
end
end
info.strip! # Because this was formatted for humans
- return [op_action, op_type, info]
+ [op_action, op_type, info]
end
private_class_method :parse_line
diff --git a/lib/chef/util/dsc/local_configuration_manager.rb b/lib/chef/util/dsc/local_configuration_manager.rb
index f8398341e5..d837a16185 100644
--- a/lib/chef/util/dsc/local_configuration_manager.rb
+++ b/lib/chef/util/dsc/local_configuration_manager.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
+# Author:: Adam Edwards (<adamed@chef.io>)
#
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/util/powershell/cmdlet'
-require 'chef/util/dsc/lcm_output_parser'
+require "chef/util/powershell/cmdlet"
+require "chef/util/dsc/lcm_output_parser"
class Chef::Util::DSC
class LocalConfigurationManager
@@ -47,7 +47,7 @@ class Chef::Util::DSC
def run_configuration_cmdlet(configuration_document, apply_configuration, shellout_flags)
Chef::Log.debug("DSC: Calling DSC Local Config Manager to #{apply_configuration ? "set" : "test"} configuration document.")
- test_only_parameters = ! apply_configuration ? '-whatif; if (! $?) { exit 1 }' : ''
+ test_only_parameters = ! apply_configuration ? "-whatif; if (! $?) { exit 1 }" : ""
start_operation_timing
command_code = lcm_command_code(@configuration_path, test_only_parameters)
@@ -74,23 +74,23 @@ class Chef::Util::DSC
def lcm_command_code(configuration_path, test_only_parameters)
<<-EOH
-$ProgressPreference = 'SilentlyContinue';start-dscconfiguration -path #{@configuration_path} -wait -erroraction 'continue' -force #{test_only_parameters}
+$ProgressPreference = 'SilentlyContinue';start-dscconfiguration -path #{@configuration_path} -wait -erroraction 'stop' -force #{test_only_parameters}
EOH
end
def log_what_if_exception(what_if_exception_output)
if whatif_not_supported?(what_if_exception_output)
# LCM returns an error if any of the resources do not support the opptional What-If
- Chef::Log::warn("Received error while testing configuration due to resource not supporting 'WhatIf'")
+ Chef::Log.warn("Received error while testing configuration due to resource not supporting 'WhatIf'")
elsif dsc_module_import_failure?(what_if_exception_output)
- Chef::Log::warn("Received error while testing configuration due to a module for an imported resource possibly not being fully installed:\n#{what_if_exception_output.gsub(/\s+/, ' ')}")
+ Chef::Log.warn("Received error while testing configuration due to a module for an imported resource possibly not being fully installed:\n#{what_if_exception_output.gsub(/\s+/, ' ')}")
else
- Chef::Log::warn("Received error while testing configuration:\n#{what_if_exception_output.gsub(/\s+/, ' ')}")
+ Chef::Log.warn("Received error while testing configuration:\n#{what_if_exception_output.gsub(/\s+/, ' ')}")
end
end
def whatif_not_supported?(what_if_exception_output)
- !! (what_if_exception_output.gsub(/[\r\n]+/, '').gsub(/\s+/, ' ') =~ /A parameter cannot be found that matches parameter name 'Whatif'/i)
+ !! (what_if_exception_output.gsub(/[\r\n]+/, "").gsub(/\s+/, " ") =~ /A parameter cannot be found that matches parameter name 'Whatif'/i)
end
def dsc_module_import_failure?(what_if_output)
@@ -102,16 +102,16 @@ EOH
def configuration_update_required?(what_if_output)
Chef::Log.debug("DSC: DSC returned the following '-whatif' output from test operation:\n#{what_if_output}")
begin
- Parser::parse(what_if_output)
+ Parser.parse(what_if_output)
rescue Chef::Exceptions::LCMParser => e
- Chef::Log::warn("Could not parse LCM output: #{e}")
- [Chef::Util::DSC::ResourceInfo.new('Unknown DSC Resources', true, ['Unknown changes because LCM output was not parsable.'])]
+ Chef::Log.warn("Could not parse LCM output: #{e}")
+ [Chef::Util::DSC::ResourceInfo.new("Unknown DSC Resources", true, ["Unknown changes because LCM output was not parsable."])]
end
end
def save_configuration_document(configuration_document)
::FileUtils.mkdir_p(@configuration_path)
- ::File.open(configuration_document_path, 'wb') do | file |
+ ::File.open(configuration_document_path, "wb") do |file|
file.write(configuration_document)
end
end
@@ -121,7 +121,7 @@ EOH
end
def configuration_document_path
- File.join(@configuration_path,'..mof')
+ File.join(@configuration_path, "..mof")
end
def clear_execution_time
diff --git a/lib/chef/util/dsc/resource_info.rb b/lib/chef/util/dsc/resource_info.rb
index 4a32451721..d6dfcff59a 100644
--- a/lib/chef/util/dsc/resource_info.rb
+++ b/lib/chef/util/dsc/resource_info.rb
@@ -2,25 +2,25 @@
class Chef
class Util
class DSC
- class ResourceInfo
- # The name is the text following [Start Set]
- attr_reader :name
+ class ResourceInfo
+ # The name is the text following [Start Set]
+ attr_reader :name
- # A list of all log messages between [Start Set] and [End Set].
- # Each line is an element in the list.
- attr_reader :change_log
+ # A list of all log messages between [Start Set] and [End Set].
+ # Each line is an element in the list.
+ attr_reader :change_log
- def initialize(name, sets, change_log)
- @name = name
- @sets = sets
- @change_log = change_log || []
- end
+ def initialize(name, sets, change_log)
+ @name = name
+ @sets = sets
+ @change_log = change_log || []
+ end
- # Does this resource change the state of the system?
- def changes_state?
- @sets
- end
+ # Does this resource change the state of the system?
+ def changes_state?
+ @sets
end
+ end
end
end
end
diff --git a/lib/chef/util/dsc/resource_store.rb b/lib/chef/util/dsc/resource_store.rb
index fdcecc2b3c..43b7d1bdf9 100644
--- a/lib/chef/util/dsc/resource_store.rb
+++ b/lib/chef/util/dsc/resource_store.rb
@@ -1,7 +1,7 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,95 +16,94 @@
# limitations under the License.
#
-require 'chef/util/powershell/cmdlet'
-require 'chef/util/powershell/cmdlet_result'
-require 'chef/exceptions'
+require "chef/util/powershell/cmdlet"
+require "chef/util/powershell/cmdlet_result"
+require "chef/exceptions"
class Chef
-class Util
-class DSC
- class ResourceStore
+ class Util
+ class DSC
+ class ResourceStore
- def self.instance
- @@instance ||= ResourceStore.new.tap do |store|
- store.send(:populate_cache)
- end
- end
+ def self.instance
+ @@instance ||= ResourceStore.new.tap do |store|
+ store.send(:populate_cache)
+ end
+ end
- def resources
- @resources ||= []
- end
+ def resources
+ @resources ||= []
+ end
- def find(name, module_name=nil)
- found = find_resources(name, module_name, resources)
+ def find(name, module_name = nil)
+ found = find_resources(name, module_name, resources)
- # We don't have it, query for the resource...it might
- # have been added since we last queried
- if found.length == 0
- rs = query_resource(name)
- add_resources(rs)
- found = find_resources(name, module_name, rs)
- end
+ # We don't have it, query for the resource...it might
+ # have been added since we last queried
+ if found.length == 0
+ rs = query_resource(name)
+ add_resources(rs)
+ found = find_resources(name, module_name, rs)
+ end
- found
- end
-
- private
+ found
+ end
- def add_resource(new_r)
- count = resources.count do |r|
- r['ResourceType'].casecmp(new_r['ResourceType']) == 0
- end
- if count == 0
- resources << new_r
- end
- end
+ private
- def add_resources(rs)
- rs.each do |r|
- add_resource(r)
- end
- end
+ def add_resource(new_r)
+ count = resources.count do |r|
+ r["ResourceType"].casecmp(new_r["ResourceType"]) == 0
+ end
+ if count == 0
+ resources << new_r
+ end
+ end
- def populate_cache
- @resources = query_resources
- end
+ def add_resources(rs)
+ rs.each do |r|
+ add_resource(r)
+ end
+ end
- def find_resources(name, module_name, rs)
- found = rs.find_all do |r|
- name_matches = r['Name'].casecmp(name) == 0
- if name_matches
- module_name == nil || (r['Module'] and r['Module']['Name'].casecmp(module_name) == 0)
- else
- false
+ def populate_cache
+ @resources = query_resources
end
- end
- end
+ def find_resources(name, module_name, rs)
+ found = rs.find_all do |r|
+ name_matches = r["Name"].casecmp(name) == 0
+ if name_matches
+ module_name.nil? || (r["Module"] && r["Module"]["Name"].casecmp(module_name) == 0)
+ else
+ false
+ end
+ end
+ end
- # Returns a list of dsc resources
- def query_resources
- cmdlet = Chef::Util::Powershell::Cmdlet.new(nil, 'get-dscresource',
- :object)
- result = cmdlet.run
- result.return_value
- end
+ # Returns a list of dsc resources
+ def query_resources
+ cmdlet = Chef::Util::Powershell::Cmdlet.new(nil, "get-dscresource",
+ :object)
+ result = cmdlet.run
+ result.return_value
+ end
- # Returns a list of dsc resources matching the provided name
- def query_resource(resource_name)
- cmdlet = Chef::Util::Powershell::Cmdlet.new(nil, "get-dscresource #{resource_name}",
- :object)
- result = cmdlet.run
- ret_val = result.return_value
- if ret_val.nil?
- []
- elsif ret_val.is_a? Array
- ret_val
- else
- [ret_val]
+ # Returns a list of dsc resources matching the provided name
+ def query_resource(resource_name)
+ cmdlet = Chef::Util::Powershell::Cmdlet.new(nil, "get-dscresource #{resource_name}",
+ :object)
+ result = cmdlet.run
+ ret_val = result.return_value
+ if ret_val.nil?
+ []
+ elsif ret_val.is_a? Array
+ ret_val
+ else
+ [ret_val]
+ end
+ end
end
end
end
end
-end
-end
diff --git a/lib/chef/util/editor.rb b/lib/chef/util/editor.rb
index 973cf48e30..fa4f0ec12e 100644
--- a/lib/chef/util/editor.rb
+++ b/lib/chef/util/editor.rb
@@ -1,6 +1,6 @@
#
# Author:: Chris Bandy (<bandy.chris@gmail.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -89,4 +89,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/util/file_edit.rb b/lib/chef/util/file_edit.rb
index 4d2a9c03eb..5aa33fd169 100644
--- a/lib/chef/util/file_edit.rb
+++ b/lib/chef/util/file_edit.rb
@@ -1,6 +1,6 @@
#
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/util/editor'
-require 'fileutils'
+require "chef/util/editor"
+require "fileutils"
class Chef
class Util
@@ -61,7 +61,7 @@ class Chef
#search the file line by line and match each line with the given regex
#if matched, delete the match (all occurrences) from the line
def search_file_delete(regex)
- search_file_replace(regex, '')
+ search_file_replace(regex, "")
end
#search the file line by line and match each line with the given regex
diff --git a/lib/chef/util/path_helper.rb b/lib/chef/util/path_helper.rb
index 9ebc9319b8..6389458b6a 100644
--- a/lib/chef/util/path_helper.rb
+++ b/lib/chef/util/path_helper.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef-config/path_helper'
+require "chef-config/path_helper"
class Chef
class Util
diff --git a/lib/chef/util/powershell/cmdlet.rb b/lib/chef/util/powershell/cmdlet.rb
index 47d63a2b85..e300266b1e 100644
--- a/lib/chef/util/powershell/cmdlet.rb
+++ b/lib/chef/util/powershell/cmdlet.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
+# Author:: Adam Edwards (<adamed@chef.io>)
#
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,155 +16,158 @@
# limitations under the License.
#
-require 'mixlib/shellout'
-require 'chef/mixin/windows_architecture_helper'
-require 'chef/util/powershell/cmdlet_result'
+require "mixlib/shellout"
+require "chef/mixin/windows_architecture_helper"
+require "chef/util/powershell/cmdlet_result"
class Chef
-class Util
-class Powershell
- class Cmdlet
- def initialize(node, cmdlet, output_format=nil, output_format_options={})
- @output_format = output_format
- @node = node
-
- case output_format
- when nil
- @json_format = false
- when :json
- @json_format = true
- when :text
- @json_format = false
- when :object
- @json_format = true
- else
- raise ArgumentError, "Invalid output format #{output_format.to_s} specified"
- end
-
- @cmdlet = cmdlet
- @output_format_options = output_format_options
- end
-
- attr_reader :output_format
-
- def run(switches={}, execution_options={}, *arguments)
- streams = { :json => CmdletStream.new('json'),
- :verbose => CmdletStream.new('verbose'),
- }
+ class Util
+ class Powershell
+ class Cmdlet
+ def initialize(node, cmdlet, output_format = nil, output_format_options = {})
+ @output_format = output_format
+ @node = node
+
+ case output_format
+ when nil
+ @json_format = false
+ when :json
+ @json_format = true
+ when :text
+ @json_format = false
+ when :object
+ @json_format = true
+ else
+ raise ArgumentError, "Invalid output format #{output_format} specified"
+ end
- arguments_string = arguments.join(' ')
+ @cmdlet = cmdlet
+ @output_format_options = output_format_options
+ end
- switches_string = command_switches_string(switches)
+ attr_reader :output_format
- json_depth = 5
+ def run(switches = {}, execution_options = {}, *arguments)
+ streams = { :json => CmdletStream.new("json"),
+ :verbose => CmdletStream.new("verbose"),
+ }
- if @json_format && @output_format_options.has_key?(:depth)
- json_depth = @output_format_options[:depth]
- end
+ arguments_string = arguments.join(" ")
- json_command = @json_format ? " | convertto-json -compress -depth #{json_depth} "\
- "> #{streams[:json].path}" : ""
- redirections = "4> '#{streams[:verbose].path}'"
- command_string = "powershell.exe -executionpolicy bypass -noprofile -noninteractive "\
- "-command \"trap [Exception] {write-error -exception "\
- "($_.Exception.Message);exit 1};#{@cmdlet} #{switches_string} "\
- "#{arguments_string} #{redirections}"\
- "#{json_command}\";if ( ! $? ) { exit 1 }"
+ switches_string = command_switches_string(switches)
- augmented_options = {:returns => [0], :live_stream => false}.merge(execution_options)
- command = Mixlib::ShellOut.new(command_string, augmented_options)
+ json_depth = 5
- status = nil
-
- with_os_architecture(@node) do
- status = command.run_command
- end
+ if @json_format && @output_format_options.has_key?(:depth)
+ json_depth = @output_format_options[:depth]
+ end
- CmdletResult.new(status, streams, @output_format)
- end
+ json_command = if @json_format
+ " | convertto-json -compress -depth #{json_depth} > #{streams[:json].path}"
+ else
+ ""
+ end
+ redirections = "4> '#{streams[:verbose].path}'"
+ command_string = "powershell.exe -executionpolicy bypass -noprofile -noninteractive "\
+ "-command \"trap [Exception] {write-error -exception "\
+ "($_.Exception.Message);exit 1};#{@cmdlet} #{switches_string} "\
+ "#{arguments_string} #{redirections}"\
+ "#{json_command}\";if ( ! $? ) { exit 1 }"
+
+ augmented_options = { :returns => [0], :live_stream => false }.merge(execution_options)
+ command = Mixlib::ShellOut.new(command_string, augmented_options)
+
+ status = nil
+
+ with_os_architecture(@node) do
+ status = command.run_command
+ end
- def run!(switches={}, execution_options={}, *arguments)
- result = run(switches, execution_options, arguments)
+ CmdletResult.new(status, streams, @output_format)
+ end
- if ! result.succeeded?
- raise Chef::Exceptions::PowershellCmdletException, "Powershell Cmdlet failed: #{result.stderr}"
- end
+ def run!(switches = {}, execution_options = {}, *arguments)
+ result = run(switches, execution_options, arguments)
- result
- end
+ if ! result.succeeded?
+ raise Chef::Exceptions::PowershellCmdletException, "Powershell Cmdlet failed: #{result.stderr}"
+ end
- protected
+ result
+ end
- include Chef::Mixin::WindowsArchitectureHelper
+ protected
- def validate_switch_name!(switch_parameter_name)
- if !!(switch_parameter_name =~ /\A[A-Za-z]+[_a-zA-Z0-9]*\Z/) == false
- raise ArgumentError, "`#{switch_parameter_name}` is not a valid PowerShell cmdlet switch parameter name"
- end
- end
+ include Chef::Mixin::WindowsArchitectureHelper
- def escape_parameter_value(parameter_value)
- parameter_value.gsub(/(`|'|"|#)/,'`\1')
- end
-
- def escape_string_parameter_value(parameter_value)
- "'#{escape_parameter_value(parameter_value)}'"
- end
+ def validate_switch_name!(switch_parameter_name)
+ if !!(switch_parameter_name =~ /\A[A-Za-z]+[_a-zA-Z0-9]*\Z/) == false
+ raise ArgumentError, "`#{switch_parameter_name}` is not a valid PowerShell cmdlet switch parameter name"
+ end
+ end
- def command_switches_string(switches)
- command_switches = switches.map do | switch_name, switch_value |
- if switch_name.class != Symbol
- raise ArgumentError, "Invalid type `#{switch_name} `for PowerShell switch '#{switch_name.to_s}'. The switch must be specified as a Symbol'"
+ def escape_parameter_value(parameter_value)
+ parameter_value.gsub(/(`|'|"|#)/, '`\1')
end
- validate_switch_name!(switch_name)
-
- switch_argument = ''
- switch_present = true
-
- case switch_value
- when Numeric
- switch_argument = switch_value.to_s
- when Float
- switch_argument = switch_value.to_s
- when FalseClass
- switch_present = false
- when TrueClass
- when String
- switch_argument = escape_string_parameter_value(switch_value)
- else
- raise ArgumentError, "Invalid argument type `#{switch_value.class}` specified for PowerShell switch `:#{switch_name.to_s}`. Arguments to PowerShell must be of type `String`, `Numeric`, `Float`, `FalseClass`, or `TrueClass`"
+ def escape_string_parameter_value(parameter_value)
+ "'#{escape_parameter_value(parameter_value)}'"
end
- switch_present ? ["-#{switch_name.to_s.downcase}", switch_argument].join(' ').strip : ''
- end
+ def command_switches_string(switches)
+ command_switches = switches.map do |switch_name, switch_value|
+ if switch_name.class != Symbol
+ raise ArgumentError, "Invalid type `#{switch_name} `for PowerShell switch '#{switch_name}'. The switch must be specified as a Symbol'"
+ end
+
+ validate_switch_name!(switch_name)
+
+ switch_argument = ""
+ switch_present = true
+
+ case switch_value
+ when Numeric
+ switch_argument = switch_value.to_s
+ when Float
+ switch_argument = switch_value.to_s
+ when FalseClass
+ switch_present = false
+ when TrueClass
+ when String
+ switch_argument = escape_string_parameter_value(switch_value)
+ else
+ raise ArgumentError, "Invalid argument type `#{switch_value.class}` specified for PowerShell switch `:#{switch_name}`. Arguments to PowerShell must be of type `String`, `Numeric`, `Float`, `FalseClass`, or `TrueClass`"
+ end
+
+ switch_present ? ["-#{switch_name.to_s.downcase}", switch_argument].join(" ").strip : ""
+ end
- command_switches.join(' ')
- end
+ command_switches.join(" ")
+ end
- class CmdletStream
- def initialize(name)
- @filename = Dir::Tmpname.create(name) {}
- ObjectSpace.define_finalizer(self, self.class.destroy(@filename))
- end
+ class CmdletStream
+ def initialize(name)
+ @filename = Dir::Tmpname.create(name) {}
+ ObjectSpace.define_finalizer(self, self.class.destroy(@filename))
+ end
- def path
- @filename
- end
+ def path
+ @filename
+ end
- def read
- if File.exist? @filename
- File.open(@filename, 'rb:bom|UTF-16LE') do |f|
- f.read.encode('UTF-8')
+ def read
+ if File.exist? @filename
+ File.open(@filename, "rb:bom|UTF-16LE") do |f|
+ f.read.encode("UTF-8")
+ end
+ end
end
- end
- end
- def self.destroy(name)
- proc { File.delete(name) if File.exists? name }
+ def self.destroy(name)
+ proc { File.delete(name) if File.exists? name }
+ end
+ end
end
end
end
end
-end
-end
diff --git a/lib/chef/util/powershell/cmdlet_result.rb b/lib/chef/util/powershell/cmdlet_result.rb
index f1fdd968b1..82aef4da40 100644
--- a/lib/chef/util/powershell/cmdlet_result.rb
+++ b/lib/chef/util/powershell/cmdlet_result.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
+# Author:: Adam Edwards (<adamed@chef.io>)
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,46 +16,46 @@
# limitations under the License.
#
-require 'chef/json_compat'
+require "chef/json_compat"
class Chef
-class Util
-class Powershell
- class CmdletResult
- attr_reader :output_format
-
- def initialize(status, streams, output_format)
- @status = status
- @output_format = output_format
- @streams = streams
- end
+ class Util
+ class Powershell
+ class CmdletResult
+ attr_reader :output_format
- def stdout
- @status.stdout
- end
-
- def stderr
- @status.stderr
- end
+ def initialize(status, streams, output_format)
+ @status = status
+ @output_format = output_format
+ @streams = streams
+ end
- def stream(name)
- @streams[name].read
- end
+ def stdout
+ @status.stdout
+ end
- def return_value
- if output_format == :object
- Chef::JSONCompat.parse(stream(:json))
- elsif output_format == :json
- stream(:json)
- else
- @status.stdout
- end
- end
+ def stderr
+ @status.stderr
+ end
- def succeeded?
- @succeeded = @status.status.exitstatus == 0
+ def stream(name)
+ @streams[name].read
+ end
+
+ def return_value
+ if output_format == :object
+ Chef::JSONCompat.parse(stream(:json))
+ elsif output_format == :json
+ stream(:json)
+ else
+ @status.stdout
+ end
+ end
+
+ def succeeded?
+ @succeeded = @status.status.exitstatus == 0
+ end
+ end
end
end
end
-end
-end
diff --git a/lib/chef/util/powershell/ps_credential.rb b/lib/chef/util/powershell/ps_credential.rb
index 3f4558a77c..32810b98a6 100644
--- a/lib/chef/util/powershell/ps_credential.rb
+++ b/lib/chef/util/powershell/ps_credential.rb
@@ -1,7 +1,7 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/win32/crypto' if Chef::Platform.windows?
+require "chef/win32/crypto" if Chef::Platform.windows?
class Chef::Util::Powershell
class PSCredential
@@ -29,9 +29,8 @@ class Chef::Util::Powershell
"New-Object System.Management.Automation.PSCredential('#{@username}',('#{encrypt(@password)}' | ConvertTo-SecureString))"
end
- def to_s
- to_psobject
- end
+ alias to_s to_psobject
+ alias to_text to_psobject
private
diff --git a/lib/chef/util/selinux.rb b/lib/chef/util/selinux.rb
index 778da042e3..0ff76c6407 100644
--- a/lib/chef/util/selinux.rb
+++ b/lib/chef/util/selinux.rb
@@ -1,10 +1,10 @@
#
# Author:: Sean O'Meara
# Author:: Kevin Keane
-# Author:: Lamont Granquist (<lamont@opscode.com>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
#
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
-# Copyright:: Copyright (c) 2013, North County Tech Center, LLC
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
+# Copyright:: Copyright 2013-2016, North County Tech Center, LLC
#
# License:: Apache License, Version 2.0
#
@@ -20,8 +20,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/mixin/shell_out'
-require 'chef/mixin/which'
+require "chef/mixin/shell_out"
+require "chef/mixin/which"
class Chef
class Util
@@ -71,19 +71,19 @@ class Chef
def check_selinux_enabled?
if selinuxenabled_path
- cmd = shell_out!(selinuxenabled_path, :returns => [0,1])
+ cmd = shell_out!(selinuxenabled_path, :returns => [0, 1])
case cmd.exitstatus
when 1
return false
when 0
return true
else
- raise RuntimeError, "Unknown exit code from command #{selinuxenabled_path}: #{cmd.exitstatus}"
+ raise "Unknown exit code from command #{selinuxenabled_path}: #{cmd.exitstatus}"
end
else
# We assume selinux is not enabled if selinux utils are not
# installed.
- return false
+ false
end
end
diff --git a/lib/chef/util/threaded_job_queue.rb b/lib/chef/util/threaded_job_queue.rb
index 824cd0a3c4..eaffd9ea70 100644
--- a/lib/chef/util/threaded_job_queue.rb
+++ b/lib/chef/util/threaded_job_queue.rb
@@ -1,4 +1,4 @@
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'thread'
+require "thread"
class Chef
class Util
diff --git a/lib/chef/util/windows.rb b/lib/chef/util/windows.rb
index 7d29a67ac5..7fa6e15d82 100644
--- a/lib/chef/util/windows.rb
+++ b/lib/chef/util/windows.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/util/windows/net_group.rb b/lib/chef/util/windows/net_group.rb
index 2085747eb9..214881df56 100644
--- a/lib/chef/util/windows/net_group.rb
+++ b/lib/chef/util/windows/net_group.rb
@@ -1,85 +1,72 @@
-#
-# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/util/windows'
-require 'chef/win32/net'
-
-#wrapper around a subset of the NetGroup* APIs.
-class Chef::Util::Windows::NetGroup
-
- private
-
- def groupname
- @groupname
- end
-
- public
-
- def initialize(groupname)
- @groupname = groupname
- end
-
- def local_get_members
- begin
- Chef::ReservedNames::Win32::NetUser::net_local_group_get_members(nil, groupname)
- rescue Chef::Exceptions::Win32NetAPIError => e
- raise ArgumentError, e.msg
- end
- end
-
- def local_add
- begin
- Chef::ReservedNames::Win32::NetUser::net_local_group_add(nil, groupname)
- rescue Chef::Exceptions::Win32NetAPIError => e
- raise ArgumentError, e.msg
- end
- end
-
- def local_set_members(members)
- begin
- Chef::ReservedNames::Win32::NetUser::net_local_group_set_members(nil, groupname, members)
- rescue Chef::Exceptions::Win32NetAPIError => e
- raise ArgumentError, e.msg
- end
- end
-
- def local_add_members(members)
- begin
- Chef::ReservedNames::Win32::NetUser::net_local_group_add_members(nil, groupname, members)
- rescue Chef::Exceptions::Win32NetAPIError => e
- raise ArgumentError, e.msg
- end
- end
-
- def local_delete_members(members)
- begin
- Chef::ReservedNames::Win32::NetUser::net_local_group_del_members(nil, groupname, members)
- rescue Chef::Exceptions::Win32NetAPIError => e
- raise ArgumentError, e.msg
- end
-
- end
-
- def local_delete
- begin
- Chef::ReservedNames::Win32::NetUser::net_local_group_del(nil, groupname)
- rescue Chef::Exceptions::Win32NetAPIError => e
- raise ArgumentError, e.msg
- end
- end
-end
+#
+# Author:: Doug MacEachern (<dougm@vmware.com>)
+# Copyright:: Copyright 2010-2016, VMware, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/util/windows"
+require "chef/win32/net"
+
+#wrapper around a subset of the NetGroup* APIs.
+class Chef::Util::Windows::NetGroup
+
+ private
+
+ def groupname
+ @groupname
+ end
+
+ public
+
+ def initialize(groupname)
+ @groupname = groupname
+ end
+
+ def local_get_members
+ Chef::ReservedNames::Win32::NetUser.net_local_group_get_members(nil, groupname)
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
+ end
+
+ def local_add
+ Chef::ReservedNames::Win32::NetUser.net_local_group_add(nil, groupname)
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
+ end
+
+ def local_set_members(members)
+ Chef::ReservedNames::Win32::NetUser.net_local_group_set_members(nil, groupname, members)
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
+ end
+
+ def local_add_members(members)
+ Chef::ReservedNames::Win32::NetUser.net_local_group_add_members(nil, groupname, members)
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
+ end
+
+ def local_delete_members(members)
+ Chef::ReservedNames::Win32::NetUser.net_local_group_del_members(nil, groupname, members)
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
+ end
+
+ def local_delete
+ Chef::ReservedNames::Win32::NetUser.net_local_group_del(nil, groupname)
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
+ end
+end
diff --git a/lib/chef/util/windows/net_use.rb b/lib/chef/util/windows/net_use.rb
index b94576e702..196ce42215 100644
--- a/lib/chef/util/windows/net_use.rb
+++ b/lib/chef/util/windows/net_use.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,8 +20,8 @@
#see also: WNetAddConnection2 and WNetAddConnection3
#see also cmd.exe: net use /?
-require 'chef/util/windows'
-require 'chef/win32/net'
+require "chef/util/windows"
+require "chef/win32/net"
class Chef::Util::Windows::NetUse < Chef::Util::Windows
def initialize(localname)
@@ -29,7 +29,7 @@ class Chef::Util::Windows::NetUse < Chef::Util::Windows
end
def to_ui2_struct(use_info)
- use_info.inject({}) do |memo, (k,v)|
+ use_info.inject({}) do |memo, (k, v)|
memo["ui2_#{k}".to_sym] = v
memo
end
@@ -52,19 +52,17 @@ class Chef::Util::Windows::NetUse < Chef::Util::Windows
end
def from_use_info_struct(ui2_hash)
- ui2_hash.inject({}) do |memo, (k,v)|
- memo[k.to_s.sub('ui2_', '').to_sym] = v
+ ui2_hash.inject({}) do |memo, (k, v)|
+ memo[k.to_s.sub("ui2_", "").to_sym] = v
memo
end
end
def get_info
- begin
- ui2 = Chef::ReservedNames::Win32::Net.net_use_get_info_l2(nil, use_name)
- from_use_info_struct(ui2)
- rescue Chef::Exceptions::Win32APIError => e
- raise ArgumentError, e
- end
+ ui2 = Chef::ReservedNames::Win32::Net.net_use_get_info_l2(nil, use_name)
+ from_use_info_struct(ui2)
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
end
def device
@@ -72,11 +70,9 @@ class Chef::Util::Windows::NetUse < Chef::Util::Windows
end
def delete
- begin
- Chef::ReservedNames::Win32::Net.net_use_del(nil, use_name, :use_noforce)
- rescue Chef::Exceptions::Win32APIError => e
- raise ArgumentError, e
- end
+ Chef::ReservedNames::Win32::Net.net_use_del(nil, use_name, :use_noforce)
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
end
def use_name
diff --git a/lib/chef/util/windows/net_user.rb b/lib/chef/util/windows/net_user.rb
index 4ce051228a..f9f8f011af 100644
--- a/lib/chef/util/windows/net_user.rb
+++ b/lib/chef/util/windows/net_user.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,17 @@
# limitations under the License.
#
-require 'chef/util/windows'
-require 'chef/exceptions'
-require 'chef/win32/net'
-require 'chef/win32/security'
+require "chef/util/windows"
+require "chef/exceptions"
+require "chef/win32/net"
+require "chef/win32/security"
#wrapper around a subset of the NetUser* APIs.
#nothing Chef specific, but not complete enough to be its own gem, so util for now.
class Chef::Util::Windows::NetUser < Chef::Util::Windows
private
+
NetUser = Chef::ReservedNames::Win32::NetUser
Security = Chef::ReservedNames::Win32::Security
@@ -62,7 +63,7 @@ class Chef::Util::Windows::NetUser < Chef::Util::Windows
}
def transform_usri3(args)
- args.inject({}) do |memo, (k,v)|
+ args.inject({}) do |memo, (k, v)|
memo[USER_INFO_3_TRANSFORM[k]] = v
memo
end
@@ -70,18 +71,16 @@ class Chef::Util::Windows::NetUser < Chef::Util::Windows
def usri3_to_hash(usri3)
t = USER_INFO_3_TRANSFORM.invert
- usri3.inject({}) do |memo, (k,v)|
+ usri3.inject({}) do |memo, (k, v)|
memo[t[k]] = v
memo
end
end
def set_info(args)
- begin
- rc = NetUser::net_user_set_info_l3(nil, @username, transform_usri3(args))
- rescue Chef::Exceptions::Win32APIError => e
- raise ArgumentError, e
- end
+ rc = NetUser.net_user_set_info_l3(nil, @username, transform_usri3(args))
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
end
public
@@ -94,18 +93,16 @@ class Chef::Util::Windows::NetUser < Chef::Util::Windows
LOGON32_LOGON_NETWORK = Security::LOGON32_LOGON_NETWORK
#XXX for an extra painful alternative, see: http://support.microsoft.com/kb/180548
def validate_credentials(passwd)
- begin
- token = Security::logon_user(@username, nil, passwd,
- LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT)
- return true
- rescue Chef::Exceptions::Win32APIError
- return false
- end
+ token = Security.logon_user(@username, nil, passwd,
+ LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT)
+ return true
+ rescue Chef::Exceptions::Win32APIError
+ return false
end
def get_info
begin
- ui3 = NetUser::net_user_get_info_l3(nil, @username)
+ ui3 = NetUser.net_user_get_info_l3(nil, @username)
rescue Chef::Exceptions::Win32APIError => e
raise ArgumentError, e
end
@@ -114,32 +111,31 @@ class Chef::Util::Windows::NetUser < Chef::Util::Windows
def add(args)
transformed_args = transform_usri3(args)
- NetUser::net_user_add_l3(nil, transformed_args)
- NetUser::net_local_group_add_member(nil, "Users", args[:name])
+ NetUser.net_user_add_l3(nil, transformed_args)
+ NetUser.net_local_group_add_member(nil, "Users", args[:name])
end
- def user_modify(&proc)
+ # FIXME: yard with @yield
+ def user_modify
user = get_info
user[:last_logon] = user[:units_per_week] = 0 #ignored as per USER_INFO_3 doc
user[:logon_hours] = nil #PBYTE field; \0 == no changes
- proc.call(user)
+ yield(user)
set_info(user)
end
def update(args)
user_modify do |user|
- args.each do |key,val|
+ args.each do |key, val|
user[key] = val
end
end
end
def delete
- begin
- NetUser::net_user_del(nil, @username)
- rescue Chef::Exceptions::Win32APIError => e
- raise ArgumentError, e
- end
+ NetUser.net_user_del(nil, @username)
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
end
def disable_account
diff --git a/lib/chef/util/windows/volume.rb b/lib/chef/util/windows/volume.rb
index 6e45594ba6..dc9c0ca1d0 100644
--- a/lib/chef/util/windows/volume.rb
+++ b/lib/chef/util/windows/volume.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
#simple wrapper around Volume APIs. might be possible with WMI, but possibly more complex.
-require 'chef/win32/api/file'
-require 'chef/util/windows'
+require "chef/win32/api/file"
+require "chef/util/windows"
class Chef::Util::Windows::Volume < Chef::Util::Windows
attr_reader :mount_point
@@ -30,27 +30,21 @@ class Chef::Util::Windows::Volume < Chef::Util::Windows
end
def device
- begin
- Chef::ReservedNames::Win32::File.get_volume_name_for_volume_mount_point(mount_point)
- rescue Chef::Exceptions::Win32APIError => e
- raise ArgumentError, e
- end
+ Chef::ReservedNames::Win32::File.get_volume_name_for_volume_mount_point(mount_point)
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
end
def delete
- begin
- Chef::ReservedNames::Win32::File.delete_volume_mount_point(mount_point)
- rescue Chef::Exceptions::Win32APIError => e
- raise ArgumentError, e
- end
+ Chef::ReservedNames::Win32::File.delete_volume_mount_point(mount_point)
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
end
def add(args)
- begin
- Chef::ReservedNames::Win32::File.set_volume_mount_point(mount_point, args[:remote])
- rescue Chef::Exceptions::Win32APIError => e
- raise ArgumentError, e
- end
+ Chef::ReservedNames::Win32::File.set_volume_mount_point(mount_point, args[:remote])
+ rescue Chef::Exceptions::Win32APIError => e
+ raise ArgumentError, e
end
def mount_point
diff --git a/lib/chef/version.rb b/lib/chef/version.rb
index c769533aa6..82afd17006 100644
--- a/lib/chef/version.rb
+++ b/lib/chef/version.rb
@@ -1,4 +1,4 @@
-# Copyright:: Copyright (c) 2010-2015 Chef Software, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,8 +20,8 @@
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
class Chef
- CHEF_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
- VERSION = '12.5.1'
+ CHEF_ROOT = File.expand_path("../..", __FILE__)
+ VERSION = "12.19.39"
end
#
diff --git a/lib/chef/version/platform.rb b/lib/chef/version/platform.rb
index 81e7614646..07b1a17b11 100644
--- a/lib/chef/version/platform.rb
+++ b/lib/chef/version/platform.rb
@@ -1,5 +1,5 @@
# Author:: Xabier de Zuazo (<xabier@onddo.com>)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/version_class'
+require "chef/version_class"
class Chef
class Version
@@ -22,7 +22,7 @@ class Chef
protected
- def parse(str="")
+ def parse(str = "")
@major, @minor, @patch =
case str.to_s
when /^(\d+)\.(\d+)\.(\d+)$/
@@ -31,10 +31,10 @@ class Chef
[ $1.to_i, $2.to_i, 0 ]
when /^(\d+)$/
[ $1.to_i, 0, 0 ]
- when /^(\d+).(\d+)-[a-z]+\d?(-p(\d+))?$/i # Match FreeBSD
+ when /^(\d+).(\d+)-[a-z]+\d?(-p(\d+))?$/i # Match FreeBSD
[ $1.to_i, $2.to_i, ($4 ? $4.to_i : 0)]
else
- msg = "'#{str.to_s}' does not match 'x.y.z', 'x.y' or 'x'"
+ msg = "'#{str}' does not match 'x.y.z', 'x.y' or 'x'"
raise Chef::Exceptions::InvalidPlatformVersion.new( msg )
end
end
diff --git a/lib/chef/version_class.rb b/lib/chef/version_class.rb
index 01af6f1f55..f98673b019 100644
--- a/lib/chef/version_class.rb
+++ b/lib/chef/version_class.rb
@@ -1,6 +1,6 @@
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@ class Chef
include Comparable
attr_reader :major, :minor, :patch
- def initialize(str="")
+ def initialize(str = "")
parse(str)
end
@@ -32,10 +32,15 @@ class Chef
"#{@major}.#{@minor}.#{@patch}"
end
- def <=>(v)
+ def <=>(other)
[:major, :minor, :patch].each do |method|
- ans = (self.send(method) <=> v.send(method))
- return ans if ans != 0
+ version = send(method)
+ begin
+ ans = (version <=> other.send(method))
+ rescue NoMethodError # if the other thing isn't a version object, return nil
+ return nil
+ end
+ return ans unless ans == 0
end
0
end
@@ -53,7 +58,7 @@ class Chef
protected
- def parse(str="")
+ def parse(str = "")
@major, @minor, @patch =
case str.to_s
when /^(\d+)\.(\d+)\.(\d+)$/
@@ -61,7 +66,7 @@ class Chef
when /^(\d+)\.(\d+)$/
[ $1.to_i, $2.to_i, 0 ]
else
- msg = "'#{str.to_s}' does not match 'x.y.z' or 'x.y'"
+ msg = "'#{str}' does not match 'x.y.z' or 'x.y'"
raise Chef::Exceptions::InvalidCookbookVersion.new( msg )
end
end
diff --git a/lib/chef/version_constraint.rb b/lib/chef/version_constraint.rb
index a78e32e94f..f10325f946 100644
--- a/lib/chef/version_constraint.rb
+++ b/lib/chef/version_constraint.rb
@@ -1,6 +1,6 @@
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,19 +14,19 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/version_class'
+require "chef/version_class"
class Chef
class VersionConstraint
DEFAULT_CONSTRAINT = ">= 0.0.0"
- STANDARD_OPS = %w(< > <= >=)
- OPS = %w(< > = <= >= ~>)
+ STANDARD_OPS = %w{< > <= >=}
+ OPS = %w{< > = <= >= ~>}
PATTERN = /^(#{OPS.join('|')}) *([0-9].*)$/
VERSION_CLASS = Chef::Version
attr_reader :op, :version
- def initialize(constraint_spec=DEFAULT_CONSTRAINT)
+ def initialize(constraint_spec = DEFAULT_CONSTRAINT)
case constraint_spec
when nil
parse(DEFAULT_CONSTRAINT)
@@ -46,19 +46,19 @@ class Chef
else
self.class::VERSION_CLASS.new(v.to_s)
end
- do_op(version)
+ do_op(version)
end
def inspect
- "(#{to_s})"
+ "(#{self})"
end
def to_s
"#{@op} #{@raw_version}"
end
- def eql?(o)
- o.class == self.class && @op == o.op && @version == o.version
+ def eql?(other)
+ other.class == self.class && @op == other.op && @version == other.version
end
alias_method :==, :eql?
@@ -67,9 +67,9 @@ class Chef
def do_op(other_version)
if STANDARD_OPS.include? @op
other_version.send(@op.to_sym, @version)
- elsif @op == '='
+ elsif @op == "="
other_version == @version
- elsif @op == '~>'
+ elsif @op == "~>"
if @missing_patch_level
(other_version.major == @version.major &&
other_version.minor >= @version.minor)
@@ -78,7 +78,7 @@ class Chef
other_version.minor == @version.minor &&
other_version.patch >= @version.patch)
end
- else # should never happen
+ else # should never happen
raise "bad op #{@op}"
end
end
@@ -106,7 +106,7 @@ class Chef
@op = $1
@raw_version = $2
@version = self.class::VERSION_CLASS.new(@raw_version)
- if @raw_version.split('.').size <= 2
+ if @raw_version.split(".").size <= 2
@missing_patch_level = true
end
else
diff --git a/lib/chef/version_constraint/platform.rb b/lib/chef/version_constraint/platform.rb
index ada4f29b70..29f4678bb5 100644
--- a/lib/chef/version_constraint/platform.rb
+++ b/lib/chef/version_constraint/platform.rb
@@ -1,5 +1,5 @@
# Author:: Xabier de Zuazo (<xabier@onddo.com>)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,8 +13,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/version_constraint'
-require 'chef/version/platform'
+require "chef/version_constraint"
+require "chef/version/platform"
class Chef
class VersionConstraint
diff --git a/lib/chef/whitelist.rb b/lib/chef/whitelist.rb
index 3682f7187e..58d0bd70c6 100644
--- a/lib/chef/whitelist.rb
+++ b/lib/chef/whitelist.rb
@@ -1,5 +1,5 @@
-require 'chef/exceptions'
+require "chef/exceptions"
class Chef
class Whitelist
@@ -27,7 +27,7 @@ class Chef
# },
# ["network/interfaces/eth0", ["filesystem", "/dev/disk"]])
# will capture the eth0 and /dev/disk subtrees.
- def self.filter(data, whitelist=nil)
+ def self.filter(data, whitelist = nil)
return data if whitelist.nil?
new_data = {}
diff --git a/lib/chef/win32/api.rb b/lib/chef/win32/api.rb
index 4786222bd4..503920a0ed 100644
--- a/lib/chef/win32/api.rb
+++ b/lib/chef/win32/api.rb
@@ -1,7 +1,7 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
# limitations under the License.
#
-require 'ffi'
-require 'chef/reserved_names'
-require 'chef/exceptions'
+require "ffi"
+require "chef/reserved_names"
+require "chef/exceptions"
class Chef
module ReservedNames::Win32
@@ -29,12 +29,10 @@ class Chef
# function into the calling module. If this fails a dummy method is
# defined which when called, raises a helpful exception to the end-user.
def safe_attach_function(win32_func, *args)
- begin
- attach_function(win32_func.to_sym, *args)
- rescue FFI::NotFoundError
- define_method(win32_func.to_sym) do |*margs|
- raise Chef::Exceptions::Win32APIFunctionNotImplemented, "This version of Windows does not implement the Win32 function [#{win32_func}]."
- end
+ attach_function(win32_func.to_sym, *args)
+ rescue FFI::NotFoundError
+ define_method(win32_func.to_sym) do |*margs|
+ raise Chef::Exceptions::Win32APIFunctionNotImplemented, "This version of Windows does not implement the Win32 function [#{win32_func}]."
end
end
@@ -67,7 +65,7 @@ class Chef
# BaseTsd.h: #ifdef (_WIN64) host.typedef int HALF_PTR; #else host.typedef short HALF_PTR;
host.typedef :ulong, :HACCEL # (L) Handle to an accelerator table. WinDef.h: #host.typedef HANDLE HACCEL;
# See http://msdn.microsoft.com/en-us/library/ms645526%28VS.85%29.aspx
- host.typedef :size_t, :HANDLE # (L) Handle to an object. WinNT.h: #host.typedef PVOID HANDLE;
+ host.typedef :size_t, :HANDLE # (L) Handle to an object. WinNT.h: #host.typedef PVOID HANDLE;
# todo: Platform-dependent! Need to change to :uint64 for Win64
host.typedef :ulong, :HBITMAP # (L) Handle to a bitmap: http://msdn.microsoft.com/en-us/library/dd183377%28VS.85%29.aspx
host.typedef :ulong, :HBRUSH # (L) Handle to a brush. http://msdn.microsoft.com/en-us/library/dd183394%28VS.85%29.aspx
@@ -147,6 +145,8 @@ class Chef
host.typedef :long, :LRESULT # Signed result of message processing. WinDef.h: host.typedef LONG_PTR LRESULT;
host.typedef :pointer, :LPWIN32_FIND_DATA # Pointer to WIN32_FIND_DATA struct
host.typedef :pointer, :LPBY_HANDLE_FILE_INFORMATION # Point to a BY_HANDLE_FILE_INFORMATION struct
+ host.typedef :pointer, :LSA_HANDLE # A handle to a Policy object
+ host.typedef :ulong, :NTSTATUS # An NTSTATUS code returned by an LSA function call.
host.typedef :pointer, :PBOOL # Pointer to a BOOL.
host.typedef :pointer, :PBOOLEAN # Pointer to a BOOL.
host.typedef :pointer, :PBYTE # Pointer to a BYTE.
@@ -174,12 +174,16 @@ class Chef
host.typedef :pointer, :PLONG_PTR # Pointer to a LONG_PTR.
host.typedef :pointer, :PLONG32 # Pointer to a LONG32.
host.typedef :pointer, :PLONG64 # Pointer to a LONG64.
+ host.typedef :pointer, :PLSA_HANDLE # Pointer to an LSA_HANDLE
+ host.typedef :pointer, :PLSA_OBJECT_ATTRIBUTES # Pointer to an LSA_OBJECT_ATTRIBUTES
+ host.typedef :pointer, :PLSA_UNICODE_STRING # Pointer to LSA_UNICODE_STRING
host.typedef :pointer, :PLUID # Pointer to a LUID.
host.typedef :pointer, :POINTER_32 # 32-bit pointer. On a 32-bit system, this is a native pointer. On a 64-bit system, this is a truncated 64-bit pointer.
host.typedef :pointer, :POINTER_64 # 64-bit pointer. On a 64-bit system, this is a native pointer. On a 32-bit system, this is a sign-extended 32-bit pointer.
host.typedef :pointer, :POINTER_SIGNED # A signed pointer.
host.typedef :pointer, :POINTER_UNSIGNED # An unsigned pointer.
host.typedef :pointer, :PSHORT # Pointer to a SHORT.
+ host.typedef :pointer, :PSID # Pointer to an account SID
host.typedef :pointer, :PSIZE_T # Pointer to a SIZE_T.
host.typedef :pointer, :PSSIZE_T # Pointer to a SSIZE_T.
host.typedef :pointer, :PSTR # Pointer to a null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.
@@ -188,7 +192,6 @@ class Chef
host.typedef :pointer, :PCRYPTPROTECT_PROMPTSTRUCT # Pointer to a CRYPTOPROTECT_PROMPTSTRUCT.
host.typedef :pointer, :PDATA_BLOB # Pointer to a DATA_BLOB.
host.typedef :pointer, :PTSTR # A PWSTR if UNICODE is defined, a PSTR otherwise.
- host.typedef :pointer, :PSID
host.typedef :pointer, :PUCHAR # Pointer to a UCHAR.
host.typedef :pointer, :PUHALF_PTR # Pointer to a UHALF_PTR.
host.typedef :pointer, :PUINT # Pointer to a UINT.
@@ -234,7 +237,7 @@ class Chef
# In WinNT.h: host.typedef wchar_t WCHAR;
#WINAPI: K, # Calling convention for system functions. WinDef.h: define WINAPI __stdcall
host.typedef :ushort, :WORD # 16-bit unsigned integer. The range is 0 through 65535 decimal.
- host.typedef :uint, :WPARAM # Message parameter. WinDef.h as follows: host.typedef UINT_PTR WPARAM;
+ host.typedef :uint, :WPARAM # Message parameter. WinDef.h as follows: host.typedef UINT_PTR WPARAM;
end
module Macros
diff --git a/lib/chef/win32/api/crypto.rb b/lib/chef/win32/api/crypto.rb
index 1837a57557..0abb908622 100644
--- a/lib/chef/win32/api/crypto.rb
+++ b/lib/chef/win32/api/crypto.rb
@@ -1,63 +1,63 @@
-#
-# Author:: Jay Mundrawala (<jdm@chef.io>)
-# Copyright:: Copyright 2015 Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/win32/api'
-
-class Chef
- module ReservedNames::Win32
- module API
- module Crypto
- extend Chef::ReservedNames::Win32::API
-
- ###############################################
- # Win32 API Bindings
- ###############################################
-
- ffi_lib 'Crypt32'
-
- CRYPTPROTECT_UI_FORBIDDEN = 0x1
- CRYPTPROTECT_LOCAL_MACHINE = 0x4
- CRYPTPROTECT_AUDIT = 0x10
-
- class CRYPT_INTEGER_BLOB < FFI::Struct
- layout :cbData, :DWORD, # Count, in bytes, of data
- :pbData, :pointer # Pointer to data buffer
- def initialize(str=nil)
- super(nil)
- if str
- self[:pbData] = FFI::MemoryPointer.from_string(str)
- self[:cbData] = str.bytesize
- end
- end
-
- end
-
- safe_attach_function :CryptProtectData, [
- :PDATA_BLOB,
- :LPCWSTR,
- :PDATA_BLOB,
- :pointer,
- :PCRYPTPROTECT_PROMPTSTRUCT,
- :DWORD,
- :PDATA_BLOB
- ], :BOOL
-
- end
- end
- end
-end
+#
+# Author:: Jay Mundrawala (<jdm@chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/win32/api"
+
+class Chef
+ module ReservedNames::Win32
+ module API
+ module Crypto
+ extend Chef::ReservedNames::Win32::API
+
+ ###############################################
+ # Win32 API Bindings
+ ###############################################
+
+ ffi_lib "Crypt32"
+
+ CRYPTPROTECT_UI_FORBIDDEN = 0x1
+ CRYPTPROTECT_LOCAL_MACHINE = 0x4
+ CRYPTPROTECT_AUDIT = 0x10
+
+ class CRYPT_INTEGER_BLOB < FFI::Struct
+ layout :cbData, :DWORD, # Count, in bytes, of data
+ :pbData, :pointer # Pointer to data buffer
+ def initialize(str = nil)
+ super(nil)
+ if str
+ self[:pbData] = FFI::MemoryPointer.from_string(str)
+ self[:cbData] = str.bytesize
+ end
+ end
+
+ end
+
+ safe_attach_function :CryptProtectData, [
+ :PDATA_BLOB,
+ :LPCWSTR,
+ :PDATA_BLOB,
+ :pointer,
+ :PCRYPTPROTECT_PROMPTSTRUCT,
+ :DWORD,
+ :PDATA_BLOB,
+ ], :BOOL
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/win32/api/error.rb b/lib/chef/win32/api/error.rb
index d1f9a309fe..12ccdb5ee9 100644
--- a/lib/chef/win32/api/error.rb
+++ b/lib/chef/win32/api/error.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/win32/api'
+require "chef/win32/api"
class Chef
module ReservedNames::Win32
@@ -178,7 +178,7 @@ class Chef
ERROR_LOCK_FAILED = 167
ERROR_BUSY = 170
ERROR_CANCEL_VIOLATION = 173
- ERROR_ATOMIC_LOCKS_NOT_SUPPORTED= 174
+ ERROR_ATOMIC_LOCKS_NOT_SUPPORTED = 174
ERROR_INVALID_SEGMENT_NUMBER = 180
ERROR_INVALID_CALLGATE = 181
@@ -194,12 +194,12 @@ class Chef
ERROR_INVALID_EXE_SIGNATURE = 191
ERROR_EXE_MARKED_INVALID = 192
ERROR_BAD_EXE_FORMAT = 193
- ERROR_ITERATED_DATA_EXCEEDS_64k = 194
+ ERROR_ITERATED_DATA_EXCEEDS_64k = 194 # rubocop:disable Style/ConstantName
ERROR_INVALID_MINALLOCSIZE = 195
ERROR_DYNLINK_FROM_INVALID_RING = 196
ERROR_IOPL_NOT_ENABLED = 197
ERROR_INVALID_SEGDPL = 198
- ERROR_AUTODATASEG_EXCEEDS_64k = 199
+ ERROR_AUTODATASEG_EXCEEDS_64k = 199 # rubocop:disable Style/ConstantName
ERROR_RING2SEG_MUST_BE_MOVABLE = 200
ERROR_RELOC_CHAIN_XEEDS_SEGLIM = 201
ERROR_INFLOOP_IN_RELOC_CHAIN = 202
@@ -446,7 +446,7 @@ class Chef
ERROR_DOWNGRADE_DETECTED = 1265
ERROR_MACHINE_LOCKED = 1271
ERROR_CALLBACK_SUPPLIED_INVALID_DATA = 1273
- ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED= 1274
+ ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED = 1274
ERROR_DRIVER_BLOCKED = 1275
ERROR_INVALID_IMPORT_OF_NON_DLL = 1276
ERROR_NOT_ALL_ASSIGNED = 1300
@@ -750,7 +750,7 @@ class Chef
ERROR_NETLOGON_NOT_STARTED = 1792
ERROR_ACCOUNT_EXPIRED = 1793
ERROR_REDIRECTOR_HAS_OPEN_HANDLES = 1794
- ERROR_PRINTER_DRIVER_ALREADY_INSTALLED= 1795
+ ERROR_PRINTER_DRIVER_ALREADY_INSTALLED = 1795
ERROR_UNKNOWN_PORT = 1796
ERROR_UNKNOWN_PRINTER_DRIVER = 1797
ERROR_UNKNOWN_PRINTPROCESSOR = 1798
@@ -824,9 +824,9 @@ class Chef
ERROR_CONTEXT_EXPIRED = 1931
ERROR_PER_USER_TRUST_QUOTA_EXCEEDED = 1932
ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED = 1933
- ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED= 1934
- ERROR_AUTHENTICATION_FIREWALL_FAILED = 1935
- ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED= 1936
+ ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED = 1934
+ ERROR_AUTHENTICATION_FIREWALL_FAILED = 1935
+ ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED = 1936
ERROR_INVALID_PIXEL_FORMAT = 2000
ERROR_BAD_DRIVER = 2001
ERROR_INVALID_WINDOW_STYLE = 2002
@@ -848,6 +848,7 @@ class Chef
ERROR_INVALID_COLORINDEX = 2022
ERROR_CONNECTED_OTHER_PASSWORD = 2108
ERROR_BAD_USERNAME = 2202
+ ERROR_USER_NOT_FOUND = 2221
ERROR_NOT_CONNECTED = 2250
ERROR_OPEN_FILES = 2401
ERROR_ACTIVE_CONNECTIONS = 2402
@@ -873,11 +874,25 @@ class Chef
SEM_NOGPFAULTERRORBOX = 0x0002
SEM_NOOPENFILEERRORBOX = 0x8000
+ # Flags for LoadLibraryEx
+
+ DONT_RESOLVE_DLL_REFERENCES = 0x00000001
+ LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010
+ LOAD_LIBRARY_AS_DATAFILE = 0x00000002
+ LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040
+ LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020
+ LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200
+ LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000
+ LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100
+ LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
+ LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400
+ LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
+
###############################################
# Win32 API Bindings
###############################################
- ffi_lib 'kernel32', 'user32'
+ ffi_lib "kernel32", "user32"
=begin
DWORD WINAPI FormatMessage(
@@ -890,8 +905,8 @@ DWORD WINAPI FormatMessage(
__in_opt va_list *Arguments
);
=end
- safe_attach_function :FormatMessageA, [:DWORD, :LPCVOID, :DWORD, :DWORD, :LPTSTR, :DWORD, :varargs], :DWORD
- safe_attach_function :FormatMessageW, [:DWORD, :LPCVOID, :DWORD, :DWORD, :LPWSTR, :DWORD, :varargs], :DWORD
+ safe_attach_function :FormatMessageA, [:DWORD, :HANDLE, :DWORD, :DWORD, :LPTSTR, :DWORD, :varargs], :DWORD
+ safe_attach_function :FormatMessageW, [:DWORD, :HANDLE, :DWORD, :DWORD, :LPWSTR, :DWORD, :varargs], :DWORD
=begin
DWORD WINAPI GetLastError(void);
@@ -915,6 +930,23 @@ UINT WINAPI SetErrorMode(
=end
safe_attach_function :SetErrorMode, [:UINT], :UINT
+=begin
+https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
+HMODULE WINAPI LoadLibraryEx(
+ _In_ LPCTSTR lpFileName,
+ _Reserved_ HANDLE hFile,
+ _In_ DWORD dwFlags
+);
+=end
+ safe_attach_function :LoadLibraryExW, [:LPCTSTR, :HANDLE, :DWORD], :HANDLE
+
+=begin
+https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152(v=vs.85).aspx
+BOOL WINAPI FreeLibrary(
+ _In_ HMODULE hModule
+);
+=end
+ safe_attach_function :FreeLibrary, [:HANDLE], :BOOL
end
end
end
diff --git a/lib/chef/win32/api/file.rb b/lib/chef/win32/api/file.rb
index 9ff1ad40d6..355cc81378 100644
--- a/lib/chef/win32/api/file.rb
+++ b/lib/chef/win32/api/file.rb
@@ -1,7 +1,7 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
+# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Mark Mzyk (<mmzyk@ospcode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
# limitations under the License.
#
-require 'chef/win32/api'
-require 'chef/win32/api/security'
-require 'chef/win32/api/system'
-require 'chef/win32/unicode'
+require "chef/win32/api"
+require "chef/win32/api/security"
+require "chef/win32/api/system"
+require "chef/win32/unicode"
class Chef
module ReservedNames::Win32
@@ -163,7 +163,7 @@ class Chef
(device_type << 16) | (access << 14) | (function << 2) | method
end
- FSCTL_GET_REPARSE_POINT = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
+ FSCTL_GET_REPARSE_POINT = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
# Reparse point tags
IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
@@ -176,13 +176,20 @@ class Chef
IO_REPARSE_TAG_SYMLINK = 0xA000000C
IO_REPARSE_TAG_DFSR = 0x80000012
- MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16*1024
+ MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024
###############################################
# Win32 API Bindings
###############################################
- ffi_lib 'kernel32'
+ ffi_lib "kernel32", "version"
+
+ # Does not map directly to a win32 struct
+ # see https://msdn.microsoft.com/en-us/library/windows/desktop/ms647464(v=vs.85).aspx
+ class Translation < FFI::Struct
+ layout :w_lang, :WORD,
+ :w_code_page, :WORD
+ end
=begin
typedef struct _FILETIME {
@@ -231,7 +238,7 @@ typedef struct _WIN32_FIND_DATA {
:n_file_size_low, :DWORD,
:dw_reserved_0, :DWORD,
:dw_reserved_1, :DWORD,
- :c_file_name, [:BYTE, MAX_PATH*2],
+ :c_file_name, [:BYTE, MAX_PATH * 2],
:c_alternate_file_name, [:BYTE, 14]
end
@@ -300,11 +307,12 @@ typedef struct _REPARSE_DATA_BUFFER {
def substitute_name
string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:SubstituteNameOffset]
- string_pointer.read_wstring(self[:SubstituteNameLength]/2)
+ string_pointer.read_wstring(self[:SubstituteNameLength] / 2)
end
+
def print_name
string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:PrintNameOffset]
- string_pointer.read_wstring(self[:PrintNameLength]/2)
+ string_pointer.read_wstring(self[:PrintNameLength] / 2)
end
end
class REPARSE_DATA_BUFFER_MOUNT_POINT < FFI::Struct
@@ -316,11 +324,12 @@ typedef struct _REPARSE_DATA_BUFFER {
def substitute_name
string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:SubstituteNameOffset]
- string_pointer.read_wstring(self[:SubstituteNameLength]/2)
+ string_pointer.read_wstring(self[:SubstituteNameLength] / 2)
end
+
def print_name
string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:PrintNameOffset]
- string_pointer.read_wstring(self[:PrintNameLength]/2)
+ string_pointer.read_wstring(self[:PrintNameLength] / 2)
end
end
class REPARSE_DATA_BUFFER_GENERIC < FFI::Struct
@@ -451,7 +460,6 @@ BOOL WINAPI DeviceIoControl(
=end
safe_attach_function :DeviceIoControl, [:HANDLE, :DWORD, :LPVOID, :DWORD, :LPVOID, :DWORD, :LPDWORD, :pointer], :BOOL
-
#BOOL WINAPI DeleteVolumeMountPoint(
#_In_ LPCTSTR lpszVolumeMountPoint
#);
@@ -470,6 +478,34 @@ BOOL WINAPI DeviceIoControl(
#);
safe_attach_function :GetVolumeNameForVolumeMountPointW, [:LPCTSTR, :LPTSTR, :DWORD], :BOOL
+=begin
+BOOL WINAPI GetFileVersionInfo(
+ _In_ LPCTSTR lptstrFilename,
+ _Reserved_ DWORD dwHandle,
+ _In_ DWORD dwLen,
+ _Out_ LPVOID lpData
+);
+=end
+ safe_attach_function :GetFileVersionInfoW, [:LPCTSTR, :DWORD, :DWORD, :LPVOID], :BOOL
+
+=begin
+DWORD WINAPI GetFileVersionInfoSize(
+ _In_ LPCTSTR lptstrFilename,
+ _Out_opt_ LPDWORD lpdwHandle
+);
+=end
+ safe_attach_function :GetFileVersionInfoSizeW, [:LPCTSTR, :LPDWORD], :DWORD
+
+=begin
+BOOL WINAPI VerQueryValue(
+ _In_ LPCVOID pBlock,
+ _In_ LPCTSTR lpSubBlock,
+ _Out_ LPVOID *lplpBuffer,
+ _Out_ PUINT puLen
+);
+=end
+ safe_attach_function :VerQueryValueW, [:LPCVOID, :LPCTSTR, :LPVOID, :PUINT], :BOOL
+
###############################################
# Helpers
###############################################
@@ -499,58 +535,55 @@ BOOL WINAPI DeviceIoControl(
# retrieves a file search handle and passes it
# to +&block+ along with the find_data. also
# ensures the handle is closed on exit of the block
- def file_search_handle(path, &block)
- begin
+ # FIXME: yard with @yield
+ def file_search_handle(path)
# Workaround for CHEF-4419:
# Make sure paths starting with "/" has a drive letter
# assigned from the current working diretory.
# Note: With CHEF-4427 this issue will be fixed with a
# broader fix to map all the paths starting with "/" to
# SYSTEM_DRIVE on windows.
- path = ::File.expand_path(path) if path.start_with? "/"
- path = canonical_encode_path(path)
- find_data = WIN32_FIND_DATA.new
- handle = FindFirstFileW(path, find_data)
- if handle == INVALID_HANDLE_VALUE
- Chef::ReservedNames::Win32::Error.raise!
- end
- block.call(handle, find_data)
- ensure
- FindClose(handle) if handle && handle != INVALID_HANDLE_VALUE
+ path = ::File.expand_path(path) if path.start_with? "/"
+ path = canonical_encode_path(path)
+ find_data = WIN32_FIND_DATA.new
+ handle = FindFirstFileW(path, find_data)
+ if handle == INVALID_HANDLE_VALUE
+ Chef::ReservedNames::Win32::Error.raise!
end
+ yield(handle, find_data)
+ ensure
+ FindClose(handle) if handle && handle != INVALID_HANDLE_VALUE
end
# retrieves a file handle and passes it
# to +&block+ along with the find_data. also
# ensures the handle is closed on exit of the block
- def file_handle(path, &block)
- begin
- path = canonical_encode_path(path)
- handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
- nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, nil)
-
- if handle == INVALID_HANDLE_VALUE
- Chef::ReservedNames::Win32::Error.raise!
- end
- block.call(handle)
- ensure
- CloseHandle(handle) if handle && handle != INVALID_HANDLE_VALUE
+ # FIXME: yard with @yield
+ def file_handle(path)
+ path = canonical_encode_path(path)
+ handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
+ nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, nil)
+
+ if handle == INVALID_HANDLE_VALUE
+ Chef::ReservedNames::Win32::Error.raise!
end
+ yield(handle)
+ ensure
+ CloseHandle(handle) if handle && handle != INVALID_HANDLE_VALUE
end
- def symlink_file_handle(path, &block)
- begin
- path = encode_path(path)
- handle = CreateFileW(path, FILE_READ_EA, FILE_SHARE_READ,
- nil, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nil)
+ # FIXME: yard with @yield
+ def symlink_file_handle(path)
+ path = encode_path(path)
+ handle = CreateFileW(path, FILE_READ_EA, FILE_SHARE_READ,
+ nil, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nil)
- if handle == INVALID_HANDLE_VALUE
- Chef::ReservedNames::Win32::Error.raise!
- end
- block.call(handle)
- ensure
- CloseHandle(handle) if handle && handle != INVALID_HANDLE_VALUE
+ if handle == INVALID_HANDLE_VALUE
+ Chef::ReservedNames::Win32::Error.raise!
end
+ yield(handle)
+ ensure
+ CloseHandle(handle) if handle && handle != INVALID_HANDLE_VALUE
end
def retrieve_file_info(file_name)
@@ -565,6 +598,21 @@ BOOL WINAPI DeviceIoControl(
file_information
end
+ def retrieve_file_version_info(file_name)
+ file_name = encode_path(file_name)
+ file_size = GetFileVersionInfoSizeW(file_name, nil)
+ if file_size == 0
+ Chef::ReservedNames::Win32::Error.raise!
+ end
+
+ version_info = FFI::MemoryPointer.new(file_size)
+ unless GetFileVersionInfoW(file_name, 0, file_size, version_info)
+ Chef::ReservedNames::Win32::Error.raise!
+ end
+
+ version_info
+ end
+
end
end
end
diff --git a/lib/chef/win32/api/installer.rb b/lib/chef/win32/api/installer.rb
index b4851eccf1..46930b65fc 100644
--- a/lib/chef/win32/api/installer.rb
+++ b/lib/chef/win32/api/installer.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'chef/exceptions'
-require 'chef/win32/api'
-require 'chef/win32/error'
-require 'pathname'
+require "chef/exceptions"
+require "chef/win32/api"
+require "chef/win32/error"
+require "pathname"
class Chef
module ReservedNames::Win32
@@ -32,12 +32,11 @@ class Chef
# Win32 API Constants
###############################################
-
###############################################
# Win32 API Bindings
###############################################
- ffi_lib 'msi'
+ ffi_lib "msi"
=begin
UINT MsiOpenPackage(
@@ -94,7 +93,7 @@ UINT MsiCloseHandle(
msg << Chef::ReservedNames::Win32::Error.format_message(status)
raise Chef::Exceptions::Package, msg
end
-
+
buffer_length = FFI::Buffer.new(:long).write_long(buffer_length.read_long + 1)
buffer = 0.chr * buffer_length.read_long
@@ -108,24 +107,24 @@ UINT MsiCloseHandle(
end
msi_close_handle(pkg_ptr.read_pointer)
- return buffer.chomp(0.chr)
+ buffer.chomp(0.chr)
end
# Opens a Microsoft Installer (MSI) file from an absolute path and returns a pointer to a handle
# Remember to close the handle with msi_close_handle()
def open_package(package_path)
- # MsiOpenPackage expects a perfect absolute Windows path to the MSI
+ # MsiOpenPackage expects a perfect absolute Windows path to the MSI
raise ArgumentError, "Provided path '#{package_path}' must be an absolute path" unless Pathname.new(package_path).absolute?
pkg_ptr = FFI::MemoryPointer.new(:pointer, 4)
status = msi_open_package(package_path, 1, pkg_ptr)
case status
- when 0
+ when 0
# success
else
raise Chef::Exceptions::Package, "msi_open_package: unexpected status #{status}: #{Chef::ReservedNames::Win32::Error.format_message(status)}"
end
- return pkg_ptr
+ pkg_ptr
end
# All installed product_codes should have a VersionString
@@ -133,11 +132,11 @@ UINT MsiCloseHandle(
def get_installed_version(product_code)
version = 0.chr
version_length = FFI::Buffer.new(:long).write_long(0)
-
+
status = msi_get_product_info(product_code, "VersionString", version, version_length)
-
+
return nil if status == 1605 # ERROR_UNKNOWN_PRODUCT (0x645)
-
+
# We expect error ERROR_MORE_DATA (234) here because we passed a buffer length of 0
if status != 234
msg = "msi_get_product_info: product code '#{product_code}' returned unknown error #{status} when retrieving VersionString: "
@@ -149,9 +148,9 @@ UINT MsiCloseHandle(
version_length = FFI::Buffer.new(:long).write_long(version_length.read_long + 1)
version = 0.chr * version_length.read_long
-
+
status = msi_get_product_info(product_code, "VersionString", version, version_length)
-
+
if status != 0
msg = "msi_get_product_info: product code '#{product_code}' returned unknown error #{status} when retrieving VersionString: "
msg << Chef::ReservedNames::Win32::Error.format_message(status)
diff --git a/lib/chef/win32/api/memory.rb b/lib/chef/win32/api/memory.rb
index abd1191718..a00ac5fec8 100644
--- a/lib/chef/win32/api/memory.rb
+++ b/lib/chef/win32/api/memory.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/win32/api'
+require "chef/win32/api"
class Chef
module ReservedNames::Win32
@@ -48,7 +48,7 @@ class Chef
# Win32 API Bindings
###############################################
- ffi_lib 'kernel32'
+ ffi_lib "kernel32"
=begin
HLOCAL WINAPI LocalAlloc(
diff --git a/lib/chef/win32/api/net.rb b/lib/chef/win32/api/net.rb
index b173987a05..abf0dd83ec 100644
--- a/lib/chef/win32/api/net.rb
+++ b/lib/chef/win32/api/net.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@getchef.com>)
-# Copyright:: Copyright 2014 Chef Software, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/win32/api'
-require 'chef/win32/unicode'
+require "chef/win32/api"
+require "chef/win32/unicode"
class Chef
module ReservedNames::Win32
@@ -45,17 +45,7 @@ class Chef
USE_FORCE = 1
USE_LOTS_OF_FORCE = 2 #every windows API should support this flag
- NERR_Success = 0
- NERR_InvalidComputer = 2351
- NERR_NotPrimary = 2226
- NERR_SpeGroupOp = 2234
- NERR_LastAdmin = 2452
- NERR_BadUsername = 2202
- NERR_BadPassword = 2203
- NERR_PasswordTooShort = 2245
- NERR_UserNotFound = 2221
- NERR_GroupNotFound = 2220
- ERROR_ACCESS_DENIED = 5
+ NERR_Success = 0 # rubocop:disable Style/ConstantName
ERROR_MORE_DATA = 234
ffi_lib "netapi32"
@@ -63,21 +53,21 @@ class Chef
module StructHelpers
def set(key, val)
val = if val.is_a? String
- encoded = if val.encoding == Encoding::UTF_16LE
- val
- else
- val.to_wstring
- end
- FFI::MemoryPointer.from_string(encoded)
- else
- val
- end
+ encoded = if val.encoding == Encoding::UTF_16LE
+ val
+ else
+ val.to_wstring
+ end
+ FFI::MemoryPointer.from_string(encoded)
+ else
+ val
+ end
self[key] = val
end
def get(key)
if respond_to? key
- send(key)
+ send(key)
else
val = self[key]
if val.is_a? FFI::Pointer
@@ -100,7 +90,6 @@ class Chef
end
end
-
class USER_INFO_3 < FFI::Struct
include StructHelpers
layout :usri3_name, :LPWSTR,
@@ -169,154 +158,153 @@ class Chef
:ui2_domainname, :LMSTR
end
-
-#NET_API_STATUS NetLocalGroupAdd(
- #_In_ LPCWSTR servername,
- #_In_ DWORD level,
- #_In_ LPBYTE buf,
- #_Out_ LPDWORD parm_err
-#);
+ #NET_API_STATUS NetLocalGroupAdd(
+ #_In_ LPCWSTR servername,
+ #_In_ DWORD level,
+ #_In_ LPBYTE buf,
+ #_Out_ LPDWORD parm_err
+ #);
safe_attach_function :NetLocalGroupAdd, [
:LPCWSTR, :DWORD, :LPBYTE, :LPDWORD
], :DWORD
-#NET_API_STATUS NetLocalGroupDel(
- #_In_ LPCWSTR servername,
- #_In_ LPCWSTR groupname
-#);
+ #NET_API_STATUS NetLocalGroupDel(
+ #_In_ LPCWSTR servername,
+ #_In_ LPCWSTR groupname
+ #);
safe_attach_function :NetLocalGroupDel, [:LPCWSTR, :LPCWSTR], :DWORD
-#NET_API_STATUS NetLocalGroupGetMembers(
- #_In_ LPCWSTR servername,
- #_In_ LPCWSTR localgroupname,
- #_In_ DWORD level,
- #_Out_ LPBYTE *bufptr,
- #_In_ DWORD prefmaxlen,
- #_Out_ LPDWORD entriesread,
- #_Out_ LPDWORD totalentries,
- #_Inout_ PDWORD_PTR resumehandle
-#);
+ #NET_API_STATUS NetLocalGroupGetMembers(
+ #_In_ LPCWSTR servername,
+ #_In_ LPCWSTR localgroupname,
+ #_In_ DWORD level,
+ #_Out_ LPBYTE *bufptr,
+ #_In_ DWORD prefmaxlen,
+ #_Out_ LPDWORD entriesread,
+ #_Out_ LPDWORD totalentries,
+ #_Inout_ PDWORD_PTR resumehandle
+ #);
safe_attach_function :NetLocalGroupGetMembers, [
:LPCWSTR, :LPCWSTR, :DWORD, :LPBYTE, :DWORD,
:LPDWORD, :LPDWORD, :PDWORD_PTR
], :DWORD
-# NET_API_STATUS NetUserEnum(
-# _In_ LPCWSTR servername,
-# _In_ DWORD level,
-# _In_ DWORD filter,
-# _Out_ LPBYTE *bufptr,
-# _In_ DWORD prefmaxlen,
-# _Out_ LPDWORD entriesread,
-# _Out_ LPDWORD totalentries,
-# _Inout_ LPDWORD resume_handle
-# );
+ # NET_API_STATUS NetUserEnum(
+ # _In_ LPCWSTR servername,
+ # _In_ DWORD level,
+ # _In_ DWORD filter,
+ # _Out_ LPBYTE *bufptr,
+ # _In_ DWORD prefmaxlen,
+ # _Out_ LPDWORD entriesread,
+ # _Out_ LPDWORD totalentries,
+ # _Inout_ LPDWORD resume_handle
+ # );
safe_attach_function :NetUserEnum, [
:LPCWSTR, :DWORD, :DWORD, :LPBYTE,
:DWORD, :LPDWORD, :LPDWORD, :LPDWORD
], :DWORD
-# NET_API_STATUS NetApiBufferFree(
-# _In_ LPVOID Buffer
-# );
+ # NET_API_STATUS NetApiBufferFree(
+ # _In_ LPVOID Buffer
+ # );
safe_attach_function :NetApiBufferFree, [:LPVOID], :DWORD
-#NET_API_STATUS NetUserAdd(
- #_In_ LMSTR servername,
- #_In_ DWORD level,
- #_In_ LPBYTE buf,
- #_Out_ LPDWORD parm_err
-#);
+ #NET_API_STATUS NetUserAdd(
+ #_In_ LMSTR servername,
+ #_In_ DWORD level,
+ #_In_ LPBYTE buf,
+ #_Out_ LPDWORD parm_err
+ #);
safe_attach_function :NetUserAdd, [
:LMSTR, :DWORD, :LPBYTE, :LPDWORD
], :DWORD
-#NET_API_STATUS NetLocalGroupAddMembers(
-# _In_ LPCWSTR servername,
-# _In_ LPCWSTR groupname,
-# _In_ DWORD level,
-# _In_ LPBYTE buf,
-# _In_ DWORD totalentries
-#);
+ #NET_API_STATUS NetLocalGroupAddMembers(
+ # _In_ LPCWSTR servername,
+ # _In_ LPCWSTR groupname,
+ # _In_ DWORD level,
+ # _In_ LPBYTE buf,
+ # _In_ DWORD totalentries
+ #);
safe_attach_function :NetLocalGroupAddMembers, [
:LPCWSTR, :LPCWSTR, :DWORD, :LPBYTE, :DWORD
], :DWORD
-#NET_API_STATUS NetLocalGroupSetMembers(
-# _In_ LPCWSTR servername,
-# _In_ LPCWSTR groupname,
-# _In_ DWORD level,
-# _In_ LPBYTE buf,
-# _In_ DWORD totalentries
-#);
+ #NET_API_STATUS NetLocalGroupSetMembers(
+ # _In_ LPCWSTR servername,
+ # _In_ LPCWSTR groupname,
+ # _In_ DWORD level,
+ # _In_ LPBYTE buf,
+ # _In_ DWORD totalentries
+ #);
safe_attach_function :NetLocalGroupSetMembers, [
:LPCWSTR, :LPCWSTR, :DWORD, :LPBYTE, :DWORD
], :DWORD
-#NET_API_STATUS NetLocalGroupDelMembers(
-# _In_ LPCWSTR servername,
-# _In_ LPCWSTR groupname,
-# _In_ DWORD level,
-# _In_ LPBYTE buf,
-# _In_ DWORD totalentries
-#);
+ #NET_API_STATUS NetLocalGroupDelMembers(
+ # _In_ LPCWSTR servername,
+ # _In_ LPCWSTR groupname,
+ # _In_ DWORD level,
+ # _In_ LPBYTE buf,
+ # _In_ DWORD totalentries
+ #);
safe_attach_function :NetLocalGroupDelMembers, [
:LPCWSTR, :LPCWSTR, :DWORD, :LPBYTE, :DWORD
], :DWORD
-#NET_API_STATUS NetUserGetInfo(
-# _In_ LPCWSTR servername,
-# _In_ LPCWSTR username,
-# _In_ DWORD level,
-# _Out_ LPBYTE *bufptr
-#);
+ #NET_API_STATUS NetUserGetInfo(
+ # _In_ LPCWSTR servername,
+ # _In_ LPCWSTR username,
+ # _In_ DWORD level,
+ # _Out_ LPBYTE *bufptr
+ #);
safe_attach_function :NetUserGetInfo, [
:LPCWSTR, :LPCWSTR, :DWORD, :LPBYTE
], :DWORD
-#NET_API_STATUS NetApiBufferFree(
-# _In_ LPVOID Buffer
-#);
+ #NET_API_STATUS NetApiBufferFree(
+ # _In_ LPVOID Buffer
+ #);
safe_attach_function :NetApiBufferFree, [:LPVOID], :DWORD
-#NET_API_STATUS NetUserSetInfo(
-# _In_ LPCWSTR servername,
-# _In_ LPCWSTR username,
-# _In_ DWORD level,
-# _In_ LPBYTE buf,
-# _Out_ LPDWORD parm_err
-#);
+ #NET_API_STATUS NetUserSetInfo(
+ # _In_ LPCWSTR servername,
+ # _In_ LPCWSTR username,
+ # _In_ DWORD level,
+ # _In_ LPBYTE buf,
+ # _Out_ LPDWORD parm_err
+ #);
safe_attach_function :NetUserSetInfo, [
:LPCWSTR, :LPCWSTR, :DWORD, :LPBYTE, :LPDWORD
], :DWORD
-#NET_API_STATUS NetUserDel(
-# _In_ LPCWSTR servername,
-# _In_ LPCWSTR username
-#);
+ #NET_API_STATUS NetUserDel(
+ # _In_ LPCWSTR servername,
+ # _In_ LPCWSTR username
+ #);
safe_attach_function :NetUserDel, [:LPCWSTR, :LPCWSTR], :DWORD
-#NET_API_STATUS NetUseDel(
- #_In_ LMSTR UncServerName,
- #_In_ LMSTR UseName,
- #_In_ DWORD ForceCond
-#);
+ #NET_API_STATUS NetUseDel(
+ #_In_ LMSTR UncServerName,
+ #_In_ LMSTR UseName,
+ #_In_ DWORD ForceCond
+ #);
safe_attach_function :NetUseDel, [:LMSTR, :LMSTR, :DWORD], :DWORD
-#NET_API_STATUS NetUseGetInfo(
- #_In_ LMSTR UncServerName,
- #_In_ LMSTR UseName,
- #_In_ DWORD Level,
- #_Out_ LPBYTE *BufPtr
-#);
+ #NET_API_STATUS NetUseGetInfo(
+ #_In_ LMSTR UncServerName,
+ #_In_ LMSTR UseName,
+ #_In_ DWORD Level,
+ #_Out_ LPBYTE *BufPtr
+ #);
safe_attach_function :NetUseGetInfo, [:LMSTR, :LMSTR, :DWORD, :pointer], :DWORD
-#NET_API_STATUS NetUseAdd(
- #_In_ LMSTR UncServerName,
- #_In_ DWORD Level,
- #_In_ LPBYTE Buf,
- #_Out_ LPDWORD ParmError
-#);
+ #NET_API_STATUS NetUseAdd(
+ #_In_ LMSTR UncServerName,
+ #_In_ DWORD Level,
+ #_In_ LPBYTE Buf,
+ #_Out_ LPDWORD ParmError
+ #);
safe_attach_function :NetUseAdd, [:LMSTR, :DWORD, :LPBYTE, :LPDWORD], :DWORD
end
end
diff --git a/lib/chef/win32/api/process.rb b/lib/chef/win32/api/process.rb
index 217880b737..3568b7e76c 100644
--- a/lib/chef/win32/api/process.rb
+++ b/lib/chef/win32/api/process.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/win32/api'
+require "chef/win32/api"
class Chef
module ReservedNames::Win32
@@ -28,7 +28,7 @@ class Chef
# Win32 API Bindings
###############################################
- ffi_lib 'kernel32'
+ ffi_lib "kernel32"
safe_attach_function :GetCurrentProcess, [], :HANDLE
safe_attach_function :GetProcessHandleCount, [ :HANDLE, :LPDWORD ], :BOOL
diff --git a/lib/chef/win32/api/psapi.rb b/lib/chef/win32/api/psapi.rb
index 3a5df3f179..9deb68d92e 100644
--- a/lib/chef/win32/api/psapi.rb
+++ b/lib/chef/win32/api/psapi.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/win32/api'
+require "chef/win32/api"
class Chef
module ReservedNames::Win32
@@ -41,7 +41,7 @@ class Chef
:PeakPagefileUsage, :SIZE_T
end
- ffi_lib 'psapi'
+ ffi_lib "psapi"
safe_attach_function :GetProcessMemoryInfo, [ :HANDLE, :pointer, :DWORD ], :BOOL
diff --git a/lib/chef/win32/api/registry.rb b/lib/chef/win32/api/registry.rb
index cbbf6b66bb..dec25118a3 100644
--- a/lib/chef/win32/api/registry.rb
+++ b/lib/chef/win32/api/registry.rb
@@ -1,6 +1,6 @@
#
# Author:: Salim Alam (<salam@chef.io>)
-# Copyright:: Copyright 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/win32/api'
+require "chef/win32/api"
class Chef
module ReservedNames::Win32
@@ -28,7 +28,7 @@ class Chef
# Win32 API Bindings
###############################################
- ffi_lib 'advapi32'
+ ffi_lib "advapi32"
# LONG WINAPI RegDeleteKeyEx(
# _In_ HKEY hKey,
@@ -48,4 +48,4 @@ class Chef
end
end
end
-end \ No newline at end of file
+end
diff --git a/lib/chef/win32/api/security.rb b/lib/chef/win32/api/security.rb
index 4c352a3554..a2cfe35dad 100644
--- a/lib/chef/win32/api/security.rb
+++ b/lib/chef/win32/api/security.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/win32/api'
+require "chef/win32/api"
class Chef
module ReservedNames::Win32
@@ -133,23 +133,13 @@ class Chef
FILE_READ_ATTRIBUTES = 0x0080
FILE_WRITE_ATTRIBUTES = 0x0100
FILE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
- SYNCHRONIZE |
- 0x1FF
+ SYNCHRONIZE |
+ 0x1FF
FILE_GENERIC_READ = STANDARD_RIGHTS_READ |
- FILE_READ_DATA |
- FILE_READ_ATTRIBUTES |
- FILE_READ_EA |
- SYNCHRONIZE
- FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE |
- FILE_WRITE_DATA |
- FILE_WRITE_ATTRIBUTES |
- FILE_WRITE_EA |
- FILE_APPEND_DATA |
- SYNCHRONIZE
- FILE_GENERIC_EXECUTE = STANDARD_RIGHTS_EXECUTE |
- FILE_READ_ATTRIBUTES |
- FILE_EXECUTE |
- SYNCHRONIZE
+ FILE_READ_DATA | FILE_READ_ATTRIBUTES |
+ FILE_READ_EA | SYNCHRONIZE
+ FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE
+ FILE_GENERIC_EXECUTE = STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE
# Access Token Rights (for OpenProcessToken)
# Access Rights for Access-Token Objects (used in OpenProcessToken)
TOKEN_ASSIGN_PRIMARY = 0x0001
@@ -173,9 +163,7 @@ class Chef
SE_PRIVILEGE_REMOVED = 0X00000004
SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000
SE_PRIVILEGE_VALID_ATTRIBUTES = SE_PRIVILEGE_ENABLED_BY_DEFAULT |
- SE_PRIVILEGE_ENABLED |
- SE_PRIVILEGE_REMOVED |
- SE_PRIVILEGE_USED_FOR_ACCESS
+ SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED | SE_PRIVILEGE_USED_FOR_ACCESS
# Minimum size of a SECURITY_DESCRIPTOR. TODO: this is probably platform dependent.
# Make it work on 64 bit.
@@ -194,18 +182,33 @@ class Chef
MAXDWORD = 0xffffffff
# LOGON32 constants for LogonUser
- LOGON32_LOGON_INTERACTIVE = 2;
- LOGON32_LOGON_NETWORK = 3;
- LOGON32_LOGON_BATCH = 4;
- LOGON32_LOGON_SERVICE = 5;
- LOGON32_LOGON_UNLOCK = 7;
- LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
- LOGON32_LOGON_NEW_CREDENTIALS = 9;
-
- LOGON32_PROVIDER_DEFAULT = 0;
- LOGON32_PROVIDER_WINNT35 = 1;
- LOGON32_PROVIDER_WINNT40 = 2;
- LOGON32_PROVIDER_WINNT50 = 3;
+ LOGON32_LOGON_INTERACTIVE = 2
+ LOGON32_LOGON_NETWORK = 3
+ LOGON32_LOGON_BATCH = 4
+ LOGON32_LOGON_SERVICE = 5
+ LOGON32_LOGON_UNLOCK = 7
+ LOGON32_LOGON_NETWORK_CLEARTEXT = 8
+ LOGON32_LOGON_NEW_CREDENTIALS = 9
+
+ LOGON32_PROVIDER_DEFAULT = 0
+ LOGON32_PROVIDER_WINNT35 = 1
+ LOGON32_PROVIDER_WINNT40 = 2
+ LOGON32_PROVIDER_WINNT50 = 3
+
+ # LSA access policy
+ POLICY_VIEW_LOCAL_INFORMATION = 0x00000001
+ POLICY_VIEW_AUDIT_INFORMATION = 0x00000002
+ POLICY_GET_PRIVATE_INFORMATION = 0x00000004
+ POLICY_TRUST_ADMIN = 0x00000008
+ POLICY_CREATE_ACCOUNT = 0x00000010
+ POLICY_CREATE_SECRET = 0x00000020
+ POLICY_CREATE_PRIVILEGE = 0x00000040
+ POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080
+ POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100
+ POLICY_AUDIT_LOG_ADMIN = 0x00000200
+ POLICY_SERVER_ADMIN = 0x00000400
+ POLICY_LOOKUP_NAMES = 0x00000800
+ POLICY_NOTIFICATION = 0x00001000
###############################################
# Win32 API Bindings
@@ -224,7 +227,7 @@ class Chef
:SE_DS_OBJECT_ALL,
:SE_PROVIDER_DEFINED_OBJECT,
:SE_WMIGUID_OBJECT,
- :SE_REGISTRY_WOW64_32KEY
+ :SE_REGISTRY_WOW64_32KEY,
]
SID_NAME_USE = enum :SID_NAME_USE, [
@@ -297,10 +300,9 @@ class Chef
:SecurityAnonymous,
:SecurityIdentification,
:SecurityImpersonation,
- :SecurityDelegation
+ :SecurityDelegation,
]
-
# SECURITY_DESCRIPTOR is an opaque structure whose contents can vary. Pass the
# pointer around and free it with LocalFree.
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa379561(v=vs.85).aspx
@@ -336,7 +338,7 @@ class Chef
ACCESS_ALLOWED_ACE_TYPE,
ACCESS_DENIED_ACE_TYPE,
SYSTEM_AUDIT_ACE_TYPE,
- SYSTEM_ALARM_ACE_TYPE
+ SYSTEM_ALARM_ACE_TYPE,
].include?(ace_type)
end
end
@@ -369,7 +371,7 @@ class Chef
:Privileges, LUID_AND_ATTRIBUTES
def self.size_with_privileges(num_privileges)
- offset_of(:Privileges) + LUID_AND_ATTRIBUTES.size*num_privileges
+ offset_of(:Privileges) + LUID_AND_ATTRIBUTES.size * num_privileges
end
def size_with_privileges
@@ -381,6 +383,23 @@ class Chef
end
end
+ # https://msdn.microsoft.com/en-us/library/windows/desktop/ms721829(v=vs.85).aspx
+ class LSA_OBJECT_ATTRIBUTES < FFI::Struct
+ layout :Length, :ULONG,
+ :RootDirectory, :HANDLE,
+ :ObjectName, :pointer,
+ :Attributes, :ULONG,
+ :SecurityDescriptor, :PVOID,
+ :SecurityQualityOfService, :PVOID
+ end
+
+ # https://msdn.microsoft.com/en-us/library/windows/desktop/ms721841(v=vs.85).aspx
+ class LSA_UNICODE_STRING < FFI::Struct
+ layout :Length, :USHORT,
+ :MaximumLength, :USHORT,
+ :Buffer, :PWSTR
+ end
+
ffi_lib "advapi32"
safe_attach_function :AccessCheck, [:pointer, :HANDLE, :DWORD, :pointer, :pointer, :pointer, :pointer, :pointer], :BOOL
@@ -399,7 +418,7 @@ class Chef
safe_attach_function :GetAce, [ :pointer, :DWORD, :pointer ], :BOOL
safe_attach_function :GetFileSecurityW, [:LPCWSTR, :DWORD, :pointer, :DWORD, :pointer], :BOOL
safe_attach_function :GetLengthSid, [ :pointer ], :DWORD
- safe_attach_function :GetNamedSecurityInfoW, [ :LPWSTR, :SE_OBJECT_TYPE, :DWORD, :pointer, :pointer, :pointer, :pointer, :pointer ], :DWORD
+ safe_attach_function :GetNamedSecurityInfoW, [ :LPWSTR, :SE_OBJECT_TYPE, :DWORD, :pointer, :pointer, :pointer, :pointer, :pointer ], :DWORD
safe_attach_function :GetSecurityDescriptorControl, [ :pointer, :PWORD, :LPDWORD], :BOOL
safe_attach_function :GetSecurityDescriptorDacl, [ :pointer, :LPBOOL, :pointer, :LPBOOL ], :BOOL
safe_attach_function :GetSecurityDescriptorGroup, [ :pointer, :pointer, :LPBOOL], :BOOL
@@ -415,6 +434,12 @@ class Chef
safe_attach_function :LookupPrivilegeNameW, [ :LPCWSTR, :PLUID, :LPWSTR, :LPDWORD ], :BOOL
safe_attach_function :LookupPrivilegeDisplayNameW, [ :LPCWSTR, :LPCWSTR, :LPWSTR, :LPDWORD, :LPDWORD ], :BOOL
safe_attach_function :LookupPrivilegeValueW, [ :LPCWSTR, :LPCWSTR, :PLUID ], :BOOL
+ safe_attach_function :LsaAddAccountRights, [ :pointer, :pointer, :pointer, :ULONG ], :NTSTATUS
+ safe_attach_function :LsaClose, [ :LSA_HANDLE ], :NTSTATUS
+ safe_attach_function :LsaEnumerateAccountRights, [ :LSA_HANDLE, :PSID, :PLSA_UNICODE_STRING, :PULONG ], :NTSTATUS
+ safe_attach_function :LsaFreeMemory, [ :PVOID ], :NTSTATUS
+ safe_attach_function :LsaNtStatusToWinError, [ :NTSTATUS ], :ULONG
+ safe_attach_function :LsaOpenPolicy, [ :PLSA_UNICODE_STRING, :PLSA_OBJECT_ATTRIBUTES, :DWORD, :PLSA_HANDLE ], :NTSTATUS
safe_attach_function :MakeAbsoluteSD, [ :pointer, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD], :BOOL
safe_attach_function :MapGenericMask, [ :PDWORD, :PGENERICMAPPING ], :void
safe_attach_function :OpenProcessToken, [ :HANDLE, :DWORD, :PHANDLE ], :BOOL
diff --git a/lib/chef/win32/api/synchronization.rb b/lib/chef/win32/api/synchronization.rb
index 9c148d7e2b..9b5d5c6ab9 100644
--- a/lib/chef/win32/api/synchronization.rb
+++ b/lib/chef/win32/api/synchronization.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/win32/api'
+require "chef/win32/api"
class Chef
module ReservedNames::Win32
@@ -24,7 +24,7 @@ class Chef
module Synchronization
extend Chef::ReservedNames::Win32::API
- ffi_lib 'kernel32'
+ ffi_lib "kernel32"
# Constant synchronization functions use to indicate wait
# forever.
diff --git a/lib/chef/win32/api/system.rb b/lib/chef/win32/api/system.rb
index a485f89708..732ed073e6 100644
--- a/lib/chef/win32/api/system.rb
+++ b/lib/chef/win32/api/system.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/win32/api'
+require "chef/win32/api"
class Chef
module ReservedNames::Win32
@@ -132,7 +132,7 @@ class Chef
# Win32 API Bindings
###############################################
- ffi_lib 'kernel32', 'user32'
+ ffi_lib "kernel32", "user32"
class OSVERSIONINFOEX < FFI::Struct
layout :dw_os_version_info_size, :DWORD,
diff --git a/lib/chef/win32/api/unicode.rb b/lib/chef/win32/api/unicode.rb
index 2a9166aa99..21ddde2865 100644
--- a/lib/chef/win32/api/unicode.rb
+++ b/lib/chef/win32/api/unicode.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/win32/api'
+require "chef/win32/api"
class Chef
module ReservedNames::Win32
@@ -92,7 +92,7 @@ class Chef
# Win32 API Bindings
###############################################
- ffi_lib 'kernel32', 'advapi32'
+ ffi_lib "kernel32", "advapi32"
=begin
BOOL IsTextUnicode(
diff --git a/lib/chef/win32/crypto.rb b/lib/chef/win32/crypto.rb
index e9c1da954b..9832f9e67e 100644
--- a/lib/chef/win32/crypto.rb
+++ b/lib/chef/win32/crypto.rb
@@ -1,50 +1,50 @@
-#
-# Author:: Jay Mundrawala (<jdm@chef.io>)
-# Copyright:: Copyright 2015 Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/win32/error'
-require 'chef/win32/api/memory'
-require 'chef/win32/api/crypto'
-require 'chef/win32/unicode'
-require 'digest'
-
-class Chef
- module ReservedNames::Win32
- class Crypto
- include Chef::ReservedNames::Win32::API::Crypto
- extend Chef::ReservedNames::Win32::API::Crypto
-
- def self.encrypt(str, &block)
- data_blob = CRYPT_INTEGER_BLOB.new
- unless CryptProtectData(CRYPT_INTEGER_BLOB.new(str.to_wstring), nil, nil, nil, nil, CRYPTPROTECT_LOCAL_MACHINE, data_blob)
- Chef::ReservedNames::Win32::Error.raise!
- end
- bytes = data_blob[:pbData].get_bytes(0, data_blob[:cbData])
- if block
- block.call(bytes)
- else
- Digest.hexencode(bytes)
- end
- ensure
- unless data_blob[:pbData].null?
- Chef::ReservedNames::Win32::Memory.local_free(data_blob[:pbData])
- end
- end
-
- end
- end
-end
+#
+# Author:: Jay Mundrawala (<jdm@chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/win32/error"
+require "chef/win32/api/memory"
+require "chef/win32/api/crypto"
+require "chef/win32/unicode"
+require "digest"
+
+class Chef
+ module ReservedNames::Win32
+ class Crypto
+ include Chef::ReservedNames::Win32::API::Crypto
+ extend Chef::ReservedNames::Win32::API::Crypto
+
+ def self.encrypt(str, &block)
+ data_blob = CRYPT_INTEGER_BLOB.new
+ unless CryptProtectData(CRYPT_INTEGER_BLOB.new(str.to_wstring), nil, nil, nil, nil, CRYPTPROTECT_LOCAL_MACHINE, data_blob)
+ Chef::ReservedNames::Win32::Error.raise!
+ end
+ bytes = data_blob[:pbData].get_bytes(0, data_blob[:cbData])
+ if block
+ block.call(bytes)
+ else
+ Digest.hexencode(bytes)
+ end
+ ensure
+ unless data_blob[:pbData].null?
+ Chef::ReservedNames::Win32::Memory.local_free(data_blob[:pbData])
+ end
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/win32/error.rb b/lib/chef/win32/error.rb
index 2175608eeb..83d4583f1d 100644
--- a/lib/chef/win32/error.rb
+++ b/lib/chef/win32/error.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'chef/win32/api/error'
-require 'chef/win32/memory'
-require 'chef/win32/unicode'
-require 'chef/exceptions'
+require "chef/win32/api/error"
+require "chef/win32/memory"
+require "chef/win32/unicode"
+require "chef/exceptions"
class Chef
module ReservedNames::Win32
@@ -29,11 +29,21 @@ class Chef
def self.format_message(message_id = 0, args = {})
flags = args[:flags] || FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY
- source = args[:source]
+ flags |= FORMAT_MESSAGE_ALLOCATE_BUFFER
+ source = args[:source] || 0
language_id = args[:language_id] || 0
varargs = args[:varargs] || [:int, 0]
buffer = FFI::MemoryPointer.new :pointer
- num_chars = FormatMessageW(flags | FORMAT_MESSAGE_ALLOCATE_BUFFER, source, message_id, language_id, buffer, 0, *varargs)
+ num_chars = FormatMessageW(flags, source, message_id, language_id, buffer, 0, *varargs)
+ if num_chars == 0
+ source = LoadLibraryExW("netmsg.dll".to_wstring, 0, LOAD_LIBRARY_AS_DATAFILE)
+ begin
+ num_chars = FormatMessageW(flags | FORMAT_MESSAGE_FROM_HMODULE, source, message_id, language_id, buffer, 0, *varargs)
+ ensure
+ FreeLibrary(source)
+ end
+ end
+
if num_chars == 0
raise!
end
@@ -57,16 +67,19 @@ class Chef
# nil::: always returns nil when it does not raise
# === Raises
# Chef::Exceptions::Win32APIError:::
- def self.raise!(message = nil)
- code = get_last_error
+ def self.raise!(message = nil, code = get_last_error)
msg = format_message(code).strip
- formatted_message = ""
- formatted_message << message if message
- formatted_message << "---- Begin Win32 API output ----\n"
- formatted_message << "System Error Code: #{code}\n"
- formatted_message << "System Error Message: #{msg}\n"
- formatted_message << "---- End Win32 API output ----\n"
- raise Chef::Exceptions::Win32APIError, msg + "\n" + formatted_message
+ if code == ERROR_USER_NOT_FOUND
+ raise Chef::Exceptions::UserIDNotFound, msg
+ else
+ formatted_message = ""
+ formatted_message << message if message
+ formatted_message << "---- Begin Win32 API output ----\n"
+ formatted_message << "System Error Code: #{code}\n"
+ formatted_message << "System Error Message: #{msg}\n"
+ formatted_message << "---- End Win32 API output ----\n"
+ raise Chef::Exceptions::Win32APIError, msg + "\n" + formatted_message
+ end
end
end
end
diff --git a/lib/chef/win32/eventlog.rb b/lib/chef/win32/eventlog.rb
index 24af2da0d6..eae0ae4abf 100644
--- a/lib/chef/win32/eventlog.rb
+++ b/lib/chef/win32/eventlog.rb
@@ -1,7 +1,7 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
#
-# Copyright:: 2015, Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
# limitations under the License.
#
-if Chef::Platform::windows? and not Chef::Platform::windows_server_2003?
+if Chef::Platform.windows? && (not Chef::Platform.windows_server_2003?)
if !defined? Chef::Win32EventLogLoaded
if defined? Windows::Constants
[:INFINITE, :WAIT_FAILED, :FORMAT_MESSAGE_IGNORE_INSERTS, :ERROR_INSUFFICIENT_BUFFER].each do |c|
@@ -25,7 +25,7 @@ if Chef::Platform::windows? and not Chef::Platform::windows_server_2003?
end
end
- require 'win32/eventlog'
- Chef::Win32EventLogLoaded = true
+ require "win32/eventlog"
+ Chef::Win32EventLogLoaded = true # rubocop:disable Style/ConstantName
end
end
diff --git a/lib/chef/win32/file.rb b/lib/chef/win32/file.rb
index 700ddb24d3..fa3d0f7a9d 100644
--- a/lib/chef/win32/file.rb
+++ b/lib/chef/win32/file.rb
@@ -1,7 +1,7 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
+# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Mark Mzyk (<mmzyk@ospcode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +17,11 @@
# limitations under the License.
#
-require 'chef/mixin/wide_string'
-require 'chef/win32/api/file'
-require 'chef/win32/api/security'
-require 'chef/win32/error'
-require 'chef/win32/unicode'
+require "chef/mixin/wide_string"
+require "chef/win32/api/file"
+require "chef/win32/api/security"
+require "chef/win32/error"
+require "chef/win32/unicode"
class Chef
module ReservedNames::Win32
@@ -39,7 +39,7 @@ class Chef
# returns nil as per MRI.
#
def self.link(old_name, new_name)
- raise Errno::ENOENT, "(#{old_name}, #{new_name})" unless ::File.exist?(old_name)
+ raise Errno::ENOENT, "(#{old_name}, #{new_name})" unless ::File.exist?(old_name) || ::File.symlink?(old_name)
# TODO do a check for CreateHardLinkW and
# raise NotImplemented exception on older Windows
old_name = encode_path(old_name)
@@ -56,7 +56,7 @@ class Chef
# returns nil as per MRI.
#
def self.symlink(old_name, new_name)
- # raise Errno::ENOENT, "(#{old_name}, #{new_name})" unless ::File.exist?(old_name)
+ # raise Errno::ENOENT, "(#{old_name}, #{new_name})" unless ::File.exist?(old_name) || ::File.symlink?(old_name)
# TODO do a check for CreateSymbolicLinkW and
# raise NotImplemented exception on older Windows
flags = ::File.directory?(old_name) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0
@@ -75,8 +75,8 @@ class Chef
def self.symlink?(file_name)
is_symlink = false
path = encode_path(file_name)
- if ::File.exists?(file_name)
- if ((GetFileAttributesW(path) & FILE_ATTRIBUTE_REPARSE_POINT) > 0)
+ if ::File.exists?(file_name) || ::File.symlink?(file_name)
+ if (GetFileAttributesW(path) & FILE_ATTRIBUTE_REPARSE_POINT) > 0
file_search_handle(file_name) do |handle, find_data|
if find_data[:dw_reserved_0] == IO_REPARSE_TAG_SYMLINK
is_symlink = true
@@ -93,7 +93,7 @@ class Chef
# will raise a NotImplementedError, as per MRI.
#
def self.readlink(link_name)
- raise Errno::ENOENT, link_name unless ::File.exists?(link_name)
+ raise Errno::ENOENT, link_name unless ::File.exists?(link_name) || ::File.symlink?(link_name)
symlink_file_handle(link_name) do |handle|
# Go to DeviceIoControl to get the symlink information
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa364571(v=vs.85).aspx
@@ -125,8 +125,8 @@ class Chef
if size == 0
Chef::ReservedNames::Win32::Error.raise!
end
- result = FFI::MemoryPointer.new :char, (size+1)*2
- if GetShortPathNameW(path, result, size+1) == 0
+ result = FFI::MemoryPointer.new :char, (size + 1) * 2
+ if GetShortPathNameW(path, result, size + 1) == 0
Chef::ReservedNames::Win32::Error.raise!
end
result.read_wstring(size)
@@ -139,8 +139,8 @@ class Chef
if size == 0
Chef::ReservedNames::Win32::Error.raise!
end
- result = FFI::MemoryPointer.new :char, (size+1)*2
- if GetLongPathNameW(path, result, size+1) == 0
+ result = FFI::MemoryPointer.new :char, (size + 1) * 2
+ if GetLongPathNameW(path, result, size + 1) == 0
Chef::ReservedNames::Win32::Error.raise!
end
result.read_wstring(size)
@@ -150,22 +150,24 @@ class Chef
Info.new(file_name)
end
+ def self.version_info(file_name)
+ VersionInfo.new(file_name)
+ end
+
def self.verify_links_supported!
- begin
- CreateSymbolicLinkW(nil)
- rescue Chef::Exceptions::Win32APIFunctionNotImplemented => e
- raise e
- rescue Exception
+ CreateSymbolicLinkW(nil)
+ rescue Chef::Exceptions::Win32APIFunctionNotImplemented => e
+ raise e
+ rescue Exception
# things are ok.
- end
end
def self.file_access_check(path, desired_access)
security_descriptor = Chef::ReservedNames::Win32::Security.get_file_security(path)
token_rights = Chef::ReservedNames::Win32::Security::TOKEN_IMPERSONATE |
- Chef::ReservedNames::Win32::Security::TOKEN_QUERY |
- Chef::ReservedNames::Win32::Security::TOKEN_DUPLICATE |
- Chef::ReservedNames::Win32::Security::STANDARD_RIGHTS_READ
+ Chef::ReservedNames::Win32::Security::TOKEN_QUERY |
+ Chef::ReservedNames::Win32::Security::TOKEN_DUPLICATE |
+ Chef::ReservedNames::Win32::Security::STANDARD_RIGHTS_READ
token = Chef::ReservedNames::Win32::Security.open_process_token(
Chef::ReservedNames::Win32::Process.get_current_process,
token_rights)
@@ -195,7 +197,7 @@ class Chef
def self.get_volume_name_for_volume_mount_point(mount_point)
buffer = FFI::MemoryPointer.new(2, 128)
- unless GetVolumeNameForVolumeMountPointW(wstring(mount_point), buffer, buffer.size/buffer.type_size)
+ unless GetVolumeNameForVolumeMountPointW(wstring(mount_point), buffer, buffer.size / buffer.type_size)
Chef::ReservedNames::Win32::Error.raise!
end
buffer.read_wstring
@@ -210,4 +212,5 @@ class Chef
end
end
-require 'chef/win32/file/info'
+require "chef/win32/file/info"
+require "chef/win32/file/version_info"
diff --git a/lib/chef/win32/file/info.rb b/lib/chef/win32/file/info.rb
index 0f07428106..55873f8a0b 100644
--- a/lib/chef/win32/file/info.rb
+++ b/lib/chef/win32/file/info.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/win32/file'
+require "chef/win32/file"
class Chef
module ReservedNames::Win32
@@ -93,7 +93,6 @@ class Chef
file_time_struct[:dw_high_date_time]))
end
-
end
end
end
diff --git a/lib/chef/win32/file/version_info.rb b/lib/chef/win32/file/version_info.rb
new file mode 100644
index 0000000000..fa04096cf1
--- /dev/null
+++ b/lib/chef/win32/file/version_info.rb
@@ -0,0 +1,93 @@
+#
+# Author:: Matt Wrock (<matt@mattwrock.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/win32/file"
+
+class Chef
+ module ReservedNames::Win32
+ class File
+
+ class VersionInfo
+
+ include Chef::ReservedNames::Win32::API::File
+
+ def initialize(file_name)
+ raise Errno::ENOENT, file_name unless ::File.exist?(file_name)
+ @file_version_info = retrieve_file_version_info(file_name)
+ end
+
+ # defining method for each predefined version resource string
+ # see https://msdn.microsoft.com/en-us/library/windows/desktop/ms647464(v=vs.85).aspx
+ [
+ :Comments,
+ :CompanyName,
+ :FileDescription,
+ :FileVersion,
+ :InternalName,
+ :LegalCopyright,
+ :LegalTrademarks,
+ :OriginalFilename,
+ :ProductName,
+ :ProductVersion,
+ :PrivateBuild,
+ :SpecialBuild,
+ ].each do |method|
+ define_method method do
+ begin
+ get_version_info_string(method.to_s)
+ rescue Chef::Exceptions::Win32APIError
+ return nil
+ end
+ end
+ end
+
+ private
+
+ def translation
+ @translation ||= begin
+ info_ptr = FFI::MemoryPointer.new(:pointer)
+ unless VerQueryValueW(@file_version_info, "\\VarFileInfo\\Translation".to_wstring, info_ptr, FFI::MemoryPointer.new(:int))
+ Chef::ReservedNames::Win32::Error.raise!
+ end
+
+ # there can potentially be multiple translations but most installers just have one
+ # we use the first because we use this for the version strings which are language
+ # agnostic. If/when we need other fields, we should we should add logic to find
+ # the "best" translation
+ trans = Translation.new(info_ptr.read_pointer)
+ to_hex(trans[:w_lang]) + to_hex(trans[:w_code_page])
+ end
+ end
+
+ def to_hex(integer)
+ integer.to_s(16).rjust(4, "0")
+ end
+
+ def get_version_info_string(string_key)
+ info_ptr = FFI::MemoryPointer.new(:pointer)
+ size_ptr = FFI::MemoryPointer.new(:int)
+ unless VerQueryValueW(@file_version_info, "\\StringFileInfo\\#{translation}\\#{string_key}".to_wstring, info_ptr, size_ptr)
+ Chef::ReservedNames::Win32::Error.raise!
+ end
+
+ info_ptr.read_pointer.read_wstring(size_ptr.read_uint)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/win32/handle.rb b/lib/chef/win32/handle.rb
index 21a8fdf339..3ebb6983c4 100644
--- a/lib/chef/win32/handle.rb
+++ b/lib/chef/win32/handle.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'chef/win32/api/process'
-require 'chef/win32/api/psapi'
-require 'chef/win32/api/system'
-require 'chef/win32/error'
+require "chef/win32/api/process"
+require "chef/win32/api/psapi"
+require "chef/win32/api/system"
+require "chef/win32/error"
class Chef
module ReservedNames::Win32
diff --git a/lib/chef/win32/memory.rb b/lib/chef/win32/memory.rb
index 8a61d27ef0..2a9d5d8eb5 100644
--- a/lib/chef/win32/memory.rb
+++ b/lib/chef/win32/memory.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/win32/error'
-require 'chef/win32/api/memory'
+require "chef/win32/error"
+require "chef/win32/api/memory"
class Chef
module ReservedNames::Win32
@@ -35,7 +35,7 @@ class Chef
Chef::ReservedNames::Win32::Error.raise!
end
# If a block is passed, handle freeing the memory at the end
- if block != nil
+ if !block.nil?
begin
yield result
ensure
diff --git a/lib/chef/win32/mutex.rb b/lib/chef/win32/mutex.rb
index 0d8eba1b3c..a14a160f56 100644
--- a/lib/chef/win32/mutex.rb
+++ b/lib/chef/win32/mutex.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'chef/win32/api/synchronization'
-require 'chef/win32/unicode'
+require "chef/win32/api/synchronization"
+require "chef/win32/unicode"
class Chef
module ReservedNames::Win32
diff --git a/lib/chef/win32/net.rb b/lib/chef/win32/net.rb
index 59f29c4d1b..09db2af89d 100644
--- a/lib/chef/win32/net.rb
+++ b/lib/chef/win32/net.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala(<jdm@chef.io>)
-# Copyright:: Copyright 2015 Chef Software
+# Copyright:: Copyright 2015-2016, Chef Software
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/win32/api/net'
-require 'chef/win32/error'
-require 'chef/mixin/wide_string'
+require "chef/win32/api/net"
+require "chef/win32/error"
+require "chef/mixin/wide_string"
class Chef
module ReservedNames::Win32
@@ -40,7 +40,7 @@ class Chef
usri3_priv: 0,
usri3_home_dir: nil,
usri3_comment: nil,
- usri3_flags: UF_SCRIPT|UF_DONT_EXPIRE_PASSWD|UF_NORMAL_ACCOUNT,
+ usri3_flags: UF_SCRIPT | UF_DONT_EXPIRE_PASSWD | UF_NORMAL_ACCOUNT,
usri3_script_path: nil,
usri3_auth_flags: 0,
usri3_full_name: nil,
@@ -62,46 +62,13 @@ class Chef
usri3_primary_group_id: DOMAIN_GROUP_RID_USERS,
usri3_profile: nil,
usri3_home_dir_drive: nil,
- usri3_password_expired: 0
- }.each do |(k,v)|
+ usri3_password_expired: 0,
+ }.each do |(k, v)|
s.set(k, v)
end
end
end
- def self.net_api_error!(code)
- msg = case code
- when NERR_InvalidComputer
- "The user does not have access to the requested information."
- when NERR_NotPrimary
- "The operation is allowed only on the primary domain controller of the domain."
- when NERR_SpeGroupOp
- "This operation is not allowed on this special group."
- when NERR_LastAdmin
- "This operation is not allowed on the last administrative account."
- when NERR_BadUsername
- "The user name or group name parameter is invalid."
- when NERR_BadPassword
- "The password parameter is invalid."
- when NERR_UserNotFound
- raise Chef::Exceptions::UserIDNotFound, code
- when NERR_PasswordTooShort
- <<END
-The password is shorter than required. (The password could also be too
-long, be too recent in its change history, not have enough unique characters,
-or not meet another password policy requirement.)
-END
- when NERR_GroupNotFound
- "The group name could not be found."
- when ERROR_ACCESS_DENIED
- "The user does not have access to the requested information."
- else
- "Received unknown error code (#{code})"
- end
-
- raise Chef::Exceptions::Win32NetAPIError.new(msg, code)
- end
-
def self.net_local_group_add(server_name, group_name)
server_name = wstring(server_name)
group_name = wstring(group_name)
@@ -111,7 +78,7 @@ END
rc = NetLocalGroupAdd(server_name, 0, buf, nil)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
end
@@ -121,7 +88,7 @@ END
rc = NetLocalGroupDel(server_name, group_name)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
end
@@ -145,7 +112,7 @@ END
nread = entries_read_ptr.read_long
nread.times do |i|
member = LOCALGROUP_MEMBERS_INFO_0.new(buf.read_pointer +
- (i * LOCALGROUP_MEMBERS_INFO_0.size))
+ (i * LOCALGROUP_MEMBERS_INFO_0.size))
member_sid = Chef::ReservedNames::Win32::Security::SID.new(member[:lgrmi0_sid])
group_members << member_sid.to_s
end
@@ -153,7 +120,7 @@ END
end
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
group_members
@@ -170,7 +137,7 @@ END
rc = NetUserAdd(server_name, 3, buf, nil)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
end
@@ -183,7 +150,7 @@ END
rc = NetUserGetInfo(server_name, user_name, 3, ui3_p)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
ui3 = USER_INFO_3.new(ui3_p.read_pointer).as_ruby
@@ -191,7 +158,7 @@ END
rc = NetApiBufferFree(ui3_p.read_pointer)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
ui3
@@ -209,7 +176,7 @@ END
rc = NetUserSetInfo(server_name, user_name, 3, buf, nil)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
end
@@ -219,7 +186,7 @@ END
rc = NetUserDel(server_name, user_name)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
end
@@ -234,13 +201,13 @@ END
rc = NetLocalGroupAddMembers(server_name, group_name, 3, buf, 1)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
end
def self.members_to_lgrmi3(members)
buf = FFI::MemoryPointer.new(LOCALGROUP_MEMBERS_INFO_3, members.size)
- members.size.times.collect do |i|
+ Array.new(members.size) do |i|
member_info = LOCALGROUP_MEMBERS_INFO_3.new(
buf + i * LOCALGROUP_MEMBERS_INFO_3.size)
member_info[:lgrmi3_domainandname] = FFI::MemoryPointer.from_string(wstring(members[i]))
@@ -257,7 +224,7 @@ END
server_name, group_name, 3, lgrmi3s[0], members.size)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
end
@@ -270,7 +237,7 @@ END
server_name, group_name, 3, lgrmi3s[0], members.size)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
end
@@ -283,11 +250,11 @@ END
server_name, group_name, 3, lgrmi3s[0], members.size)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
end
- def self.net_use_del(server_name, use_name, force=:use_noforce)
+ def self.net_use_del(server_name, use_name, force = :use_noforce)
server_name = wstring(server_name)
use_name = wstring(use_name)
force_const = case force
@@ -303,7 +270,7 @@ END
rc = NetUseDel(server_name, use_name, force_const)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
end
@@ -314,7 +281,7 @@ END
rc = NetUseGetInfo(server_name, use_name, 2, ui2_p)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
ui2 = USE_INFO_2.new(ui2_p.read_pointer).as_ruby
@@ -329,13 +296,13 @@ END
buf = USE_INFO_2.new
- ui2_hash.each do |(k,v)|
- buf.set(k,v)
+ ui2_hash.each do |(k, v)|
+ buf.set(k, v)
end
rc = NetUseAdd(server_name, 2, buf, nil)
if rc != NERR_Success
- net_api_error!(rc)
+ Chef::ReservedNames::Win32::Error.raise!(nil, rc)
end
end
end
diff --git a/lib/chef/win32/process.rb b/lib/chef/win32/process.rb
index 767d4f390c..76e526340b 100644
--- a/lib/chef/win32/process.rb
+++ b/lib/chef/win32/process.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'chef/win32/api/process'
-require 'chef/win32/api/psapi'
-require 'chef/win32/error'
-require 'chef/win32/handle'
-require 'ffi'
+require "chef/win32/api/process"
+require "chef/win32/api/psapi"
+require "chef/win32/error"
+require "chef/win32/handle"
+require "ffi"
class Chef
module ReservedNames::Win32
diff --git a/lib/chef/win32/registry.rb b/lib/chef/win32/registry.rb
index 12ad08a965..6f1eb9ff12 100644
--- a/lib/chef/win32/registry.rb
+++ b/lib/chef/win32/registry.rb
@@ -1,8 +1,8 @@
#
-# Author:: Prajakta Purohit (<prajakta@opscode.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
+# Author:: Prajakta Purohit (<prajakta@chef.io>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
#
-# Copyright:: 2012, Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,15 +16,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/reserved_names'
-require 'chef/win32/api'
-require 'chef/mixin/wide_string'
+require "chef/reserved_names"
+require "chef/win32/api"
+require "chef/mixin/wide_string"
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
- require 'chef/monkey_patches/win32/registry'
- require 'chef/win32/api/registry'
- require 'win32/registry'
- require 'win32/api'
+ require "chef/monkey_patches/win32/registry"
+ require "chef/win32/api/registry"
+ require "win32/registry"
+ require "win32/api"
end
class Chef
@@ -42,7 +42,7 @@ class Chef
attr_accessor :run_context
attr_accessor :architecture
- def initialize(run_context=nil, user_architecture=:machine)
+ def initialize(run_context = nil, user_architecture = :machine)
@run_context = run_context
self.architecture = user_architecture
end
@@ -56,12 +56,14 @@ class Chef
hive, key = get_hive_and_key(key_path)
key_exists!(key_path)
values = hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
- reg.map { |name, type, data| {:name=>name, :type=>get_name_from_type(type), :data=>data} }
+ reg.map { |name, type, data| { :name => name, :type => get_name_from_type(type), :data => data } }
end
end
def set_value(key_path, value)
- Chef::Log.debug("Updating value #{value[:name]} in registry key #{key_path} with type #{value[:type]} and data #{value[:data]}")
+ data = value[:data]
+ data = data.to_s if value[:type] == :string
+ Chef::Log.debug("Updating value #{value[:name]} in registry key #{key_path} with type #{value[:type]} and data #{data}")
key_exists!(key_path)
hive, key = get_hive_and_key(key_path)
if value_exists?(key_path, value)
@@ -70,13 +72,13 @@ class Chef
return false
else
hive.open(key, ::Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | registry_system_architecture) do |reg|
- reg.write(value[:name], get_type_from_name(value[:type]), value[:data])
+ reg.write(value[:name], get_type_from_name(value[:type]), data)
end
Chef::Log.debug("Value #{value[:name]} in registry key #{key_path} updated")
end
else
hive.open(key, ::Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | registry_system_architecture) do |reg|
- reg.write(value[:name], get_type_from_name(value[:type]), value[:data])
+ reg.write(value[:name], get_type_from_name(value[:type]), data)
end
Chef::Log.debug("Value #{value[:name]} in registry key #{key_path} created")
end
@@ -168,16 +170,16 @@ class Chef
rescue Chef::Exceptions::Win32RegHiveMissing => e
return false
end
- return true
+ true
end
def has_subkeys?(key_path)
key_exists!(key_path)
hive, key = get_hive_and_key(key_path)
hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
- reg.each_key{ |key| return true }
+ reg.each_key { |key| return true }
end
- return false
+ false
end
def get_subkeys(key_path)
@@ -185,9 +187,9 @@ class Chef
key_exists!(key_path)
hive, key = get_hive_and_key(key_path)
hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
- reg.each_key{ |current_key| subkeys << current_key }
+ reg.each_key { |current_key| subkeys << current_key }
end
- return subkeys
+ subkeys
end
# 32-bit chef clients running on 64-bit machines will default to reading the 64-bit registry
@@ -200,9 +202,9 @@ class Chef
key_exists!(key_path)
hive, key = get_hive_and_key(key_path)
hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
- return true if reg.any? {|val| safely_downcase(val) == safely_downcase(value[:name]) }
+ return true if reg.any? { |val| safely_downcase(val) == safely_downcase(value[:name]) }
end
- return false
+ false
end
def data_exists?(key_path, value)
@@ -211,13 +213,13 @@ class Chef
hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
reg.each do |val_name, val_type, val_data|
if safely_downcase(val_name) == safely_downcase(value[:name]) &&
- val_type == get_type_from_name(value[:type]) &&
- val_data == value[:data]
+ val_type == get_type_from_name(value[:type]) &&
+ val_data == value[:data]
return true
end
end
end
- return false
+ false
end
def value_exists!(key_path, value)
@@ -247,7 +249,7 @@ class Chef
end
end
end
- return false
+ false
end
def type_matches!(key_path, value)
@@ -256,19 +258,6 @@ class Chef
end
end
- def get_type_from_name(val_type)
- value = {
- :binary => ::Win32::Registry::REG_BINARY,
- :string => ::Win32::Registry::REG_SZ,
- :multi_string => ::Win32::Registry::REG_MULTI_SZ,
- :expand_string => ::Win32::Registry::REG_EXPAND_SZ,
- :dword => ::Win32::Registry::REG_DWORD,
- :dword_big_endian => ::Win32::Registry::REG_DWORD_BIG_ENDIAN,
- :qword => ::Win32::Registry::REG_QWORD
- }[val_type]
- return value
- end
-
def keys_missing?(key_path)
missing_key_arr = key_path.split("\\")
missing_key_arr.pop
@@ -286,12 +275,11 @@ class Chef
private
-
def safely_downcase(val)
if val.is_a? String
return val.downcase
end
- return val
+ val
end
def node
@@ -328,7 +316,7 @@ class Chef
raise Chef::Exceptions::Win32RegHiveMissing, "Registry Hive #{hive_name} does not exist" unless hive
- return hive, key
+ [hive, key]
end
def _type_name_map
@@ -339,7 +327,7 @@ class Chef
:expand_string => ::Win32::Registry::REG_EXPAND_SZ,
:dword => ::Win32::Registry::REG_DWORD,
:dword_big_endian => ::Win32::Registry::REG_DWORD_BIG_ENDIAN,
- :qword => ::Win32::Registry::REG_QWORD
+ :qword => ::Win32::Registry::REG_QWORD,
}
end
@@ -355,9 +343,9 @@ class Chef
2 => ::Win32::Registry::REG_EXPAND_SZ,
4 => ::Win32::Registry::REG_DWORD,
5 => ::Win32::Registry::REG_DWORD_BIG_ENDIAN,
- 11 => ::Win32::Registry::REG_QWORD
+ 11 => ::Win32::Registry::REG_QWORD,
}[val_type]
- return value
+ value
end
def create_missing(key_path)
diff --git a/lib/chef/win32/security.rb b/lib/chef/win32/security.rb
index bc80517d80..c7d3f55a40 100644
--- a/lib/chef/win32/security.rb
+++ b/lib/chef/win32/security.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'chef/win32/api/security'
-require 'chef/win32/error'
-require 'chef/win32/memory'
-require 'chef/win32/process'
-require 'chef/win32/unicode'
-require 'chef/win32/security/token'
-require 'chef/mixin/wide_string'
+require "chef/win32/api/security"
+require "chef/win32/error"
+require "chef/win32/memory"
+require "chef/win32/process"
+require "chef/win32/unicode"
+require "chef/win32/security/token"
+require "chef/mixin/wide_string"
class Chef
module ReservedNames::Win32
@@ -104,6 +104,22 @@ class Chef
end
end
+ def self.add_account_right(name, privilege)
+ privilege_pointer = FFI::MemoryPointer.new LSA_UNICODE_STRING, 1
+ privilege_lsa_string = LSA_UNICODE_STRING.new(privilege_pointer)
+ privilege_lsa_string[:Buffer] = FFI::MemoryPointer.from_string(privilege.to_wstring)
+ privilege_lsa_string[:Length] = privilege.length * 2
+ privilege_lsa_string[:MaximumLength] = (privilege.length + 1) * 2
+
+ with_lsa_policy(name) do |policy_handle, sid|
+ result = LsaAddAccountRights(policy_handle.read_pointer, sid, privilege_pointer, 1)
+ win32_error = LsaNtStatusToWinError(result)
+ if win32_error != 0
+ Chef::ReservedNames::Win32::Error.raise!(nil, win32_error)
+ end
+ end
+ end
+
def self.adjust_token_privileges(token, privileges)
token = token.handle if token.respond_to?(:handle)
old_privileges_size = FFI::Buffer.new(:long).write_long(privileges.size_with_privileges)
@@ -165,6 +181,29 @@ class Chef
end
end
+ def self.get_account_right(name)
+ privileges = []
+ privilege_pointer = FFI::MemoryPointer.new(:pointer)
+ privilege_length = FFI::MemoryPointer.new(:ulong)
+
+ with_lsa_policy(name) do |policy_handle, sid|
+ result = LsaEnumerateAccountRights(policy_handle.read_pointer, sid, privilege_pointer, privilege_length)
+ win32_error = LsaNtStatusToWinError(result)
+ return [] if win32_error == 2 # FILE_NOT_FOUND - No rights assigned
+ if win32_error != 0
+ Chef::ReservedNames::Win32::Error.raise!(nil, win32_error)
+ end
+
+ privilege_length.read_ulong.times do |i|
+ privilege = LSA_UNICODE_STRING.new(privilege_pointer.read_pointer + i * LSA_UNICODE_STRING.size)
+ privileges << privilege[:Buffer].read_wstring
+ end
+ LsaFreeMemory(privilege_pointer)
+ end
+
+ privileges
+ end
+
def self.get_ace(acl, index)
acl = acl.pointer if acl.respond_to?(:pointer)
ace = FFI::Buffer.new :pointer
@@ -196,12 +235,11 @@ class Chef
SecurityDescriptor.new(security_descriptor_ptr)
end
-
def self.get_named_security_info(path, type = :SE_FILE_OBJECT, info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION)
security_descriptor = FFI::MemoryPointer.new :pointer
hr = GetNamedSecurityInfoW(path.to_wstring, type, info, nil, nil, nil, nil, security_descriptor)
if hr != ERROR_SUCCESS
- Chef::ReservedNames::Win32::Error.raise!("get_named_security_info(#{path}, #{type}, #{info})")
+ Chef::ReservedNames::Win32::Error.raise!("get_named_security_info(#{path}, #{type}, #{info})", hr)
end
result_pointer = security_descriptor.read_pointer
@@ -346,7 +384,7 @@ class Chef
end
sid = FFI::MemoryPointer.new :char, sid_size.read_long
- referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long*2)
+ referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long * 2)
use = FFI::Buffer.new(:long).write_long(0)
unless LookupAccountNameW(system_name, name.to_wstring, sid, sid_size, referenced_domain_name, referenced_domain_name_size, use)
Chef::ReservedNames::Win32::Error.raise!
@@ -367,8 +405,8 @@ class Chef
Chef::ReservedNames::Win32::Error.raise!
end
- name = FFI::MemoryPointer.new :char, (name_size.read_long*2)
- referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long*2)
+ name = FFI::MemoryPointer.new :char, (name_size.read_long * 2)
+ referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long * 2)
use = FFI::Buffer.new(:long).write_long(0)
unless LookupAccountSidW(system_name, sid, name, name_size, referenced_domain_name, referenced_domain_name_size, use)
Chef::ReservedNames::Win32::Error.raise!
@@ -386,7 +424,7 @@ class Chef
Chef::ReservedNames::Win32::Error.raise!
end
- name = FFI::MemoryPointer.new :char, (name_size.read_long*2)
+ name = FFI::MemoryPointer.new :char, (name_size.read_long * 2)
unless LookupPrivilegeNameW(system_name, luid, name, name_size)
Chef::ReservedNames::Win32::Error.raise!
end
@@ -404,7 +442,7 @@ class Chef
Chef::ReservedNames::Win32::Error.raise!
end
- display_name = FFI::MemoryPointer.new :char, (display_name_size.read_long*2)
+ display_name = FFI::MemoryPointer.new :char, (display_name_size.read_long * 2)
unless LookupPrivilegeDisplayNameW(system_name, name.to_wstring, display_name, display_name_size, language_id)
Chef::ReservedNames::Win32::Error.raise!
end
@@ -500,7 +538,7 @@ class Chef
hr = SetNamedSecurityInfoW(path.to_wstring, type, security_information, owner, group, dacl, sacl)
if hr != ERROR_SUCCESS
- Chef::ReservedNames::Win32::Error.raise!
+ Chef::ReservedNames::Win32::Error.raise! nil, hr
end
end
@@ -513,7 +551,7 @@ class Chef
def set_security_descriptor_dacl(security_descriptor, acl, defaulted = false, present = nil)
security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
acl = acl.pointer if acl.respond_to?(:pointer)
- present = !security_descriptor.null? if present == nil
+ present = !security_descriptor.null? if present.nil?
unless SetSecurityDescriptorDacl(security_descriptor, present, acl, defaulted)
Chef::ReservedNames::Win32::Error.raise!
@@ -541,13 +579,37 @@ class Chef
def self.set_security_descriptor_sacl(security_descriptor, acl, defaulted = false, present = nil)
security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer)
acl = acl.pointer if acl.respond_to?(:pointer)
- present = !security_descriptor.null? if present == nil
+ present = !security_descriptor.null? if present.nil?
unless SetSecurityDescriptorSacl(security_descriptor, present, acl, defaulted)
Chef::ReservedNames::Win32::Error.raise!
end
end
+ def self.with_lsa_policy(username)
+ sid = lookup_account_name(username)[1]
+
+ access = 0
+ access |= POLICY_CREATE_ACCOUNT
+ access |= POLICY_LOOKUP_NAMES
+
+ policy_handle = FFI::MemoryPointer.new(:pointer)
+ result = LsaOpenPolicy(nil, LSA_OBJECT_ATTRIBUTES.new, access, policy_handle)
+ win32_error = LsaNtStatusToWinError(result)
+ if win32_error != 0
+ Chef::ReservedNames::Win32::Error.raise!(nil, win32_error)
+ end
+
+ begin
+ yield policy_handle, sid.pointer
+ ensure
+ win32_error = LsaNtStatusToWinError(LsaClose(policy_handle.read_pointer))
+ if win32_error != 0
+ Chef::ReservedNames::Win32::Error.raise!(nil, win32_error)
+ end
+ end
+ end
+
def self.with_privileges(*privilege_names)
# Set privileges
token = open_current_process_token(TOKEN_READ | TOKEN_ADJUST_PRIVILEGES)
@@ -596,8 +658,8 @@ class Chef
end
end
-require 'chef/win32/security/ace'
-require 'chef/win32/security/acl'
-require 'chef/win32/security/securable_object'
-require 'chef/win32/security/security_descriptor'
-require 'chef/win32/security/sid'
+require "chef/win32/security/ace"
+require "chef/win32/security/acl"
+require "chef/win32/security/securable_object"
+require "chef/win32/security/security_descriptor"
+require "chef/win32/security/sid"
diff --git a/lib/chef/win32/security/ace.rb b/lib/chef/win32/security/ace.rb
index 1f54b1cafb..d593513983 100644
--- a/lib/chef/win32/security/ace.rb
+++ b/lib/chef/win32/security/ace.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'chef/win32/security'
-require 'chef/win32/security/sid'
-require 'chef/win32/memory'
+require "chef/win32/security"
+require "chef/win32/security/sid"
+require "chef/win32/memory"
-require 'ffi'
+require "ffi"
class Chef
module ReservedNames::Win32
diff --git a/lib/chef/win32/security/acl.rb b/lib/chef/win32/security/acl.rb
index e129d5c9a0..0d9f7decd0 100644
--- a/lib/chef/win32/security/acl.rb
+++ b/lib/chef/win32/security/acl.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/win32/security'
-require 'chef/win32/security/ace'
-require 'ffi'
+require "chef/win32/security"
+require "chef/win32/security/ace"
+require "ffi"
class Chef
module ReservedNames::Win32
@@ -34,7 +34,7 @@ class Chef
end
def self.create(aces)
- aces_size = aces.inject(0) { |sum,ace| sum + ace.size }
+ aces_size = aces.inject(0) { |sum, ace| sum + ace.size }
acl_size = align_dword(Chef::ReservedNames::Win32::API::Security::ACLStruct.size + aces_size) # What the heck is 94???
acl = Chef::ReservedNames::Win32::Security.initialize_acl(acl_size)
aces.each { |ace| Chef::ReservedNames::Win32::Security.add_ace(acl, ace) }
@@ -45,10 +45,10 @@ class Chef
def ==(other)
return false if length != other.length
- 0.upto(length-1) do |i|
+ 0.upto(length - 1) do |i|
return false if self[i] != other[i]
end
- return true
+ true
end
def pointer
@@ -64,7 +64,7 @@ class Chef
end
def each
- 0.upto(length-1) { |i| yield self[i] }
+ 0.upto(length - 1) { |i| yield self[i] }
end
def insert(index, *aces)
@@ -88,7 +88,7 @@ class Chef
end
def to_s
- "[#{self.collect { |ace| ace.to_s }.join(", ")}]"
+ "[#{collect { |ace| ace.to_s }.join(", ")}]"
end
def self.align_dword(size)
diff --git a/lib/chef/win32/security/securable_object.rb b/lib/chef/win32/security/securable_object.rb
index 00655c9bab..aef1a72c8c 100644
--- a/lib/chef/win32/security/securable_object.rb
+++ b/lib/chef/win32/security/securable_object.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/win32/security'
-require 'chef/win32/security/acl'
-require 'chef/win32/security/sid'
+require "chef/win32/security"
+require "chef/win32/security/acl"
+require "chef/win32/security/sid"
class Chef
module ReservedNames::Win32
diff --git a/lib/chef/win32/security/security_descriptor.rb b/lib/chef/win32/security/security_descriptor.rb
index 658e9104b4..8bfd8b8287 100644
--- a/lib/chef/win32/security/security_descriptor.rb
+++ b/lib/chef/win32/security/security_descriptor.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/win32/security'
-require 'chef/win32/security/acl'
-require 'chef/win32/security/sid'
+require "chef/win32/security"
+require "chef/win32/security/acl"
+require "chef/win32/security/sid"
class Chef
module ReservedNames::Win32
diff --git a/lib/chef/win32/security/sid.rb b/lib/chef/win32/security/sid.rb
index f8bd934876..983166ac70 100644
--- a/lib/chef/win32/security/sid.rb
+++ b/lib/chef/win32/security/sid.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'chef/win32/security'
-require 'chef/win32/api/net'
-require 'chef/win32/api/error'
+require "chef/win32/security"
+require "chef/win32/api/net"
+require "chef/win32/api/error"
-require 'wmi-lite/wmi'
+require "wmi-lite/wmi"
class Chef
module ReservedNames::Win32
@@ -46,11 +46,11 @@ class Chef
end
def self.from_string_sid(string_sid)
- Chef::ReservedNames::Win32::Security::convert_string_sid_to_sid(string_sid)
+ Chef::ReservedNames::Win32::Security.convert_string_sid_to_sid(string_sid)
end
def ==(other)
- other != nil && Chef::ReservedNames::Win32::Security.equal_sid(self, other)
+ !other.nil? && Chef::ReservedNames::Win32::Security.equal_sid(self, other)
end
attr_reader :pointer
@@ -61,7 +61,7 @@ class Chef
def account_name
domain, name, use = account
- (domain != nil && domain.length > 0) ? "#{domain}\\#{name}" : name
+ (!domain.nil? && domain.length > 0) ? "#{domain}\\#{name}" : name
end
def size
@@ -78,123 +78,161 @@ class Chef
# Well-known SIDs
def self.Null
- SID.from_string_sid('S-1-0')
+ SID.from_string_sid("S-1-0")
end
+
def self.Nobody
- SID.from_string_sid('S-1-0-0')
+ SID.from_string_sid("S-1-0-0")
end
+
def self.World
- SID.from_string_sid('S-1-1')
+ SID.from_string_sid("S-1-1")
end
+
def self.Everyone
- SID.from_string_sid('S-1-1-0')
+ SID.from_string_sid("S-1-1-0")
end
+
def self.Local
- SID.from_string_sid('S-1-2')
+ SID.from_string_sid("S-1-2")
end
+
def self.Creator
- SID.from_string_sid('S-1-3')
+ SID.from_string_sid("S-1-3")
end
+
def self.CreatorOwner
- SID.from_string_sid('S-1-3-0')
+ SID.from_string_sid("S-1-3-0")
end
+
def self.CreatorGroup
- SID.from_string_sid('S-1-3-1')
+ SID.from_string_sid("S-1-3-1")
end
+
def self.CreatorOwnerServer
- SID.from_string_sid('S-1-3-2')
+ SID.from_string_sid("S-1-3-2")
end
+
def self.CreatorGroupServer
- SID.from_string_sid('S-1-3-3')
+ SID.from_string_sid("S-1-3-3")
end
+
def self.NonUnique
- SID.from_string_sid('S-1-4')
+ SID.from_string_sid("S-1-4")
end
+
def self.Nt
- SID.from_string_sid('S-1-5')
+ SID.from_string_sid("S-1-5")
end
+
def self.Dialup
- SID.from_string_sid('S-1-5-1')
+ SID.from_string_sid("S-1-5-1")
end
+
def self.Network
- SID.from_string_sid('S-1-5-2')
+ SID.from_string_sid("S-1-5-2")
end
+
def self.Batch
- SID.from_string_sid('S-1-5-3')
+ SID.from_string_sid("S-1-5-3")
end
+
def self.Interactive
- SID.from_string_sid('S-1-5-4')
+ SID.from_string_sid("S-1-5-4")
end
+
def self.Service
- SID.from_string_sid('S-1-5-6')
+ SID.from_string_sid("S-1-5-6")
end
+
def self.Anonymous
- SID.from_string_sid('S-1-5-7')
+ SID.from_string_sid("S-1-5-7")
end
+
def self.Proxy
- SID.from_string_sid('S-1-5-8')
+ SID.from_string_sid("S-1-5-8")
end
+
def self.EnterpriseDomainControllers
- SID.from_string_sid('S-1-5-9')
+ SID.from_string_sid("S-1-5-9")
end
+
def self.PrincipalSelf
- SID.from_string_sid('S-1-5-10')
+ SID.from_string_sid("S-1-5-10")
end
+
def self.AuthenticatedUsers
- SID.from_string_sid('S-1-5-11')
+ SID.from_string_sid("S-1-5-11")
end
+
def self.RestrictedCode
- SID.from_string_sid('S-1-5-12')
+ SID.from_string_sid("S-1-5-12")
end
+
def self.TerminalServerUsers
- SID.from_string_sid('S-1-5-13')
+ SID.from_string_sid("S-1-5-13")
end
+
def self.LocalSystem
- SID.from_string_sid('S-1-5-18')
+ SID.from_string_sid("S-1-5-18")
end
+
def self.NtLocal
- SID.from_string_sid('S-1-5-19')
+ SID.from_string_sid("S-1-5-19")
end
+
def self.NtNetwork
- SID.from_string_sid('S-1-5-20')
+ SID.from_string_sid("S-1-5-20")
end
+
def self.BuiltinAdministrators
- SID.from_string_sid('S-1-5-32-544')
+ SID.from_string_sid("S-1-5-32-544")
end
+
def self.BuiltinUsers
- SID.from_string_sid('S-1-5-32-545')
+ SID.from_string_sid("S-1-5-32-545")
end
+
def self.Guests
- SID.from_string_sid('S-1-5-32-546')
+ SID.from_string_sid("S-1-5-32-546")
end
+
def self.PowerUsers
- SID.from_string_sid('S-1-5-32-547')
+ SID.from_string_sid("S-1-5-32-547")
end
+
def self.AccountOperators
- SID.from_string_sid('S-1-5-32-548')
+ SID.from_string_sid("S-1-5-32-548")
end
+
def self.ServerOperators
- SID.from_string_sid('S-1-5-32-549')
+ SID.from_string_sid("S-1-5-32-549")
end
+
def self.PrintOperators
- SID.from_string_sid('S-1-5-32-550')
+ SID.from_string_sid("S-1-5-32-550")
end
+
def self.BackupOperators
- SID.from_string_sid('S-1-5-32-551')
+ SID.from_string_sid("S-1-5-32-551")
end
+
def self.Replicators
- SID.from_string_sid('S-1-5-32-552')
+ SID.from_string_sid("S-1-5-32-552")
end
+
def self.Administrators
- SID.from_string_sid('S-1-5-32-544')
+ SID.from_string_sid("S-1-5-32-544")
end
def self.None
SID.from_account("#{::ENV['COMPUTERNAME']}\\None")
end
+
def self.Administrator
SID.from_account("#{::ENV['COMPUTERNAME']}\\#{SID.admin_account_name}")
end
+
def self.Guest
SID.from_account("#{::ENV['COMPUTERNAME']}\\Guest")
end
@@ -237,11 +275,11 @@ class Chef
status = ERROR_MORE_DATA
- while(status == ERROR_MORE_DATA) do
+ while status == ERROR_MORE_DATA
status = NetUserEnum(servername, level, filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle)
- if (status == NERR_Success || status == ERROR_MORE_DATA)
- entriesread.read_long.times.collect do |i|
+ if status == NERR_Success || status == ERROR_MORE_DATA
+ Array.new(entriesread.read_long) do |i|
user_info = USER_INFO_3.new(bufptr.read_pointer + i * USER_INFO_3.size)
# Check if the account is the Administrator account
# RID for the Administrator account is always 500 and it's privilage is set to USER_PRIV_ADMIN
diff --git a/lib/chef/win32/security/token.rb b/lib/chef/win32/security/token.rb
index 8d4e54ad8c..38ef03b33c 100644
--- a/lib/chef/win32/security/token.rb
+++ b/lib/chef/win32/security/token.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'chef/win32/security'
-require 'chef/win32/api/security'
-require 'chef/win32/unicode'
-require 'ffi'
+require "chef/win32/security"
+require "chef/win32/api/security"
+require "chef/win32/unicode"
+require "ffi"
class Chef
module ReservedNames::Win32
@@ -55,7 +55,7 @@ class Chef
def adjust_privileges(privileges_struct)
if privileges_struct[:PrivilegeCount] > 0
- Chef::ReservedNames::Win32::Security::adjust_token_privileges(self, privileges_struct)
+ Chef::ReservedNames::Win32::Security.adjust_token_privileges(self, privileges_struct)
end
end
diff --git a/lib/chef/win32/system.rb b/lib/chef/win32/system.rb
index cdd063f174..ec2e5d3457 100755
--- a/lib/chef/win32/system.rb
+++ b/lib/chef/win32/system.rb
@@ -1,6 +1,6 @@
#
# Author:: Salim Alam (<salam@chef.io>)
-# Copyright:: Copyright 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/win32/api/system'
-require 'chef/win32/error'
-require 'ffi'
+require "chef/win32/api/system"
+require "chef/win32/error"
+require "ffi"
class Chef
module ReservedNames::Win32
diff --git a/lib/chef/win32/unicode.rb b/lib/chef/win32/unicode.rb
index d63b9790b9..dd5a197f71 100644
--- a/lib/chef/win32/unicode.rb
+++ b/lib/chef/win32/unicode.rb
@@ -1,7 +1,7 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/mixin/wide_string'
-require 'chef/win32/api/unicode'
+require "chef/mixin/wide_string"
+require "chef/win32/api/unicode"
class Chef
module ReservedNames::Win32
@@ -38,15 +38,15 @@ module FFI
# Find the length of the string
length = 0
last_char = nil
- while last_char != "\000\000" do
+ while last_char != "\000\000"
length += 1
- last_char = self.get_bytes(0,length * 2)[-2..-1]
+ last_char = get_bytes(0, length * 2)[-2..-1]
end
num_wchars = length
end
- wide_to_utf8(self.get_bytes(0, num_wchars*2))
+ wide_to_utf8(get_bytes(0, num_wchars * 2))
end
end
end
diff --git a/lib/chef/win32/version.rb b/lib/chef/win32/version.rb
index 6a7a65b01b..3e2d6bc1fe 100644
--- a/lib/chef/win32/version.rb
+++ b/lib/chef/win32/version.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'chef/win32/api'
-require 'chef/win32/api/system'
-require 'wmi-lite/wmi'
+require "chef/win32/api"
+require "chef/win32/api/system"
+require "wmi-lite/wmi"
class Chef
module ReservedNames::Win32
@@ -41,28 +41,28 @@ class Chef
private_class_method :get_system_metrics
def self.method_name_from_marketing_name(marketing_name)
- "#{marketing_name.gsub(/\s/, '_').gsub(/\./, '_').downcase}?"
+ "#{marketing_name.gsub(/\s/, '_').tr('.', '_').downcase}?"
# "#{marketing_name.gsub(/\s/, '_').gsub(//, '_').downcase}?"
end
private_class_method :method_name_from_marketing_name
WIN_VERSIONS = {
- "Windows 10" => {:major => 6, :minor => 4, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
- "Windows Server 10" => {:major => 6, :minor => 4, :callable => lambda {|product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
- "Windows 8.1" => {:major => 6, :minor => 3, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
- "Windows Server 2012 R2" => {:major => 6, :minor => 3, :callable => lambda {|product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
- "Windows 8" => {:major => 6, :minor => 2, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
- "Windows Server 2012" => {:major => 6, :minor => 2, :callable => lambda{ |product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
- "Windows 7" => {:major => 6, :minor => 1, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
- "Windows Server 2008 R2" => {:major => 6, :minor => 1, :callable => lambda{ |product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
- "Windows Server 2008" => {:major => 6, :minor => 0, :callable => lambda{ |product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
- "Windows Vista" => {:major => 6, :minor => 0, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
- "Windows Server 2003 R2" => {:major => 5, :minor => 2, :callable => lambda{ |product_type, suite_mask| get_system_metrics(SM_SERVERR2) != 0 }},
- "Windows Home Server" => {:major => 5, :minor => 2, :callable => lambda{ |product_type, suite_mask| (suite_mask & VER_SUITE_WH_SERVER) == VER_SUITE_WH_SERVER }},
- "Windows Server 2003" => {:major => 5, :minor => 2, :callable => lambda{ |product_type, suite_mask| get_system_metrics(SM_SERVERR2) == 0 }},
- "Windows XP" => {:major => 5, :minor => 1},
- "Windows 2000" => {:major => 5, :minor => 0}
+ "Windows 10" => { :major => 10, :minor => 0, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
+ "Windows Server 2016" => { :major => 10, :minor => 0, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
+ "Windows 8.1" => { :major => 6, :minor => 3, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
+ "Windows Server 2012 R2" => { :major => 6, :minor => 3, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
+ "Windows 8" => { :major => 6, :minor => 2, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
+ "Windows Server 2012" => { :major => 6, :minor => 2, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
+ "Windows 7" => { :major => 6, :minor => 1, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
+ "Windows Server 2008 R2" => { :major => 6, :minor => 1, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
+ "Windows Server 2008" => { :major => 6, :minor => 0, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
+ "Windows Vista" => { :major => 6, :minor => 0, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
+ "Windows Server 2003 R2" => { :major => 5, :minor => 2, :callable => lambda { |product_type, suite_mask| get_system_metrics(SM_SERVERR2) != 0 } },
+ "Windows Home Server" => { :major => 5, :minor => 2, :callable => lambda { |product_type, suite_mask| (suite_mask & VER_SUITE_WH_SERVER) == VER_SUITE_WH_SERVER } },
+ "Windows Server 2003" => { :major => 5, :minor => 2, :callable => lambda { |product_type, suite_mask| get_system_metrics(SM_SERVERR2) == 0 } },
+ "Windows XP" => { :major => 5, :minor => 1 },
+ "Windows 2000" => { :major => 5, :minor => 0 },
}
def initialize
@@ -76,7 +76,7 @@ class Chef
# Obtain sku information for the purpose of identifying
# datacenter, cluster, and core skus, the latter 2 only
# exist in releases after Windows Server 2003
- if ! Chef::Platform::windows_server_2003?
+ if ! Chef::Platform.windows_server_2003?
@sku = get_product_info(@major_version, @minor_version, @sp_major_version, @sp_minor_version)
else
# The get_product_info API is not supported on Win2k3,
@@ -88,19 +88,19 @@ class Chef
marketing_names = Array.new
# General Windows checks
- WIN_VERSIONS.each do |k,v|
+ WIN_VERSIONS.each do |k, v|
method_name = method_name_from_marketing_name(k)
define_method(method_name) do
(@major_version == v[:major]) &&
- (@minor_version == v[:minor]) &&
- (v[:callable] ? v[:callable].call(@product_type, @suite_mask) : true)
+ (@minor_version == v[:minor]) &&
+ (v[:callable] ? v[:callable].call(@product_type, @suite_mask) : true)
end
marketing_names << [k, method_name]
end
define_method(:marketing_name) do
marketing_names.each do |mn|
- break mn[0] if self.send(mn[1])
+ break mn[0] if send(mn[1])
end
end
@@ -123,13 +123,13 @@ class Chef
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
wmi = WmiLite::Wmi.new
- os_info = wmi.first_of('Win32_OperatingSystem')
- os_version = os_info['version']
+ os_info = wmi.first_of("Win32_OperatingSystem")
+ os_version = os_info["version"]
# The operating system version is a string in the following form
# that can be split into components based on the '.' delimiter:
# MajorVersionNumber.MinorVersionNumber.BuildNumber
- os_version.split('.').collect { | version_string | version_string.to_i }
+ os_version.split(".").collect { |version_string| version_string.to_i }
end
def get_version_ex
diff --git a/lib/chef/workstation_config_loader.rb b/lib/chef/workstation_config_loader.rb
index 8398c5d616..97f41240f3 100644
--- a/lib/chef/workstation_config_loader.rb
+++ b/lib/chef/workstation_config_loader.rb
@@ -1,6 +1,6 @@
#
# Author:: Claire McQuin (<claire@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef-config/workstation_config_loader'
+require "chef-config/workstation_config_loader"
class Chef
WorkstationConfigLoader = ChefConfig::WorkstationConfigLoader
diff --git a/omnibus/.gitignore b/omnibus/.gitignore
new file mode 100644
index 0000000000..1a2c556f8d
--- /dev/null
+++ b/omnibus/.gitignore
@@ -0,0 +1,11 @@
+vendor/bundle
+pkg/*
+.kitchen.local.yml
+bin/*
+files/chef-server-cookbooks/cache/
+files/msi/ChefClient-Config.wxi
+cookbooks
+vendor/cookbooks
+build_timestamp
+ldd.out
+Berksfile.lock
diff --git a/omnibus/.kitchen.vmware.yml b/omnibus/.kitchen.vmware.yml
new file mode 100644
index 0000000000..69f001ef97
--- /dev/null
+++ b/omnibus/.kitchen.vmware.yml
@@ -0,0 +1,6 @@
+driver:
+ name: vagrant
+ provider: vmware_fusion
+ customize:
+ numvcpus: 4
+ memsize: 4096
diff --git a/omnibus/.kitchen.yml b/omnibus/.kitchen.yml
new file mode 100644
index 0000000000..a14d3498de
--- /dev/null
+++ b/omnibus/.kitchen.yml
@@ -0,0 +1,137 @@
+#
+# NOTE: this runs the omnibus cookbook, but does not actually run Omnibus. Use
+# 'kichen converge' to setup the virtual machine and then `kitchen login` to
+# SSH into the machine and run Omnibus.
+#
+
+driver:
+ name: vagrant
+ forward_agent: yes
+ customize:
+ cpus: 4
+ memory: 4096
+ synced_folders:
+ - ['../..', '/vagrant/code']
+ - ['../../omnibus', '/home/vagrant/omnibus']
+ - ['../../omnibus-software', '/home/vagrant/omnibus-software']
+
+provisioner:
+ name: chef_zero
+ # Always install the latest version of Chef.
+ # This is not the version of chef that we're building - this is the version
+ # of chef that omnibus needs to build chef/chef.
+ require_chef_omnibus: true
+ attributes:
+ vagrant:
+ this_key_exists_so_we_have_a_vagrant_key: true
+ omnibus:
+ build_user: vagrant
+ build_user_group: vagrant
+ build_user_password: vagrant
+ product_name: angrychef
+ product_version: latest
+ chef_omnibus_root: /opt/angrychef
+
+platforms:
+ - name: centos-5.11
+ run_list: yum-epel::default
+ - name: centos-6.7
+ run_list: yum-epel::default
+ - name: centos-7.2
+ run_list: yum-epel::default
+ - name: debian-6.0.8
+ run_list: apt::default
+ - name: debian-7.9
+ run_list: apt::default
+ - name: debian-8.2
+ run_list: apt::default
+ - name: freebsd-9.3
+ run_list:
+ - freebsd::portsnap
+ - freebsd::pkgng
+ - name: freebsd-10.2
+ run_list: freebsd::portsnap
+ - name: ubuntu-10.04
+ run_list: apt::default
+ - name: ubuntu-12.04
+ run_list: apt::default
+ - name: ubuntu-14.04
+ run_list: apt::default
+ # The following (private) boxes are shared via Atlas and are only
+ # available to users working for Chef. Sorry, it's about software licensing.
+ #
+ # Chef-internal users, you will need to:
+ # 1. Create an Atlas account: https://atlas.hashicorp.com/
+ # 2. Ping #eng-services-support with your Atlas account name
+ # to be added to the relevant team in Atlas,
+ # 3. Do `vagrant login` with your Atlas creds so that you can download
+ # the private boxes.
+ #
+ # The Mac OS X boxes are VMware only also. You can enable VMware Fusion
+ # by activating the `.kitchen.vmware.yml` file with the `KITCHEN_LOCAL_YAML`
+ # environment variable:
+ #
+ # KITCHEN_LOCAL_YAML=.kitchen.vmware.yml kitchen converge chefdk-macosx-109
+ #
+ <% %w(
+ 10.9
+ 10.10
+ 10.11
+ ).each do |mac_version| %>
+ - name: macosx-<%= mac_version %>
+ driver:
+ box: chef/macosx-<%= mac_version %> # private
+ synced_folders:
+ - ['..', '/Users/vagrant/chef']
+ - ['../../omnibus', '/Users/vagrant/omnibus']
+ - ['../../omnibus-software', '/Users/vagrant/omnibus-software']
+ <% end %>
+ - name: windows-2012r2-standard
+ driver:
+ box: chef/windows-server-2012r2-standard # private
+ synced_folders:
+ # We have to mount this repos enclosing folder as the Omnibus build
+ # gets cranky if the mounted Chef source folder is a symlink. This
+ # mounts at `C:\vagrant\code` and the Chef source folder is available
+ # at `C:\vagrant\code\chef`
+ - ['../..', '/vagrant/code']
+ provisioner:
+ attributes:
+ omnibus:
+ build_user: vagrant
+ build_user_group: Administrators
+ build_user_password: vagrant
+ chef_omnibus_root: /opscode/angrychef
+ # By adding an `i386` to the name the Omnibus cookbook's `load-omnibus-toolchain.bat`
+ # will load the 32-bit version of the MinGW toolchain.
+ - name: windows-2012r2-standard-i386
+ driver:
+ box: chef/windows-server-2012r2-standard # private
+ synced_folders:
+ # We have to mount this repos enclosing folder as the Omnibus build
+ # gets cranky if the mounted ChefDK source folder is a symlink. This
+ # mounts at `C:\vagrant\code` and the ChefDK source folder is available
+ # at `C:\vagrant\code\chef-dk`
+ - ['../..', '/vagrant/code']
+ provisioner:
+ attributes:
+ omnibus:
+ build_user: vagrant
+ build_user_group: Administrators
+ build_user_password: vagrant
+ chef_omnibus_root: /opscode/angrychef
+
+suites:
+ # - name: angrychef
+ # attributes:
+ # omnibus:
+ # <<: *attribute_defaults
+ # install_dir: /opt/angrychef
+ # run_list:
+ # - omnibus::default
+ - name: chef
+ attributes:
+ omnibus:
+ install_dir: /opt/chef
+ run_list:
+ - omnibus::default
diff --git a/omnibus/Berksfile b/omnibus/Berksfile
new file mode 100644
index 0000000000..614c6da643
--- /dev/null
+++ b/omnibus/Berksfile
@@ -0,0 +1,12 @@
+source "https://supermarket.chef.io"
+
+cookbook "omnibus"
+
+# Uncomment to use the latest version of the Omnibus cookbook from GitHub
+# cookbook 'omnibus', github: 'opscode-cookbooks/omnibus'
+
+group :integration do
+ cookbook "apt", "~> 2.3"
+ cookbook "freebsd", "~> 0.1"
+ cookbook "yum-epel", "~> 0.3"
+end
diff --git a/omnibus/Gemfile b/omnibus/Gemfile
new file mode 100644
index 0000000000..735b371c62
--- /dev/null
+++ b/omnibus/Gemfile
@@ -0,0 +1,24 @@
+source "https://rubygems.org"
+
+gem "omnibus", github: "chef/omnibus", branch: "rhass/COOL-502_with_gcc_investigate"
+gem "omnibus-software", github: "chef/omnibus-software", branch: "shain/ruby_windows_monster"
+gem "license_scout", github: "chef/license_scout"
+
+gem "pedump"
+
+# This development group is installed by default when you run `bundle install`,
+# but if you are using Omnibus in a CI-based infrastructure, you do not need
+# the Test Kitchen-based build lab. You can skip these unnecessary dependencies
+# by running `bundle install --without development` to speed up build times.
+group :development do
+ # Use Berkshelf for resolving cookbook dependencies
+ gem "berkshelf", "~> 4.0"
+
+ # Use Test Kitchen with Vagrant for converging the build environment
+ gem "test-kitchen", "~> 1.13"
+ gem "kitchen-vagrant", "~> 0.19.0"
+ gem "winrm-fs", "~> 1.0"
+ gem "pry"
+ gem "pry-byebug"
+ gem "pry-stack_explorer"
+end
diff --git a/omnibus/Gemfile.lock b/omnibus/Gemfile.lock
new file mode 100644
index 0000000000..ceb322bf20
--- /dev/null
+++ b/omnibus/Gemfile.lock
@@ -0,0 +1,270 @@
+GIT
+ remote: git://github.com/chef/license_scout.git
+ revision: f90293a9753652fb64994a14de4108e503c06632
+ specs:
+ license_scout (0.1.2)
+ ffi-yajl (~> 2.2)
+ mixlib-shellout (~> 2.2)
+
+GIT
+ remote: git://github.com/chef/omnibus-software.git
+ revision: 086710002ec0054b3d240d14ca04d11163f528aa
+ branch: shain/ruby_windows_monster
+ specs:
+ omnibus-software (4.0.0)
+ chef-sugar (>= 3.4.0)
+ omnibus (>= 5.5.0)
+
+GIT
+ remote: git://github.com/chef/omnibus.git
+ revision: dce5283a85a44484a66a8a84991beba92e46fd12
+ branch: rhass/COOL-502_with_gcc_investigate
+ specs:
+ omnibus (5.5.0)
+ aws-sdk (~> 2)
+ chef-sugar (~> 3.3)
+ cleanroom (~> 1.0)
+ ffi-yajl (~> 2.2)
+ license_scout
+ mixlib-shellout (~> 2.0)
+ mixlib-versioning
+ ohai (~> 8.0)
+ ruby-progressbar (~> 1.7)
+ thor (~> 0.18)
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ addressable (2.5.0)
+ public_suffix (~> 2.0, >= 2.0.2)
+ artifactory (2.6.0)
+ awesome_print (1.7.0)
+ aws-sdk (2.7.5)
+ aws-sdk-resources (= 2.7.5)
+ aws-sdk-core (2.7.5)
+ aws-sigv4 (~> 1.0)
+ jmespath (~> 1.0)
+ aws-sdk-resources (2.7.5)
+ aws-sdk-core (= 2.7.5)
+ aws-sigv4 (1.0.0)
+ berkshelf (4.3.5)
+ addressable (~> 2.3, >= 2.3.4)
+ berkshelf-api-client (~> 2.0, >= 2.0.2)
+ buff-config (~> 1.0)
+ buff-extensions (~> 1.0)
+ buff-shell_out (~> 0.1)
+ celluloid (= 0.16.0)
+ celluloid-io (~> 0.16.1)
+ cleanroom (~> 1.0)
+ faraday (~> 0.9)
+ httpclient (~> 2.7)
+ minitar (~> 0.5, >= 0.5.4)
+ mixlib-archive (~> 0.1)
+ octokit (~> 4.0)
+ retryable (~> 2.0)
+ ridley (~> 4.5)
+ solve (~> 2.0)
+ thor (~> 0.19)
+ berkshelf-api-client (2.0.2)
+ faraday (~> 0.9.1)
+ httpclient (~> 2.7.0)
+ ridley (~> 4.5)
+ binding_of_caller (0.7.2)
+ debug_inspector (>= 0.0.1)
+ buff-config (1.0.1)
+ buff-extensions (~> 1.0)
+ varia_model (~> 0.4)
+ buff-extensions (1.0.0)
+ buff-ignore (1.1.1)
+ buff-ruby_engine (0.1.0)
+ buff-shell_out (0.2.0)
+ buff-ruby_engine (~> 0.1.0)
+ builder (3.2.3)
+ byebug (9.0.6)
+ celluloid (0.16.0)
+ timers (~> 4.0.0)
+ celluloid-io (0.16.2)
+ celluloid (>= 0.16.0)
+ nio4r (>= 1.1.0)
+ chef-config (12.18.31)
+ addressable
+ fuzzyurl
+ mixlib-config (~> 2.0)
+ mixlib-shellout (~> 2.0)
+ chef-sugar (3.4.0)
+ cleanroom (1.0.0)
+ coderay (1.1.1)
+ debug_inspector (0.0.2)
+ erubis (2.7.0)
+ faraday (0.9.2)
+ multipart-post (>= 1.2, < 3)
+ ffi (1.9.17)
+ ffi (1.9.17-x86-mingw32)
+ ffi-yajl (2.3.0)
+ libyajl2 (~> 1.2)
+ fuzzyurl (0.9.0)
+ gssapi (1.2.0)
+ ffi (>= 1.0.1)
+ gyoku (1.3.1)
+ builder (>= 2.1.2)
+ hashie (3.5.1)
+ hitimes (1.2.4)
+ hitimes (1.2.4-x86-mingw32)
+ httpclient (2.7.2)
+ iostruct (0.0.4)
+ ipaddress (0.8.3)
+ jmespath (1.3.1)
+ json (2.0.3)
+ kitchen-vagrant (0.19.0)
+ test-kitchen (~> 1.4)
+ libyajl2 (1.2.0)
+ little-plugger (1.1.4)
+ logging (2.1.0)
+ little-plugger (~> 1.1)
+ multi_json (~> 1.10)
+ method_source (0.8.2)
+ minitar (0.6.1)
+ mixlib-archive (0.4.1)
+ mixlib-log
+ mixlib-authentication (1.4.1)
+ mixlib-log
+ mixlib-cli (1.7.0)
+ mixlib-config (2.2.4)
+ mixlib-install (2.1.12)
+ artifactory
+ mixlib-shellout
+ mixlib-versioning
+ thor
+ mixlib-log (1.7.1)
+ mixlib-shellout (2.2.7)
+ mixlib-shellout (2.2.7-universal-mingw32)
+ win32-process (~> 0.8.2)
+ wmi-lite (~> 1.0)
+ mixlib-versioning (1.1.0)
+ molinillo (0.4.5)
+ multi_json (1.12.1)
+ multipart-post (2.0.0)
+ net-scp (1.2.1)
+ net-ssh (>= 2.6.5)
+ net-ssh (4.0.1)
+ net-ssh-gateway (1.3.0)
+ net-ssh (>= 2.6.5)
+ nio4r (2.0.0)
+ nori (2.6.0)
+ octokit (4.6.2)
+ sawyer (~> 0.8.0, >= 0.5.3)
+ ohai (8.23.0)
+ chef-config (>= 12.5.0.alpha.1, < 13)
+ ffi (~> 1.9)
+ ffi-yajl (~> 2.2)
+ ipaddress
+ mixlib-cli
+ mixlib-config (~> 2.0)
+ mixlib-log (>= 1.7.1, < 2.0)
+ mixlib-shellout (~> 2.0)
+ plist (~> 3.1)
+ systemu (~> 2.6.4)
+ wmi-lite (~> 1.0)
+ pedump (0.5.2)
+ awesome_print
+ iostruct (>= 0.0.4)
+ multipart-post (~> 2.0.0)
+ progressbar
+ zhexdump (>= 0.0.2)
+ plist (3.2.0)
+ progressbar (1.8.2)
+ pry (0.10.4)
+ coderay (~> 1.1.0)
+ method_source (~> 0.8.1)
+ slop (~> 3.4)
+ pry-byebug (3.4.2)
+ byebug (~> 9.0)
+ pry (~> 0.10)
+ pry-stack_explorer (0.4.9.2)
+ binding_of_caller (>= 0.7)
+ pry (>= 0.9.11)
+ public_suffix (2.0.5)
+ retryable (2.0.4)
+ ridley (4.6.1)
+ addressable
+ buff-config (~> 1.0)
+ buff-extensions (~> 1.0)
+ buff-ignore (~> 1.1.1)
+ buff-shell_out (~> 0.1)
+ celluloid (~> 0.16.0)
+ celluloid-io (~> 0.16.1)
+ chef-config (>= 12.5.0)
+ erubis
+ faraday (~> 0.9.0)
+ hashie (>= 2.0.2, < 4.0.0)
+ httpclient (~> 2.7)
+ json (>= 1.7.7)
+ mixlib-authentication (>= 1.3.0)
+ retryable (~> 2.0)
+ semverse (~> 1.1)
+ varia_model (~> 0.4.0)
+ ruby-progressbar (1.8.1)
+ rubyntlm (0.6.1)
+ rubyzip (1.2.1)
+ safe_yaml (1.0.4)
+ sawyer (0.8.1)
+ addressable (>= 2.3.5, < 2.6)
+ faraday (~> 0.8, < 1.0)
+ semverse (1.2.1)
+ slop (3.6.0)
+ solve (2.0.3)
+ molinillo (~> 0.4.2)
+ semverse (~> 1.1)
+ systemu (2.6.5)
+ test-kitchen (1.15.0)
+ mixlib-install (>= 1.2, < 3.0)
+ mixlib-shellout (>= 1.2, < 3.0)
+ net-scp (~> 1.1)
+ net-ssh (>= 2.9, < 5.0)
+ net-ssh-gateway (~> 1.2)
+ safe_yaml (~> 1.0)
+ thor (~> 0.18)
+ thor (0.19.4)
+ timers (4.0.4)
+ hitimes
+ varia_model (0.4.1)
+ buff-extensions (~> 1.0)
+ hashie (>= 2.0.2, < 4.0.0)
+ win32-process (0.8.3)
+ ffi (>= 1.0.0)
+ winrm (2.1.2)
+ builder (>= 2.1.2)
+ erubis (~> 2.7)
+ gssapi (~> 1.2)
+ gyoku (~> 1.0)
+ httpclient (~> 2.2, >= 2.2.0.2)
+ logging (>= 1.6.1, < 3.0)
+ nori (~> 2.0)
+ rubyntlm (~> 0.6.0, >= 0.6.1)
+ winrm-fs (1.0.1)
+ erubis (~> 2.7)
+ logging (>= 1.6.1, < 3.0)
+ rubyzip (~> 1.1)
+ winrm (~> 2.0)
+ wmi-lite (1.0.0)
+ zhexdump (0.0.2)
+
+PLATFORMS
+ ruby
+ x86-mingw32
+
+DEPENDENCIES
+ berkshelf (~> 4.0)
+ kitchen-vagrant (~> 0.19.0)
+ license_scout!
+ omnibus!
+ omnibus-software!
+ pedump
+ pry
+ pry-byebug
+ pry-stack_explorer
+ test-kitchen (~> 1.13)
+ winrm-fs (~> 1.0)
+
+BUNDLED WITH
+ 1.12.5
diff --git a/omnibus/README.md b/omnibus/README.md
new file mode 100644
index 0000000000..5f325aa164
--- /dev/null
+++ b/omnibus/README.md
@@ -0,0 +1,152 @@
+Client Tools Omnibus project
+============================
+This project creates full-stack platform-specific packages for the following projects:
+
+* AngryChef
+* Chef
+* Chef with FIPS enabled
+
+Installation
+------------
+You must have a sane Ruby 1.9+ environment with Bundler installed. Ensure all
+the required gems are installed:
+
+```shell
+$ bundle install --without development
+```
+
+Usage
+-----
+### Build
+
+You create a platform-specific package using the `build project` command:
+
+```shell
+$ bundle exec omnibus build <PROJECT>
+```
+
+The platform/architecture type of the package created will match the platform
+where the `build project` command is invoked. For example, running this command
+on a MacBook Pro will generate a Mac OS X package. After the build completes
+packages will be available in the `pkg/` folder.
+
+### Clean
+
+You can clean up all temporary files generated during the build process with
+the `clean` command:
+
+```shell
+$ bundle exec omnibus clean <PROJECT>
+```
+
+Adding the `--purge` purge option removes __ALL__ files generated during the
+build including the project install directory (`/opt/chef`) and
+the package cache directory (`/var/cache/omnibus/pkg`):
+
+```shell
+$ bundle exec omnibus clean <PROJECT> --purge
+```
+
+### Publish
+
+Omnibus has a built-in mechanism for releasing to a variety of "backends", such
+as Amazon S3 and Artifactory. You must set the proper credentials in your `omnibus.rb`
+config file or specify them via the command line.
+
+```shell
+$ bundle exec omnibus publish path/to/*.deb --backend s3
+```
+
+### Help
+
+Full help for the Omnibus command line interface can be accessed with the
+`help` command:
+
+```shell
+$ bundle exec omnibus help
+```
+
+Kitchen-based Build Environment
+-------------------------------
+Every Omnibus project ships will a project-specific
+[Berksfile](http://berkshelf.com/) that will allow you to build your omnibus projects on all of the projects listed
+in the `.kitchen.yml`. You can add/remove additional platforms as needed by
+changing the list found in the `.kitchen.yml` `platforms` YAML stanza.
+
+This build environment is designed to get you up-and-running quickly. However,
+there is nothing that restricts you to building on other platforms. Simply use
+the [omnibus cookbook](https://github.com/chef-cookbooks/omnibus) to setup
+your desired platform and execute the build steps listed above.
+
+The default build environment requires Test Kitchen and VirtualBox for local
+development. Test Kitchen also exposes the ability to provision instances using
+various cloud providers like AWS, DigitalOcean, or OpenStack. For more
+information, please see the [Test Kitchen documentation](http://kitchen.ci).
+
+Once you have tweaked your `.kitchen.yml` (or `.kitchen.local.yml`) to your
+liking, you can bring up an individual build environment using the `kitchen`
+command.
+
+```shell
+$ bundle exec kitchen converge chef-ubuntu-1404
+```
+
+Then login to the instance and build the project as described in the Usage
+section:
+
+```shell
+$ bundle exec kitchen login <PROJECT>-ubuntu-1204
+[vagrant@ubuntu...] $ cd chef/omnibus
+[vagrant@ubuntu...] $ bundle install --without development # Don't install dev tools!
+[vagrant@ubuntu...] $ ...
+[vagrant@ubuntu...] $ bundle exec omnibus build <PROJECT> -l internal
+```
+```shell
+$ kitchen login chef-ubuntu-1404
+[vagrant@ubuntu...] $ source load-omnibus-toolchain.sh
+[vagrant@ubuntu...] $ cd chef/omnibus
+[vagrant@ubuntu...] $ bundle install --without development # Don't install dev tools!
+[vagrant@ubuntu...] $ ...
+[vagrant@ubuntu...] $ bundle exec omnibus build chef -l internal
+```
+
+You can also login to Windows instances but will have to manually call the
+`load-omnibus-toolchain.bat` script which initializes the build environment.
+Please note the mounted code directory is also at `C:\home\vagrant\chef\omnibus`
+as opposed to `C:\Users\vagrant\chef\omnibus`.
+
+```shell
+$ bundle exec kitchen login <PROJECT>-windows-81-professional
+Last login: Sat Sep 13 10:19:04 2014 from 172.16.27.1
+Microsoft Windows [Version 6.3.9600]
+(c) 2013 Microsoft Corporation. All rights reserved.
+
+C:\>C:\vagrant\load-omnibus-toolchain.bat
+
+C:\>cd C:\vagrant\code\chef\omnibus
+
+C:\vagrant\code\chef\omnibus>bundle install --without development
+
+C:\vagrant\code\chef\omnibus>bundle exec omnibus build chef -l internal
+```
+
+For a complete list of all commands and platforms, run `kitchen list` or
+`kitchen help`.
+
+License
+-------
+```text
+Copyright 2012-2016, Chef Software, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+```
diff --git a/omnibus/config/projects/angrychef.rb b/omnibus/config/projects/angrychef.rb
new file mode 100644
index 0000000000..ff83f41327
--- /dev/null
+++ b/omnibus/config/projects/angrychef.rb
@@ -0,0 +1,42 @@
+#
+# Copyright 2012-2016, Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# This is a clone of the Chef project that we can install on the Chef build and
+# test machines. As such this project definition is just a thin wrapper around
+# `config/project/chef.rb`.
+#
+current_file = __FILE__
+chef_project_contents = IO.read(File.expand_path("../chef.rb", __FILE__))
+instance_eval chef_project_contents
+
+name "angrychef"
+friendly_name "Angry Chef Client"
+
+if windows?
+ # NOTE: Ruby DevKit fundamentally CANNOT be installed into "Program Files"
+ # Native gems will use gcc which will barf on files with spaces,
+ # which is only fixable if everyone in the world fixes their Makefiles
+ install_dir "#{default_root}/opscode/#{name}"
+ package_name "angrychef"
+else
+ install_dir "#{default_root}/#{name}"
+end
+
+resources_path "#{resources_path}/../chef"
+
+msi_upgrade_code = "D7FDDC1A-7668-404E-AD2F-61F875632A9C"
+project_location_dir = "angrychef"
diff --git a/omnibus/config/projects/chef.rb b/omnibus/config/projects/chef.rb
new file mode 100644
index 0000000000..a0e490ceab
--- /dev/null
+++ b/omnibus/config/projects/chef.rb
@@ -0,0 +1,79 @@
+#
+# Copyright 2012-2016, Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+name "chef"
+friendly_name "Chef Client"
+maintainer "Chef Software, Inc. <maintainers@chef.io>"
+homepage "https://www.chef.io"
+license "Apache-2.0"
+license_file "../LICENSE"
+
+build_iteration 1
+# Do not use __FILE__ after this point, use current_file. If you use __FILE__
+# after this point, any dependent defs (ex: angrychef) that use instance_eval
+# will fail to work correctly.
+current_file ||= __FILE__
+version_file = File.expand_path("../../../../VERSION", current_file)
+build_version IO.read(version_file).strip
+
+if windows?
+ # NOTE: Ruby DevKit fundamentally CANNOT be installed into "Program Files"
+ # Native gems will use gcc which will barf on files with spaces,
+ # which is only fixable if everyone in the world fixes their Makefiles
+ install_dir "#{default_root}/opscode/#{name}"
+ package_name "chef-client"
+else
+ install_dir "#{default_root}/#{name}"
+end
+
+# Load dynamically updated overrides
+overrides_path = File.expand_path("../../../../omnibus_overrides.rb", current_file)
+instance_eval(IO.read(overrides_path), overrides_path)
+
+override :"ruby-windows-devkit", version: "4.5.2-20111229-1559" if windows? && windows_arch_i386?
+
+dependency "preparation"
+
+# All actual dependencies are in chef-complete, so that the addition
+# or removal of a dependency doesn't dirty the entire project file
+dependency "chef-complete"
+
+package :rpm do
+ signing_passphrase ENV["OMNIBUS_RPM_SIGNING_PASSPHRASE"]
+end
+
+proj_to_work_around_cleanroom = self
+package :pkg do
+ identifier "com.getchef.pkg.#{proj_to_work_around_cleanroom.name}"
+ signing_identity "Developer ID Installer: Chef Software, Inc. (EU3VF8YLX2)"
+end
+compress :dmg
+
+msi_upgrade_code = "D607A85C-BDFA-4F08-83ED-2ECB4DCD6BC5"
+project_location_dir = name
+package :msi do
+ fast_msi true
+ upgrade_code msi_upgrade_code
+ wix_candle_extension "WixUtilExtension"
+ wix_light_extension "WixUtilExtension"
+ signing_identity "F74E1A68005E8A9C465C3D2FF7B41F3988F0EA09", machine_store: true
+ parameters ChefLogDllPath: windows_safe_path(gem_path("chef-[0-9]*-mingw32/ext/win32-eventlog/chef-log.dll")),
+ ProjectLocationDir: project_location_dir
+end
+
+package :appx do
+ signing_identity "F74E1A68005E8A9C465C3D2FF7B41F3988F0EA09", machine_store: true
+end
diff --git a/omnibus/config/software/chef-appbundle.rb b/omnibus/config/software/chef-appbundle.rb
new file mode 100644
index 0000000000..8ea21103fb
--- /dev/null
+++ b/omnibus/config/software/chef-appbundle.rb
@@ -0,0 +1,18 @@
+name "chef-appbundle"
+default_version "local_source"
+
+license :project_license
+skip_transitive_dependency_licensing true
+
+source path: project.files_path
+
+dependency "chef"
+
+build do
+ # This is where we get the definitions below
+ require_relative "../../files/chef-appbundle/build-chef-appbundle"
+ extend BuildChefAppbundle
+
+ appbundle_gem "chef"
+ appbundle_gem "ohai"
+end
diff --git a/omnibus/config/software/chef-cleanup.rb b/omnibus/config/software/chef-cleanup.rb
new file mode 100644
index 0000000000..302e841699
--- /dev/null
+++ b/omnibus/config/software/chef-cleanup.rb
@@ -0,0 +1,30 @@
+name "chef-cleanup"
+default_version "local_source"
+
+license :project_license
+skip_transitive_dependency_licensing true
+
+source path: project.files_path
+
+dependency "chef"
+
+build do
+ # This is where we get the definitions below
+ require_relative "../../files/chef/build-chef"
+ extend BuildChef
+
+ # Clear the now-unnecessary git caches, cached gems, and git-checked-out gems
+ block "Delete bundler git cache and git installs" do
+ gemdir = shellout!("#{gem_bin} environment gemdir", env: env).stdout.chomp
+ remove_directory "#{gemdir}/cache"
+ remove_directory "#{gemdir}/bundler"
+ end
+
+ delete "#{install_dir}/embedded/docs"
+ delete "#{install_dir}/embedded/share/man"
+ delete "#{install_dir}/embedded/share/doc"
+ delete "#{install_dir}/embedded/share/gtk-doc"
+ delete "#{install_dir}/embedded/ssl/man"
+ delete "#{install_dir}/embedded/man"
+ delete "#{install_dir}/embedded/info"
+end
diff --git a/omnibus/config/software/chef-complete.rb b/omnibus/config/software/chef-complete.rb
new file mode 100644
index 0000000000..4e2b9f6ec2
--- /dev/null
+++ b/omnibus/config/software/chef-complete.rb
@@ -0,0 +1,20 @@
+name "chef-complete"
+
+license :project_license
+skip_transitive_dependency_licensing true
+
+dependency "chef"
+dependency "chef-appbundle"
+dependency "chef-cleanup"
+
+dependency "gem-permissions"
+dependency "shebang-cleanup"
+dependency "version-manifest"
+dependency "openssl-customization"
+
+if windows?
+ # TODO can this be safely moved to before the chef?
+ # It would make caching better ...
+ dependency "ruby-windows-devkit"
+ dependency "ruby-windows-devkit-bash"
+end
diff --git a/omnibus/config/software/chef-gem-bcrypt_pbkdf-ruby.rb b/omnibus/config/software/chef-gem-bcrypt_pbkdf-ruby.rb
new file mode 100644
index 0000000000..1f7f4d3207
--- /dev/null
+++ b/omnibus/config/software/chef-gem-bcrypt_pbkdf-ruby.rb
@@ -0,0 +1,10 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "MIT"
+license_file "https://raw.githubusercontent.com/mfazekas/bcrypt_pbkdf-ruby/master/COPYING"
+skip_transitive_dependency_licensing true
diff --git a/omnibus/config/software/chef-gem-binding_of_caller.rb b/omnibus/config/software/chef-gem-binding_of_caller.rb
new file mode 100644
index 0000000000..3e7a9f9c70
--- /dev/null
+++ b/omnibus/config/software/chef-gem-binding_of_caller.rb
@@ -0,0 +1,10 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "MIT"
+license_file "https://github.com/banister/binding_of_caller/blob/master/LICENSE"
+skip_transitive_dependency_licensing true
diff --git a/omnibus/config/software/chef-gem-byebug.rb b/omnibus/config/software/chef-gem-byebug.rb
new file mode 100644
index 0000000000..3aef706e82
--- /dev/null
+++ b/omnibus/config/software/chef-gem-byebug.rb
@@ -0,0 +1,10 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "MIT"
+license_file "https://github.com/deivid-rodriguez/byebug/blob/master/LICENSE"
+skip_transitive_dependency_licensing true
diff --git a/omnibus/config/software/chef-gem-debug_inspector.rb b/omnibus/config/software/chef-gem-debug_inspector.rb
new file mode 100644
index 0000000000..ab818768ea
--- /dev/null
+++ b/omnibus/config/software/chef-gem-debug_inspector.rb
@@ -0,0 +1,10 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "MIT"
+license_file "https://github.com/banister/debug_inspector/blob/master/README.md"
+skip_transitive_dependency_licensing true
diff --git a/omnibus/config/software/chef-gem-ffi-yajl.rb b/omnibus/config/software/chef-gem-ffi-yajl.rb
new file mode 100644
index 0000000000..44f98446bd
--- /dev/null
+++ b/omnibus/config/software/chef-gem-ffi-yajl.rb
@@ -0,0 +1,12 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "MIT"
+license_file "https://github.com/chef/ffi-yajl/blob/master/LICENSE"
+skip_transitive_dependency_licensing true
+
+dependency "chef-gem-libyajl2"
diff --git a/omnibus/config/software/chef-gem-ffi.rb b/omnibus/config/software/chef-gem-ffi.rb
new file mode 100644
index 0000000000..ea8879c2ac
--- /dev/null
+++ b/omnibus/config/software/chef-gem-ffi.rb
@@ -0,0 +1,12 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "BSD-3-Clause"
+license_file "https://github.com/ffi/ffi/blob/master/LICENSE"
+license_file "https://github.com/ffi/ffi/blob/master/COPYING"
+license_file "https://github.com/ffi/ffi/blob/master/LICENSE.SPECS"
+skip_transitive_dependency_licensing true
diff --git a/omnibus/config/software/chef-gem-json.rb b/omnibus/config/software/chef-gem-json.rb
new file mode 100644
index 0000000000..9217359ba2
--- /dev/null
+++ b/omnibus/config/software/chef-gem-json.rb
@@ -0,0 +1,11 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "Ruby"
+license_file "https://github.com/flori/json/blob/master/README.md"
+license_file "https://www.ruby-lang.org/en/about/license.txt"
+skip_transitive_dependency_licensing true
diff --git a/omnibus/config/software/chef-gem-libyajl2.rb b/omnibus/config/software/chef-gem-libyajl2.rb
new file mode 100644
index 0000000000..47ef42e1cf
--- /dev/null
+++ b/omnibus/config/software/chef-gem-libyajl2.rb
@@ -0,0 +1,10 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "Apache-2.0"
+license_file "https://github.com/chef/libyajl2-gem/blob/master/LICENSE"
+skip_transitive_dependency_licensing true
diff --git a/omnibus/config/software/chef-gem-mini_portile2.rb b/omnibus/config/software/chef-gem-mini_portile2.rb
new file mode 100644
index 0000000000..36a2b833dd
--- /dev/null
+++ b/omnibus/config/software/chef-gem-mini_portile2.rb
@@ -0,0 +1,10 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "MIT"
+license_file "https://github.com/flavorjones/mini_portile/blob/master/LICENSE.txt"
+skip_transitive_dependency_licensing true
diff --git a/omnibus/config/software/chef-gem-nokogiri.rb b/omnibus/config/software/chef-gem-nokogiri.rb
new file mode 100644
index 0000000000..c6b8d03822
--- /dev/null
+++ b/omnibus/config/software/chef-gem-nokogiri.rb
@@ -0,0 +1,13 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "MIT"
+license_file "https://github.com/ruby-prof/ruby-prof/blob/master/LICENSE"
+skip_transitive_dependency_licensing true
+
+dependency "chef-gem-pkg-config"
+dependency "chef-gem-mini_portile2"
diff --git a/omnibus/config/software/chef-gem-pkg-config.rb b/omnibus/config/software/chef-gem-pkg-config.rb
new file mode 100644
index 0000000000..051091b73f
--- /dev/null
+++ b/omnibus/config/software/chef-gem-pkg-config.rb
@@ -0,0 +1,10 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "LGPL-2.1"
+license_file "https://github.com/ruby-gnome2/pkg-config/blob/master/LGPL-2.1"
+skip_transitive_dependency_licensing true
diff --git a/omnibus/config/software/chef-gem-rbnacl-libsodium.rb b/omnibus/config/software/chef-gem-rbnacl-libsodium.rb
new file mode 100644
index 0000000000..90bbc69dfb
--- /dev/null
+++ b/omnibus/config/software/chef-gem-rbnacl-libsodium.rb
@@ -0,0 +1,10 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "MIT"
+license_file "https://raw.githubusercontent.com/cryptosphere/rbnacl-libsodium/master/LICENSE"
+skip_transitive_dependency_licensing true
diff --git a/omnibus/config/software/chef-gem-ruby-prof.rb b/omnibus/config/software/chef-gem-ruby-prof.rb
new file mode 100644
index 0000000000..af90212d23
--- /dev/null
+++ b/omnibus/config/software/chef-gem-ruby-prof.rb
@@ -0,0 +1,10 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "BSD-2-Clause"
+license_file "https://github.com/ruby-prof/ruby-prof/blob/master/LICENSE"
+skip_transitive_dependency_licensing true
diff --git a/omnibus/config/software/chef-gem-ruby-shadow.rb b/omnibus/config/software/chef-gem-ruby-shadow.rb
new file mode 100644
index 0000000000..02fc906d9d
--- /dev/null
+++ b/omnibus/config/software/chef-gem-ruby-shadow.rb
@@ -0,0 +1,11 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "Public-Domain"
+license_file "https://github.com/apalmblad/ruby-shadow/blob/master/LICENSE"
+license_file "http://creativecommons.org/licenses/publicdomain/"
+skip_transitive_dependency_licensing true
diff --git a/omnibus/config/software/chef.rb b/omnibus/config/software/chef.rb
new file mode 100644
index 0000000000..c53a2339ae
--- /dev/null
+++ b/omnibus/config/software/chef.rb
@@ -0,0 +1,87 @@
+name "chef"
+default_version "local_source"
+
+license :project_license
+
+# For the specific super-special version "local_source", build the source from
+# the local git checkout. This is what you'd want to occur by default if you
+# just ran omnibus build locally.
+version("local_source") do
+ source path: File.expand_path("../..", project.files_path),
+ # Since we are using the local repo, we try to not copy any files
+ # that are generated in the process of bundle installing omnibus.
+ # If the install steps are well-behaved, this should not matter
+ # since we only perform bundle and gem installs from the
+ # omnibus cache source directory, but we do this regardless
+ # to maintain consistency between what a local build sees and
+ # what a github based build will see.
+ options: { exclude: [ "omnibus/vendor" ] }
+end
+
+# For any version other than "local_source", fetch from github.
+if version != "local_source"
+ source git: "git://github.com/chef/chef.git"
+end
+
+# For nokogiri
+dependency "libxml2"
+dependency "libxslt"
+dependency "libiconv"
+dependency "liblzma"
+dependency "zlib"
+
+# ruby and bundler and friends
+dependency "ruby"
+dependency "rubygems"
+dependency "bundler"
+
+# Install all the native gems separately
+# Worst offenders first to take best advantage of cache:
+dependency "chef-gem-ffi-yajl"
+dependency "chef-gem-nokogiri"
+dependency "chef-gem-libyajl2"
+dependency "chef-gem-ruby-prof"
+dependency "chef-gem-byebug"
+dependency "chef-gem-debug_inspector"
+dependency "chef-gem-binding_of_caller"
+unless ios_xr? || solaris?
+ dependency "chef-gem-rbnacl-libsodium"
+ dependency "chef-gem-bcrypt_pbkdf-ruby"
+end
+
+# Now everyone else, in alphabetical order because we don't care THAT much
+Dir.entries(File.dirname(__FILE__)).sort.each do |gem_software|
+ if gem_software =~ /^(chef-gem-.+)\.rb$/
+ dependency $1
+ end
+end
+
+build do
+ # This is where we get the definitions below
+ require_relative "../../files/chef/build-chef"
+ extend BuildChef
+
+ project_env = env.dup
+ project_env["BUNDLE_GEMFILE"] = project_gemfile
+
+ # Prepare to install: build config, retries, job, frozen=true
+ # TODO Windows install seems to sometimes install already-installed gems such
+ # as gherkin (and fail as a result) if you use jobs > 1.
+ create_bundle_config(project_gemfile, retries: 4, jobs: windows? ? 1 : 7, frozen: true)
+
+ # Install all the things. Arguments are specified in .bundle/config (see create_bundle_config)
+ block { log.info(log_key) { "" } }
+ bundle "install --verbose", env: project_env
+
+ # Check that it worked
+ block { log.info(log_key) { "" } }
+ bundle "check", env: project_env
+
+ # fix up git-sourced gems
+ properly_reinstall_git_and_path_sourced_gems
+ install_shared_gemfile
+
+ # Check that the final gemfile worked
+ block { log.info(log_key) { "" } }
+ bundle "check", env: env, cwd: File.dirname(shared_gemfile)
+end
diff --git a/omnibus/files/chef-appbundle/build-chef-appbundle.rb b/omnibus/files/chef-appbundle/build-chef-appbundle.rb
new file mode 100644
index 0000000000..eaf4904501
--- /dev/null
+++ b/omnibus/files/chef-appbundle/build-chef-appbundle.rb
@@ -0,0 +1,93 @@
+require_relative "../chef-gem/build-chef-gem"
+
+module BuildChefAppbundle
+ include BuildChefGem
+
+ def lockdown_gem(gem_name)
+ shared_gemfile = self.shared_gemfile
+
+ # Update the Gemfile to restrict to built versions so that bundle installs
+ # will do the right thing
+ block "Lock down the #{gem_name} gem" do
+ installed_path = shellout!("#{bundle_bin} show #{gem_name}", env: env, cwd: install_dir).stdout.chomp
+ installed_gemfile = File.join(installed_path, "Gemfile")
+
+ #
+ # Include the main distribution Gemfile in the gem's Gemfile
+ #
+ # NOTE: if this fails and the build retries, you will see this multiple
+ # times in the file.
+ #
+ distribution_gemfile = Pathname(shared_gemfile).relative_path_from(Pathname(installed_gemfile)).to_s
+ gemfile_text = <<-EOM.gsub(/^\s+/, "")
+ # Lock gems that are part of the distribution
+ distribution_gemfile = File.expand_path(#{distribution_gemfile.inspect}, __FILE__)
+ instance_eval(IO.read(distribution_gemfile), distribution_gemfile)
+ EOM
+ gemfile_text << IO.read(installed_gemfile)
+ create_file(installed_gemfile) { gemfile_text }
+
+ # Remove the gemfile.lock
+ remove_file("#{installed_gemfile}.lock") if File.exist?("#{installed_gemfile}.lock")
+
+ # If it's frozen, make it not be.
+ shellout!("#{bundle_bin} config --delete frozen")
+
+ # This could be changed to `bundle install` if we wanted to actually
+ # install extra deps out of their gemfile ...
+ shellout!("#{bundle_bin} lock", env: env, cwd: installed_path)
+ # bundle lock doesn't always tell us when it fails, so we have to check :/
+ unless File.exist?("#{installed_gemfile}.lock")
+ raise "bundle lock failed: no #{installed_gemfile}.lock created!"
+ end
+
+ # Ensure all the gems we need are actually installed (if the bundle adds
+ # something, we need to know about it so we can include it in the main
+ # solve).
+ # Save bundle config and modify to use --without development before checking
+ bundle_config = File.expand_path("../.bundle/config", installed_gemfile)
+ orig_config = IO.read(bundle_config) if File.exist?(bundle_config)
+ # "test", "changelog" and "guard" come from berkshelf, "maintenance" comes from chef
+ # "tools" and "integration" come from inspec
+ shellout!("#{bundle_bin} config --local without #{without_groups.join(":")}", env: env, cwd: installed_path)
+ shellout!("#{bundle_bin} config --local frozen 1")
+
+ shellout!("#{bundle_bin} check", env: env, cwd: installed_path)
+
+ # Restore bundle config
+ if orig_config
+ create_file(bundle_config) { orig_config }
+ else
+ remove_file bundle_config
+ end
+ end
+ end
+
+ # appbundle the gem, making /opt/chef/bin/<binary> do the superfast pinning
+ # thing.
+ #
+ # To protect the app from loading the wrong versions of things, it uses
+ # appbundler against the resulting file.
+ #
+ # Relocks the Gemfiles inside the specified gems (e.g. berkshelf, test-kitchen,
+ # chef) to use the distribution's chosen gems.
+ def appbundle_gem(gem_name)
+ # First lock the gemfile down.
+ lockdown_gem(gem_name)
+
+ shared_gemfile = self.shared_gemfile
+
+ # Ensure the main bin dir exists
+ bin_dir = File.join(install_dir, "bin")
+ mkdir(bin_dir)
+
+ block "Lock down the #{gem_name} gem" do
+ installed_path = shellout!("#{bundle_bin} show #{gem_name}", env: env, cwd: install_dir).stdout.chomp
+
+ # appbundle the gem
+ appbundler_args = [ installed_path, bin_dir, gem_name ]
+ appbundler_args = appbundler_args.map { |a| ::Shellwords.escape(a) }
+ shellout!("#{appbundler_bin} #{appbundler_args.join(" ")}", env: env, cwd: installed_path)
+ end
+ end
+end
diff --git a/omnibus/files/chef-gem/build-chef-gem.rb b/omnibus/files/chef-gem/build-chef-gem.rb
new file mode 100644
index 0000000000..701461b01e
--- /dev/null
+++ b/omnibus/files/chef-gem/build-chef-gem.rb
@@ -0,0 +1,123 @@
+require "shellwords"
+require "pathname"
+require "bundler"
+require_relative "../../../version_policy"
+
+# Common definitions and helpers (like compile environment and binary
+# locations) for all software definitions.
+module BuildChefGem
+ PLATFORM_FAMILY_FAMILIES = {
+ "linux" => %w{wrlinux debian fedora rhel suse gentoo slackware arch exherbo alpine},
+ "bsd" => %w{dragonflybsd freebsd netbsd openbsd},
+ "solaris" => %w{smartos omnios openindiana opensolaris solaris2 nextentacore},
+ "aix" => %w{aix},
+ "windows" => %w{windows},
+ "mac_os_x" => %w{mac_os_x},
+ }
+ def platform_family_families
+ PLATFORM_FAMILY_FAMILIES.keys
+ end
+
+ def platform_family_family
+ PLATFORM_FAMILY_FAMILIES.
+ select { |key, families| families.include?(Omnibus::Ohai["platform_family"]) }.
+ first[0]
+ end
+
+ def embedded_bin(binary)
+ windows_safe_path("#{install_dir}/embedded/bin/#{binary}")
+ end
+
+ def appbundler_bin
+ embedded_bin("appbundler")
+ end
+
+ def bundle_bin
+ embedded_bin("bundle")
+ end
+
+ def gem_bin
+ embedded_bin("gem")
+ end
+
+ def rake_bin
+ embedded_bin("rake")
+ end
+
+ def without_groups
+ # Add --without for every known OS except the one we're in.
+ exclude_os_groups = platform_family_families - [ platform_family_family ]
+ (INSTALL_WITHOUT_GROUPS + exclude_os_groups).map { |g| g.to_sym }
+ end
+
+ #
+ # Get the path to the top level shared Gemfile included by all individual
+ # Gemfiles
+ #
+ def shared_gemfile
+ File.join(install_dir, "Gemfile")
+ end
+
+ # A common env for building everything including nokogiri and dep-selector-libgecode
+ def env
+ env = with_standard_compiler_flags(with_embedded_path, bfd_flags: true)
+
+ # From dep-selector-libgecode
+ # On some RHEL-based systems, the default GCC that's installed is 4.1. We
+ # need to use 4.4, which is provided by the gcc44 and gcc44-c++ packages.
+ # These do not use the gcc binaries so we set the flags to point to the
+ # correct version here.
+ if File.exist?("/usr/bin/gcc44")
+ env["CC"] = "gcc44"
+ env["CXX"] = "g++44"
+ end
+
+ # From dep-selector-libgecode
+ # Ruby DevKit ships with BSD Tar
+ env["PROG_TAR"] = "bsdtar" if windows?
+ env["ARFLAGS"] = "rv #{env["ARFLAGS"]}" if env["ARFLAGS"]
+
+ # Set up nokogiri environment and args
+ env["NOKOGIRI_USE_SYSTEM_LIBRARIES"] = "true"
+ env
+ end
+
+ #
+ # Install arguments for various gems (to be passed to `gem install` or set in
+ # `bundle config build.<gemname>`).
+ #
+ def all_install_args
+ @all_install_args = {
+ "nokogiri" => %W{
+ --use-system-libraries
+ --with-xml2-lib=#{Shellwords.escape("#{install_dir}/embedded/lib")}
+ --with-xml2-include=#{Shellwords.escape("#{install_dir}/embedded/include/libxml2")}
+ --with-xslt-lib=#{Shellwords.escape("#{install_dir}/embedded/lib")}
+ --with-xslt-include=#{Shellwords.escape("#{install_dir}/embedded/include/libxslt")}
+ --with-iconv-dir=#{Shellwords.escape("#{install_dir}/embedded")}
+ --with-zlib-dir=#{Shellwords.escape("#{install_dir}/embedded")}
+ }.join(" "),
+ }
+ end
+
+ # gem install arguments for a particular gem. "" if no special args.
+ def install_args_for(gem_name)
+ all_install_args[gem_name] || ""
+ end
+
+ # Give block all the variables
+ def block(*args, &block)
+ super do
+ extend BuildChefGem
+ instance_eval(&block)
+ end
+ end
+
+ # Give build all the variables
+ def build(*args, &block)
+ super do
+ extend BuildChefGem
+ instance_eval(&block)
+ end
+ end
+end
diff --git a/omnibus/files/chef-gem/build-chef-gem/gem-install-software-def.rb b/omnibus/files/chef-gem/build-chef-gem/gem-install-software-def.rb
new file mode 100644
index 0000000000..3022bf448e
--- /dev/null
+++ b/omnibus/files/chef-gem/build-chef-gem/gem-install-software-def.rb
@@ -0,0 +1,118 @@
+require "bundler"
+require "omnibus"
+require_relative "../build-chef-gem"
+require_relative "../../../../tasks/gemfile_util"
+
+module BuildChefGem
+ class GemInstallSoftwareDef
+ def self.define(software, software_filename)
+ new(software, software_filename).send(:define)
+ end
+
+ include BuildChefGem
+ include Omnibus::Logging
+
+ protected
+
+ def initialize(software, software_filename)
+ @software = software
+ @software_filename = software_filename
+ end
+
+ attr_reader :software, :software_filename
+
+ def define
+ software.name "#{File.basename(software_filename)[0..-4]}"
+ software.default_version gem_version
+
+ # If the source directory for building stuff changes, tell omnibus to
+ # de-cache us
+ software.source path: File.expand_path("../..", __FILE__)
+
+ # ruby and bundler and friends
+ software.dependency "ruby"
+ software.dependency "rubygems"
+
+ gem_name = self.gem_name
+ gem_version = self.gem_version
+ gem_metadata = self.gem_metadata
+ lockfile_path = self.lockfile_path
+
+ software.build do
+ extend BuildChefGem
+
+ if gem_version == "<skip>"
+ if gem_metadata
+ block do
+ log.info(log_key) { "#{gem_name} has source #{gem_metadata} in #{lockfile_path}. We only cache rubygems.org installs in omnibus to keep things simple. The chef step will build #{gem_name} ..." }
+ end
+ else
+ block do
+ log.info(log_key) { "#{gem_name} is not in the #{lockfile_path}. This can happen if your OS doesn't build it, or if chef no longer depends on it. Skipping ..." }
+ end
+ end
+ else
+ block do
+ log.info(log_key) { "Found version #{gem_version} of #{gem_name} in #{lockfile_path}. Building early to take advantage of omnibus caching ..." }
+ end
+ gem "install #{gem_name} -v #{gem_version} --no-doc --no-ri --ignore-dependencies --verbose -- #{install_args_for(gem_name)}", env: env
+ end
+ end
+ end
+
+ # Path above omnibus (where Gemfile is)
+ def root_path
+ File.expand_path("../../../../..", __FILE__)
+ end
+
+ def gemfile_path
+ File.join(root_path, "Gemfile")
+ end
+
+ def lockfile_path
+ "#{gemfile_path}.lock"
+ end
+
+ def gem_name
+ @gem_name ||= begin
+ # File must be named chef-<gemname>.rb
+ # Will look at chef/Gemfile.lock and install that version of the gem using "gem install"
+ # (and only that version)
+ if File.basename(software_filename) =~ /^chef-gem-(.+)\.rb$/
+ $1
+ else
+ raise "#{software_filename} must be named chef-<gemname>.rb to build a gem automatically"
+ end
+ end
+ end
+
+ def gem_metadata
+ @gem_metadata ||= begin
+ bundle = GemfileUtil::Bundle.parse(gemfile_path, lockfile_path)
+ result = bundle.gems[gem_name]
+ if result
+ if bundle.select_gems(without_groups: without_groups).include?(gem_name)
+ log.info(software.name) { "Using #{gem_name} version #{result[:version]} from #{gemfile_path}" }
+ result
+ else
+ log.info(software.name) { "#{gem_name} not loaded from #{gemfile_path} because it was only in groups #{without_groups.join(", ")}. Skipping ..." }
+ nil
+ end
+ else
+ log.info(software.name) { "#{gem_name} was not found in #{lockfile_path}. Skipping ..." }
+ nil
+ end
+ end
+ end
+
+ def gem_version
+ @gem_version ||= begin
+ if gem_metadata && URI(gem_metadata[:source]) == URI("https://rubygems.org/")
+ gem_metadata[:version]
+ else
+ "<skip>"
+ end
+ end
+ end
+ end
+end
diff --git a/omnibus/files/chef/build-chef.rb b/omnibus/files/chef/build-chef.rb
new file mode 100644
index 0000000000..4b8ec78054
--- /dev/null
+++ b/omnibus/files/chef/build-chef.rb
@@ -0,0 +1,127 @@
+require "shellwords"
+require "pathname"
+require "bundler"
+require_relative "../chef-gem/build-chef-gem"
+require_relative "../../../version_policy"
+
+# We use this to break up the `build` method into readable parts
+module BuildChef
+ include BuildChefGem
+
+ def create_bundle_config(gemfile, without: without_groups, retries: nil, jobs: nil, frozen: nil)
+ bundle_config = File.expand_path("../.bundle/config", gemfile)
+
+ block "Put build config into #{bundle_config}: #{{ without: without, retries: retries, jobs: jobs, frozen: frozen }}" do
+ # bundle config build.nokogiri #{nokogiri_build_config} messes up the line,
+ # so we write it directly ourselves.
+ new_bundle_config = "---\n"
+ new_bundle_config << "BUNDLE_WITHOUT: #{Array(without).join(":")}\n" if without
+ new_bundle_config << "BUNDLE_RETRY: #{retries}\n" if retries
+ new_bundle_config << "BUNDLE_JOBS: #{jobs}\n" if jobs
+ new_bundle_config << "BUNDLE_FROZEN: '1'\n" if frozen
+ all_install_args.each do |gem_name, install_args|
+ new_bundle_config << "BUNDLE_BUILD__#{gem_name.upcase}: #{install_args}\n"
+ end
+ create_file(bundle_config) { new_bundle_config }
+ end
+ end
+
+ #
+ # Get the (possibly platform-specific) path to the Gemfile.
+ #
+ def project_gemfile
+ File.join(project_dir, "Gemfile")
+ end
+
+ #
+ # Some gems we installed don't end up in the `gem list` due to the fact that
+ # they have git sources (`gem 'chef', github: 'chef/chef'`) or paths (`gemspec`
+ # or `gem 'chef-config', path: 'chef-config'`). To get them in there, we need
+ # to go through these gems, run `rake install` from their top level, and
+ # then delete the git cached versions.
+ #
+ # Once we finish with all this, we update the Gemfile that will end up in the
+ # top-level install so that it doesn't have git or path references anymore.
+ #
+ def properly_reinstall_git_and_path_sourced_gems
+ # Emit blank line to separate different tasks
+ block { log.info(log_key) { "" } }
+ project_env = env.dup.merge("BUNDLE_GEMFILE" => project_gemfile)
+
+ # Reinstall git-sourced or path-sourced gems, and delete the originals
+ block "Reinstall git-sourced gems properly" do
+ # Grab info about the gem environment so we can make decisions
+ gemdir = shellout!("#{gem_bin} environment gemdir", env: env).stdout.chomp
+ gem_install_dir = File.join(gemdir, "gems")
+
+ # bundle list --paths gets us the list of gem install paths. Get the ones
+ # that are installed local (git and path sources like `gem :x, github: 'chef/x'`
+ # or `gem :x, path: '.'` or `gemspec`). To do this, we just detect which ones
+ # have properly-installed paths (in the `gems` directory that shows up when
+ # you run `gem list`).
+ locally_installed_gems = shellout!("#{bundle_bin} list --paths", env: project_env, cwd: project_dir).
+ stdout.lines.select { |gem_path| !gem_path.start_with?(gem_install_dir) }
+
+ # Install the gems for real using `rake install` in their directories
+ locally_installed_gems.each do |gem_path|
+ gem_path = gem_path.chomp
+ # We use the already-installed bundle to rake install, because (hopefully)
+ # just rake installing doesn't require anything special.
+ # Emit blank line to separate different tasks
+ log.info(log_key) { "" }
+ log.info(log_key) { "Properly installing git or path sourced gem #{gem_path} using rake install" }
+ shellout!("#{bundle_bin} exec #{rake_bin} install", env: project_env, cwd: gem_path)
+ end
+ end
+ end
+
+ def install_shared_gemfile
+ # Emit blank line to separate different tasks
+ block { log.info(log_key) { "" } }
+
+ shared_gemfile = self.shared_gemfile
+ project_env = env.dup.merge("BUNDLE_GEMFILE" => project_gemfile)
+
+ # Show the config for good measure
+ bundle "config", env: project_env
+
+ # Make `Gemfile` point to these by removing path and git sources and pinning versions.
+ block "Rewrite Gemfile using all properly-installed gems" do
+ gem_pins = ""
+ result = []
+ shellout!("#{bundle_bin} list", env: project_env).stdout.lines.map do |line|
+ if line =~ /^\s*\*\s*(\S+)\s+\((\S+).*\)\s*$/
+ name, version = $1, $2
+ # rubocop is an exception, since different projects disagree
+ next if GEMS_ALLOWED_TO_FLOAT.include?(name)
+ gem_pins << "gem #{name.inspect}, #{version.inspect}, override: true\n"
+ end
+ end
+
+ # Find the installed chef gem by looking for lib/chef.rb
+ chef_gem = File.expand_path("../..", shellout!("#{gem_bin} which chef", env: project_env).stdout.chomp)
+ # Figure out the path to gemfile_util from there
+ gemfile_util = Pathname.new(File.join(chef_gem, "tasks", "gemfile_util"))
+ gemfile_util = gemfile_util.relative_path_from(Pathname.new(shared_gemfile).dirname)
+
+ create_file(shared_gemfile) { <<-EOM }
+ # Meant to be included in component Gemfiles at the beginning with:
+ #
+ # instance_eval(IO.read("#{install_dir}/Gemfile"), "#{install_dir}/Gemfile")
+ #
+ # Override any existing gems with our own.
+ require_relative "#{gemfile_util}"
+ extend GemfileUtil
+ #{gem_pins}
+ EOM
+ end
+
+ shared_gemfile_env = env.dup.merge("BUNDLE_GEMFILE" => shared_gemfile)
+
+ # Create a `Gemfile.lock` at the final location
+ bundle "lock", env: shared_gemfile_env
+
+ # Freeze the location's Gemfile.lock.
+ create_bundle_config(shared_gemfile, frozen: true)
+ end
+end
diff --git a/omnibus/files/openssl-customization/windows/ssl_env_hack.rb b/omnibus/files/openssl-customization/windows/ssl_env_hack.rb
new file mode 100644
index 0000000000..26b68e4191
--- /dev/null
+++ b/omnibus/files/openssl-customization/windows/ssl_env_hack.rb
@@ -0,0 +1,34 @@
+#
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This script sets the SSL_CERT_FILE environment variable to the CA cert bundle
+# that ships with omnibus packages of Chef and Chef DK. If this environment
+# variable is already configured, this script is a no-op.
+#
+# This is required to make Chef tools use https URLs out of the box.
+
+unless ENV.key?("SSL_CERT_FILE")
+ base_dirs = File.dirname(__FILE__).split(File::SEPARATOR)
+
+ (base_dirs.length - 1).downto(0) do |i|
+ candidate_ca_bundle = File.join(base_dirs[0..i] + [ "ssl/certs/cacert.pem" ])
+ if File.exist?(candidate_ca_bundle)
+ ENV["SSL_CERT_FILE"] = candidate_ca_bundle
+ break
+ end
+ end
+end
diff --git a/omnibus/omnibus.rb b/omnibus/omnibus.rb
new file mode 100644
index 0000000000..dfbd2bc338
--- /dev/null
+++ b/omnibus/omnibus.rb
@@ -0,0 +1,55 @@
+#
+# This file is used to configure the Omnibus projects in this repo. It contains
+# some minimal configuration examples for working with Omnibus. For a full list
+# of configurable options, please see the documentation for +omnibus/config.rb+.
+#
+
+# Build internally
+# ------------------------------
+# By default, Omnibus uses system folders (like +/var+ and +/opt+) to build and
+# cache components. If you would to build everything internally, you can
+# uncomment the following options. This will prevent the need for root
+# permissions in most cases.
+#
+# Uncomment this line to change the default base directory to "local"
+# -------------------------------------------------------------------
+# base_dir './local'
+#
+# Alternatively you can tune the individual values
+# ------------------------------------------------
+# cache_dir './local/omnibus/cache'
+# git_cache_dir './local/omnibus/cache/git_cache'
+# source_dir './local/omnibus/src'
+# build_dir './local/omnibus/build'
+# package_dir './local/omnibus/pkg'
+# package_tmp './local/omnibus/pkg-tmp'
+
+# Windows architecture defaults - set to x86 unless otherwise specified.
+# ------------------------------
+env_omnibus_windows_arch = (ENV["OMNIBUS_WINDOWS_ARCH"] || "").downcase
+env_omnibus_windows_arch = :x86 unless %w{x86 x64}.include?(env_omnibus_windows_arch)
+
+windows_arch env_omnibus_windows_arch
+
+# Disable git caching
+# ------------------------------
+# use_git_caching false
+
+# Enable S3 asset caching
+# ------------------------------
+use_s3_caching true
+s3_access_key ENV["AWS_ACCESS_KEY_ID"]
+s3_secret_key ENV["AWS_SECRET_ACCESS_KEY"]
+s3_bucket "opscode-omnibus-cache"
+
+build_retries 3
+fetcher_retries 3
+fetcher_read_timeout 120
+
+# Load additional software
+# ------------------------------
+# software_gems ['omnibus-software', 'my-company-software']
+# local_software_dirs ['/path/to/local/software']
+
+fatal_transitive_dependency_licensing_warnings true
+fips_mode (ENV["OMNIBUS_FIPS_MODE"] || "").casecmp("true") >= 0
diff --git a/omnibus/package-scripts/angrychef/postinst b/omnibus/package-scripts/angrychef/postinst
new file mode 100755
index 0000000000..a173efeaef
--- /dev/null
+++ b/omnibus/package-scripts/angrychef/postinst
@@ -0,0 +1,111 @@
+#!/bin/sh
+# WARNING: REQUIRES /bin/sh
+#
+# - must run on /bin/sh on solaris 9
+# - must run on /bin/sh on AIX 6.x
+# - if you think you are a bash wizard, you probably do not understand
+# this programming language. do not touch.
+# - if you are under 40, get peer review from your elders.
+#
+# Install a full Opscode Client
+#
+
+PROGNAME=`basename $0`
+INSTALLER_DIR=/opt/angrychef
+CONFIG_DIR=/etc/chef
+USAGE="usage: $0 [-v validation_key] ([-o organization] || [-u url])"
+
+error_exit()
+{
+ echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2
+ exit 1
+}
+
+is_darwin()
+{
+ uname -v | grep "^Darwin" 2>&1 >/dev/null
+}
+
+is_smartos()
+{
+ uname -v | grep "^joyent" 2>&1 >/dev/null
+}
+
+if is_smartos; then
+ PREFIX="/opt/local"
+elif is_darwin; then
+ PREFIX="/usr/local"
+ mkdir -p "$PREFIX/bin"
+else
+ PREFIX="/usr"
+fi
+
+validation_key=
+organization=
+chef_url=
+
+while getopts o:u:v: opt
+do
+ case "$opt" in
+ v) validation_key="${OPTARG}";;
+ o) organization="${OPTARG}"; chef_url="https://api.opscode.com/organizations/${OPTARG}";;
+ u) chef_url="${OPTARG}";;
+ \?) # unknown flag
+ echo >&2 ${USAGE}
+ exit 1;;
+ esac
+done
+shift `expr ${OPTIND} - 1`
+
+if [ "" != "$chef_url" ]; then
+ mkdir -p ${CONFIG_DIR} || error_exit "Cannot create ${CONFIG_DIR}!"
+ (
+ cat <<'EOP'
+log_level :info
+log_location STDOUT
+EOP
+ ) > ${CONFIG_DIR}/client.rb
+ if [ "" != "$chef_url" ]; then
+ echo "chef_server_url '${chef_url}'" >> ${CONFIG_DIR}/client.rb
+ fi
+ if [ "" != "$organization" ]; then
+ echo "validation_client_name '${organization}-validator'" >> ${CONFIG_DIR}/client.rb
+ fi
+ chmod 644 ${CONFIG_DIR}/client.rb
+fi
+
+if [ "" != "$validation_key" ]; then
+ cp ${validation_key} ${CONFIG_DIR}/validation.pem || error_exit "Cannot copy the validation key!"
+ chmod 600 ${CONFIG_DIR}/validation.pem
+fi
+
+# rm -f before ln -sf is required for solaris 9
+rm -f $PREFIX/bin/chef-client
+rm -f $PREFIX/bin/chef-solo
+rm -f $PREFIX/bin/chef-apply
+rm -f $PREFIX/bin/chef-shell
+rm -f $PREFIX/bin/knife
+rm -f $PREFIX/bin/ohai
+
+ln -sf $INSTALLER_DIR/bin/chef-solo $PREFIX/bin || error_exit "Cannot link chef-solo to $PREFIX/bin"
+if [ -f "$INSTALLER_DIR/bin/chef-apply" ]; then
+ ln -sf $INSTALLER_DIR/bin/chef-apply $PREFIX/bin || error_exit "Cannot link chef-apply to $PREFIX/bin"
+fi
+if [ -f "$INSTALLER_DIR/bin/chef-shell" ]; then
+ ln -sf $INSTALLER_DIR/bin/chef-shell $PREFIX/bin || error_exit "Cannot link chef-shell to $PREFIX/bin"
+fi
+ln -sf $INSTALLER_DIR/bin/knife $PREFIX/bin || error_exit "Cannot link knife to $PREFIX/bin"
+ln -sf $INSTALLER_DIR/bin/ohai $PREFIX/bin || error_exit "Cannot link ohai to $PREFIX/bin"
+
+# We test for the presence of /usr/bin/chef-client to know if this script succeeds, so this
+# must appear as the last real action in the script
+ln -sf $INSTALLER_DIR/bin/chef-client $PREFIX/bin || error_exit "Cannot link chef-client to $PREFIX/bin"
+
+# Ensure all files/directories in $INSTALLER_DIR are owned by root. This
+# has been fixed on new installs but upgrades from old installs need to
+# be manually fixed.
+chown -Rh 0:0 $INSTALLER_DIR
+
+echo "Thank you for installing Chef!"
+
+exit 0
diff --git a/omnibus/package-scripts/angrychef/postrm b/omnibus/package-scripts/angrychef/postrm
new file mode 100755
index 0000000000..247688074e
--- /dev/null
+++ b/omnibus/package-scripts/angrychef/postrm
@@ -0,0 +1,42 @@
+#!/bin/sh
+# WARNING: REQUIRES /bin/sh
+#
+# - must run on /bin/sh on solaris 9
+# - must run on /bin/sh on AIX 6.x
+# - if you think you are a bash wizard, you probably do not understand
+# this programming language. do not touch.
+# - if you are under 40, get peer review from your elders.
+
+is_smartos() {
+ uname -v | grep "^joyent" 2>&1 >/dev/null
+}
+
+is_darwin()
+{
+ uname -v | grep "^Darwin" 2>&1 >/dev/null
+}
+
+if is_smartos; then
+ PREFIX="/opt/local"
+elif is_darwin; then
+ PREFIX="/usr/local"
+else
+ PREFIX="/usr"
+fi
+
+cleanup_symlinks() {
+ binaries="chef-client chef-solo chef-apply chef-shell knife ohai"
+ for binary in $binaries; do
+ rm -f $PREFIX/bin/$binary
+ done
+}
+
+# Clean up binary symlinks if they exist
+# see: http://tickets.opscode.com/browse/CHEF-3022
+if [ ! -f /etc/redhat-release -a ! -f /etc/fedora-release -a ! -f /etc/system-release -a ! -f /etc/SuSE-release ]; then
+ # not a redhat-ish RPM-based system
+ cleanup_symlinks
+elif [ "x$1" = "x0" ]; then
+ # RPM-based system and we're deinstalling rather than upgrading
+ cleanup_symlinks
+fi
diff --git a/omnibus/package-scripts/chef-fips/postinst b/omnibus/package-scripts/chef-fips/postinst
new file mode 100755
index 0000000000..8aa6f19ec1
--- /dev/null
+++ b/omnibus/package-scripts/chef-fips/postinst
@@ -0,0 +1,111 @@
+#!/bin/sh
+# WARNING: REQUIRES /bin/sh
+#
+# - must run on /bin/sh on solaris 9
+# - must run on /bin/sh on AIX 6.x
+# - if you think you are a bash wizard, you probably do not understand
+# this programming language. do not touch.
+# - if you are under 40, get peer review from your elders.
+#
+# Install a full Opscode Client
+#
+
+PROGNAME=`basename $0`
+INSTALLER_DIR=/opt/chef-fips
+CONFIG_DIR=/etc/chef
+USAGE="usage: $0 [-v validation_key] ([-o organization] || [-u url])"
+
+error_exit()
+{
+ echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2
+ exit 1
+}
+
+is_darwin()
+{
+ uname -v | grep "^Darwin" 2>&1 >/dev/null
+}
+
+is_smartos()
+{
+ uname -v | grep "^joyent" 2>&1 >/dev/null
+}
+
+if is_smartos; then
+ PREFIX="/opt/local"
+elif is_darwin; then
+ PREFIX="/usr/local"
+ mkdir -p "$PREFIX/bin"
+else
+ PREFIX="/usr"
+fi
+
+validation_key=
+organization=
+chef_url=
+
+while getopts o:u:v: opt
+do
+ case "$opt" in
+ v) validation_key="${OPTARG}";;
+ o) organization="${OPTARG}"; chef_url="https://api.opscode.com/organizations/${OPTARG}";;
+ u) chef_url="${OPTARG}";;
+ \?) # unknown flag
+ echo >&2 ${USAGE}
+ exit 1;;
+ esac
+done
+shift `expr ${OPTIND} - 1`
+
+if [ "" != "$chef_url" ]; then
+ mkdir -p ${CONFIG_DIR} || error_exit "Cannot create ${CONFIG_DIR}!"
+ (
+ cat <<'EOP'
+log_level :info
+log_location STDOUT
+EOP
+ ) > ${CONFIG_DIR}/client.rb
+ if [ "" != "$chef_url" ]; then
+ echo "chef_server_url '${chef_url}'" >> ${CONFIG_DIR}/client.rb
+ fi
+ if [ "" != "$organization" ]; then
+ echo "validation_client_name '${organization}-validator'" >> ${CONFIG_DIR}/client.rb
+ fi
+ chmod 644 ${CONFIG_DIR}/client.rb
+fi
+
+if [ "" != "$validation_key" ]; then
+ cp ${validation_key} ${CONFIG_DIR}/validation.pem || error_exit "Cannot copy the validation key!"
+ chmod 600 ${CONFIG_DIR}/validation.pem
+fi
+
+# rm -f before ln -sf is required for solaris 9
+rm -f $PREFIX/bin/chef-client
+rm -f $PREFIX/bin/chef-solo
+rm -f $PREFIX/bin/chef-apply
+rm -f $PREFIX/bin/chef-shell
+rm -f $PREFIX/bin/knife
+rm -f $PREFIX/bin/ohai
+
+ln -sf $INSTALLER_DIR/bin/chef-solo $PREFIX/bin || error_exit "Cannot link chef-solo to $PREFIX/bin"
+if [ -f "$INSTALLER_DIR/bin/chef-apply" ]; then
+ ln -sf $INSTALLER_DIR/bin/chef-apply $PREFIX/bin || error_exit "Cannot link chef-apply to $PREFIX/bin"
+fi
+if [ -f "$INSTALLER_DIR/bin/chef-shell" ]; then
+ ln -sf $INSTALLER_DIR/bin/chef-shell $PREFIX/bin || error_exit "Cannot link chef-shell to $PREFIX/bin"
+fi
+ln -sf $INSTALLER_DIR/bin/knife $PREFIX/bin || error_exit "Cannot link knife to $PREFIX/bin"
+ln -sf $INSTALLER_DIR/bin/ohai $PREFIX/bin || error_exit "Cannot link ohai to $PREFIX/bin"
+
+# We test for the presence of /usr/bin/chef-client to know if this script succeeds, so this
+# must appear as the last real action in the script
+ln -sf $INSTALLER_DIR/bin/chef-client $PREFIX/bin || error_exit "Cannot link chef-client to $PREFIX/bin"
+
+# Ensure all files/directories in $INSTALLER_DIR are owned by root. This
+# has been fixed on new installs but upgrades from old installs need to
+# be manually fixed.
+chown -Rh 0:0 $INSTALLER_DIR
+
+echo "Thank you for installing Chef!"
+
+exit 0
diff --git a/omnibus/package-scripts/chef-fips/postrm b/omnibus/package-scripts/chef-fips/postrm
new file mode 100755
index 0000000000..247688074e
--- /dev/null
+++ b/omnibus/package-scripts/chef-fips/postrm
@@ -0,0 +1,42 @@
+#!/bin/sh
+# WARNING: REQUIRES /bin/sh
+#
+# - must run on /bin/sh on solaris 9
+# - must run on /bin/sh on AIX 6.x
+# - if you think you are a bash wizard, you probably do not understand
+# this programming language. do not touch.
+# - if you are under 40, get peer review from your elders.
+
+is_smartos() {
+ uname -v | grep "^joyent" 2>&1 >/dev/null
+}
+
+is_darwin()
+{
+ uname -v | grep "^Darwin" 2>&1 >/dev/null
+}
+
+if is_smartos; then
+ PREFIX="/opt/local"
+elif is_darwin; then
+ PREFIX="/usr/local"
+else
+ PREFIX="/usr"
+fi
+
+cleanup_symlinks() {
+ binaries="chef-client chef-solo chef-apply chef-shell knife ohai"
+ for binary in $binaries; do
+ rm -f $PREFIX/bin/$binary
+ done
+}
+
+# Clean up binary symlinks if they exist
+# see: http://tickets.opscode.com/browse/CHEF-3022
+if [ ! -f /etc/redhat-release -a ! -f /etc/fedora-release -a ! -f /etc/system-release -a ! -f /etc/SuSE-release ]; then
+ # not a redhat-ish RPM-based system
+ cleanup_symlinks
+elif [ "x$1" = "x0" ]; then
+ # RPM-based system and we're deinstalling rather than upgrading
+ cleanup_symlinks
+fi
diff --git a/omnibus/package-scripts/chef/postinst b/omnibus/package-scripts/chef/postinst
new file mode 100755
index 0000000000..45893241b3
--- /dev/null
+++ b/omnibus/package-scripts/chef/postinst
@@ -0,0 +1,111 @@
+#!/bin/sh
+# WARNING: REQUIRES /bin/sh
+#
+# - must run on /bin/sh on solaris 9
+# - must run on /bin/sh on AIX 6.x
+# - if you think you are a bash wizard, you probably do not understand
+# this programming language. do not touch.
+# - if you are under 40, get peer review from your elders.
+#
+# Install a full Opscode Client
+#
+
+PROGNAME=`basename $0`
+INSTALLER_DIR=/opt/chef
+CONFIG_DIR=/etc/chef
+USAGE="usage: $0 [-v validation_key] ([-o organization] || [-u url])"
+
+error_exit()
+{
+ echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2
+ exit 1
+}
+
+is_darwin()
+{
+ uname -v | grep "^Darwin" 2>&1 >/dev/null
+}
+
+is_smartos()
+{
+ uname -v | grep "^joyent" 2>&1 >/dev/null
+}
+
+if is_smartos; then
+ PREFIX="/opt/local"
+elif is_darwin; then
+ PREFIX="/usr/local"
+ mkdir -p "$PREFIX/bin"
+else
+ PREFIX="/usr"
+fi
+
+validation_key=
+organization=
+chef_url=
+
+while getopts o:u:v: opt
+do
+ case "$opt" in
+ v) validation_key="${OPTARG}";;
+ o) organization="${OPTARG}"; chef_url="https://api.opscode.com/organizations/${OPTARG}";;
+ u) chef_url="${OPTARG}";;
+ \?) # unknown flag
+ echo >&2 ${USAGE}
+ exit 1;;
+ esac
+done
+shift `expr ${OPTIND} - 1`
+
+if [ "" != "$chef_url" ]; then
+ mkdir -p ${CONFIG_DIR} || error_exit "Cannot create ${CONFIG_DIR}!"
+ (
+ cat <<'EOP'
+log_level :info
+log_location STDOUT
+EOP
+ ) > ${CONFIG_DIR}/client.rb
+ if [ "" != "$chef_url" ]; then
+ echo "chef_server_url '${chef_url}'" >> ${CONFIG_DIR}/client.rb
+ fi
+ if [ "" != "$organization" ]; then
+ echo "validation_client_name '${organization}-validator'" >> ${CONFIG_DIR}/client.rb
+ fi
+ chmod 644 ${CONFIG_DIR}/client.rb
+fi
+
+if [ "" != "$validation_key" ]; then
+ cp ${validation_key} ${CONFIG_DIR}/validation.pem || error_exit "Cannot copy the validation key!"
+ chmod 600 ${CONFIG_DIR}/validation.pem
+fi
+
+# rm -f before ln -sf is required for solaris 9
+rm -f $PREFIX/bin/chef-client
+rm -f $PREFIX/bin/chef-solo
+rm -f $PREFIX/bin/chef-apply
+rm -f $PREFIX/bin/chef-shell
+rm -f $PREFIX/bin/knife
+rm -f $PREFIX/bin/ohai
+
+ln -sf $INSTALLER_DIR/bin/chef-solo $PREFIX/bin || error_exit "Cannot link chef-solo to $PREFIX/bin"
+if [ -f "$INSTALLER_DIR/bin/chef-apply" ]; then
+ ln -sf $INSTALLER_DIR/bin/chef-apply $PREFIX/bin || error_exit "Cannot link chef-apply to $PREFIX/bin"
+fi
+if [ -f "$INSTALLER_DIR/bin/chef-shell" ]; then
+ ln -sf $INSTALLER_DIR/bin/chef-shell $PREFIX/bin || error_exit "Cannot link chef-shell to $PREFIX/bin"
+fi
+ln -sf $INSTALLER_DIR/bin/knife $PREFIX/bin || error_exit "Cannot link knife to $PREFIX/bin"
+ln -sf $INSTALLER_DIR/bin/ohai $PREFIX/bin || error_exit "Cannot link ohai to $PREFIX/bin"
+
+# We test for the presence of /usr/bin/chef-client to know if this script succeeds, so this
+# must appear as the last real action in the script
+ln -sf $INSTALLER_DIR/bin/chef-client $PREFIX/bin || error_exit "Cannot link chef-client to $PREFIX/bin"
+
+# Ensure all files/directories in $INSTALLER_DIR are owned by root. This
+# has been fixed on new installs but upgrades from old installs need to
+# be manually fixed.
+chown -Rh 0:0 $INSTALLER_DIR
+
+echo "Thank you for installing Chef!"
+
+exit 0
diff --git a/omnibus/package-scripts/chef/postrm b/omnibus/package-scripts/chef/postrm
new file mode 100755
index 0000000000..247688074e
--- /dev/null
+++ b/omnibus/package-scripts/chef/postrm
@@ -0,0 +1,42 @@
+#!/bin/sh
+# WARNING: REQUIRES /bin/sh
+#
+# - must run on /bin/sh on solaris 9
+# - must run on /bin/sh on AIX 6.x
+# - if you think you are a bash wizard, you probably do not understand
+# this programming language. do not touch.
+# - if you are under 40, get peer review from your elders.
+
+is_smartos() {
+ uname -v | grep "^joyent" 2>&1 >/dev/null
+}
+
+is_darwin()
+{
+ uname -v | grep "^Darwin" 2>&1 >/dev/null
+}
+
+if is_smartos; then
+ PREFIX="/opt/local"
+elif is_darwin; then
+ PREFIX="/usr/local"
+else
+ PREFIX="/usr"
+fi
+
+cleanup_symlinks() {
+ binaries="chef-client chef-solo chef-apply chef-shell knife ohai"
+ for binary in $binaries; do
+ rm -f $PREFIX/bin/$binary
+ done
+}
+
+# Clean up binary symlinks if they exist
+# see: http://tickets.opscode.com/browse/CHEF-3022
+if [ ! -f /etc/redhat-release -a ! -f /etc/fedora-release -a ! -f /etc/system-release -a ! -f /etc/SuSE-release ]; then
+ # not a redhat-ish RPM-based system
+ cleanup_symlinks
+elif [ "x$1" = "x0" ]; then
+ # RPM-based system and we're deinstalling rather than upgrading
+ cleanup_symlinks
+fi
diff --git a/omnibus/resources/chef/dmg/background.png b/omnibus/resources/chef/dmg/background.png
new file mode 100644
index 0000000000..82c605ae51
--- /dev/null
+++ b/omnibus/resources/chef/dmg/background.png
Binary files differ
diff --git a/omnibus/resources/chef/dmg/icon.png b/omnibus/resources/chef/dmg/icon.png
new file mode 100644
index 0000000000..2195d7c82a
--- /dev/null
+++ b/omnibus/resources/chef/dmg/icon.png
Binary files differ
diff --git a/omnibus/resources/chef/ips/symlinks.erb b/omnibus/resources/chef/ips/symlinks.erb
new file mode 100644
index 0000000000..419d52ddf7
--- /dev/null
+++ b/omnibus/resources/chef/ips/symlinks.erb
@@ -0,0 +1,6 @@
+link path=usr/bin/chef-solo target=<%= projectdir %>/bin/chef-solo
+link path=usr/bin/chef-client target=<%= projectdir %>/bin/chef-client
+link path=usr/bin/chef-apply target=<%= projectdir %>/bin/chef-apply
+link path=usr/bin/chef-shell target=<%= projectdir %>/bin/chef-shell
+link path=usr/bin/knife target=<%= projectdir %>/bin/knife
+link path=usr/bin/ohai target=<%= projectdir %>/bin/ohai
diff --git a/omnibus/resources/chef/msi/assets/LICENSE.rtf b/omnibus/resources/chef/msi/assets/LICENSE.rtf
new file mode 100644
index 0000000000..b18e6f59b8
--- /dev/null
+++ b/omnibus/resources/chef/msi/assets/LICENSE.rtf
@@ -0,0 +1,197 @@
+{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Courier New;}}
+
+{\*\generator Msftedit 5.41.21.2500;}\viewkind4\uc1\pard\qc\lang1033\f0\fs20 Apache License\par
+
+Version 2.0, January 2004\par
+
+http://www.apache.org/licenses/\par
+
+\pard\par
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\par
+
+\par
+
+1. Definitions.\par
+
+\par
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.\par
+
+\par
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.\par
+
+\par
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.\par
+
+\par
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.\par
+
+\par
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation, source, and configuration files.\par
+
+\par
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.\par
+
+\par
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).\par
+
+\par
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.\par
+
+\par
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."\par
+
+\par
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.\par
+
+\par
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.\par
+
+\par
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license plies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.\par
+
+\par
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:\par
+
+\par
+
+ (a) You must give any other recipients of the Work or\par
+
+ Derivative Works a copy of this License; and\par
+
+\par
+
+ (b) You must cause any modified files to carry prominent notices\par
+
+ stating that You changed the files; and\par
+
+\par
+
+ (c) You must retain, in the Source form of any Derivative Works\par
+
+ that You distribute, all copyright, patent, trademark, and\par
+
+ attribution notices from the Source form of the Work,\par
+
+ excluding those notices that do not pertain to any part of\par
+
+ the Derivative Works; and\par
+
+\par
+
+ (d) If the Work includes a "NOTICE" text file as part of its\par
+
+ distribution, then any Derivative Works that You distribute\par
+
+ must include a readable copy of the attribution notices\par
+
+ contained within such NOTICE file, excluding those notices\par
+
+ that do not pertain to any part of the Derivative Works, in\par
+
+ at least one of the following places: within a NOTICE text\par
+
+ file distributed as part of the Derivative Works; within the\par
+
+ Source form or documentation, if provided along with the\par
+
+ Derivative Works; or, within a display generated by the\par
+
+ Derivative Works, if and wherever such third-party notices\par
+
+ normally appear. The contents of the NOTICE file are for\par
+
+ informational purposes only and do not modify the License.\par
+
+ You may add Your own attribution notices within Derivative\par
+
+ Works that You distribute, alongside or as an addendum to the\par
+
+ NOTICE text from the Work, provided that such additional\par
+
+ attribution notices cannot be construed as modifying the\par
+
+ License.\par
+
+\par
+
+You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.\par
+
+\par
+
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.\par
+
+\par
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.\par
+
+\par
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.\par
+
+\par
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.\par
+
+\par
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.\par
+
+\par
+
+END OF TERMS AND CONDITIONS\par
+
+\par
+
+APPENDIX: How to apply the Apache License to your work.\par
+
+\par
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.\par
+
+\par
+
+ Copyright [yyyy] [name of copyright owner]\par
+
+\par
+
+ Licensed under the Apache License, Version 2.0 (the "License");\par
+
+ you may not use this file except in compliance with the License.\par
+
+ You may obtain a copy of the License at\par
+
+\par
+
+ http://www.apache.org/licenses/LICENSE-2.0\par
+
+\par
+
+ Unless required by applicable law or agreed to in writing, software\par
+
+ distributed under the License is distributed on an "AS IS" BASIS,\par
+
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\par
+
+ implied. See the License for the specific language governing\par
+
+ permissions and limitations under the License.\par
+
+\par
+
+}
+
+
diff --git a/omnibus/resources/chef/msi/assets/banner_background.bmp b/omnibus/resources/chef/msi/assets/banner_background.bmp
new file mode 100644
index 0000000000..5769a883c3
--- /dev/null
+++ b/omnibus/resources/chef/msi/assets/banner_background.bmp
Binary files differ
diff --git a/omnibus/resources/chef/msi/assets/dialog_background.bmp b/omnibus/resources/chef/msi/assets/dialog_background.bmp
new file mode 100644
index 0000000000..4dbe489e9c
--- /dev/null
+++ b/omnibus/resources/chef/msi/assets/dialog_background.bmp
Binary files differ
diff --git a/omnibus/resources/chef/msi/assets/oc.ico b/omnibus/resources/chef/msi/assets/oc.ico
new file mode 100644
index 0000000000..c4cee7bd75
--- /dev/null
+++ b/omnibus/resources/chef/msi/assets/oc.ico
Binary files differ
diff --git a/omnibus/resources/chef/msi/assets/oc_16x16.ico b/omnibus/resources/chef/msi/assets/oc_16x16.ico
new file mode 100644
index 0000000000..d3bd065a6a
--- /dev/null
+++ b/omnibus/resources/chef/msi/assets/oc_16x16.ico
Binary files differ
diff --git a/omnibus/resources/chef/msi/assets/oc_32x32.ico b/omnibus/resources/chef/msi/assets/oc_32x32.ico
new file mode 100644
index 0000000000..5eee0042c3
--- /dev/null
+++ b/omnibus/resources/chef/msi/assets/oc_32x32.ico
Binary files differ
diff --git a/omnibus/resources/chef/msi/localization-en-us.wxl.erb b/omnibus/resources/chef/msi/localization-en-us.wxl.erb
new file mode 100644
index 0000000000..c5e8e5ddab
--- /dev/null
+++ b/omnibus/resources/chef/msi/localization-en-us.wxl.erb
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
+ <!-- http://wix.codeplex.com/SourceControl/changeset/view/792e101c5cf7#src%2fext%2fUIExtension%2fwixlib%2fWixUI_en-us.wxl -->
+ <String Id="LANG">1033</String>
+ <String Id="ProductName"><%= friendly_name %></String>
+ <String Id="ManufacturerName">Chef Software, Inc.</String>
+ <String Id="WelcomeDlgTitle">{\WixUI_Font_Bigger}Welcome to the [ProductName] Setup Wizard</String>
+
+ <String Id="LicenseAgreementDlgTitle">{\WixUI_Font_Title_White}End-User License Agreement</String>
+ <String Id="LicenseAgreementDlgDescription">{\WixUI_Font_Normal_White}Please read the following license agreement carefully</String>
+
+ <String Id="InstallDirDlgTitle">{\WixUI_Font_Title_White}Destination Folder</String>
+ <String Id="InstallDirDlgDescription">{\WixUI_Font_Normal_White}Click Next to install to the default folder or click Change to choose another.</String>
+
+ <String Id="ProgressDlgTitleInstalling">{\WixUI_Font_Title_White}Installing [ProductName]</String>
+
+ <String Id="VerifyReadyDlgInstallTitle">{\WixUI_Font_Title_White}Ready to install [ProductName]</String>
+
+ <!-- Scheduled Task -->
+ <String Id="SchTaskDisplayName"><%= friendly_name %> Scheduled Task</String>
+ <String Id="SchTaskDescription">Schedule <%= friendly_name %> to run at a pre-defined time intervals.</String>
+ <!-- Service -->
+ <!-- Keep these in sync with the name and description in chef-service-manager -->
+ <String Id="ServiceDisplayName"><%= friendly_name %> Service</String>
+ <String Id="ServiceDescription">Runs <%= friendly_name %> on regular, configurable intervals.</String>
+ <String Id="FeatureMainName"><%= friendly_name %></String>
+ <String Id="FeatureSchTaskName"><%= friendly_name %> Scheduled Task</String>
+ <String Id="FeatureServiceName"><%= friendly_name %> Service</String>
+ <String Id="FeaturePSModuleName"><%= friendly_name %> PowerShell wrappers</String>
+
+ <String Id="MinimumOSVersionMessage">This package requires minimum OS version: Windows 7/Windows Server 2008 R2 or greater.</String>
+ <String Id="DowngradeErrorMessage">A newer version of [ProductName] is already installed.</String>
+ <String Id="FileExtractionProgress">Extracting files, please wait...</String>
+
+ <String Id="CustomizeDlgTextMsg">Select an option to change between the Chef's unattended execution options.</String>
+ <String Id="CustomizeDlgTextTitle">Chef Unattended Execution Options</String>
+ <String Id="CustomizeDlgFirstRadioButtonText">Chef Client Scheduled Task</String>
+ <String Id="CustomizeDlgSecondRadioButtonText">Chef Client Service</String>
+ <String Id="CustomizeDlgThirdRadioButtonText">None</String>
+
+ <String Id="CustomizeDlgOptionsMsg">The installer can configure the Chef Client to run periodically as either a scheduled task or a service. Using a scheduled task is recommended. For more information, see https://docs.chef.io/windows.html.</String>
+</WixLocalization>
diff --git a/omnibus/resources/chef/msi/parameters.wxi.erb b/omnibus/resources/chef/msi/parameters.wxi.erb
new file mode 100644
index 0000000000..febd1738e2
--- /dev/null
+++ b/omnibus/resources/chef/msi/parameters.wxi.erb
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Include>
+ <?define VersionNumber="<%= version %>" ?>
+ <?define DisplayVersionNumber="<%= display_version %>" ?>
+ <?define UpgradeCode="<%= upgrade_code %>" ?>
+<% parameters.each do |key, value| -%>
+ <?define <%= key %>="<%= value %>" ?>
+<% end -%>
+</Include>
diff --git a/omnibus/resources/chef/msi/source.wxs.erb b/omnibus/resources/chef/msi/source.wxs.erb
new file mode 100644
index 0000000000..c49a8324f9
--- /dev/null
+++ b/omnibus/resources/chef/msi/source.wxs.erb
@@ -0,0 +1,333 @@
+<?xml version='1.0'?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
+
+ <!-- This is how we include wxi files -->
+ <?include "parameters.wxi" ?>
+
+ <!--
+ Id="*" is to enable upgrading. * means that the product ID will be autogenerated on each build.
+ Name is made of localized product name and version number.
+ -->
+ <Product Id="*" Name="!(loc.ProductName) v$(var.DisplayVersionNumber)" Language="!(loc.LANG)"
+ Version="$(var.VersionNumber)" Manufacturer="!(loc.ManufacturerName)" UpgradeCode="$(var.UpgradeCode)">
+
+ <!--
+ Define the minimum supported installer version (2.0).
+ The install should be done for the whole machine not just the current user
+ -->
+ <Package InstallerVersion="200" InstallPrivileges="elevated"
+ Compressed="yes" InstallScope="perMachine" />
+
+ <!--
+ Create property references for the well known SIDs of the
+ accounts we want to restrict for the project location folder
+ -->
+ <PropertyRef Id="WIX_ACCOUNT_LOCALSYSTEM" />
+ <PropertyRef Id="WIX_ACCOUNT_ADMINISTRATORS" />
+ <PropertyRef Id="WIX_ACCOUNT_USERS" />
+
+ <Media Id="1" Cabinet="ChefClient.cab" EmbedCab="yes" CompressionLevel="high" />
+
+ <Property Id="CHEF_SERVICE_OPTIONS_RADIO_BUTTON_GROUP" Value="None" />
+
+ <!--
+ Uncomment launch condition below to check for minimum OS
+ 601 = Windows 7/Server 2008R2.
+ -->
+ <!-- Condition Message="!(loc.MinimumOSVersionMessage)">
+ <![CDATA[Installed OR VersionNT >= 601]]>
+ </Condition -->
+
+ <!-- We always do Major upgrades -->
+ <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeErrorMessage)" />
+
+
+ <!--
+ If fastmsi is set, custom actions will be invoked during install to unzip
+ project files, and during uninstall to remove the project folder
+ -->
+ <% if fastmsi %>
+ <SetProperty Id="FastUnzip"
+ Value="FASTZIPDIR=[INSTALLLOCATION];FASTZIPAPPNAME=$(var.ProjectLocationDir)"
+ Sequence="execute"
+ Before="FastUnzip" />
+
+ <CustomAction Id="FastUnzip"
+ BinaryKey="CustomActionFastMsiDLL"
+ DllEntry="FastUnzip"
+ Execute="deferred"
+ Impersonate="no"
+ Return="check" />
+
+ <Binary Id="CustomActionFastMsiDLL"
+ SourceFile="CustomActionFastMsi.CA.dll" />
+
+ <CustomAction Id="Cleanup"
+ Directory="INSTALLLOCATION"
+ ExeCommand="cmd /C &quot;rd /S /Q $(var.ProjectLocationDir)&quot;"
+ Execute="deferred"
+ Impersonate="no"
+ Return="ignore" />
+
+ <CustomAction Id="CreateChefClientScheduledTask"
+ Directory="TARGETDIR"
+ ExeCommand="&quot;[SystemFolder]SCHTASKS.EXE&quot; /CREATE /TN &quot;chef-client&quot; /SC &quot;MINUTE&quot; /MO &quot;30&quot; /F /TR &quot;cmd /c \&quot;[EMBEDDEDBIN]ruby.exe [PROJECTLOCATIONBIN]chef-client -L [CONFIGLOCATION]chef-client.log -c [CONFIGLOCATION]client.rb\&quot;&quot; /RU &quot;NT Authority\System&quot; /RP /RL &quot;HIGHEST&quot;"
+ Execute="deferred"
+ Impersonate="no"
+ Return="check" />
+
+ <CustomAction Id="RemoveChefClientScheduledTask"
+ Directory="TARGETDIR"
+ ExeCommand="&quot;[SystemFolder]SCHTASKS.EXE&quot; /DELETE /TN &quot;chef-client&quot; /F"
+ Execute="deferred"
+ Impersonate="no"
+ Return="ignore" />
+
+ <CustomAction Id="RemoveChefClientService"
+ Directory="TARGETDIR"
+ ExeCommand="&quot;[SystemFolder]SC.EXE&quot; DELETE &quot;chef-client&quot;"
+ Execute="deferred"
+ Impersonate="no"
+ Return="ignore" />
+
+ <InstallExecuteSequence>
+ <Custom Action="FastUnzip" After="InstallFiles">NOT Installed</Custom>
+ <Custom Action="Cleanup" After="RemoveFiles">REMOVE~="ALL"</Custom>
+
+ <Custom Action="CreateChefClientScheduledTask" After="InstallFiles">
+ <![CDATA[&ChefSchTaskFeature=3]]>
+ </Custom>
+
+ <Custom Action="RemoveChefClientScheduledTask" Before="RemoveFiles">
+ <![CDATA[(Installed AND (&NoneFeature=3 OR &ChefServiceFeature=3)) OR (REMOVE="ALL")]]>
+ </Custom>
+
+ <Custom Action="RemoveChefClientService" Before="RemoveFiles">
+ <![CDATA[Installed AND (&NoneFeature=3 OR &ChefSchTaskFeature=3) OR (REMOVE="ALL")]]>
+ </Custom>
+ </InstallExecuteSequence>
+
+ <UI>
+ <ProgressText Action="FastUnzip">!(loc.FileExtractionProgress)</ProgressText>
+ </UI>
+ <% end %>
+
+ <Directory Id="TARGETDIR" Name="SourceDir">
+ <Directory Id="WindowsVolume">
+ <!-- Service needs chef directory to be present. -->
+ <Directory Id="CONFIGLOCATION" Name="chef">
+ <Component Id="CONFIGLOCATIONDIR" Guid="{F66F6394-51A4-4C5D-908B-E55584473436}" >
+ <CreateFolder Directory="CONFIGLOCATION" />
+ </Component>
+ </Directory>
+ <Directory Id="INSTALLLOCATION" Name="opscode">
+ <Directory Id="PROJECTLOCATION" Name="$(var.ProjectLocationDir)" >
+ <Component Id="ProjectLocationPermissions" Guid="{75f50556-efae-4ede-beb2-a2c9b1a4d43f}" >
+ <!--
+ Windows client SKUs give the Authenticated Users group modify rights
+ to new folders created. We ONLY want the local system account and any administrator to have that right to protect non admin users from injecting code that could be executed by a service running as SYSTEM
+ -->
+ <CreateFolder>
+ <Permission User="[WIX_ACCOUNT_LOCALSYSTEM]" GenericAll="yes"/>
+ <Permission User="[WIX_ACCOUNT_ADMINISTRATORS]" GenericAll="yes"/>
+ <Permission User="[WIX_ACCOUNT_USERS]" GenericRead="yes" GenericExecute="yes"/>
+ </CreateFolder>
+ </Component>
+ <Directory Id="PROJECTLOCATIONBIN" Name="bin" >
+ <Component Id="ChefClientPath" Guid="{7F663F88-55A2-4E20-82BF-8BD2E60BB83A}" >
+ <Environment Id="ClientPathEnvironment"
+ Name="PATH" Action="set" Part="last" System="yes" Value="[PROJECTLOCATIONBIN]" />
+ </Component>
+ </Directory>
+ <Directory Id="PSMODULES" Name="modules" >
+ <Component Id="ChefPSModulePath" Guid="{357DA654-F02E-430A-9EA6-A10554E3EF38}" >
+ <Environment Id="ChefPSModulePathEnvironment"
+ Name="PSModulePath" Action="set" Part="last" System="yes" Value="[PSMODULES]" />
+ </Component>
+ </Directory>
+ <Directory Id="EMBEDDED" Name="embedded" >
+ <Directory Id="EMBEDDEDBIN" Name="bin" >
+ <Component Id="ChefClientService" Guid="{69B2D8BE-4A47-4BE3-AEE8-83FAEB6E2FAF}" >
+ <File Id="RubyExecutable" Source="$(var.ProjectSourceDir)\embedded\bin\ruby.exe" KeyPath="yes" />
+ <ServiceInstall Name="chef-client" Type="ownProcess"
+ Start="auto" Vital="yes" ErrorControl="ignore"
+ Arguments="[PROJECTLOCATION]bin\chef-windows-service"
+ DisplayName="!(loc.ServiceDisplayName)"
+ Description="!(loc.ServiceDescription)">
+ <ServiceDependency Id="Winmgmt" />
+ <ServiceConfig DelayedAutoStart="yes" OnInstall="yes" />
+ </ServiceInstall>
+ <ServiceControl Id="ControlChefClientService" Name="chef-client"
+ Remove="both" Stop="both" Wait="yes" />
+ </Component>
+ <Component Id="ChefClientLog" Guid="{8e492d59-3a0c-43fd-b889-e35dfa33da91}">
+ <util:EventSource xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
+ Name="Chef" Log="Application"
+ EventMessageFile="[PROJECTLOCATION]$(var.ChefLogDllPath)"
+ />
+ </Component>
+ </Directory>
+ </Directory>
+ </Directory>
+ </Directory>
+ <Directory Id="ChefSchTaskFeatureTempDir">
+ <Component Id="ChefSchTask" Guid="{7f9f917a-952c-41d8-baa1-037269eecb50}">
+ <CreateFolder />
+ </Component>
+ </Directory>
+ <Directory Id="NoneFeatureTempDir">
+ <Component Id="None" Guid="{d8f3eba5-cecb-436c-a4ef-540dba3c5ccf}">
+ <CreateFolder />
+ </Component>
+ </Directory>
+ </Directory>
+ </Directory>
+
+ <!-- Set the components defined in our fragment files that will be used for our feature -->
+ <Feature Id="ChefClientFeature" Title="!(loc.FeatureMainName)" Absent="disallow" AllowAdvertise="no" Level="1" ConfigurableDirectory="INSTALLLOCATION">
+ <ComponentGroupRef Id="ProjectDir" />
+ <ComponentRef Id="ProjectLocationPermissions" />
+ <ComponentRef Id="ChefClientPath" />
+ <ComponentRef Id="CONFIGLOCATIONDIR" />
+ <ComponentRef Id="ChefClientLog" />
+ </Feature>
+
+ <Feature Id="ChefPSModuleFeature" Title="!(loc.FeaturePSModuleName)" Level="1000" AllowAdvertise="no">
+ <ComponentRef Id="ChefPSModulePath" />
+ </Feature>
+
+ <Feature Id="ChefUnattendedExecutionOptions" Title="Chef Unattended Execution Options" Level="1000" AllowAdvertise="no">
+ <Feature Id="ChefSchTaskFeature" Title="!(loc.FeatureSchTaskName)" Level="1000" AllowAdvertise="no" Display="hidden">
+ <!-- Here, CustomAction will get executed and scheduled task for chef-client will get created -->
+
+ <!-- This is an empty component to keep track of the feature -->
+ <ComponentRef Id="ChefSchTask" />
+ </Feature>
+
+ <Feature Id="ChefServiceFeature" Title="!(loc.FeatureServiceName)" Level="1000" AllowAdvertise="no" Display="hidden">
+ <ComponentRef Id="ChefClientService" />
+ </Feature>
+
+ <Feature Id="NoneFeature" Title="None" Level="1000" AllowAdvertise="no" Display="hidden">
+ <!-- Do Nothing -->
+
+ <!-- This is an empty component to keep track of the feature -->
+ <ComponentRef Id="None" />
+ </Feature>
+ </Feature>
+
+ <!--
+ TODO:
+
+ * create initial Client config? ie C:\chef\client.rb?
+ * optionally install extra tools? ie git?
+
+ -->
+
+ <!--
+ UI Stuff
+ -->
+ <Icon Id="oc.ico" SourceFile="Resources\assets\oc_16x16.ico"/>
+ <Property Id="ARPPRODUCTICON" Value="oc.ico" />
+ <Property Id="ARPHELPLINK" Value="http://www.getchef.com/support/" />
+ <Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION" />
+
+ <UIRef Id="ChefClientUI_InstallDir"/>
+ <UI Id="ChefClientUI_InstallDir">
+ <!-- WixUI_FeatureTree module's code embedded and modified here as per the requirement -->
+ <TextStyle Id="WixUI_Font_Normal_White" FaceName="Tahoma" Size="8" Red="255" Green="255" Blue="255" />
+ <TextStyle Id="WixUI_Font_Bigger_White" FaceName="Tahoma" Size="12" Red="255" Green="255" Blue="255" />
+ <TextStyle Id="WixUI_Font_Title_White" FaceName="Tahoma" Size="9" Bold="yes" Red="255" Green="255" Blue="255" />
+ <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
+ <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
+ <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
+ <TextStyle Id="WixUI_Font_Msg" FaceName="Tahoma" Size="9" />
+
+ <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
+ <Property Id="WixUI_Mode" Value="FeatureTree" />
+
+ <DialogRef Id="ErrorDlg" />
+ <DialogRef Id="FatalError" />
+ <DialogRef Id="FilesInUse" />
+ <DialogRef Id="MsiRMFilesInUse" />
+ <DialogRef Id="PrepareDlg" />
+ <DialogRef Id="ProgressDlg" />
+ <DialogRef Id="ResumeDlg" />
+ <DialogRef Id="UserExit" />
+
+ <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
+
+ <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="LicenseAgreementDlg">NOT Installed</Publish>
+ <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>
+
+ <Publish Dialog="LicenseAgreementDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish>
+ <Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="CustomizeDlg">LicenseAccepted = "1"</Publish>
+
+ <Publish Dialog="CustomizeDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="1">Installed</Publish>
+ <Publish Dialog="CustomizeDlg" Control="Back" Event="NewDialog" Value="LicenseAgreementDlg" Order="2">NOT Installed</Publish>
+
+ <Publish Dialog="CustomizeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg"><![CDATA[((NOT &ChefUnattendedExecutionOptions=3) AND NOT ((?ChefSchTask=3) OR (?ChefClientService=3) OR (?None=3)))]]></Publish>
+
+ <Publish Dialog="CustomizeDlg" Control="Next" Event="NewDialog" Value="ChefUnattendedExecutionOptionsSelectionDlg"><![CDATA[((&ChefUnattendedExecutionOptions=3) OR (?ChefSchTask=3 OR ?ChefClientService=3 OR ?None=3))]]></Publish>
+
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="CustomizeDlg" Order="1"><![CDATA[NOT &ChefUnattendedExecutionOptions=3]]> AND (NOT Installed OR WixUI_InstallMode = "Change")</Publish>
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="ChefUnattendedExecutionOptionsSelectionDlg" Order="1"><![CDATA[&ChefUnattendedExecutionOptions=3]]> AND (NOT Installed OR WixUI_InstallMode = "Change")</Publish>
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish>
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="3">Installed AND PATCH</Publish>
+
+ <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
+
+ <Publish Dialog="MaintenanceTypeDlg" Control="ChangeButton" Event="NewDialog" Value="CustomizeDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>
+
+ <Dialog Id ="ChefUnattendedExecutionOptionsSelectionDlg" Width ="370" Height ="270" Title ="!(loc.ProductName) v$(var.DisplayVersionNumber) Setup" NoMinimize ="no">
+ <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="!(loc.CustomizeDlgBannerBitmap)" />
+ <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
+ <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
+ <Control Id="Title" Type="Text" X="15" Y="6" Width="210" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.CustomizeDlgTitle)" />
+ <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.CustomizeDlgDescription)" />
+ <Control Id="TextMsg" Type="Text" X="25" Y="55" Width="320" Height="20" Text="!(loc.CustomizeDlgTextMsg)" />
+
+ <Control Id="LeftBox" Type="GroupBox" X="25" Y="81" Width="175" Height="118" />
+ <Control Id="TextTitle" Type="Text" X="30" Y="100" Width="169" Height="20" Text="{\WixUI_Font_Title}!(loc.CustomizeDlgTextTitle)" />
+ <Control Id="OptionsRadioGroup" Type="RadioButtonGroup" Property="CHEF_SERVICE_OPTIONS_RADIO_BUTTON_GROUP" Height="80" Width="140" X="35" Y="110">
+ <RadioButtonGroup Property="CHEF_SERVICE_OPTIONS_RADIO_BUTTON_GROUP">
+ <RadioButton Value="SchTask" Text="!(loc.CustomizeDlgFirstRadioButtonText)" Height="17" Width="140" X="0" Y="10" />
+ <RadioButton Value="Service" Text="!(loc.CustomizeDlgSecondRadioButtonText)" Height="17" Width="140" X="0" Y="35" />
+ <RadioButton Value="None" Text="!(loc.CustomizeDlgThirdRadioButtonText)" Height="17" Width="140" X="0" Y="60" />
+ </RadioButtonGroup>
+ </Control>
+
+ <Control Id="RightBox" Type="GroupBox" X="210" Y="81" Width="150" Height="118" />
+ <Control Id="OptionsMsg" Type="Text" X="214" Y="100" Width="146" Height="80" Text="{\WixUI_Font_Msg}!(loc.CustomizeDlgOptionsMsg)" />
+
+ <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Default="no" Text="Back">
+ <Publish Event="NewDialog" Value="CustomizeDlg">1</Publish>
+ </Control>
+ <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="Next">
+ <Publish Event="AddLocal" Value="ChefSchTaskFeature">CHEF_SERVICE_OPTIONS_RADIO_BUTTON_GROUP = "SchTask"</Publish>
+ <Publish Event="AddLocal" Value="ChefServiceFeature">CHEF_SERVICE_OPTIONS_RADIO_BUTTON_GROUP = "Service"</Publish>
+ <Publish Event="AddLocal" Value="NoneFeature">CHEF_SERVICE_OPTIONS_RADIO_BUTTON_GROUP = "None"</Publish>
+ <Publish Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ </Control>
+ <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="no" Text="Cancel" Cancel="yes">
+ <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
+ </Control>
+ </Dialog>
+ </UI>
+
+ <UIRef Id="WixUI_Common" />
+
+ <WixVariable Id="WixUILicenseRtf" Value="Resources\assets\LICENSE.rtf" />
+ <WixVariable Id="WixUIDialogBmp" Value="Resources\assets\dialog_background.bmp" />
+ <WixVariable Id="WixUIBannerBmp" Value="Resources\assets\banner_background.bmp" />
+
+ <WixVariable Id="WixUIExclamationIco" Value="Resources\assets\oc_32x32.ico" />
+ <WixVariable Id="WixUIInfoIco" Value="Resources\assets\oc_32x32.ico" />
+ <WixVariable Id="WixUINewIco" Value="Resources\assets\oc_16x16.ico" />
+ <WixVariable Id="WixUIUpIco" Value="Resources\assets\oc_16x16.ico" />
+
+ </Product>
+</Wix>
diff --git a/omnibus/resources/chef/pkg/background.png b/omnibus/resources/chef/pkg/background.png
new file mode 100644
index 0000000000..027453ab8c
--- /dev/null
+++ b/omnibus/resources/chef/pkg/background.png
Binary files differ
diff --git a/omnibus/resources/chef/pkg/license.html.erb b/omnibus/resources/chef/pkg/license.html.erb
new file mode 100644
index 0000000000..21b7991abf
--- /dev/null
+++ b/omnibus/resources/chef/pkg/license.html.erb
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright <%= Time.new.year %> Chef Software Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/omnibus/resources/chef/pkg/welcome.html.erb b/omnibus/resources/chef/pkg/welcome.html.erb
new file mode 100644
index 0000000000..04a02fb225
--- /dev/null
+++ b/omnibus/resources/chef/pkg/welcome.html.erb
@@ -0,0 +1,5 @@
+
+ This installer will help you install <%= friendly_name %> version <%= build_version %>.
+
+
+ You will be guided through the steps necessary to install this software.
diff --git a/omnibus_overrides.rb b/omnibus_overrides.rb
new file mode 100644
index 0000000000..69a5a7af05
--- /dev/null
+++ b/omnibus_overrides.rb
@@ -0,0 +1,19 @@
+# DO NOT EDIT. Generated by "rake dependencies". Edit version_policy.rb instead.
+override :rubygems, version: "2.6.10"
+override :bundler, version: "1.12.5"
+override "libffi", version: "3.2.1"
+override "libiconv", version: "1.14"
+override "liblzma", version: "5.2.2"
+override "libtool", version: "2.4.2"
+override "libxml2", version: "2.9.4"
+override "libxslt", version: "1.1.29"
+override "libyaml", version: "0.1.6"
+override "makedepend", version: "1.0.5"
+override "ncurses", version: "5.9"
+override "pkg-config-lite", version: "0.28-1"
+override "ruby", version: "2.3.1"
+override "ruby-windows-devkit-bash", version: "3.1.23-4-msys-1.0.18"
+override "util-macros", version: "1.19.0"
+override "xproto", version: "7.0.28"
+override "zlib", version: "1.2.8"
+override "openssl", version: "1.0.2j"
diff --git a/pedant.gemfile b/pedant.gemfile
deleted file mode 100644
index 3302bccfe1..0000000000
--- a/pedant.gemfile
+++ /dev/null
@@ -1,25 +0,0 @@
-source "https://rubygems.org"
-gemspec :name => "chef"
-
-# TODO figure out how to grab this stuff from the main Gemfile
-gem "activesupport", "< 4.0.0", :group => :compat_testing, :platform => "ruby"
-
-# We are pinning chef-zero to 4.2.x until ChefFS can deal
-# with V1 api calls or chef-zero supports both v0 and v1
-gem "chef-zero", "~> 4.2.3"
-
-group(:docgen) do
- gem "tomlrb"
- gem "yard"
-end
-
-group(:development, :test) do
- gem "simplecov"
- gem 'rack', "~> 1.5.1"
-
- gem 'ruby-shadow', :platforms => :ruby unless RUBY_PLATFORM.downcase.match(/(aix|cygwin)/)
-end
-
-# If you want to load debugging tools into the bundle exec sandbox,
-# add these additional dependencies into chef/Gemfile.local
-eval(IO.read(__FILE__ + '.local'), binding) if File.exists?(__FILE__ + '.local')
diff --git a/rubygems-pkg/rubygems-update-2.4.6.gem b/rubygems-pkg/rubygems-update-2.4.6.gem
deleted file mode 100644
index 97ebec693a..0000000000
--- a/rubygems-pkg/rubygems-update-2.4.6.gem
+++ /dev/null
Binary files differ
diff --git a/spec/data/apt/chef-integration-test-1.0/debian/copyright b/spec/data/apt/chef-integration-test-1.0/debian/copyright
index 72b6c65542..e840a11cca 100644
--- a/spec/data/apt/chef-integration-test-1.0/debian/copyright
+++ b/spec/data/apt/chef-integration-test-1.0/debian/copyright
@@ -8,7 +8,7 @@ Upstream Author(s):
Copyright:
- Copyright (C) 2010 Opscode, Inc
+ Copyright 2010-2016, Chef Software Inc.
License:
@@ -26,7 +26,7 @@ License:
The Debian packaging is:
- Copyright (C) 2010 Opscode, Inc (<legal@opscode.com>)
+ Copyright 2010-2016, Chef Software Inc. (<legal@chef.io>)
and is licensed under the Apache 2.0 license.
diff --git a/spec/data/apt/chef-integration-test-1.1/debian/copyright b/spec/data/apt/chef-integration-test-1.1/debian/copyright
index 72b6c65542..e840a11cca 100644
--- a/spec/data/apt/chef-integration-test-1.1/debian/copyright
+++ b/spec/data/apt/chef-integration-test-1.1/debian/copyright
@@ -8,7 +8,7 @@ Upstream Author(s):
Copyright:
- Copyright (C) 2010 Opscode, Inc
+ Copyright 2010-2016, Chef Software Inc.
License:
@@ -26,7 +26,7 @@ License:
The Debian packaging is:
- Copyright (C) 2010 Opscode, Inc (<legal@opscode.com>)
+ Copyright 2010-2016, Chef Software Inc. (<legal@chef.io>)
and is licensed under the Apache 2.0 license.
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/changelog b/spec/data/apt/chef-integration-test2-1.0/debian/changelog
new file mode 100644
index 0000000000..1b846f8f4d
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/changelog
@@ -0,0 +1,5 @@
+chef-integration-test2 (1.0-1) unstable; urgency=low
+
+ * Initial release (Closes: #CHEF-1718)
+
+ -- Joshua Timberman <joshua@opscode.com> Thu, 30 Sep 2010 09:53:45 -0600
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log
new file mode 100644
index 0000000000..2d06fcdad9
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log
@@ -0,0 +1,45 @@
+dh_auto_configure
+dh_auto_build
+dh_auto_test
+dh_prep
+dh_installdirs
+dh_auto_install
+dh_install
+dh_installdocs
+dh_installchangelogs
+dh_installexamples
+dh_installman
+dh_installcatalogs
+dh_installcron
+dh_installdebconf
+dh_installemacsen
+dh_installifupdown
+dh_installinfo
+dh_pysupport
+dh_installinit
+dh_installmenu
+dh_installmime
+dh_installmodules
+dh_installlogcheck
+dh_installlogrotate
+dh_installpam
+dh_installppp
+dh_installudev
+dh_installwm
+dh_installxfonts
+dh_bugfiles
+dh_lintian
+dh_gconf
+dh_icons
+dh_perl
+dh_usrlocal
+dh_link
+dh_compress
+dh_fixperms
+dh_strip
+dh_makeshlibs
+dh_shlibdeps
+dh_installdeb
+dh_gencontrol
+dh_md5sums
+dh_builddeb
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars
new file mode 100644
index 0000000000..abd3ebebc3
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars
@@ -0,0 +1 @@
+misc:Depends=
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles
new file mode 100644
index 0000000000..ac4307eadf
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles
@@ -0,0 +1 @@
+/usr/share/doc/chef-integration-test2/copyright
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control
new file mode 100644
index 0000000000..27d53d9750
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control
@@ -0,0 +1,10 @@
+Package: chef-integration-test2
+Version: 1.0-1
+Architecture: amd64
+Maintainer: Joshua Timberman <Joshua Timberman <joshua@opscode.com>>
+Installed-Size: 36
+Section: ruby
+Priority: extra
+Homepage: http://tickets.opscode.com
+Description: Chef integration tests for APT in Cucumber
+ This package is used for cucumber integration testing in Chef.
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums
new file mode 100644
index 0000000000..144b7931de
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums
@@ -0,0 +1 @@
+8b3b9ff6cdfe7d7b2b8b8d4f7b9e381f usr/share/doc/chef-integration-test2/changelog.Debian.gz
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/compat b/spec/data/apt/chef-integration-test2-1.0/debian/compat
new file mode 100644
index 0000000000..7f8f011eb7
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/conffiles b/spec/data/apt/chef-integration-test2-1.0/debian/conffiles
new file mode 100644
index 0000000000..ac4307eadf
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/conffiles
@@ -0,0 +1 @@
+/usr/share/doc/chef-integration-test2/copyright
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/control b/spec/data/apt/chef-integration-test2-1.0/debian/control
new file mode 100644
index 0000000000..f2731a6848
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/control
@@ -0,0 +1,13 @@
+Source: chef-integration-test2
+Section: ruby
+Priority: extra
+Maintainer: Joshua Timberman <Joshua Timberman <joshua@opscode.com>>
+Build-Depends: debhelper (>= 7.0.50~)
+Standards-Version: 3.8.4
+Homepage: http://tickets.opscode.com
+
+Package: chef-integration-test2
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Chef integration tests for APT in Cucumber
+ This package is used for cucumber integration testing in Chef.
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/copyright b/spec/data/apt/chef-integration-test2-1.0/debian/copyright
new file mode 100644
index 0000000000..e840a11cca
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/copyright
@@ -0,0 +1,34 @@
+This work was packaged by:
+
+ Joshua Timberman <Joshua Timberman <joshua@opscode.com>> on Thu, 30 Sep 2010 09:53:45 -0600
+
+Upstream Author(s):
+
+ Opscode, Inc.
+
+Copyright:
+
+ Copyright 2010-2016, Chef Software Inc.
+
+License:
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+The Debian packaging is:
+
+ Copyright 2010-2016, Chef Software Inc. (<legal@chef.io>)
+
+
+and is licensed under the Apache 2.0 license.
+
+See "/usr/share/common-licenses/Apache-2.0"
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/files b/spec/data/apt/chef-integration-test2-1.0/debian/files
new file mode 100644
index 0000000000..640e4c6414
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/files
@@ -0,0 +1 @@
+chef-integration-test2_1.0-1_amd64.deb ruby extra
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/rules b/spec/data/apt/chef-integration-test2-1.0/debian/rules
new file mode 100755
index 0000000000..b760bee7f4
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/rules
@@ -0,0 +1,13 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+%:
+ dh $@
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/source/format b/spec/data/apt/chef-integration-test2-1.0/debian/source/format
new file mode 100644
index 0000000000..163aaf8d82
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/spec/data/apt/chef-integration-test2_1.0-1.debian.tar.gz b/spec/data/apt/chef-integration-test2_1.0-1.debian.tar.gz
new file mode 100644
index 0000000000..6c002a7420
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2_1.0-1.debian.tar.gz
Binary files differ
diff --git a/spec/data/apt/chef-integration-test2_1.0-1.dsc b/spec/data/apt/chef-integration-test2_1.0-1.dsc
new file mode 100644
index 0000000000..b247f49346
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2_1.0-1.dsc
@@ -0,0 +1,18 @@
+Format: 3.0 (quilt)
+Source: chef-integration-test2
+Binary: chef-integration-test2
+Architecture: any
+Version: 1.0-1
+Maintainer: Joshua Timberman <Joshua Timberman <joshua@opscode.com>>
+Homepage: http://tickets.opscode.com
+Standards-Version: 3.8.4
+Build-Depends: debhelper (>= 7.0.50~)
+Checksums-Sha1:
+ 755c304197c6559128aed206ea70643fec2bb90d 248 chef-integration-test2_1.0.orig.tar.gz
+ 8b7df49a9e2c57b4460c2738852db1156a21a089 1369 chef-integration-test2_1.0-1.debian.tar.gz
+Checksums-Sha256:
+ 8b206a7b3d422290bc8d82bd700cb89f1c6e3962b96be6a3955c7a0159f9031c 248 chef-integration-test2_1.0.orig.tar.gz
+ 77a7956e222c35afcddc4a5a8d338ca6e36dc1fbd720af255ce2412885f82702 1369 chef-integration-test2_1.0-1.debian.tar.gz
+Files:
+ f1f7d7bbe63ad631d25d707f564a8d33 248 chef-integration-test2_1.0.orig.tar.gz
+ 4fab5c1cd9a7b47c4f319af776f48a1d 1369 chef-integration-test2_1.0-1.debian.tar.gz
diff --git a/spec/data/apt/chef-integration-test2_1.0-1_amd64.build b/spec/data/apt/chef-integration-test2_1.0-1_amd64.build
new file mode 100644
index 0000000000..8ef31d3ccf
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2_1.0-1_amd64.build
@@ -0,0 +1,91 @@
+ dpkg-buildpackage -rfakeroot -D -us -uc
+dpkg-buildpackage: warning: using a gain-root-command while being root
+dpkg-buildpackage: set CFLAGS to default value: -g -O2
+dpkg-buildpackage: set CPPFLAGS to default value:
+dpkg-buildpackage: set LDFLAGS to default value: -Wl,-Bsymbolic-functions
+dpkg-buildpackage: set FFLAGS to default value: -g -O2
+dpkg-buildpackage: set CXXFLAGS to default value: -g -O2
+dpkg-buildpackage: source package chef-integration-test2
+dpkg-buildpackage: source version 1.0-1
+dpkg-buildpackage: source changed by Joshua Timberman <joshua@opscode.com>
+dpkg-buildpackage: host architecture amd64
+ fakeroot debian/rules clean
+dh clean
+ dh_testdir
+ dh_auto_clean
+ dh_clean
+ dpkg-source -b chef-integration-test2-1.0
+dpkg-source: info: using source format `3.0 (quilt)'
+dpkg-source: info: building chef-integration-test2 using existing ./chef-integration-test2_1.0.orig.tar.gz
+dpkg-source: warning: ignoring deletion of directory cache
+dpkg-source: warning: ignoring deletion of directory cache/chef-integration-test2
+dpkg-source: warning: ignoring deletion of file cache/chef-integration-test2/contents
+dpkg-source: info: building chef-integration-test2 in chef-integration-test2_1.0-1.debian.tar.gz
+dpkg-source: info: building chef-integration-test2 in chef-integration-test2_1.0-1.dsc
+ debian/rules build
+dh build
+ dh_testdir
+ dh_auto_configure
+ dh_auto_build
+ dh_auto_test
+ fakeroot debian/rules binary
+dh binary
+ dh_testroot
+ dh_prep
+ dh_installdirs
+ dh_auto_install
+ dh_install
+ dh_installdocs
+ dh_installchangelogs
+ dh_installexamples
+ dh_installman
+ dh_installcatalogs
+ dh_installcron
+ dh_installdebconf
+ dh_installemacsen
+ dh_installifupdown
+ dh_installinfo
+ dh_pysupport
+ dh_installinit
+ dh_installmenu
+ dh_installmime
+ dh_installmodules
+ dh_installlogcheck
+ dh_installlogrotate
+ dh_installpam
+ dh_installppp
+ dh_installudev
+ dh_installwm
+ dh_installxfonts
+ dh_bugfiles
+ dh_lintian
+ dh_gconf
+ dh_icons
+ dh_perl
+ dh_usrlocal
+ dh_link
+ dh_compress
+ dh_fixperms
+ dh_strip
+ dh_makeshlibs
+ dh_shlibdeps
+ dh_installdeb
+ dh_gencontrol
+dpkg-gencontrol: warning: unknown substitution variable ${shlibs:Depends}
+ dh_md5sums
+ dh_builddeb
+dpkg-deb: building package `chef-integration-test2' in `../chef-integration-test2_1.0-1_amd64.deb'.
+ dpkg-genchanges >../chef-integration-test2_1.0-1_amd64.changes
+dpkg-genchanges: including full source code in upload
+dpkg-buildpackage: full upload (original source is included)
+Now running lintian...
+warning: lintian's authors do not recommend running it with root privileges!
+E: chef-integration-test2 source: maintainer-address-malformed Joshua Timberman <Joshua Timberman <joshua@opscode.com>>
+W: chef-integration-test2 source: changelog-should-mention-nmu
+W: chef-integration-test2 source: source-nmu-has-incorrect-version-number 1.0-1
+W: chef-integration-test2: new-package-should-close-itp-bug
+W: chef-integration-test2: wrong-bug-number-in-closes l3:#CHEF
+E: chef-integration-test2: file-in-usr-marked-as-conffile /usr/share/doc/chef-integration-test2/copyright
+E: chef-integration-test2: maintainer-address-malformed Joshua Timberman <Joshua Timberman <joshua@opscode.com>>
+W: chef-integration-test2: empty-binary-package
+Finished running lintian.
diff --git a/spec/data/apt/chef-integration-test2_1.0-1_amd64.changes b/spec/data/apt/chef-integration-test2_1.0-1_amd64.changes
new file mode 100644
index 0000000000..be3cd45343
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2_1.0-1_amd64.changes
@@ -0,0 +1,31 @@
+Format: 1.8
+Date: Thu, 30 Sep 2010 09:53:45 -0600
+Source: chef-integration-test2
+Binary: chef-integration-test2
+Architecture: source amd64
+Version: 1.0-1
+Distribution: unstable
+Urgency: low
+Maintainer: Joshua Timberman <Joshua Timberman <joshua@opscode.com>>
+Changed-By: Joshua Timberman <joshua@opscode.com>
+Description:
+ chef-integration-test2 - Chef integration tests for APT in Cucumber
+Changes:
+ chef-integration-test2 (1.0-1) unstable; urgency=low
+ .
+ * Initial release (Closes: #CHEF-1718)
+Checksums-Sha1:
+ 7e065fdf71f4d798312b318a29cec43b7bc1c8e1 885 chef-integration-test2_1.0-1.dsc
+ 755c304197c6559128aed206ea70643fec2bb90d 248 chef-integration-test2_1.0.orig.tar.gz
+ 8b7df49a9e2c57b4460c2738852db1156a21a089 1369 chef-integration-test2_1.0-1.debian.tar.gz
+ f3f89c051bce36d40ef1be12d231c44b2d5be05b 1694 chef-integration-test2_1.0-1_amd64.deb
+Checksums-Sha256:
+ 80d314349e1d978f242d05482ca81c9361739047daa4adcecc9e5e622fdc6fb4 885 chef-integration-test2_1.0-1.dsc
+ 8b206a7b3d422290bc8d82bd700cb89f1c6e3962b96be6a3955c7a0159f9031c 248 chef-integration-test2_1.0.orig.tar.gz
+ 77a7956e222c35afcddc4a5a8d338ca6e36dc1fbd720af255ce2412885f82702 1369 chef-integration-test2_1.0-1.debian.tar.gz
+ 19a767db0a947a350fb1c8492699e8a808fbe1838d4a582001106cfbe520ad8f 1694 chef-integration-test2_1.0-1_amd64.deb
+Files:
+ 9f927b32d95b5406c696b5b0b23177e8 885 ruby extra chef-integration-test2_1.0-1.dsc
+ f1f7d7bbe63ad631d25d707f564a8d33 248 ruby extra chef-integration-test2_1.0.orig.tar.gz
+ 4fab5c1cd9a7b47c4f319af776f48a1d 1369 ruby extra chef-integration-test2_1.0-1.debian.tar.gz
+ 9914e6152e278b6828bcade3b3f5580c 1694 ruby extra chef-integration-test2_1.0-1_amd64.deb
diff --git a/spec/data/apt/chef-integration-test2_1.0-1_amd64.deb b/spec/data/apt/chef-integration-test2_1.0-1_amd64.deb
new file mode 100644
index 0000000000..7b9b69d378
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2_1.0-1_amd64.deb
Binary files differ
diff --git a/spec/data/apt/chef-integration-test2_1.0.orig.tar.gz b/spec/data/apt/chef-integration-test2_1.0.orig.tar.gz
new file mode 100644
index 0000000000..18f7aa17d6
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2_1.0.orig.tar.gz
Binary files differ
diff --git a/spec/data/client.d_00/00-foo.rb b/spec/data/client.d_00/00-foo.rb
new file mode 100644
index 0000000000..44a763aca1
--- /dev/null
+++ b/spec/data/client.d_00/00-foo.rb
@@ -0,0 +1,2 @@
+# 00-foo.rb
+# d6f9b976-289c-4149-baf7-81e6ffecf228
diff --git a/spec/data/client.d_00/01-bar.rb b/spec/data/client.d_00/01-bar.rb
new file mode 100644
index 0000000000..73f91386bc
--- /dev/null
+++ b/spec/data/client.d_00/01-bar.rb
@@ -0,0 +1 @@
+# 01-bar.rb
diff --git a/spec/data/client.d_00/bar b/spec/data/client.d_00/bar
new file mode 100644
index 0000000000..72dca4d5e4
--- /dev/null
+++ b/spec/data/client.d_00/bar
@@ -0,0 +1 @@
+1 / 0
diff --git a/spec/data/client.d_01/foo/bar.rb b/spec/data/client.d_01/foo/bar.rb
new file mode 100644
index 0000000000..72dca4d5e4
--- /dev/null
+++ b/spec/data/client.d_01/foo/bar.rb
@@ -0,0 +1 @@
+1 / 0
diff --git a/spec/data/client.d_02/foo.rb/foo.txt b/spec/data/client.d_02/foo.rb/foo.txt
new file mode 100644
index 0000000000..d724c93bef
--- /dev/null
+++ b/spec/data/client.d_02/foo.rb/foo.txt
@@ -0,0 +1 @@
+# foo.txt
diff --git a/spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb b/spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb
index 01d302f043..0bb34e78e1 100644
--- a/spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb
+++ b/spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb
@@ -2,7 +2,7 @@
# Cookbook Name:: name-mismatch
# Recipe:: default
#
-# Copyright (C) 2014
+# Copyright 2014-2016,
#
#
#
diff --git a/spec/unit/provider/package_spec.rbe b/spec/data/cookbooks/openldap/.root_dotfile
index e69de29bb2..e69de29bb2 100644
--- a/spec/unit/provider/package_spec.rbe
+++ b/spec/data/cookbooks/openldap/.root_dotfile
diff --git a/spec/data/cookbooks/openldap/spec/spec_helper.rb b/spec/data/cookbooks/openldap/spec/spec_helper.rb
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/spec/data/cookbooks/openldap/spec/spec_helper.rb
diff --git a/spec/data/cookbooks/supports-platform-constraints/metadata.rb b/spec/data/cookbooks/supports-platform-constraints/metadata.rb
new file mode 100644
index 0000000000..3620249d5f
--- /dev/null
+++ b/spec/data/cookbooks/supports-platform-constraints/metadata.rb
@@ -0,0 +1,5 @@
+name 'supports-platform-constraints'
+version '0.1.0'
+
+supports 'centos', '>= 6'
+supports 'freebsd', '> 10.1-fake-p12'
diff --git a/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb b/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb
index 65ae049ce8..0d8cca1bda 100644
--- a/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb
+++ b/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb
@@ -2,7 +2,7 @@
# Cookbook Name:: incomplete-metadata
# Recipe:: default
#
-# Copyright (C) 2014
+# Copyright 2014-2016,
#
#
#
diff --git a/spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb b/spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb
index f548ad1dd8..1130ee40e8 100644
--- a/spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb
+++ b/spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb
@@ -1,5 +1,3 @@
-raise "THIS METADATA HAS A BUG"
-
name 'invalid-metadata'
maintainer ''
maintainer_email ''
@@ -8,3 +6,4 @@ description 'Installs/Configures invalid-metadata'
long_description 'Installs/Configures invalid-metadata'
version '0.1.0'
+raise "THIS METADATA HAS A BUG"
diff --git a/spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb b/spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb
index 1411b9e39f..33ec1144fe 100644
--- a/spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb
+++ b/spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb
@@ -2,7 +2,7 @@
# Cookbook Name:: invalid-metadata
# Recipe:: default
#
-# Copyright (C) 2014
+# Copyright 2014-2016,
#
#
#
diff --git a/spec/data/prefer_metadata_json/metadata.json b/spec/data/prefer_metadata_json/metadata.json
new file mode 100644
index 0000000000..eff8836a3b
--- /dev/null
+++ b/spec/data/prefer_metadata_json/metadata.json
@@ -0,0 +1,51 @@
+{
+ "name": "prefer_metadata_json",
+ "description": "",
+ "long_description": "",
+ "maintainer": null,
+ "maintainer_email": null,
+ "license": "All rights reserved",
+ "platforms": {
+
+ },
+ "dependencies": {
+
+ },
+ "recommendations": {
+
+ },
+ "suggestions": {
+
+ },
+ "conflicting": {
+
+ },
+ "providing": {
+
+ },
+ "replacing": {
+
+ },
+ "attributes": {
+
+ },
+ "groupings": {
+
+ },
+ "recipes": {
+
+ },
+ "version": "1.2.3",
+ "source_url": "",
+ "issues_url": "",
+ "privacy": false,
+ "chef_versions": [
+
+ ],
+ "ohai_versions": [
+
+ ],
+ "gems": [
+
+ ]
+}
diff --git a/spec/data/prefer_metadata_json/metadata.rb b/spec/data/prefer_metadata_json/metadata.rb
new file mode 100644
index 0000000000..a46aa29a5c
--- /dev/null
+++ b/spec/data/prefer_metadata_json/metadata.rb
@@ -0,0 +1,6 @@
+# these deliberately do not match metadata.json
+name "test"
+version "0.0.1"
+
+# this raises hard if anything even tries to parse it
+raise "TEH SADNESS"
diff --git a/spec/data/prefer_metadata_json/recipes/default.rb b/spec/data/prefer_metadata_json/recipes/default.rb
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/spec/data/prefer_metadata_json/recipes/default.rb
diff --git a/spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb b/spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb
index ef0967a4d2..e45e7d9f68 100644
--- a/spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb
+++ b/spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb
@@ -1,4 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "circular-dep1::default"
-
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "circular-dep1::default"
diff --git a/spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb b/spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb
index f2ef012aa1..37f396b1f9 100644
--- a/spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb
+++ b/spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb
@@ -1,3 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "circular-dep2::default"
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "circular-dep2::default"
diff --git a/spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb b/spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb
index e818d36a9e..3059494198 100644
--- a/spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb
+++ b/spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb
@@ -1,2 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "dependency1::aa_first"
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "dependency1::aa_first"
diff --git a/spec/data/run_context/cookbooks/dependency1/attributes/default.rb b/spec/data/run_context/cookbooks/dependency1/attributes/default.rb
index 6875274e3f..a65a3345bc 100644
--- a/spec/data/run_context/cookbooks/dependency1/attributes/default.rb
+++ b/spec/data/run_context/cookbooks/dependency1/attributes/default.rb
@@ -1,2 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "dependency1::default"
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "dependency1::default"
diff --git a/spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb b/spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb
index 1a513b03d4..94ffb30133 100644
--- a/spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb
+++ b/spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb
@@ -1,3 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "dependency1::zz_last"
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "dependency1::zz_last"
diff --git a/spec/data/run_context/cookbooks/dependency2/attributes/default.rb b/spec/data/run_context/cookbooks/dependency2/attributes/default.rb
index 526751f422..8917bf9730 100644
--- a/spec/data/run_context/cookbooks/dependency2/attributes/default.rb
+++ b/spec/data/run_context/cookbooks/dependency2/attributes/default.rb
@@ -1,3 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "dependency2::default"
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "dependency2::default"
diff --git a/spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb b/spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb
index 3ad2b925aa..07294665b2 100644
--- a/spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb
+++ b/spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb
@@ -1,3 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "no-default-attr::server"
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "no-default-attr::server"
diff --git a/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb b/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb
index cca56bc61f..77309462b1 100644
--- a/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb
+++ b/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb
@@ -1,3 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "test-with-circular-deps::default"
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "test-with-circular-deps::default"
diff --git a/spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb b/spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb
index 4d71cc3cfe..c4cc8151a4 100644
--- a/spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb
+++ b/spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb
@@ -1,3 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "test-with-deps::default"
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "test-with-deps::default"
diff --git a/spec/data/sample_msu1.xml b/spec/data/sample_msu1.xml
new file mode 100644
index 0000000000..cc68dbf060
--- /dev/null
+++ b/spec/data/sample_msu1.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<unattend xmlns="urn:schemas-microsoft-com:unattend">
+ <servicing>
+ <package action="install">
+ <assemblyIdentity name="Package_for_KB2859903" version="10.2.1.0" language="neutral" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"/>
+ <source location="%configsetroot%\IE10-Windows6.1-KB2859903-x86.CAB" />
+ </package>
+ </servicing>
+</unattend>
+
diff --git a/spec/data/sample_msu2.xml b/spec/data/sample_msu2.xml
new file mode 100644
index 0000000000..6f95e04f93
--- /dev/null
+++ b/spec/data/sample_msu2.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<unattend xmlns="urn:schemas-microsoft-com:unattend">
+ <servicing>
+ <package action="install">
+ <assemblyIdentity name="Package_for_KB2859903" version="10.2.1.0" language="neutral" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"/>
+ <source location="%configsetroot%\IE10-Windows6.1-KB2859903-x86.CAB" />
+ </package>
+ <package action="install">
+ <assemblyIdentity name="Package_for_abc" version="10.2.1.0" language="neutral" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"/>
+ <source location="%configsetroot%\abc.CAB" />
+ </package>
+ </servicing>
+</unattend>
+
diff --git a/spec/data/sample_msu3.xml b/spec/data/sample_msu3.xml
new file mode 100644
index 0000000000..0ef09da206
--- /dev/null
+++ b/spec/data/sample_msu3.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<unattend xmlns="urn:schemas-microsoft-com:unattend">
+ <servicing>
+ <package action="install">
+ <assemblyIdentity name="Package_for_KB2859903" version="10.2.1.0" language="neutral" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"/>
+ <source location="%configsetroot%\IE10-Windows6.1-KB2859903-x86.CAB" />
+ </package>
+ </servicing>
+ <servicing>
+ <package action="install">
+ <assemblyIdentity name="Package_for_abc" version="10.2.1.0" language="neutral" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"/>
+ <source location="%configsetroot%\abc.CAB" />
+ </package>
+ </servicing>
+</unattend>
+
diff --git a/spec/data/templates/chef-seattle20160930-4388-1crv7ef.txt b/spec/data/templates/chef-seattle20160930-4388-1crv7ef.txt
new file mode 100644
index 0000000000..f476ccd704
--- /dev/null
+++ b/spec/data/templates/chef-seattle20160930-4388-1crv7ef.txt
@@ -0,0 +1 @@
+Do do do do, do do do do, do do do do, do do do do \ No newline at end of file
diff --git a/spec/data/templates/chef-seattle20160930-4388-jjfoae.txt b/spec/data/templates/chef-seattle20160930-4388-jjfoae.txt
new file mode 100644
index 0000000000..f476ccd704
--- /dev/null
+++ b/spec/data/templates/chef-seattle20160930-4388-jjfoae.txt
@@ -0,0 +1 @@
+Do do do do, do do do do, do do do do, do do do do \ No newline at end of file
diff --git a/spec/data/templates/chef-seattle20160930-4388-umeq2c.txt b/spec/data/templates/chef-seattle20160930-4388-umeq2c.txt
new file mode 100644
index 0000000000..f476ccd704
--- /dev/null
+++ b/spec/data/templates/chef-seattle20160930-4388-umeq2c.txt
@@ -0,0 +1 @@
+Do do do do, do do do do, do do do do, do do do do \ No newline at end of file
diff --git a/spec/data/trusted_certs/example_no_cn.crt b/spec/data/trusted_certs/example_no_cn.crt
new file mode 100644
index 0000000000..6b42b40d99
--- /dev/null
+++ b/spec/data/trusted_certs/example_no_cn.crt
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGPzCCBCegAwIBAgIJAKwtLqBeqNzfMA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJXQTEQMA4GA1UEBxMHU2VhdHRsZTEQMA4GA1UEChMH
+WW91Q29ycDETMBEGA1UECxMKT3BlcmF0aW9uczEdMBsGCSqGSIb3DQEJARYObWVA
+ZXhhbXBsZS5jb20wHhcNMTYxMDMxMTkxMzQ2WhcNMjYxMDI5MTkxMzQ2WjByMQsw
+CQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxEDAOBgNV
+BAoTB1lvdUNvcnAxEzARBgNVBAsTCk9wZXJhdGlvbnMxHTAbBgkqhkiG9w0BCQEW
+Dm1lQGV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
+s1OiWnMV3shxVccqzenDBww5rSou9Ab/VqujKisJ54dXyHukYMxh9MJwlRDsy0FB
+uKRAyNfhM43hSMYhtF7NS//D1lI/LDvIQkBaH8R834bvK102Avmsx7zKPOo/CUkd
+g7uuL2eRzRszEuAREH1E7/PpTj11CjirG9i7FlbKj7vDA1Nqvtb0kHdiQuH2Cojy
+Uf1uVFyE5UliFXtePDrxpOAfJUbcSdOLsK8olKHGCb0cfN/tCfbyEY8rHGsAUK2A
+afuHRTR7pRQwfqJ5EK3DBbbFz+GSi+9zWFOudfqTsczS/HtpMbF8HBwqBAa+mpU/
+UjmhpTYQ+rgVtWtEcttboeK6jvFBFLyQ6VRcrDi/8lmAnm1Q+RZk5g3GwZMhIMNU
+5XQZf6jsUsIFBuOaRyLn9dXkgyO7gOy8n8Yw+YdIFt29kaqZ6pu9kpS0jquxzSKj
+MVS4OrThLwgazfQu/BlOvJpQfcNPI/VP9c41yHKpeoIh6oxNDc/212/wwgwPgD83
+8YXddupaSuE++h9Z10CCZgwux8deTlMjzETIMiIo8R3KV0pJgZ11akeJ8USr+QQ2
++fO/GdpNUa5nNTgF3t4zTF3DPToqj6KDgxLhUdXopF1hLYgwr8FKOtn9KXP+I0hz
+hWzZoX9gwFLEPrUy265Gpw8TVTmNuSiiZtgJDSDKTBcCAwEAAaOB1zCB1DAdBgNV
+HQ4EFgQUr5Y6dxhyVxfhwFsEKLDIXxQ2zBswgaQGA1UdIwSBnDCBmYAUr5Y6dxhy
+VxfhwFsEKLDIXxQ2zBuhdqR0MHIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJXQTEQ
+MA4GA1UEBxMHU2VhdHRsZTEQMA4GA1UEChMHWW91Q29ycDETMBEGA1UECxMKT3Bl
+cmF0aW9uczEdMBsGCSqGSIb3DQEJARYObWVAZXhhbXBsZS5jb22CCQCsLS6gXqjc
+3zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQBYXgqXAnocH6i8o47c
+BZPMGO9y4LCB4YNIrZPKRNFvRl2aolA5KiBxr6WJp1iczxVA4lCmXU1LGfvRPHec
+nHtVax3+Q1JCZhBSv/txQTjgn72qoJyCsPmjyWifbE1jFdRj0g74/Eu/0ku3L0vV
+jTlqzJXQIzRkQm+Y5OrZo92tXaOgO+C0qdd6gaEaIIya6bzrBpW95NtVymhXi2Qf
+7G7Z/yw8XhoQiDJaPHF6XavC3dYvi51cehnPR4E6Jok23kbJEe3Qw5Yh747JjSsS
+Sz07CKqTFcFjHI2f1sFdDjw34lj5mtOf3pEpRGGmvzkF8zm/sVQQ2rCKnqEe7zPy
+Bg9guzVpORG+g76hGFZcYnz78LLNrIYcuYoLcbbZh404wjmifVKO5OC1dRgmJTuc
+VnJe92568Y9cUAjrLztxp5gwXgYUllsXweJ2UGiHxSBqUfCCGG5vK5sYs52HR6wJ
+wRSvwk/VHifYPxJ54RRB51ebYjmD1j41tRseHdFq21qpXSvr9DFLUJBvdN9zA/6t
+xCBlXAdYxD0n0/bruUYNoXBeMhLp+WKSAQvTlVIyqoNQCo1OBBzBVNg9otl3jw5d
+1QOhodRqmS5UQAJptuXtk8WN8OZqMCCeogIfdpa5tJG+/fxFML9EvqedS4c05Wf/
+oYdVLVWSjyoA2l4Xb4LdexAgCg==
+-----END CERTIFICATE-----
diff --git a/spec/functional/application_spec.rb b/spec/functional/application_spec.rb
index 00ff0f702a..19a23e0e22 100644
--- a/spec/functional/application_spec.rb
+++ b/spec/functional/application_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "chef/mixin/shell_out"
describe Chef::Application do
include Chef::Mixin::ShellOut
@@ -42,15 +42,15 @@ describe Chef::Application do
Chef::Config[:ftp_proxy] = nil
Chef::Config[:no_proxy] = nil
- @app.configure_proxy_environment_variables
+ Chef::Config.export_proxies
end
it "saves built proxy to ENV which shell_out can use" do
so = if windows?
- shell_out("echo %http_proxy%")
- else
- shell_out("echo $http_proxy")
- end
+ shell_out("echo %http_proxy%")
+ else
+ shell_out("echo $http_proxy")
+ end
expect(so.stdout.chomp).to eq("http://proxy.example.org:8080")
end
diff --git a/spec/functional/assets/chocolatey_feed/test-A.1.0.nupkg b/spec/functional/assets/chocolatey_feed/test-A.1.0.nupkg
new file mode 100644
index 0000000000..0295507373
--- /dev/null
+++ b/spec/functional/assets/chocolatey_feed/test-A.1.0.nupkg
Binary files differ
diff --git a/spec/functional/assets/chocolatey_feed/test-A.1.5.nupkg b/spec/functional/assets/chocolatey_feed/test-A.1.5.nupkg
new file mode 100644
index 0000000000..19782211e3
--- /dev/null
+++ b/spec/functional/assets/chocolatey_feed/test-A.1.5.nupkg
Binary files differ
diff --git a/spec/functional/assets/chocolatey_feed/test-A.2.0.nupkg b/spec/functional/assets/chocolatey_feed/test-A.2.0.nupkg
new file mode 100644
index 0000000000..360c0843e2
--- /dev/null
+++ b/spec/functional/assets/chocolatey_feed/test-A.2.0.nupkg
Binary files differ
diff --git a/spec/functional/assets/chocolatey_feed/test-B.1.0.nupkg b/spec/functional/assets/chocolatey_feed/test-B.1.0.nupkg
new file mode 100644
index 0000000000..d82b0d09bc
--- /dev/null
+++ b/spec/functional/assets/chocolatey_feed/test-B.1.0.nupkg
Binary files differ
diff --git a/spec/functional/assets/testchefsubsys b/spec/functional/assets/testchefsubsys
index e9ff30d4aa..e5c2f8cfc4 100755
--- a/spec/functional/assets/testchefsubsys
+++ b/spec/functional/assets/testchefsubsys
@@ -5,7 +5,6 @@ sleep 120 &
pid="$!"
-trap 'echo I am going down, so killing off my processes..; kill $pid; exit' SIGHUP SIGINT
- SIGQUIT SIGTERM
+trap 'echo I am going down, so killing off my processes..; kill $pid; exit' SIGHUP SIGINT SIGQUIT SIGTERM
-wait \ No newline at end of file
+wait
diff --git a/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.i686.rpm b/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.i686.rpm
new file mode 100644
index 0000000000..29a4624971
--- /dev/null
+++ b/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.i686.rpm
Binary files differ
diff --git a/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.src.rpm b/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.src.rpm
new file mode 100644
index 0000000000..b6a6ec3176
--- /dev/null
+++ b/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.src.rpm
Binary files differ
diff --git a/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.x86_64.rpm b/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.x86_64.rpm
new file mode 100644
index 0000000000..239b6ef145
--- /dev/null
+++ b/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.x86_64.rpm
Binary files differ
diff --git a/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.i686.rpm b/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.i686.rpm
new file mode 100644
index 0000000000..3421c3628f
--- /dev/null
+++ b/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.i686.rpm
Binary files differ
diff --git a/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.src.rpm b/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.src.rpm
new file mode 100644
index 0000000000..d420659fd5
--- /dev/null
+++ b/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.src.rpm
Binary files differ
diff --git a/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm b/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm
new file mode 100644
index 0000000000..93c1f5e3e3
--- /dev/null
+++ b/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm
Binary files differ
diff --git a/spec/functional/assets/yumrepo/repodata/313329137b55fd333b2dc66394a6661a2befa6cc535d8460d92a4a78a9c581f0-primary.sqlite.bz2 b/spec/functional/assets/yumrepo/repodata/313329137b55fd333b2dc66394a6661a2befa6cc535d8460d92a4a78a9c581f0-primary.sqlite.bz2
new file mode 100644
index 0000000000..d7726b9df6
--- /dev/null
+++ b/spec/functional/assets/yumrepo/repodata/313329137b55fd333b2dc66394a6661a2befa6cc535d8460d92a4a78a9c581f0-primary.sqlite.bz2
Binary files differ
diff --git a/spec/functional/assets/yumrepo/repodata/31ac4db5d5ac593728fcc26aef82b7b93c4cc4dbec843786b1845b939b658553-other.xml.gz b/spec/functional/assets/yumrepo/repodata/31ac4db5d5ac593728fcc26aef82b7b93c4cc4dbec843786b1845b939b658553-other.xml.gz
new file mode 100644
index 0000000000..30d7778ac4
--- /dev/null
+++ b/spec/functional/assets/yumrepo/repodata/31ac4db5d5ac593728fcc26aef82b7b93c4cc4dbec843786b1845b939b658553-other.xml.gz
Binary files differ
diff --git a/spec/functional/assets/yumrepo/repodata/4ac40fa3c6728c1401318e2e20a997436624e83dcf7a5f952b851ef422637773-filelists.sqlite.bz2 b/spec/functional/assets/yumrepo/repodata/4ac40fa3c6728c1401318e2e20a997436624e83dcf7a5f952b851ef422637773-filelists.sqlite.bz2
new file mode 100644
index 0000000000..2df608aa34
--- /dev/null
+++ b/spec/functional/assets/yumrepo/repodata/4ac40fa3c6728c1401318e2e20a997436624e83dcf7a5f952b851ef422637773-filelists.sqlite.bz2
Binary files differ
diff --git a/spec/functional/assets/yumrepo/repodata/66391e53f0510b98b3f0b79f40ba1048026d9a1ef20905d9c40ba6f5411f3243-primary.xml.gz b/spec/functional/assets/yumrepo/repodata/66391e53f0510b98b3f0b79f40ba1048026d9a1ef20905d9c40ba6f5411f3243-primary.xml.gz
new file mode 100644
index 0000000000..d9b7cb879a
--- /dev/null
+++ b/spec/functional/assets/yumrepo/repodata/66391e53f0510b98b3f0b79f40ba1048026d9a1ef20905d9c40ba6f5411f3243-primary.xml.gz
Binary files differ
diff --git a/spec/functional/assets/yumrepo/repodata/8b34697595fcc87928e12d24644dda9462c3857bd932861e28bc77ae1f31be16-filelists.xml.gz b/spec/functional/assets/yumrepo/repodata/8b34697595fcc87928e12d24644dda9462c3857bd932861e28bc77ae1f31be16-filelists.xml.gz
new file mode 100644
index 0000000000..35a973d170
--- /dev/null
+++ b/spec/functional/assets/yumrepo/repodata/8b34697595fcc87928e12d24644dda9462c3857bd932861e28bc77ae1f31be16-filelists.xml.gz
Binary files differ
diff --git a/spec/functional/assets/yumrepo/repodata/b97cca3fe14bcf06c52be4449b6108f7731239ff221111dcce8aada5467f60dc-other.sqlite.bz2 b/spec/functional/assets/yumrepo/repodata/b97cca3fe14bcf06c52be4449b6108f7731239ff221111dcce8aada5467f60dc-other.sqlite.bz2
new file mode 100644
index 0000000000..e682fc0f0b
--- /dev/null
+++ b/spec/functional/assets/yumrepo/repodata/b97cca3fe14bcf06c52be4449b6108f7731239ff221111dcce8aada5467f60dc-other.sqlite.bz2
Binary files differ
diff --git a/spec/functional/assets/yumrepo/repodata/repomd.xml b/spec/functional/assets/yumrepo/repodata/repomd.xml
new file mode 100644
index 0000000000..92937e151a
--- /dev/null
+++ b/spec/functional/assets/yumrepo/repodata/repomd.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1479418959</revision>
+<data type="filelists">
+ <checksum type="sha256">8b34697595fcc87928e12d24644dda9462c3857bd932861e28bc77ae1f31be16</checksum>
+ <open-checksum type="sha256">9f5be999b4a535c19afc53703851577e1a325227fab651189c5c39708b9a1e38</open-checksum>
+ <location href="repodata/8b34697595fcc87928e12d24644dda9462c3857bd932861e28bc77ae1f31be16-filelists.xml.gz"/>
+ <timestamp>1479418959</timestamp>
+ <size>419</size>
+ <open-size>1127</open-size>
+</data>
+<data type="primary">
+ <checksum type="sha256">66391e53f0510b98b3f0b79f40ba1048026d9a1ef20905d9c40ba6f5411f3243</checksum>
+ <open-checksum type="sha256">dc25cfbf4520861130e0ba203d27cc40b183fbb7c576aac33d838fb20a68aa32</open-checksum>
+ <location href="repodata/66391e53f0510b98b3f0b79f40ba1048026d9a1ef20905d9c40ba6f5411f3243-primary.xml.gz"/>
+ <timestamp>1479418959</timestamp>
+ <size>859</size>
+ <open-size>4529</open-size>
+</data>
+<data type="primary_db">
+ <checksum type="sha256">313329137b55fd333b2dc66394a6661a2befa6cc535d8460d92a4a78a9c581f0</checksum>
+ <open-checksum type="sha256">720b637c782cce8604b922e9989ecfff9091e26163d643bd1b676778beb1c933</open-checksum>
+ <location href="repodata/313329137b55fd333b2dc66394a6661a2befa6cc535d8460d92a4a78a9c581f0-primary.sqlite.bz2"/>
+ <timestamp>1479418959</timestamp>
+ <database_version>10</database_version>
+ <size>2460</size>
+ <open-size>32768</open-size>
+</data>
+<data type="other_db">
+ <checksum type="sha256">b97cca3fe14bcf06c52be4449b6108f7731239ff221111dcce8aada5467f60dc</checksum>
+ <open-checksum type="sha256">938156bcfc95828cb6857e1b2790dceaef57196843a80464ba5749772fc15e83</open-checksum>
+ <location href="repodata/b97cca3fe14bcf06c52be4449b6108f7731239ff221111dcce8aada5467f60dc-other.sqlite.bz2"/>
+ <timestamp>1479418959</timestamp>
+ <database_version>10</database_version>
+ <size>967</size>
+ <open-size>6144</open-size>
+</data>
+<data type="other">
+ <checksum type="sha256">31ac4db5d5ac593728fcc26aef82b7b93c4cc4dbec843786b1845b939b658553</checksum>
+ <open-checksum type="sha256">2ea64cdb2f5ba3859af29fe67a85d61d5b4de23f3da1ee71d5af175d8d887ab6</open-checksum>
+ <location href="repodata/31ac4db5d5ac593728fcc26aef82b7b93c4cc4dbec843786b1845b939b658553-other.xml.gz"/>
+ <timestamp>1479418959</timestamp>
+ <size>413</size>
+ <open-size>1035</open-size>
+</data>
+<data type="filelists_db">
+ <checksum type="sha256">4ac40fa3c6728c1401318e2e20a997436624e83dcf7a5f952b851ef422637773</checksum>
+ <open-checksum type="sha256">8bc15efa19d02a5112e20c6ed1be17c5851287ddfba17aee2283ddb216dd08d7</open-checksum>
+ <location href="repodata/4ac40fa3c6728c1401318e2e20a997436624e83dcf7a5f952b851ef422637773-filelists.sqlite.bz2"/>
+ <timestamp>1479418959</timestamp>
+ <database_version>10</database_version>
+ <size>1131</size>
+ <open-size>7168</open-size>
+</data>
+</repomd>
diff --git a/spec/functional/audit/rspec_formatter_spec.rb b/spec/functional/audit/rspec_formatter_spec.rb
index 009374db68..209694ae70 100644
--- a/spec/functional/audit/rspec_formatter_spec.rb
+++ b/spec/functional/audit/rspec_formatter_spec.rb
@@ -1,8 +1,8 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
-# Author:: Claire McQuin (<claire@getchef.com>)
+# Author:: Claire McQuin (<claire@chef.io>)
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,12 +18,12 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'rspec/core/sandbox'
-require 'chef/audit/runner'
-require 'rspec/support/spec/in_sub_process'
-require 'rspec/support/spec/stderr_splitter'
-require 'chef/audit/rspec_formatter'
+require "spec_helper"
+require "rspec/core/sandbox"
+require "chef/audit/runner"
+require "rspec/support/spec/in_sub_process"
+require "rspec/support/spec/stderr_splitter"
+require "chef/audit/rspec_formatter"
describe Chef::Audit::RspecFormatter do
include RSpec::Support::InSubProcess
diff --git a/spec/functional/audit/runner_spec.rb b/spec/functional/audit/runner_spec.rb
index aae8fcf582..54f014e28f 100644
--- a/spec/functional/audit/runner_spec.rb
+++ b/spec/functional/audit/runner_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'rspec/core/sandbox'
-require 'chef/audit/runner'
-require 'rspec/support/spec/in_sub_process'
-require 'rspec/support/spec/stderr_splitter'
-require 'tempfile'
+require "spec_helper"
+require "rspec/core/sandbox"
+require "chef/audit/runner"
+require "rspec/support/spec/in_sub_process"
+require "rspec/support/spec/stderr_splitter"
+require "tempfile"
##
# This functional test ensures that our runner can be setup to not interfere with existing RSpec
@@ -52,6 +52,10 @@ describe Chef::Audit::Runner do
let(:run_context) { instance_double(Chef::RunContext, :events => events, :audits => audits) }
let(:control_group_name) { "control_group_name" }
+ # Set cookbook path to include our parent, so that it will recognize this
+ # rspec file as one that should show up in the backtrace.
+ before(:each) { Chef::Config[:cookbook_path] = File.dirname(__FILE__) }
+
shared_context "passing audit" do
let(:audits) do
should_pass = lambda do
@@ -59,7 +63,7 @@ describe Chef::Audit::Runner do
expect(2 - 2).to eq(0)
end
end
- { control_group_name => Struct.new(:args, :block).new([control_group_name], should_pass)}
+ { control_group_name => Struct.new(:args, :block).new([control_group_name], should_pass) }
end
end
@@ -70,7 +74,7 @@ describe Chef::Audit::Runner do
expect(2 - 1).to eq(0)
end
end
- { control_group_name => Struct.new(:args, :block).new([control_group_name], should_fail)}
+ { control_group_name => Struct.new(:args, :block).new([control_group_name], should_fail) }
end
end
diff --git a/spec/functional/dsl/reboot_pending_spec.rb b/spec/functional/dsl/reboot_pending_spec.rb
index 1d11f38dbc..c7a93c6822 100644
--- a/spec/functional/dsl/reboot_pending_spec.rb
+++ b/spec/functional/dsl/reboot_pending_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,17 +22,12 @@ require "spec_helper"
describe Chef::DSL::RebootPending, :windows_only do
def run_ohai
- ohai = Ohai::System.new
- # Would be nice to limit this to platform/kernel/arch etc for Ohai 7
- ohai.all_plugins
- node.consume_external_attrs(ohai.data,{})
-
- ohai
+ node.consume_external_attrs(OHAI_SYSTEM.data, {})
end
let(:node) { Chef::Node.new }
- let(:events) { Chef::EventDispatch::Dispatcher.new }
let!(:ohai) { run_ohai } # Ensure we have necessary node data
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
let(:run_context) { Chef::RunContext.new(node, {}, events) }
let(:recipe) { Chef::Recipe.new("a windows cookbook", "the windows recipe", run_context) }
let(:registry) { Chef::Win32::Registry.new(run_context) }
@@ -47,19 +42,19 @@ describe Chef::DSL::RebootPending, :windows_only do
describe 'HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations' do
let(:reg_key) { 'HKLM\SYSTEM\CurrentControlSet\Control\Session Manager' }
- let(:original_set) { registry.value_exists?(reg_key, { :name => 'PendingFileRenameOperations' }) }
+ let(:original_set) { registry.value_exists?(reg_key, { :name => "PendingFileRenameOperations" }) }
it "returns true if the registry value exists" do
- skip 'found existing registry key' if original_set
+ skip "found existing registry key" if original_set
registry.set_value(reg_key,
- { :name => 'PendingFileRenameOperations', :type => :multi_string, :data => ['\??\C:\foo.txt|\??\C:\bar.txt'] })
+ { :name => "PendingFileRenameOperations", :type => :multi_string, :data => ['\??\C:\foo.txt|\??\C:\bar.txt'] })
expect(recipe.reboot_pending?).to be_truthy
end
after do
unless original_set
- registry.delete_value(reg_key, { :name => 'PendingFileRenameOperations' })
+ registry.delete_value(reg_key, { :name => "PendingFileRenameOperations" })
end
end
end
@@ -69,7 +64,7 @@ describe Chef::DSL::RebootPending, :windows_only do
let(:original_set) { registry.key_exists?(reg_key) }
it "returns true if the registry key exists" do
- skip 'found existing registry key' if original_set
+ skip "found existing registry key" if original_set
pending "Permissions are limited to 'TrustedInstaller' by default"
registry.create_key(reg_key, false)
@@ -88,7 +83,7 @@ describe Chef::DSL::RebootPending, :windows_only do
let(:original_set) { registry.key_exists?(reg_key) }
it "returns true if the registry key exists" do
- skip 'found existing registry key' if original_set
+ skip "found existing registry key" if original_set
registry.create_key(reg_key, false)
expect(recipe.reboot_pending?).to be_truthy
@@ -103,7 +98,7 @@ describe Chef::DSL::RebootPending, :windows_only do
describe "when there is nothing to indicate a reboot is pending" do
it "should return false" do
- skip 'reboot pending' if @any_flag.any? { |_,v| v == true }
+ skip "reboot pending" if @any_flag.any? { |_, v| v == true }
expect(recipe.reboot_pending?).to be_falsey
end
end
diff --git a/spec/functional/dsl/registry_helper_spec.rb b/spec/functional/dsl/registry_helper_spec.rb
index df5b09f1f6..d90d5090e4 100644
--- a/spec/functional/dsl/registry_helper_spec.rb
+++ b/spec/functional/dsl/registry_helper_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Prajakta Purohit (<prajakta@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,15 +25,13 @@ describe Chef::Resource::RegistryKey, :windows_only do
::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root"
::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch"
::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root', Win32::Registry::KEY_ALL_ACCESS) do |reg|
- reg['RootType1', Win32::Registry::REG_SZ] = 'fibrous'
- reg.write('Roots', Win32::Registry::REG_MULTI_SZ, ["strong roots", "healthy tree"])
+ reg["RootType1", Win32::Registry::REG_SZ] = "fibrous"
+ reg.write("Roots", Win32::Registry::REG_MULTI_SZ, ["strong roots", "healthy tree"])
end
events = Chef::EventDispatch::Dispatcher.new
node = Chef::Node.new
- ohai = Ohai::System.new
- ohai.all_plugins
- node.consume_external_attrs(ohai.data,{})
+ node.consume_external_attrs(OHAI_SYSTEM.data, {})
run_context = Chef::RunContext.new(node, {}, events)
@resource = Chef::Resource.new("foo", run_context)
end
@@ -44,7 +42,7 @@ describe Chef::Resource::RegistryKey, :windows_only do
end
it "returns true if registry has specified value" do
values = @resource.registry_get_values("HKCU\\Software\\Root")
- expect(values.include?({:name=>"RootType1",:type=>:string,:data=>"fibrous"})).to eq(true)
+ expect(values.include?({ :name => "RootType1", :type => :string, :data => "fibrous" })).to eq(true)
end
it "returns true if specified registry_has_subkey" do
expect(@resource.registry_has_subkeys?("HKCU\\Software\\Root")).to eq(true)
@@ -54,10 +52,10 @@ describe Chef::Resource::RegistryKey, :windows_only do
expect(subkeys.include?("Branch")).to eq(true)
end
it "returns true if registry_value_exists" do
- expect(@resource.registry_value_exists?("HKCU\\Software\\Root", {:name=>"RootType1", :type=>:string, :data=>"fibrous"})).to eq(true)
+ expect(@resource.registry_value_exists?("HKCU\\Software\\Root", { :name => "RootType1", :type => :string, :data => "fibrous" })).to eq(true)
end
it "returns true if data_value_exists" do
- expect(@resource.registry_data_exists?("HKCU\\Software\\Root", {:name=>"RootType1", :type=>:string, :data=>"fibrous"})).to eq(true)
+ expect(@resource.registry_data_exists?("HKCU\\Software\\Root", { :name => "RootType1", :type => :string, :data => "fibrous" })).to eq(true)
end
end
end
diff --git a/spec/functional/event_loggers/windows_eventlog_spec.rb b/spec/functional/event_loggers/windows_eventlog_spec.rb
index 0723e7b984..019595ea8d 100644
--- a/spec/functional/event_loggers/windows_eventlog_spec.rb
+++ b/spec/functional/event_loggers/windows_eventlog_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Jay Mundrawala (<jdm@getchef.com>)
+# Author:: Jay Mundrawala (<jdm@chef.io>)
#
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,60 +16,68 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'securerandom'
-require 'chef/event_loggers/windows_eventlog'
-if Chef::Platform.windows? and not Chef::Platform::windows_server_2003?
- require 'win32/eventlog'
+require "spec_helper"
+require "securerandom"
+require "chef/event_loggers/windows_eventlog"
+if Chef::Platform.windows? && (not Chef::Platform.windows_server_2003?)
+ require "win32/eventlog"
include Win32
end
describe Chef::EventLoggers::WindowsEventLogger, :windows_only, :not_supported_on_win2k3 do
- let(:run_id) { SecureRandom.uuid }
- let(:version) { SecureRandom.uuid }
- let(:elapsed_time) { SecureRandom.random_number(100) }
+ def rand
+ random.rand(1 << 32).to_s
+ end
+
+ let(:random) { Random.new }
+ let(:run_id) { rand }
+ let(:version) { rand }
+ let(:elapsed_time) { rand }
let(:logger) { Chef::EventLoggers::WindowsEventLogger.new }
let(:flags) { nil }
let(:node) { nil }
- let(:run_status) { double('Run Status', {run_id: run_id, elapsed_time: elapsed_time }) }
+ let(:run_status) { double("Run Status", { run_id: run_id, elapsed_time: elapsed_time }) }
let(:event_log) { EventLog.new("Application") }
let!(:offset) { event_log.read_last_event.record_number }
- let(:mock_exception) { double('Exception', {message: SecureRandom.uuid, backtrace:[SecureRandom.uuid, SecureRandom.uuid]})}
+ let(:mock_exception) { double("Exception", { message: rand, backtrace: [rand, rand] }) }
- it 'is available' do
+ it "is available" do
expect(Chef::EventLoggers::WindowsEventLogger.available?).to be_truthy
end
- it 'writes run_start event with event_id 10000 and contains version' do
+ it "writes run_start event with event_id 10000 and contains version" do
logger.run_start(version)
- expect(event_log.read(flags, offset).any? { |e| e.source == 'Chef' && e.event_id == 10000 &&
- e.string_inserts[0].include?(version)}).to be_truthy
+ expect(event_log.read(flags, offset).any? do |e|
+ e.source == "Chef" && e.event_id == 10000 &&
+ e.string_inserts[0].include?(version) end).to be_truthy
end
- it 'writes run_started event with event_id 10001 and contains the run_id' do
+ it "writes run_started event with event_id 10001 and contains the run_id" do
logger.run_started(run_status)
- expect(event_log.read(flags, offset).any? { |e| e.source == 'Chef' && e.event_id == 10001 &&
- e.string_inserts[0].include?(run_id)}).to be_truthy
+ expect(event_log.read(flags, offset).any? do |e|
+ e.source == "Chef" && e.event_id == 10001 &&
+ e.string_inserts[0].include?(run_id) end).to be_truthy
end
- it 'writes run_completed event with event_id 10002 and contains the run_id and elapsed time' do
+ it "writes run_completed event with event_id 10002 and contains the run_id and elapsed time" do
logger.run_started(run_status)
logger.run_completed(node)
- expect(event_log.read(flags, offset).any? { |e| e.source == 'Chef' && e.event_id == 10002 &&
- e.string_inserts[0].include?(run_id) &&
- e.string_inserts[1].include?(elapsed_time.to_s)
- }).to be_truthy
+ expect(event_log.read(flags, offset).any? do |e|
+ e.source == "Chef" && e.event_id == 10002 &&
+ e.string_inserts[0].include?(run_id) &&
+ e.string_inserts[1].include?(elapsed_time.to_s)
+ end).to be_truthy
end
- it 'writes run_failed event with event_id 10003 and contains the run_id, elapsed time, and exception info' do
+ it "writes run_failed event with event_id 10003 and contains the run_id, elapsed time, and exception info" do
logger.run_started(run_status)
logger.run_failed(mock_exception)
expect(event_log.read(flags, offset).any? do |e|
- e.source == 'Chef' && e.event_id == 10003 &&
+ e.source == "Chef" && e.event_id == 10003 &&
e.string_inserts[0].include?(run_id) &&
e.string_inserts[1].include?(elapsed_time.to_s) &&
e.string_inserts[2].include?(mock_exception.class.name) &&
@@ -79,11 +87,11 @@ describe Chef::EventLoggers::WindowsEventLogger, :windows_only, :not_supported_o
end).to be_truthy
end
- it 'writes run_failed event with event_id 10003 even when run_status is not set' do
+ it "writes run_failed event with event_id 10003 even when run_status is not set" do
logger.run_failed(mock_exception)
expect(event_log.read(flags, offset).any? do |e|
- e.source == 'Chef' && e.event_id == 10003 &&
+ e.source == "Chef" && e.event_id == 10003 &&
e.string_inserts[0].include?("UNKNOWN") &&
e.string_inserts[1].include?("UNKNOWN") &&
e.string_inserts[2].include?(mock_exception.class.name) &&
diff --git a/spec/functional/file_content_management/deploy_strategies_spec.rb b/spec/functional/file_content_management/deploy_strategies_spec.rb
index 8a995d0e41..9e2131388f 100644
--- a/spec/functional/file_content_management/deploy_strategies_spec.rb
+++ b/spec/functional/file_content_management/deploy_strategies_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
shared_examples_for "a content deploy strategy" do
@@ -38,7 +38,6 @@ shared_examples_for "a content deploy strategy" do
let(:content_deployer) { described_class.new }
let(:target_file_path) { File.join(sandbox_dir, "cp-deploy-strategy-target-file.txt") }
-
describe "creating the file" do
##
@@ -69,7 +68,7 @@ shared_examples_for "a content deploy strategy" do
def ace_inherits?(ace)
flags = ace.flags
- (flags & masks::OBJECT_INHERIT_ACE) !=0
+ (flags & masks::OBJECT_INHERIT_ACE) != 0
end
let(:parent_inheritable_aces) do
@@ -126,7 +125,7 @@ shared_examples_for "a content deploy strategy" do
security_descriptor_invariants.inject({}) do |prop_map, property|
prop_map[property] = descriptor.send(property)
prop_map
- end
+ end
end
before do
@@ -180,7 +179,7 @@ describe Chef::FileContentManagement::Deploy::Cp do
:uid,
:gid,
:mode,
- :ino
+ :ino,
]
end
@@ -188,7 +187,7 @@ describe Chef::FileContentManagement::Deploy::Cp do
[
:owner,
:group,
- :dacl
+ :dacl,
]
end
@@ -202,7 +201,7 @@ describe Chef::FileContentManagement::Deploy::MvUnix, :unix_only do
[
:uid,
:gid,
- :mode
+ :mode,
]
end
@@ -210,7 +209,7 @@ describe Chef::FileContentManagement::Deploy::MvUnix, :unix_only do
end
# On Unix we won't have loaded the file, avoid undefined constant errors:
-class Chef::FileContentManagement::Deploy::MvWindows ; end
+class Chef::FileContentManagement::Deploy::MvWindows; end
describe Chef::FileContentManagement::Deploy::MvWindows, :windows_only do
@@ -220,7 +219,7 @@ describe Chef::FileContentManagement::Deploy::MvWindows, :windows_only do
[
:owner,
:group,
- :dacl
+ :dacl,
]
end
diff --git a/spec/functional/http/simple_spec.rb b/spec/functional/http/simple_spec.rb
index 36468b4eba..421045693a 100644
--- a/spec/functional/http/simple_spec.rb
+++ b/spec/functional/http/simple_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tiny_server'
-require 'support/shared/functional/http'
+require "spec_helper"
+require "tiny_server"
+require "support/shared/functional/http"
describe Chef::HTTP::Simple do
include ChefHTTPShared
@@ -26,11 +26,11 @@ describe Chef::HTTP::Simple do
let(:http_client) { described_class.new(source) }
let(:http_client_disable_gzip) { described_class.new(source, { :disable_gzip => true } ) }
- before(:all) do
+ before(:each) do
start_tiny_server
end
- after(:all) do
+ after(:each) do
stop_tiny_server
end
@@ -84,14 +84,14 @@ describe Chef::HTTP::Simple do
context "when Chef::Log.level = :debug" do
before do
Chef::Log.level = :debug
- @debug_log = ''
+ @debug_log = ""
allow(Chef::Log).to receive(:debug) { |str| @debug_log << str }
end
- let(:source) { 'http://localhost:9000' }
+ let(:source) { "http://localhost:9000" }
it "Logs the request and response for 200's but not the body" do
- http_client.get('http://localhost:9000/nyan_cat.png')
+ http_client.get("http://localhost:9000/nyan_cat.png")
expect(@debug_log).to match(/200/)
expect(@debug_log).to match(/HTTP Request Header Data/)
expect(@debug_log).to match(/HTTP Status and Header Data/)
@@ -101,7 +101,7 @@ describe Chef::HTTP::Simple do
end
it "Logs the request and response for 200 POST, but not the body" do
- http_client.post('http://localhost:9000/posty', 'hithere')
+ http_client.post("http://localhost:9000/posty", "hithere")
expect(@debug_log).to match(/200/)
expect(@debug_log).to match(/HTTP Request Header Data/)
expect(@debug_log).to match(/HTTP Status and Header Data/)
@@ -113,7 +113,7 @@ describe Chef::HTTP::Simple do
it "Logs the request and response and bodies for 400 response" do
expect do
- http_client.get('http://localhost:9000/bad_request')
+ http_client.get("http://localhost:9000/bad_request")
end.to raise_error(Net::HTTPServerException)
expect(@debug_log).to match(/400/)
expect(@debug_log).to match(/HTTP Request Header Data/)
@@ -126,7 +126,7 @@ describe Chef::HTTP::Simple do
it "Logs the request and response and bodies for 400 POST response" do
expect do
- http_client.post('http://localhost:9000/bad_request', 'hithere')
+ http_client.post("http://localhost:9000/bad_request", "hithere")
end.to raise_error(Net::HTTPServerException)
expect(@debug_log).to match(/400/)
expect(@debug_log).to match(/HTTP Request Header Data/)
diff --git a/spec/functional/knife/configure_spec.rb b/spec/functional/knife/configure_spec.rb
index 3bef18a0aa..f1da2d660e 100644
--- a/spec/functional/knife/configure_spec.rb
+++ b/spec/functional/knife/configure_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,23 +16,18 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/knife/configure'
-require 'ohai'
+require "chef/knife/configure"
describe "knife configure" do
let (:ohai) do
- o = Ohai::System.new
- o.load_plugins
- o.require_plugin 'os'
- o.require_plugin 'hostname'
- o
+ OHAI_SYSTEM
end
it "loads the fqdn from Ohai" do
knife_configure = Chef::Knife::Configure.new
- hostname_guess = ohai[:fqdn] || ohai[:machinename] || ohai[:hostname] || 'localhost'
+ hostname_guess = ohai[:fqdn] || ohai[:machinename] || ohai[:hostname] || "localhost"
expect(knife_configure.guess_servername).to eql(hostname_guess)
end
end
diff --git a/spec/functional/knife/cookbook_delete_spec.rb b/spec/functional/knife/cookbook_delete_spec.rb
index bffad8cbed..7438ef9841 100644
--- a/spec/functional/knife/cookbook_delete_spec.rb
+++ b/spec/functional/knife/cookbook_delete_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,90 +16,79 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tiny_server'
+require "spec_helper"
+require "tiny_server"
describe Chef::Knife::CookbookDelete do
- before(:all) do
- @server = TinyServer::Manager.new
- @server.start
+ let(:server) { TinyServer::Manager.new }
+ let(:api) { TinyServer::API.instance }
+ let(:knife_stdout) { StringIO.new }
+ let(:knife_stderr) { StringIO.new }
+ let(:knife) do
+ knife = Chef::Knife::CookbookDelete.new
+ allow(knife.ui).to receive(:stdout).and_return(knife_stdout)
+ allow(knife.ui).to receive(:stderr).and_return(knife_stderr)
+ knife
end
before(:each) do
- @knife = Chef::Knife::CookbookDelete.new
- @api = TinyServer::API.instance
- @api.clear
+ server.start
+ api.clear
Chef::Config[:node_name] = nil
Chef::Config[:client_key] = nil
- Chef::Config[:chef_server_url] = 'http://localhost:9000'
+ Chef::Config[:chef_server_url] = "http://localhost:9000"
end
- after(:all) do
- @server.stop
+ after(:each) do
+ server.stop
end
context "when the cookbook doesn't exist" do
- let(:log_output) { StringIO.new }
-
before do
- @knife.name_args = %w{no-such-cookbook}
- @api.get("/cookbooks/no-such-cookbook", 404, Chef::JSONCompat.to_json({'error'=>'dear Tim, no. -Sent from my iPad'}))
- end
-
- around do |ex|
- old_logger = Chef::Log.logger
- old_level = Chef::Log.level
- begin
- Chef::Log.logger = Logger.new(log_output)
- Chef::Log.level = :debug
- ex.run
- ensure
- Chef::Log.logger = old_logger
- Chef::Log.level = old_level
- end
+ knife.name_args = %w{no-such-cookbook}
+ api.get("/cookbooks/no-such-cookbook", 404, Chef::JSONCompat.to_json({ "error" => "dear Tim, no. -Sent from my iPad" }))
end
it "logs an error and exits" do
- allow(@knife.ui).to receive(:stderr).and_return(log_output)
- expect {@knife.run}.to raise_error(SystemExit)
- expect(log_output.string).to match(/Cannot find a cookbook named no-such-cookbook to delete/)
+ expect { knife.run }.to raise_error(SystemExit)
+ expect(knife_stderr.string).to match(/Cannot find a cookbook named no-such-cookbook to delete/)
end
end
context "when there is only one version of a cookbook" do
before do
- @knife.name_args = %w{obsolete-cookbook}
- @cookbook_list = {'obsolete-cookbook' => { 'versions' => ['version' => '1.0.0']} }
- @api.get("/cookbooks/obsolete-cookbook", 200, Chef::JSONCompat.to_json(@cookbook_list))
+ knife.name_args = %w{obsolete-cookbook}
+ @cookbook_list = { "obsolete-cookbook" => { "versions" => ["version" => "1.0.0"] } }
+ api.get("/cookbooks/obsolete-cookbook", 200, Chef::JSONCompat.to_json(@cookbook_list))
end
it "asks for confirmation, then deletes the cookbook" do
stdin, stdout = StringIO.new("y\n"), StringIO.new
- allow(@knife.ui).to receive(:stdin).and_return(stdin)
- allow(@knife.ui).to receive(:stdout).and_return(stdout)
+ allow(knife.ui).to receive(:stdin).and_return(stdin)
+ allow(knife.ui).to receive(:stdout).and_return(stdout)
cb100_deleted = false
- @api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" }
+ api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" }
- @knife.run
+ knife.run
expect(stdout.string).to match(/#{Regexp.escape('Do you really want to delete obsolete-cookbook version 1.0.0? (Y/N)')}/)
expect(cb100_deleted).to be_truthy
end
it "asks for confirmation before purging" do
- @knife.config[:purge] = true
+ knife.config[:purge] = true
stdin, stdout = StringIO.new("y\ny\n"), StringIO.new
- allow(@knife.ui).to receive(:stdin).and_return(stdin)
- allow(@knife.ui).to receive(:stdout).and_return(stdout)
+ allow(knife.ui).to receive(:stdin).and_return(stdin)
+ allow(knife.ui).to receive(:stdout).and_return(stdout)
cb100_deleted = false
- @api.delete("/cookbooks/obsolete-cookbook/1.0.0?purge=true", 200) { cb100_deleted = true; "[\"true\"]" }
+ api.delete("/cookbooks/obsolete-cookbook/1.0.0?purge=true", 200) { cb100_deleted = true; "[\"true\"]" }
- @knife.run
+ knife.run
expect(stdout.string).to match(/#{Regexp.escape('Are you sure you want to purge files')}/)
expect(stdout.string).to match(/#{Regexp.escape('Do you really want to delete obsolete-cookbook version 1.0.0? (Y/N)')}/)
@@ -111,21 +100,21 @@ describe Chef::Knife::CookbookDelete do
context "when there are several versions of a cookbook" do
before do
- @knife.name_args = %w{obsolete-cookbook}
- versions = ['1.0.0', '1.1.0', '1.2.0']
- with_version = lambda { |version| { 'version' => version } }
- @cookbook_list = {'obsolete-cookbook' => { 'versions' => versions.map(&with_version) } }
- @api.get("/cookbooks/obsolete-cookbook", 200, Chef::JSONCompat.to_json(@cookbook_list))
+ knife.name_args = %w{obsolete-cookbook}
+ versions = ["1.0.0", "1.1.0", "1.2.0"]
+ with_version = lambda { |version| { "version" => version } }
+ @cookbook_list = { "obsolete-cookbook" => { "versions" => versions.map(&with_version) } }
+ api.get("/cookbooks/obsolete-cookbook", 200, Chef::JSONCompat.to_json(@cookbook_list))
end
it "deletes all versions of a cookbook when given the '-a' flag" do
- @knife.config[:all] = true
- @knife.config[:yes] = true
+ knife.config[:all] = true
+ knife.config[:yes] = true
cb100_deleted = cb110_deleted = cb120_deleted = nil
- @api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" }
- @api.delete("/cookbooks/obsolete-cookbook/1.1.0", 200) { cb110_deleted = true; "[\"true\"]" }
- @api.delete("/cookbooks/obsolete-cookbook/1.2.0", 200) { cb120_deleted = true; "[\"true\"]" }
- @knife.run
+ api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" }
+ api.delete("/cookbooks/obsolete-cookbook/1.1.0", 200) { cb110_deleted = true; "[\"true\"]" }
+ api.delete("/cookbooks/obsolete-cookbook/1.2.0", 200) { cb120_deleted = true; "[\"true\"]" }
+ knife.run
expect(cb100_deleted).to be_truthy
expect(cb110_deleted).to be_truthy
@@ -134,28 +123,28 @@ describe Chef::Knife::CookbookDelete do
it "asks which version to delete and deletes that when not given the -a flag" do
cb100_deleted = cb110_deleted = cb120_deleted = nil
- @api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" }
+ api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" }
stdin, stdout = StringIO.new, StringIO.new
- allow(@knife.ui).to receive(:stdin).and_return(stdin)
- allow(@knife.ui).to receive(:stdout).and_return(stdout)
+ allow(knife.ui).to receive(:stdin).and_return(stdin)
+ allow(knife.ui).to receive(:stdout).and_return(stdout)
stdin << "1\n"
stdin.rewind
- @knife.run
+ knife.run
expect(cb100_deleted).to be_truthy
expect(stdout.string).to match(/Which version\(s\) do you want to delete\?/)
end
it "deletes all versions of the cookbook when not given the -a flag and the user chooses to delete all" do
cb100_deleted = cb110_deleted = cb120_deleted = nil
- @api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" }
- @api.delete("/cookbooks/obsolete-cookbook/1.1.0", 200) { cb110_deleted = true; "[\"true\"]" }
- @api.delete("/cookbooks/obsolete-cookbook/1.2.0", 200) { cb120_deleted = true; "[\"true\"]" }
+ api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" }
+ api.delete("/cookbooks/obsolete-cookbook/1.1.0", 200) { cb110_deleted = true; "[\"true\"]" }
+ api.delete("/cookbooks/obsolete-cookbook/1.2.0", 200) { cb120_deleted = true; "[\"true\"]" }
stdin, stdout = StringIO.new("4\n"), StringIO.new
- allow(@knife.ui).to receive(:stdin).and_return(stdin)
- allow(@knife.ui).to receive(:stdout).and_return(stdout)
+ allow(knife.ui).to receive(:stdin).and_return(stdin)
+ allow(knife.ui).to receive(:stdout).and_return(stdout)
- @knife.run
+ knife.run
expect(cb100_deleted).to be_truthy
expect(cb110_deleted).to be_truthy
diff --git a/spec/functional/knife/exec_spec.rb b/spec/functional/knife/exec_spec.rb
index 6262094a9f..ac8f617a90 100644
--- a/spec/functional/knife/exec_spec.rb
+++ b/spec/functional/knife/exec_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,19 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tiny_server'
+require "spec_helper"
+require "tiny_server"
describe Chef::Knife::Exec do
- before(:all) do
- @server = TinyServer::Manager.new#(:debug => true)
+ before(:each) do
+ @server = TinyServer::Manager.new #(:debug => true)
@server.start
end
+ after(:each) do
+ @server.stop
+ end
+
before(:each) do
@knife = Chef::Knife::Exec.new
@api = TinyServer::API.instance
@@ -32,19 +36,15 @@ describe Chef::Knife::Exec do
Chef::Config[:node_name] = nil
Chef::Config[:client_key] = nil
- Chef::Config[:chef_server_url] = 'http://localhost:9000'
+ Chef::Config[:chef_server_url] = "http://localhost:9000"
$output = StringIO.new
end
- after(:all) do
- @server.stop
- end
-
it "executes a script in the context of the chef-shell main context" do
@node = Chef::Node.new
@node.name("ohai-world")
- response = {"rows" => [@node],"start" => 0,"total" => 1}
+ response = { "rows" => [@node], "start" => 0, "total" => 1 }
@api.get(%r{^/search/node}, 200, Chef::JSONCompat.to_json(response))
code = "$output.puts nodes.all"
@knife.config[:exec] = code
diff --git a/spec/functional/knife/rehash_spec.rb b/spec/functional/knife/rehash_spec.rb
new file mode 100644
index 0000000000..22ffa125fa
--- /dev/null
+++ b/spec/functional/knife/rehash_spec.rb
@@ -0,0 +1,39 @@
+#
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+require "chef/knife/rehash"
+require "chef/knife/core/subcommand_loader"
+
+describe "knife rehash" do
+ before do
+ allow(Chef::Knife::SubcommandLoader).to receive(:load_commands)
+ end
+
+ after do
+ # We need to clean up the generated manifest or else is messes with later tests
+ FileUtils.rm_f(Chef::Knife::SubcommandLoader.plugin_manifest_path)
+ end
+
+ it "writes the loaded plugins to disc" do
+ knife_rehash = Chef::Knife::Rehash.new
+ knife_rehash.run
+ expect(File.read(Chef::Knife::SubcommandLoader.plugin_manifest_path)).to match(/node_list.rb/)
+ end
+end
diff --git a/spec/functional/knife/smoke_test.rb b/spec/functional/knife/smoke_test.rb
index 607e8065cf..350644d177 100644
--- a/spec/functional/knife/smoke_test.rb
+++ b/spec/functional/knife/smoke_test.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe "knife smoke tests" do
@@ -31,4 +31,12 @@ describe "knife smoke tests" do
knife_cmd.error!
expect(knife_cmd.stdout).to include(Chef::VERSION)
end
+
+ it "can run and show help" do
+ knife_path = File.expand_path("../../bin/knife", CHEF_SPEC_DATA)
+ knife_cmd = Mixlib::ShellOut.new("#{knife_path} --help")
+ knife_cmd.run_command
+ knife_cmd.error!
+ expect(knife_cmd.stdout).to include("Usage")
+ end
end
diff --git a/spec/functional/knife/ssh_spec.rb b/spec/functional/knife/ssh_spec.rb
index 51524b7009..aea7585bb2 100644
--- a/spec/functional/knife/ssh_spec.rb
+++ b/spec/functional/knife/ssh_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,18 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tiny_server'
+require "spec_helper"
+require "tiny_server"
describe Chef::Knife::Ssh do
- before(:all) do
+ before(:each) do
Chef::Knife::Ssh.load_deps
@server = TinyServer::Manager.new
@server.start
end
- after(:all) do
+ after(:each) do
@server.stop
end
@@ -50,55 +50,55 @@ describe Chef::Knife::Ssh do
describe "identity file" do
context "when knife[:ssh_identity_file] is set" do
before do
- setup_knife(['*:*', 'uptime'])
+ setup_knife(["*:*", "uptime"])
Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/aws.rsa"
end
it "uses the ssh_identity_file" do
@knife.run
- expect(@knife.config[:identity_file]).to eq("~/.ssh/aws.rsa")
+ expect(@knife.config[:ssh_identity_file]).to eq("~/.ssh/aws.rsa")
end
end
context "when knife[:ssh_identity_file] is set and frozen" do
before do
- setup_knife(['*:*', 'uptime'])
+ setup_knife(["*:*", "uptime"])
Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/aws.rsa".freeze
end
it "uses the ssh_identity_file" do
@knife.run
- expect(@knife.config[:identity_file]).to eq("~/.ssh/aws.rsa")
+ expect(@knife.config[:ssh_identity_file]).to eq("~/.ssh/aws.rsa")
end
end
context "when -i is provided" do
before do
- setup_knife(['-i ~/.ssh/aws.rsa', '*:*', 'uptime'])
+ setup_knife(["-i ~/.ssh/aws.rsa", "*:*", "uptime"])
Chef::Config[:knife][:ssh_identity_file] = nil
end
it "should use the value on the command line" do
@knife.run
- expect(@knife.config[:identity_file]).to eq("~/.ssh/aws.rsa")
+ expect(@knife.config[:ssh_identity_file]).to eq("~/.ssh/aws.rsa")
end
it "should override what is set in knife.rb" do
Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/other.rsa"
@knife.run
- expect(@knife.config[:identity_file]).to eq("~/.ssh/aws.rsa")
+ expect(@knife.config[:ssh_identity_file]).to eq("~/.ssh/aws.rsa")
end
end
context "when knife[:ssh_identity_file] is not provided]" do
before do
- setup_knife(['*:*', 'uptime'])
+ setup_knife(["*:*", "uptime"])
Chef::Config[:knife][:ssh_identity_file] = nil
end
it "uses the default" do
@knife.run
- expect(@knife.config[:identity_file]).to eq(nil)
+ expect(@knife.config[:ssh_identity_file]).to eq(nil)
end
end
end
@@ -106,7 +106,7 @@ describe Chef::Knife::Ssh do
describe "port" do
context "when -p 31337 is provided" do
before do
- setup_knife(['-p 31337', '*:*', 'uptime'])
+ setup_knife(["-p 31337", "*:*", "uptime"])
end
it "uses the ssh_port" do
@@ -119,7 +119,7 @@ describe Chef::Knife::Ssh do
describe "user" do
context "when knife[:ssh_user] is set" do
before do
- setup_knife(['*:*', 'uptime'])
+ setup_knife(["*:*", "uptime"])
Chef::Config[:knife][:ssh_user] = "ubuntu"
end
@@ -131,7 +131,7 @@ describe Chef::Knife::Ssh do
context "when knife[:ssh_user] is set and frozen" do
before do
- setup_knife(['*:*', 'uptime'])
+ setup_knife(["*:*", "uptime"])
Chef::Config[:knife][:ssh_user] = "ubuntu".freeze
end
@@ -143,7 +143,7 @@ describe Chef::Knife::Ssh do
context "when -x is provided" do
before do
- setup_knife(['-x ubuntu', '*:*', 'uptime'])
+ setup_knife(["-x ubuntu", "*:*", "uptime"])
Chef::Config[:knife][:ssh_user] = nil
end
@@ -161,7 +161,7 @@ describe Chef::Knife::Ssh do
context "when knife[:ssh_user] is not provided]" do
before do
- setup_knife(['*:*', 'uptime'])
+ setup_knife(["*:*", "uptime"])
Chef::Config[:knife][:ssh_user] = nil
end
@@ -175,31 +175,31 @@ describe Chef::Knife::Ssh do
describe "attribute" do
context "when knife[:ssh_attribute] is set" do
before do
- setup_knife(['*:*', 'uptime'])
+ setup_knife(["*:*", "uptime"])
Chef::Config[:knife][:ssh_attribute] = "ec2.public_hostname"
end
it "uses the ssh_attribute" do
@knife.run
- expect(@knife.get_ssh_attribute(Chef::Node.new)).to eq("ec2.public_hostname")
+ expect(@knife.get_ssh_attribute({ "knife_config" => "ec2.public_hostname" })).to eq("ec2.public_hostname")
end
end
context "when knife[:ssh_attribute] is not provided]" do
before do
- setup_knife(['*:*', 'uptime'])
+ setup_knife(["*:*", "uptime"])
Chef::Config[:knife][:ssh_attribute] = nil
end
it "uses the default" do
@knife.run
- expect(@knife.get_ssh_attribute(Chef::Node.new)).to eq("fqdn")
+ expect(@knife.get_ssh_attribute({ "fqdn" => "fqdn" })).to eq("fqdn")
end
end
- context "when -a ec2.public_ipv4 is provided" do
+ context "when -a ec2.public_public_hostname is provided" do
before do
- setup_knife(['-a ec2.public_hostname', '*:*', 'uptime'])
+ setup_knife(["-a ec2.public_hostname", "*:*", "uptime"])
Chef::Config[:knife][:ssh_attribute] = nil
end
@@ -212,7 +212,7 @@ describe Chef::Knife::Ssh do
# This is the setting imported from knife.rb
Chef::Config[:knife][:ssh_attribute] = "fqdn"
# Then we run knife with the -a flag, which sets the above variable
- setup_knife(['-a ec2.public_hostname', '*:*', 'uptime'])
+ setup_knife(["-a ec2.public_hostname", "*:*", "uptime"])
@knife.run
expect(@knife.config[:attribute]).to eq("ec2.public_hostname")
end
@@ -222,7 +222,7 @@ describe Chef::Knife::Ssh do
describe "gateway" do
context "when knife[:ssh_gateway] is set" do
before do
- setup_knife(['*:*', 'uptime'])
+ setup_knife(["*:*", "uptime"])
Chef::Config[:knife][:ssh_gateway] = "user@ec2.public_hostname"
end
@@ -235,7 +235,7 @@ describe Chef::Knife::Ssh do
context "when -G user@ec2.public_hostname is provided" do
before do
- setup_knife(['-G user@ec2.public_hostname', '*:*', 'uptime'])
+ setup_knife(["-G user@ec2.public_hostname", "*:*", "uptime"])
Chef::Config[:knife][:ssh_gateway] = nil
end
@@ -248,7 +248,7 @@ describe Chef::Knife::Ssh do
context "when the gateway requires a password" do
before do
- setup_knife(['-G user@ec2.public_hostname', '*:*', 'uptime'])
+ setup_knife(["-G user@ec2.public_hostname", "*:*", "uptime"])
Chef::Config[:knife][:ssh_gateway] = nil
allow(@knife.session).to receive(:via) do |host, user, options|
raise Net::SSH::AuthenticationFailed unless options[:password]
@@ -262,7 +262,7 @@ describe Chef::Knife::Ssh do
end
end
- def setup_knife(params=[])
+ def setup_knife(params = [])
@knife = Chef::Knife::Ssh.new(params)
# We explicitly avoid running #configure_chef, which would read a knife.rb
# if available, but #merge_configs (which is called by #configure_chef) is
@@ -274,11 +274,11 @@ describe Chef::Knife::Ssh do
Chef::Config[:node_name] = nil
Chef::Config[:client_key] = nil
- Chef::Config[:chef_server_url] = 'http://localhost:9000'
+ Chef::Config[:chef_server_url] = "http://localhost:9000"
- @api.get("/search/node?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0", 200) {
- %({"total":1, "start":0, "rows":[{"name":"i-xxxxxxxx", "json_class":"Chef::Node", "automatic":{"fqdn":"the.fqdn", "ec2":{"public_hostname":"the_public_hostname"}},"recipes":[]}]})
- }
+ @api.post("/search/node?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0", 200) do
+ %({"total":1, "start":0, "rows":[{"data": {"fqdn":"the.fqdn", "config": "the_public_hostname", "knife_config": "the_public_hostname" }}]})
+ end
end
end
diff --git a/spec/functional/mixin/powershell_out_spec.rb b/spec/functional/mixin/powershell_out_spec.rb
index 9cc8aeed7e..66214cb0c7 100644
--- a/spec/functional/mixin/powershell_out_spec.rb
+++ b/spec/functional/mixin/powershell_out_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,15 +15,15 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/powershell_out'
+require "spec_helper"
+require "chef/mixin/powershell_out"
describe Chef::Mixin::PowershellOut, windows_only: true do
include Chef::Mixin::PowershellOut
describe "#powershell_out" do
it "runs a powershell command and collects stdout" do
- expect(powershell_out("get-process").run_command.stdout).to match /Handles\s+NPM\(K\)\s+PM\(K\)\s+WS\(K\)\s+VM\(M\)\s+CPU\(s\)\s+Id\s+ProcessName/
+ expect(powershell_out("get-process").run_command.stdout).to match /Handles\s+NPM\(K\)\s+PM\(K\)\s+WS\(K\)\s+VM\(M\)\s+CPU\(s\)\s+Id\s+/
end
it "does not raise exceptions when the command is invalid" do
@@ -33,7 +33,7 @@ describe Chef::Mixin::PowershellOut, windows_only: true do
describe "#powershell_out!" do
it "runs a powershell command and collects stdout" do
- expect(powershell_out!("get-process").run_command.stdout).to match /Handles\s+NPM\(K\)\s+PM\(K\)\s+WS\(K\)\s+VM\(M\)\s+CPU\(s\)\s+Id\s+ProcessName/
+ expect(powershell_out!("get-process").run_command.stdout).to match /Handles\s+NPM\(K\)\s+PM\(K\)\s+WS\(K\)\s+VM\(M\)\s+CPU\(s\)\s+Id\s+/
end
it "raises exceptions when the command is invalid" do
diff --git a/spec/functional/mixin/shell_out_spec.rb b/spec/functional/mixin/shell_out_spec.rb
index 35e5b30eae..48f6b7d912 100644
--- a/spec/functional/mixin/shell_out_spec.rb
+++ b/spec/functional/mixin/shell_out_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Mixin::ShellOut do
include Chef::Mixin::ShellOut
@@ -24,24 +24,24 @@ describe Chef::Mixin::ShellOut do
describe "when environment['LC_ALL'] is not set" do
it "should use the default shell_out setting" do
cmd = if windows?
- shell_out_with_systems_locale('echo %LC_ALL%')
- else
- shell_out_with_systems_locale('echo $LC_ALL')
- end
+ shell_out_with_systems_locale("echo %LC_ALL%")
+ else
+ shell_out_with_systems_locale("echo $LC_ALL")
+ end
- expect(cmd.stdout.chomp).to match_environment_variable('LC_ALL')
+ expect(cmd.stdout.chomp).to match_environment_variable("LC_ALL")
end
end
describe "when environment['LC_ALL'] is set" do
it "should use the option's setting" do
cmd = if windows?
- shell_out_with_systems_locale('echo %LC_ALL%', :environment => {'LC_ALL' => 'POSIX'})
- else
- shell_out_with_systems_locale('echo $LC_ALL', :environment => {'LC_ALL' => 'POSIX'})
- end
+ shell_out_with_systems_locale("echo %LC_ALL%", :environment => { "LC_ALL" => "POSIX" })
+ else
+ shell_out_with_systems_locale("echo $LC_ALL", :environment => { "LC_ALL" => "POSIX" })
+ end
- expect(cmd.stdout.chomp).to eq 'POSIX'
+ expect(cmd.stdout.chomp).to eq "POSIX"
end
end
end
diff --git a/spec/functional/notifications_spec.rb b/spec/functional/notifications_spec.rb
index a02fdffe5e..8d8b2d970c 100644
--- a/spec/functional/notifications_spec.rb
+++ b/spec/functional/notifications_spec.rb
@@ -1,6 +1,5 @@
-require 'spec_helper'
-require 'chef/recipe'
-
+require "spec_helper"
+require "chef/recipe"
# The goal of these tests is to make sure that loading resources from a file creates the necessary notifications.
# Then once converge has started, both immediate and delayed notifications are called as the resources are converged.
@@ -14,11 +13,11 @@ describe "Notifications" do
# We always pretend we are on OSx because that has a specific provider (HomebrewProvider) so it
# tests the translation from Provider => HomebrewProvider
- let(:node) {
+ let(:node) do
n = Chef::Node.new
n.override[:os] = "darwin"
n
- }
+ end
let(:cookbook_collection) { double("Chef::CookbookCollection").as_null_object }
let(:events) { double("Chef::EventDispatch::Dispatcher").as_null_object }
let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) }
@@ -74,6 +73,76 @@ describe "Notifications" do
runner.converge
end
+ it "should notify from one resource to another before" do
+ log_resource = recipe.declare_resource(:log, "log") do
+ message "This is a log message"
+ action :write
+ notifies :install, "package[vim]", :before
+ end
+ update_action(log_resource, 2)
+
+ package_resource = recipe.declare_resource(:package, "vim") do
+ action :nothing
+ end
+
+ actions = []
+ [ log_resource, package_resource ].each do |resource|
+ allow(resource).to receive(:run_action).and_wrap_original do |m, action, notification_type, notifying_resource|
+ actions << { resource: resource.to_s, action: action }
+ actions[-1][:why_run] = Chef::Config[:why_run] if Chef::Config[:why_run]
+ actions[-1][:notification_type] = notification_type if notification_type
+ actions[-1][:notifying_resource] = notifying_resource.to_s if notifying_resource
+ m.call(action, notification_type, notifying_resource)
+ end
+ end
+
+ runner.converge
+
+ expect(actions).to eq [
+ # First it runs why-run to check if the resource would update
+ { resource: log_resource.to_s, action: :write, why_run: true },
+ # Then it runs the before action
+ { resource: package_resource.to_s, action: :install, notification_type: :before, notifying_resource: log_resource.to_s },
+ # Then it runs the actual action
+ { resource: log_resource.to_s, action: :write },
+ { resource: package_resource.to_s, action: :nothing },
+ ]
+ end
+
+ it "should not notify from one resource to another before if the resource is not updated" do
+ log_resource = recipe.declare_resource(:log, "log") do
+ message "This is a log message"
+ action :write
+ notifies :install, "package[vim]", :before
+ end
+
+ package_resource = recipe.declare_resource(:package, "vim") do
+ action :nothing
+ end
+
+ actions = []
+ [ log_resource, package_resource ].each do |resource|
+ allow(resource).to receive(:run_action).and_wrap_original do |m, action, notification_type, notifying_resource|
+ actions << { resource: resource.to_s, action: action }
+ actions[-1][:why_run] = Chef::Config[:why_run] if Chef::Config[:why_run]
+ actions[-1][:notification_type] = notification_type if notification_type
+ actions[-1][:notifying_resource] = notifying_resource.to_s if notifying_resource
+ m.call(action, notification_type, notifying_resource)
+ end
+ end
+
+ runner.converge
+
+ expect(actions).to eq [
+ # First it runs why-run to check if the resource would update
+ { resource: log_resource.to_s, action: :write, why_run: true },
+ # Then it does NOT run the before action
+ # Then it runs the actual action
+ { resource: log_resource.to_s, action: :write },
+ { resource: package_resource.to_s, action: :nothing },
+ ]
+ end
+
it "should notify from one resource to another delayed" do
log_resource = recipe.declare_resource(:log, "log") do
message "This is a log message"
@@ -94,7 +163,7 @@ describe "Notifications" do
runner.converge
end
-
+
describe "when one resource is defined lazily" do
it "subscribes to a resource defined in a ruby block" do
@@ -158,10 +227,10 @@ describe "Notifications" do
end
# Mocks having the provider run successfully and update the resource
- def update_action(resource)
+ def update_action(resource, times = 1)
p = Chef::Provider.new(resource, run_context)
- expect(resource).to receive(:provider_for_action).and_return(p)
- expect(p).to receive(:run_action) {
+ expect(resource).to receive(:provider_for_action).exactly(times).times.and_return(p)
+ expect(p).to receive(:run_action).exactly(times).times {
resource.updated_by_last_action(true)
}
end
diff --git a/spec/functional/provider/remote_file/cache_control_data_spec.rb b/spec/functional/provider/remote_file/cache_control_data_spec.rb
index 41f228ae3c..c56787e7e5 100755
--- a/spec/functional/provider/remote_file/cache_control_data_spec.rb
+++ b/spec/functional/provider/remote_file/cache_control_data_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,19 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'uri'
+require "spec_helper"
+require "uri"
describe Chef::Provider::RemoteFile::CacheControlData do
before do
- @original_config = Chef::Config.hash_dup
+ @original_config = Chef::Config.hash_dup
end
after do
- Chef::Config.configuration = @original_config if @original_config
+ Chef::Config.configuration = @original_config if @original_config
end
-
+
before(:each) do
Chef::Config[:file_cache_path] = Dir.mktmpdir
end
@@ -38,7 +38,7 @@ describe Chef::Provider::RemoteFile::CacheControlData do
end
let(:uri) { URI.parse("http://www.bing.com/robots.txt") }
-
+
describe "when the cache control data save method is invoked" do
subject(:cache_control_data) do
@@ -66,7 +66,7 @@ describe Chef::Provider::RemoteFile::CacheControlData do
saved_cache_control_data = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum)
expect(saved_cache_control_data.etag).to eq(cache_control_data.etag)
expect(saved_cache_control_data.mtime).to eq(cache_control_data.mtime)
- expect(saved_cache_control_data.checksum).to eq(cache_control_data.checksum)
+ expect(saved_cache_control_data.checksum).to eq(cache_control_data.checksum)
end
# Cover the very long remote file path case -- see CHEF-4422 where
@@ -75,7 +75,7 @@ describe Chef::Provider::RemoteFile::CacheControlData do
# file system API's on both Windows and Unix systems.
context "when the length of the uri exceeds the path length limits for the local file system" do
let(:uri_exceeds_file_system_limit) do
- URI.parse("http://www.bing.com/" + ('0' * 1024))
+ URI.parse("http://www.bing.com/" + ("0" * 1024))
end
let(:uri) { uri_exceeds_file_system_limit }
@@ -91,11 +91,10 @@ describe Chef::Provider::RemoteFile::CacheControlData do
saved_cache_control_data = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum)
expect(saved_cache_control_data.etag).to eq(cache_control_data.etag)
expect(saved_cache_control_data.mtime).to eq(cache_control_data.mtime)
- expect(saved_cache_control_data.checksum).to eq(cache_control_data.checksum)
+ expect(saved_cache_control_data.checksum).to eq(cache_control_data.checksum)
end
end
end
end
-
diff --git a/spec/functional/provider/whyrun_safe_ruby_block_spec.rb b/spec/functional/provider/whyrun_safe_ruby_block_spec.rb
index 2b582feb05..1bb36f2cf6 100644
--- a/spec/functional/provider/whyrun_safe_ruby_block_spec.rb
+++ b/spec/functional/provider/whyrun_safe_ruby_block_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::WhyrunSafeRubyBlock do
let(:node) { Chef::Node.new }
- let(:run_context) {
+ let(:run_context) do
events = Chef::EventDispatch::Dispatcher.new
Chef::RunContext.new(node, {}, events)
- }
+ end
before do
$evil_global_evil_laugh = :wahwah
@@ -43,7 +43,7 @@ describe Chef::Resource::WhyrunSafeRubyBlock do
end
it "updates the evil laugh, even in why-run mode" do
- Array(new_resource.action).each {|action| new_resource.run_action(action) }
+ Array(new_resource.action).each { |action| new_resource.run_action(action) }
expect($evil_global_evil_laugh).to eq(:mwahahaha)
expect(new_resource).to be_updated
end
diff --git a/spec/functional/rebooter_spec.rb b/spec/functional/rebooter_spec.rb
index a0e2665de5..1b6e95b39c 100644
--- a/spec/functional/rebooter_spec.rb
+++ b/spec/functional/rebooter_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Chris Doherty <cdoherty@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef, Inc.
+# Author:: Chris Doherty <cdoherty@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Platform::Rebooter do
@@ -24,7 +24,7 @@ describe Chef::Platform::Rebooter do
{
:delay_mins => 5,
:requested_by => "reboot resource functional test",
- :reason => "rebooter spec test"
+ :reason => "rebooter spec test",
}
end
@@ -43,22 +43,22 @@ describe Chef::Platform::Rebooter do
let(:expected) do
{
- :windows => 'shutdown /r /t 300 /c "rebooter spec test"',
- :linux => 'shutdown -r +5 "rebooter spec test"'
+ :windows => "#{ENV['SYSTEMROOT']}/System32/shutdown.exe /r /t 300 /c \"rebooter spec test\"",
+ :linux => 'shutdown -r +5 "rebooter spec test"',
}
end
let(:rebooter) { Chef::Platform::Rebooter }
- describe '#reboot_if_needed!' do
+ describe "#reboot_if_needed!" do
- it 'should not call #shell_out! when reboot has not been requested' do
+ it "should not call #shell_out! when reboot has not been requested" do
expect(rebooter).to receive(:shell_out!).exactly(0).times
expect(rebooter).to receive(:reboot_if_needed!).once.and_call_original
rebooter.reboot_if_needed!(run_context.node)
end
- describe 'calling #shell_out! to reboot' do
+ describe "calling #shell_out! to reboot" do
before(:each) do
run_context.request_reboot(reboot_info)
@@ -68,7 +68,7 @@ describe Chef::Platform::Rebooter do
run_context.cancel_reboot
end
- shared_context 'test a reboot method' do
+ shared_context "test a reboot method" do
def test_rebooter_method(method_sym, is_windows, expected_reboot_str)
allow(ChefConfig).to receive(:windows?).and_return(is_windows)
expect(rebooter).to receive(:shell_out!).once.with(expected_reboot_str)
@@ -77,26 +77,26 @@ describe Chef::Platform::Rebooter do
end
end
- describe 'when using #reboot_if_needed!' do
- include_context 'test a reboot method'
+ describe "when using #reboot_if_needed!" do
+ include_context "test a reboot method"
- it 'should produce the correct string on Windows' do
+ it "should produce the correct string on Windows", :windows_only do
test_rebooter_method(:reboot_if_needed!, true, expected[:windows])
end
- it 'should produce the correct (Linux-specific) string on non-Windows' do
+ it "should produce the correct (Linux-specific) string on non-Windows" do
test_rebooter_method(:reboot_if_needed!, false, expected[:linux])
end
end
- describe 'when using #reboot!' do
- include_context 'test a reboot method'
+ describe "when using #reboot!" do
+ include_context "test a reboot method"
- it 'should produce the correct string on Windows' do
+ it "should produce the correct string on Windows", :windows_only do
test_rebooter_method(:reboot!, true, expected[:windows])
end
- it 'should produce the correct (Linux-specific) string on non-Windows' do
+ it "should produce the correct (Linux-specific) string on non-Windows" do
test_rebooter_method(:reboot!, false, expected[:linux])
end
end
diff --git a/spec/functional/resource/aix_service_spec.rb b/spec/functional/resource/aix_service_spec.rb
index 9dec87db93..5fff3e00d7 100755
--- a/spec/functional/resource/aix_service_spec.rb
+++ b/spec/functional/resource/aix_service_spec.rb
@@ -1,7 +1,7 @@
# encoding: UTF-8
#
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,24 +17,24 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
shared_examples "src service" do
include Chef::Mixin::ShellOut
def service_should_be_started
- expect(shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(' ').last).to eq("active")
+ expect(shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(" ").last).to eq("active")
end
def service_should_be_stopped
- expect(shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(' ').last).to eq("inoperative")
+ expect(shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(" ").last).to eq("inoperative")
end
def get_service_pid
- args = shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(' ')
+ args = shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(" ")
if args.length == 3
args[1]
else
@@ -94,7 +94,6 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
shell_out!("rmssys -s ctestsys")
end
-
let(:new_resource) do
new_resource = Chef::Resource::Service.new("ctestsys", run_context)
new_resource
@@ -108,8 +107,8 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
it_behaves_like "src service"
end
-
- describe "When service is a group" do
+ # Cannot run this test on a WPAR
+ describe "When service is a group", :not_wpar do
before(:all) do
script_dir = File.join(File.dirname(__FILE__), "/../assets/")
shell_out!("mkssys -s ctestsys -p #{script_dir}/testchefsubsys -u #{get_user_id} -S -n 15 -f 9 -R -Q -G ctestgrp")
diff --git a/spec/functional/resource/aixinit_service_spec.rb b/spec/functional/resource/aixinit_service_spec.rb
index 3d9216158e..bf50046b03 100755
--- a/spec/functional/resource/aixinit_service_spec.rb
+++ b/spec/functional/resource/aixinit_service_spec.rb
@@ -1,7 +1,7 @@
# encoding: UTF-8
#
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
-require 'fileutils'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
+require "fileutils"
describe Chef::Resource::Service, :requires_root, :aix_only do
@@ -29,17 +29,17 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
# Platform specific validation routines.
def service_should_be_started(file_name)
# The existence of this file indicates that the service was started.
- expect(File.exists?("/tmp/#{file_name}")).to be_truthy
+ expect(File.exists?("#{Dir.tmpdir}/#{file_name}")).to be_truthy
end
def service_should_be_stopped(file_name)
- expect(File.exists?("/tmp/#{file_name}")).to be_falsey
+ expect(File.exists?("#{Dir.tmpdir}/#{file_name}")).to be_falsey
end
def valide_symlinks(expected_output, run_level = nil, status = nil, priority = nil)
directory = []
- if priority.is_a?Hash
- priority.each do |level,o|
+ if priority.is_a? Hash
+ priority.each do |level, o|
directory << "/etc/rc.d/rc#{level}.d/#{(o[0] == :start ? 'S' : 'K')}#{o[1]}#{new_resource.service_name}"
end
directory
@@ -51,7 +51,7 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
end
def delete_test_files
- files = Dir.glob("/tmp/chefinit[a-z_]*.txt")
+ files = Dir.glob("#{Dir.tmpdir}/chefinit[a-z_]*.txt")
File.delete(*files)
end
@@ -59,7 +59,7 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
let(:new_resource) do
new_resource = Chef::Resource::Service.new("chefinittest", run_context)
new_resource.provider Chef::Provider::Service::AixInit
- new_resource.supports({:status => true, :restart => true, :reload => true})
+ new_resource.supports({ :status => true, :restart => true, :reload => true })
new_resource
end
@@ -70,7 +70,7 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
before(:all) do
File.delete("/etc/rc.d/init.d/chefinittest") if File.exists?("/etc/rc.d/init.d/chefinittest")
- FileUtils.cp("#{File.join(File.dirname(__FILE__), "/../assets/chefinittest")}", "/etc/rc.d/init.d/chefinittest")
+ FileUtils.cp("#{File.join(File.dirname(__FILE__), "/../assets/chefinittest")}", "/etc/rc.d/init.d/chefinittest")
end
after(:all) do
@@ -130,7 +130,7 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
context "when the service doesn't set a priority" do
it "creates symlink with status S" do
new_resource.run_action(:enable)
- valide_symlinks(["/etc/rc.d/rc2.d/Schefinittest"],2,'S')
+ valide_symlinks(["/etc/rc.d/rc2.d/Schefinittest"], 2, "S")
end
end
@@ -141,19 +141,19 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
it "creates a symlink with status S and a priority" do
new_resource.run_action(:enable)
- valide_symlinks(["/etc/rc.d/rc2.d/S75chefinittest"], 2,'S',75)
+ valide_symlinks(["/etc/rc.d/rc2.d/S75chefinittest"], 2, "S", 75)
end
end
context "when the service sets complex priorities (hash)" do
before do
- priority = {2 => [:start, 20], 3 => [:stop, 10]}
+ priority = { 2 => [:start, 20], 3 => [:stop, 10] }
new_resource.priority(priority)
end
it "create symlink with status start (S) or stop (K) and a priority " do
new_resource.run_action(:enable)
- valide_symlinks(["/etc/rc.d/rc2.d/S20chefinittest", "/etc/rc.d/rc3.d/K10chefinittest"], 2,'S',new_resource.priority)
+ valide_symlinks(["/etc/rc.d/rc2.d/S20chefinittest", "/etc/rc.d/rc3.d/K10chefinittest"], 2, "S", new_resource.priority)
end
end
end
@@ -171,7 +171,7 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
it "creates symlink with status K" do
new_resource.run_action(:disable)
- valide_symlinks(["/etc/rc.d/rc2.d/Kchefinittest"], 2,'K')
+ valide_symlinks(["/etc/rc.d/rc2.d/Kchefinittest"], 2, "K")
end
end
@@ -187,13 +187,13 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
it "creates a symlink with status K and a priority" do
new_resource.run_action(:disable)
- valide_symlinks(["/etc/rc.d/rc2.d/K25chefinittest"], 2,'K',25)
+ valide_symlinks(["/etc/rc.d/rc2.d/K25chefinittest"], 2, "K", 25)
end
end
context "when the service sets complex priorities (hash)" do
before do
- @priority = {2 => [:stop, 20], 3 => [:start, 10]}
+ @priority = { 2 => [:stop, 20], 3 => [:start, 10] }
new_resource.priority(@priority)
File.symlink("/etc/rc.d/init.d/chefinittest", "/etc/rc.d/rc2.d/Schefinittest")
end
@@ -204,7 +204,7 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
it "create symlink with status stop (K) and a priority " do
new_resource.run_action(:disable)
- valide_symlinks(["/etc/rc.d/rc2.d/K80chefinittest"], 2,'K',80)
+ valide_symlinks(["/etc/rc.d/rc2.d/K80chefinittest"], 2, "K", 80)
end
end
end
diff --git a/spec/functional/resource/base.rb b/spec/functional/resource/base.rb
index 10b26f924f..38175e81c0 100644
--- a/spec/functional/resource/base.rb
+++ b/spec/functional/resource/base.rb
@@ -1,6 +1,6 @@
#
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,6 @@
# limitations under the License.
#
-
def run_context
@run_context ||= begin
node = Chef::Node.new
@@ -27,4 +26,3 @@ def run_context
Chef::RunContext.new(node, {}, events)
end
end
-
diff --git a/spec/functional/resource/bash_spec.rb b/spec/functional/resource/bash_spec.rb
index 209ec4a12f..a2e174d557 100644
--- a/spec/functional/resource/bash_spec.rb
+++ b/spec/functional/resource/bash_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,24 +16,24 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'functional/resource/base'
+require "spec_helper"
+require "functional/resource/base"
describe Chef::Resource::Bash, :unix_only do
let(:code) { "echo hello" }
- let(:resource) {
+ let(:resource) do
resource = Chef::Resource::Bash.new("foo_resource", run_context)
resource.code(code)
resource
- }
+ end
describe "when setting the command attribute" do
- let (:command) { 'wizard racket' }
+ let (:command) { "wizard racket" }
# in Chef-12 the `command` attribute is largely useless, but does set the identity attribute
# so that notifications need to target the value of the command. it will not run the `command`
# and if it is given without a code block then it does nothing and always succeeds.
- describe "in Chef-12", :chef_lt_13_only do
+ describe "in Chef-12", chef: "< 13" do
it "gets the commmand attribute from the name" do
expect(resource.command).to eql("foo_resource")
end
@@ -61,7 +61,7 @@ describe Chef::Resource::Bash, :unix_only do
end
# in Chef-13 the `command` attribute needs to be for internal use only
- describe "in Chef-13", :chef_gte_13_only do
+ describe "in Chef-13", chef: ">= 13" do
it "should raise an exception when trying to set the command" do
expect { resource.command command }.to raise_error # FIXME: add a real error in Chef-13
end
@@ -81,7 +81,7 @@ describe Chef::Resource::Bash, :unix_only do
end
it "times out when a timeout is set on the resource" do
- resource.code 'sleep 600'
+ resource.code "sleep 600"
resource.timeout 0.1
expect { resource.run_action(:run) }.to raise_error(Mixlib::ShellOut::CommandTimeout)
end
diff --git a/spec/functional/resource/batch_spec.rb b/spec/functional/resource/batch_spec.rb
index 39133fd40b..2b176ed06c 100644
--- a/spec/functional/resource/batch_spec.rb
+++ b/spec/functional/resource/batch_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,18 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::WindowsScript::Batch, :windows_only do
include_context Chef::Resource::WindowsScript
- let(:output_command) { ' > ' }
+ let(:output_command) { " > " }
- let (:architecture_command) { '@echo %PROCESSOR_ARCHITECTURE%' }
+ let(:architecture_command) { "@echo %PROCESSOR_ARCHITECTURE%" }
+
+ let(:resource) do
+ Chef::Resource::WindowsScript::Batch.new("Batch resource functional test", @run_context)
+ end
it_behaves_like "a Windows script running on Windows"
diff --git a/spec/functional/resource/bff_spec.rb b/spec/functional/resource/bff_spec.rb
index b969254b6b..e7f7540e5a 100644
--- a/spec/functional/resource/bff_spec.rb
+++ b/spec/functional/resource/bff_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Prabhu Das (<prabhu.das@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "functional/resource/base"
+require "chef/mixin/shell_out"
# Run the test only for AIX platform.
-describe Chef::Resource::BffPackage, :requires_root, :external => ohai[:platform] != 'aix' do
+describe Chef::Resource::BffPackage, :requires_root, :external => ohai[:platform] != "aix" do
include Chef::Mixin::ShellOut
let(:new_resource) do
@@ -39,11 +39,10 @@ describe Chef::Resource::BffPackage, :requires_root, :external => ohai[:platform
!::File.exists?("/usr/PkgA/bin/acommand")
end
-
before(:all) do
@pkg_name = "PkgA.rte"
- @pkg_path = "/tmp/PkgA.1.0.0.0.bff"
- FileUtils.cp 'spec/functional/assets/PkgA.1.0.0.0.bff' , @pkg_path
+ @pkg_path = "#{Dir.tmpdir}/PkgA.1.0.0.0.bff"
+ FileUtils.cp "spec/functional/assets/PkgA.1.0.0.0.bff" , @pkg_path
end
after(:all) do
@@ -70,15 +69,15 @@ describe Chef::Resource::BffPackage, :requires_root, :external => ohai[:platform
after(:each) do
shell_out("installp -u #{@pkg_name}")
- FileUtils.rm "/tmp/installp.log"
+ FileUtils.rm "#{Dir.tmpdir}/installp.log"
end
end
context "package upgrade action" do
before(:each) do
shell_out("installp -aYF -d #{@pkg_path} #{@pkg_name}")
- @pkg_path = "/tmp/PkgA.2.0.0.0.bff"
- FileUtils.cp 'spec/functional/assets/PkgA.2.0.0.0.bff' , @pkg_path
+ @pkg_path = "#{Dir.tmpdir}/PkgA.2.0.0.0.bff"
+ FileUtils.cp "spec/functional/assets/PkgA.2.0.0.0.bff" , @pkg_path
end
it "should upgrade package" do
@@ -115,8 +114,7 @@ describe Chef::Resource::BffPackage, :requires_root, :external => ohai[:platform
end
after(:each) do
- FileUtils.rm "/tmp/installp.log"
+ FileUtils.rm "#{Dir.tmpdir}/installp.log"
end
end
end
-
diff --git a/spec/functional/resource/chocolatey_package_spec.rb b/spec/functional/resource/chocolatey_package_spec.rb
new file mode 100644
index 0000000000..7bb6698daf
--- /dev/null
+++ b/spec/functional/resource/chocolatey_package_spec.rb
@@ -0,0 +1,125 @@
+#
+# Author:: Matt Wrock (<matt@mattwrock.com>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+require "spec_helper"
+require "chef/mixin/powershell_out"
+
+describe Chef::Resource::ChocolateyPackage, :windows_only do
+ include Chef::Mixin::PowershellOut
+
+ before(:all) do
+ powershell_out!("iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))")
+ unless ENV["PATH"] =~ /chocolatey\\bin/
+ ENV["PATH"] = "C:\\ProgramData\\chocolatey\\bin;#{ENV["PATH"]}"
+ end
+ end
+
+ let(:package_name) { "test-A" }
+ let(:package_list) { proc { powershell_out!("choco list -lo -r #{Array(package_name).join(' ')}").stdout.chomp } }
+ let(:package_source) { File.join(CHEF_SPEC_ASSETS, "chocolatey_feed") }
+
+ subject do
+ new_resource = Chef::Resource::ChocolateyPackage.new("test choco package", run_context)
+ new_resource.package_name package_name
+ new_resource.source package_source
+ new_resource
+ end
+
+ context "installing a package" do
+ after { remove_package }
+
+ it "installs the latest version" do
+ subject.run_action(:install)
+ expect(package_list.call).to eq("#{package_name}|2.0")
+ end
+
+ it "does not install if already installed" do
+ subject.run_action(:install)
+ subject.run_action(:install)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "installs version given" do
+ subject.version "1.0"
+ subject.run_action(:install)
+ expect(package_list.call).to eq("#{package_name}|1.0")
+ end
+
+ it "installs new version if one is already installed" do
+ subject.version "1.0"
+ subject.run_action(:install)
+ expect(package_list.call).to eq("#{package_name}|1.0")
+
+ subject.version "2.0"
+ subject.run_action(:install)
+ expect(package_list.call).to eq("#{package_name}|2.0")
+ end
+
+ context "installing multiple packages" do
+ let(:package_name) { [ "test-A", "test-B" ] }
+
+ it "installs both packages" do
+ subject.run_action(:install)
+ expect(package_list.call).to eq("test-A|2.0\r\ntest-B|1.0")
+ end
+ end
+
+ it "raises if package is not found" do
+ subject.package_name "blah"
+ expect { subject.run_action(:install) }.to raise_error Chef::Exceptions::Package
+ end
+ end
+
+ context "upgrading a package" do
+ after { remove_package }
+
+ it "upgrades to a specific version" do
+ subject.version "1.0"
+ subject.run_action(:install)
+ expect(package_list.call).to eq("#{package_name}|1.0")
+
+ subject.version "1.5"
+ subject.run_action(:upgrade)
+ expect(package_list.call).to eq("#{package_name}|1.5")
+ end
+
+ it "upgrades to the latest version if no version given" do
+ subject.version "1.0"
+ subject.run_action(:install)
+ expect(package_list.call).to eq("#{package_name}|1.0")
+
+ subject2 = Chef::Resource::ChocolateyPackage.new("test-A", run_context)
+ subject2.source package_source
+ subject2.run_action(:upgrade)
+ expect(package_list.call).to eq("#{package_name}|2.0")
+ end
+ end
+
+ context "removing a package" do
+ it "removes an installed package" do
+ subject.run_action(:install)
+ remove_package
+ expect(package_list.call).to eq("")
+ end
+ end
+
+ def remove_package
+ pkg_to_remove = Chef::Resource::ChocolateyPackage.new(package_name, run_context)
+ pkg_to_remove.source = package_source
+ pkg_to_remove.run_action(:remove)
+ end
+end
diff --git a/spec/functional/resource/cookbook_file_spec.rb b/spec/functional/resource/cookbook_file_spec.rb
index 6d4c5b4a8f..d127413c73 100644
--- a/spec/functional/resource/cookbook_file_spec.rb
+++ b/spec/functional/resource/cookbook_file_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::CookbookFile do
include_context Chef::Resource::File
- let(:file_base) { 'cookbook_file_spec' }
- let(:source) { 'java.response' }
- let(:cookbook_name) { 'java' }
+ let(:file_base) { "cookbook_file_spec" }
+ let(:source) { "java.response" }
+ let(:cookbook_name) { "java" }
let(:expected_content) do
- content = File.open(File.join(CHEF_SPEC_DATA, 'cookbooks', 'java', 'files', 'default', 'java.response'), "rb") do |f|
+ content = File.open(File.join(CHEF_SPEC_DATA, "cookbooks", "java", "files", "default", "java.response"), "rb") do |f|
f.read
end
content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding)
@@ -39,7 +39,7 @@ describe Chef::Resource::CookbookFile do
def create_resource
# set up cookbook collection for this run to use, based on our
# spec data.
- cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, 'cookbooks'))
+ cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
loader = Chef::CookbookLoader.new(cookbook_repo)
loader.load_cookbooks
@@ -66,11 +66,11 @@ describe Chef::Resource::CookbookFile do
# implementation
# stages files in temp.
context "targets a file outside of the system temp directory" do
- let(:windows_non_temp_dir) { File.join(ENV['systemdrive'], make_tmpname(file_base, "non-temp")) }
+ let(:windows_non_temp_dir) { File.join(ENV["systemdrive"], make_tmpname(file_base, "non-temp")) }
let(:path) { File.join(windows_non_temp_dir, make_tmpname(file_base)) }
before do
- FileUtils::mkdir_p(windows_non_temp_dir) if Chef::Platform.windows?
+ FileUtils.mkdir_p(windows_non_temp_dir) if Chef::Platform.windows?
end
after do
diff --git a/spec/functional/resource/cron_spec.rb b/spec/functional/resource/cron_spec.rb
index ed30756583..f5948191c5 100644
--- a/spec/functional/resource/cron_spec.rb
+++ b/spec/functional/resource/cron_spec.rb
@@ -1,7 +1,7 @@
# encoding: UTF-8
#
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
describe Chef::Resource::Cron, :requires_root, :unix_only do
@@ -55,17 +55,17 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
# Actual tests
let(:new_resource) do
new_resource = Chef::Resource::Cron.new("Chef functional test cron", run_context)
- new_resource.user 'root'
+ new_resource.user "root"
# @hourly is not supported on solaris, aix
if ohai[:platform] == "solaris" || ohai[:platform] == "solaris2" || ohai[:platform] == "aix"
new_resource.minute "0 * * * *"
else
- new_resource.minute '@hourly'
+ new_resource.minute "@hourly"
end
- new_resource.hour ''
- new_resource.day ''
- new_resource.month ''
- new_resource.weekday ''
+ new_resource.hour ""
+ new_resource.day ""
+ new_resource.month ""
+ new_resource.weekday ""
new_resource.command "/bin/true"
new_resource
end
@@ -104,11 +104,11 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
end
end
- exclude_solaris = ["solaris", "opensolaris", "solaris2", "omnios"].include?(ohai[:platform])
+ exclude_solaris = %w{solaris opensolaris solaris2 omnios}.include?(ohai[:platform])
describe "create action with various attributes", :external => exclude_solaris do
def create_and_validate_with_attribute(resource, attribute, value)
- if ohai[:platform] == 'aix'
- expect {resource.run_action(:create)}.to raise_error(Chef::Exceptions::Cron, /Aix cron entry does not support environment variables. Please set them in script and use script in cron./)
+ if ohai[:platform] == "aix"
+ expect { resource.run_action(:create) }.to raise_error(Chef::Exceptions::Cron, /Aix cron entry does not support environment variables. Please set them in script and use script in cron./)
else
resource.run_action(:create)
# Verify if the cron is created successfully
@@ -117,10 +117,10 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
end
def cron_attribute_should_exists(cron_name, attribute, value)
- return if ['aix', 'solaris'].include?(ohai[:platform])
+ return if %w{aix solaris}.include?(ohai[:platform])
# Test if the attribute exists on newly created cron
cron_should_exists(cron_name, "")
- expect(shell_out("crontab -l -u #{new_resource.user} | grep \"#{attribute.upcase}=#{value}\"").exitstatus).to eq(0)
+ expect(shell_out("crontab -l -u #{new_resource.user} | grep '#{attribute.upcase}=\"#{value}\"'").exitstatus).to eq(0)
end
after do
@@ -146,6 +146,13 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
new_resource.home "/home/opscode"
create_and_validate_with_attribute(new_resource, "home", "/home/opscode")
end
+
+ %i{ home mailto path shell }.each do |attr|
+ it "supports an empty string for #{attr} attribute" do
+ new_resource.send(attr, "")
+ create_and_validate_with_attribute(new_resource, attr.to_s, "")
+ end
+ end
end
describe "negative tests for create action" do
diff --git a/spec/functional/resource/deploy_revision_spec.rb b/spec/functional/resource/deploy_revision_spec.rb
index 4bce309a51..572609d8ff 100644
--- a/spec/functional/resource/deploy_revision_spec.rb
+++ b/spec/functional/resource/deploy_revision_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
# Deploy relies heavily on symlinks, so it doesn't work on windows.
-describe Chef::Resource::DeployRevision, :unix_only => true do
+describe Chef::Resource::DeployRevision, :unix_only => true, :requires_git => true do
let(:file_cache_path) { Dir.mktmpdir }
let(:deploy_directory) { Dir.mktmpdir }
@@ -45,7 +45,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
before(:all) do
@ohai = Ohai::System.new
- @ohai.all_plugins(["platform", "os"])
+ @ohai.all_plugins(%w{platform os})
end
let(:node) do
@@ -193,7 +193,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
it "restarts the application" do
expect(File).to exist(rel_path("current/restart.txt"))
- expect(actual_operations_order).to eq(%w[deploy_to_latest_rev])
+ expect(actual_operations_order).to eq(%w{deploy_to_latest_rev})
end
it "is marked as updated" do
@@ -214,7 +214,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
the_app_is_deployed_at_revision(:latest_rev)
it "restarts the application after rolling back" do
- expect(actual_operations_order).to eq(%w[deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again])
+ expect(actual_operations_order).to eq(%w{deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again})
end
it "is marked updated" do
@@ -248,7 +248,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
it "restarts the application" do
expect(File).to exist(rel_path("current/restart.txt"))
- expect(actual_operations_order).to eq(%w[deploy_to_latest_rev])
+ expect(actual_operations_order).to eq(%w{deploy_to_latest_rev})
end
it "is marked as updated" do
@@ -265,7 +265,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
the_app_is_deployed_at_revision(:latest_rev)
it "does not restart the app" do
- expect(actual_operations_order).to eq(%w[deploy_to_latest_rev])
+ expect(actual_operations_order).to eq(%w{deploy_to_latest_rev})
end
it "is not marked updated" do
@@ -283,7 +283,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
the_app_is_deployed_at_revision(:latest_rev)
it "restarts the app" do
- expect(actual_operations_order).to eq(%w[deploy_to_latest_rev deploy_to_latest_rev_again])
+ expect(actual_operations_order).to eq(%w{deploy_to_latest_rev deploy_to_latest_rev_again})
end
it "is marked updated" do
@@ -301,7 +301,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
the_app_is_deployed_at_revision(:latest_rev)
it "restarts the application after the new deploy" do
- expect(actual_operations_order).to eq(%w[deploy_to_previous_rev deploy_to_latest_rev])
+ expect(actual_operations_order).to eq(%w{deploy_to_previous_rev deploy_to_latest_rev})
end
it "is marked updated" do
@@ -324,7 +324,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
the_app_is_deployed_at_revision(:latest_rev)
it "restarts the application after rolling back" do
- expect(actual_operations_order).to eq(%w[deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again])
+ expect(actual_operations_order).to eq(%w{deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again})
end
it "is marked updated" do
@@ -349,7 +349,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
the_app_is_deployed_at_revision(:previous_rev)
it "restarts the application after rolling back" do
- expect(actual_operations_order).to eq(%w[deploy_to_previous_rev deploy_to_latest_rev deploy_to_latest_rev_again])
+ expect(actual_operations_order).to eq(%w{deploy_to_previous_rev deploy_to_latest_rev deploy_to_latest_rev_again})
end
it "is marked updated" do
@@ -392,7 +392,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
the_app_is_deployed_at_revision(:previous_rev)
it "restarts the application after rolling back" do
- expect(actual_operations_order).to eq(%w[deploy_to_previous_rev deploy_to_latest_rev deploy_to_previous_rev_again])
+ expect(actual_operations_order).to eq(%w{deploy_to_previous_rev deploy_to_latest_rev deploy_to_previous_rev_again})
end
it "is marked updated" do
@@ -437,7 +437,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
the_app_is_deployed_at_revision(:second_rev)
it "restarts the application after rolling back" do
- expect(actual_operations_order).to eq(%w[deploy_to_second_rev deploy_to_previous_rev deploy_to_previous_rev_again deploy_to_latest_rev deploy_to_latest_rev_again])
+ expect(actual_operations_order).to eq(%w{deploy_to_second_rev deploy_to_previous_rev deploy_to_previous_rev_again deploy_to_latest_rev deploy_to_latest_rev_again})
end
it "is marked updated" do
@@ -474,7 +474,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
the_app_is_deployed_at_revision(:second_rev)
it "restarts the application after rolling back" do
- expect(actual_operations_order).to eq(%w[deploy_to_second_rev deploy_to_previous_rev deploy_to_second_rev_again deploy_to_latest_rev deploy_to_second_rev_again_again])
+ expect(actual_operations_order).to eq(%w{deploy_to_second_rev deploy_to_previous_rev deploy_to_second_rev_again deploy_to_latest_rev deploy_to_second_rev_again_again})
end
it "is marked updated" do
@@ -689,7 +689,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
end
it "runs migrations in between the before_migrate and before_symlink steps" do
- expect(actual_operations_order).to eq(%w[before_migrate migration before_symlink before_restart after_restart])
+ expect(actual_operations_order).to eq(%w{before_migrate migration before_symlink before_restart after_restart})
end
end
@@ -799,7 +799,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
let(:deploy_that_fails) do
resource = deploy_to_latest_rev.dup
- errant_callback = lambda {|x| raise Exception, "I am a failed deploy" }
+ errant_callback = lambda { |x| raise Exception, "I am a failed deploy" }
resource.send(callback, &errant_callback)
resource
end
@@ -840,7 +840,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
end
def run_action(action)
- raise RuntimeError, "network error"
+ raise "network error"
end
end
@@ -862,7 +862,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
let(:deploy_that_fails) do
resource = deploy_to_previous_rev.dup
- resource.after_restart {|x| raise Exception, "I am a failed deploy" }
+ resource.after_restart { |x| raise Exception, "I am a failed deploy" }
resource
end
diff --git a/spec/functional/resource/directory_spec.rb b/spec/functional/resource/directory_spec.rb
index 88a810964f..0c1345d57f 100644
--- a/spec/functional/resource/directory_spec.rb
+++ b/spec/functional/resource/directory_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Directory do
include_context Chef::Resource::Directory
@@ -33,7 +33,7 @@ describe Chef::Resource::Directory do
end
let(:resource) do
- create_resource
+ create_resource
end
it_behaves_like "a directory resource"
diff --git a/spec/functional/resource/dnf_package_spec.rb b/spec/functional/resource/dnf_package_spec.rb
new file mode 100644
index 0000000000..4c9ee6ca97
--- /dev/null
+++ b/spec/functional/resource/dnf_package_spec.rb
@@ -0,0 +1,686 @@
+#
+# Copyright:: Copyright 2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
+
+# run this test only for following platforms.
+exclude_test = !(%w{rhel fedora}.include?(ohai[:platform_family]) && File.exist?("/usr/bin/dnf"))
+describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test do
+ include Chef::Mixin::ShellOut
+
+ def flush_cache
+ # needed on at least fc23/fc24 sometimes to deal with the dnf cache getting out of sync with the rpm db
+ FileUtils.rm_f "/var/cache/dnf/@System.solv"
+ Chef::Resource::DnfPackage.new("shouldnt-matter", run_context).run_action(:flush_cache)
+ end
+
+ def preinstall(*rpms)
+ rpms.each do |rpm|
+ shell_out!("rpm -ivh #{CHEF_SPEC_ASSETS}/yumrepo/#{rpm}")
+ end
+ flush_cache
+ end
+
+ before(:each) do
+ File.open("/etc/yum.repos.d/chef-dnf-localtesting.repo", "w+") do |f|
+ f.write <<-EOF
+[chef-dnf-localtesting]
+name=Chef DNF spec testing repo
+baseurl=file://#{CHEF_SPEC_ASSETS}/yumrepo
+enable=1
+gpgcheck=0
+ EOF
+ end
+ shell_out!("rpm -qa | grep chef_rpm | xargs -r rpm -e")
+ end
+
+ after(:all) do
+ shell_out!("rpm -qa | grep chef_rpm | xargs -r rpm -e")
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ end
+
+ let(:package_name) { "chef_rpm" }
+ let(:dnf_package) { Chef::Resource::DnfPackage.new(package_name, run_context) }
+
+ describe ":install" do
+ context "vanilla use case" do
+ let(:package_name) { "chef_rpm" }
+
+ it "installs if the package is not installed" do
+ flush_cache
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "does not install if the package is installed" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "does not install twice" do
+ flush_cache
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "does not install if the prior version package is installed" do
+ preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "does not install if the i686 package is installed" do
+ skip "FIXME: do nothing, or install the x86_64 version?"
+ preinstall("chef_rpm-1.10-1.fc24.i686.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.i686")
+ end
+
+ it "does not install if the prior version i686 package is installed" do
+ skip "FIXME: do nothing, or install the x86_64 version?"
+ preinstall("chef_rpm-1.2-1.fc24.i686.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.i686")
+ end
+ end
+
+ context "with versions or globs in the name" do
+ it "works with a version" do
+ flush_cache
+ dnf_package.package_name("chef_rpm-1.10")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "works with an older version" do
+ flush_cache
+ dnf_package.package_name("chef_rpm-1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "works with an evr" do
+ flush_cache
+ dnf_package.package_name("chef_rpm-0:1.2-1.fc24")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "works with a version glob" do
+ flush_cache
+ dnf_package.package_name("chef_rpm-1*")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "works with a name glob + version glob" do
+ flush_cache
+ dnf_package.package_name("chef_rp*-1*")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+ end
+
+ # version only matches the actual dnf version, does not work with epoch or release or combined evr
+ context "with version property" do
+ it "matches the full version" do
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.version("1.10")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "matches with a glob" do
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.version("1*")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "matches the vr" do
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.version("1.10-1.fc24")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "matches the evr" do
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.version("0:1.10-1.fc24")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "matches with a vr glob" do
+ pending "doesn't work on command line either"
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.version("1.10-1*")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "matches with an evr glob" do
+ pending "doesn't work on command line either"
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.version("0:1.10-1*")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+ end
+
+ context "downgrades" do
+ it "just work with DNF" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.version("1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "throws a deprecation warning with allow_downgrade" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(Chef).to receive(:deprecated).with(:dnf_package_allow_downgrade, /^the allow_downgrade property on the dnf_package provider is not used/)
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.version("1.2")
+ dnf_package.run_action(:install)
+ dnf_package.allow_downgrade true
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+ end
+
+ context "with arches" do
+ it "installs with 64-bit arch in the name" do
+ flush_cache
+ dnf_package.package_name("chef_rpm.x86_64")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "installs with 32-bit arch in the name" do
+ flush_cache
+ dnf_package.package_name("chef_rpm.i686")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.i686")
+ end
+
+ it "installs with 64-bit arch in the property" do
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.arch("x86_64")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "installs with 32-bit arch in the property" do
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.arch("i686")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.i686")
+ end
+ end
+
+ context "with constraints" do
+ it "with nothing installed, it installs the latest version" do
+ flush_cache
+ dnf_package.package_name("chef_rpm >= 1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "when it is met, it does nothing" do
+ preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.package_name("chef_rpm >= 1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "when it is met, it does nothing" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.package_name("chef_rpm >= 1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "with nothing intalled, it installs the latest version" do
+ flush_cache
+ dnf_package.package_name("chef_rpm > 1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "when it is not met by an installed rpm, it upgrades" do
+ preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.package_name("chef_rpm > 1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "when it is met by an installed rpm, it does nothing" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.package_name("chef_rpm > 1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "when there is no solution to the contraint" do
+ flush_cache
+ dnf_package.package_name("chef_rpm > 2.0")
+ expect { dnf_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/)
+ end
+
+ it "when there is no solution to the contraint but an rpm is preinstalled" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.package_name("chef_rpm > 2.0")
+ expect { dnf_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/)
+ end
+ end
+
+ context "with source arguments" do
+ it "raises an exception when the package does not exist" do
+ flush_cache
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/this-file-better-not-exist.rpm")
+ expect { dnf_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/)
+ end
+
+ it "does not raise a hard exception in why-run mode when the package does not exist" do
+ Chef::Config[:why_run] = true
+ flush_cache
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/this-file-better-not-exist.rpm")
+ dnf_package.run_action(:install)
+ expect { dnf_package.run_action(:install) }.not_to raise_error
+ end
+
+ it "installs the package when using the source argument" do
+ flush_cache
+ dnf_package.name "something"
+ dnf_package.package_name "somethingelse"
+ dnf_package.source("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "installs the package when the name is a path to a file" do
+ flush_cache
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "does not downgrade the package with :install" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "does not upgrade the package with :install" do
+ preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "is idempotent when the package is already installed" do
+ preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+ end
+
+ context "with no available version" do
+ it "works when a package is installed" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "works with a local source" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ flush_cache
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+ end
+
+ context "multipackage with arches" do
+ it "installs two rpms" do
+ flush_cache
+ dnf_package.package_name([ "chef_rpm.x86_64", "chef_rpm.i686" ] )
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.x86_64/)
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.i686/)
+ end
+
+ it "does nothing if both are installed" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm", "chef_rpm-1.10-1.fc24.i686.rpm")
+ flush_cache
+ dnf_package.package_name([ "chef_rpm.x86_64", "chef_rpm.i686" ] )
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ end
+
+ it "installs the second rpm if the first is installed" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.package_name([ "chef_rpm.x86_64", "chef_rpm.i686" ] )
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.x86_64/)
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.i686/)
+ end
+
+ it "installs the first rpm if the second is installed" do
+ preinstall("chef_rpm-1.10-1.fc24.i686.rpm")
+ dnf_package.package_name([ "chef_rpm.x86_64", "chef_rpm.i686" ] )
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.x86_64/)
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.i686/)
+ end
+
+ # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name
+ it "installs two rpms with multi-arch" do
+ flush_cache
+ dnf_package.package_name(%w{chef_rpm chef_rpm} )
+ dnf_package.arch(%w{x86_64 i686})
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.x86_64/)
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.i686/)
+ end
+
+ # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name
+ it "installs the second rpm if the first is installed (muti-arch)" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.package_name(%w{chef_rpm chef_rpm} )
+ dnf_package.arch(%w{x86_64 i686})
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.x86_64/)
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.i686/)
+ end
+
+ # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name
+ it "installs the first rpm if the second is installed (muti-arch)" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.package_name(%w{chef_rpm chef_rpm} )
+ dnf_package.arch(%w{x86_64 i686})
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.x86_64/)
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.i686/)
+ end
+
+ # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name
+ it "does nothing if both are installed (muti-arch)" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm", "chef_rpm-1.10-1.fc24.i686.rpm")
+ dnf_package.package_name(%w{chef_rpm chef_rpm} )
+ dnf_package.arch(%w{x86_64 i686})
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ end
+ end
+ end
+
+ describe ":upgrade" do
+ context "downgrades" do
+ it "just work with DNF" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.version("1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "throws a deprecation warning with allow_downgrade" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(Chef).to receive(:deprecated).with(:dnf_package_allow_downgrade, /^the allow_downgrade property on the dnf_package provider is not used/)
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.version("1.2")
+ dnf_package.run_action(:install)
+ dnf_package.allow_downgrade true
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+ end
+
+ context "with source arguments" do
+ it "installs the package when using the source argument" do
+ flush_cache
+ dnf_package.name "something"
+ dnf_package.package_name "somethingelse"
+ dnf_package.source("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "installs the package when the name is a path to a file" do
+ flush_cache
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "downgrades the package" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "upgrades the package" do
+ preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+
+ it "is idempotent when the package is already installed" do
+ preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+ end
+
+ context "with no available version" do
+ it "works when a package is installed" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+
+ it "works with a local source" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ flush_cache
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64")
+ end
+ end
+ end
+
+ describe ":remove" do
+ context "vanilla use case" do
+ let(:package_name) { "chef_rpm" }
+ it "does nothing if the package is not installed" do
+ flush_cache
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "removes the package if the package is installed" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "does not remove the package twice" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "removes the package if the prior version package is installed" do
+ preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "removes the package if the i686 package is installed" do
+ skip "FIXME: should this be fixed or is the current behavior correct?"
+ preinstall("chef_rpm-1.10-1.fc24.i686.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "removes the package if the prior version i686 package is installed" do
+ skip "FIXME: should this be fixed or is the current behavior correct?"
+ preinstall("chef_rpm-1.2-1.fc24.i686.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+ end
+
+ context "with 64-bit arch" do
+ let(:package_name) { "chef_rpm.x86_64" }
+ it "does nothing if the package is not installed" do
+ flush_cache
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "removes the package if the package is installed" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "removes the package if the prior version package is installed" do
+ preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "does nothing if the i686 package is installed" do
+ preinstall("chef_rpm-1.10-1.fc24.i686.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.i686")
+ end
+
+ it "does nothing if the prior version i686 package is installed" do
+ preinstall("chef_rpm-1.2-1.fc24.i686.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.i686")
+ end
+ end
+
+ context "with 32-bit arch" do
+ let(:package_name) { "chef_rpm.i686" }
+ it "removes only the 32-bit arch if both are installed" do
+ preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm", "chef_rpm-1.10-1.fc24.i686.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64")
+ end
+ end
+
+ context "with no available version" do
+ it "works when a package is installed" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+ end
+ end
+end
diff --git a/spec/functional/resource/dpkg_package_spec.rb b/spec/functional/resource/dpkg_package_spec.rb
new file mode 100644
index 0000000000..1988fd0c7d
--- /dev/null
+++ b/spec/functional/resource/dpkg_package_spec.rb
@@ -0,0 +1,339 @@
+#
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/mixin/shell_out"
+
+describe Chef::Resource::DpkgPackage, :requires_root, :debian_family_only, arch: "x86_64" do
+ include Chef::Mixin::ShellOut
+
+ let(:apt_data) { File.join(CHEF_SPEC_DATA, "apt") }
+
+ let(:test1_0) { File.join(apt_data, "chef-integration-test_1.0-1_amd64.deb") }
+ let(:test1_1) { File.join(apt_data, "chef-integration-test_1.1-1_amd64.deb") }
+ let(:test2_0) { File.join(apt_data, "chef-integration-test2_1.0-1_amd64.deb") }
+
+ let(:run_context) do
+ node = TEST_NODE.dup
+ events = Chef::EventDispatch::Dispatcher.new
+ Chef::RunContext.new(node, {}, events)
+ end
+
+ let(:dpkg_package) { Chef::Resource::DpkgPackage.new(test1_0, run_context) }
+
+ before(:each) do
+ shell_out("dpkg -P chef-integration-test chef-integration-test2")
+ end
+
+ # handles setting the name property after the initializer runs
+ def set_dpkg_package_name(name)
+ dpkg_package.name name
+ dpkg_package.package_name name
+ end
+
+ def should_be_purged_or_removed(package, action = nil)
+ status = shell_out("dpkg -s #{package}")
+ output = status.stdout + status.stderr
+ if action.nil? || action == :purge
+ expect(output).to match(/no info|not-installed|not installed/)
+ elsif action == :remove
+ expect(output).to match(/deinstall ok config-files/)
+ else
+ raise "Unknown action"
+ end
+ end
+
+ shared_examples_for "common behavior for upgrade or install" do
+ it "installs a package when given only the filename as a name argument (no source)" do
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ shell_out!("dpkg -s chef-integration-test")
+ end
+
+ it "installs a package when given the name and a source argument" do
+ set_dpkg_package_name "chef-integration-test"
+ dpkg_package.source test1_0
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ shell_out!("dpkg -s chef-integration-test")
+ end
+
+ it "installs a package when given a different name and a source argument" do
+ set_dpkg_package_name "some other name"
+ dpkg_package.source test1_0
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ shell_out!("dpkg -s chef-integration-test")
+ end
+
+ it "installs a package when given a path as a package_name and no source" do
+ set_dpkg_package_name "chef-integration-test"
+ dpkg_package.package_name test1_0
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ shell_out!("dpkg -s chef-integration-test")
+ end
+
+ it "raises an error when the name is not a path and the source is not given" do
+ set_dpkg_package_name "chef-integration-test"
+ dpkg_package.package_name "chef-integration-test"
+ expect { dpkg_package.run_action(action) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ it "raises an error when passed a package_name that does not exist" do
+ set_dpkg_package_name File.join(test1_0, "make.it.fail")
+ expect { dpkg_package.run_action(action) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ it "raises an error when passed a source that does not exist" do
+ set_dpkg_package_name "chef-integration-test"
+ dpkg_package.source File.join(test1_0, "make.it.fail")
+ expect { dpkg_package.run_action(action) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ it "should not install an already installed package" do
+ shell_out!("dpkg -i #{test1_0}")
+ dpkg_package.run_action(action)
+ expect(dpkg_package).not_to be_updated_by_last_action
+ shell_out!("dpkg -s chef-integration-test")
+ end
+
+ it "should handle a multipackage install" do
+ set_dpkg_package_name [ test1_0, test2_0 ]
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ shell_out!("dpkg -s chef-integration-test")
+ shell_out!("dpkg -s chef-integration-test2")
+ end
+
+ it "should not update multipackages that are up-to-date" do
+ shell_out!("dpkg -i #{test1_0} #{test2_0}")
+ set_dpkg_package_name [ test1_0, test2_0 ]
+ dpkg_package.run_action(action)
+ expect(dpkg_package).not_to be_updated_by_last_action
+ shell_out!("dpkg -s chef-integration-test")
+ shell_out!("dpkg -s chef-integration-test2")
+ end
+
+ it "should install the second if the first is installed" do
+ shell_out!("dpkg -i #{test1_0}")
+ set_dpkg_package_name [ test1_0, test2_0 ]
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ shell_out!("dpkg -s chef-integration-test")
+ shell_out!("dpkg -s chef-integration-test2")
+ end
+
+ it "should install the first if the second is installed" do
+ shell_out!("dpkg -i #{test2_0}")
+ set_dpkg_package_name [ test1_0, test2_0 ]
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ shell_out!("dpkg -s chef-integration-test")
+ shell_out!("dpkg -s chef-integration-test2")
+ end
+ end
+
+ context "action :install" do
+ let(:action) { :install }
+ it_behaves_like "common behavior for upgrade or install"
+
+ it "should not upgrade a package" do
+ shell_out!("dpkg -i #{test1_0}")
+ set_dpkg_package_name test1_1
+ dpkg_package.run_action(action)
+ expect(dpkg_package).not_to be_updated_by_last_action
+ end
+
+ it "should not upgrade on a multipackage install" do
+ shell_out!("dpkg -i #{test1_0} #{test2_0}")
+ set_dpkg_package_name [ test1_1, test2_0 ]
+ dpkg_package.run_action(action)
+ expect(dpkg_package).not_to be_updated_by_last_action
+ end
+ end
+
+ context "action :upgrade" do
+ let(:action) { :upgrade }
+ it_behaves_like "common behavior for upgrade or install"
+
+ it "should upgrade a package" do
+ shell_out!("dpkg -i #{test1_0}")
+ set_dpkg_package_name test1_1
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ end
+
+ it "should upgrade on a multipackage install" do
+ shell_out!("dpkg -i #{test1_0} #{test2_0}")
+ set_dpkg_package_name [ test1_1, test2_0 ]
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ end
+ end
+
+ shared_examples_for "common behavior for remove or purge" do
+ it "should remove a package that is installed when the name is a source" do
+ shell_out!("dpkg -i #{test1_0}")
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ end
+
+ it "should do nothing if the package is not installed when the name is a source" do
+ dpkg_package.run_action(action)
+ expect(dpkg_package).not_to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ end
+
+ it "should remove a package that is installed when the name is the package name and source is nil" do
+ shell_out!("dpkg -i #{test1_0}")
+ set_dpkg_package_name "chef-integration-test"
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ end
+
+ it "should do nothing if the package is not installed when the name is the package name and the source is nil" do
+ set_dpkg_package_name "chef-integration-test"
+ dpkg_package.run_action(action)
+ expect(dpkg_package).not_to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ end
+
+ it "should remove a package that is installed when the name is changed but the source is a package" do
+ shell_out!("dpkg -i #{test1_0}")
+ set_dpkg_package_name "some other name"
+ dpkg_package.source test1_0
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ end
+
+ it "should do nothing if the package is not installed when the name is changed but the source is a package" do
+ set_dpkg_package_name "some other name"
+ dpkg_package.source test1_0
+ dpkg_package.run_action(action)
+ expect(dpkg_package).not_to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ end
+
+ it "should remove a package if the name is a file that does not exist, but the source exists" do
+ shell_out!("dpkg -i #{test1_0}")
+ dpkg_package.name "whatever"
+ dpkg_package.package_name File.join(test1_0, "make.it.fail")
+ dpkg_package.source test1_0
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ end
+
+ it "should do nothing if the package is not installed when the name is a file that does not exist, but the source exists" do
+ set_dpkg_package_name "some other name"
+ dpkg_package.name "whatever"
+ dpkg_package.package_name File.join(test1_0, "make.it.fail")
+ dpkg_package.source test1_0
+ dpkg_package.run_action(action)
+ expect(dpkg_package).not_to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ end
+
+ it "should remove a package if the package_name is correct, but the source does not exist" do
+ shell_out!("dpkg -i #{test1_0}")
+ dpkg_package.name "whatever"
+ dpkg_package.package_name "chef-integration-test"
+ dpkg_package.source File.join(test1_0, "make.it.fail")
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ end
+
+ it "should do nothing if the package_name is correct, but the source does not exist, and the package is not installed" do
+ dpkg_package.name "whatever"
+ dpkg_package.package_name "chef-integration-test"
+ dpkg_package.source File.join(test1_0, "make.it.fail")
+ dpkg_package.run_action(action)
+ expect(dpkg_package).not_to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ end
+
+ it "should remove both packages when called with two" do
+ shell_out!("dpkg -i #{test1_0} #{test2_0}")
+ set_dpkg_package_name [ "chef-integration-test", "chef-integration-test2" ]
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ should_be_purged_or_removed("chef-integration-test2", action)
+ end
+
+ it "should remove a package when only the first one is installed" do
+ shell_out!("dpkg -i #{test1_0}")
+ set_dpkg_package_name [ "chef-integration-test", "chef-integration-test2" ]
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ should_be_purged_or_removed("chef-integration-test2")
+ end
+
+ it "should remove a package when only the second one is installed" do
+ shell_out!("dpkg -i #{test2_0}")
+ set_dpkg_package_name [ "chef-integration-test", "chef-integration-test2" ]
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ should_be_purged_or_removed("chef-integration-test2", action)
+ end
+
+ it "should do nothing when both packages are not installed" do
+ set_dpkg_package_name [ "chef-integration-test", "chef-integration-test2" ]
+ dpkg_package.run_action(action)
+ expect(dpkg_package).not_to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test")
+ should_be_purged_or_removed("chef-integration-test2")
+ end
+ end
+
+ context "action :remove" do
+ let(:action) { :remove }
+ it_behaves_like "common behavior for remove or purge"
+
+ it "should not remove a removed package when the name is a source" do
+ # the "test2" file has a conffile declared in it
+ shell_out!("dpkg -i #{test2_0}")
+ shell_out!("dpkg -r chef-integration-test2")
+ set_dpkg_package_name "chef-integration-test2"
+ dpkg_package.run_action(action)
+ expect(dpkg_package).not_to be_updated_by_last_action
+ shell_out!("dpkg -s chef-integration-test2") # its still 'installed'
+ end
+ end
+
+ context "action :purge" do
+ let(:action) { :purge }
+ it_behaves_like "common behavior for remove or purge"
+
+ it "should purge a removed package when the name is a source" do
+ # the "test2" file has a conffile declared in it
+ shell_out!("dpkg -i #{test2_0}")
+ shell_out!("dpkg -r chef-integration-test2")
+ set_dpkg_package_name "chef-integration-test2"
+ dpkg_package.run_action(action)
+ expect(dpkg_package).to be_updated_by_last_action
+ should_be_purged_or_removed("chef-integration-test2", action)
+ end
+ end
+end
diff --git a/spec/functional/resource/dsc_resource_spec.rb b/spec/functional/resource/dsc_resource_spec.rb
index 24503f1ec7..bb3cf2157d 100644
--- a/spec/functional/resource/dsc_resource_spec.rb
+++ b/spec/functional/resource/dsc_resource_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,48 +16,43 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::DscResource, :windows_powershell_dsc_only do
- before(:all) do
- @ohai = Ohai::System.new
- @ohai.all_plugins(['platform', 'os', 'languages/powershell'])
- end
-
let(:event_dispatch) { Chef::EventDispatch::Dispatcher.new }
- let(:node) {
+ let(:node) do
Chef::Node.new.tap do |n|
- n.consume_external_attrs(@ohai.data, {})
+ n.consume_external_attrs(OHAI_SYSTEM.data, {})
end
- }
+ end
let(:run_context) { Chef::RunContext.new(node, {}, event_dispatch) }
- let(:new_resource) {
+ let(:new_resource) do
Chef::Resource::DscResource.new("dsc_resource_test", run_context)
- }
+ end
- context 'when Powershell does not support Invoke-DscResource'
- context 'when Powershell supports Invoke-DscResource' do
+ context "when Powershell does not support Invoke-DscResource"
+ context "when Powershell supports Invoke-DscResource" do
before do
if !Chef::Platform.supports_dsc_invoke_resource?(node)
- skip 'Requires Powershell >= 5.0.10018.0'
- elsif !Chef::Platform.dsc_refresh_mode_disabled?(node)
- skip 'Requires LCM RefreshMode is Disabled'
+ skip "Requires Powershell >= 5.0.10018.0"
+ elsif !Chef::Platform.supports_refresh_mode_enabled?(node) && !Chef::Platform.dsc_refresh_mode_disabled?(node)
+ skip "Requires LCM RefreshMode is Disabled"
end
end
- context 'with an invalid dsc resource' do
- it 'raises an exception if the resource is not found' do
- new_resource.resource 'thisdoesnotexist'
+ context "with an invalid dsc resource" do
+ it "raises an exception if the resource is not found" do
+ new_resource.resource "thisdoesnotexist"
expect { new_resource.run_action(:run) }.to raise_error(
Chef::Exceptions::ResourceNotFound)
end
end
- context 'with a valid dsc resource' do
- let(:tmp_file_name) { Dir::Tmpname.create('tmpfile') {} }
- let(:test_text) { "'\"!@#$%^&*)(}{][\u2713~n"}
+ context "with a valid dsc resource" do
+ let(:tmp_file_name) { Dir::Tmpname.create("tmpfile") {} }
+ let(:test_text) { "'\"!@#$%^&*)(}{][\u2713~n" }
before do
new_resource.resource :File
@@ -69,20 +64,20 @@ describe Chef::Resource::DscResource, :windows_powershell_dsc_only do
File.delete(tmp_file_name) if File.exists? tmp_file_name
end
- it 'converges the resource if it is not converged' do
+ it "converges the resource if it is not converged" do
new_resource.run_action(:run)
- contents = File.open(tmp_file_name, 'rb:bom|UTF-16LE') do |f|
- f.read.encode('UTF-8')
+ contents = File.open(tmp_file_name, "rb:bom|UTF-16LE") do |f|
+ f.read.encode("UTF-8")
end
expect(contents).to eq(test_text)
expect(new_resource).to be_updated
end
- it 'does not converge the resource if it is already converged' do
+ it "does not converge the resource if it is already converged" do
new_resource.run_action(:run)
expect(new_resource).to be_updated
reresource =
- Chef::Resource::DscResource.new("dsc_resource_retest", run_context)
+ Chef::Resource::DscResource.new("dsc_resource_retest", run_context)
reresource.resource :File
reresource.property :Contents, test_text
reresource.property :DestinationPath, tmp_file_name
diff --git a/spec/functional/resource/dsc_script_spec.rb b/spec/functional/resource/dsc_script_spec.rb
index dc7704481f..ce92c468f0 100644
--- a/spec/functional/resource/dsc_script_spec.rb
+++ b/spec/functional/resource/dsc_script_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,25 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/shell_out'
-require 'chef/mixin/windows_architecture_helper'
-require 'support/shared/integration/integration_helper'
+require "spec_helper"
+require "chef/mixin/powershell_out"
+require "chef/mixin/shell_out"
+require "chef/mixin/windows_architecture_helper"
+require "support/shared/integration/integration_helper"
describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
include Chef::Mixin::WindowsArchitectureHelper
+ include Chef::Mixin::PowershellOut
before(:all) do
@temp_dir = ::Dir.mktmpdir("dsc-functional-test")
+ # enable the HTTP listener if it is not already enabled needed by underlying DSC engine
+ winrm_code = <<-CODE
+ winrm get winrm/config/listener?Address=*+Transport=HTTP
+ if($LASTEXITCODE -ne 0) {
+ winrm create winrm/config/Listener?Address=*+Transport=HTTP
+ }
+ CODE
+ powershell_out!(winrm_code)
end
after(:all) do
@@ -35,10 +45,10 @@ describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
def create_config_script_from_code(code, configuration_name, data = false)
script_code = data ? code : "Configuration '#{configuration_name}'\n{\n\t#{code}\n}\n"
- data_suffix = data ? '_config_data' : ''
- extension = data ? 'psd1' : 'ps1'
+ data_suffix = data ? "_config_data" : ""
+ extension = data ? "psd1" : "ps1"
script_path = "#{@temp_dir}/dsc_functional_test#{data_suffix}.#{extension}"
- ::File.open(script_path, 'wt') do | script |
+ ::File.open(script_path, "wt") do |script|
script.write(script_code)
end
script_path
@@ -55,36 +65,36 @@ describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
end
def delete_user(target_user)
- begin
- shell_out!("net user #{target_user} /delete")
- rescue Mixlib::ShellOut::ShellCommandFailed
- end
+ shell_out!("net user #{target_user} /delete")
+ rescue Mixlib::ShellOut::ShellCommandFailed
end
- let(:dsc_env_variable) { 'chefenvtest' }
- let(:dsc_env_value1) { 'value1' }
- let(:env_value2) { 'value2' }
- let(:dsc_test_run_context) {
+ let(:dsc_env_variable) { "chefenvtest" }
+ let(:dsc_env_value1) { "value1" }
+ let(:env_value2) { "value2" }
+ let(:dsc_test_run_context) do
node = Chef::Node.new
- node.automatic['platform'] = 'windows'
- node.automatic['platform_version'] = '6.1'
- node.automatic['kernel'][:machine] = :x86_64 # Only 64-bit architecture is supported
- node.automatic[:languages][:powershell][:version] = '4.0'
+ node.automatic["os"] = "windows"
+ node.automatic["platform"] = "windows"
+ node.automatic["platform_version"] = "6.1"
+ node.automatic["kernel"][:machine] = :x86_64 # Only 64-bit architecture is supported
+ node.automatic[:languages][:powershell][:version] = "4.0"
empty_events = Chef::EventDispatch::Dispatcher.new
Chef::RunContext.new(node, {}, empty_events)
- }
- let(:dsc_test_resource_name) { 'DSCTest' }
- let(:dsc_test_resource_base) {
+ end
+ let(:dsc_test_resource_name) { "DSCTest" }
+ let(:dsc_test_resource_base) do
Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
- }
+ end
let(:test_registry_key) { 'HKEY_LOCAL_MACHINE\Software\Chef\Spec\Functional\Resource\dsc_script_spec' }
- let(:test_registry_value) { 'Registration' }
- let(:test_registry_data1) { 'LL927' }
- let(:test_registry_data2) { 'LL928' }
- let(:reg_key_name_param_name) { 'testregkeyname' }
- let(:reg_key_value_param_name) { 'testregvaluename' }
- let(:registry_embedded_parameters) { "$#{reg_key_name_param_name} = '#{test_registry_key}';$#{reg_key_value_param_name} = '#{test_registry_value}'"}
- let(:dsc_reg_code) { <<-EOH
+ let(:test_registry_value) { "Registration" }
+ let(:test_registry_data1) { "LL927" }
+ let(:test_registry_data2) { "LL928" }
+ let(:reg_key_name_param_name) { "testregkeyname" }
+ let(:reg_key_value_param_name) { "testregvaluename" }
+ let(:registry_embedded_parameters) { "$#{reg_key_name_param_name} = '#{test_registry_key}';$#{reg_key_value_param_name} = '#{test_registry_value}'" }
+ let(:dsc_reg_code) do
+ <<-EOH
#{registry_embedded_parameters}
Registry "ChefRegKey"
{
@@ -94,31 +104,33 @@ describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
Ensure = 'Present'
}
EOH
- }
+ end
let(:dsc_code) { dsc_reg_code }
- let(:dsc_reg_script) { <<-EOH
+ let(:dsc_reg_script) do
+ <<-EOH
param($testregkeyname, $testregvaluename)
#{dsc_reg_code}
EOH
- }
+ end
- let(:dsc_user_prefix) { 'dsc' }
- let(:dsc_user_suffix) { 'chefx' }
- let(:dsc_user) {"#{dsc_user_prefix}_usr_#{dsc_user_suffix}" }
- let(:dsc_user_prefix_env_var_name) { 'dsc_user_env_prefix' }
- let(:dsc_user_suffix_env_var_name) { 'dsc_user_env_suffix' }
- let(:dsc_user_prefix_env_code) { "$env:#{dsc_user_prefix_env_var_name}"}
- let(:dsc_user_suffix_env_code) { "$env:#{dsc_user_suffix_env_var_name}"}
- let(:dsc_user_prefix_param_name) { 'dsc_user_prefix_param' }
- let(:dsc_user_suffix_param_name) { 'dsc_user_suffix_param' }
- let(:dsc_user_prefix_param_code) { "$#{dsc_user_prefix_param_name}"}
- let(:dsc_user_suffix_param_code) { "$#{dsc_user_suffix_param_name}"}
- let(:dsc_user_env_code) { "\"$(#{dsc_user_prefix_env_code})_usr_$(#{dsc_user_suffix_env_code})\""}
- let(:dsc_user_param_code) { "\"$(#{dsc_user_prefix_param_code})_usr_$(#{dsc_user_suffix_param_code})\""}
+ let(:dsc_user_prefix) { "dsc" }
+ let(:dsc_user_suffix) { "chefx" }
+ let(:dsc_user) { "#{dsc_user_prefix}_usr_#{dsc_user_suffix}" }
+ let(:dsc_user_prefix_env_var_name) { "dsc_user_env_prefix" }
+ let(:dsc_user_suffix_env_var_name) { "dsc_user_env_suffix" }
+ let(:dsc_user_prefix_env_code) { "$env:#{dsc_user_prefix_env_var_name}" }
+ let(:dsc_user_suffix_env_code) { "$env:#{dsc_user_suffix_env_var_name}" }
+ let(:dsc_user_prefix_param_name) { "dsc_user_prefix_param" }
+ let(:dsc_user_suffix_param_name) { "dsc_user_suffix_param" }
+ let(:dsc_user_prefix_param_code) { "$#{dsc_user_prefix_param_name}" }
+ let(:dsc_user_suffix_param_code) { "$#{dsc_user_suffix_param_name}" }
+ let(:dsc_user_env_code) { "\"$(#{dsc_user_prefix_env_code})_usr_$(#{dsc_user_suffix_env_code})\"" }
+ let(:dsc_user_param_code) { "\"$(#{dsc_user_prefix_param_code})_usr_$(#{dsc_user_suffix_param_code})\"" }
let(:config_flags) { nil }
- let(:config_params) { <<-EOH
+ let(:config_params) do
+ <<-EOH
[CmdletBinding()]
param
@@ -127,14 +139,15 @@ EOH
$#{dsc_user_suffix_param_name}
)
EOH
- }
+ end
- let(:config_param_section) { '' }
+ let(:config_param_section) { "" }
let(:dsc_user_code) { "'#{dsc_user}'" }
let(:dsc_user_prefix_code) { dsc_user_prefix }
let(:dsc_user_suffix_code) { dsc_user_suffix }
let(:dsc_script_environment_attribute) { nil }
- let(:dsc_user_resources_code) { <<-EOH
+ let(:dsc_user_resources_code) do
+ <<-EOH
#{config_param_section}
node localhost
{
@@ -154,10 +167,10 @@ User dsctestusercreate
}
}
EOH
- }
+ end
- let(:dsc_user_config_data) {
-<<-EOH
+ let(:dsc_user_config_data) do
+ <<-EOH
@{
AllNodes = @(
@{
@@ -168,13 +181,14 @@ EOH
}
EOH
- }
+ end
- let(:dsc_environment_env_var_name) { 'dsc_test_cwd' }
+ let(:dsc_environment_env_var_name) { "dsc_test_cwd" }
let(:dsc_environment_no_fail_not_etc_directory) { "#{ENV['systemroot']}\\system32" }
let(:dsc_environment_fail_etc_directory) { "#{ENV['systemroot']}\\system32\\drivers\\etc" }
- let(:exception_message_signature) { 'LL927-LL928' }
- let(:dsc_environment_config) {<<-EOH
+ let(:exception_message_signature) { "LL927-LL928" }
+ let(:dsc_environment_config) do
+ <<-EOH
if (($pwd.path -eq '#{dsc_environment_fail_etc_directory}') -and (test-path('#{dsc_environment_fail_etc_directory}')))
{
throw 'Signature #{exception_message_signature}: Purposefully failing because cwd == #{dsc_environment_fail_etc_directory}'
@@ -186,21 +200,21 @@ environment "whatsmydir"
Ensure = 'Present'
}
EOH
-}
+ end
- let(:dsc_config_name) {
+ let(:dsc_config_name) do
dsc_test_resource_base.name
- }
- let(:dsc_resource_from_code) {
+ end
+ let(:dsc_resource_from_code) do
dsc_test_resource_base.code(dsc_code)
dsc_test_resource_base
- }
+ end
let(:config_name_value) { dsc_test_resource_base.name }
- let(:dsc_resource_from_path) {
+ let(:dsc_resource_from_path) do
dsc_test_resource_base.command(create_config_script_from_code(dsc_code, config_name_value))
dsc_test_resource_base
- }
+ end
before(:each) do
test_key_resource = Chef::Resource::RegistryKey.new(test_registry_key, dsc_test_run_context)
@@ -214,19 +228,19 @@ EOH
test_key_resource.run_action(:delete_key)
end
- shared_examples_for 'a dsc_script resource with specified PowerShell configuration code' do
+ shared_examples_for "a dsc_script resource with specified PowerShell configuration code" do
let(:test_registry_data) { test_registry_data1 }
- it 'should create a registry key with a specific registry value and data' do
+ it "should create a registry key with a specific registry value and data" do
expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(false)
dsc_test_resource.run_action(:run)
expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(true)
- expect(dsc_test_resource.registry_value_exists?(test_registry_key, {:name => test_registry_value, :type => :string, :data => test_registry_data})).to eq(true)
+ expect(dsc_test_resource.registry_value_exists?(test_registry_key, { :name => test_registry_value, :type => :string, :data => test_registry_data })).to eq(true)
end
- it_should_behave_like 'a dsc_script resource with configuration affected by cwd'
+ it_should_behave_like "a dsc_script resource with configuration affected by cwd"
end
- shared_examples_for 'a dsc_script resource with configuration affected by cwd' do
+ shared_examples_for "a dsc_script resource with configuration affected by cwd" do
after(:each) do
removal_resource = Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
removal_resource.code <<-EOH
@@ -239,16 +253,16 @@ EOH
removal_resource.run_action(:run)
end
- describe 'when the DSC configuration contains code that raises an exception if cwd has a specific value' do
+ describe "when the DSC configuration contains code that raises an exception if cwd has a specific value" do
let(:dsc_code) { dsc_environment_config }
- it 'should not raise an exception if the cwd is not etc' do
+ it "should not raise an exception if the cwd is not etc" do
dsc_test_resource.cwd(dsc_environment_no_fail_not_etc_directory)
- expect {dsc_test_resource.run_action(:run)}.not_to raise_error
+ expect { dsc_test_resource.run_action(:run) }.not_to raise_error
end
- it 'should raise an exception if the cwd is etc' do
+ it "should raise an exception if the cwd is etc" do
dsc_test_resource.cwd(dsc_environment_fail_etc_directory)
- expect {dsc_test_resource.run_action(:run)}.to raise_error(Chef::Exceptions::PowershellCmdletException)
+ expect { dsc_test_resource.run_action(:run) }.to raise_error(Chef::Exceptions::PowershellCmdletException)
begin
dsc_test_resource.run_action(:run)
rescue Chef::Exceptions::PowershellCmdletException => e
@@ -258,14 +272,14 @@ EOH
end
end
- shared_examples_for 'a parameterized DSC configuration script' do
+ shared_examples_for "a parameterized DSC configuration script" do
let(:dsc_user_prefix_code) { dsc_user_prefix_env_code }
let(:dsc_user_suffix_code) { dsc_user_suffix_env_code }
- it_behaves_like 'a dsc_script with configuration that uses environment variables'
+ it_behaves_like "a dsc_script with configuration that uses environment variables"
end
- shared_examples_for 'a dsc_script without configuration data that takes parameters' do
- context 'when configuration data is not specified' do
+ shared_examples_for "a dsc_script without configuration data that takes parameters" do
+ context "when configuration data is not specified" do
before(:each) do
test_key_resource = Chef::Resource::RegistryKey.new(test_registry_key, dsc_test_run_context)
@@ -280,120 +294,118 @@ EOH
end
let(:test_registry_data) { test_registry_data1 }
- let(:dsc_parameterized_env_param_value) { "val" + Random::rand.to_s }
+ let(:dsc_parameterized_env_param_value) { "val" + Random.rand.to_s }
- it 'should have a default value of nil for the configuration_data attribute' do
+ it "should have a default value of nil for the configuration_data attribute" do
expect(dsc_test_resource.configuration_data).to eql(nil)
end
- it 'should have a default value of nil for the configuration_data_path attribute' do
+ it "should have a default value of nil for the configuration_data_path attribute" do
expect(dsc_test_resource.configuration_data_script).to eql(nil)
end
let(:dsc_test_resource) { dsc_resource_from_path }
- let(:registry_embedded_parameters) { '' }
+ let(:registry_embedded_parameters) { "" }
let(:dsc_code) { dsc_reg_script }
- it 'should set a registry key according to parameters passed to the configuration' do
+ it "should set a registry key according to parameters passed to the configuration" do
dsc_test_resource.configuration_name(config_name_value)
- dsc_test_resource.flags({:"#{reg_key_name_param_name}" => test_registry_key, :"#{reg_key_value_param_name}" => test_registry_value})
+ dsc_test_resource.flags({ :"#{reg_key_name_param_name}" => test_registry_key, :"#{reg_key_value_param_name}" => test_registry_value })
expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(false)
dsc_test_resource.run_action(:run)
expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(true)
- expect(dsc_test_resource.registry_value_exists?(test_registry_key, {:name => test_registry_value, :type => :string, :data => test_registry_data})).to eq(true)
+ expect(dsc_test_resource.registry_value_exists?(test_registry_key, { :name => test_registry_value, :type => :string, :data => test_registry_data })).to eq(true)
end
end
end
- shared_examples_for 'a dsc_script with configuration data' do
- let(:configuration_data_attribute) { 'configuration_data' }
- it_behaves_like 'a dsc_script with configuration data set via an attribute'
+ shared_examples_for "a dsc_script with configuration data" do
+ let(:configuration_data_attribute) { "configuration_data" }
+ it_behaves_like "a dsc_script with configuration data set via an attribute"
- let(:configuration_data_attribute) { 'configuration_data_script' }
- it_behaves_like 'a dsc_script with configuration data set via an attribute'
+ let(:configuration_data_attribute) { "configuration_data_script" }
+ it_behaves_like "a dsc_script with configuration data set via an attribute"
end
- shared_examples_for 'a dsc_script with configuration data set via an attribute' do
- it 'should run a configuration script that creates a user' do
+ shared_examples_for "a dsc_script with configuration data set via an attribute" do
+ it "should run a configuration script that creates a user" do
config_data_value = dsc_user_config_data
dsc_test_resource.configuration_name(config_name_value)
- if configuration_data_attribute == 'configuration_data_script'
- config_data_value = create_config_script_from_code(dsc_user_config_data, '', true)
+ if configuration_data_attribute == "configuration_data_script"
+ config_data_value = create_config_script_from_code(dsc_user_config_data, "", true)
end
- dsc_test_resource.environment({dsc_user_prefix_env_var_name => dsc_user_prefix,
- dsc_user_suffix_env_var_name => dsc_user_suffix})
+ dsc_test_resource.environment({ dsc_user_prefix_env_var_name => dsc_user_prefix,
+ dsc_user_suffix_env_var_name => dsc_user_suffix })
dsc_test_resource.send(configuration_data_attribute, config_data_value)
dsc_test_resource.flags(config_flags)
expect(user_exists?(dsc_user)).to eq(false)
- expect {dsc_test_resource.run_action(:run)}.not_to raise_error
+ expect { dsc_test_resource.run_action(:run) }.not_to raise_error
expect(user_exists?(dsc_user)).to eq(true)
end
end
- shared_examples_for 'a dsc_script with configuration data that takes parameters' do
+ shared_examples_for "a dsc_script with configuration data that takes parameters" do
let(:dsc_user_code) { dsc_user_param_code }
let(:config_param_section) { config_params }
- let(:config_flags) {{:"#{dsc_user_prefix_param_name}" => "#{dsc_user_prefix}", :"#{dsc_user_suffix_param_name}" => "#{dsc_user_suffix}"}}
- it 'does not directly contain the user name' do
- configuration_script_content = ::File.open(dsc_test_resource.command) do | file |
+ let(:config_flags) { { :"#{dsc_user_prefix_param_name}" => "#{dsc_user_prefix}", :"#{dsc_user_suffix_param_name}" => "#{dsc_user_suffix}" } }
+ it "does not directly contain the user name" do
+ configuration_script_content = ::File.open(dsc_test_resource.command) do |file|
file.read
end
expect(configuration_script_content.include?(dsc_user)).to be(false)
end
- it_behaves_like 'a dsc_script with configuration data'
+ it_behaves_like "a dsc_script with configuration data"
end
- shared_examples_for 'a dsc_script with configuration data that uses environment variables' do
+ shared_examples_for "a dsc_script with configuration data that uses environment variables" do
let(:dsc_user_code) { dsc_user_env_code }
- it 'does not directly contain the user name' do
- configuration_script_content = ::File.open(dsc_test_resource.command) do | file |
+ it "does not directly contain the user name" do
+ configuration_script_content = ::File.open(dsc_test_resource.command) do |file|
file.read
end
expect(configuration_script_content.include?(dsc_user)).to be(false)
end
- it_behaves_like 'a dsc_script with configuration data'
+ it_behaves_like "a dsc_script with configuration data"
end
- context 'when supplying configuration through the configuration attribute' do
+ context "when supplying configuration through the configuration attribute" do
let(:dsc_test_resource) { dsc_resource_from_code }
- it_behaves_like 'a dsc_script resource with specified PowerShell configuration code'
+ it_behaves_like "a dsc_script resource with specified PowerShell configuration code"
end
- context 'when supplying configuration using the path attribute' do
+ context "when supplying configuration using the path attribute" do
let(:dsc_test_resource) { dsc_resource_from_path }
- it_behaves_like 'a dsc_script resource with specified PowerShell configuration code'
+ it_behaves_like "a dsc_script resource with specified PowerShell configuration code"
end
- context 'when running a configuration that manages users' do
+ context "when running a configuration that manages users" do
before(:each) do
delete_user(dsc_user)
end
let(:dsc_code) { dsc_user_resources_code }
- let(:config_name_value) { 'DSCTestConfig' }
+ let(:config_name_value) { "DSCTestConfig" }
let(:dsc_test_resource) { dsc_resource_from_path }
- it_behaves_like 'a dsc_script with configuration data'
- it_behaves_like 'a dsc_script with configuration data that uses environment variables'
- it_behaves_like 'a dsc_script with configuration data that takes parameters'
- it_behaves_like 'a dsc_script without configuration data that takes parameters'
+ it_behaves_like "a dsc_script with configuration data"
+ it_behaves_like "a dsc_script with configuration data that uses environment variables"
+ it_behaves_like "a dsc_script with configuration data that takes parameters"
+ it_behaves_like "a dsc_script without configuration data that takes parameters"
end
- context 'when using ps_credential' do
+ context "when using ps_credential" do
include IntegrationSupport
before(:each) do
delete_user(dsc_user)
- ohai_reader = Ohai::System.new
- ohai_reader.all_plugins(["platform", "os", "languages/powershell"])
- dsc_test_run_context.node.consume_external_attrs(ohai_reader.data,{})
+ dsc_test_run_context.node.consume_external_attrs(OHAI_SYSTEM.data, {})
end
let(:configuration_data_path) { 'C:\\configurationdata.psd1' }
let(:self_signed_cert_path) do
- File.join(CHEF_SPEC_DATA, 'dsc_lcm.pfx')
+ File.join(CHEF_SPEC_DATA, "dsc_lcm.pfx")
end
let(:dsc_configuration_script) do
@@ -424,12 +436,12 @@ if($cert -eq $null) {
}
lcm -thumbprint $cert.thumbprint
-set-dsclocalconfigurationmanager -path ./LCM
+set-dsclocalconfigurationmanager -path ./LCM
$ConfigurationData = @"
@{
-AllNodes = @(
- @{
- NodeName = "localhost";
+AllNodes = @(
+ @{
+ NodeName = "localhost";
CertificateID = '$($cert.thumbprint)';
};
);
@@ -440,7 +452,7 @@ $ConfigurationData | out-file '#{configuration_data_path}' -force
end
let(:powershell_script_resource) do
- Chef::Resource::PowershellScript.new('configure-lcm', dsc_test_run_context).tap do |r|
+ Chef::Resource::PowershellScript.new("configure-lcm", dsc_test_run_context).tap do |r|
r.code(dsc_configuration_script)
r.architecture(:x86_64)
end
@@ -460,7 +472,8 @@ EOF
end
end
- it 'allows the use of ps_credential' do
+ it "allows the use of ps_credential" do
+ skip("Skipped until we can adjust the test cert to meet the WMF 5 cert requirements.")
expect(user_exists?(dsc_user)).to eq(false)
powershell_script_resource.run_action(:run)
expect(File).to exist(configuration_data_path)
diff --git a/spec/functional/resource/env_spec.rb b/spec/functional/resource/env_spec.rb
index b9dcd7b33a..4b0ff70c0b 100755
--- a/spec/functional/resource/env_spec.rb
+++ b/spec/functional/resource/env_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,28 +16,28 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Env, :windows_only do
- context 'when running on Windows' do
- let(:chef_env_test_lower_case) { 'chefenvtest' }
- let(:chef_env_test_mixed_case) { 'chefENVtest' }
- let(:env_dne_key) { 'env_dne_key' }
- let(:env_value1) { 'value1' }
- let(:env_value2) { 'value2' }
-
- let(:env_value_expandable) { '%SystemRoot%' }
- let(:test_run_context) {
+ context "when running on Windows" do
+ let(:chef_env_test_lower_case) { "chefenvtest" }
+ let(:chef_env_test_mixed_case) { "chefENVtest" }
+ let(:env_dne_key) { "env_dne_key" }
+ let(:env_value1) { "value1" }
+ let(:env_value2) { "value2" }
+
+ let(:env_value_expandable) { "%SystemRoot%" }
+ let(:test_run_context) do
node = Chef::Node.new
- node.default['os'] = 'windows'
- node.default['platform'] = 'windows'
- node.default['platform_version'] = '6.1'
+ node.default["os"] = "windows"
+ node.default["platform"] = "windows"
+ node.default["platform_version"] = "6.1"
empty_events = Chef::EventDispatch::Dispatcher.new
Chef::RunContext.new(node, {}, empty_events)
- }
- let(:test_resource) {
- Chef::Resource::Env.new('unknown', test_run_context)
- }
+ end
+ let(:test_resource) do
+ Chef::Resource::Env.new("unknown", test_run_context)
+ end
before(:each) do
resource_lower = Chef::Resource::Env.new(chef_env_test_lower_case, test_run_context)
@@ -47,7 +47,7 @@ describe Chef::Resource::Env, :windows_only do
end
context "when the create action is invoked" do
- it 'should create an environment variable for action create' do
+ it "should create an environment variable for action create" do
expect(ENV[chef_env_test_lower_case]).to eq(nil)
test_resource.key_name(chef_env_test_lower_case)
test_resource.value(env_value1)
@@ -76,7 +76,7 @@ describe Chef::Resource::Env, :windows_only do
expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
end
- it 'should not expand environment variables if the variable is not PATH' do
+ it "should not expand environment variables if the variable is not PATH" do
expect(ENV[chef_env_test_lower_case]).to eq(nil)
test_resource.key_name(chef_env_test_lower_case)
test_resource.value(env_value_expandable)
@@ -90,7 +90,7 @@ describe Chef::Resource::Env, :windows_only do
expect(ENV[chef_env_test_lower_case]).to eq(nil)
test_resource.key_name(chef_env_test_lower_case)
test_resource.value(env_value1)
- expect {test_resource.run_action(:modify) }.to raise_error(Chef::Exceptions::Env)
+ expect { test_resource.run_action(:modify) }.to raise_error(Chef::Exceptions::Env)
end
it "should modify an existing variable's value to a new value" do
@@ -115,7 +115,7 @@ describe Chef::Resource::Env, :windows_only do
expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
end
- it 'should not expand environment variables if the variable is not PATH' do
+ it "should not expand environment variables if the variable is not PATH" do
test_resource.key_name(chef_env_test_lower_case)
test_resource.value(env_value1)
test_resource.run_action(:create)
@@ -125,27 +125,27 @@ describe Chef::Resource::Env, :windows_only do
expect(ENV[chef_env_test_lower_case]).to eq(env_value_expandable)
end
- context 'when using PATH' do
+ context "when using PATH" do
let(:random_name) { Time.now.to_i }
- let(:env_val) { "#{env_value_expandable}_#{random_name}"}
- let!(:path_before) { test_resource.provider_for_action(test_resource.action).env_value('PATH') || '' }
- let!(:env_path_before) { ENV['PATH'] }
+ let(:env_val) { "#{env_value_expandable}_#{random_name}" }
+ let!(:path_before) { test_resource.provider_for_action(test_resource.action).env_value("PATH") || "" }
+ let!(:env_path_before) { ENV["PATH"] }
- it 'should expand PATH' do
+ it "should expand PATH" do
expect(path_before).not_to include(env_val)
- test_resource.key_name('PATH')
+ test_resource.key_name("PATH")
test_resource.value("#{path_before};#{env_val}")
test_resource.run_action(:create)
- expect(ENV['PATH']).not_to include(env_val)
- expect(ENV['PATH']).to include("#{random_name}")
+ expect(ENV["PATH"]).not_to include(env_val)
+ expect(ENV["PATH"]).to include("#{random_name}")
end
after(:each) do
# cleanup so we don't flood the path
- test_resource.key_name('PATH')
+ test_resource.key_name("PATH")
test_resource.value(path_before)
test_resource.run_action(:create)
- ENV['PATH'] = env_path_before
+ ENV["PATH"] = env_path_before
end
end
@@ -165,7 +165,7 @@ describe Chef::Resource::Env, :windows_only do
expect(ENV[chef_env_test_lower_case]).to eq(nil)
test_resource.key_name(chef_env_test_lower_case)
test_resource.value(env_value1)
- expect{test_resource.run_action(:delete)}.not_to raise_error
+ expect { test_resource.run_action(:delete) }.not_to raise_error
expect(ENV[chef_env_test_lower_case]).to eq(nil)
end
diff --git a/spec/functional/resource/execute_spec.rb b/spec/functional/resource/execute_spec.rb
index 692ccfb796..09b7286854 100644
--- a/spec/functional/resource/execute_spec.rb
+++ b/spec/functional/resource/execute_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'functional/resource/base'
-require 'timeout'
+require "spec_helper"
+require "functional/resource/base"
+require "timeout"
describe Chef::Resource::Execute do
- let(:resource) {
+ let(:resource) do
resource = Chef::Resource::Execute.new("foo_resource", run_context)
resource.command("echo hello")
resource
- }
+ end
describe "when guard is ruby block" do
it "guard can still run" do
@@ -41,10 +41,10 @@ describe Chef::Resource::Execute do
end
let(:guard) { "ruby -e 'exit 0'" }
- let!(:guard_resource) {
+ let!(:guard_resource) do
interpreter = Chef::GuardInterpreter::ResourceGuardInterpreter.new(resource, guard, nil)
interpreter.send(:get_interpreter_resource, resource)
- }
+ end
it "executes the guard and not the regular resource" do
expect_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:get_interpreter_resource).and_return(guard_resource)
@@ -106,7 +106,7 @@ describe Chef::Resource::Execute do
it "guard adds additional values in its :environment and runs" do
resource.only_if %{ruby -e 'exit 1 if ENV["SGCE_SECRET"] != "regularsecret"'}, {
- :environment => { 'SGCE_SECRET' => "regularsecret" }
+ :environment => { "SGCE_SECRET" => "regularsecret" },
}
resource.run_action(:run)
expect(resource).to be_updated_by_last_action
@@ -114,7 +114,7 @@ describe Chef::Resource::Execute do
it "guard adds additional values in its :environment and does not run" do
resource.only_if %{ruby -e 'exit 1 if ENV["SGCE_SECRET"] == "regularsecret"'}, {
- :environment => { 'SGCE_SECRET' => "regularsecret" }
+ :environment => { "SGCE_SECRET" => "regularsecret" },
}
resource.run_action(:run)
expect(resource).not_to be_updated_by_last_action
@@ -122,7 +122,7 @@ describe Chef::Resource::Execute do
it "guard overwrites value with its :environment and runs" do
resource.only_if %{ruby -e 'exit 1 if ENV["SAWS_SECRET"] != "regularsecret"'}, {
- :environment => { 'SAWS_SECRET' => "regularsecret" }
+ :environment => { "SAWS_SECRET" => "regularsecret" },
}
resource.run_action(:run)
expect(resource).to be_updated_by_last_action
@@ -130,13 +130,25 @@ describe Chef::Resource::Execute do
it "guard overwrites value with its :environment and does not runs" do
resource.only_if %{ruby -e 'exit 1 if ENV["SAWS_SECRET"] == "regularsecret"'}, {
- :environment => { 'SAWS_SECRET' => "regularsecret" }
+ :environment => { "SAWS_SECRET" => "regularsecret" },
}
resource.run_action(:run)
expect(resource).not_to be_updated_by_last_action
end
end
+ describe "when a guard is specified" do
+ describe "when using the default guard interpreter" do
+ let(:guard_interpreter_resource) { nil }
+ it_behaves_like "a resource with a guard specifying an alternate user identity"
+ end
+
+ describe "when using the execute resource as the guard interpreter" do
+ let(:guard_interpreter_resource) { :execute }
+ it_behaves_like "a resource with a guard specifying an alternate user identity"
+ end
+ end
+
# Ensure that CommandTimeout is raised, and is caused by resource.timeout really expiring.
# https://github.com/chef/chef/issues/2985
#
@@ -145,10 +157,15 @@ describe Chef::Resource::Execute do
# Timeout::timeout should be longer than resource.timeout, but less than the resource.command ruby sleep timer,
# so we fail if we finish on resource.command instead of resource.timeout, but raise CommandTimeout anyway (#2175).
it "times out when a timeout is set on the resource" do
- Timeout::timeout(30) do
+ Timeout.timeout(30) do
resource.command %{ruby -e 'sleep 300'}
resource.timeout 0.1
expect { resource.run_action(:run) }.to raise_error(Mixlib::ShellOut::CommandTimeout)
end
end
+
+ describe "when running with an alternate user identity" do
+ let(:resource_command_property) { :command }
+ it_behaves_like "an execute resource that supports alternate user identity"
+ end
end
diff --git a/spec/functional/resource/file_spec.rb b/spec/functional/resource/file_spec.rb
index 9e30e62111..0fa1317032 100644
--- a/spec/functional/resource/file_spec.rb
+++ b/spec/functional/resource/file_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
describe Chef::Resource::File do
include_context Chef::Resource::File
@@ -25,17 +25,17 @@ describe Chef::Resource::File do
let(:file_base) { "file_spec" }
let(:expected_content) { "Don't fear the ruby." }
- def create_resource(opts={})
+ def create_resource(opts = {})
events = Chef::EventDispatch::Dispatcher.new
node = Chef::Node.new
run_context = Chef::RunContext.new(node, {}, events)
use_path = if opts[:use_relative_path]
- Dir.chdir(Dir.tmpdir)
- File.basename(path)
- else
- path
- end
+ Dir.chdir(Dir.tmpdir)
+ File.basename(path)
+ else
+ path
+ end
Chef::Resource::File.new(use_path, run_context)
end
@@ -86,7 +86,6 @@ describe Chef::Resource::File do
end
end
-
describe "when using backup" do
before do
Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH
@@ -102,9 +101,9 @@ describe Chef::Resource::File do
end
it "only stores the number of requested backups" do
- resource_without_content.content('foo')
+ resource_without_content.content("foo")
resource_without_content.run_action(:create)
- resource_without_content.content('bar')
+ resource_without_content.content("bar")
resource_without_content.run_action(:create)
expect(Dir.glob(backup_glob).length).to eq(1)
end
diff --git a/spec/functional/resource/git_spec.rb b/spec/functional/resource/git_spec.rb
index 9d3b82f19e..6808898c29 100644
--- a/spec/functional/resource/git_spec.rb
+++ b/spec/functional/resource/git_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/shell_out'
-require 'tmpdir'
-require 'shellwords'
+require "spec_helper"
+require "chef/mixin/shell_out"
+require "tmpdir"
+require "shellwords"
# Deploy relies heavily on symlinks, so it doesn't work on windows.
-describe Chef::Resource::Git do
+describe Chef::Resource::Git, :requires_git => true do
include Chef::Mixin::ShellOut
let(:file_cache_path) { Dir.mktmpdir }
# Some versions of git complains when the deploy directory is
@@ -62,7 +62,7 @@ describe Chef::Resource::Git do
let(:v1_tag) { "9b73fb5e316bfaff7b822b0ccb3e1e08f9885085" }
let(:rev_foo) { "ed181b3419b6f489bedab282348162a110d6d3a1" }
let(:rev_testing) { "972d153654503bccec29f630c5dd369854a561e8" }
- let(:rev_head) { "d294fbfd05aa7709ad9a9b8ef6343b17d355bf5f"}
+ let(:rev_head) { "d294fbfd05aa7709ad9a9b8ef6343b17d355bf5f" }
let(:git_user_config) do
<<-E
@@ -76,23 +76,21 @@ E
Chef::Log.level = :warn # silence git command live streams
@old_file_cache_path = Chef::Config[:file_cache_path]
shell_out!("git clone \"#{git_bundle_repo}\" example", :cwd => origin_repo_dir)
- File.open("#{origin_repo}/.git/config", "a+") {|f| f.print(git_user_config) }
+ File.open("#{origin_repo}/.git/config", "a+") { |f| f.print(git_user_config) }
Chef::Config[:file_cache_path] = file_cache_path
end
after(:each) do
Chef::Config[:file_cache_path] = @old_file_cache_path
FileUtils.remove_entry_secure deploy_directory if File.exist?(deploy_directory)
+ FileUtils.remove_entry_secure base_dir_path
FileUtils.remove_entry_secure file_cache_path
- end
-
- after(:all) do
FileUtils.remove_entry_secure origin_repo_dir
end
before(:all) do
@ohai = Ohai::System.new
- @ohai.all_plugins(["platform", "os"])
+ @ohai.all_plugins(%w{platform os})
end
context "working with pathes with special characters" do
@@ -129,10 +127,10 @@ E
it "checks out the revision pointed to by the tag commit, not the tag commit itself" do
basic_git_resource.run_action(:sync)
- head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+ head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
expect(head_rev).to eq(v1_commit)
# also verify the tag commit itself is what we expect as an extra sanity check
- rev = shell_out!('git rev-parse v1.0.0', :cwd => deploy_directory, :returns => [0]).stdout.strip
+ rev = shell_out!("git rev-parse v1.0.0", :cwd => deploy_directory, :returns => [0]).stdout.strip
expect(rev).to eq(v1_tag)
end
@@ -140,7 +138,7 @@ E
# this used to fail because we didn't resolve the annotated tag
# properly to the pointed to commit.
basic_git_resource.run_action(:sync)
- head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+ head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
expect(head_rev).to eq(v1_commit)
copy_git_resource.run_action(:sync)
@@ -166,14 +164,14 @@ E
it "checks out the expected revision ed18" do
basic_git_resource.revision rev_foo
basic_git_resource.run_action(:sync)
- head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+ head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
expect(head_rev).to eq(rev_foo)
end
it "doesn't update if up-to-date" do
basic_git_resource.revision rev_foo
basic_git_resource.run_action(:sync)
- head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+ head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
expect(head_rev).to eq(rev_foo)
copy_git_resource.revision rev_foo
@@ -184,7 +182,7 @@ E
it "checks out the expected revision 972d" do
basic_git_resource.revision rev_testing
basic_git_resource.run_action(:sync)
- head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+ head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
expect(head_rev).to eq(rev_testing)
end
end
@@ -193,13 +191,13 @@ E
let(:basic_git_resource) do
Chef::Resource::Git.new(deploy_directory, run_context).tap do |r|
r.repository origin_repo
- r.revision 'HEAD'
+ r.revision "HEAD"
end
end
it "checks out the expected revision" do
basic_git_resource.run_action(:sync)
- head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+ head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
expect(head_rev).to eq(rev_head)
end
end
@@ -214,7 +212,7 @@ E
it "checks out HEAD as the default revision" do
basic_git_resource.run_action(:sync)
- head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+ head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
expect(head_rev).to eq(rev_head)
end
end
@@ -228,7 +226,7 @@ E
let(:basic_git_resource) do
Chef::Resource::Git.new(deploy_directory, run_context).tap do |r|
r.repository origin_repo
- r.revision 'HEAD'
+ r.revision "HEAD"
end
end
@@ -241,7 +239,7 @@ E
it "checks out the (master) HEAD revision and ignores the tag" do
basic_git_resource.run_action(:sync)
- head_rev = shell_out!('git rev-parse HEAD',
+ head_rev = shell_out!("git rev-parse HEAD",
:cwd => deploy_directory,
:returns => [0]).stdout.strip
expect(head_rev).to eq(rev_head)
@@ -249,7 +247,7 @@ E
it "checks out the (master) HEAD revision when no revision is specified (ignores tag)" do
git_resource_default_rev.run_action(:sync)
- head_rev = shell_out!('git rev-parse HEAD',
+ head_rev = shell_out!("git rev-parse HEAD",
:cwd => deploy_directory,
:returns => [0]).stdout.strip
expect(head_rev).to eq(rev_head)
diff --git a/spec/functional/resource/group_spec.rb b/spec/functional/resource/group_spec.rb
index 0862b8e15f..7effd386a4 100644
--- a/spec/functional/resource/group_spec.rb
+++ b/spec/functional/resource/group_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Chirag Jog (<chirag@clogeny.com>)
# Author:: Siddheshwar More (<siddheshwar.more@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
# Chef::Resource::Group are turned off on Mac OS X 10.6 due to caching
# issues around Etc.getgrnam() not picking up the group membership
@@ -31,8 +31,8 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
def group_should_exist(group)
case ohai[:platform_family]
when "debian", "fedora", "rhel", "suse", "gentoo", "slackware", "arch"
- expect { Etc::getgrnam(group) }.not_to raise_error
- expect(group).to eq(Etc::getgrnam(group).name)
+ expect { Etc.getgrnam(group) }.not_to raise_error
+ expect(group).to eq(Etc.getgrnam(group).name)
when "windows"
expect { Chef::Util::Windows::NetGroup.new(group).local_get_members }.not_to raise_error
end
@@ -49,21 +49,21 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
members.shift # Get rid of GroupMembership: string
members.include?(user)
else
- Etc::getgrnam(group_name).mem.include?(user)
+ Etc.getgrnam(group_name).mem.include?(user)
end
end
def group_should_not_exist(group)
case ohai[:platform_family]
when "debian", "fedora", "rhel", "suse", "gentoo", "slackware", "arch"
- expect { Etc::getgrnam(group) }.to raise_error(ArgumentError, "can't find group for #{group}")
+ expect { Etc.getgrnam(group) }.to raise_error(ArgumentError, "can't find group for #{group}")
when "windows"
- expect { Chef::Util::Windows::NetGroup.new(group).local_get_members }.to raise_error(ArgumentError, "The group name could not be found.")
+ expect { Chef::Util::Windows::NetGroup.new(group).local_get_members }.to raise_error(ArgumentError, /The group name could not be found./)
end
end
def compare_gid(resource, gid)
- return resource.gid == Etc::getgrnam(resource.name).gid if unix?
+ return resource.gid == Etc.getgrnam(resource.name).gid if unix?
end
def sid_string_from_user(user)
@@ -79,27 +79,41 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
def windows_domain_user?(user_name)
domain, user = user_name.split('\\')
- if user && domain != '.'
- computer_name = ENV['computername']
- domain.downcase != computer_name.downcase
+ if user && domain != "."
+ computer_name = ENV["computername"]
+ !domain.casecmp(computer_name.downcase).zero?
end
end
+ def node
+ node = Chef::Node.new
+ node.consume_external_attrs(ohai.data, {})
+ node
+ end
+
def user(username)
- usr = Chef::Resource::User.new("#{username}", run_context)
+ usr = Chef::Resource.resource_for_node(:user, node).new(username, run_context)
if ohai[:platform_family] == "windows"
usr.password("ComplexPass11!")
end
usr
end
- def create_user(username)
- user(username).run_action(:create) if ! windows_domain_user?(username)
+ def create_user(username, uid = nil)
+ if ! windows_domain_user?(username)
+ user_to_create = user(username)
+ user_to_create.uid(uid) if uid
+ user_to_create.run_action(:create)
+ end
# TODO: User should exist
end
def remove_user(username)
- user(username).run_action(:remove) if ! windows_domain_user?(username)
+ if ! windows_domain_user?(username)
+ u = user(username)
+ u.manage_home false # jekins hosts throw mail spool file not owned by user if we use manage_home true
+ u.run_action(:remove)
+ end
# TODO: User shouldn't exist
end
@@ -159,8 +173,11 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
describe "when the users exist" do
before do
+ high_uid = 30000
(spec_members).each do |member|
- create_user(member)
+ remove_user(member)
+ create_user(member, high_uid)
+ high_uid += 1
end
end
@@ -267,14 +284,14 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
end
describe "when removing members" do
- it "raises an error for a non well-formed domain name" do
+ it "does not raise an error for a non well-formed domain name" do
group_resource.excluded_members [invalid_domain_user_name]
- expect { group_resource.run_action(tested_action) }.to raise_error Chef::Exceptions::Win32APIError
+ expect { group_resource.run_action(tested_action) }.to_not raise_error
end
- it "raises an error for a nonexistent domain" do
+ it "does not raise an error for a nonexistent domain" do
group_resource.excluded_members [nonexistent_domain_user_name]
- expect { group_resource.run_action(tested_action) }.to raise_error Chef::Exceptions::Win32APIError
+ expect { group_resource.run_action(tested_action) }.to_not raise_error
end
end
end
@@ -282,12 +299,13 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
let(:group_name) { "group#{SecureRandom.random_number(9999)}" }
let(:included_members) { nil }
let(:excluded_members) { nil }
- let(:group_resource) {
+ let(:group_resource) do
group = Chef::Resource::Group.new(group_name, run_context)
group.members(included_members)
group.excluded_members(excluded_members)
+ group.gid(30000) unless ohai[:platform_family] == "mac_os_x"
group
- }
+ end
it "append should be false by default" do
expect(group_resource.append).to eq(false)
@@ -305,10 +323,11 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
end
describe "when group name is length 256", :windows_only do
- let!(:group_name) { "theoldmanwalkingdownthestreetalwayshadagood\
+ let!(:group_name) do
+ "theoldmanwalkingdownthestreetalwayshadagood\
smileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisface\
theoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalking\
-downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestree" }
+downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestree" end
it "should create a group" do
group_resource.run_action(:create)
@@ -317,10 +336,11 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestree" }
end
describe "when group name length is more than 256", :windows_only do
- let!(:group_name) { "theoldmanwalkingdownthestreetalwayshadagood\
+ let!(:group_name) do
+ "theoldmanwalkingdownthestreetalwayshadagood\
smileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisface\
theoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalking\
-downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
+downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" end
it "should not create a group" do
expect { group_resource.run_action(:create) }.to raise_error(ArgumentError)
@@ -334,7 +354,7 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
invalid_resource = group_resource.dup
invalid_resource.members(["Jack"])
invalid_resource.excluded_members(["Jack"])
- expect { invalid_resource.run_action(:create)}.to raise_error(Chef::Exceptions::ConflictingMembersInGroup)
+ expect { invalid_resource.run_action(:create) }.to raise_error(Chef::Exceptions::ConflictingMembersInGroup)
end
end
end
@@ -361,14 +381,14 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
end
describe "group modify action", :not_supported_on_solaris do
- let(:spec_members){ ["Gordon", "Eric", "Anthony"] }
+ let(:spec_members) { %w{mnou5sdz htulrvwq x4c3g1lu} }
let(:included_members) { [spec_members[0], spec_members[1]] }
let(:excluded_members) { [spec_members[2]] }
let(:tested_action) { :modify }
describe "when there is no group" do
it "should raise an error" do
- expect { group_resource.run_action(:modify) }.to raise_error
+ expect { group_resource.run_action(:modify) }.to raise_error(Chef::Exceptions::Group)
end
end
@@ -378,8 +398,8 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
describe "when running on Windows", :windows_only do
describe "when members are Active Directory domain identities", :windows_domain_joined_only do
- let(:computer_domain) { ohai[:kernel]['cs_info']['domain'].split('.')[0] }
- let(:spec_members){ ["#{computer_domain}\\Domain Admins", "#{computer_domain}\\Domain Users", "#{computer_domain}\\Domain Computers"] }
+ let(:computer_domain) { ohai[:kernel]["cs_info"]["domain"].split(".")[0] }
+ let(:spec_members) { ["#{computer_domain}\\Domain Admins", "#{computer_domain}\\Domain Users", "#{computer_domain}\\Domain Computers"] }
include_examples "correct group management"
end
@@ -389,7 +409,7 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
end
describe "group manage action", :not_supported_on_solaris do
- let(:spec_members){ ["Gordon", "Eric", "Anthony"] }
+ let(:spec_members) { %w{mnou5sdz htulrvwq x4c3g1lu} }
let(:included_members) { [spec_members[0], spec_members[1]] }
let(:excluded_members) { [spec_members[2]] }
let(:tested_action) { :manage }
@@ -401,10 +421,11 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
end
it "raises an error on modify" do
- expect { group_resource.run_action(:modify) }.to raise_error
+ expect { group_resource.run_action(:modify) }.to raise_error(Chef::Exceptions::Group)
end
it "does not raise an error on manage" do
+ allow(Etc).to receive(:getpwnam).and_return(double("User"))
expect { group_resource.run_action(:manage) }.not_to raise_error
end
end
@@ -415,8 +436,8 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
describe "running on windows", :windows_only do
describe "when members are Windows domain identities", :windows_domain_joined_only do
- let(:computer_domain) { ohai[:kernel]['cs_info']['domain'].split('.')[0] }
- let(:spec_members){ ["#{computer_domain}\\Domain Admins", "#{computer_domain}\\Domain Users", "#{computer_domain}\\Domain Computers"] }
+ let(:computer_domain) { ohai[:kernel]["cs_info"]["domain"].split(".")[0] }
+ let(:spec_members) { ["#{computer_domain}\\Domain Admins", "#{computer_domain}\\Domain Users", "#{computer_domain}\\Domain Computers"] }
include_examples "correct group management"
end
@@ -427,34 +448,34 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
describe "group resource with Usermod provider", :solaris_only do
describe "when excluded_members is set" do
- let(:excluded_members) { ["Anthony"] }
+ let(:excluded_members) { ["x4c3g1lu"] }
it ":manage should raise an error" do
- expect {group_resource.run_action(:manage) }.to raise_error
+ expect { group_resource.run_action(:manage) }.to raise_error
end
it ":modify should raise an error" do
- expect {group_resource.run_action(:modify) }.to raise_error
+ expect { group_resource.run_action(:modify) }.to raise_error
end
it ":create should raise an error" do
- expect {group_resource.run_action(:create) }.to raise_error
+ expect { group_resource.run_action(:create) }.to raise_error
end
end
describe "when append is not set" do
- let(:included_members) { ["Gordon", "Eric"] }
+ let(:included_members) { %w{gordon eric} }
before(:each) do
group_resource.append(false)
end
it ":manage should raise an error" do
- expect {group_resource.run_action(:manage) }.to raise_error
+ expect { group_resource.run_action(:manage) }.to raise_error
end
it ":modify should raise an error" do
- expect {group_resource.run_action(:modify) }.to raise_error
+ expect { group_resource.run_action(:modify) }.to raise_error
end
end
end
diff --git a/spec/functional/resource/ifconfig_spec.rb b/spec/functional/resource/ifconfig_spec.rb
index 9c613544ac..0298dbcf45 100644
--- a/spec/functional/resource/ifconfig_spec.rb
+++ b/spec/functional/resource/ifconfig_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,19 @@
# limitations under the License.
#
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "functional/resource/base"
+require "chef/mixin/shell_out"
# run this test only for following platforms.
-include_flag = !(['ubuntu', 'centos', 'aix'].include?(ohai[:platform]))
+include_flag = !(%w{ubuntu centos aix}.include?(ohai[:platform]))
+
+describe Chef::Resource::Ifconfig, :requires_root, :skip_travis, :external => include_flag do
+ # This test does not work in travis because there is no eth0
-describe Chef::Resource::Ifconfig, :requires_root, :external => include_flag do
include Chef::Mixin::ShellOut
let(:new_resource) do
- new_resource = Chef::Resource::Ifconfig.new('10.10.0.1', run_context)
+ new_resource = Chef::Resource::Ifconfig.new("10.10.0.1", run_context)
new_resource
end
@@ -43,19 +45,25 @@ describe Chef::Resource::Ifconfig, :requires_root, :external => include_flag do
# use loopback interface for tests
case ohai[:platform]
when "aix"
- 'lo0'
+ "lo0"
else
- 'lo'
+ "lo"
end
end
+ def fetch_first_interface_name
+ shell_out("ifconfig | grep Ethernet | head -1 | cut -d' ' -f1").stdout.strip
+ end
+
# **Caution: any updates to core interfaces can be risky.
def en0_interface_for_test
case ohai[:platform]
when "aix"
- 'en0'
+ "en0"
+ when "ubuntu"
+ fetch_first_interface_name
else
- 'eth0'
+ "eth0"
end
end
@@ -105,14 +113,14 @@ describe Chef::Resource::Ifconfig, :requires_root, :external => include_flag do
# Actual tests
describe "#load_current_resource" do
- it 'should load given interface' do
+ it "should load given interface" do
new_resource.device lo_interface_for_test
expect(current_resource.device).to eql(lo_interface_for_test)
expect(current_resource.inet_addr).to match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)
end
end
- exclude_test = ohai[:platform] != 'ubuntu'
+ exclude_test = ohai[:platform] != "ubuntu"
describe "#action_add", :external => exclude_test do
after do
new_resource.run_action(:delete)
diff --git a/spec/functional/resource/link_spec.rb b/spec/functional/resource/link_spec.rb
index 7e903b30b4..256f350640 100644
--- a/spec/functional/resource/link_spec.rb
+++ b/spec/functional/resource/link_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,33 +16,34 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
if windows?
- require 'chef/win32/file' #probably need this in spec_helper
+ require "chef/win32/file" #probably need this in spec_helper
+ require "chef/win32/security"
end
describe Chef::Resource::Link do
let(:file_base) { "file_spec" }
- let(:expect_updated?) {true}
+ let(:expect_updated?) { true }
# We create the files in a different directory than tmp to exercise
# different file deployment strategies more completely.
let(:test_file_dir) do
if windows?
- File.join(ENV['systemdrive'], "test-dir")
+ File.join(ENV["systemdrive"], "test-dir")
else
File.join(CHEF_SPEC_DATA, "test-dir")
end
end
before do
- FileUtils::mkdir_p(test_file_dir)
+ FileUtils.mkdir_p(test_file_dir)
end
after do
- FileUtils::rm_rf(test_file_dir)
+ FileUtils.rm_rf(test_file_dir)
end
let(:to) do
@@ -62,6 +63,18 @@ describe Chef::Resource::Link do
end
end
+ def node
+ node = Chef::Node.new
+ node.consume_external_attrs(ohai.data, {})
+ node
+ end
+
+ def user(user)
+ usr = Chef::Resource.resource_for_node(:user, node).new(user, run_context)
+ usr.password("ComplexPass11!") if windows?
+ usr
+ end
+
def cleanup_link(path)
if windows? && File.directory?(path)
# If the link target is a directory rm_rf doesn't work all the
@@ -73,7 +86,7 @@ describe Chef::Resource::Link do
end
def canonicalize(path)
- windows? ? path.gsub('/', '\\') : path
+ windows? ? path.tr("/", '\\') : path
end
def symlink(a, b)
@@ -83,6 +96,7 @@ describe Chef::Resource::Link do
File.symlink(a, b)
end
end
+
def symlink?(file)
if windows?
Chef::ReservedNames::Win32::File.symlink?(file)
@@ -90,6 +104,7 @@ describe Chef::Resource::Link do
File.symlink?(file)
end
end
+
def readlink(file)
if windows?
Chef::ReservedNames::Win32::File.readlink(file)
@@ -97,6 +112,7 @@ describe Chef::Resource::Link do
File.readlink(file)
end
end
+
def link(a, b)
if windows?
Chef::ReservedNames::Win32::File.link(a, b)
@@ -105,6 +121,42 @@ describe Chef::Resource::Link do
end
end
+ let(:test_user) { windows? ? nil : ENV["USER"] }
+
+ def expected_owner
+ if windows?
+ get_sid(test_user)
+ else
+ test_user
+ end
+ end
+
+ def get_sid(value)
+ if value.kind_of?(String)
+ Chef::ReservedNames::Win32::Security::SID.from_account(value)
+ elsif value.kind_of?(Chef::ReservedNames::Win32::Security::SID)
+ value
+ else
+ raise "Must specify username or SID: #{value}"
+ end
+ end
+
+ def chown(file, user)
+ if windows?
+ Chef::ReservedNames::Win32::Security::SecurableObject.new(file).owner = get_sid(user)
+ else
+ File.lchown(Etc.getpwnam(user).uid, Etc.getpwnam(user).gid, file)
+ end
+ end
+
+ def owner(file)
+ if windows?
+ Chef::ReservedNames::Win32::Security::SecurableObject.new(file).security_descriptor.owner
+ else
+ Etc.getpwuid(File.lstat(file).uid).name
+ end
+ end
+
def create_resource
node = Chef::Node.new
events = Chef::EventDispatch::Dispatcher.new
@@ -121,142 +173,144 @@ describe Chef::Resource::Link do
end
describe "when supported on platform", :not_supported_on_win2k3 do
- shared_examples_for 'delete errors out' do
- it 'delete errors out' do
+ shared_examples_for "delete errors out" do
+ it "delete errors out" do
expect { resource.run_action(:delete) }.to raise_error(Chef::Exceptions::Link)
expect(File.exist?(target_file) || symlink?(target_file)).to be_truthy
end
end
- shared_context 'delete is noop' do
- describe 'the :delete action' do
+ shared_context "delete is noop" do
+ describe "the :delete action" do
before(:each) do
@info = []
allow(Chef::Log).to receive(:info) { |msg| @info << msg }
resource.run_action(:delete)
end
- it 'leaves the file deleted' do
+ it "leaves the file deleted" do
expect(File.exist?(target_file)).to be_falsey
expect(symlink?(target_file)).to be_falsey
end
- it 'does not mark the resource updated' do
+ it "does not mark the resource updated" do
expect(resource).not_to be_updated
end
- it 'does not log that it deleted' do
+ it "does not log that it deleted" do
expect(@info.include?("link[#{target_file}] deleted")).to be_falsey
end
end
end
- shared_context 'delete succeeds' do
- describe 'the :delete action' do
+ shared_context "delete succeeds" do
+ describe "the :delete action" do
before(:each) do
@info = []
allow(Chef::Log).to receive(:info) { |msg| @info << msg }
resource.run_action(:delete)
end
- it 'deletes the file' do
+ it "deletes the file" do
expect(File.exist?(target_file)).to be_falsey
expect(symlink?(target_file)).to be_falsey
end
- it 'marks the resource updated' do
+ it "marks the resource updated" do
expect(resource).to be_updated
end
- it 'logs that it deleted' do
+ it "logs that it deleted" do
expect(@info.include?("link[#{target_file}] deleted")).to be_truthy
end
end
end
- shared_context 'create symbolic link succeeds' do
- describe 'the :create action' do
+ shared_context "create symbolic link succeeds" do
+ describe "the :create action" do
before(:each) do
@info = []
allow(Chef::Log).to receive(:info) { |msg| @info << msg }
resource.run_action(:create)
end
- it 'links to the target file' do
+ it "links to the target file" do
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(to))
+ expect(owner(target_file)).to eq(expected_owner) unless test_user.nil?
end
- it 'marks the resource updated' do
+ it "marks the resource updated" do
expect(resource).to be_updated
end
- it 'logs that it created' do
+ it "logs that it created" do
expect(@info.include?("link[#{target_file}] created")).to be_truthy
end
end
end
- shared_context 'create symbolic link is noop' do
- describe 'the :create action' do
+ shared_context "create symbolic link is noop" do
+ describe "the :create action" do
before(:each) do
@info = []
allow(Chef::Log).to receive(:info) { |msg| @info << msg }
resource.run_action(:create)
end
- it 'leaves the file linked' do
+ it "leaves the file linked" do
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(to))
+ expect(owner(target_file)).to eq(expected_owner) unless test_user.nil?
end
- it 'does not mark the resource updated' do
+ it "does not mark the resource updated" do
expect(resource).not_to be_updated
end
- it 'does not log that it created' do
+ it "does not log that it created" do
expect(@info.include?("link[#{target_file}] created")).to be_falsey
end
end
end
- shared_context 'create hard link succeeds' do
- describe 'the :create action' do
+ shared_context "create hard link succeeds" do
+ describe "the :create action" do
before(:each) do
@info = []
allow(Chef::Log).to receive(:info) { |msg| @info << msg }
resource.run_action(:create)
end
- it 'preserves the hard link' do
+ it "preserves the hard link" do
expect(File.exists?(target_file)).to be_truthy
expect(symlink?(target_file)).to be_falsey
# Writing to one hardlinked file should cause both
# to have the new value.
expect(IO.read(to)).to eq(IO.read(target_file))
- File.open(to, "w") { |file| file.write('wowzers') }
- expect(IO.read(target_file)).to eq('wowzers')
+ File.open(to, "w") { |file| file.write("wowzers") }
+ expect(IO.read(target_file)).to eq("wowzers")
end
- it 'marks the resource updated' do
+ it "marks the resource updated" do
expect(resource).to be_updated
end
- it 'logs that it created' do
+ it "logs that it created" do
expect(@info.include?("link[#{target_file}] created")).to be_truthy
end
end
end
- shared_context 'create hard link is noop' do
- describe 'the :create action' do
+ shared_context "create hard link is noop" do
+ describe "the :create action" do
before(:each) do
@info = []
allow(Chef::Log).to receive(:info) { |msg| @info << msg }
resource.run_action(:create)
end
- it 'links to the target file' do
+ it "links to the target file" do
expect(File.exists?(target_file)).to be_truthy
expect(symlink?(target_file)).to be_falsey
# Writing to one hardlinked file should cause both
# to have the new value.
expect(IO.read(to)).to eq(IO.read(target_file))
- File.open(to, "w") { |file| file.write('wowzers') }
- expect(IO.read(target_file)).to eq('wowzers')
+ File.open(to, "w") { |file| file.write("wowzers") }
+ expect(IO.read(target_file)).to eq("wowzers")
end
- it 'does not mark the resource updated' do
+ it "does not mark the resource updated" do
expect(resource).not_to be_updated
end
- it 'does not log that it created' do
+ it "does not log that it created" do
expect(@info.include?("link[#{target_file}] created")).to be_falsey
end
end
@@ -264,99 +318,111 @@ describe Chef::Resource::Link do
context "is symbolic" do
- context 'when the link destination is a file' do
+ context "when the link destination is a file" do
before(:each) do
File.open(to, "w") do |file|
- file.write('woohoo')
+ file.write("woohoo")
end
end
- context 'and the link does not yet exist' do
- include_context 'create symbolic link succeeds'
- include_context 'delete is noop'
+ context "and the link does not yet exist" do
+ include_context "create symbolic link succeeds"
+ include_context "delete is noop"
end
- context 'and the link already exists and is a symbolic link' do
- context 'pointing at the target' do
+ context "and the link already exists and is a symbolic link" do
+ context "pointing at the target" do
before(:each) do
symlink(to, target_file)
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(to))
end
- include_context 'create symbolic link is noop'
- include_context 'delete succeeds'
- it 'the :delete action does not delete the target file' do
+ include_context "create symbolic link is noop"
+ include_context "delete succeeds"
+ it "the :delete action does not delete the target file" do
resource.run_action(:delete)
expect(File.exists?(to)).to be_truthy
end
end
- context 'pointing somewhere else' do
+ context "pointing somewhere else", :requires_root_or_running_windows do
+ let(:test_user) { "test-link-user" }
+ before do
+ user(test_user).run_action(:create)
+ end
+ after do
+ user(test_user).run_action(:remove)
+ end
before(:each) do
- @other_target = File.join(test_file_dir, make_tmpname('other_spec'))
- File.open(@other_target, 'w') { |file| file.write('eek') }
+ resource.owner(test_user)
+ @other_target = File.join(test_file_dir, make_tmpname("other_spec"))
+ File.open(@other_target, "w") { |file| file.write("eek") }
symlink(@other_target, target_file)
+ chown(target_file, test_user)
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(@other_target))
+ expect(owner(target_file)).to eq(expected_owner)
end
after(:each) do
File.delete(@other_target)
end
- include_context 'create symbolic link succeeds'
- include_context 'delete succeeds'
- it 'the :delete action does not delete the target file' do
+ include_context "create symbolic link succeeds"
+ include_context "delete succeeds"
+ it "the :delete action does not delete the target file" do
resource.run_action(:delete)
expect(File.exists?(to)).to be_truthy
end
end
- context 'pointing nowhere' do
+ context "pointing nowhere" do
before(:each) do
- nonexistent = File.join(test_file_dir, make_tmpname('nonexistent_spec'))
+ nonexistent = File.join(test_file_dir, make_tmpname("nonexistent_spec"))
symlink(nonexistent, target_file)
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(nonexistent))
end
- include_context 'create symbolic link succeeds'
- include_context 'delete succeeds'
+ include_context "create symbolic link succeeds"
+ include_context "delete succeeds"
end
end
- context 'and the link already exists and is a hard link to the file' do
+ context "and the link already exists and is a hard link to the file" do
before(:each) do
link(to, target_file)
expect(File.exists?(target_file)).to be_truthy
expect(symlink?(target_file)).to be_falsey
end
- include_context 'create symbolic link succeeds'
- it_behaves_like 'delete errors out'
+ include_context "create symbolic link succeeds"
+ it_behaves_like "delete errors out"
end
- context 'and the link already exists and is a file' do
+ context "and the link already exists and is a file" do
before(:each) do
- File.open(target_file, 'w') { |file| file.write('eek') }
+ File.open(target_file, "w") { |file| file.write("eek") }
end
- include_context 'create symbolic link succeeds'
- it_behaves_like 'delete errors out'
+ include_context "create symbolic link succeeds"
+ it_behaves_like "delete errors out"
end
- context 'and the link already exists and is a directory' do
+ context "and the link already exists and is a directory" do
before(:each) do
Dir.mkdir(target_file)
end
- it 'create errors out' do
+ it "create errors out" do
if windows?
expect { resource.run_action(:create) }.to raise_error(Errno::EACCES)
- elsif os_x? or solaris? or freebsd? or aix?
+ elsif os_x? || solaris? || freebsd? || aix?
expect { resource.run_action(:create) }.to raise_error(Errno::EPERM)
else
expect { resource.run_action(:create) }.to raise_error(Errno::EISDIR)
end
end
- it_behaves_like 'delete errors out'
+ it_behaves_like "delete errors out"
end
- it_behaves_like 'a securable resource without existing target' do
+ it_behaves_like "a securable resource without existing target" do
let(:path) { target_file }
def allowed_acl(sid, expected_perms)
[ ACE.access_allowed(sid, expected_perms[:specific]) ]
end
+
def denied_acl(sid, expected_perms)
[ ACE.access_denied(sid, expected_perms[:specific]) ]
end
+
def parent_inheritable_acls
dummy_file_path = File.join(test_file_dir, "dummy_file")
FileUtils.touch(dummy_file_path)
@@ -366,27 +432,35 @@ describe Chef::Resource::Link do
end
end
end
- context 'when the link destination is a directory' do
+ context "when the link destination is a directory" do
before(:each) do
Dir.mkdir(to)
end
# On Windows, readlink fails to open the link. FILE_FLAG_OPEN_REPARSE_POINT
# might help, from http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
- context 'and the link does not yet exist' do
- include_context 'create symbolic link succeeds'
- include_context 'delete is noop'
+ context "and the link does not yet exist" do
+ include_context "create symbolic link succeeds"
+ include_context "delete is noop"
end
- context 'and the link already exists and points to a different directory' do
+ context "and the link already exists and points to a different directory" do
before(:each) do
other_dir = File.join(test_file_dir, make_tmpname("other_dir"))
Dir.mkdir(other_dir)
symlink(other_dir, target_file)
end
- include_context 'create symbolic link succeeds'
+ include_context "create symbolic link succeeds"
+ include_context "delete succeeds"
+ end
+ context "and the link already exists and points at the target" do
+ before do
+ symlink(to, target_file)
+ end
+ include_context "create symbolic link is noop"
+ include_context "delete succeeds"
end
end
context "when the link destination is a symbolic link" do
- context 'to a file that exists' do
+ context "to a file that exists" do
before(:each) do
@other_target = File.join(test_file_dir, make_tmpname("other_spec"))
File.open(@other_target, "w") { |file| file.write("eek") }
@@ -397,32 +471,58 @@ describe Chef::Resource::Link do
after(:each) do
File.delete(@other_target)
end
- context 'and the link does not yet exist' do
- include_context 'create symbolic link succeeds'
- include_context 'delete is noop'
+ context "and the link does not yet exist" do
+ include_context "create symbolic link succeeds"
+ include_context "delete is noop"
+ end
+ context "and the destination itself has another symbolic link" do
+ context "to a link that exist" do
+ before do
+ symlink(to, target_file)
+ end
+ include_context "create symbolic link is noop"
+ include_context "delete succeeds"
+ end
+ context "to a link that does not exist" do
+ include_context "create symbolic link succeeds"
+ include_context "delete is noop"
+ end
end
end
- context 'to a file that does not exist' do
+ context "to a file that does not exist" do
before(:each) do
@other_target = File.join(test_file_dir, make_tmpname("other_spec"))
symlink(@other_target, to)
expect(symlink?(to)).to be_truthy
expect(readlink(to)).to eq(canonicalize(@other_target))
end
- context 'and the link does not yet exist' do
- include_context 'create symbolic link succeeds'
- include_context 'delete is noop'
+ context "and the link does not yet exist" do
+ include_context "create symbolic link succeeds"
+ include_context "delete is noop"
+ end
+ context "and the destination itself has another symbolic link" do
+ context "to a link that exist" do
+ before do
+ symlink(to, target_file)
+ end
+ include_context "create symbolic link is noop"
+ include_context "delete succeeds"
+ end
+ context "to a link that does not exist" do
+ include_context "create symbolic link succeeds"
+ include_context "delete is noop"
+ end
end
end
end
context "when the link destination does not exist" do
- include_context 'create symbolic link succeeds'
- include_context 'delete is noop'
+ include_context "create symbolic link succeeds"
+ include_context "delete is noop"
end
{
- '../' => 'with a relative link destination',
- '' => 'with a bare filename for the link destination'
+ "../" => "with a relative link destination",
+ "" => "with a bare filename for the link destination",
}.each do |prefix, desc|
context desc do
let(:to) { "#{prefix}#{File.basename(absolute_to)}" }
@@ -430,27 +530,27 @@ describe Chef::Resource::Link do
before(:each) do
resource.to(to)
end
- context 'when the link does not yet exist' do
- include_context 'create symbolic link succeeds'
- include_context 'delete is noop'
+ context "when the link does not yet exist" do
+ include_context "create symbolic link succeeds"
+ include_context "delete is noop"
end
- context 'when the link already exists and points at the target' do
+ context "when the link already exists and points at the target" do
before(:each) do
symlink(to, target_file)
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(to))
end
- include_context 'create symbolic link is noop'
- include_context 'delete succeeds'
+ include_context "create symbolic link is noop"
+ include_context "delete succeeds"
end
- context 'when the link already exists and points at the target with an absolute path' do
+ context "when the link already exists and points at the target with an absolute path" do
before(:each) do
symlink(absolute_to, target_file)
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(absolute_to))
end
- include_context 'create symbolic link succeeds'
- include_context 'delete succeeds'
+ include_context "create symbolic link succeeds"
+ include_context "delete succeeds"
end
end
end
@@ -464,12 +564,12 @@ describe Chef::Resource::Link do
context "when the link destination is a file" do
before(:each) do
File.open(to, "w") do |file|
- file.write('woohoo')
+ file.write("woohoo")
end
end
context "and the link does not yet exist" do
- include_context 'create hard link succeeds'
- include_context 'delete is noop'
+ include_context "create hard link succeeds"
+ include_context "delete is noop"
end
context "and the link already exists and is a symbolic link pointing at the same file" do
before(:each) do
@@ -477,54 +577,54 @@ describe Chef::Resource::Link do
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(to))
end
- include_context 'create hard link succeeds'
- it_behaves_like 'delete errors out'
+ include_context "create hard link succeeds"
+ it_behaves_like "delete errors out"
end
- context 'and the link already exists and is a hard link to the file' do
+ context "and the link already exists and is a hard link to the file" do
before(:each) do
link(to, target_file)
expect(File.exists?(target_file)).to be_truthy
expect(symlink?(target_file)).to be_falsey
end
- include_context 'create hard link is noop'
- include_context 'delete succeeds'
- it 'the :delete action does not delete the target file' do
+ include_context "create hard link is noop"
+ include_context "delete succeeds"
+ it "the :delete action does not delete the target file" do
resource.run_action(:delete)
expect(File.exists?(to)).to be_truthy
end
end
context "and the link already exists and is a file" do
before(:each) do
- File.open(target_file, 'w') { |file| file.write('tomfoolery') }
+ File.open(target_file, "w") { |file| file.write("tomfoolery") }
end
- include_context 'create hard link succeeds'
- it_behaves_like 'delete errors out'
+ include_context "create hard link succeeds"
+ it_behaves_like "delete errors out"
end
context "and the link already exists and is a directory" do
before(:each) do
Dir.mkdir(target_file)
end
- it 'errors out' do
+ it "errors out" do
if windows?
expect { resource.run_action(:create) }.to raise_error(Errno::EACCES)
- elsif os_x? or solaris? or freebsd? or aix?
+ elsif os_x? || solaris? || freebsd? || aix?
expect { resource.run_action(:create) }.to raise_error(Errno::EPERM)
else
expect { resource.run_action(:create) }.to raise_error(Errno::EISDIR)
end
end
- it_behaves_like 'delete errors out'
+ it_behaves_like "delete errors out"
end
context "and specifies security attributes" do
before(:each) do
- resource.owner(windows? ? 'Guest' : 'nobody')
+ resource.owner(windows? ? "Guest" : "nobody")
end
- it 'ignores them' do
+ it "ignores them" do
resource.run_action(:create)
if windows?
expect(Chef::ReservedNames::Win32::Security.get_named_security_info(target_file).owner).not_to eq(SID.Guest)
else
- expect(File.lstat(target_file).uid).not_to eq(Etc.getpwnam('nobody').uid)
+ expect(File.lstat(target_file).uid).not_to eq(Etc.getpwnam("nobody").uid)
end
end
end
@@ -533,15 +633,15 @@ describe Chef::Resource::Link do
before(:each) do
Dir.mkdir(to)
end
- context 'and the link does not yet exist' do
- it 'create errors out' do
+ context "and the link does not yet exist" do
+ it "create errors out" do
expect { resource.run_action(:create) }.to raise_error(windows? ? Chef::Exceptions::Win32APIError : Errno::EPERM)
end
- include_context 'delete is noop'
+ include_context "delete is noop"
end
end
context "when the link destination is a symbolic link" do
- context 'to a real file' do
+ context "to a real file" do
before(:each) do
@other_target = File.join(test_file_dir, make_tmpname("other_spec"))
File.open(@other_target, "w") { |file| file.write("eek") }
@@ -552,49 +652,44 @@ describe Chef::Resource::Link do
after(:each) do
File.delete(@other_target)
end
- context 'and the link does not yet exist' do
- it 'links to the target file' do
- skip('OS X/FreeBSD/AIX symlink? and readlink working on hard links to symlinks') if (os_x? or freebsd? or aix?)
+ context "and the link does not yet exist" do
+ it "links to the target file" do
+ skip("OS X/FreeBSD/AIX symlink? and readlink working on hard links to symlinks") if os_x? || freebsd? || aix?
resource.run_action(:create)
expect(File.exists?(target_file)).to be_truthy
# OS X gets angry about this sort of link. Bug in OS X, IMO.
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(@other_target))
end
- include_context 'delete is noop'
+ include_context "delete is noop"
end
end
- context 'to a nonexistent file' do
+ context "to a nonexistent file" do
before(:each) do
@other_target = File.join(test_file_dir, make_tmpname("other_spec"))
symlink(@other_target, to)
expect(symlink?(to)).to be_truthy
expect(readlink(to)).to eq(canonicalize(@other_target))
end
- context 'and the link does not yet exist' do
- it 'links to the target file' do
- skip('OS X/FreeBSD/AIX fails to create hardlinks to broken symlinks') if (os_x? or freebsd? or aix?)
+ context "and the link does not yet exist" do
+ it "links to the target file" do
+ skip("OS X/FreeBSD/AIX fails to create hardlinks to broken symlinks") if os_x? || freebsd? || aix?
resource.run_action(:create)
- # Windows and Unix have different definitions of exists? here, and that's OK.
- if windows?
- expect(File.exists?(target_file)).to be_truthy
- else
- expect(File.exists?(target_file)).to be_falsey
- end
+ expect(File.exists?(target_file) || File.symlink?(target_file)).to be_truthy
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(@other_target))
end
- include_context 'delete is noop'
+ include_context "delete is noop"
end
end
end
context "when the link destination does not exist" do
- context 'and the link does not yet exist' do
- it 'create errors out' do
+ context "and the link does not yet exist" do
+ it "create errors out" do
expect { resource.run_action(:create) }.to raise_error(Errno::ENOENT)
end
- include_context 'delete is noop'
+ include_context "delete is noop"
end
end
end
@@ -602,7 +697,7 @@ describe Chef::Resource::Link do
describe "when not supported on platform", :win2k3_only do
it "raises error" do
- expect {resource}.to raise_error(Chef::Exceptions::Win32APIFunctionNotImplemented)
+ expect { resource }.to raise_error(Chef::Exceptions::Win32APIFunctionNotImplemented)
end
end
end
diff --git a/spec/functional/resource/mount_spec.rb b/spec/functional/resource/mount_spec.rb
index a016d12293..c756b0d3d4 100644
--- a/spec/functional/resource/mount_spec.rb
+++ b/spec/functional/resource/mount_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,17 @@
# limitations under the License.
#
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
-require 'tmpdir'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
+require "tmpdir"
# run this test only for following platforms.
-include_flag = !(['ubuntu', 'centos', 'aix', 'solaris2'].include?(ohai[:platform]))
+include_flag = !(%w{ubuntu centos aix solaris2}.include?(ohai[:platform]))
-describe Chef::Resource::Mount, :requires_root, :external => include_flag do
+describe Chef::Resource::Mount, :requires_root, :skip_travis, :external => include_flag do
+ # Disabled in travis because it refuses to let us mount a ramdisk. /dev/ramX does not
+ # exist even after loading the kernel module
include Chef::Mixin::ShellOut
@@ -34,13 +37,11 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
# This can cleaner if we have chef resource/provider for ramdisk.
case ohai[:platform]
when "aix"
- ramdisk = shell_out!("mkramdisk 16M").stdout
-
- # identify device, for /dev/rramdisk0 it is /dev/ramdisk0
- device = ramdisk.tr("\n","").gsub(/\/rramdisk/, '/ramdisk')
-
- fstype = "jfs2"
- shell_out!("mkfs -V #{fstype} #{device}")
+ # On AIX, we can't create a ramdisk inside a WPAR, so we use
+ # a "namefs" mount against / to test
+ # https://www-304.ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.performance/namefs_file_sys.htm
+ device = "/"
+ fstype = "namefs"
when "ubuntu", "centos"
device = "/dev/ram1"
shell_out("ls -1 /dev/ram*").stdout.each_line do |d|
@@ -60,15 +61,6 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
[device, fstype]
end
- def cleanup_device(device)
- case ohai[:platform]
- when "aix"
- ramdisk = device.gsub(/\/ramdisk/, '/rramdisk')
- shell_out("rmramdisk #{ramdisk}")
- else
- end
- end
-
def cleanup_mount(mount_point)
shell_out("umount #{mount_point}")
end
@@ -87,9 +79,9 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
def unix_mount_config_file
case ohai[:platform]
- when 'aix'
+ when "aix"
mount_config = "/etc/filesystems"
- when 'solaris2'
+ when "solaris2"
mount_config = "/etc/vfstab"
else
mount_config = "/etc/fstab"
@@ -98,7 +90,7 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
def mount_should_be_enabled(mount_point, device)
case ohai[:platform]
- when 'aix'
+ when "aix"
expect(shell_out("cat #{unix_mount_config_file} | grep \"#{mount_point}:\" ").exitstatus).to eq(0)
else
expect(shell_out("cat #{unix_mount_config_file} | grep \"#{mount_point}\" | grep \"#{device}\" ").exitstatus).to eq(0)
@@ -114,7 +106,7 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
new_resource.device @device
new_resource.name @mount_point
new_resource.fstype @fstype
- new_resource.options "log=NULL" if ohai[:platform] == 'aix'
+ new_resource.options "log=NULL" if ohai[:platform] == "aix"
new_resource
end
@@ -146,7 +138,6 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
after(:all) do
Dir.rmdir(@mount_point)
- cleanup_device(@device)
end
after(:each) do
@@ -172,10 +163,10 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
mount_should_exist(new_resource.mount_point, new_resource.device)
new_resource.supports[:remount] = true
- new_resource.options "rw,log=NULL" if ohai[:platform] == 'aix'
+ new_resource.options "rw" if ohai[:platform] == "aix"
new_resource.run_action(:remount)
- mount_should_exist(new_resource.mount_point, new_resource.device, nil, (ohai[:platform] == 'aix') ? new_resource.options : nil)
+ mount_should_exist(new_resource.mount_point, new_resource.device, nil, (ohai[:platform] == "aix") ? new_resource.options : nil)
end
end
diff --git a/spec/functional/resource/msu_package_spec.rb b/spec/functional/resource/msu_package_spec.rb
new file mode 100644
index 0000000000..23342be6ae
--- /dev/null
+++ b/spec/functional/resource/msu_package_spec.rb
@@ -0,0 +1,84 @@
+#
+# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/provider/package/cab"
+
+describe Chef::Resource::MsuPackage, :win2012r2_only do
+
+ let(:package_name) { "Package_for_KB2959977" }
+ let(:package_source) { "https://download.microsoft.com/download/3/B/3/3B320C07-B7B1-41E5-81F4-79EBC02DF7D3/Windows8.1-KB2959977-x64.msu" }
+
+ let(:new_resource) { Chef::Resource::CabPackage.new("windows_test_pkg") }
+ let(:cab_provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::Package::Cab.new(new_resource, run_context)
+ end
+
+ subject do
+ new_resource = Chef::Resource::MsuPackage.new("test msu package", run_context)
+ new_resource.package_name package_name
+ new_resource.source package_source
+ new_resource
+ end
+
+ context "installing package" do
+ after { remove_package }
+
+ it "installs the package successfully" do
+ subject.run_action(:install)
+ found_packages = cab_provider.installed_packages.select { |p| p["package_identity"] =~ /^#{package_name}~/ }
+ expect(found_packages.length).to be == 1
+ end
+ end
+
+ context "removing a package" do
+ it "removes an installed package" do
+ subject.run_action(:install)
+ remove_package
+ found_packages = cab_provider.installed_packages.select { |p| p["package_identity"] =~ /^#{package_name}~/ }
+ expect(found_packages.length).to be == 0
+ end
+ end
+
+ context "when an invalid msu package is given" do
+ def package_name
+ "Package_for_KB2859903"
+ end
+
+ def package_source
+ "https://download.microsoft.com/download/5/2/B/52BE95BF-22D8-4415-B644-0FDF398F6D96/IE10-Windows6.1-KB2859903-x86.msu"
+ end
+
+ it "raises error while installing" do
+ expect { subject.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ it "raises error while removing" do
+ expect { subject.run_action(:remove) }.to raise_error(Chef::Exceptions::Package)
+ end
+ end
+
+ def remove_package
+ pkg_to_remove = Chef::Resource::MsuPackage.new(package_name, run_context)
+ pkg_to_remove.source = package_source
+ pkg_to_remove.run_action(:remove)
+ end
+end
diff --git a/spec/functional/resource/ohai_spec.rb b/spec/functional/resource/ohai_spec.rb
index da47b9e140..06bccfc398 100644
--- a/spec/functional/resource/ohai_spec.rb
+++ b/spec/functional/resource/ohai_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,23 +16,21 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Ohai do
- let(:ohai) {
- o = Ohai::System.new
- o.all_plugins
- o
- }
+ let(:ohai) do
+ OHAI_SYSTEM
+ end
let(:node) { Chef::Node.new }
- let(:run_context) {
+ let(:run_context) do
node.default[:platform] = ohai[:platform]
node.default[:platform_version] = ohai[:platform_version]
events = Chef::EventDispatch::Dispatcher.new
Chef::RunContext.new(node, {}, events)
- }
+ end
shared_examples_for "reloaded :uptime" do
it "should reload :uptime" do
@@ -47,18 +45,17 @@ describe Chef::Resource::Ohai do
end
describe "when reloading all plugins" do
- let(:ohai_resource) { Chef::Resource::Ohai.new("reload all", run_context)}
+ let(:ohai_resource) { Chef::Resource::Ohai.new("reload all", run_context) }
it_behaves_like "reloaded :uptime"
end
describe "when reloading only uptime" do
- let(:ohai_resource) {
+ let(:ohai_resource) do
r = Chef::Resource::Ohai.new("reload all", run_context)
r.plugin("uptime")
r
- }
-
+ end
it_behaves_like "reloaded :uptime"
end
diff --git a/spec/functional/resource/package_spec.rb b/spec/functional/resource/package_spec.rb
index 8d37b072e8..0f01a751ec 100644
--- a/spec/functional/resource/package_spec.rb
+++ b/spec/functional/resource/package_spec.rb
@@ -1,7 +1,7 @@
# encoding: UTF-8
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'webrick'
+require "spec_helper"
+require "webrick"
module AptServer
def enable_testing_apt_source
@@ -66,7 +66,7 @@ module AptServer
@apt_server_thread = Thread.new do
run_apt_server
end
- until tcp_test_port("localhost", 9000) do
+ until tcp_test_port("localhost", 9000)
if @apt_server_thread.alive?
sleep 1
else
@@ -87,9 +87,9 @@ module AptServer
end
metadata = { :unix_only => true,
- :requires_root => true,
- :provider => {:package => Chef::Provider::Package::Apt},
- :arch => "x86_64" # test packages are 64bit
+ :requires_root => true,
+ :provider => { :package => Chef::Provider::Package::Apt },
+ :arch => "x86_64" # test packages are 64bit
}
describe Chef::Resource::Package, metadata do
@@ -112,7 +112,6 @@ describe Chef::Resource::Package, metadata do
shell_out!("apt-get clean")
end
-
after do
shell_out!("dpkg -r chef-integration-test")
shell_out("dpkg --clear-avail")
@@ -239,7 +238,7 @@ describe Chef::Resource::Package, metadata do
it "does not update the package configuration" do
package_resource.run_action(:install)
cmd = shell_out!("debconf-show chef-integration-test")
- expect(cmd.stdout).to include('chef-integration-test/sample-var: INVALID')
+ expect(cmd.stdout).to include("chef-integration-test/sample-var: INVALID")
expect(package_resource).to be_updated_by_last_action
end
@@ -261,7 +260,7 @@ describe Chef::Resource::Package, metadata do
end
before do
- node.set[:preseed_value] = "FROM TEMPLATE"
+ node.normal[:preseed_value] = "FROM TEMPLATE"
end
it "preseeds the package, then installs it" do
@@ -276,7 +275,7 @@ describe Chef::Resource::Package, metadata do
r = base_resource
r.cookbook_name = "preseed"
r.response_file("preseed-template-variables.seed")
- r.response_file_variables({ :template_variable => 'SUPPORTS VARIABLES' })
+ r.response_file_variables({ :template_variable => "SUPPORTS VARIABLES" })
r
end
@@ -325,14 +324,13 @@ describe Chef::Resource::Package, metadata do
# un chef-integration-test <none> (no description available)
def pkg_should_be_removed
# will raise if exit code != 0,1
- pkg_check = shell_out!("dpkg -l chef-integration-test", :returns => [0,1])
+ pkg_check = shell_out!("dpkg -l chef-integration-test", :returns => [0, 1])
if pkg_check.exitstatus == 0
expect(pkg_check.stdout).to match(/un[\s]+chef-integration-test/)
end
end
-
it "removes the package for action :remove" do
package_resource.run_action(:remove)
pkg_should_be_removed
diff --git a/spec/functional/resource/powershell_script_spec.rb b/spec/functional/resource/powershell_script_spec.rb
index 91b74fd752..af345b0ea4 100644
--- a/spec/functional/resource/powershell_script_spec.rb
+++ b/spec/functional/resource/powershell_script_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'chef/platform/query_helpers'
-require 'spec_helper'
+require "chef/platform/query_helpers"
+require "spec_helper"
describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
include_context Chef::Resource::WindowsScript
- let (:architecture_command) { 'echo $env:PROCESSOR_ARCHITECTURE' }
- let (:output_command) { ' | out-file -encoding ASCII ' }
+ let (:architecture_command) { "echo $env:PROCESSOR_ARCHITECTURE" }
+ let (:output_command) { " | out-file -encoding ASCII " }
it_behaves_like "a Windows script running on Windows"
@@ -59,7 +59,7 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
it "returns the exit status 27 for a powershell script that exits with 27" do
pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
- file = Tempfile.new(['foo', '.ps1'])
+ file = Tempfile.new(["foo", ".ps1"])
begin
file.write "exit 27"
file.close
@@ -79,9 +79,9 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
# Versions of PowerShell prior to 4.0 return a 16-bit unsigned value --
# PowerShell 4.0 and later versions return a 32-bit signed value.
- file = Tempfile.new(['foo', '.ps1'])
+ file = Tempfile.new(["foo", ".ps1"])
begin
- file.write "exit #{negative_exit_status.to_s}"
+ file.write "exit #{negative_exit_status}"
file.close
resource.code(". \"#{file.path}\"")
@@ -114,7 +114,7 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
end
it "returns 0 if the last command was a cmdlet that succeeded and was preceded by a non-cmdlet Windows binary that failed" do
- resource.code([windows_process_exit_code_not_found_content, cmdlet_exit_code_success_content].join(';'))
+ resource.code([windows_process_exit_code_not_found_content, cmdlet_exit_code_success_content].join(";"))
resource.returns(0)
resource.run_action(:run)
end
@@ -130,7 +130,7 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
it "returns 1 if the last command was a cmdlet that failed and was preceded by a successfully executed non-cmdlet Windows binary" do
pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
- resource.code([windows_process_exit_code_success_content, cmdlet_exit_code_not_found_content].join(';'))
+ resource.code([windows_process_exit_code_success_content, cmdlet_exit_code_not_found_content].join(";"))
resource.returns(1)
expect { resource.run_action(:run) }.not_to raise_error
end
@@ -138,7 +138,7 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
it "raises a Mixlib::ShellOut::ShellCommandFailed error if the script is not syntactically correct" do
pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
- resource.code('if({)')
+ resource.code("if({)")
resource.returns(0)
expect { resource.run_action(:run) }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
end
@@ -148,7 +148,7 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
# The error is a false-positive.
skip "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
- resource.code('if({)')
+ resource.code("if({)")
resource.returns(1)
expect { resource.run_action(:run) }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
end
@@ -164,7 +164,7 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
it "returns 1 if the last command was a cmdlet that failed and was preceded by an unsuccessfully executed non-cmdlet Windows binary" do
pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
- resource.code([arbitrary_nonzero_process_exit_code_content,cmdlet_exit_code_not_found_content].join(';'))
+ resource.code([arbitrary_nonzero_process_exit_code_content, cmdlet_exit_code_not_found_content].join(";"))
resource.returns(arbitrary_nonzero_process_exit_code)
resource.run_action(:run)
end
@@ -172,7 +172,7 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
it "returns 0 if the last command was a non-cmdlet Windows binary that succeeded and was preceded by a failed cmdlet" do
pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
- resource.code([cmdlet_exit_code_success_content, arbitrary_nonzero_process_exit_code_content].join(';'))
+ resource.code([cmdlet_exit_code_success_content, arbitrary_nonzero_process_exit_code_content].join(";"))
resource.returns(arbitrary_nonzero_process_exit_code)
resource.run_action(:run)
end
@@ -180,7 +180,7 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
it "returns a specific error code if the last command was a non-cmdlet Windows binary that failed and was preceded by cmdlet that succeeded" do
pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
- resource.code([cmdlet_exit_code_success_content, arbitrary_nonzero_process_exit_code_content].join(';'))
+ resource.code([cmdlet_exit_code_success_content, arbitrary_nonzero_process_exit_code_content].join(";"))
resource.returns(arbitrary_nonzero_process_exit_code)
resource.run_action(:run)
end
@@ -188,7 +188,7 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
it "returns a specific error code if the last command was a non-cmdlet Windows binary that failed and was preceded by cmdlet that failed" do
pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
- resource.code([cmdlet_exit_code_not_found_content, arbitrary_nonzero_process_exit_code_content].join(';'))
+ resource.code([cmdlet_exit_code_not_found_content, arbitrary_nonzero_process_exit_code_content].join(";"))
resource.returns(arbitrary_nonzero_process_exit_code)
resource.run_action(:run)
end
@@ -226,9 +226,9 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
resource.returns(0)
resource.run_action(:run)
- is_64_bit = (ENV['PROCESSOR_ARCHITECTURE'] == 'AMD64') || (ENV['PROCESSOR_ARCHITEW6432'] == 'AMD64')
+ is_64_bit = (ENV["PROCESSOR_ARCHITECTURE"] == "AMD64") || (ENV["PROCESSOR_ARCHITEW6432"] == "AMD64")
- detected_64_bit = source_contains_case_insensitive_content?( get_script_output, 'AMD64' )
+ detected_64_bit = source_contains_case_insensitive_content?( get_script_output, "AMD64" )
expect(is_64_bit).to eq(detected_64_bit)
end
@@ -280,7 +280,7 @@ configuration LCM
resource.returns(0)
resource.run_action(:run)
- expect(source_contains_case_insensitive_content?( get_script_output, 'x86' )).to eq(true)
+ expect(source_contains_case_insensitive_content?( get_script_output, "x86" )).to eq(true)
end
context "when running on a 64-bit version of Windows", :windows64_only do
@@ -290,7 +290,7 @@ configuration LCM
resource.returns(0)
resource.run_action(:run)
- expect(source_contains_case_insensitive_content?( get_script_output, 'AMD64' )).to eq(true)
+ expect(source_contains_case_insensitive_content?( get_script_output, "AMD64" )).to eq(true)
end
end
@@ -311,7 +311,7 @@ configuration LCM
resource.returns(0)
resource.run_action(:run)
- expect(source_contains_case_insensitive_content?( get_script_output, 'AMD64' )).to eq(true)
+ expect(source_contains_case_insensitive_content?( get_script_output, "AMD64" )).to eq(true)
end
it "executes a script with a 32-bit process if :i386 arch is specified", :not_supported_on_nano do
@@ -320,12 +320,12 @@ configuration LCM
resource.returns(0)
resource.run_action(:run)
- expect(source_contains_case_insensitive_content?( get_script_output, 'x86' )).to eq(true)
+ expect(source_contains_case_insensitive_content?( get_script_output, "x86" )).to eq(true)
end
it "raises an error when executing a script with a 32-bit process on Windows Nano Server", :windows_nano_only do
resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}")
- expect{ resource.architecture(:i386) }.to raise_error(Chef::Exceptions::Win32ArchitectureIncorrect,
+ expect { resource.architecture(:i386) }.to raise_error(Chef::Exceptions::Win32ArchitectureIncorrect,
"cannot execute script with requested architecture 'i386' on Windows Nano Server")
end
end
@@ -342,22 +342,22 @@ configuration LCM
end
it "evaluates a succeeding not_if block using cmd.exe as false by default" do
- resource.not_if "exit /b 0"
+ resource.not_if "exit /b 0"
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates a failing not_if block using cmd.exe as true by default" do
- resource.not_if "exit /b 2"
+ resource.not_if "exit /b 2"
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates an succeeding only_if block using cmd.exe as true by default" do
- resource.only_if "exit /b 0"
+ resource.only_if "exit /b 0"
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a failing only_if block using cmd.exe as false by default" do
- resource.only_if "exit /b 2"
+ resource.only_if "exit /b 2"
expect(resource.should_skip?(:run)).to be_truthy
end
end
@@ -383,126 +383,126 @@ configuration LCM
it "evaluates a powershell $false for a not_if block as true" do
pending "powershell.exe always exits with $true on nano" if Chef::Platform.windows_nano_server?
- resource.not_if "$false"
+ resource.not_if "$false"
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a powershell $true for a not_if block as false" do
- resource.not_if "$true"
+ resource.not_if "$true"
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates a powershell $false for an only_if block as false" do
pending "powershell.exe always exits with $true on nano" if Chef::Platform.windows_nano_server?
- resource.only_if "$false"
+ resource.only_if "$false"
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates a powershell $true for a only_if block as true" do
- resource.only_if "$true"
+ resource.only_if "$true"
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a not_if block using powershell.exe" do
- resource.not_if "exit([int32](![System.Environment]::CommandLine.Contains('powershell.exe')))"
+ resource.not_if "exit([int32](![System.Environment]::CommandLine.Contains('powershell.exe')))"
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates an only_if block using powershell.exe" do
- resource.only_if "exit([int32](![System.Environment]::CommandLine.Contains('powershell.exe')))"
+ resource.only_if "exit([int32](![System.Environment]::CommandLine.Contains('powershell.exe')))"
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a non-zero powershell exit status for not_if as true" do
pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
- resource.not_if "exit 37"
+ resource.not_if "exit 37"
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a zero powershell exit status for not_if as false" do
- resource.not_if "exit 0"
+ resource.not_if "exit 0"
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates a failed executable exit status for not_if as false" do
pending "powershell.exe always exits with success on nano" if Chef::Platform.windows_nano_server?
- resource.not_if windows_process_exit_code_not_found_content
+ resource.not_if windows_process_exit_code_not_found_content
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a successful executable exit status for not_if as true" do
- resource.not_if windows_process_exit_code_success_content
+ resource.not_if windows_process_exit_code_success_content
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates a failed executable exit status for only_if as false" do
pending "powershell.exe always exits with success on nano" if Chef::Platform.windows_nano_server?
- resource.only_if windows_process_exit_code_not_found_content
+ resource.only_if windows_process_exit_code_not_found_content
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates a successful executable exit status for only_if as true" do
- resource.only_if windows_process_exit_code_success_content
+ resource.only_if windows_process_exit_code_success_content
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a failed cmdlet exit status for not_if as true" do
pending "powershell.exe always exits with success on nano" if Chef::Platform.windows_nano_server?
- resource.not_if "throw 'up'"
+ resource.not_if "throw 'up'"
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a successful cmdlet exit status for not_if as true" do
- resource.not_if "cd ."
+ resource.not_if "cd ."
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates a failed cmdlet exit status for only_if as false" do
pending "powershell.exe always exits with success on nano" if Chef::Platform.windows_nano_server?
- resource.only_if "throw 'up'"
+ resource.only_if "throw 'up'"
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates a successful cmdlet exit status for only_if as true" do
- resource.only_if "cd ."
+ resource.only_if "cd ."
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a not_if block using the cwd guard parameter" do
custom_cwd = "#{ENV['SystemRoot']}\\system32\\drivers\\etc"
- resource.not_if "exit ! [int32]($pwd.path -eq '#{custom_cwd}')", :cwd => custom_cwd
+ resource.not_if "exit ! [int32]($pwd.path -eq '#{custom_cwd}')", :cwd => custom_cwd
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates an only_if block using the cwd guard parameter" do
custom_cwd = "#{ENV['SystemRoot']}\\system32\\drivers\\etc"
- resource.only_if "exit ! [int32]($pwd.path -eq '#{custom_cwd}')", :cwd => custom_cwd
+ resource.only_if "exit ! [int32]($pwd.path -eq '#{custom_cwd}')", :cwd => custom_cwd
expect(resource.should_skip?(:run)).to be_falsey
end
it "inherits cwd from the parent resource for only_if" do
custom_cwd = "#{ENV['SystemRoot']}\\system32\\drivers\\etc"
resource.cwd custom_cwd
- resource.only_if "exit ! [int32]($pwd.path -eq '#{custom_cwd}')"
+ resource.only_if "exit ! [int32]($pwd.path -eq '#{custom_cwd}')"
expect(resource.should_skip?(:run)).to be_falsey
end
it "inherits cwd from the parent resource for not_if" do
custom_cwd = "#{ENV['SystemRoot']}\\system32\\drivers\\etc"
resource.cwd custom_cwd
- resource.not_if "exit ! [int32]($pwd.path -eq '#{custom_cwd}')"
+ resource.not_if "exit ! [int32]($pwd.path -eq '#{custom_cwd}')"
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates a 64-bit resource with a 64-bit guard and interprets boolean false as zero status code", :windows64_only do
resource.architecture :x86_64
- resource.only_if "exit [int32]($env:PROCESSOR_ARCHITECTURE -ne 'AMD64')"
+ resource.only_if "exit [int32]($env:PROCESSOR_ARCHITECTURE -ne 'AMD64')"
expect(resource.should_skip?(:run)).to be_falsey
end
@@ -510,19 +510,19 @@ configuration LCM
pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
resource.architecture :x86_64
- resource.only_if "exit [int32]($env:PROCESSOR_ARCHITECTURE -eq 'AMD64')"
+ resource.only_if "exit [int32]($env:PROCESSOR_ARCHITECTURE -eq 'AMD64')"
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean false as zero status code", :not_supported_on_nano do
resource.architecture :i386
- resource.only_if "exit [int32]($env:PROCESSOR_ARCHITECTURE -ne 'X86')"
+ resource.only_if "exit [int32]($env:PROCESSOR_ARCHITECTURE -ne 'X86')"
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean true as nonzero status code", :not_supported_on_nano do
resource.architecture :i386
- resource.only_if "exit [int32]($env:PROCESSOR_ARCHITECTURE -eq 'X86')"
+ resource.only_if "exit [int32]($env:PROCESSOR_ARCHITECTURE -eq 'X86')"
expect(resource.should_skip?(:run)).to be_truthy
end
@@ -530,7 +530,7 @@ configuration LCM
pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
resource.convert_boolean_return true
- resource.only_if "$false"
+ resource.only_if "$false"
expect(resource.should_skip?(:run)).to be_truthy
end
@@ -538,53 +538,53 @@ configuration LCM
pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
resource.convert_boolean_return true
- resource.not_if "$false"
+ resource.not_if "$false"
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a simple boolean true as 0 status code when convert_boolean_return is true for only_if" do
resource.convert_boolean_return true
- resource.only_if "$true"
+ resource.only_if "$true"
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a simple boolean true as 0 status code when convert_boolean_return is true for not_if" do
resource.convert_boolean_return true
- resource.not_if "$true"
+ resource.not_if "$true"
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean false as zero status code using convert_boolean_return for only_if", :not_supported_on_nano do
resource.convert_boolean_return true
resource.architecture :i386
- resource.only_if "$env:PROCESSOR_ARCHITECTURE -eq 'X86'"
+ resource.only_if "$env:PROCESSOR_ARCHITECTURE -eq 'X86'"
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean false as zero status code using convert_boolean_return for not_if", :not_supported_on_nano do
resource.convert_boolean_return true
resource.architecture :i386
- resource.not_if "$env:PROCESSOR_ARCHITECTURE -ne 'X86'"
+ resource.not_if "$env:PROCESSOR_ARCHITECTURE -ne 'X86'"
expect(resource.should_skip?(:run)).to be_falsey
end
it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean true as nonzero status code using convert_boolean_return for only_if", :not_supported_on_nano do
resource.convert_boolean_return true
resource.architecture :i386
- resource.only_if "$env:PROCESSOR_ARCHITECTURE -ne 'X86'"
+ resource.only_if "$env:PROCESSOR_ARCHITECTURE -ne 'X86'"
expect(resource.should_skip?(:run)).to be_truthy
end
it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean true as nonzero status code using convert_boolean_return for not_if", :not_supported_on_nano do
resource.convert_boolean_return true
resource.architecture :i386
- resource.not_if "$env:PROCESSOR_ARCHITECTURE -eq 'X86'"
+ resource.not_if "$env:PROCESSOR_ARCHITECTURE -eq 'X86'"
expect(resource.should_skip?(:run)).to be_truthy
end
it "raises an error when a 32-bit guard is used on Windows Nano Server", :windows_nano_only do
resource.only_if "$true", :architecture => :i386
- expect{resource.run_action(:run)}.to raise_error(
+ expect { resource.run_action(:run) }.to raise_error(
Chef::Exceptions::Win32ArchitectureIncorrect,
/cannot execute script with requested architecture 'i386' on Windows Nano Server/)
end
diff --git a/spec/functional/resource/reboot_spec.rb b/spec/functional/resource/reboot_spec.rb
index 99de136827..c264b122a7 100644
--- a/spec/functional/resource/reboot_spec.rb
+++ b/spec/functional/resource/reboot_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Chris Doherty <cdoherty@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef, Inc.
+# Author:: Chris Doherty <cdoherty@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Reboot do
@@ -24,7 +24,7 @@ describe Chef::Resource::Reboot do
{
:delay_mins => 5,
:requested_by => "reboot resource functional test",
- :reason => "reboot resource spec test"
+ :reason => "reboot resource spec test",
}
end
@@ -42,7 +42,7 @@ describe Chef::Resource::Reboot do
create_resource
end
- shared_context 'testing run context modification' do
+ shared_context "testing run context modification" do
def test_reboot_action(resource)
reboot_info = resource.run_context.reboot_info
expect(reboot_info.keys.sort).to eq([:delay_mins, :reason, :requested_by, :timestamp])
@@ -55,8 +55,8 @@ describe Chef::Resource::Reboot do
end
# the currently defined behavior for multiple calls to this resource is "last one wins."
- describe 'the request_reboot_on_successful_run action' do
- include_context 'testing run context modification'
+ describe "the request_reboot_on_successful_run action" do
+ include_context "testing run context modification"
before do
resource.run_action(:request_reboot)
@@ -66,23 +66,23 @@ describe Chef::Resource::Reboot do
resource.run_context.cancel_reboot
end
- it 'should have modified the run context correctly' do
+ it "should have modified the run context correctly" do
test_reboot_action(resource)
end
end
- describe 'the reboot_interrupt_run action' do
- include_context 'testing run context modification'
+ describe "the reboot_interrupt_run action" do
+ include_context "testing run context modification"
after do
resource.run_context.cancel_reboot
end
- it 'should have modified the run context correctly' do
+ it "should have modified the run context correctly" do
# this doesn't actually test the flow of Chef::Client#do_run, unfortunately.
- expect {
+ expect do
resource.run_action(:reboot_now)
- }.to throw_symbol(:end_client_run_early)
+ end.to throw_symbol(:end_client_run_early)
test_reboot_action(resource)
end
@@ -94,7 +94,7 @@ describe Chef::Resource::Reboot do
resource.run_action(:cancel)
end
- it 'should have cleared the reboot request' do
+ it "should have cleared the reboot request" do
# arguably we shouldn't be querying RunContext's internal data directly.
expect(resource.run_context.reboot_info).to eq({})
expect(resource.run_context.reboot_requested?).to be_falsey
diff --git a/spec/functional/resource/registry_spec.rb b/spec/functional/resource/registry_spec.rb
index f112ad9b00..5c97626c78 100644
--- a/spec/functional/resource/registry_spec.rb
+++ b/spec/functional/resource/registry_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Prajakta Purohit (<prajakta@opscode.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta@chef.io>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,15 +27,15 @@ describe Chef::Resource::RegistryKey, :unix_only do
node = Chef::Node.new
ohai = Ohai::System.new
ohai.all_plugins
- node.consume_external_attrs(ohai.data,{})
+ node.consume_external_attrs(ohai.data, {})
run_context = Chef::RunContext.new(node, {}, events)
@resource = Chef::Resource::RegistryKey.new("HKCU\\Software", run_context)
end
context "when load_current_resource is run on a non-windows node" do
it "throws an exception because you don't have a windows registry (derp)" do
@resource.key("HKCU\\Software\\Opscode")
- @resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}])
- expect{@resource.run_action(:create)}.to raise_error(Chef::Exceptions::Win32NotWindows)
+ @resource.values([{ :name => "Color", :type => :string, :data => "Orange" }])
+ expect { @resource.run_action(:create) }.to raise_error(Chef::Exceptions::Win32NotWindows)
end
end
end
@@ -43,8 +43,8 @@ end
describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
# parent and key must be single keys, not paths
- let(:parent) { 'Opscode' }
- let(:child) { 'Whatever' }
+ let(:parent) { "Opscode" }
+ let(:child) { "Whatever" }
let(:key_parent) { "SOFTWARE\\" + parent }
let(:key_child) { "SOFTWARE\\" + parent + "\\" + child }
# must be under HKLM\SOFTWARE for WOW64 redirection to work
@@ -78,7 +78,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
hive_class.create(key_parent + '\Opscode', Win32::Registry::KEY_WRITE | flag)
hive_class.open(key_parent + '\Opscode', Win32::Registry::KEY_ALL_ACCESS | flag) do |reg|
reg["Color", Win32::Registry::REG_SZ] = "Orange"
- reg.write("Opscode", Win32::Registry::REG_MULTI_SZ, ["Seattle", "Washington"])
+ reg.write("Opscode", Win32::Registry::REG_MULTI_SZ, %w{Seattle Washington})
reg["AKA", Win32::Registry::REG_SZ] = "OC"
end
hive_class.create(key_parent + '\ReportKey', Win32::Registry::KEY_WRITE | flag)
@@ -98,7 +98,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
@node = Chef::Node.new
ohai = Ohai::System.new
ohai.all_plugins
- @node.consume_external_attrs(ohai.data,{})
+ @node.consume_external_attrs(ohai.data, {})
@run_context = Chef::RunContext.new(@node, {}, @events)
@new_resource = Chef::Resource::RegistryKey.new(resource_name, @run_context)
@@ -111,10 +111,10 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
before do
@node.name("windowsbox")
- @rest_client = double("Chef::REST (mock)")
- allow(@rest_client).to receive(:create_url).and_return("reports/nodes/windowsbox/runs/#{@run_id}");
- allow(@rest_client).to receive(:raw_http_request).and_return({"result"=>"ok"});
- allow(@rest_client).to receive(:post_rest).and_return({"uri"=>"https://example.com/reports/nodes/windowsbox/runs/#{@run_id}"});
+ @rest_client = double("Chef::ServerAPI (mock)")
+ allow(@rest_client).to receive(:create_url).and_return("reports/nodes/windowsbox/runs/#{@run_id}")
+ allow(@rest_client).to receive(:raw_http_request).and_return({ "result" => "ok" })
+ allow(@rest_client).to receive(:post_rest).and_return({ "uri" => "https://example.com/reports/nodes/windowsbox/runs/#{@run_id}" })
@resource_reporter = Chef::ResourceReporter.new(@rest_client)
@events.register(@resource_reporter)
@@ -122,7 +122,6 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
@resource_reporter.run_started(@run_status)
@run_id = @resource_reporter.run_id
-
@new_resource.cookbook_name = "monkey"
@cookbook_version = double("Cookbook::Version", :version => "1.2.3")
allow(@new_resource).to receive(:cookbook_version).and_return(@cookbook_version)
@@ -138,76 +137,110 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
end
it "creates registry key, value if the key is missing" do
@new_resource.key(reg_child)
- @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}])
+ @new_resource.values([{ :name => "Color", :type => :string, :data => "Orange" }])
@new_resource.run_action(:create)
expect(@registry.key_exists?(reg_child)).to eq(true)
- expect(@registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
+ expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
end
it "does not create the key if it already exists with same value, type and data" do
@new_resource.key(reg_child)
- @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}])
+ @new_resource.values([{ :name => "Color", :type => :string, :data => "Orange" }])
+ @new_resource.run_action(:create)
+
+ expect(@registry.key_exists?(reg_child)).to eq(true)
+ expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
+ end
+
+ it "does not create the key if it already exists with same value and type but datatype of data differs" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "number", :type => :dword, :data => "12345" }])
@new_resource.run_action(:create)
+ expect(@new_resource).not_to be_updated_by_last_action
expect(@registry.key_exists?(reg_child)).to eq(true)
- expect(@registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
+ expect(@registry.data_exists?(reg_child, { :name => "number", :type => :dword, :data => 12344 })).to eq(true)
end
it "creates a value if it does not exist" do
@new_resource.key(reg_child)
- @new_resource.values([{:name=>"Mango", :type=>:string, :data=>"Yellow"}])
+ @new_resource.values([{ :name => "Mango", :type => :string, :data => "Yellow" }])
@new_resource.run_action(:create)
- expect(@registry.data_exists?(reg_child, {:name=>"Mango", :type=>:string, :data=>"Yellow"})).to eq(true)
+ expect(@registry.data_exists?(reg_child, { :name => "Mango", :type => :string, :data => "Yellow" })).to eq(true)
end
it "modifies the data if the key and value exist and type matches" do
@new_resource.key(reg_child)
- @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Not just Orange - OpscodeOrange!"}])
+ @new_resource.values([{ :name => "Color", :type => :string, :data => "Not just Orange - OpscodeOrange!" }])
@new_resource.run_action(:create)
- expect(@registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Not just Orange - OpscodeOrange!"})).to eq(true)
+ expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :string, :data => "Not just Orange - OpscodeOrange!" })).to eq(true)
end
it "modifys the type if the key and value exist and the type does not match" do
@new_resource.key(reg_child)
- @new_resource.values([{:name=>"Color", :type=>:multi_string, :data=>["Not just Orange - OpscodeOrange!"]}])
+ @new_resource.values([{ :name => "Color", :type => :multi_string, :data => ["Not just Orange - OpscodeOrange!"] }])
@new_resource.run_action(:create)
- expect(@registry.data_exists?(reg_child, {:name=>"Color", :type=>:multi_string, :data=>["Not just Orange - OpscodeOrange!"]})).to eq(true)
+ expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :multi_string, :data => ["Not just Orange - OpscodeOrange!"] })).to eq(true)
end
it "creates subkey if parent exists" do
@new_resource.key(reg_child + '\OpscodeTest')
- @new_resource.values([{:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]}])
+ @new_resource.values([{ :name => "Chef", :type => :multi_string, :data => %w{OpscodeOrange Rules} }])
@new_resource.recursive(false)
@new_resource.run_action(:create)
expect(@registry.key_exists?(reg_child + '\OpscodeTest')).to eq(true)
- expect(@registry.value_exists?(reg_child + '\OpscodeTest', {:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]})).to eq(true)
+ expect(@registry.value_exists?(reg_child + '\OpscodeTest', { :name => "Chef", :type => :multi_string, :data => %w{OpscodeOrange Rules} })).to eq(true)
end
- it "gives error if action create and parent does not exist and recursive is set to false" do
+ it "raises an error if action create and parent does not exist and recursive is set to false" do
@new_resource.key(reg_child + '\Missing1\Missing2')
- @new_resource.values([{:name=>"OC", :type=>:string, :data=>"MissingData"}])
+ @new_resource.values([{ :name => "OC", :type => :string, :data => "MissingData" }])
@new_resource.recursive(false)
- expect{@new_resource.run_action(:create)}.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+ expect { @new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+ end
+
+ it "raises an error if action create and type key missing in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC", :data => "my_data" }])
+ expect { @new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::RegKeyValuesTypeMissing)
+ end
+
+ it "raises an error if action create and data key missing in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC", :type => :string }])
+ expect { @new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::RegKeyValuesDataMissing)
+ end
+
+ it "raises an error if action create and only name key present in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC" }])
+ expect { @new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::RegKeyValuesTypeMissing)
+ end
+
+ it "does not raise an error if action create and all keys are present in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC", :type => :string, :data => "my_data" }])
+ expect { @new_resource.run_action(:create) }.to_not raise_error
end
it "creates missing keys if action create and parent does not exist and recursive is set to true" do
@new_resource.key(reg_child + '\Missing1\Missing2')
- @new_resource.values([{:name=>"OC", :type=>:string, :data=>"MissingData"}])
+ @new_resource.values([{ :name => "OC", :type => :string, :data => "MissingData" }])
@new_resource.recursive(true)
@new_resource.run_action(:create)
expect(@registry.key_exists?(reg_child + '\Missing1\Missing2')).to eq(true)
- expect(@registry.value_exists?(reg_child + '\Missing1\Missing2', {:name=>"OC", :type=>:string, :data=>"MissingData"})).to eq(true)
+ expect(@registry.value_exists?(reg_child + '\Missing1\Missing2', { :name => "OC", :type => :string, :data => "MissingData" })).to eq(true)
end
it "creates key with multiple value as specified" do
@new_resource.key(reg_child)
- @new_resource.values([{:name=>"one", :type=>:string, :data=>"1"},{:name=>"two", :type=>:string, :data=>"2"},{:name=>"three", :type=>:string, :data=>"3"}])
+ @new_resource.values([{ :name => "one", :type => :string, :data => "1" }, { :name => "two", :type => :string, :data => "2" }, { :name => "three", :type => :string, :data => "3" }])
@new_resource.recursive(true)
@new_resource.run_action(:create)
@@ -226,12 +259,12 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
end
it "creates a key in a 32-bit registry that is not viewable in 64-bit" do
@new_resource.key(reg_child + '\Atraxi' )
- @new_resource.values([{:name=>"OC", :type=>:string, :data=>"Data"}])
+ @new_resource.values([{ :name => "OC", :type => :string, :data => "Data" }])
@new_resource.recursive(true)
@new_resource.architecture(:i386)
@new_resource.run_action(:create)
@registry.architecture = :i386
- expect(@registry.data_exists?(reg_child + '\Atraxi', {:name=>"OC", :type=>:string, :data=>"Data"})).to eq(true)
+ expect(@registry.data_exists?(reg_child + '\Atraxi', { :name => "OC", :type => :string, :data => "Data" })).to eq(true)
@registry.architecture = :x86_64
expect(@registry.key_exists?(reg_child + '\Atraxi')).to eq(false)
end
@@ -239,7 +272,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
it "prepares the reporting data for action :create" do
@new_resource.key(reg_child + '\Ood')
- @new_resource.values([{:name=>"ReportingVal1", :type=>:string, :data=>"report1"},{:name=>"ReportingVal2", :type=>:string, :data=>"report2"}])
+ @new_resource.values([{ :name => "ReportingVal1", :type => :string, :data => "report1" }, { :name => "ReportingVal2", :type => :string, :data => "report2" }])
@new_resource.recursive(true)
@new_resource.run_action(:create)
@report = @resource_reporter.prepare_run_data
@@ -248,8 +281,8 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
expect(@report["resources"][0]["type"]).to eq("registry_key")
expect(@report["resources"][0]["name"]).to eq(resource_name)
expect(@report["resources"][0]["id"]).to eq(reg_child + '\Ood')
- expect(@report["resources"][0]["after"][:values]).to eq([{:name=>"ReportingVal1", :type=>:string, :data=>"report1"},
- {:name=>"ReportingVal2", :type=>:string, :data=>"report2"}])
+ expect(@report["resources"][0]["after"][:values]).to eq([{ :name => "ReportingVal1", :type => :string, :data => "report1" },
+ { :name => "ReportingVal2", :type => :string, :data => "report2" }])
expect(@report["resources"][0]["before"][:values]).to eq([])
expect(@report["resources"][0]["result"]).to eq("create")
expect(@report["status"]).to eq("success")
@@ -261,21 +294,50 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
Chef::Config[:why_run] = true
end
- it "does not throw an exception if the keys do not exist but recursive is set to false" do
+ it "does not raise an exception if the keys do not exist but recursive is set to false" do
@new_resource.key(reg_child + '\Slitheen\Raxicoricofallapatorius')
- @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+ @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
@new_resource.recursive(false)
@new_resource.run_action(:create) # should not raise_error
expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
expect(@registry.key_exists?(reg_child + '\Slitheen\Raxicoricofallapatorius')).to eq(false)
end
+
it "does not create key if the action is create" do
@new_resource.key(reg_child + '\Slitheen')
- @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+ @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
@new_resource.recursive(false)
@new_resource.run_action(:create)
expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
end
+
+ it "does not raise an exception if the action create and type key missing in values hash" do
+ @new_resource.key(reg_child + '\Slitheen')
+ @new_resource.values([{ :name => "BriskWalk", :data => "my_data" }])
+ @new_resource.run_action(:create) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
+ end
+
+ it "does not raise an exception if the action create and data key missing in values hash" do
+ @new_resource.key(reg_child + '\Slitheen')
+ @new_resource.values([{ :name => "BriskWalk", :type => :string }])
+ @new_resource.run_action(:create) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
+ end
+
+ it "does not raise an exception if the action create and only name key present in values hash" do
+ @new_resource.key(reg_child + '\Slitheen')
+ @new_resource.values([{ :name => "BriskWalk" }])
+ @new_resource.run_action(:create) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
+ end
+
+ it "does not raise an exception if the action create and all keys are present in values hash" do
+ @new_resource.key(reg_child + '\Slitheen')
+ @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "my_data" }])
+ @new_resource.run_action(:create) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
+ end
end
end
@@ -286,61 +348,85 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
it "creates registry key, value if the key is missing" do
@new_resource.key(reg_child)
- @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}])
+ @new_resource.values([{ :name => "Color", :type => :string, :data => "Orange" }])
@new_resource.run_action(:create_if_missing)
expect(@registry.key_exists?(reg_parent)).to eq(true)
expect(@registry.key_exists?(reg_child)).to eq(true)
- expect(@registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
+ expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
end
it "does not create the key if it already exists with same value, type and data" do
@new_resource.key(reg_child)
- @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}])
+ @new_resource.values([{ :name => "Color", :type => :string, :data => "Orange" }])
@new_resource.run_action(:create_if_missing)
expect(@registry.key_exists?(reg_child)).to eq(true)
- expect(@registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
+ expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
end
it "creates a value if it does not exist" do
@new_resource.key(reg_child)
- @new_resource.values([{:name=>"Mango", :type=>:string, :data=>"Yellow"}])
+ @new_resource.values([{ :name => "Mango", :type => :string, :data => "Yellow" }])
@new_resource.run_action(:create_if_missing)
- expect(@registry.data_exists?(reg_child, {:name=>"Mango", :type=>:string, :data=>"Yellow"})).to eq(true)
+ expect(@registry.data_exists?(reg_child, { :name => "Mango", :type => :string, :data => "Yellow" })).to eq(true)
end
it "creates subkey if parent exists" do
@new_resource.key(reg_child + '\Pyrovile')
- @new_resource.values([{:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]}])
+ @new_resource.values([{ :name => "Chef", :type => :multi_string, :data => %w{OpscodeOrange Rules} }])
@new_resource.recursive(false)
@new_resource.run_action(:create_if_missing)
expect(@registry.key_exists?(reg_child + '\Pyrovile')).to eq(true)
- expect(@registry.value_exists?(reg_child + '\Pyrovile', {:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]})).to eq(true)
+ expect(@registry.value_exists?(reg_child + '\Pyrovile', { :name => "Chef", :type => :multi_string, :data => %w{OpscodeOrange Rules} })).to eq(true)
end
- it "gives error if action create and parent does not exist and recursive is set to false" do
+ it "raises an error if action create and parent does not exist and recursive is set to false" do
@new_resource.key(reg_child + '\Sontaran\Sontar')
- @new_resource.values([{:name=>"OC", :type=>:string, :data=>"MissingData"}])
+ @new_resource.values([{ :name => "OC", :type => :string, :data => "MissingData" }])
@new_resource.recursive(false)
- expect{@new_resource.run_action(:create_if_missing)}.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+ expect { @new_resource.run_action(:create_if_missing) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+ end
+
+ it "raises an error if action create_if_missing and type key missing in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC", :data => "my_data" }])
+ expect { @new_resource.run_action(:create_if_missing) }.to raise_error(Chef::Exceptions::RegKeyValuesTypeMissing)
+ end
+
+ it "raises an error if action create_if_missing and data key missing in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC", :type => :string }])
+ expect { @new_resource.run_action(:create_if_missing) }.to raise_error(Chef::Exceptions::RegKeyValuesDataMissing)
+ end
+
+ it "raises an error if action create_if_missing and only name key present in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC" }])
+ expect { @new_resource.run_action(:create_if_missing) }.to raise_error(Chef::Exceptions::RegKeyValuesTypeMissing)
+ end
+
+ it "does not raise an error if action create_if_missing and all keys are present in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC", :type => :string, :data => "my_data" }])
+ expect { @new_resource.run_action(:create_if_missing) }.to_not raise_error
end
it "creates missing keys if action create and parent does not exist and recursive is set to true" do
@new_resource.key(reg_child + '\Sontaran\Sontar')
- @new_resource.values([{:name=>"OC", :type=>:string, :data=>"MissingData"}])
+ @new_resource.values([{ :name => "OC", :type => :string, :data => "MissingData" }])
@new_resource.recursive(true)
@new_resource.run_action(:create_if_missing)
expect(@registry.key_exists?(reg_child + '\Sontaran\Sontar')).to eq(true)
- expect(@registry.value_exists?(reg_child + '\Sontaran\Sontar', {:name=>"OC", :type=>:string, :data=>"MissingData"})).to eq(true)
+ expect(@registry.value_exists?(reg_child + '\Sontaran\Sontar', { :name => "OC", :type => :string, :data => "MissingData" })).to eq(true)
end
it "creates key with multiple value as specified" do
@new_resource.key(reg_child + '\Adipose')
- @new_resource.values([{:name=>"one", :type=>:string, :data=>"1"},{:name=>"two", :type=>:string, :data=>"2"},{:name=>"three", :type=>:string, :data=>"3"}])
+ @new_resource.values([{ :name => "one", :type => :string, :data => "1" }, { :name => "two", :type => :string, :data => "2" }, { :name => "three", :type => :string, :data => "3" }])
@new_resource.recursive(true)
@new_resource.run_action(:create_if_missing)
@@ -351,7 +437,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
it "prepares the reporting data for :create_if_missing" do
@new_resource.key(reg_child + '\Judoon')
- @new_resource.values([{:name=>"ReportingVal3", :type=>:string, :data=>"report3"}])
+ @new_resource.values([{ :name => "ReportingVal3", :type => :string, :data => "report3" }])
@new_resource.recursive(true)
@new_resource.run_action(:create_if_missing)
@report = @resource_reporter.prepare_run_data
@@ -360,7 +446,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
expect(@report["resources"][0]["type"]).to eq("registry_key")
expect(@report["resources"][0]["name"]).to eq(resource_name)
expect(@report["resources"][0]["id"]).to eq(reg_child + '\Judoon')
- expect(@report["resources"][0]["after"][:values]).to eq([{:name=>"ReportingVal3", :type=>:string, :data=>"report3"}])
+ expect(@report["resources"][0]["after"][:values]).to eq([{ :name => "ReportingVal3", :type => :string, :data => "report3" }])
expect(@report["resources"][0]["before"][:values]).to eq([])
expect(@report["resources"][0]["result"]).to eq("create_if_missing")
expect(@report["status"]).to eq("success")
@@ -372,21 +458,50 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
Chef::Config[:why_run] = true
end
- it "does not throw an exception if the keys do not exist but recursive is set to false" do
+ it "does not raise an exception if the keys do not exist but recursive is set to false" do
@new_resource.key(reg_child + '\Zygons\Zygor')
- @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+ @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
@new_resource.recursive(false)
@new_resource.run_action(:create_if_missing) # should not raise_error
expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
expect(@registry.key_exists?(reg_child + '\Zygons\Zygor')).to eq(false)
end
+
it "does nothing if the action is create_if_missing" do
@new_resource.key(reg_child + '\Zygons')
- @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+ @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
@new_resource.recursive(false)
@new_resource.run_action(:create_if_missing)
expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
end
+
+ it "does not raise an exception if the action create_if_missing and type key missing in values hash" do
+ @new_resource.key(reg_child + '\Zygons')
+ @new_resource.values([{ :name => "BriskWalk", :data => "my_data" }])
+ @new_resource.run_action(:create_if_missing) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
+ end
+
+ it "does not raise an exception if the action create_if_missing and data key missing in values hash" do
+ @new_resource.key(reg_child + '\Zygons')
+ @new_resource.values([{ :name => "BriskWalk", :type => :string }])
+ @new_resource.run_action(:create_if_missing) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
+ end
+
+ it "does not raise an exception if the action create_if_missing and only name key present in values hash" do
+ @new_resource.key(reg_child + '\Zygons')
+ @new_resource.values([{ :name => "BriskWalk" }])
+ @new_resource.run_action(:create_if_missing) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
+ end
+
+ it "does not raise an exception if the action create_if_missing and all keys are present in values hash" do
+ @new_resource.key(reg_child + '\Zygons')
+ @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "my_data" }])
+ @new_resource.run_action(:create_if_missing) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
+ end
end
end
@@ -399,7 +514,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
it "takes no action if the specified key path does not exist in the system" do
expect(@registry.key_exists?(reg_parent + '\Osirian')).to eq(false)
- @new_resource.key(reg_parent+ '\Osirian')
+ @new_resource.key(reg_parent + '\Osirian')
@new_resource.recursive(false)
@new_resource.run_action(:delete)
@@ -407,53 +522,53 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
end
it "takes no action if the key exists but the value does not" do
- expect(@registry.data_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
+ expect(@registry.data_exists?(reg_parent + '\Opscode', { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
@new_resource.key(reg_parent + '\Opscode')
- @new_resource.values([{:name=>"LooksLike", :type=>:multi_string, :data=>["SeattleGrey", "OCOrange"]}])
+ @new_resource.values([{ :name => "LooksLike", :type => :multi_string, :data => %w{SeattleGrey OCOrange} }])
@new_resource.recursive(false)
@new_resource.run_action(:delete)
- expect(@registry.data_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
+ expect(@registry.data_exists?(reg_parent + '\Opscode', { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
end
it "deletes only specified values under a key path" do
@new_resource.key(reg_parent + '\Opscode')
- @new_resource.values([{:name=>"Opscode", :type=>:multi_string, :data=>["Seattle", "Washington"]}, {:name=>"AKA", :type=>:string, :data=>"OC"}])
+ @new_resource.values([{ :name => "Opscode", :type => :multi_string, :data => %w{Seattle Washington} }, { :name => "AKA", :type => :string, :data => "OC" }])
@new_resource.recursive(false)
@new_resource.run_action(:delete)
- expect(@registry.data_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
- expect(@registry.value_exists?(reg_parent + '\Opscode', {:name=>"AKA", :type=>:string, :data=>"OC"})).to eq(false)
- expect(@registry.value_exists?(reg_parent + '\Opscode', {:name=>"Opscode", :type=>:multi_string, :data=>["Seattle", "Washington"]})).to eq(false)
+ expect(@registry.data_exists?(reg_parent + '\Opscode', { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
+ expect(@registry.value_exists?(reg_parent + '\Opscode', { :name => "AKA", :type => :string, :data => "OC" })).to eq(false)
+ expect(@registry.value_exists?(reg_parent + '\Opscode', { :name => "Opscode", :type => :multi_string, :data => %w{Seattle Washington} })).to eq(false)
end
it "it deletes the values with the same name irrespective of it type and data" do
@new_resource.key(reg_parent + '\Opscode')
- @new_resource.values([{:name=>"Color", :type=>:multi_string, :data=>["Black", "Orange"]}])
+ @new_resource.values([{ :name => "Color", :type => :multi_string, :data => %w{Black Orange} }])
@new_resource.recursive(false)
@new_resource.run_action(:delete)
- expect(@registry.value_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(false)
+ expect(@registry.value_exists?(reg_parent + '\Opscode', { :name => "Color", :type => :string, :data => "Orange" })).to eq(false)
end
it "prepares the reporting data for action :delete" do
@new_resource.key(reg_parent + '\ReportKey')
- @new_resource.values([{:name=>"ReportVal4", :type=>:string, :data=>"report4"},{:name=>"ReportVal5", :type=>:string, :data=>"report5"}])
+ @new_resource.values([{ :name => "ReportVal4", :type => :string, :data => "report4" }, { :name => "ReportVal5", :type => :string, :data => "report5" }])
@new_resource.recursive(true)
@new_resource.run_action(:delete)
@report = @resource_reporter.prepare_run_data
- expect(@registry.value_exists?(reg_parent + '\ReportKey', [{:name=>"ReportVal4", :type=>:string, :data=>"report4"},{:name=>"ReportVal5", :type=>:string, :data=>"report5"}])).to eq(false)
+ expect(@registry.value_exists?(reg_parent + '\ReportKey', [{ :name => "ReportVal4", :type => :string, :data => "report4" }, { :name => "ReportVal5", :type => :string, :data => "report5" }])).to eq(false)
expect(@report["action"]).to eq("end")
expect(@report["resources"].count).to eq(1)
expect(@report["resources"][0]["type"]).to eq("registry_key")
expect(@report["resources"][0]["name"]).to eq(resource_name)
expect(@report["resources"][0]["id"]).to eq(reg_parent + '\ReportKey')
- expect(@report["resources"][0]["before"][:values]).to eq([{:name=>"ReportVal4", :type=>:string, :data=>"report4"},
- {:name=>"ReportVal5", :type=>:string, :data=>"report5"}])
+ expect(@report["resources"][0]["before"][:values]).to eq([{ :name => "ReportVal4", :type => :string, :data => "report4" },
+ { :name => "ReportVal5", :type => :string, :data => "report5" }])
#Not testing for after values to match since after -> new_resource values.
expect(@report["resources"][0]["result"]).to eq("delete")
expect(@report["status"]).to eq("success")
@@ -466,7 +581,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
end
it "does nothing if the action is delete" do
@new_resource.key(reg_parent + '\OpscodeWhyRun')
- @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+ @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
@new_resource.recursive(false)
@new_resource.run_action(:delete)
@@ -502,7 +617,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
it "raises an exception if the key has subkeys and recursive == false" do
@new_resource.key(reg_parent)
@new_resource.recursive(false)
- expect{@new_resource.run_action(:delete_key)}.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+ expect { @new_resource.run_action(:delete_key) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
end
it "ignores the values under a key" do
@@ -544,13 +659,13 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
it "does not throw an exception if the key has subkeys but recursive is set to false" do
@new_resource.key(reg_parent + '\OpscodeWhyRun')
- @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+ @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
@new_resource.recursive(false)
@new_resource.run_action(:delete_key)
end
it "does nothing if the action is delete_key" do
@new_resource.key(reg_parent + '\OpscodeWhyRun')
- @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+ @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
@new_resource.recursive(false)
@new_resource.run_action(:delete_key)
diff --git a/spec/functional/resource/remote_directory_spec.rb b/spec/functional/resource/remote_directory_spec.rb
index 37ffbbc971..c25e51cf2a 100644
--- a/spec/functional/resource/remote_directory_spec.rb
+++ b/spec/functional/resource/remote_directory_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::RemoteDirectory do
include_context Chef::Resource::Directory
@@ -36,14 +36,14 @@ describe Chef::Resource::RemoteDirectory do
resource = Chef::Resource::RemoteDirectory.new(path, run_context)
resource.source "remotedir"
- resource.cookbook('openldap')
+ resource.cookbook("openldap")
resource
end
def create_extraneous_files
- FileUtils.mkdir_p(File.join(path, 'remotesubdir'))
- @existing1 = File.join(path, 'marked_for_death.txt')
- @existing2 = File.join(path, 'remotesubdir', 'marked_for_death_again.txt')
+ FileUtils.mkdir_p(File.join(path, "remotesubdir"))
+ @existing1 = File.join(path, "marked_for_death.txt")
+ @existing2 = File.join(path, "remotesubdir", "marked_for_death_again.txt")
FileUtils.touch(@existing1)
FileUtils.touch(@existing2)
end
@@ -59,12 +59,12 @@ describe Chef::Resource::RemoteDirectory do
# See spec/data/cookbooks/openldap/files/default
let(:expected_files) do
[
- File.join(path, 'remote_dir_file1.txt'),
- File.join(path, 'remote_dir_file2.txt'),
- File.join(path, 'remotesubdir', 'remote_subdir_file1.txt'),
- File.join(path, 'remotesubdir', 'remote_subdir_file2.txt'),
- File.join(path, 'remotesubdir', '.a_dotfile'),
- File.join(path, '.a_dotdir', '.a_dotfile_in_a_dotdir')
+ File.join(path, "remote_dir_file1.txt"),
+ File.join(path, "remote_dir_file2.txt"),
+ File.join(path, "remotesubdir", "remote_subdir_file1.txt"),
+ File.join(path, "remotesubdir", "remote_subdir_file2.txt"),
+ File.join(path, "remotesubdir", ".a_dotfile"),
+ File.join(path, ".a_dotdir", ".a_dotfile_in_a_dotdir"),
]
end
@@ -133,11 +133,11 @@ describe Chef::Resource::RemoteDirectory do
end
it "leaves modifications alone" do
- FileUtils.mkdir_p(File.join(path, 'remotesubdir'))
- modified_file = File.join(path, 'remote_dir_file1.txt')
- modified_subdir_file = File.join(path, 'remotesubdir', 'remote_subdir_file1.txt')
- File.open(modified_file, 'a') {|f| f.puts "santa is real"}
- File.open(modified_subdir_file, 'a') {|f| f.puts "so is rudolph"}
+ FileUtils.mkdir_p(File.join(path, "remotesubdir"))
+ modified_file = File.join(path, "remote_dir_file1.txt")
+ modified_subdir_file = File.join(path, "remotesubdir", "remote_subdir_file1.txt")
+ File.open(modified_file, "a") { |f| f.puts "santa is real" }
+ File.open(modified_subdir_file, "a") { |f| f.puts "so is rudolph" }
modified_file_checksum = sha256_checksum(modified_file)
modified_subdir_file_checksum = sha256_checksum(modified_subdir_file)
@@ -190,11 +190,11 @@ describe Chef::Resource::RemoteDirectory do
context "and there are deeply nested extraneous files in the directory" do
before do
- FileUtils.mkdir_p(File.join(path, 'a', 'multiply', 'nested', 'directory'))
- @existing1 = File.join(path, 'a', 'foo.txt')
- @existing2 = File.join(path, 'a', 'multiply', 'bar.txt')
- @existing3 = File.join(path, 'a', 'multiply', 'nested', 'baz.txt')
- @existing4 = File.join(path, 'a', 'multiply', 'nested', 'directory', 'qux.txt')
+ FileUtils.mkdir_p(File.join(path, "a", "multiply", "nested", "directory"))
+ @existing1 = File.join(path, "a", "foo.txt")
+ @existing2 = File.join(path, "a", "multiply", "bar.txt")
+ @existing3 = File.join(path, "a", "multiply", "nested", "baz.txt")
+ @existing4 = File.join(path, "a", "multiply", "nested", "directory", "qux.txt")
FileUtils.touch(@existing1)
FileUtils.touch(@existing2)
FileUtils.touch(@existing3)
diff --git a/spec/functional/resource/remote_file_spec.rb b/spec/functional/resource/remote_file_spec.rb
index 4fbcd2d24b..1f92a567f3 100644
--- a/spec/functional/resource/remote_file_spec.rb
+++ b/spec/functional/resource/remote_file_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tiny_server'
-require 'support/shared/functional/http'
+require "spec_helper"
+require "tiny_server"
+require "support/shared/functional/http"
describe Chef::Resource::RemoteFile do
include ChefHTTPShared
@@ -55,19 +55,19 @@ describe Chef::Resource::RemoteFile do
let(:default_mode) { (0666 & ~File.umask).to_s(8) }
context "when fetching files over HTTP" do
- before(:all) do
+ before(:each) do
start_tiny_server
end
- after(:all) do
+ after(:each) do
stop_tiny_server
end
describe "when redownload isn't necessary" do
- let(:source) { 'http://localhost:9000/seattle_capo.png' }
+ let(:source) { "http://localhost:9000/seattle_capo.png" }
before do
- @api.get("/seattle_capo.png", 304, "", { 'Etag' => 'abcdef' } )
+ @api.get("/seattle_capo.png", 304, "", { "Etag" => "abcdef" } )
end
it "does not fetch the file" do
@@ -76,7 +76,7 @@ describe Chef::Resource::RemoteFile do
end
context "when using normal encoding" do
- let(:source) { 'http://localhost:9000/nyan_cat.png' }
+ let(:source) { "http://localhost:9000/nyan_cat.png" }
let(:expected_content) { binread(nyan_uncompressed_filename) }
it_behaves_like "a file resource"
@@ -85,7 +85,7 @@ describe Chef::Resource::RemoteFile do
end
context "when using gzip encoding" do
- let(:source) { 'http://localhost:9000/nyan_cat.png.gz' }
+ let(:source) { "http://localhost:9000/nyan_cat.png.gz" }
let(:expected_content) { binread(nyan_compressed_filename) }
it_behaves_like "a file resource"
@@ -97,7 +97,7 @@ describe Chef::Resource::RemoteFile do
context "when fetching files over HTTPS" do
- before(:all) do
+ before(:each) do
cert_text = File.read(File.expand_path("ssl/chef-rspec.cert", CHEF_SPEC_DATA))
cert = OpenSSL::X509::Certificate.new(cert_text)
key_text = File.read(File.expand_path("ssl/chef-rspec.key", CHEF_SPEC_DATA))
@@ -111,11 +111,11 @@ describe Chef::Resource::RemoteFile do
start_tiny_server(server_opts)
end
- after(:all) do
+ after(:each) do
stop_tiny_server
end
- let(:source) { 'https://localhost:9000/nyan_cat.png' }
+ let(:source) { "https://localhost:9000/nyan_cat.png" }
let(:expected_content) { binread(nyan_uncompressed_filename) }
@@ -124,17 +124,17 @@ describe Chef::Resource::RemoteFile do
end
context "when dealing with content length checking" do
- before(:all) do
+ before(:each) do
start_tiny_server
end
- after(:all) do
+ after(:each) do
stop_tiny_server
end
context "when downloading compressed data" do
let(:expected_content) { binread(nyan_uncompressed_filename) }
- let(:source) { 'http://localhost:9000/nyan_cat_content_length_compressed.png' }
+ let(:source) { "http://localhost:9000/nyan_cat_content_length_compressed.png" }
before do
expect(File).not_to exist(path)
@@ -156,7 +156,7 @@ describe Chef::Resource::RemoteFile do
context "when downloding uncompressed data" do
let(:expected_content) { binread(nyan_uncompressed_filename) }
- let(:source) { 'http://localhost:9000/nyan_cat_content_length.png' }
+ let(:source) { "http://localhost:9000/nyan_cat_content_length.png" }
before do
expect(File).not_to exist(path)
@@ -177,7 +177,7 @@ describe Chef::Resource::RemoteFile do
end
context "when downloading truncated compressed data" do
- let(:source) { 'http://localhost:9000/nyan_cat_truncated_compressed.png' }
+ let(:source) { "http://localhost:9000/nyan_cat_truncated_compressed.png" }
before do
expect(File).not_to exist(path)
@@ -190,7 +190,7 @@ describe Chef::Resource::RemoteFile do
end
context "when downloding truncated uncompressed data" do
- let(:source) { 'http://localhost:9000/nyan_cat_truncated.png' }
+ let(:source) { "http://localhost:9000/nyan_cat_truncated.png" }
before do
expect(File).not_to exist(path)
@@ -204,7 +204,7 @@ describe Chef::Resource::RemoteFile do
context "when downloding data with transfer-encoding set" do
let(:expected_content) { binread(nyan_uncompressed_filename) }
- let(:source) { 'http://localhost:9000/nyan_cat_transfer_encoding.png' }
+ let(:source) { "http://localhost:9000/nyan_cat_transfer_encoding.png" }
before do
expect(File).not_to exist(path)
@@ -225,14 +225,23 @@ describe Chef::Resource::RemoteFile do
end
describe "when the download of the source raises an exception" do
- let(:source) { 'http://localhost:0000/seattle_capo.png' }
+ let(:source) { "http://localhost:0000/seattle_capo.png" }
before do
expect(File).not_to exist(path)
end
it "should not create the file" do
- expect{ resource.run_action(:create) }.to raise_error
+ # This can legitimately raise either Errno::EADDRNOTAVAIL or Errno::ECONNREFUSED
+ # in different Ruby versions.
+ old_value = RSpec::Expectations.configuration.on_potential_false_positives
+ RSpec::Expectations.configuration.on_potential_false_positives = :nothing
+ begin
+ expect { resource.run_action(:create) }.to raise_error
+ ensure
+ RSpec::Expectations.configuration.on_potential_false_positives = old_value
+ end
+
expect(File).not_to exist(path)
end
end
diff --git a/spec/functional/resource/rpm_spec.rb b/spec/functional/resource/rpm_spec.rb
index b37ee781f1..17d0bf9e3c 100644
--- a/spec/functional/resource/rpm_spec.rb
+++ b/spec/functional/resource/rpm_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Prabhu Das (<prabhu.das@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
# run this test only for following platforms.
-exclude_test = !['aix', 'centos', 'redhat', 'suse'].include?(ohai[:platform])
+exclude_test = !%w{aix rhel fedora suse}.include?(ohai[:platform_family])
describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test do
include Chef::Mixin::ShellOut
@@ -32,41 +32,38 @@ describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test d
end
def rpm_pkg_should_be_installed(resource)
- case ohai[:platform]
# Due to dependency issues , different rpm pkgs are used in different platforms.
# dummy rpm package works in aix, without any dependency issues.
- when "aix"
+ if ohai[:platform] == "aix"
expect(shell_out("rpm -qa | grep dummy").exitstatus).to eq(0)
# mytest rpm package works in centos, redhat and in suse without any dependency issues.
- when "centos", "redhat", "suse"
+ else
expect(shell_out("rpm -qa | grep mytest").exitstatus).to eq(0)
::File.exists?("/opt/mytest/mytest.sh") # The mytest rpm package contains the mytest.sh file
end
end
def rpm_pkg_should_not_be_installed(resource)
- case ohai[:platform]
- when "aix"
+ if ohai[:platform] == "aix"
expect(shell_out("rpm -qa | grep dummy").exitstatus).to eq(1)
- when "centos", "redhat", "suse"
+ else
expect(shell_out("rpm -qa | grep mytest").exitstatus).to eq(1)
!::File.exists?("/opt/mytest/mytest.sh")
end
end
before(:all) do
- case ohai[:platform]
# Due to dependency issues , different rpm pkgs are used in different platforms.
- when "aix"
+ if ohai[:platform] == "aix"
@pkg_name = "dummy"
@pkg_version = "1-0"
- @pkg_path = "/tmp/dummy-1-0.aix6.1.noarch.rpm"
- FileUtils.cp(File.join(CHEF_SPEC_ASSETS, 'dummy-1-0.aix6.1.noarch.rpm') , @pkg_path)
- when "centos", "redhat", "suse"
+ @pkg_path = "#{Dir.tmpdir}/dummy-1-0.aix6.1.noarch.rpm"
+ FileUtils.cp(File.join(CHEF_SPEC_ASSETS, "dummy-1-0.aix6.1.noarch.rpm") , @pkg_path)
+ else
@pkg_name = "mytest"
@pkg_version = "1.0-1"
- @pkg_path = "/tmp/mytest-1.0-1.noarch.rpm"
- FileUtils.cp(File.join(CHEF_SPEC_ASSETS, 'mytest-1.0-1.noarch.rpm') , @pkg_path)
+ @pkg_path = "#{Dir.tmpdir}/mytest-1.0-1.noarch.rpm"
+ FileUtils.cp(File.join(CHEF_SPEC_ASSETS, "mytest-1.0-1.noarch.rpm") , @pkg_path)
end
end
@@ -99,14 +96,14 @@ describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test d
context "package upgrade action" do
before(:each) do
shell_out("rpm -i #{@pkg_path}")
- if ohai[:platform] == 'aix'
+ if ohai[:platform] == "aix"
@pkg_version = "2-0"
- @pkg_path = "/tmp/dummy-2-0.aix6.1.noarch.rpm"
- FileUtils.cp(File.join(CHEF_SPEC_ASSETS, 'dummy-2-0.aix6.1.noarch.rpm') , @pkg_path)
+ @pkg_path = "#{Dir.tmpdir}/dummy-2-0.aix6.1.noarch.rpm"
+ FileUtils.cp(File.join(CHEF_SPEC_ASSETS, "dummy-2-0.aix6.1.noarch.rpm") , @pkg_path)
else
@pkg_version = "2.0-1"
- @pkg_path = "/tmp/mytest-2.0-1.noarch.rpm"
- FileUtils.cp(File.join(CHEF_SPEC_ASSETS, 'mytest-2.0-1.noarch.rpm') , @pkg_path)
+ @pkg_path = "#{Dir.tmpdir}/mytest-2.0-1.noarch.rpm"
+ FileUtils.cp(File.join(CHEF_SPEC_ASSETS, "mytest-2.0-1.noarch.rpm") , @pkg_path)
end
end
diff --git a/spec/functional/resource/template_spec.rb b/spec/functional/resource/template_spec.rb
index 35c5166e31..32529fbb0c 100644
--- a/spec/functional/resource/template_spec.rb
+++ b/spec/functional/resource/template_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Template do
def binread(file)
- File.open(file,"rb") {|f| f.read }
+ File.open(file, "rb") { |f| f.read }
end
include_context Chef::Resource::File
@@ -44,8 +44,8 @@ describe Chef::Resource::Template do
events = Chef::EventDispatch::Dispatcher.new
run_context = Chef::RunContext.new(node, cookbook_collection, events)
resource = Chef::Resource::Template.new(path, run_context)
- resource.source('openldap_stuff.conf.erb')
- resource.cookbook('openldap')
+ resource.source("openldap_stuff.conf.erb")
+ resource.cookbook("openldap")
# NOTE: partials rely on `cookbook_name` getting set by chef internals and
# ignore the user-set `cookbook` attribute.
@@ -66,14 +66,14 @@ describe Chef::Resource::Template do
context "when the target file does not exist" do
it "creates the template with the rendered content using the variable attribute when the :create action is run" do
- resource.source('openldap_variable_stuff.conf.erb')
+ resource.source("openldap_variable_stuff.conf.erb")
resource.variables(:secret => "nutella")
resource.run_action(:create)
expect(IO.read(path)).to eq("super secret is nutella")
end
it "creates the template with the rendered content using a local erb file when the :create action is run" do
- resource.source(File.expand_path(File.join(CHEF_SPEC_DATA,'cookbooks','openldap','templates','default','openldap_stuff.conf.erb')))
+ resource.source(File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks", "openldap", "templates", "default", "openldap_stuff.conf.erb")))
resource.cookbook(nil)
resource.local(true)
resource.run_action(:create)
@@ -110,7 +110,7 @@ describe Chef::Resource::Template do
context "using single helper syntax referencing @node" do
before do
- node.set[:helper_test_attr] = "value from helper method"
+ node.normal[:helper_test_attr] = "value from helper method"
resource.helper(:helper_method) { "#{@node[:helper_test_attr]}" }
end
@@ -131,7 +131,7 @@ describe Chef::Resource::Template do
context "using an inline block referencing @node" do
before do
- node.set[:helper_test_attr] = "value from helper method"
+ node.normal[:helper_test_attr] = "value from helper method"
resource.helpers do
def helper_method
@@ -168,7 +168,7 @@ describe Chef::Resource::Template do
end
before do
- node.set[:helper_test_attr] = "value from helper method"
+ node.normal[:helper_test_attr] = "value from helper method"
resource.helpers(ExampleModuleReferencingATNode)
end
@@ -191,7 +191,7 @@ describe Chef::Resource::Template do
describe "when template source contains windows style line endings" do
include_context "diff disabled"
- ["all", "some", "no"].each do |test_case|
+ %w{all some no}.each do |test_case|
context "for #{test_case} lines" do
let(:resource) do
r = create_resource
diff --git a/spec/functional/resource/user/dscl_spec.rb b/spec/functional/resource/user/dscl_spec.rb
index 5d960daf11..ed96e31bac 100644
--- a/spec/functional/resource/user/dscl_spec.rb
+++ b/spec/functional/resource/user/dscl_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "chef/mixin/shell_out"
metadata = {
:mac_osx_only => true,
@@ -28,11 +28,9 @@ describe "Chef::Resource::User with Chef::Provider::User::Dscl provider", metada
include Chef::Mixin::ShellOut
def clean_user
- begin
- shell_out!("/usr/bin/dscl . -delete '/Users/#{username}'")
- rescue Mixlib::ShellOut::ShellCommandFailed
+ shell_out!("/usr/bin/dscl . -delete '/Users/#{username}'")
+ rescue Mixlib::ShellOut::ShellCommandFailed
# Raised when the user is already cleaned
- end
end
def user_should_exist
@@ -76,7 +74,7 @@ describe "Chef::Resource::User with Chef::Provider::User::Dscl provider", metada
let(:iterations) { nil }
let(:user_resource) do
- r = Chef::Resource::User.new("TEST USER RESOURCE", run_context)
+ r = Chef::Resource::User::DsclUser.new("TEST USER RESOURCE", run_context)
r.username(username)
r.uid(uid)
r.gid(gid)
@@ -123,7 +121,7 @@ describe "Chef::Resource::User with Chef::Provider::User::Dscl provider", metada
end
describe "when password is being set via shadow hash" do
- let(:password) {
+ let(:password) do
if node[:platform_version].start_with?("10.7.")
# On Mac 10.7 we only need to set the password
"c9b3bd1a0cde797eef0eff16c580dab996ba3a21961cccc\
@@ -139,7 +137,7 @@ b1d4880833aa7a190afc13e2bf0936b8\
c5adbbac718b7eb99463a7b679571e0f\
1c9fef2ef08d0b9e9c2bcf644eed2ffc"
end
- }
+ end
let(:iterations) { 25000 }
let(:salt) { "9e2e7d5ee473b496fd24cf0bbfcaedfcb291ee21740e570d1e917e874f8788ca" }
@@ -168,7 +166,7 @@ c5adbbac718b7eb99463a7b679571e0f\
end
describe "when a user is member of some groups" do
- let(:groups) { ["staff", "operator"] }
+ let(:groups) { %w{staff operator} }
before do
existing_resource = user_resource.dup
@@ -186,7 +184,7 @@ c5adbbac718b7eb99463a7b679571e0f\
end
end
- it ":remove action removes the user from the groups and deletes the user"do
+ it ":remove action removes the user from the groups and deletes the user" do
user_resource.run_action(:remove)
groups.each do |group|
# Do not raise an error when group is empty
diff --git a/spec/functional/resource/user/useradd_spec.rb b/spec/functional/resource/user/useradd_spec.rb
index 474f6a4ecf..497cb0b043 100644
--- a/spec/functional/resource/user/useradd_spec.rb
+++ b/spec/functional/resource/user/useradd_spec.rb
@@ -1,7 +1,7 @@
# encoding: UTF-8
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,40 +17,46 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
-def user_provider_for_platform
- case ohai[:platform]
+def resource_for_platform(username, run_context)
+ Chef::Resource.resource_for_node(:user, node).new(username, run_context)
+end
+
+# ideally we could somehow pass an array of [ ...::Aix, ...::Linux ] to the
+# filter, but we have to pick the right one for the O/S.
+def user_provider_filter
+ case ohai[:os]
when "aix"
Chef::Provider::User::Aix
- else
- Chef::Provider::User::Useradd
+ when "linux"
+ Chef::Provider::User::Linux
end
end
-metadata = { :unix_only => true,
+metadata = {
+ :unix_only => true,
:requires_root => true,
:not_supported_on_mac_osx => true,
- :provider => {:user => user_provider_for_platform}
+ :provider => { :user => user_provider_filter },
}
describe Chef::Provider::User::Useradd, metadata do
include Chef::Mixin::ShellOut
-
# Utility code for /etc/passwd interaction, avoid any caching of user records:
PwEntry = Struct.new(:name, :passwd, :uid, :gid, :gecos, :home, :shell)
class UserNotFound < StandardError; end
def pw_entry
- passwd_file = File.open("/etc/passwd", "rb") {|f| f.read}
+ passwd_file = File.open("/etc/passwd", "rb") { |f| f.read }
matcher = /^#{Regexp.escape(username)}.+$/
if passwd_entry = passwd_file.scan(matcher).first
- PwEntry.new(*passwd_entry.split(':'))
+ PwEntry.new(*passwd_entry.split(":"))
else
raise UserNotFound, "no entry matching #{matcher.inspect} found in /etc/passwd"
end
@@ -59,9 +65,9 @@ describe Chef::Provider::User::Useradd, metadata do
def etc_shadow
case ohai[:platform]
when "aix"
- File.open("/etc/security/passwd") {|f| f.read }
+ File.open("/etc/security/passwd") { |f| f.read }
else
- File.open("/etc/shadow") {|f| f.read }
+ File.open("/etc/shadow") { |f| f.read }
end
end
@@ -82,13 +88,14 @@ describe Chef::Provider::User::Useradd, metadata do
end
def try_cleanup
- ['/home/cheftestfoo', '/home/cheftestbar'].each do |f|
+ ["/home/cheftestfoo", "/home/cheftestbar", "/home/cf-test"].each do |f|
FileUtils.rm_rf(f) if File.exists? f
end
- ['cf-test'].each do |u|
- r = Chef::Resource::User.new("DELETE USER", run_context)
- r.username('cf-test')
+ ["cf-test"].each do |u|
+ r = resource_for_platform("DELETE USER", run_context)
+ r.manage_home true
+ r.username("cf-test")
r.run_action(:remove)
end
end
@@ -104,7 +111,7 @@ describe Chef::Provider::User::Useradd, metadata do
while max_retries > 0
begin
pw_entry # will raise if the user doesn't exist
- status = shell_out!("userdel", "-r", username, :returns => [0,8,12])
+ status = shell_out!("userdel", "-r", username, :returns => [0, 8, 12])
# Error code 8 during userdel indicates that the user is logged in.
# This occurs randomly because the accounts daemon holds a lock due to which userdel fails.
@@ -112,7 +119,7 @@ describe Chef::Provider::User::Useradd, metadata do
break if status.exitstatus != 8
sleep 1
- max_retries = max_retries - 1
+ max_retries -= 1
rescue UserNotFound
break
end
@@ -135,10 +142,7 @@ describe Chef::Provider::User::Useradd, metadata do
Chef::RunContext.new(node, {}, events)
end
- let(:username) do
- "cf-test"
- end
-
+ let(:username) { "cf-test" }
let(:uid) { nil }
let(:home) { nil }
let(:manage_home) { false }
@@ -147,7 +151,7 @@ describe Chef::Provider::User::Useradd, metadata do
let(:comment) { nil }
let(:user_resource) do
- r = Chef::Resource::User.new("TEST USER RESOURCE", run_context)
+ r = resource_for_platform("TEST USER RESOURCE", run_context)
r.username(username)
r.uid(uid)
r.home(home)
@@ -160,7 +164,7 @@ describe Chef::Provider::User::Useradd, metadata do
let(:expected_shadow) do
if ohai[:platform] == "aix"
- expected_shadow = "cf-test" # For aix just check user entry in shadow file
+ expected_shadow = "cf-test" # For aix just check user entry in shadow file
else
expected_shadow = "cf-test:$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
end
@@ -174,7 +178,6 @@ describe Chef::Provider::User::Useradd, metadata do
expect(user_resource).to be_updated_by_last_action
end
-
it "ensures the user exists" do
expect(pw_entry.name).to eq(username)
end
@@ -194,7 +197,6 @@ describe Chef::Provider::User::Useradd, metadata do
end
end
-
context "when uid is set" do
# Should verify uid not in use...
let(:uid) { 1999 }
@@ -242,25 +244,26 @@ describe Chef::Provider::User::Useradd, metadata do
let(:home) { "/home/#{username}" }
it "ensures the user's home is set to the given path" do
- expect(pw_entry.home).to eq("/home/#{username}")
+ expect(pw_entry.home).to eq(home)
end
- if %w{rhel fedora}.include?(OHAI_SYSTEM["platform_family"])
- # Inconsistent behavior. See: CHEF-2205
- it "creates the home dir when not explicitly asked to on RHEL (XXX)" do
- expect(File).to exist("/home/#{username}")
- end
- else
- it "does not create the home dir without `manage_home'" do
- expect(File).not_to exist("/home/#{username}")
- end
+ it "does not create the home dir without `manage_home'" do
+ expect(File).not_to exist(home)
end
context "and manage_home is enabled" do
let(:manage_home) { true }
it "ensures the user's home directory exists" do
- expect(File).to exist("/home/#{username}")
+ expect(File).to exist(home)
+ end
+ end
+
+ context "and manage_home is the default" do
+ let(:manage_home) { nil }
+
+ it "does not create the home dir without `manage_home'" do
+ expect(File).not_to exist(home)
end
end
end
@@ -282,24 +285,17 @@ describe Chef::Provider::User::Useradd, metadata do
end
end
- context "when a system user is specified" do
+ context "when a system user is specified", skip: aix? do
let(:system) { true }
let(:uid_min) do
- case ohai[:platform]
- when "aix"
- # UIDs and GIDs below 100 are typically reserved for system accounts and services
- # http://www.ibm.com/developerworks/aix/library/au-satuidgid/
- 100
- else
- # from `man useradd`, login user means uid will be between
- # UID_SYS_MIN and UID_SYS_MAX defined in /etc/login.defs. On my
- # Ubuntu 13.04 system, these are commented out, so we'll look at
- # UID_MIN to find the lower limit of the non-system-user range, and
- # use that value in our assertions.
- login_defs = File.open("/etc/login.defs", "rb") {|f| f.read }
- uid_min_scan = /^UID_MIN\s+(\d+)/
- login_defs.match(uid_min_scan)[1]
- end
+ # from `man useradd`, login user means uid will be between
+ # UID_SYS_MIN and UID_SYS_MAX defined in /etc/login.defs. On my
+ # Ubuntu 13.04 system, these are commented out, so we'll look at
+ # UID_MIN to find the lower limit of the non-system-user range, and
+ # use that value in our assertions.
+ login_defs = File.open("/etc/login.defs", "rb") { |f| f.read }
+ uid_min_scan = /^UID_MIN\s+(\d+)/
+ login_defs.match(uid_min_scan)[1]
end
it "ensures the user has the properties of a system user" do
@@ -320,8 +316,8 @@ describe Chef::Provider::User::Useradd, metadata do
let(:existing_comment) { nil }
let(:existing_user) do
- r = Chef::Resource::User.new("TEST USER RESOURCE", run_context)
- # username is identity attr, must match.
+ r = resource_for_platform("TEST USER RESOURCE", run_context)
+ # username is identity attr, must match.
r.username(username)
r.uid(existing_uid)
r.home(existing_home)
@@ -455,7 +451,6 @@ describe Chef::Provider::User::Useradd, metadata do
end
end
-
it "ensures the password is set" do
password_should_be_set
expect(etc_shadow).to include(expected_shadow)
@@ -484,7 +479,6 @@ describe Chef::Provider::User::Useradd, metadata do
end
end
-
it "ensures the password is set to the desired value" do
password_should_be_set
expect(etc_shadow).to include(expected_shadow)
@@ -518,11 +512,11 @@ describe Chef::Provider::User::Useradd, metadata do
let(:user_locked_context?) { false }
def shadow_entry
- etc_shadow.lines.select {|l| l.include?(username) }.first
+ etc_shadow.lines.find { |l| l.include?(username) }
end
def shadow_password
- shadow_entry.split(':')[1]
+ shadow_entry.split(":")[1]
end
def aix_user_lock_status
@@ -596,7 +590,6 @@ describe Chef::Provider::User::Useradd, metadata do
end
end
-
it "locks the user's password" do
user_account_should_be_locked
end
@@ -644,12 +637,23 @@ describe Chef::Provider::User::Useradd, metadata do
context "and has no password" do
# TODO: platform_family should be setup in spec_helper w/ tags
- if %w[suse opensuse].include?(OHAI_SYSTEM["platform_family"])
- # suse gets this right:
+ if %w{opensuse}.include?(OHAI_SYSTEM["platform_family"]) ||
+ (%w{suse}.include?(OHAI_SYSTEM["platform_family"]) &&
+ OHAI_SYSTEM["platform_version"].to_f < 12.1)
+ # suse 11.x gets this right:
it "errors out trying to unlock the user" do
expect(@error).to be_a(Mixlib::ShellOut::ShellCommandFailed)
expect(@error.message).to include("Cannot unlock the password")
end
+ elsif %w{rhel}.include?(OHAI_SYSTEM["platform_family"]) &&
+ OHAI_SYSTEM["platform_version"].to_f == 6.8
+ # usermod -U returns following message for rhel68 on s390x platforms
+ # usermod: unlocking the user's password would result in a passwordless account.
+ #You should set a password with usermod -p to unlock this user's password.
+ it "errors out trying to unlock the user" do
+ expect(@error).to be_a(Mixlib::ShellOut::ShellCommandFailed)
+ expect(@error.message).to include("You should set a password")
+ end
else
# borked on all other platforms:
@@ -665,10 +669,10 @@ describe Chef::Provider::User::Useradd, metadata do
# DEBUG: Ran usermod -U chef-functional-test returned 0
expect(@error).to be_nil
if ohai[:platform] == "aix"
- expect(pw_entry.passwd).to eq('*')
+ expect(pw_entry.passwd).to eq("*")
user_account_should_be_unlocked
else
- expect(pw_entry.passwd).to eq('x')
+ expect(pw_entry.passwd).to eq("x")
expect(shadow_password).to include("!")
end
end
diff --git a/spec/functional/resource/user/windows_spec.rb b/spec/functional/resource/user/windows_spec.rb
index 5e3a9090d4..f61a51c636 100644
--- a/spec/functional/resource/user/windows_spec.rb
+++ b/spec/functional/resource/user/windows_spec.rb
@@ -1,5 +1,5 @@
# Author:: Jay Mundrawala (<jdm@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software
+# Copyright:: Copyright 2015-2016, Chef Software
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,13 +15,13 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "chef/mixin/shell_out"
describe Chef::Provider::User::Windows, :windows_only do
include Chef::Mixin::ShellOut
- let(:username) { 'ChefFunctionalTest' }
+ let(:username) { "ChefFunctionalTest" }
let(:password) { SecureRandom.uuid }
let(:node) do
@@ -47,84 +47,84 @@ describe Chef::Provider::User::Windows, :windows_only do
delete_user(username)
end
- describe 'action :create' do
- it 'creates a user when a username and password are given' do
+ describe "action :create" do
+ it "creates a user when a username and password are given" do
new_resource.run_action(:create)
expect(new_resource).to be_updated_by_last_action
expect(shell_out("net user #{username}").exitstatus).to eq(0)
end
- it 'reports no changes if there are no changes needed' do
+ it "reports no changes if there are no changes needed" do
new_resource.run_action(:create)
new_resource.run_action(:create)
expect(new_resource).not_to be_updated_by_last_action
end
- it 'allows chaning the password' do
+ it "allows chaning the password" do
new_resource.run_action(:create)
new_resource.password(SecureRandom.uuid)
new_resource.run_action(:create)
expect(new_resource).to be_updated_by_last_action
end
- context 'with a gid specified' do
- it 'warns unsupported' do
+ context "with a gid specified" do
+ it "warns unsupported" do
expect(Chef::Log).to receive(:warn).with(/not implemented/)
- new_resource.gid('agroup')
+ new_resource.gid("agroup")
new_resource.run_action(:create)
end
end
end
- describe 'action :remove' do
+ describe "action :remove" do
before do
new_resource.run_action(:create)
end
- it 'deletes the user' do
+ it "deletes the user" do
new_resource.run_action(:remove)
expect(new_resource).to be_updated_by_last_action
expect(shell_out("net user #{username}").exitstatus).to eq(2)
end
- it 'is idempotent' do
+ it "is idempotent" do
new_resource.run_action(:remove)
new_resource.run_action(:remove)
expect(new_resource).not_to be_updated_by_last_action
end
end
- describe 'action :lock' do
+ describe "action :lock" do
before do
new_resource.run_action(:create)
end
- it 'locks the user account' do
+ it "locks the user account" do
new_resource.run_action(:lock)
expect(new_resource).to be_updated_by_last_action
expect(shell_out("net user #{username}").stdout).to match(/Account active\s*No/)
end
- it 'is idempotent' do
+ it "is idempotent" do
new_resource.run_action(:lock)
new_resource.run_action(:lock)
expect(new_resource).not_to be_updated_by_last_action
end
end
- describe 'action :unlock' do
+ describe "action :unlock" do
before do
new_resource.run_action(:create)
new_resource.run_action(:lock)
end
- it 'unlocks the user account' do
+ it "unlocks the user account" do
new_resource.run_action(:unlock)
expect(new_resource).to be_updated_by_last_action
expect(shell_out("net user #{username}").stdout).to match(/Account active\s*Yes/)
end
- it 'is idempotent' do
+ it "is idempotent" do
new_resource.run_action(:unlock)
new_resource.run_action(:unlock)
expect(new_resource).not_to be_updated_by_last_action
diff --git a/spec/functional/resource/windows_package_spec.rb b/spec/functional/resource/windows_package_spec.rb
new file mode 100644
index 0000000000..bc508dc526
--- /dev/null
+++ b/spec/functional/resource/windows_package_spec.rb
@@ -0,0 +1,168 @@
+#
+# Author:: Matt Wrock (<matt@mattwrock.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "functional/resource/base"
+
+describe Chef::Resource::WindowsPackage, :windows_only, :volatile do
+ let(:pkg_name) { nil }
+ let(:pkg_path) { nil }
+ let(:pkg_checksum) { nil }
+ let(:pkg_version) { nil }
+ let(:pkg_type) { nil }
+ let(:pkg_options) { nil }
+
+ subject do
+ new_resource = Chef::Resource::WindowsPackage.new(pkg_name, run_context)
+ new_resource.source pkg_path if pkg_path
+ new_resource.version pkg_version
+ new_resource.installer_type pkg_type
+ new_resource.options pkg_options
+ new_resource.checksum pkg_checksum
+ new_resource
+ end
+
+ describe "install package" do
+ let(:pkg_name) { "Microsoft Visual C++ 2005 Redistributable" }
+ let(:pkg_checksum) { "d6832398e3bc9156a660745f427dc1c2392ce4e9a872e04f41f62d0c6bae07a8" }
+ let(:pkg_path) { "https://download.microsoft.com/download/6/B/B/6BB661D6-A8AE-4819-B79F-236472F6070C/vcredist_x86.exe" }
+ let(:pkg_checksum) { nil }
+ let(:pkg_type) { :custom }
+ let(:pkg_options) { "/Q" }
+
+ it "updates resource on first install" do
+ subject.run_action(:install)
+ expect(subject).to be_updated_by_last_action
+ end
+
+ it "does not update resource when already installed" do
+ subject.run_action(:install)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ context "installing additional version" do
+ let(:pkg_path) { "https://download.microsoft.com/download/e/1/c/e1c773de-73ba-494a-a5ba-f24906ecf088/vcredist_x86.exe" }
+ let(:pkg_checksum) { "eb00f891919d4f894ab725b158459db8834470c382dc60cd3c3ee2c6de6da92c" }
+ let(:pkg_version) { "8.0.56336" }
+
+ it "installs older version" do
+ subject.run_action(:install)
+ expect(subject).to be_updated_by_last_action
+ end
+ end
+
+ describe "removing package" do
+ subject { Chef::Resource::WindowsPackage.new(pkg_name, run_context) }
+
+ context "multiple versions and a version given to remove" do
+ before { subject.version("8.0.56336") }
+
+ it "removes specified version" do
+ subject.run_action(:remove)
+ expect(subject).to be_updated_by_last_action
+ prov = subject.provider_for_action(:remove)
+ prov.load_current_resource
+ expect(prov.current_version_array).to eq([["8.0.59193"]])
+ end
+ end
+
+ context "single version installed and no version given to remove" do
+ it "removes last remaining version" do
+ subject.run_action(:remove)
+ expect(subject).to be_updated_by_last_action
+ prov = subject.provider_for_action(:remove)
+ prov.load_current_resource
+ expect(prov.current_version_array).to eq([nil])
+ end
+ end
+
+ describe "removing multiple versions at once" do
+ let(:pkg_version) { nil }
+ before do
+ install1 = Chef::Resource::WindowsPackage.new(pkg_name, run_context)
+ install1.source pkg_path
+ install1.version pkg_version
+ install1.installer_type pkg_type
+ install1.options pkg_options
+ install1.run_action(:install)
+
+ install2 = Chef::Resource::WindowsPackage.new(pkg_name, run_context)
+ install2.source "https://download.microsoft.com/download/e/1/c/e1c773de-73ba-494a-a5ba-f24906ecf088/vcredist_x86.exe"
+ install2.version "8.0.56336"
+ install2.installer_type pkg_type
+ install2.options pkg_options
+ install2.run_action(:install)
+ end
+
+ it "removes all versions" do
+ subject.run_action(:remove)
+ expect(subject).to be_updated_by_last_action
+ prov = subject.provider_for_action(:remove)
+ prov.load_current_resource
+ expect(prov.current_version_array).to eq([nil])
+ end
+ end
+ end
+ end
+
+ describe "package version and installer type" do
+ after { subject.run_action(:remove) }
+
+ context "null soft" do
+ let(:pkg_name) { "Ultra Defragmenter" }
+ let(:pkg_path) { "http://iweb.dl.sourceforge.net/project/ultradefrag/stable-release/6.1.1/ultradefrag-6.1.1.bin.amd64.exe" }
+ let(:pkg_checksum) { "11d53ed4c426c8c867ad43f142b7904226ffd9938c02e37086913620d79e3c09" }
+
+ it "finds the correct installer type" do
+ subject.run_action(:install)
+ expect(subject.provider_for_action(:install).installer_type).to eq(:nsis)
+ end
+ end
+
+ context "inno" do
+ let(:pkg_name) { "Mercurial 3.6.1 (64-bit)" }
+ let(:pkg_path) { "http://mercurial.selenic.com/release/windows/Mercurial-3.6.1-x64.exe" }
+ let(:pkg_checksum) { "febd29578cb6736163d232708b834a2ddd119aa40abc536b2c313fc5e1b5831d" }
+
+ it "finds the correct installer type" do
+ subject.run_action(:install)
+ expect(subject.provider_for_action(:install).installer_type).to eq(:inno)
+ end
+ end
+ end
+
+ describe "install from local file" do
+ let(:pkg_name) { "Mercurial 3.6.1 (64-bit)" }
+ let(:pkg_path) { ::File.join(Chef::Config[:file_cache_path], "package", "Mercurial-3.6.1-x64.exe") }
+ let(:pkg_checksum) { "febd29578cb6736163d232708b834a2ddd119aa40abc536b2c313fc5e1b5831d" }
+
+ it "installs the app" do
+ subject.run_action(:install)
+ expect(subject).to be_updated_by_last_action
+ end
+ end
+
+ describe "uninstall exe without source" do
+ let(:pkg_name) { "Mercurial 3.6.1 (64-bit)" }
+
+ it "uninstalls the app" do
+ subject.run_action(:remove)
+ expect(subject).to be_updated_by_last_action
+ end
+ end
+end
diff --git a/spec/functional/resource/windows_service_spec.rb b/spec/functional/resource/windows_service_spec.rb
index 90545429e5..531f9e9250 100644
--- a/spec/functional/resource/windows_service_spec.rb
+++ b/spec/functional/resource/windows_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Chris Doherty (<cdoherty@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,29 +16,30 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_gem_only, :appveyor_only do
+describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_gem_only, :appveyor_only, :broken => true do
+ # Marking as broken. This test is causing appveyor tests to exit with 116.
include_context "using Win32::Service"
- let(:username) { "service_spec_user"}
- let(:qualified_username) { ".\\#{username}"}
- let(:password) { "1a2b3c4X!&narf"}
+ let(:username) { "service_spec_user" }
+ let(:qualified_username) { "#{ENV['COMPUTERNAME']}\\#{username}" }
+ let(:password) { "1a2b3c4X!&narf" }
- let(:user_resource) {
- r = Chef::Resource::User.new(username, run_context)
+ let(:user_resource) do
+ r = Chef::Resource::User::WindowsUser.new(username, run_context)
r.username(username)
r.password(password)
r.comment("temp spec user")
r
- }
+ end
- let(:global_service_file_path) {
+ let(:global_service_file_path) do
"#{ENV['WINDIR']}\\temp\\#{File.basename(test_service[:service_file_path])}"
- }
+ end
- let(:service_params) {
+ let(:service_params) do
id = "#{$$}_#{rand(1000)}"
@@ -50,24 +51,24 @@ describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_
service_description: "Test service for running the windows_service functional spec.",
service_file_path: global_service_file_path,
} )
- }
+ end
- let(:manager) {
+ let(:manager) do
Chef::Application::WindowsServiceManager.new(service_params)
- }
+ end
- let(:service_resource) {
+ let(:service_resource) do
r = Chef::Resource::WindowsService.new(service_params[:service_name], run_context)
[:run_as_user, :run_as_password].each { |prop| r.send(prop, service_params[prop]) }
r
- }
+ end
- before {
+ before do
user_resource.run_action(:create)
# the service executable has to be outside the current user's home
# directory in order for the logon user to execute it.
- FileUtils::copy_file(test_service[:service_file_path], global_service_file_path)
+ FileUtils.copy_file(test_service[:service_file_path], global_service_file_path)
# if you don't make the file executable by the service user, you'll get
# the not-very-helpful "service did not respond fast enough" error.
@@ -80,19 +81,22 @@ describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_
file.run_action(:create)
manager.run(%w{--action install})
- }
+ end
- after {
+ after do
user_resource.run_action(:remove)
manager.run(%w{--action uninstall})
File.delete(global_service_file_path)
- }
+ end
describe "logon as a service" do
it "successfully runs a service as another user" do
service_resource.run_action(:start)
end
- it "raises an exception when it can't grant the logon privilege"
+ it "grants the user the log on as service right" do
+ service_resource.run_action(:start)
+ expect(Chef::ReservedNames::Win32::Security.get_account_right(qualified_username)).to include("SeServiceLogonRight")
+ end
end
end
diff --git a/spec/functional/rest_spec.rb b/spec/functional/rest_spec.rb
index 7c6b1872ef..14e76087c4 100644
--- a/spec/functional/rest_spec.rb
+++ b/spec/functional/rest_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tiny_server'
-require 'support/shared/functional/http'
+require "spec_helper"
+require "tiny_server"
+require "support/shared/functional/http"
describe Chef::REST do
include ChefHTTPShared
@@ -80,13 +80,14 @@ describe Chef::REST do
before do
Chef::Config[:node_name] = "webmonkey.example.com"
Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem"
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
end
- before(:all) do
+ before(:each) do
start_tiny_server
end
- after(:all) do
+ after(:each) do
stop_tiny_server
end
diff --git a/spec/functional/run_lock_spec.rb b/spec/functional/run_lock_spec.rb
index 78b3847d19..d270803698 100644
--- a/spec/functional/run_lock_spec.rb
+++ b/spec/functional/run_lock_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require File.expand_path('../../spec_helper', __FILE__)
-require 'chef/client'
+require File.expand_path("../../spec_helper", __FILE__)
+require "chef/client"
describe Chef::RunLock do
@@ -28,28 +28,27 @@ describe Chef::RunLock do
let(:random_temp_root) do
Kernel.srand(Time.now.to_i + Process.pid)
- "/tmp/#{Kernel.rand(Time.now.to_i + Process.pid)}"
+ "#{Dir.tmpdir}/#{Kernel.rand(Time.now.to_i + Process.pid)}"
end
- let(:lockfile){ "#{random_temp_root}/this/long/path/does/not/exist/chef-client-running.pid" }
+ let(:lockfile) { "#{random_temp_root}/this/long/path/does/not/exist/chef-client-running.pid" }
# make sure to start with a clean slate.
- before(:each){ log_event("rm -rf before"); FileUtils.rm_r(random_temp_root) if File.exist?(random_temp_root) }
- after(:each){ log_event("rm -rf after"); FileUtils.rm_r(random_temp_root) if File.exist?(random_temp_root) }
+ before(:each) { log_event("rm -rf before"); FileUtils.rm_r(random_temp_root) if File.exist?(random_temp_root) }
+ after(:each) { log_event("rm -rf after"); FileUtils.rm_r(random_temp_root) if File.exist?(random_temp_root) }
- def log_event(message, time=Time.now.strftime("%H:%M:%S.%L"))
+ def log_event(message, time = Time.now.strftime("%H:%M:%S.%L"))
events << [ message, time ]
end
+
def events
@events ||= []
end
WAIT_ON_LOCK_TIME = 1.0
- def wait_on_lock
- Timeout::timeout(WAIT_ON_LOCK_TIME) do
- until File.exist?(lockfile)
- sleep 0.1
- end
+ def wait_on_lock(from_fork)
+ Timeout.timeout(WAIT_ON_LOCK_TIME) do
+ from_fork.readline
end
rescue Timeout::Error
raise "Lockfile never created, abandoning test"
@@ -59,8 +58,8 @@ describe Chef::RunLock do
BREATHING_ROOM = 1
# ClientProcess is defined below
- let!(:p1) { ClientProcess.new(self, 'p1') }
- let!(:p2) { ClientProcess.new(self, 'p2') }
+ let!(:p1) { ClientProcess.new(self, "p1") }
+ let!(:p2) { ClientProcess.new(self, "p2") }
after(:each) do |example|
begin
p1.stop
@@ -103,7 +102,7 @@ describe Chef::RunLock do
end
it "the lockfile is empty" do
- expect(IO.read(lockfile)).to eq('')
+ expect(IO.read(lockfile)).to eq("")
end
context "and a second client gets the lock" do
@@ -157,7 +156,7 @@ describe Chef::RunLock do
end
it "the lockfile is empty" do
- expect(IO.read(lockfile)).to eq('')
+ expect(IO.read(lockfile)).to eq("")
end
it "and a second client tries to acquire the lock, it doesn't get the lock until *after* the first client exits" do
@@ -257,37 +256,48 @@ describe Chef::RunLock do
it "test returns true and acquires the lock" do
run_lock = Chef::RunLock.new(lockfile)
+ from_tests, to_fork = IO.pipe
+ from_fork, to_tests = IO.pipe
p1 = fork do
expect(run_lock.test).to eq(true)
- run_lock.save_pid
- sleep 2
- exit! 1
+ to_tests.puts "lock acquired"
+ # Wait for the test to tell us we can exit before exiting
+ from_tests.readline
+ exit! 0
end
- wait_on_lock
+ wait_on_lock(from_fork)
p2 = fork do
expect(run_lock.test).to eq(false)
exit! 0
end
- Process.waitpid2(p2)
- Process.waitpid2(p1)
+ pid, exit_status = Process.waitpid2(p2)
+ expect(exit_status).to eq(0)
+ to_fork.puts "you can exit now"
+ pid, exit_status = Process.waitpid2(p1)
+ expect(exit_status).to eq(0)
end
it "test returns without waiting when the lock is acquired" do
run_lock = Chef::RunLock.new(lockfile)
+ from_tests, to_fork = IO.pipe
+ from_fork, to_tests = IO.pipe
p1 = fork do
run_lock.acquire
- run_lock.save_pid
- sleep 2
- exit! 1
+ to_tests.puts "lock acquired"
+ # Wait for the test to tell us we can exit before exiting
+ from_tests.readline
+ exit! 0
end
- wait_on_lock
-
+ wait_on_lock(from_fork)
expect(run_lock.test).to eq(false)
- Process.waitpid2(p1)
+
+ to_fork.puts "you can exit now"
+ pid, exit_status = Process.waitpid2(p1)
+ expect(exit_status).to eq(0)
end
end
@@ -321,7 +331,7 @@ describe Chef::RunLock do
attr_reader :pid
def last_event
- while true
+ loop do
line = readline_nonblock(read_from_process)
break if line.nil?
event, time = line.split("@")
@@ -342,10 +352,10 @@ describe Chef::RunLock do
write_to_process.print "#{to_event}\n"
# Run the background block
- background_block.call if background_block
+ yield if background_block
# Wait until it gets there
- Timeout::timeout(CLIENT_PROCESS_TIMEOUT) do
+ Timeout.timeout(CLIENT_PROCESS_TIMEOUT) do
until @last_event == "after #{to_event}"
got_event, time = read_from_process.gets.split("@")
example.log_event("#{name}.last_event got #{got_event}")
@@ -372,7 +382,7 @@ describe Chef::RunLock do
def wait_for_exit
example.log_event("#{name}.wait_for_exit (pid #{pid})")
- Timeout::timeout(CLIENT_PROCESS_TIMEOUT) do
+ Timeout.timeout(CLIENT_PROCESS_TIMEOUT) do
Process.wait(pid) if pid
end
example.log_event("#{name}.wait_for_exit finished (pid #{pid})")
@@ -383,11 +393,9 @@ describe Chef::RunLock do
example.log_event("#{name}.stop (pid #{pid})")
begin
# Send it the kill signal over and over until it dies
- Timeout::timeout(CLIENT_PROCESS_TIMEOUT) do
+ Timeout.timeout(CLIENT_PROCESS_TIMEOUT) do
Process.kill(:KILL, pid)
- while !Process.waitpid2(pid, Process::WNOHANG)
- sleep(0.05)
- end
+ sleep(0.05) until Process.waitpid2(pid, Process::WNOHANG)
end
example.log_event("#{name}.stop finished (stopped pid #{pid})")
# Process not found is perfectly fine when we're trying to kill a process :)
@@ -430,7 +438,7 @@ describe Chef::RunLock do
example.log_event("#{name}.start")
@pid = fork do
begin
- Timeout::timeout(CLIENT_PROCESS_TIMEOUT) do
+ Timeout.timeout(CLIENT_PROCESS_TIMEOUT) do
run_lock = TestRunLock.new(example.lockfile)
run_lock.client_process = self
fire_event("started")
diff --git a/spec/functional/shell_spec.rb b/spec/functional/shell_spec.rb
index a753948c7f..636162fb16 100644
--- a/spec/functional/shell_spec.rb
+++ b/spec/functional/shell_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,11 @@
# limitations under the License.
#
-require 'functional/resource/base'
-require 'chef/version'
-require 'chef/shell'
-require 'chef/mixin/command/unix'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/version"
+require "chef/shell"
+require "chef/mixin/command/unix"
describe Shell do
@@ -29,7 +30,7 @@ describe Shell do
describe "smoke tests", :unix_only => true do
include Chef::Mixin::Command::Unix
- TIMEOUT=300
+ TIMEOUT = 300
def read_until(io, expected_value)
start = Time.new
@@ -42,7 +43,7 @@ describe Shell do
end
if Time.new - start > TIMEOUT
raise "did not read expected value `#{expected_value}' within #{TIMEOUT}s\n" +
- "Buffer so far: `#{buffer}'"
+ "Buffer so far: `#{buffer}'"
end
end
buffer
@@ -82,7 +83,7 @@ describe Shell do
when "aix"
config = File.expand_path("shef-config.rb", CHEF_SPEC_DATA)
path_to_chef_shell = File.expand_path("../../../bin/chef-shell", __FILE__)
- output = ''
+ output = ""
status = popen4("#{path_to_chef_shell} -c #{config} #{options}", :waitlast => true) do |pid, stdin, stdout, stderr|
read_until(stdout, "chef (#{Chef::VERSION})>")
yield stdout, stdin if block_given?
@@ -97,7 +98,7 @@ describe Shell do
# Windows ruby installs don't (always?) have PTY,
# so hide the require here
begin
- require 'pty'
+ require "pty"
config = File.expand_path("shef-config.rb", CHEF_SPEC_DATA)
path_to_chef_shell = File.expand_path("../../../bin/chef-shell", __FILE__)
reader, writer, pid = PTY.spawn("#{path_to_chef_shell} -c #{config} #{options}")
@@ -136,7 +137,7 @@ describe Shell do
it "sets the override_runlist from the command line" do
output, exitstatus = run_chef_shell_with("-o 'override::foo,override::bar'") do |out, keyboard|
- show_recipes_code = %q[puts "#{node.recipes.inspect}"]
+ show_recipes_code = %q[puts "#{node["recipes"].inspect}"]
keyboard.puts(show_recipes_code)
read_until(out, show_recipes_code)
end
diff --git a/spec/functional/tiny_server_spec.rb b/spec/functional/tiny_server_spec.rb
index 87be948a0d..1ec56bd490 100644
--- a/spec/functional/tiny_server_spec.rb
+++ b/spec/functional/tiny_server_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tiny_server'
+require "spec_helper"
+require "tiny_server"
describe TinyServer::API do
before do
@@ -26,53 +26,54 @@ describe TinyServer::API do
end
it "is a Singleton" do
- expect {TinyServer::API.new}.to raise_error
+ expect { TinyServer::API.new }.to raise_error NoMethodError
end
it "clears the router" do
- @api.get('/blargh', 200, "blargh")
+ @api.get("/blargh", 200, "blargh")
@api.clear
expect(@api.routes["GET"]).to be_empty
end
it "creates a route for a GET request" do
- @api.get('/foo/bar', 200, 'hello foobar')
+ @api.get("/foo/bar", 200, "hello foobar")
# WEBrick gives you the full URI with host, Thin only gave the part after scheme+host+port
- response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => 'http://localhost:1974/foo/bar')
- expect(response).to eq([200, {'Content-Type' => 'application/json'}, [ 'hello foobar' ]])
+ response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => "http://localhost:1974/foo/bar")
+ expect(response).to eq([200, { "Content-Type" => "application/json" }, [ "hello foobar" ]])
end
it "creates a route for a request with a block" do
block_called = false
- @api.get('/bar/baz', 200) { block_called = true; 'hello barbaz' }
- response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => 'http://localhost:1974/bar/baz')
- expect(response).to eq([200, {'Content-Type' => 'application/json'}, [ 'hello barbaz' ]])
+ @api.get("/bar/baz", 200) { block_called = true; "hello barbaz" }
+ response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => "http://localhost:1974/bar/baz")
+ expect(response).to eq([200, { "Content-Type" => "application/json" }, [ "hello barbaz" ]])
expect(block_called).to be_truthy
end
it "returns debugging info for 404s" do
- response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => '/no_such_thing')
+ response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => "/no_such_thing")
expect(response[0]).to eq(404)
- expect(response[1]).to eq({'Content-Type' => 'application/json'})
+ expect(response[1]).to eq({ "Content-Type" => "application/json" })
expect(response[2]).to be_a_kind_of(Array)
response_obj = Chef::JSONCompat.from_json(response[2].first)
expect(response_obj["message"]).to eq("no data matches the request for /no_such_thing")
- expect(response_obj["available_routes"]).to eq({"GET"=>[], "PUT"=>[], "POST"=>[], "DELETE"=>[]})
- expect(response_obj["request"]).to eq({"REQUEST_METHOD"=>"GET", "REQUEST_URI"=>"/no_such_thing"})
+ expect(response_obj["available_routes"]).to eq({ "GET" => [], "PUT" => [], "POST" => [], "DELETE" => [] })
+ expect(response_obj["request"]).to eq({ "REQUEST_METHOD" => "GET", "REQUEST_URI" => "/no_such_thing" })
end
end
describe TinyServer::Manager do
it "runs the server" do
- @server = TinyServer::Manager.new
- @server.start
+ server = TinyServer::Manager.new
+ server.start
+ begin
+ TinyServer::API.instance.get("/index", 200, "[\"hello\"]")
- TinyServer::API.instance.get("/index", 200, "[\"hello\"]")
-
- rest = Chef::REST.new('http://localhost:9000', false, false)
- expect(rest.get_rest("index")).to eq(["hello"])
-
- @server.stop
+ rest = Chef::HTTP.new("http://localhost:9000")
+ expect(rest.get("index")).to eq("[\"hello\"]")
+ ensure
+ server.stop
+ end
end
end
diff --git a/spec/functional/util/path_helper_spec.rb b/spec/functional/util/path_helper_spec.rb
index 0321702bb8..fd484adff2 100644
--- a/spec/functional/util/path_helper_spec.rb
+++ b/spec/functional/util/path_helper_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'tmpdir'
-require 'chef/util/path_helper'
-require 'spec_helper'
+require "tmpdir"
+require "chef/util/path_helper"
+require "spec_helper"
describe Chef::Util::PathHelper, "escape_glob" do
PathHelper = Chef::Util::PathHelper
@@ -27,10 +27,10 @@ describe Chef::Util::PathHelper, "escape_glob" do
# add some files
files = ["some.rb", "file.txt", "names.csv"]
files.each do |file|
- File.new(File.join(dir, file), 'w').close
+ File.new(File.join(dir, file), "w").close
end
- pattern = File.join(PathHelper.escape_glob(dir), "*")
+ pattern = File.join(PathHelper.escape_glob_dir(dir), "*")
expect(Dir.glob(pattern).map { |x| File.basename(x) }).to match_array(files)
end
end
diff --git a/spec/functional/util/powershell/cmdlet_spec.rb b/spec/functional/util/powershell/cmdlet_spec.rb
index 201fb95af8..19f5e58a49 100644
--- a/spec/functional/util/powershell/cmdlet_spec.rb
+++ b/spec/functional/util/powershell/cmdlet_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
+# Author:: Adam Edwards (<adamed@chef.io>)
#
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,24 +16,21 @@
# limitations under the License.
#
-require 'chef/json_compat'
-require File.expand_path('../../../../spec_helper', __FILE__)
+require "chef/json_compat"
+require File.expand_path("../../../../spec_helper", __FILE__)
-describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only do
+describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only do
before(:all) do
- ohai = Ohai::System.new
- ohai.load_plugins
- ohai.run_plugins(true, ['platform', 'kernel'])
@node = Chef::Node.new
- @node.consume_external_attrs(ohai.data, {})
+ @node.consume_external_attrs(OHAI_SYSTEM.data, {})
end
let(:cmd_output_format) { :text }
- let(:simple_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, 'get-childitem', cmd_output_format, {:depth => 2}) }
- let(:invalid_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, 'get-idontexist', cmd_output_format) }
- let(:cmdlet_get_item_requires_switch_or_argument) { Chef::Util::Powershell::Cmdlet.new(@node, 'get-item', cmd_output_format, {:depth => 2}) }
- let(:cmdlet_alias_requires_switch_or_argument) { Chef::Util::Powershell::Cmdlet.new(@node, 'alias', cmd_output_format, {:depth => 2}) }
+ let(:simple_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, "get-childitem", cmd_output_format, { :depth => 2 }) }
+ let(:invalid_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, "get-idontexist", cmd_output_format) }
+ let(:cmdlet_get_item_requires_switch_or_argument) { Chef::Util::Powershell::Cmdlet.new(@node, "get-item", cmd_output_format, { :depth => 2 }) }
+ let(:cmdlet_alias_requires_switch_or_argument) { Chef::Util::Powershell::Cmdlet.new(@node, "alias", cmd_output_format, { :depth => 2 }) }
let(:etc_directory) { "#{ENV['systemroot']}\\system32\\drivers\\etc" }
- let(:architecture_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, "$env:PROCESSOR_ARCHITECTURE")}
+ let(:architecture_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, "$env:PROCESSOR_ARCHITECTURE") }
it "executes a simple process" do
result = simple_cmdlet.run
@@ -41,17 +38,17 @@ describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only do
end
it "#run does not raise a PowershellCmdletException exception if the command cannot be executed" do
- expect {invalid_cmdlet.run}.not_to raise_error
+ expect { invalid_cmdlet.run }.not_to raise_error
end
it "#run! raises a PowershellCmdletException exception if the command cannot be executed" do
- expect {invalid_cmdlet.run!}.to raise_error(Chef::Exceptions::PowershellCmdletException)
+ expect { invalid_cmdlet.run! }.to raise_error(Chef::Exceptions::PowershellCmdletException)
end
it "executes a 64-bit command on a 64-bit OS, 32-bit otherwise" do
- os_arch = ENV['PROCESSOR_ARCHITEW6432']
+ os_arch = ENV["PROCESSOR_ARCHITEW6432"]
if os_arch.nil?
- os_arch = ENV['PROCESSOR_ARCHITECTURE']
+ os_arch = ENV["PROCESSOR_ARCHITECTURE"]
end
result = architecture_cmdlet.run
@@ -61,17 +58,17 @@ describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only do
end
it "passes command line switches to the command" do
- result = cmdlet_alias_requires_switch_or_argument.run({:name => 'ls'})
+ result = cmdlet_alias_requires_switch_or_argument.run({ :name => "ls" })
expect(result.succeeded?).to eq(true)
end
it "passes command line arguments to the command" do
- result = cmdlet_alias_requires_switch_or_argument.run({},{},'ls')
+ result = cmdlet_alias_requires_switch_or_argument.run({}, {}, "ls")
expect(result.succeeded?).to eq(true)
end
it "passes command line arguments and switches to the command" do
- result = cmdlet_get_item_requires_switch_or_argument.run({:path => etc_directory},{},' | select-object -property fullname | format-table -hidetableheaders')
+ result = cmdlet_get_item_requires_switch_or_argument.run({ :path => etc_directory }, {}, " | select-object -property fullname | format-table -hidetableheaders")
expect(result.succeeded?).to eq(true)
returned_directory = result.return_value
returned_directory.strip!
@@ -79,7 +76,7 @@ describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only do
end
it "passes execution options to the command" do
- result = cmdlet_get_item_requires_switch_or_argument.run({},{:cwd => etc_directory},'. | select-object -property fullname | format-table -hidetableheaders')
+ result = cmdlet_get_item_requires_switch_or_argument.run({}, { :cwd => etc_directory }, ". | select-object -property fullname | format-table -hidetableheaders")
expect(result.succeeded?).to eq(true)
returned_directory = result.return_value
returned_directory.strip!
@@ -89,26 +86,26 @@ describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only do
context "when returning json" do
let(:cmd_output_format) { :json }
it "returns json format data" do
- result = cmdlet_alias_requires_switch_or_argument.run({},{},'ls')
+ result = cmdlet_alias_requires_switch_or_argument.run({}, {}, "ls")
expect(result.succeeded?).to eq(true)
- expect(lambda{Chef::JSONCompat.parse(result.return_value)}).not_to raise_error
+ expect(lambda { Chef::JSONCompat.parse(result.return_value) }).not_to raise_error
end
end
context "when returning Ruby objects" do
let(:cmd_output_format) { :object }
it "returns object format data" do
- result = simple_cmdlet.run({},{:cwd => etc_directory}, 'hosts')
+ result = simple_cmdlet.run({}, { :cwd => etc_directory }, "hosts")
expect(result.succeeded?).to eq(true)
data = result.return_value
- expect(data['Name']).to eq('hosts')
+ expect(data["Name"]).to eq("hosts")
end
end
context "when constructor is given invalid arguments" do
let(:cmd_output_format) { :invalid }
it "throws an exception if an invalid format is passed to the constructor" do
- expect(lambda{simple_cmdlet}).to raise_error
+ expect(lambda { simple_cmdlet }).to raise_error(ArgumentError)
end
end
end
diff --git a/spec/functional/version_spec.rb b/spec/functional/version_spec.rb
index cd5bbc7678..a45c25ff8c 100644
--- a/spec/functional/version_spec.rb
+++ b/spec/functional/version_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,10 +15,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require File.expand_path('../../spec_helper', __FILE__)
-require 'chef/mixin/shell_out'
-require 'chef/version'
-require 'ohai/version'
+require File.expand_path("../../spec_helper", __FILE__)
+require "chef/mixin/shell_out"
+require "chef/version"
+require "ohai/version"
describe "Chef Versions" do
include Chef::Mixin::ShellOut
diff --git a/spec/functional/win32/crypto_spec.rb b/spec/functional/win32/crypto_spec.rb
index 1492995886..145c9881b9 100644
--- a/spec/functional/win32/crypto_spec.rb
+++ b/spec/functional/win32/crypto_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala(<jdm@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,28 +16,25 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
if Chef::Platform.windows?
- require 'chef/win32/crypto'
+ require "chef/win32/crypto"
end
-describe 'Chef::ReservedNames::Win32::Crypto', :windows_only do
- describe '#encrypt' do
+describe "Chef::ReservedNames::Win32::Crypto", :windows_only do
+ describe "#encrypt" do
before(:all) do
- ohai_reader = Ohai::System.new
- ohai_reader.all_plugins("platform")
-
new_node = Chef::Node.new
- new_node.consume_external_attrs(ohai_reader.data,{})
+ new_node.consume_external_attrs(OHAI_SYSTEM.data, {})
events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(new_node, {}, events)
end
- let (:plaintext) { 'p@assword' }
+ let (:plaintext) { "p@assword" }
- it 'can be decrypted by powershell' do
+ it "can be decrypted by powershell" do
encrypted = Chef::ReservedNames::Win32::Crypto.encrypt(plaintext)
resource = Chef::Resource::WindowsScript::PowershellScript.new("Powershell resource functional test", @run_context)
resource.code <<-EOF
diff --git a/spec/functional/win32/registry_spec.rb b/spec/functional/win32/registry_spec.rb
index dcfc49e2b3..bcfa0ffd48 100644
--- a/spec/functional/win32/registry_spec.rb
+++ b/spec/functional/win32/registry_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Prajakta Purohit (<prajakta@opscode.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta@chef.io>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,33 +17,32 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/win32/registry'
+require "spec_helper"
+require "chef/win32/registry"
-describe 'Chef::Win32::Registry', :windows_only do
+describe "Chef::Win32::Registry", :windows_only do
before(:all) do
#Create a registry item
::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root"
::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch"
+ ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\B®anch"
::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch\\Flower"
::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root', Win32::Registry::KEY_ALL_ACCESS) do |reg|
- reg['RootType1', Win32::Registry::REG_SZ] = 'fibrous'
- reg.write('Roots', Win32::Registry::REG_MULTI_SZ, ["strong roots", "healthy tree"])
+ reg["RootType1", Win32::Registry::REG_SZ] = "fibrous"
+ reg.write("Roots", Win32::Registry::REG_MULTI_SZ, ["strong roots", "healthy tree"])
end
::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Branch', Win32::Registry::KEY_ALL_ACCESS) do |reg|
- reg['Strong', Win32::Registry::REG_SZ] = 'bird nest'
+ reg["Strong", Win32::Registry::REG_SZ] = "bird nest"
end
::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Branch\\Flower', Win32::Registry::KEY_ALL_ACCESS) do |reg|
- reg['Petals', Win32::Registry::REG_MULTI_SZ] = ["Pink", "Delicate"]
+ reg["Petals", Win32::Registry::REG_MULTI_SZ] = %w{Pink Delicate}
end
#Create the node with ohai data
events = Chef::EventDispatch::Dispatcher.new
@node = Chef::Node.new
- ohai = Ohai::System.new
- ohai.all_plugins
- @node.consume_external_attrs(ohai.data,{})
+ @node.consume_external_attrs(OHAI_SYSTEM.data, {})
@run_context = Chef::RunContext.new(@node, {}, events)
#Create a registry object that has access ot the node previously created
@@ -83,7 +82,7 @@ describe 'Chef::Win32::Registry', :windows_only do
end
it "throws an exception if the hive does not exist" do
- expect {@registry.key_exists?("JKLM\\Software\\Branch\\Flower")}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.key_exists?("JKLM\\Software\\Branch\\Flower") }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
end
@@ -93,95 +92,95 @@ describe 'Chef::Win32::Registry', :windows_only do
end
it "throws an exception if the key path does not exist" do
- expect {@registry.key_exists!("HKCU\\Software\\Branch\\Flower")}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { @registry.key_exists!("HKCU\\Software\\Branch\\Flower") }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "throws an exception if the hive does not exist" do
- expect {@registry.key_exists!("JKLM\\Software\\Branch\\Flower")}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.key_exists!("JKLM\\Software\\Branch\\Flower") }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
end
describe "value_exists?" do
it "throws an exception if the hive does not exist" do
- expect {@registry.value_exists?("JKLM\\Software\\Branch\\Flower", {:name=>"Petals"})}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.value_exists?("JKLM\\Software\\Branch\\Flower", { :name => "Petals" }) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
it "throws an exception if the key does not exist" do
- expect {@registry.value_exists?("HKCU\\Software\\Branch\\Flower", {:name=>"Petals"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { @registry.value_exists?("HKCU\\Software\\Branch\\Flower", { :name => "Petals" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "returns true if the value exists" do
- expect(@registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals"})).to eq(true)
+ expect(@registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals" })).to eq(true)
end
it "returns true if the value exists with a case mismatch on the value name" do
- expect(@registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"petals"})).to eq(true)
+ expect(@registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "petals" })).to eq(true)
end
it "returns false if the value does not exist" do
- expect(@registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"FOOBAR"})).to eq(false)
+ expect(@registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "FOOBAR" })).to eq(false)
end
end
describe "value_exists!" do
it "throws an exception if the hive does not exist" do
- expect {@registry.value_exists!("JKLM\\Software\\Branch\\Flower", {:name=>"Petals"})}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.value_exists!("JKLM\\Software\\Branch\\Flower", { :name => "Petals" }) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
it "throws an exception if the key does not exist" do
- expect {@registry.value_exists!("HKCU\\Software\\Branch\\Flower", {:name=>"Petals"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { @registry.value_exists!("HKCU\\Software\\Branch\\Flower", { :name => "Petals" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "returns true if the value exists" do
- expect(@registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals"})).to eq(true)
+ expect(@registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals" })).to eq(true)
end
it "returns true if the value exists with a case mismatch on the value name" do
- expect(@registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"petals"})).to eq(true)
+ expect(@registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "petals" })).to eq(true)
end
it "throws an exception if the value does not exist" do
- expect {@registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"FOOBAR"})}.to raise_error(Chef::Exceptions::Win32RegValueMissing)
+ expect { @registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "FOOBAR" }) }.to raise_error(Chef::Exceptions::Win32RegValueMissing)
end
end
describe "data_exists?" do
it "throws an exception if the hive does not exist" do
- expect {@registry.data_exists?("JKLM\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.data_exists?("JKLM\\Software\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => %w{Pink Delicate} }) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
it "throws an exception if the key does not exist" do
- expect {@registry.data_exists?("HKCU\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { @registry.data_exists?("HKCU\\Software\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => %w{Pink Delicate} }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "returns true if all the data matches" do
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})).to eq(true)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => %w{Pink Delicate} })).to eq(true)
end
it "returns true if all the data matches with a case mismatch on the data name" do
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})).to eq(true)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "petals", :type => :multi_string, :data => %w{Pink Delicate} })).to eq(true)
end
it "returns false if the name does not exist" do
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"slateP", :type=>:multi_string, :data=>["Pink", "Delicate"]})).to eq(false)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "slateP", :type => :multi_string, :data => %w{Pink Delicate} })).to eq(false)
end
it "returns false if the types do not match" do
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Pink"})).to eq(false)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :string, :data => "Pink" })).to eq(false)
end
it "returns false if the data does not match" do
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Mauve", "Delicate"]})).to eq(false)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => %w{Mauve Delicate} })).to eq(false)
end
end
describe "data_exists!" do
it "throws an exception if the hive does not exist" do
- expect {@registry.data_exists!("JKLM\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.data_exists!("JKLM\\Software\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => %w{Pink Delicate} }) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
it "throws an exception if the key does not exist" do
- expect {@registry.data_exists!("HKCU\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { @registry.data_exists!("HKCU\\Software\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => %w{Pink Delicate} }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "returns true if all the data matches" do
- expect(@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})).to eq(true)
+ expect(@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => %w{Pink Delicate} })).to eq(true)
end
it "returns true if all the data matches with a case mismatch on the data name" do
- expect(@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})).to eq(true)
+ expect(@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "petals", :type => :multi_string, :data => %w{Pink Delicate} })).to eq(true)
end
it "throws an exception if the name does not exist" do
- expect {@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"slateP", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.to raise_error(Chef::Exceptions::Win32RegDataMissing)
+ expect { @registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "slateP", :type => :multi_string, :data => %w{Pink Delicate} }) }.to raise_error(Chef::Exceptions::Win32RegDataMissing)
end
it "throws an exception if the types do not match" do
- expect {@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Pink"})}.to raise_error(Chef::Exceptions::Win32RegDataMissing)
+ expect { @registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :string, :data => "Pink" }) }.to raise_error(Chef::Exceptions::Win32RegDataMissing)
end
it "throws an exception if the data does not match" do
- expect {@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Mauve", "Delicate"]})}.to raise_error(Chef::Exceptions::Win32RegDataMissing)
+ expect { @registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => %w{Mauve Delicate} }) }.to raise_error(Chef::Exceptions::Win32RegDataMissing)
end
end
@@ -189,85 +188,85 @@ describe 'Chef::Win32::Registry', :windows_only do
it "returns all values for a key if it exists" do
values = @registry.get_values("HKCU\\Software\\Root")
expect(values).to be_an_instance_of Array
- expect(values).to eq([{:name=>"RootType1", :type=>:string, :data=>"fibrous"},
- {:name=>"Roots", :type=>:multi_string, :data=>["strong roots", "healthy tree"]}])
+ expect(values).to eq([{ :name => "RootType1", :type => :string, :data => "fibrous" },
+ { :name => "Roots", :type => :multi_string, :data => ["strong roots", "healthy tree"] }])
end
it "throws an exception if the key does not exist" do
- expect {@registry.get_values("HKCU\\Software\\Branch\\Flower")}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { @registry.get_values("HKCU\\Software\\Branch\\Flower") }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "throws an exception if the hive does not exist" do
- expect {@registry.get_values("JKLM\\Software\\Branch\\Flower")}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.get_values("JKLM\\Software\\Branch\\Flower") }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
end
describe "set_value" do
it "updates a value if the key, value exist and type matches and value different" do
- expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(true)
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(true)
+ expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(true)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(true)
end
it "updates a value if the type does match and the values are different" do
- expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Yellow"})).to eq(true)
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Yellow"})).to eq(true)
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(false)
+ expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :string, :data => "Yellow" })).to eq(true)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :string, :data => "Yellow" })).to eq(true)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(false)
end
it "creates a value if key exists and value does not" do
- expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(true)
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(true)
+ expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Stamen", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(true)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Stamen", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(true)
end
it "does nothing if data,type and name parameters for the value are same" do
- expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(false)
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(true)
+ expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Stamen", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(false)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Stamen", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(true)
end
it "throws an exception if the key does not exist" do
- expect {@registry.set_value("HKCU\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { @registry.set_value("HKCU\\Software\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Yellow", "Changed Color"] }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "throws an exception if the hive does not exist" do
- expect {@registry.set_value("JKLM\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.set_value("JKLM\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Yellow", "Changed Color"] }) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
# we are validating that the data gets .to_i called on it when type is a :dword
it "casts an integer string given as a dword into an integer" do
- expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe32767", :type=>:dword, :data=>"32767"})).to eq(true)
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe32767", :type=>:dword, :data=>32767})).to eq(true)
+ expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBe32767", :type => :dword, :data => "32767" })).to eq(true)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBe32767", :type => :dword, :data => 32767 })).to eq(true)
end
it "casts a nonsense string given as a dword into zero" do
- expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBeZero", :type=>:dword, :data=>"whatdoesthisdo"})).to eq(true)
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBeZero", :type=>:dword, :data=>0})).to eq(true)
+ expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBeZero", :type => :dword, :data => "whatdoesthisdo" })).to eq(true)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBeZero", :type => :dword, :data => 0 })).to eq(true)
end
it "throws an exception when trying to cast an array to an int for a dword" do
- expect {@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldThrow", :type=>:dword, :data=>["one","two"]})}.to raise_error
+ expect { @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldThrow", :type => :dword, :data => %w{one two} }) }.to raise_error NoMethodError
end
# we are validating that the data gets .to_s called on it when type is a :string
it "stores the string representation of an array into a string if you pass it an array" do
- expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBePainful", :type=>:string, :data=>["one","two"]})).to eq(true)
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBePainful", :type=>:string, :data=>'["one", "two"]'})).to eq(true)
+ expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBePainful", :type => :string, :data => %w{one two} })).to eq(true)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBePainful", :type => :string, :data => '["one", "two"]' })).to eq(true)
end
it "stores the string representation of a number into a string if you pass it an number" do
- expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe65535", :type=>:string, :data=>65535})).to eq(true)
- expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe65535", :type=>:string, :data=>"65535"})).to eq(true)
+ expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBe65535", :type => :string, :data => 65535 })).to eq(true)
+ expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBe65535", :type => :string, :data => "65535" })).to eq(true)
end
# we are validating that the data gets .to_a called on it when type is a :multi_string
it "throws an exception when a multi-string is passed a number" do
- expect {@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldThrow", :type=>:multi_string, :data=>65535})}.to raise_error
+ expect { @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldThrow", :type => :multi_string, :data => 65535 }) }.to raise_error NoMethodError
end
it "throws an exception when a multi-string is passed a string" do
- expect {@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBeWat", :type=>:multi_string, :data=>"foo"})}.to raise_error
+ expect { @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBeWat", :type => :multi_string, :data => "foo" }) }.to raise_error NoMethodError
end
end
@@ -282,7 +281,7 @@ describe 'Chef::Win32::Registry', :windows_only do
end
it "throws an exception if the path has missing keys but recursive set to false" do
- expect {@registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", false)}.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+ expect { @registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", false) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker")).to eq(false)
end
@@ -297,7 +296,7 @@ describe 'Chef::Win32::Registry', :windows_only do
end
it "throws an exception of the hive does not exist" do
- expect {@registry.create_key("JKLM\\Software\\Root\\Trunk\\Peck\\Woodpecker", false)}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.create_key("JKLM\\Software\\Root\\Trunk\\Peck\\Woodpecker", false) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
end
@@ -305,26 +304,26 @@ describe 'Chef::Win32::Registry', :windows_only do
before(:all) do
::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk\\Peck\\Woodpecker"
::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Trunk\\Peck\\Woodpecker', Win32::Registry::KEY_ALL_ACCESS) do |reg|
- reg['Peter', Win32::Registry::REG_SZ] = 'Tiny'
+ reg["Peter", Win32::Registry::REG_SZ] = "Tiny"
end
end
it "deletes values if the value exists" do
- expect(@registry.delete_value("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})).to eq(true)
- expect(@registry.value_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})).to eq(false)
+ expect(@registry.delete_value("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", { :name => "Peter", :type => :string, :data => "Tiny" })).to eq(true)
+ expect(@registry.value_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", { :name => "Peter", :type => :string, :data => "Tiny" })).to eq(false)
end
it "does nothing if value does not exist" do
- expect(@registry.delete_value("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})).to eq(true)
- expect(@registry.value_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})).to eq(false)
+ expect(@registry.delete_value("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", { :name => "Peter", :type => :string, :data => "Tiny" })).to eq(true)
+ expect(@registry.value_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", { :name => "Peter", :type => :string, :data => "Tiny" })).to eq(false)
end
it "throws an exception if the key does not exist?" do
- expect {@registry.delete_value("HKCU\\Software\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { @registry.delete_value("HKCU\\Software\\Trunk\\Peck\\Woodpecker", { :name => "Peter", :type => :string, :data => "Tiny" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "throws an exception if the hive does not exist" do
- expect {@registry.delete_value("JKLM\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.delete_value("JKLM\\Software\\Root\\Trunk\\Peck\\Woodpecker", { :name => "Peter", :type => :string, :data => "Tiny" }) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
end
@@ -332,11 +331,11 @@ describe 'Chef::Win32::Registry', :windows_only do
before (:all) do
::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch\\Fruit"
::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Branch\\Fruit', Win32::Registry::KEY_ALL_ACCESS) do |reg|
- reg['Apple', Win32::Registry::REG_MULTI_SZ] = ["Red", "Juicy"]
+ reg["Apple", Win32::Registry::REG_MULTI_SZ] = %w{Red Juicy}
end
::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk\\Peck\\Woodpecker"
::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Trunk\\Peck\\Woodpecker', Win32::Registry::KEY_ALL_ACCESS) do |reg|
- reg['Peter', Win32::Registry::REG_SZ] = 'Tiny'
+ reg["Peter", Win32::Registry::REG_SZ] = "Tiny"
end
end
@@ -361,7 +360,7 @@ describe 'Chef::Win32::Registry', :windows_only do
end
it "throws an exception if the hive does not exist" do
- expect {@registry.delete_key("JKLM\\Software\\Root\\Branch\\Flower", false)}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.delete_key("JKLM\\Software\\Root\\Branch\\Flower", false) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
end
@@ -377,11 +376,11 @@ describe 'Chef::Win32::Registry', :windows_only do
end
it "throws an exception if the hive was missing" do
- expect {@registry.has_subkeys?("LMNO\\Software\\Root")}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.has_subkeys?("LMNO\\Software\\Root") }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
it "throws an exception if the key is missing" do
- expect {@registry.has_subkeys?("HKCU\\Software\\Root\\Trunk\\Red")}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { @registry.has_subkeys?("HKCU\\Software\\Root\\Trunk\\Red") }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "returns true if the key has subkeys" do
@@ -396,16 +395,16 @@ describe 'Chef::Win32::Registry', :windows_only do
describe "get_subkeys" do
it "throws an exception if the key is missing" do
- expect {@registry.get_subkeys("HKCU\\Software\\Trunk\\Red")}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { @registry.get_subkeys("HKCU\\Software\\Trunk\\Red") }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "throws an exception if the hive does not exist" do
- expect {@registry.get_subkeys("JKLM\\Software\\Root")}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+ expect { @registry.get_subkeys("JKLM\\Software\\Root") }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
end
it "returns the array of subkeys for a given key" do
subkeys = @registry.get_subkeys("HKCU\\Software\\Root")
reg_subkeys = []
::Win32::Registry::HKEY_CURRENT_USER.open("Software\\Root", Win32::Registry::KEY_ALL_ACCESS) do |reg|
- reg.each_key{|name| reg_subkeys << name}
+ reg.each_key { |name| reg_subkeys << name }
end
expect(reg_subkeys).to eq(subkeys)
end
@@ -424,7 +423,7 @@ describe 'Chef::Win32::Registry', :windows_only do
context "registry constructor" do
it "throws an exception if requested architecture is 64bit but running on 32bit" do
- expect {Chef::Win32::Registry.new(@run_context, :x86_64)}.to raise_error(Chef::Exceptions::Win32RegArchitectureIncorrect)
+ expect { Chef::Win32::Registry.new(@run_context, :x86_64) }.to raise_error(Chef::Exceptions::Win32RegArchitectureIncorrect)
end
it "can correctly set the requested architecture to 32-bit" do
@@ -442,7 +441,7 @@ describe 'Chef::Win32::Registry', :windows_only do
context "architecture setter" do
it "throws an exception if requested architecture is 64bit but running on 32bit" do
- expect {@registry.architecture = :x86_64}.to raise_error(Chef::Exceptions::Win32RegArchitectureIncorrect)
+ expect { @registry.architecture = :x86_64 }.to raise_error(Chef::Exceptions::Win32RegArchitectureIncorrect)
end
it "sets the requested architecture to :machine if passed :machine" do
@@ -527,12 +526,12 @@ describe 'Chef::Win32::Registry', :windows_only do
# 64-bit
::Win32::Registry::HKEY_LOCAL_MACHINE.create("Software\\Root\\Mauve", ::Win32::Registry::KEY_ALL_ACCESS | 0x0100)
::Win32::Registry::HKEY_LOCAL_MACHINE.open('Software\\Root\\Mauve', Win32::Registry::KEY_ALL_ACCESS | 0x0100) do |reg|
- reg['Alert', Win32::Registry::REG_SZ] = 'Universal'
+ reg["Alert", Win32::Registry::REG_SZ] = "Universal"
end
# 32-bit
::Win32::Registry::HKEY_LOCAL_MACHINE.create("Software\\Root\\Poosh", ::Win32::Registry::KEY_ALL_ACCESS | 0x0200)
::Win32::Registry::HKEY_LOCAL_MACHINE.open('Software\\Root\\Poosh', Win32::Registry::KEY_ALL_ACCESS | 0x0200) do |reg|
- reg['Status', Win32::Registry::REG_SZ] = 'Lost'
+ reg["Status", Win32::Registry::REG_SZ] = "Lost"
end
end
@@ -547,58 +546,58 @@ describe 'Chef::Win32::Registry', :windows_only do
describe "key_exists?" do
it "does not find 64-bit keys in the 32-bit registry" do
- @registry.architecture=:i386
+ @registry.architecture = :i386
expect(@registry.key_exists?("HKLM\\Software\\Root\\Mauve")).to eq(false)
end
it "finds 32-bit keys in the 32-bit registry" do
- @registry.architecture=:i386
+ @registry.architecture = :i386
expect(@registry.key_exists?("HKLM\\Software\\Root\\Poosh")).to eq(true)
end
it "does not find 32-bit keys in the 64-bit registry" do
- @registry.architecture=:x86_64
+ @registry.architecture = :x86_64
expect(@registry.key_exists?("HKLM\\Software\\Root\\Mauve")).to eq(true)
end
it "finds 64-bit keys in the 64-bit registry" do
- @registry.architecture=:x86_64
+ @registry.architecture = :x86_64
expect(@registry.key_exists?("HKLM\\Software\\Root\\Poosh")).to eq(false)
end
end
describe "value_exists?" do
it "does not find 64-bit values in the 32-bit registry" do
- @registry.architecture=:i386
- expect{@registry.value_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ @registry.architecture = :i386
+ expect { @registry.value_exists?("HKLM\\Software\\Root\\Mauve", { :name => "Alert" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "finds 32-bit values in the 32-bit registry" do
- @registry.architecture=:i386
- expect(@registry.value_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status"})).to eq(true)
+ @registry.architecture = :i386
+ expect(@registry.value_exists?("HKLM\\Software\\Root\\Poosh", { :name => "Status" })).to eq(true)
end
it "does not find 32-bit values in the 64-bit registry" do
- @registry.architecture=:x86_64
- expect(@registry.value_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert"})).to eq(true)
+ @registry.architecture = :x86_64
+ expect(@registry.value_exists?("HKLM\\Software\\Root\\Mauve", { :name => "Alert" })).to eq(true)
end
it "finds 64-bit values in the 64-bit registry" do
- @registry.architecture=:x86_64
- expect{@registry.value_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ @registry.architecture = :x86_64
+ expect { @registry.value_exists?("HKLM\\Software\\Root\\Poosh", { :name => "Status" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
end
describe "data_exists?" do
it "does not find 64-bit keys in the 32-bit registry" do
- @registry.architecture=:i386
- expect{@registry.data_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert", :type=>:string, :data=>"Universal"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ @registry.architecture = :i386
+ expect { @registry.data_exists?("HKLM\\Software\\Root\\Mauve", { :name => "Alert", :type => :string, :data => "Universal" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "finds 32-bit keys in the 32-bit registry" do
- @registry.architecture=:i386
- expect(@registry.data_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status", :type=>:string, :data=>"Lost"})).to eq(true)
+ @registry.architecture = :i386
+ expect(@registry.data_exists?("HKLM\\Software\\Root\\Poosh", { :name => "Status", :type => :string, :data => "Lost" })).to eq(true)
end
it "does not find 32-bit keys in the 64-bit registry" do
- @registry.architecture=:x86_64
- expect(@registry.data_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert", :type=>:string, :data=>"Universal"})).to eq(true)
+ @registry.architecture = :x86_64
+ expect(@registry.data_exists?("HKLM\\Software\\Root\\Mauve", { :name => "Alert", :type => :string, :data => "Universal" })).to eq(true)
end
it "finds 64-bit keys in the 64-bit registry" do
- @registry.architecture=:x86_64
- expect{@registry.data_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status", :type=>:string, :data=>"Lost"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ @registry.architecture = :x86_64
+ expect { @registry.data_exists?("HKLM\\Software\\Root\\Poosh", { :name => "Status", :type => :string, :data => "Lost" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
end
diff --git a/spec/functional/win32/security_spec.rb b/spec/functional/win32/security_spec.rb
index 27af263860..40ae99bfa4 100644
--- a/spec/functional/win32/security_spec.rb
+++ b/spec/functional/win32/security_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
if Chef::Platform.windows?
- require 'chef/win32/security'
+ require "chef/win32/security"
end
-describe 'Chef::Win32::Security', :windows_only do
+describe "Chef::Win32::Security", :windows_only do
it "has_admin_privileges? returns true when running as admin" do
expect(Chef::ReservedNames::Win32::Security.has_admin_privileges?).to eq(true)
end
@@ -35,8 +35,8 @@ describe 'Chef::Win32::Security', :windows_only do
skip "requires user support in mixlib-shellout"
end
- describe 'get_file_security' do
- it 'should return a security descriptor when called with a path that exists' do
+ describe "get_file_security" do
+ it "should return a security descriptor when called with a path that exists" do
security_descriptor = Chef::ReservedNames::Win32::Security.get_file_security(
"C:\\Program Files")
# Make sure the security descriptor works
@@ -44,56 +44,56 @@ describe 'Chef::Win32::Security', :windows_only do
end
end
- describe 'access_check' do
- let(:security_descriptor) {
+ describe "access_check" do
+ let(:security_descriptor) do
Chef::ReservedNames::Win32::Security.get_file_security(
"C:\\Program Files")
- }
+ end
let(:token_rights) { Chef::ReservedNames::Win32::Security::TOKEN_ALL_ACCESS }
- let(:token) {
+ let(:token) do
Chef::ReservedNames::Win32::Security.open_process_token(
Chef::ReservedNames::Win32::Process.get_current_process,
token_rights).duplicate_token(:SecurityImpersonation)
- }
+ end
- let(:mapping) {
+ let(:mapping) do
mapping = Chef::ReservedNames::Win32::Security::GENERIC_MAPPING.new
mapping[:GenericRead] = Chef::ReservedNames::Win32::Security::FILE_GENERIC_READ
mapping[:GenericWrite] = Chef::ReservedNames::Win32::Security::FILE_GENERIC_WRITE
mapping[:GenericExecute] = Chef::ReservedNames::Win32::Security::FILE_GENERIC_EXECUTE
mapping[:GenericAll] = Chef::ReservedNames::Win32::Security::FILE_ALL_ACCESS
mapping
- }
+ end
let(:desired_access) { Chef::ReservedNames::Win32::Security::FILE_GENERIC_READ }
- it 'should check if the provided token has the desired access' do
- expect(Chef::ReservedNames::Win32::Security.access_check(security_descriptor,
+ it "should check if the provided token has the desired access" do
+ expect(Chef::ReservedNames::Win32::Security.access_check(security_descriptor,
token, desired_access, mapping)).to be true
end
end
- describe 'Chef::Win32::Security::Token' do
- let(:token) {
+ describe "Chef::Win32::Security::Token" do
+ let(:token) do
Chef::ReservedNames::Win32::Security.open_process_token(
Chef::ReservedNames::Win32::Process.get_current_process,
token_rights)
- }
- context 'with all rights' do
+ end
+ context "with all rights" do
let(:token_rights) { Chef::ReservedNames::Win32::Security::TOKEN_ALL_ACCESS }
- it 'can duplicate a token' do
- expect{ token.duplicate_token(:SecurityImpersonation) }.not_to raise_error
+ it "can duplicate a token" do
+ expect { token.duplicate_token(:SecurityImpersonation) }.not_to raise_error
end
end
- context 'with read only rights' do
+ context "with read only rights" do
let(:token_rights) { Chef::ReservedNames::Win32::Security::TOKEN_READ }
- it 'raises an exception when trying to duplicate' do
- expect{ token.duplicate_token(:SecurityImpersonation) }.to raise_error(Chef::Exceptions::Win32APIError)
+ it "raises an exception when trying to duplicate" do
+ expect { token.duplicate_token(:SecurityImpersonation) }.to raise_error(Chef::Exceptions::Win32APIError)
end
end
end
diff --git a/spec/functional/win32/service_manager_spec.rb b/spec/functional/win32/service_manager_spec.rb
index a1ce36146f..8fff73396e 100644
--- a/spec/functional/win32/service_manager_spec.rb
+++ b/spec/functional/win32/service_manager_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
if Chef::Platform.windows?
- require 'chef/application/windows_service_manager'
+ require "chef/application/windows_service_manager"
end
#
@@ -81,7 +81,7 @@ describe "Chef::Application::WindowsServiceManager", :windows_only, :system_wind
end
it "other actions => should say service doesn't exist" do
- ["delete", "start", "stop", "pause", "resume", "uninstall"].each do |action|
+ %w{delete start stop pause resume uninstall}.each do |action|
service_manager.run(["-a", action])
expect(@service_manager_output.grep(/doesn't exist on the system/).length).to be > 0
@service_manager_output = [ ]
@@ -101,12 +101,12 @@ describe "Chef::Application::WindowsServiceManager", :windows_only, :system_wind
end
it "install => should say service already exists" do
- service_manager.run(["-a", "install"])
- expect(@service_manager_output.grep(/already exists/).length).to be > 0
+ service_manager.run(["-a", "install"])
+ expect(@service_manager_output.grep(/already exists/).length).to be > 0
end
context "and service is stopped" do
- ["delete", "uninstall"].each do |action|
+ %w{delete uninstall}.each do |action|
it "#{action} => should remove the service", :volatile do
service_manager.run(["-a", action])
expect(test_service_exists?).to be_falsey
@@ -133,8 +133,7 @@ describe "Chef::Application::WindowsServiceManager", :windows_only, :system_wind
expect(test_service_state).to eq("stopped")
end
-
- ["pause", "resume"].each do |action|
+ %w{pause resume}.each do |action|
it "#{action} => should raise error" do
expect { service_manager.run(["-a", action]) }.to raise_error(SystemCallError)
end
@@ -145,7 +144,7 @@ describe "Chef::Application::WindowsServiceManager", :windows_only, :system_wind
service_manager.run(["-a", "start"])
end
- ["delete", "uninstall"].each do |action|
+ %w{delete uninstall}.each do |action|
it "#{action} => should remove the service", :volatile do
service_manager.run(["-a", action])
expect(test_service_exists?).to be_falsey
@@ -183,7 +182,7 @@ describe "Chef::Application::WindowsServiceManager", :windows_only, :system_wind
service_manager.run(["-a", "pause"])
end
- actions = ["delete", "uninstall"]
+ actions = %w{delete uninstall}
actions.each do |action|
it "#{action} => should remove the service" do
service_manager.run(["-a", action])
@@ -211,7 +210,7 @@ describe "Chef::Application::WindowsServiceManager", :windows_only, :system_wind
end
it "start should raise an error" do
- expect {service_manager.run(["-a", "start"])}.to raise_error(::Win32::Service::Error)
+ expect { service_manager.run(["-a", "start"]) }.to raise_error(::Win32::Service::Error)
end
end
diff --git a/spec/functional/win32/sid_spec.rb b/spec/functional/win32/sid_spec.rb
index 1f5f66178a..eac62d88b6 100644
--- a/spec/functional/win32/sid_spec.rb
+++ b/spec/functional/win32/sid_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Dan Bjorge (<dbjorge@gmail.com>)
-# Copyright:: Copyright (c) 2015 Dan Bjorge
+# Copyright:: Copyright 2015-2016, Dan Bjorge
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,39 +16,39 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
if Chef::Platform.windows?
- require 'chef/win32/security'
+ require "chef/win32/security"
end
-describe 'Chef::ReservedNames::Win32::SID', :windows_only do
+describe "Chef::ReservedNames::Win32::SID", :windows_only do
if Chef::Platform.windows?
SID ||= Chef::ReservedNames::Win32::Security::SID
end
- it 'should resolve default_security_object_group as a sane user group', :windows_not_domain_joined_only do
+ it "should resolve default_security_object_group as a sane user group", :windows_not_domain_joined_only do
# Domain accounts: domain-specific Domain Users SID
# Microsoft Accounts: SID.current_user
# Else: SID.None
expect(SID.default_security_object_group).to eq(SID.None).or eq(SID.current_user)
end
- context 'running as an elevated administrator user' do
- it 'should resolve default_security_object_owner as the Administrators group' do
+ context "running as an elevated administrator user" do
+ it "should resolve default_security_object_owner as the Administrators group" do
expect(SID.default_security_object_owner).to eq(SID.Administrators)
end
end
- context 'running as a non-elevated administrator user' do
- it 'should resolve default_security_object_owner as the current user' do
- skip 'requires user support in mixlib-shellout, see security_spec.rb'
+ context "running as a non-elevated administrator user" do
+ it "should resolve default_security_object_owner as the current user" do
+ skip "requires user support in mixlib-shellout, see security_spec.rb"
expect(SID.default_security_object_owner).to eq(SID.Administrators)
end
end
- context 'running as a non-elevated, non-administrator user' do
- it 'should resolve default_security_object_owner as the current user' do
- skip 'requires user support in mixlib-shellout, see security_spec.rb'
+ context "running as a non-elevated, non-administrator user" do
+ it "should resolve default_security_object_owner as the current user" do
+ skip "requires user support in mixlib-shellout, see security_spec.rb"
expect(SID.default_security_object_owner).to eq(SID.current_user)
end
end
diff --git a/spec/functional/win32/version_info_spec.rb b/spec/functional/win32/version_info_spec.rb
new file mode 100644
index 0000000000..b5570732a0
--- /dev/null
+++ b/spec/functional/win32/version_info_spec.rb
@@ -0,0 +1,50 @@
+#
+# Author:: Matt Wrock (<matt@mattwrock.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+if Chef::Platform.windows?
+ require "chef/win32/file/version_info"
+end
+
+describe "Chef::ReservedNames::Win32::File::VersionInfo", :windows_only do
+ require "wmi-lite/wmi"
+ let(:file_path) { ENV["ComSpec"] }
+ let(:os_version) do
+ wmi = WmiLite::Wmi.new
+ os_info = wmi.first_of("Win32_OperatingSystem")
+ os_info["version"]
+ end
+
+ subject { Chef::ReservedNames::Win32::File::VersionInfo.new(file_path) }
+
+ it "file version has the same version as windows" do
+ expect(subject.FileVersion).to start_with(os_version)
+ end
+
+ it "product version has the same version as windows" do
+ expect(subject.ProductVersion).to start_with(os_version)
+ end
+
+ it "company is microsoft" do
+ expect(subject.CompanyName).to eq("Microsoft Corporation")
+ end
+
+ it "file description is command processor" do
+ expect(subject.FileDescription).to eq("Windows Command Processor")
+ end
+end
diff --git a/spec/functional/win32/versions_spec.rb b/spec/functional/win32/versions_spec.rb
index 38af47b0c9..d6e840ed7f 100644
--- a/spec/functional/win32/versions_spec.rb
+++ b/spec/functional/win32/versions_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Chirag Jog (<chirag@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
if Chef::Platform.windows?
- require 'chef/win32/version'
+ require "chef/win32/version"
end
describe "Chef::ReservedNames::Win32::Version", :windows_only, :not_supported_on_win2k3 do
before do
wmi = WmiLite::Wmi.new
- host = wmi.first_of('Win32_OperatingSystem')
+ host = wmi.first_of("Win32_OperatingSystem")
# Use WMI to determine current OS version.
# On Win2k8R2 and later, we can dynamically obtain marketing
@@ -36,23 +36,23 @@ describe "Chef::ReservedNames::Win32::Version", :windows_only, :not_supported_on
# from WMI contain extended characters such as registered
# trademark on Win2k8 and Win2k3 that we're not using in our
# library, so we have to set the expectation statically.
- if Chef::Platform::windows_server_2003?
- @current_os_version = 'Windows Server 2003 R2'
+ if Chef::Platform.windows_server_2003?
+ @current_os_version = "Windows Server 2003 R2"
elsif is_windows_server_2008?(host)
- @current_os_version = 'Windows Server 2008'
+ @current_os_version = "Windows Server 2008"
else
# The name from WMI is actually what we want in Win2k8R2+.
# So this expectation sould continue to hold without modification
# as new versions of Windows are released.
- @current_os_version = host['caption']
+ @current_os_version = host["caption"]
end
@version = Chef::ReservedNames::Win32::Version.new
end
- def for_each_windows_version(&block)
+ def for_each_windows_version
@version.methods.each do |method_name|
- if Chef::ReservedNames::Win32::Version::WIN_VERSIONS.keys.find { | key | method_name.to_s == Chef::ReservedNames::Win32::Version.send(:method_name_from_marketing_name,key) }
+ if Chef::ReservedNames::Win32::Version::WIN_VERSIONS.keys.find { |key| method_name.to_s == Chef::ReservedNames::Win32::Version.send(:method_name_from_marketing_name, key) }
yield method_name
end
end
@@ -98,20 +98,20 @@ describe "Chef::ReservedNames::Win32::Version", :windows_only, :not_supported_on
def is_windows_server_2008?(wmi_host)
is_win2k8 = false
- os_version = wmi_host['version']
+ os_version = wmi_host["version"]
# The operating system version is a string in the following form
# that can be split into components based on the '.' delimiter:
# MajorVersionNumber.MinorVersionNumber.BuildNumber
- os_version_components = os_version.split('.')
+ os_version_components = os_version.split(".")
if os_version_components.length < 2
- raise 'WMI returned a Windows version from Win32_OperatingSystem.Version ' +
- 'with an unexpected format. The Windows version could not be determined.'
+ raise "WMI returned a Windows version from Win32_OperatingSystem.Version " +
+ "with an unexpected format. The Windows version could not be determined."
end
# Windows 6.0 is Windows Server 2008, so test the major and
# minor version components
- is_win2k8 = os_version_components[0] == '6' && os_version_components[1] == '0'
+ is_win2k8 = os_version_components[0] == "6" && os_version_components[1] == "0"
end
end
diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb
index 314a9310be..7a8059066a 100644
--- a/spec/integration/client/client_spec.rb
+++ b/spec/integration/client/client_spec.rb
@@ -1,30 +1,29 @@
-require 'support/shared/integration/integration_helper'
-require 'chef/mixin/shell_out'
-require 'tiny_server'
-require 'tmpdir'
-
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
+require "tiny_server"
+require "tmpdir"
describe "chef-client" do
def recipes_filename
- File.join(CHEF_SPEC_DATA, 'recipes.tgz')
+ File.join(CHEF_SPEC_DATA, "recipes.tgz")
end
- def start_tiny_server(server_opts={})
+ def start_tiny_server(server_opts = {})
@server = TinyServer::Manager.new(server_opts)
@server.start
- @api = TinyServer::API.instance
+ @api = TinyServer::API.instance
@api.clear
#
# trivial endpoints
#
# just a normal file
# (expected_content should be uncompressed)
- @api.get("/recipes.tgz", 200) {
+ @api.get("/recipes.tgz", 200) do
File.open(recipes_filename, "rb") do |f|
f.read
end
- }
+ end
end
def stop_tiny_server
@@ -47,14 +46,15 @@ describe "chef-client" do
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_solo) { "ruby '#{chef_dir}/chef-solo' --minimal-ohai" }
- let(:critical_env_vars) { %w(PATH RUBYOPT BUNDLE_GEMFILE GEM_PATH).map {|o| "#{o}=#{ENV[o]}"} .join(' ') }
+ let(:critical_env_vars) { %w{_ORIGINAL_GEM_PATH GEM_PATH GEM_HOME GEM_ROOT BUNDLE_BIN_PATH BUNDLE_GEMFILE RUBYLIB RUBYOPT RUBY_ENGINE RUBY_ROOT RUBY_VERSION PATH}.map { |o| "#{o}=#{ENV[o]}" } .join(" ") }
when_the_repository "has a cookbook with a no-op recipe" do
- before { file 'cookbooks/x/recipes/default.rb', '' }
+ before { file "cookbooks/x/recipes/default.rb", "" }
it "should complete with success" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
EOM
@@ -63,7 +63,7 @@ EOM
end
it "should complete successfully with no other environment variables", :skip => (Chef::Platform.windows?) do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
EOM
@@ -79,7 +79,7 @@ EOM
end
it "should complete successfully with --no-listen" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
EOM
@@ -90,32 +90,32 @@ EOM
it "should be able to node.save with bad utf8 characters in the node data" do
file "cookbooks/x/attributes/default.rb", 'default["badutf8"] = "Elan Ruusam\xE4e"'
- result = shell_out("#{chef_client} -z -r 'x::default' --disable-config", :cwd => path_to(''))
+ result = shell_out("#{chef_client} -z -r 'x::default' --disable-config", :cwd => path_to(""))
result.error!
end
- context 'and no config file' do
- it 'should complete with success when cwd is just above cookbooks and paths are not specified' do
- result = shell_out("#{chef_client} -z -o 'x::default' --disable-config", :cwd => path_to(''))
+ context "and no config file" do
+ it "should complete with success when cwd is just above cookbooks and paths are not specified" do
+ result = shell_out("#{chef_client} -z -o 'x::default' --disable-config", :cwd => path_to(""))
result.error!
end
- it 'should complete with success when cwd is below cookbooks and paths are not specified' do
- result = shell_out("#{chef_client} -z -o 'x::default' --disable-config", :cwd => path_to('cookbooks/x'))
+ it "should complete with success when cwd is below cookbooks and paths are not specified" do
+ result = shell_out("#{chef_client} -z -o 'x::default' --disable-config", :cwd => path_to("cookbooks/x"))
result.error!
end
- it 'should fail when cwd is below high above and paths are not specified' do
- result = shell_out("#{chef_client} -z -o 'x::default' --disable-config", :cwd => File.expand_path('..', path_to('')))
+ it "should fail when cwd is below high above and paths are not specified" do
+ result = shell_out("#{chef_client} -z -o 'x::default' --disable-config", :cwd => File.expand_path("..", path_to("")))
expect(result.exitstatus).to eq(1)
end
end
- context 'and a config file under .chef/knife.rb' do
- before { file '.chef/knife.rb', 'xxx.xxx' }
+ context "and a config file under .chef/knife.rb" do
+ before { file ".chef/knife.rb", "xxx.xxx" }
- it 'should load .chef/knife.rb when -z is specified' do
- result = shell_out("#{chef_client} -z -o 'x::default'", :cwd => path_to(''))
+ it "should load .chef/knife.rb when -z is specified" do
+ result = shell_out("#{chef_client} -z -o 'x::default'", :cwd => path_to(""))
# FATAL: Configuration error NoMethodError: undefined method `xxx' for nil:NilClass
expect(result.stdout).to include("xxx")
end
@@ -123,7 +123,7 @@ EOM
end
it "should complete with success" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
EOM
@@ -132,9 +132,9 @@ EOM
result.error!
end
- context 'and a private key' do
+ context "and a private key" do
before do
- file 'mykey.pem', <<EOM
+ file "mykey.pem", <<EOM
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEApubutqtYYQ5UiA9QhWP7UvSmsfHsAoPKEVVPdVW/e8Svwpyf
0Xef6OFWVmBE+W442ZjLOe2y6p2nSnaq4y7dg99NFz6X+16mcKiCbj0RCiGqCvCk
@@ -166,7 +166,7 @@ EOM
end
it "should complete with success even with a client key" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
client_key #{path_to('mykey.pem').inspect}
cookbook_path #{path_to('cookbooks').inspect}
@@ -177,19 +177,19 @@ EOM
end
it "should run recipes specified directly on the command line" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
client_key #{path_to('mykey.pem').inspect}
cookbook_path #{path_to('cookbooks').inspect}
EOM
- file 'arbitrary.rb', <<EOM
+ file "arbitrary.rb", <<EOM
file #{path_to('tempfile.txt').inspect} do
content '1'
end
EOM
- file 'arbitrary2.rb', <<EOM
+ file "arbitrary2.rb", <<EOM
file #{path_to('tempfile2.txt').inspect} do
content '2'
end
@@ -198,57 +198,57 @@ EOM
result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" #{path_to('arbitrary.rb')} #{path_to('arbitrary2.rb')}", :cwd => chef_dir)
result.error!
- expect(IO.read(path_to('tempfile.txt'))).to eq('1')
- expect(IO.read(path_to('tempfile2.txt'))).to eq('2')
+ expect(IO.read(path_to("tempfile.txt"))).to eq("1")
+ expect(IO.read(path_to("tempfile2.txt"))).to eq("2")
end
it "should run recipes specified as relative paths directly on the command line" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
client_key #{path_to('mykey.pem').inspect}
cookbook_path #{path_to('cookbooks').inspect}
EOM
- file 'arbitrary.rb', <<EOM
+ file "arbitrary.rb", <<EOM
file #{path_to('tempfile.txt').inspect} do
content '1'
end
EOM
- result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" arbitrary.rb", :cwd => path_to(''))
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" arbitrary.rb", :cwd => path_to(""))
result.error!
- expect(IO.read(path_to('tempfile.txt'))).to eq('1')
+ expect(IO.read(path_to("tempfile.txt"))).to eq("1")
end
it "should run recipes specified directly on the command line AFTER recipes in the run list" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
client_key #{path_to('mykey.pem').inspect}
cookbook_path #{path_to('cookbooks').inspect}
EOM
- file 'cookbooks/x/recipes/constant_definition.rb', <<EOM
+ file "cookbooks/x/recipes/constant_definition.rb", <<EOM
class ::Blah
THECONSTANT = '1'
end
EOM
- file 'arbitrary.rb', <<EOM
+ file "arbitrary.rb", <<EOM
file #{path_to('tempfile.txt').inspect} do
content ::Blah::THECONSTANT
end
EOM
- result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o x::constant_definition arbitrary.rb", :cwd => path_to(''))
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o x::constant_definition arbitrary.rb", :cwd => path_to(""))
result.error!
- expect(IO.read(path_to('tempfile.txt'))).to eq('1')
+ expect(IO.read(path_to("tempfile.txt"))).to eq("1")
end
end
it "should complete with success when passed the -z flag" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
chef_server_url 'http://omg.com/blah'
cookbook_path "#{path_to('cookbooks')}"
EOM
@@ -258,7 +258,7 @@ EOM
end
it "should complete with success when passed the --local-mode flag" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
chef_server_url 'http://omg.com/blah'
cookbook_path "#{path_to('cookbooks')}"
EOM
@@ -268,7 +268,7 @@ EOM
end
it "should not print SSL warnings when running in local-mode" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
chef_server_url 'http://omg.com/blah'
cookbook_path "#{path_to('cookbooks')}"
EOM
@@ -279,7 +279,7 @@ EOM
end
it "should complete with success when passed -z and --chef-zero-port" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
chef_server_url 'http://omg.com/blah'
cookbook_path "#{path_to('cookbooks')}"
EOM
@@ -289,7 +289,7 @@ EOM
end
it "should complete with success when setting the run list with -r" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
chef_server_url 'http://omg.com/blah'
cookbook_path "#{path_to('cookbooks')}"
EOM
@@ -302,7 +302,7 @@ EOM
end
it "should complete with success when using --profile-ruby and output a profile file" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
EOM
@@ -311,7 +311,7 @@ EOM
end
it "doesn't produce a profile when --profile-ruby is not present" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
EOM
@@ -320,9 +320,74 @@ EOM
end
end
+ when_the_repository "has a cookbook that should fail chef_version checks" do
+ before do
+ file "cookbooks/x/recipes/default.rb", ""
+ file "cookbooks/x/metadata.rb", <<EOM
+name 'x'
+version '0.0.1'
+chef_version '~> 999.99'
+EOM
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+EOM
+ end
+ it "should fail the chef client run" do
+ command = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' --no-fork", :cwd => chef_dir)
+ expect(command.exitstatus).to eql(1)
+ expect(command.stdout).to match(/Chef::Exceptions::CookbookChefVersionMismatch/)
+ end
+ end
+
+ when_the_repository "has a cookbook that uses cheffish resources" do
+ before do
+ file "cookbooks/x/recipes/default.rb", <<-EOM
+ raise "Cheffish was loaded before we used any cheffish things!" if defined?(Cheffish::VERSION)
+ ran_block = false
+ got_server = with_chef_server 'https://blah.com' do
+ ran_block = true
+ run_context.cheffish.current_chef_server
+ end
+ raise "with_chef_server block was not run!" if !ran_block
+ raise "Cheffish was not loaded when we did cheffish things!" if !defined?(Cheffish::VERSION)
+ raise "current_chef_server did not return its value!" if got_server[:chef_server_url] != 'https://blah.com'
+ EOM
+ file "config/client.rb", <<-EOM
+ local_mode true
+ cookbook_path "#{path_to('cookbooks')}"
+ EOM
+ end
+
+ it "the cheffish DSL is loaded lazily" do
+ command = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' --no-fork", :cwd => chef_dir)
+ expect(command.exitstatus).to eql(0)
+ end
+ end
+
+ when_the_repository "has a cookbook that uses chef-provisioning resources" do
+ before do
+ file "cookbooks/x/recipes/default.rb", <<-EOM
+ with_driver 'blah'
+ EOM
+ file "config/client.rb", <<-EOM
+ local_mode true
+ cookbook_path "#{path_to('cookbooks')}"
+ EOM
+ end
+
+ it "the cheffish DSL tries to load but fails (because chef-provisioning is not there)" do
+ # we'd need to have a custom bundle to fix this that omitted chef-provisioning, but that would dig our crazy even deeper, so lets not
+ skip "but if chef-provisioning is in our bundle or in our gemset then this test, very annoyingly, always fails"
+ command = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' --no-fork", :cwd => chef_dir)
+ expect(command.exitstatus).to eql(1)
+ expect(command.stdout).to match(/cannot load such file -- chef\/provisioning/)
+ end
+ end
+
when_the_repository "has a cookbook that generates deprecation warnings" do
before do
- file 'cookbooks/x/recipes/default.rb', <<-EOM
+ file "cookbooks/x/recipes/default.rb", <<-EOM
class ::MyResource < Chef::Resource
use_automatic_resource_name
property :x, default: []
@@ -349,7 +414,7 @@ EOM
end
it "should output each deprecation warning only once, at the end of the run" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
# Mimick what happens when you are on the console
@@ -357,7 +422,7 @@ formatters << :doc
log_level :warn
EOM
- ENV.delete('CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS')
+ ENV.delete("CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS")
result = shell_out!("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'", :cwd => chef_dir)
expect(result.error?).to be_falsey
@@ -367,14 +432,14 @@ EOM
expect(run_complete).to be >= 0
# Make sure there is exactly one result for each, and that it occurs *after* the complete message.
- expect(match_indices(/nil currently does not overwrite the value of/, result.stdout)).to match([ be > run_complete ])
+ expect(match_indices(/An attempt was made to change x from \[\] to nil by calling x\(nil\). In Chef 12, this does a get rather than a set. In Chef 13, this will change to set the value to nil./, result.stdout)).to match([ be > run_complete ])
end
end
when_the_repository "has a cookbook with only an audit recipe" do
before do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
audit_mode :enabled
@@ -382,7 +447,7 @@ EOM
end
it "should exit with a zero code when there is not an audit failure" do
- file 'cookbooks/audit_test/recipes/succeed.rb', <<-RECIPE
+ file "cookbooks/audit_test/recipes/succeed.rb", <<-RECIPE
control_group "control group without top level control" do
it "should succeed" do
expect(2 - 2).to eq(0)
@@ -396,7 +461,7 @@ end
end
it "should exit with a non-zero code when there is an audit failure" do
- file 'cookbooks/audit_test/recipes/fail.rb', <<-RECIPE
+ file "cookbooks/audit_test/recipes/fail.rb", <<-RECIPE
control_group "control group without top level control" do
it "should fail" do
expect(2 - 2).to eq(1)
@@ -412,27 +477,59 @@ end
# Fails on appveyor, but works locally on windows and on windows hosts in Ci.
context "when using recipe-url", :skip_appveyor do
- before(:all) do
+ before(:each) do
start_tiny_server
end
- after(:all) do
+ after(:each) do
stop_tiny_server
end
let(:tmp_dir) { Dir.mktmpdir("recipe-url") }
it "should complete with success when passed -z and --recipe-url" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
chef_repo_path "#{tmp_dir}"
EOM
result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --recipe-url=http://localhost:9000/recipes.tgz -o 'x::default' -z", :cwd => tmp_dir)
result.error!
end
- it 'should fail when passed --recipe-url and not passed -z' do
+ it "should fail when passed --recipe-url and not passed -z" do
result = shell_out("#{chef_client} --recipe-url=http://localhost:9000/recipes.tgz", :cwd => tmp_dir)
expect(result.exitstatus).not_to eq(0)
end
end
+
+ when_the_repository "has a cookbook with broken metadata.rb, but has metadata.json" do
+ before do
+ file "cookbooks/x/recipes/default.rb", ""
+ file "cookbooks/x/metadata.rb", <<EOM
+name 'x'
+version '0.0.1'
+raise "TEH SADNESS"
+EOM
+ file "cookbooks/x/metadata.json", <<EOM
+{
+ "name": "x",
+ "version": "0.0.1"
+}
+EOM
+
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+EOM
+ end
+
+ it "the chef client run should succeed" do
+ command = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' --no-fork", :cwd => chef_dir)
+ command.error!
+ end
+
+ it "a chef-solo run should succeed" do
+ command = shell_out("#{chef_solo} -c \"#{path_to('config/client.rb')}\" -o 'x::default' --no-fork", :cwd => chef_dir)
+ command.error!
+ end
+ end
end
diff --git a/spec/integration/client/exit_code_spec.rb b/spec/integration/client/exit_code_spec.rb
new file mode 100644
index 0000000000..30020f6a3f
--- /dev/null
+++ b/spec/integration/client/exit_code_spec.rb
@@ -0,0 +1,245 @@
+
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
+require "tiny_server"
+require "tmpdir"
+require "chef/platform"
+
+describe "chef-client" do
+
+ include IntegrationSupport
+ include Chef::Mixin::ShellOut
+
+ let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") }
+
+ # Invoke `chef-client` as `ruby PATH/TO/chef-client`. This ensures the
+ # following constraints are satisfied:
+ # * Windows: windows can only run batch scripts as bare executables. Rubygems
+ # creates batch wrappers for installed gems, but we don't have batch wrappers
+ # in the source tree.
+ # * Other `chef-client` in PATH: A common case is running the tests on a
+ # machine that has omnibus chef installed. In that case we need to ensure
+ # we're running `chef-client` from the source tree and not the external one.
+ # cf. CHEF-4914
+ let(:chef_client) { "ruby '#{chef_dir}/chef-client' --no-fork --minimal-ohai" }
+
+ let(:critical_env_vars) { %w{PATH RUBYOPT BUNDLE_GEMFILE GEM_PATH}.map { |o| "#{o}=#{ENV[o]}" } .join(" ") }
+
+ when_the_repository "does not have exit_status configured" do
+
+ def setup_client_rb
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+EOM
+ end
+
+ def setup_client_rb_with_audit_mode
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+audit_mode :audit_only
+EOM
+ end
+
+ def run_chef_client_and_expect_exit_code(exit_code)
+ shell_out!(
+ "#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'",
+ :cwd => chef_dir,
+ :returns => [exit_code])
+ end
+
+ context "has a cookbook" do
+ context "with a library" do
+ context "which cannot be loaded" do
+ before do
+ file "cookbooks/x/recipes/default.rb", ""
+ file "cookbooks/x/libraries/error.rb", "require 'does/not/exist'"
+ end
+
+ it "exits with GENERIC_FAILURE, 1" do
+ setup_client_rb
+ run_chef_client_and_expect_exit_code 1
+ end
+ end
+ end
+
+ context "with an audit recipe" do
+ context "which fails" do
+ before do
+ file "cookbooks/x/recipes/default.rb", <<-RECIPE
+control_group "control group without top level control" do
+ it "should fail" do
+ expect(2 - 2).to eq(1)
+ end
+end
+RECIPE
+ end
+
+ it "exits with GENERIC_FAILURE, 1" do
+ setup_client_rb_with_audit_mode
+ run_chef_client_and_expect_exit_code 1
+ end
+ end
+ end
+
+ context "with a recipe" do
+ context "which throws an error" do
+ before { file "cookbooks/x/recipes/default.rb", "raise 'BOOM'" }
+
+ it "exits with GENERIC_FAILURE, 1" do
+ setup_client_rb
+ run_chef_client_and_expect_exit_code 1
+ end
+ end
+
+ context "with a recipe which calls Chef::Application.fatal with a non-RFC exit code" do
+ before { file "cookbooks/x/recipes/default.rb", "Chef::Application.fatal!('BOOM', 123)" }
+
+ it "exits with the specified exit code" do
+ setup_client_rb
+ run_chef_client_and_expect_exit_code 123
+ end
+ end
+
+ context "with a recipe which calls Chef::Application.exit with a non-RFC exit code" do
+ before { file "cookbooks/x/recipes/default.rb", "Chef::Application.exit!('BOOM', 231)" }
+
+ it "exits with the specified exit code" do
+ setup_client_rb
+ run_chef_client_and_expect_exit_code 231
+ end
+ end
+ end
+
+ context "when an attempt to reboot fails (like from the reboot resource)" do
+ before do
+ file "cookbooks/x/recipes/default.rb", <<EOM
+raise Chef::Exceptions::RebootFailed.new
+EOM
+ end
+
+ it "exits with GENERIC_FAILURE, 1" do
+ setup_client_rb
+ run_chef_client_and_expect_exit_code 1
+ end
+ end
+ end
+ end
+
+ when_the_repository "does has exit_status enabled" do
+
+ def setup_client_rb
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+exit_status :enabled
+EOM
+ end
+
+ def setup_client_rb_with_audit_mode
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+exit_status :enabled
+audit_mode :audit_only
+EOM
+ end
+
+ def run_chef_client_and_expect_exit_code(exit_code)
+ shell_out!("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'",
+ :cwd => chef_dir,
+ :returns => [exit_code])
+ end
+
+ context "has a cookbook" do
+ context "with a library" do
+ context "which cannot be loaded" do
+ before do
+ file "cookbooks/x/recipes/default.rb", ""
+ file "cookbooks/x/libraries/error.rb", "require 'does/not/exist'"
+ end
+
+ it "exits with GENERIC_FAILURE, 1" do
+ setup_client_rb
+ run_chef_client_and_expect_exit_code 1
+ end
+ end
+ end
+
+ context "with an audit recipe" do
+ context "which fails" do
+ before do
+ file "cookbooks/x/recipes/default.rb", <<-RECIPE
+control_group "control group without top level control" do
+ it "should fail" do
+ expect(4 - 4).to eq(1)
+ end
+end
+RECIPE
+ end
+
+ it "exits with AUDIT_MODE_FAILURE, 42" do
+ setup_client_rb_with_audit_mode
+ run_chef_client_and_expect_exit_code 42
+ end
+ end
+ end
+
+ context "with a recipe" do
+ context "which throws an error" do
+ before { file "cookbooks/x/recipes/default.rb", "raise 'BOOM'" }
+
+ it "exits with GENERIC_FAILURE, 1" do
+ setup_client_rb
+ run_chef_client_and_expect_exit_code 1
+ end
+ end
+
+ context "with a recipe which calls Chef::Application.fatal with a non-RFC exit code" do
+ before { file "cookbooks/x/recipes/default.rb", "Chef::Application.fatal!('BOOM', 123)" }
+
+ it "exits with the GENERIC_FAILURE exit code, 1" do
+ setup_client_rb
+ run_chef_client_and_expect_exit_code 1
+ end
+ end
+
+ context "with a recipe which calls Chef::Application.exit with a non-RFC exit code" do
+ before { file "cookbooks/x/recipes/default.rb", "Chef::Application.exit!('BOOM', 231)" }
+
+ it "exits with the GENERIC_FAILURE exit code, 1" do
+ setup_client_rb
+ run_chef_client_and_expect_exit_code 1
+ end
+ end
+
+ context "when a reboot exception is raised (like from the reboot resource)" do
+ before do
+ file "cookbooks/x/recipes/default.rb", <<EOM
+raise Chef::Exceptions::Reboot.new
+EOM
+ end
+
+ it "exits with REBOOT_SCHEDULED, 35" do
+ setup_client_rb
+ run_chef_client_and_expect_exit_code 35
+ end
+ end
+
+ context "when an attempt to reboot fails (like from the reboot resource)" do
+ before do
+ file "cookbooks/x/recipes/default.rb", <<EOM
+raise Chef::Exceptions::RebootFailed.new
+EOM
+ end
+
+ it "exits with REBOOT_FAILED, 41" do
+ setup_client_rb
+ run_chef_client_and_expect_exit_code 41
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/integration/client/ipv6_spec.rb b/spec/integration/client/ipv6_spec.rb
index 8be873edf4..68c58bb8ea 100644
--- a/spec/integration/client/ipv6_spec.rb
+++ b/spec/integration/client/ipv6_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,14 +15,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'chef/mixin/shell_out'
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
describe "chef-client" do
include IntegrationSupport
include Chef::Mixin::ShellOut
- let(:chef_zero_opts) { {:host => "::1"} }
+ let(:chef_zero_opts) { { :host => "::1" } }
let(:validation_pem) do
<<-END_VALIDATION_PEM
@@ -73,10 +73,9 @@ END_CLIENT_RB
basic_config_file
end
-
let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") }
- let(:chef_client_cmd) { %Q[ruby '#{chef_dir}/chef-client' --minimal-ohai -c "#{path_to('config/client.rb')}" -lwarn] }
+ let(:chef_client_cmd) { %Q{ruby '#{chef_dir}/chef-client' --minimal-ohai -c "#{path_to('config/client.rb')}" -lwarn} }
after do
FileUtils.rm_rf(cache_path)
@@ -84,13 +83,13 @@ END_CLIENT_RB
# Some Solaris test platforms are too old for IPv6. These tests should not
# otherwise be platform dependent, so exclude solaris
- when_the_chef_server "is running on IPv6", :not_supported_on_solaris do
+ when_the_chef_server "is running on IPv6", :not_supported_on_solaris, :not_supported_on_gce do
when_the_repository "has a cookbook with a no-op recipe" do
before do
- cookbook 'noop', '1.0.0', { }, "recipes" => {"default.rb" => "#raise 'foo'"}
- file 'config/client.rb', client_rb_content
- file 'config/validator.pem', validation_pem
+ cookbook "noop", "1.0.0", {}, "recipes" => { "default.rb" => "#raise 'foo'" }
+ file "config/client.rb", client_rb_content
+ file "config/validator.pem", validation_pem
end
it "should complete with success" do
@@ -103,7 +102,7 @@ END_CLIENT_RB
when_the_repository "has a cookbook that hits server APIs" do
before do
- recipe=<<-END_RECIPE
+ recipe = <<-END_RECIPE
actual_item = data_bag_item("expect_bag", "expect_item")
if actual_item.key?("expect_key") and actual_item["expect_key"] == "expect_value"
Chef::Log.info "lookin good"
@@ -115,14 +114,14 @@ END_CLIENT_RB
END_RECIPE
- data_bag('expect_bag', { 'expect_item' => {"expect_key" => "expect_value"} })
+ data_bag("expect_bag", { "expect_item" => { "expect_key" => "expect_value" } })
- cookbook 'api-smoke-test', '1.0.0', { }, "recipes" => {"default.rb" => recipe}
+ cookbook "api-smoke-test", "1.0.0", {}, "recipes" => { "default.rb" => recipe }
end
before do
- file 'config/client.rb', client_rb_content
- file 'config/validator.pem', validation_pem
+ file "config/client.rb", client_rb_content
+ file "config/validator.pem", validation_pem
end
it "should complete with success" do
diff --git a/spec/integration/knife/chef_fs_data_store_spec.rb b/spec/integration/knife/chef_fs_data_store_spec.rb
index c1f2c7134f..02508b799d 100644
--- a/spec/integration/knife/chef_fs_data_store_spec.rb
+++ b/spec/integration/knife/chef_fs_data_store_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,36 +15,77 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/list'
-require 'chef/knife/delete'
-require 'chef/knife/show'
-require 'chef/knife/raw'
-require 'chef/knife/cookbook_upload'
+require "support/shared/integration/integration_helper"
+require "chef/knife/list"
+require "chef/knife/delete"
+require "chef/knife/show"
+require "chef/knife/raw"
+require "chef/knife/cookbook_upload"
-describe 'ChefFSDataStore tests', :workstation do
+describe "ChefFSDataStore tests", :workstation do
include IntegrationSupport
include KnifeSupport
let(:cookbook_x_100_metadata_rb) { cb_metadata("x", "1.0.0") }
let(:cookbook_z_100_metadata_rb) { cb_metadata("z", "1.0.0") }
- when_the_repository "has one of each thing" do
+ describe "with repo mode 'hosted_everything' (default)" do
before do
- file 'clients/x.json', {}
- file 'cookbooks/x/metadata.rb', cookbook_x_100_metadata_rb
- file 'data_bags/x/y.json', {}
- file 'environments/x.json', {}
- file 'nodes/x.json', {}
- file 'roles/x.json', {}
- file 'users/x.json', {}
+ Chef::Config.chef_zero.osc_compat = false
end
- context 'GET /TYPE' do
- it 'knife list -z -R returns everything' do
- knife('list -z -Rfp /').should_succeed <<EOM
+ when_the_repository "has one of each thing" do
+ before do
+ file "clients/x.json", {}
+ file "cookbook_artifacts/x-111/metadata.rb", cookbook_x_100_metadata_rb
+ file "cookbooks/x/metadata.rb", cookbook_x_100_metadata_rb
+ file "data_bags/x/y.json", {}
+ file "environments/x.json", {}
+ file "nodes/x.json", {}
+ file "roles/x.json", {}
+ # file "users/x.json", {}
+ file "containers/x.json", {}
+ file "groups/x.json", {}
+ file "containers/x.json", {}
+ file "groups/x.json", {}
+ file "policies/x-111.json", {}
+ file "policy_groups/x.json", {}
+ end
+
+ context "GET /TYPE" do
+ it "knife list -z -R returns everything" do
+ knife("list -z -Rfp /").should_succeed <<EOM
+/acls/
+/acls/clients/
+/acls/clients/x.json
+/acls/containers/
+/acls/containers/x.json
+/acls/cookbook_artifacts/
+/acls/cookbook_artifacts/x.json
+/acls/cookbooks/
+/acls/cookbooks/x.json
+/acls/data_bags/
+/acls/data_bags/x.json
+/acls/environments/
+/acls/environments/x.json
+/acls/groups/
+/acls/groups/x.json
+/acls/nodes/
+/acls/nodes/x.json
+/acls/organization.json
+/acls/policies/
+/acls/policies/x.json
+/acls/policy_groups/
+/acls/policy_groups/x.json
+/acls/roles/
+/acls/roles/x.json
/clients/
/clients/x.json
+/containers/
+/containers/x.json
+/cookbook_artifacts/
+/cookbook_artifacts/x-111/
+/cookbook_artifacts/x-111/metadata.rb
/cookbooks/
/cookbooks/x/
/cookbooks/x/metadata.rb
@@ -53,317 +94,462 @@ describe 'ChefFSDataStore tests', :workstation do
/data_bags/x/y.json
/environments/
/environments/x.json
+/groups/
+/groups/x.json
+/invitations.json
+/members.json
/nodes/
/nodes/x.json
+/org.json
+/policies/
+/policies/x-111.json
+/policy_groups/
+/policy_groups/x.json
/roles/
/roles/x.json
-/users/
-/users/x.json
EOM
+ end
end
- end
- context 'DELETE /TYPE/NAME' do
- it 'knife delete -z /clients/x.json works' do
- knife('delete -z /clients/x.json').should_succeed "Deleted /clients/x.json\n"
- knife('list -z -Rfp /clients').should_succeed ''
- end
+ context "DELETE /TYPE/NAME" do
+ it "knife delete -z /clients/x.json works" do
+ knife("delete -z /clients/x.json").should_succeed "Deleted /clients/x.json\n"
+ knife("list -z -Rfp /clients").should_succeed ""
+ end
- it 'knife delete -z -r /cookbooks/x works' do
- knife('delete -z -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
- knife('list -z -Rfp /cookbooks').should_succeed ''
- end
+ it "knife delete -z -r /cookbooks/x works" do
+ knife("delete -z -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+ knife("list -z -Rfp /cookbooks").should_succeed ""
+ end
- it 'knife delete -z -r /data_bags/x works' do
- knife('delete -z -r /data_bags/x').should_succeed "Deleted /data_bags/x\n"
- knife('list -z -Rfp /data_bags').should_succeed ''
- end
+ it "knife delete -z -r /data_bags/x works" do
+ knife("delete -z -r /data_bags/x").should_succeed "Deleted /data_bags/x\n"
+ knife("list -z -Rfp /data_bags").should_succeed ""
+ end
- it 'knife delete -z /data_bags/x/y.json works' do
- knife('delete -z /data_bags/x/y.json').should_succeed "Deleted /data_bags/x/y.json\n"
- knife('list -z -Rfp /data_bags').should_succeed "/data_bags/x/\n"
- end
+ it "knife delete -z /data_bags/x/y.json works" do
+ knife("delete -z /data_bags/x/y.json").should_succeed "Deleted /data_bags/x/y.json\n"
+ knife("list -z -Rfp /data_bags").should_succeed "/data_bags/x/\n"
+ end
- it 'knife delete -z /environments/x.json works' do
- knife('delete -z /environments/x.json').should_succeed "Deleted /environments/x.json\n"
- knife('list -z -Rfp /environments').should_succeed ''
- end
+ it "knife delete -z /environments/x.json works" do
+ knife("delete -z /environments/x.json").should_succeed "Deleted /environments/x.json\n"
+ knife("list -z -Rfp /environments").should_succeed ""
+ end
- it 'knife delete -z /nodes/x.json works' do
- knife('delete -z /nodes/x.json').should_succeed "Deleted /nodes/x.json\n"
- knife('list -z -Rfp /nodes').should_succeed ''
- end
+ it "knife delete -z /nodes/x.json works" do
+ knife("delete -z /nodes/x.json").should_succeed "Deleted /nodes/x.json\n"
+ knife("list -z -Rfp /nodes").should_succeed ""
+ end
- it 'knife delete -z /roles/x.json works' do
- knife('delete -z /roles/x.json').should_succeed "Deleted /roles/x.json\n"
- knife('list -z -Rfp /roles').should_succeed ''
- end
+ it "knife delete -z /roles/x.json works" do
+ knife("delete -z /roles/x.json").should_succeed "Deleted /roles/x.json\n"
+ knife("list -z -Rfp /roles").should_succeed ""
+ end
- it 'knife delete -z /users/x.json works' do
- knife('delete -z /users/x.json').should_succeed "Deleted /users/x.json\n"
- knife('list -z -Rfp /users').should_succeed ''
end
- end
- context 'GET /TYPE/NAME' do
- it 'knife show -z /clients/x.json works' do
- knife('show -z /clients/x.json').should_succeed( /"x"/ )
- end
+ context "GET /TYPE/NAME" do
+ it "knife show -z /clients/x.json works" do
+ knife("show -z /clients/x.json").should_succeed( /"x"/ )
+ end
- it 'knife show -z /cookbooks/x/metadata.rb works' do
- knife('show -z /cookbooks/x/metadata.rb').should_succeed "/cookbooks/x/metadata.rb:\n#{cookbook_x_100_metadata_rb}\n"
- end
+ it "knife show -z /cookbooks/x/metadata.rb works" do
+ knife("show -z /cookbooks/x/metadata.rb").should_succeed "/cookbooks/x/metadata.rb:\n#{cookbook_x_100_metadata_rb}\n"
+ end
- it 'knife show -z /data_bags/x/y.json works' do
- knife('show -z /data_bags/x/y.json').should_succeed( /"y"/ )
- end
+ it "knife show -z /data_bags/x/y.json works" do
+ knife("show -z /data_bags/x/y.json").should_succeed( /"y"/ )
+ end
- it 'knife show -z /environments/x.json works' do
- knife('show -z /environments/x.json').should_succeed( /"x"/ )
- end
+ it "knife show -z /environments/x.json works" do
+ knife("show -z /environments/x.json").should_succeed( /"x"/ )
+ end
- it 'knife show -z /nodes/x.json works' do
- knife('show -z /nodes/x.json').should_succeed( /"x"/ )
- end
+ it "knife show -z /nodes/x.json works" do
+ knife("show -z /nodes/x.json").should_succeed( /"x"/ )
+ end
- it 'knife show -z /roles/x.json works' do
- knife('show -z /roles/x.json').should_succeed( /"x"/ )
- end
+ it "knife show -z /roles/x.json works" do
+ knife("show -z /roles/x.json").should_succeed( /"x"/ )
+ end
- it 'knife show -z /users/x.json works' do
- knife('show -z /users/x.json').should_succeed( /"x"/ )
end
- end
- context 'PUT /TYPE/NAME' do
- before do
- file 'empty.json', {}
- file 'dummynode.json', { "name" => "x", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => {"foo" => "bar"}}
- file 'rolestuff.json', '{"description":"hi there","name":"x"}'
- file 'cookbooks_to_upload/x/metadata.rb', cookbook_x_100_metadata_rb
- end
+ context "PUT /TYPE/NAME" do
+ before do
+ file "empty.json", {}
+ file "dummynode.json", { "name" => "x", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => { "foo" => "bar" } }
+ file "rolestuff.json", '{"description":"hi there","name":"x"}'
+ file "cookbooks_to_upload/x/metadata.rb", cookbook_x_100_metadata_rb
+ end
- it 'knife raw -z -i empty.json -m PUT /clients/x' do
- knife("raw -z -i #{path_to('empty.json')} -m PUT /clients/x").should_succeed( /"x"/ )
- knife('list --local /clients').should_succeed "/clients/x.json\n"
- end
+ it "knife raw -z -i empty.json -m PUT /clients/x" do
+ knife("raw -z -i #{path_to('empty.json')} -m PUT /clients/x").should_succeed( /"x"/ )
+ knife("list --local /clients").should_succeed "/clients/x.json\n"
+ end
- it 'knife cookbook upload works' do
- knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} x").should_succeed :stderr => <<EOM
+ it "knife cookbook upload works" do
+ knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} x").should_succeed :stderr => <<EOM
Uploading x [1.0.0]
Uploaded 1 cookbook.
EOM
- knife('list --local -Rfp /cookbooks').should_succeed "/cookbooks/x/\n/cookbooks/x/metadata.rb\n"
- end
-
- it 'knife raw -z -i empty.json -m PUT /data/x/y' do
- knife("raw -z -i #{path_to('empty.json')} -m PUT /data/x/y").should_succeed( /"y"/ )
- knife('list --local -Rfp /data_bags').should_succeed "/data_bags/x/\n/data_bags/x/y.json\n"
- end
-
- it 'knife raw -z -i empty.json -m PUT /environments/x' do
- knife("raw -z -i #{path_to('empty.json')} -m PUT /environments/x").should_succeed( /"x"/ )
- knife('list --local /environments').should_succeed "/environments/x.json\n"
- end
-
- it 'knife raw -z -i dummynode.json -m PUT /nodes/x' do
- knife("raw -z -i #{path_to('dummynode.json')} -m PUT /nodes/x").should_succeed( /"x"/ )
- knife('list --local /nodes').should_succeed "/nodes/x.json\n"
- knife('show -z /nodes/x.json --verbose').should_succeed /"bar"/
- end
-
- it 'knife raw -z -i empty.json -m PUT /roles/x' do
- knife("raw -z -i #{path_to('empty.json')} -m PUT /roles/x").should_succeed( /"x"/ )
- knife('list --local /roles').should_succeed "/roles/x.json\n"
- end
-
- it 'knife raw -z -i empty.json -m PUT /users/x' do
- knife("raw -z -i #{path_to('empty.json')} -m PUT /users/x").should_succeed( /"x"/ )
- knife('list --local /users').should_succeed "/users/x.json\n"
- end
-
- it 'After knife raw -z -i rolestuff.json -m PUT /roles/x, the output is pretty', :skip => (RUBY_VERSION < "1.9") do
- knife("raw -z -i #{path_to('rolestuff.json')} -m PUT /roles/x").should_succeed( /"x"/ )
- expect(IO.read(path_to('roles/x.json'))).to eq <<EOM.strip
+ knife("list --local -Rfp /cookbooks").should_succeed "/cookbooks/x/\n/cookbooks/x/metadata.rb\n"
+ end
+
+ it "knife raw -z -i empty.json -m PUT /data/x/y" do
+ knife("raw -z -i #{path_to('empty.json')} -m PUT /data/x/y").should_succeed( /"y"/ )
+ knife("list --local -Rfp /data_bags").should_succeed "/data_bags/x/\n/data_bags/x/y.json\n"
+ end
+
+ it "knife raw -z -i empty.json -m PUT /environments/x" do
+ knife("raw -z -i #{path_to('empty.json')} -m PUT /environments/x").should_succeed( /"x"/ )
+ knife("list --local /environments").should_succeed "/environments/x.json\n"
+ end
+
+ it "knife raw -z -i dummynode.json -m PUT /nodes/x" do
+ knife("raw -z -i #{path_to('dummynode.json')} -m PUT /nodes/x").should_succeed( /"x"/ )
+ knife("list --local /nodes").should_succeed "/nodes/x.json\n"
+ knife("show -z /nodes/x.json --verbose").should_succeed(/"bar"/)
+ end
+
+ it "knife raw -z -i empty.json -m PUT /roles/x" do
+ knife("raw -z -i #{path_to('empty.json')} -m PUT /roles/x").should_succeed( /"x"/ )
+ knife("list --local /roles").should_succeed "/roles/x.json\n"
+ end
+
+ it "After knife raw -z -i rolestuff.json -m PUT /roles/x, the output is pretty", :skip => (RUBY_VERSION < "1.9") do
+ knife("raw -z -i #{path_to('rolestuff.json')} -m PUT /roles/x").should_succeed( /"x"/ )
+ expect(IO.read(path_to("roles/x.json"))).to eq <<EOM.strip
{
"name": "x",
"description": "hi there"
}
EOM
+ end
end
end
- end
-
- when_the_repository 'is empty' do
- context 'POST /TYPE/NAME' do
- before do
- file 'empty.json', { 'name' => 'z' }
- file 'dummynode.json', { "name" => "z", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => {"foo" => "bar"}}
- file 'empty_x.json', { 'name' => 'x' }
- file 'empty_id.json', { 'id' => 'z' }
- file 'rolestuff.json', '{"description":"hi there","name":"x"}'
- file 'cookbooks_to_upload/z/metadata.rb', cookbook_z_100_metadata_rb
- end
- it 'knife raw -z -i empty.json -m POST /clients' do
- knife("raw -z -i #{path_to('empty.json')} -m POST /clients").should_succeed( /uri/ )
- knife('list --local /clients').should_succeed "/clients/z.json\n"
- end
-
- it 'knife cookbook upload works' do
- knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} z").should_succeed :stderr => <<EOM
+ when_the_repository "is empty" do
+ context "POST /TYPE/NAME" do
+ before do
+ file "empty.json", { "name" => "z" }
+ file "dummynode.json", { "name" => "z", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => { "foo" => "bar" } }
+ file "empty_x.json", { "name" => "x" }
+ file "empty_id.json", { "id" => "z" }
+ file "rolestuff.json", '{"description":"hi there","name":"x"}'
+ file "cookbooks_to_upload/z/metadata.rb", cookbook_z_100_metadata_rb
+ end
+
+ it "knife raw -z -i empty.json -m POST /clients" do
+ knife("raw -z -i #{path_to('empty.json')} -m POST /clients").should_succeed( /uri/ )
+ knife("list --local /clients").should_succeed "/clients/z.json\n"
+ end
+
+ it "knife cookbook upload works" do
+ knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} z").should_succeed :stderr => <<EOM
Uploading z [1.0.0]
Uploaded 1 cookbook.
EOM
- knife('list --local -Rfp /cookbooks').should_succeed "/cookbooks/z/\n/cookbooks/z/metadata.rb\n"
- end
-
- it 'knife raw -z -i empty.json -m POST /data' do
- knife("raw -z -i #{path_to('empty.json')} -m POST /data").should_succeed( /uri/ )
- knife('list --local -Rfp /data_bags').should_succeed "/data_bags/z/\n"
- end
-
- it 'knife raw -z -i empty.json -m POST /data/x' do
- knife("raw -z -i #{path_to('empty_x.json')} -m POST /data").should_succeed( /uri/ )
- knife("raw -z -i #{path_to('empty_id.json')} -m POST /data/x").should_succeed( /"z"/ )
- knife('list --local -Rfp /data_bags').should_succeed "/data_bags/x/\n/data_bags/x/z.json\n"
- end
-
- it 'knife raw -z -i empty.json -m POST /environments' do
- knife("raw -z -i #{path_to('empty.json')} -m POST /environments").should_succeed( /uri/ )
- knife('list --local /environments').should_succeed "/environments/z.json\n"
- end
-
- it 'knife raw -z -i dummynode.json -m POST /nodes' do
- knife("raw -z -i #{path_to('dummynode.json')} -m POST /nodes").should_succeed( /uri/ )
- knife('list --local /nodes').should_succeed "/nodes/z.json\n"
- knife('show -z /nodes/z.json').should_succeed /"bar"/
- end
-
- it 'knife raw -z -i empty.json -m POST /roles' do
- knife("raw -z -i #{path_to('empty.json')} -m POST /roles").should_succeed( /uri/ )
- knife('list --local /roles').should_succeed "/roles/z.json\n"
- end
-
- it 'knife raw -z -i empty.json -m POST /users' do
- knife("raw -z -i #{path_to('empty.json')} -m POST /users").should_succeed( /uri/ )
- knife('list --local /users').should_succeed "/users/z.json\n"
- end
-
- it 'After knife raw -z -i rolestuff.json -m POST /roles, the output is pretty', :skip => (RUBY_VERSION < "1.9") do
- knife("raw -z -i #{path_to('rolestuff.json')} -m POST /roles").should_succeed( /uri/ )
- expect(IO.read(path_to('roles/x.json'))).to eq <<EOM.strip
+ knife("list --local -Rfp /cookbooks").should_succeed "/cookbooks/z/\n/cookbooks/z/metadata.rb\n"
+ end
+
+ it "knife raw -z -i empty.json -m POST /data" do
+ knife("raw -z -i #{path_to('empty.json')} -m POST /data").should_succeed( /uri/ )
+ knife("list --local -Rfp /data_bags").should_succeed "/data_bags/z/\n"
+ end
+
+ it "knife raw -z -i empty.json -m POST /data/x" do
+ knife("raw -z -i #{path_to('empty_x.json')} -m POST /data").should_succeed( /uri/ )
+ knife("raw -z -i #{path_to('empty_id.json')} -m POST /data/x").should_succeed( /"z"/ )
+ knife("list --local -Rfp /data_bags").should_succeed "/data_bags/x/\n/data_bags/x/z.json\n"
+ end
+
+ it "knife raw -z -i empty.json -m POST /environments" do
+ knife("raw -z -i #{path_to('empty.json')} -m POST /environments").should_succeed( /uri/ )
+ knife("list --local /environments").should_succeed "/environments/z.json\n"
+ end
+
+ it "knife raw -z -i dummynode.json -m POST /nodes" do
+ knife("raw -z -i #{path_to('dummynode.json')} -m POST /nodes").should_succeed( /uri/ )
+ knife("list --local /nodes").should_succeed "/nodes/z.json\n"
+ knife("show -z /nodes/z.json").should_succeed(/"bar"/)
+ end
+
+ it "knife raw -z -i empty.json -m POST /roles" do
+ knife("raw -z -i #{path_to('empty.json')} -m POST /roles").should_succeed( /uri/ )
+ knife("list --local /roles").should_succeed "/roles/z.json\n"
+ end
+
+ it "After knife raw -z -i rolestuff.json -m POST /roles, the output is pretty", :skip => (RUBY_VERSION < "1.9") do
+ knife("raw -z -i #{path_to('rolestuff.json')} -m POST /roles").should_succeed( /uri/ )
+ expect(IO.read(path_to("roles/x.json"))).to eq <<EOM.strip
{
"name": "x",
"description": "hi there"
}
EOM
- end
- end
-
- it 'knife list -z -R returns nothing' do
- knife('list -z -Rfp /').should_succeed <<EOM
+ end
+ end
+
+ it "knife list -z -R returns nothing" do
+ knife("list -z -Rfp /").should_succeed <<EOM
+/acls/
+/acls/clients/
+/acls/containers/
+/acls/cookbook_artifacts/
+/acls/cookbooks/
+/acls/data_bags/
+/acls/environments/
+/acls/groups/
+/acls/nodes/
+/acls/organization.json
+/acls/policies/
+/acls/policy_groups/
+/acls/roles/
/clients/
+/containers/
+/cookbook_artifacts/
/cookbooks/
/data_bags/
/environments/
+/groups/
+/invitations.json
+/members.json
/nodes/
+/org.json
+/policies/
+/policy_groups/
/roles/
-/users/
EOM
- end
-
- context 'DELETE /TYPE/NAME' do
- it 'knife delete -z /clients/x.json fails with an error' do
- knife('delete -z /clients/x.json').should_fail "ERROR: /clients/x.json: No such file or directory\n"
end
- it 'knife delete -z -r /cookbooks/x fails with an error' do
- knife('delete -z -r /cookbooks/x').should_fail "ERROR: /cookbooks/x: No such file or directory\n"
- end
+ context "DELETE /TYPE/NAME" do
+ it "knife delete -z /clients/x.json fails with an error" do
+ knife("delete -z /clients/x.json").should_fail "ERROR: /clients/x.json: No such file or directory\n"
+ end
- it 'knife delete -z -r /data_bags/x fails with an error' do
- knife('delete -z -r /data_bags/x').should_fail "ERROR: /data_bags/x: No such file or directory\n"
- end
+ it "knife delete -z -r /cookbooks/x fails with an error" do
+ knife("delete -z -r /cookbooks/x").should_fail "ERROR: /cookbooks/x: No such file or directory\n"
+ end
- it 'knife delete -z /data_bags/x/y.json fails with an error' do
- knife('delete -z /data_bags/x/y.json').should_fail "ERROR: /data_bags/x/y.json: No such file or directory\n"
- end
+ it "knife delete -z -r /data_bags/x fails with an error" do
+ knife("delete -z -r /data_bags/x").should_fail "ERROR: /data_bags/x: No such file or directory\n"
+ end
- it 'knife delete -z /environments/x.json fails with an error' do
- knife('delete -z /environments/x.json').should_fail "ERROR: /environments/x.json: No such file or directory\n"
- end
+ it "knife delete -z /data_bags/x/y.json fails with an error" do
+ knife("delete -z /data_bags/x/y.json").should_fail "ERROR: /data_bags/x/y.json: No such file or directory\n"
+ end
- it 'knife delete -z /nodes/x.json fails with an error' do
- knife('delete -z /nodes/x.json').should_fail "ERROR: /nodes/x.json: No such file or directory\n"
- end
+ it "knife delete -z /environments/x.json fails with an error" do
+ knife("delete -z /environments/x.json").should_fail "ERROR: /environments/x.json: No such file or directory\n"
+ end
- it 'knife delete -z /roles/x.json fails with an error' do
- knife('delete -z /roles/x.json').should_fail "ERROR: /roles/x.json: No such file or directory\n"
- end
+ it "knife delete -z /nodes/x.json fails with an error" do
+ knife("delete -z /nodes/x.json").should_fail "ERROR: /nodes/x.json: No such file or directory\n"
+ end
- it 'knife delete -z /users/x.json fails with an error' do
- knife('delete -z /users/x.json').should_fail "ERROR: /users/x.json: No such file or directory\n"
- end
- end
+ it "knife delete -z /roles/x.json fails with an error" do
+ knife("delete -z /roles/x.json").should_fail "ERROR: /roles/x.json: No such file or directory\n"
+ end
- context 'GET /TYPE/NAME' do
- it 'knife show -z /clients/x.json fails with an error' do
- knife('show -z /clients/x.json').should_fail "ERROR: /clients/x.json: No such file or directory\n"
end
- it 'knife show -z /cookbooks/x/metadata.rb fails with an error' do
- knife('show -z /cookbooks/x/metadata.rb').should_fail "ERROR: /cookbooks/x/metadata.rb: No such file or directory\n"
- end
+ context "GET /TYPE/NAME" do
+ it "knife show -z /clients/x.json fails with an error" do
+ knife("show -z /clients/x.json").should_fail "ERROR: /clients/x.json: No such file or directory\n"
+ end
- it 'knife show -z /data_bags/x/y.json fails with an error' do
- knife('show -z /data_bags/x/y.json').should_fail "ERROR: /data_bags/x/y.json: No such file or directory\n"
- end
+ it "knife show -z /cookbooks/x/metadata.rb fails with an error" do
+ knife("show -z /cookbooks/x/metadata.rb").should_fail "ERROR: /cookbooks/x/metadata.rb: No such file or directory\n"
+ end
- it 'knife show -z /environments/x.json fails with an error' do
- knife('show -z /environments/x.json').should_fail "ERROR: /environments/x.json: No such file or directory\n"
- end
+ it "knife show -z /data_bags/x/y.json fails with an error" do
+ knife("show -z /data_bags/x/y.json").should_fail "ERROR: /data_bags/x/y.json: No such file or directory\n"
+ end
- it 'knife show -z /nodes/x.json fails with an error' do
- knife('show -z /nodes/x.json').should_fail "ERROR: /nodes/x.json: No such file or directory\n"
- end
+ it "knife show -z /environments/x.json fails with an error" do
+ knife("show -z /environments/x.json").should_fail "ERROR: /environments/x.json: No such file or directory\n"
+ end
+
+ it "knife show -z /nodes/x.json fails with an error" do
+ knife("show -z /nodes/x.json").should_fail "ERROR: /nodes/x.json: No such file or directory\n"
+ end
+
+ it "knife show -z /roles/x.json fails with an error" do
+ knife("show -z /roles/x.json").should_fail "ERROR: /roles/x.json: No such file or directory\n"
+ end
- it 'knife show -z /roles/x.json fails with an error' do
- knife('show -z /roles/x.json').should_fail "ERROR: /roles/x.json: No such file or directory\n"
end
- it 'knife show -z /users/x.json fails with an error' do
- knife('show -z /users/x.json').should_fail "ERROR: /users/x.json: No such file or directory\n"
+ context "PUT /TYPE/NAME" do
+ before do
+ file "empty.json", {}
+ end
+
+ it "knife raw -z -i empty.json -m PUT /clients/x fails with 404" do
+ knife("raw -z -i #{path_to('empty.json')} -m PUT /clients/x").should_fail( /404/ )
+ end
+
+ it "knife raw -z -i empty.json -m PUT /data/x/y fails with 404" do
+ knife("raw -z -i #{path_to('empty.json')} -m PUT /data/x/y").should_fail( /404/ )
+ end
+
+ it "knife raw -z -i empty.json -m PUT /environments/x fails with 404" do
+ knife("raw -z -i #{path_to('empty.json')} -m PUT /environments/x").should_fail( /404/ )
+ end
+
+ it "knife raw -z -i empty.json -m PUT /nodes/x fails with 404" do
+ knife("raw -z -i #{path_to('empty.json')} -m PUT /nodes/x").should_fail( /404/ )
+ end
+
+ it "knife raw -z -i empty.json -m PUT /roles/x fails with 404" do
+ knife("raw -z -i #{path_to('empty.json')} -m PUT /roles/x").should_fail( /404/ )
+ end
+
end
end
+ end
- context 'PUT /TYPE/NAME' do
+ # We have to configure Zero for Chef 11 mode in order to test users because:
+ # 1. local mode overrides your `chef_server_url` to something like "http://localhost:PORT"
+ # 2. single org mode maps requests like "https://localhost:PORT/users" so
+ # they're functionally equivalent to "https://localhost:PORT/organizations/DEFAULT/users"
+ # 3. Users are global objects in Chef 12, and should be accessed at URLs like
+ # "https://localhost:PORT/users" (there is an org-specific users endpoint,
+ # but it's for listing users in an org, not for managing users).
+ # 4. Therefore you can't hit the _real_ users endpoint in local mode when
+ # configured for Chef Server 12 mode.
+ #
+ # Because of this, we have to configure Zero for Chef 11 OSC mode in order to
+ # test the users part of the data store with local mode.
+ describe "with repo mode 'everything'" do
+ before do
+ Chef::Config.repo_mode = "everything"
+ Chef::Config.chef_zero.osc_compat = true
+ end
+
+ when_the_repository "has one of each thing" do
before do
- file 'empty.json', {}
+ file "clients/x.json", {}
+ file "cookbooks/x/metadata.rb", cookbook_x_100_metadata_rb
+ file "data_bags/x/y.json", {}
+ file "environments/x.json", {}
+ file "nodes/x.json", {}
+ file "roles/x.json", {}
+ file "users/x.json", {}
+ end
+
+ context "GET /TYPE" do
+ it "knife list -z -R returns everything" do
+ knife("list -z -Rfp /").should_succeed <<EOM
+/clients/
+/clients/x.json
+/cookbooks/
+/cookbooks/x/
+/cookbooks/x/metadata.rb
+/data_bags/
+/data_bags/x/
+/data_bags/x/y.json
+/environments/
+/environments/x.json
+/nodes/
+/nodes/x.json
+/roles/
+/roles/x.json
+/users/
+/users/x.json
+EOM
+ end
end
- it 'knife raw -z -i empty.json -m PUT /clients/x fails with 404' do
- knife("raw -z -i #{path_to('empty.json')} -m PUT /clients/x").should_fail( /404/ )
+ context "DELETE /TYPE/NAME" do
+ it "knife delete -z /users/x.json works" do
+ knife("delete -z /users/x.json").should_succeed "Deleted /users/x.json\n"
+ knife("list -z -Rfp /users").should_succeed ""
+ end
end
- it 'knife raw -z -i empty.json -m PUT /data/x/y fails with 404' do
- knife("raw -z -i #{path_to('empty.json')} -m PUT /data/x/y").should_fail( /404/ )
+ context "GET /TYPE/NAME" do
+ it "knife show -z /users/x.json works" do
+ knife("show -z /users/x.json").should_succeed( /"x"/ )
+ end
+ end
+
+ context "PUT /TYPE/NAME" do
+ before do
+ file "empty.json", {}
+ file "dummynode.json", { "name" => "x", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => { "foo" => "bar" } }
+ file "rolestuff.json", '{"description":"hi there","name":"x"}'
+ file "cookbooks_to_upload/x/metadata.rb", cookbook_x_100_metadata_rb
+ end
+
+ it "knife raw -z -i empty.json -m PUT /users/x" do
+ knife("raw -z -i #{path_to('empty.json')} -m PUT /users/x").should_succeed( /"x"/ )
+ knife("list --local /users").should_succeed "/users/x.json\n"
+ end
+
+ it "After knife raw -z -i rolestuff.json -m PUT /roles/x, the output is pretty", :skip => (RUBY_VERSION < "1.9") do
+ knife("raw -z -i #{path_to('rolestuff.json')} -m PUT /roles/x").should_succeed( /"x"/ )
+ expect(IO.read(path_to("roles/x.json"))).to eq <<EOM.strip
+{
+ "name": "x",
+ "description": "hi there"
+}
+EOM
+ end
end
+ end
- it 'knife raw -z -i empty.json -m PUT /environments/x fails with 404' do
- knife("raw -z -i #{path_to('empty.json')} -m PUT /environments/x").should_fail( /404/ )
+ when_the_repository "is empty" do
+ context "POST /TYPE/NAME" do
+ before do
+ file "empty.json", { "name" => "z" }
+ file "dummynode.json", { "name" => "z", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => { "foo" => "bar" } }
+ file "empty_x.json", { "name" => "x" }
+ file "empty_id.json", { "id" => "z" }
+ file "rolestuff.json", '{"description":"hi there","name":"x"}'
+ file "cookbooks_to_upload/z/metadata.rb", cookbook_z_100_metadata_rb
+ end
+
+ it "knife raw -z -i empty.json -m POST /users" do
+ knife("raw -z -i #{path_to('empty.json')} -m POST /users").should_succeed( /uri/ )
+ knife("list --local /users").should_succeed "/users/z.json\n"
+ end
+ end
+
+ it "knife list -z -R returns nothing" do
+ knife("list -z -Rfp /").should_succeed <<EOM
+/clients/
+/cookbooks/
+/data_bags/
+/environments/
+/nodes/
+/roles/
+/users/
+EOM
end
- it 'knife raw -z -i empty.json -m PUT /nodes/x fails with 404' do
- knife("raw -z -i #{path_to('empty.json')} -m PUT /nodes/x").should_fail( /404/ )
+ context "DELETE /TYPE/NAME" do
+ it "knife delete -z /users/x.json fails with an error" do
+ knife("delete -z /users/x.json").should_fail "ERROR: /users/x.json: No such file or directory\n"
+ end
end
- it 'knife raw -z -i empty.json -m PUT /roles/x fails with 404' do
- knife("raw -z -i #{path_to('empty.json')} -m PUT /roles/x").should_fail( /404/ )
+ context "GET /TYPE/NAME" do
+ it "knife show -z /users/x.json fails with an error" do
+ knife("show -z /users/x.json").should_fail "ERROR: /users/x.json: No such file or directory\n"
+ end
end
- it 'knife raw -z -i empty.json -m PUT /users/x fails with 404' do
- knife("raw -z -i #{path_to('empty.json')} -m PUT /users/x").should_fail( /404/ )
+ context "PUT /TYPE/NAME" do
+ before do
+ file "empty.json", {}
+ end
+
+ it "knife raw -z -i empty.json -m PUT /users/x fails with 404" do
+ knife("raw -z -i #{path_to('empty.json')} -m PUT /users/x").should_fail( /404/ )
+ end
end
end
end
diff --git a/spec/integration/knife/chef_repo_path_spec.rb b/spec/integration/knife/chef_repo_path_spec.rb
index 908657e5f7..e609fa60b3 100644
--- a/spec/integration/knife/chef_repo_path_spec.rb
+++ b/spec/integration/knife/chef_repo_path_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,49 +15,49 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'support/shared/context/config'
-require 'chef/knife/list'
-require 'chef/knife/show'
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/list"
+require "chef/knife/show"
-describe 'chef_repo_path tests', :workstation do
+describe "chef_repo_path tests", :workstation do
include IntegrationSupport
include KnifeSupport
let(:error_rel_path_outside_repo) { /^ERROR: Attempt to use relative path '' when current directory is outside the repository path/ }
# TODO alternate repo_path / *_path
- context 'alternate *_path' do
- when_the_repository 'has clients and clients2, cookbooks and cookbooks2, etc.' do
+ context "alternate *_path" do
+ when_the_repository "has clients and clients2, cookbooks and cookbooks2, etc." do
before do
- file 'clients/client1.json', {}
- file 'cookbooks/cookbook1/metadata.rb', ''
- file 'data_bags/bag/item.json', {}
- file 'environments/env1.json', {}
- file 'nodes/node1.json', {}
- file 'roles/role1.json', {}
- file 'users/user1.json', {}
-
- file 'clients2/client2.json', {}
- file 'cookbooks2/cookbook2/metadata.rb', ''
- file 'data_bags2/bag2/item2.json', {}
- file 'environments2/env2.json', {}
- file 'nodes2/node2.json', {}
- file 'roles2/role2.json', {}
- file 'users2/user2.json', {}
-
- directory 'chef_repo2' do
- file 'clients/client3.json', {}
- file 'cookbooks/cookbook3/metadata.rb', ''
- file 'data_bags/bag3/item3.json', {}
- file 'environments/env3.json', {}
- file 'nodes/node3.json', {}
- file 'roles/role3.json', {}
- file 'users/user3.json', {}
+ file "clients/client1.json", {}
+ file "cookbooks/cookbook1/metadata.rb", ""
+ file "data_bags/bag/item.json", {}
+ file "environments/env1.json", {}
+ file "nodes/node1.json", {}
+ file "roles/role1.json", {}
+ file "users/user1.json", {}
+
+ file "clients2/client2.json", {}
+ file "cookbooks2/cookbook2/metadata.rb", ""
+ file "data_bags2/bag2/item2.json", {}
+ file "environments2/env2.json", {}
+ file "nodes2/node2.json", {}
+ file "roles2/role2.json", {}
+ file "users2/user2.json", {}
+
+ directory "chef_repo2" do
+ file "clients/client3.json", {}
+ file "cookbooks/cookbook3/metadata.rb", "name 'cookbook3'"
+ file "data_bags/bag3/item3.json", {}
+ file "environments/env3.json", {}
+ file "nodes/node3.json", {}
+ file "roles/role3.json", {}
+ file "users/user3.json", {}
end
end
- it 'knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff' do
+ it "knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff" do
Chef::Config.delete(:chef_repo_path)
knife("list --local -Rfp --chef-repo-path #{path_to('chef_repo2')} /").should_succeed <<EOM
/clients/
@@ -79,15 +79,84 @@ describe 'chef_repo_path tests', :workstation do
EOM
end
- context 'when all _paths are set to alternates' do
+ it "knife list --local -Rfp --chef-repo-path chef_r~1 / grabs chef_repo2 stuff", :windows_only do
+ Chef::Config.delete(:chef_repo_path)
+ knife("list --local -Rfp --chef-repo-path #{path_to('chef_r~1')} /").should_succeed <<EOM
+/clients/
+/clients/client3.json
+/cookbooks/
+/cookbooks/cookbook3/
+/cookbooks/cookbook3/metadata.rb
+/data_bags/
+/data_bags/bag3/
+/data_bags/bag3/item3.json
+/environments/
+/environments/env3.json
+/nodes/
+/nodes/node3.json
+/roles/
+/roles/role3.json
+/users/
+/users/user3.json
+EOM
+ end
+
+ it "knife list --local -Rfp --chef-repo-path chef_r~1 / grabs chef_repo2 stuff", :windows_only do
+ Chef::Config.delete(:chef_repo_path)
+ knife("list -z -Rfp --chef-repo-path #{path_to('chef_r~1')} /").should_succeed <<EOM
+/acls/
+/acls/clients/
+/acls/clients/client3.json
+/acls/containers/
+/acls/cookbook_artifacts/
+/acls/cookbooks/
+/acls/cookbooks/cookbook3.json
+/acls/data_bags/
+/acls/data_bags/bag3.json
+/acls/environments/
+/acls/environments/env3.json
+/acls/groups/
+/acls/nodes/
+/acls/nodes/node3.json
+/acls/organization.json
+/acls/policies/
+/acls/policy_groups/
+/acls/roles/
+/acls/roles/role3.json
+/clients/
+/clients/client3.json
+/containers/
+/cookbook_artifacts/
+/cookbooks/
+/cookbooks/cookbook3/
+/cookbooks/cookbook3/metadata.rb
+/data_bags/
+/data_bags/bag3/
+/data_bags/bag3/item3.json
+/environments/
+/environments/env3.json
+/groups/
+/invitations.json
+/members.json
+/nodes/
+/nodes/node3.json
+/org.json
+/policies/
+/policy_groups/
+/roles/
+/roles/role3.json
+EOM
+ end
+
+ context "when all _paths are set to alternates" do
before :each do
- %w(client cookbook data_bag environment node role user).each do |object_name|
+ %w{client cookbook data_bag environment node role user}.each do |object_name|
Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, "#{object_name}s2")
end
- Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, 'chef_repo2')
+ Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2")
end
- it 'knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff' do
+ it "knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff" do
knife("list --local -Rfp --chef-repo-path #{path_to('chef_repo2')} /").should_succeed <<EOM
/clients/
/clients/client3.json
@@ -108,24 +177,24 @@ EOM
EOM
end
- context 'when cwd is at the top level' do
- before { cwd '.' }
- it 'knife list --local -Rfp fails' do
- knife('list --local -Rfp').should_fail(error_rel_path_outside_repo)
+ context "when cwd is at the top level" do
+ before { cwd "." }
+ it "knife list --local -Rfp fails" do
+ knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
end
end
- context 'when cwd is inside the data_bags directory' do
- before { cwd 'data_bags' }
- it 'knife list --local -Rfp fails' do
- knife('list --local -Rfp').should_fail(error_rel_path_outside_repo)
+ context "when cwd is inside the data_bags directory" do
+ before { cwd "data_bags" }
+ it "knife list --local -Rfp fails" do
+ knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
end
end
- context 'when cwd is inside chef_repo2' do
- before { cwd 'chef_repo2' }
- it 'knife list --local -Rfp lists everything' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside chef_repo2" do
+ before { cwd "chef_repo2" }
+ it "knife list --local -Rfp lists everything" do
+ knife("list --local -Rfp").should_succeed <<EOM
clients/
clients/client2.json
cookbooks/
@@ -146,31 +215,31 @@ EOM
end
end
- context 'when cwd is inside data_bags2' do
- before { cwd 'data_bags2' }
- it 'knife list --local -Rfp lists data bags' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside data_bags2" do
+ before { cwd "data_bags2" }
+ it "knife list --local -Rfp lists data bags" do
+ knife("list --local -Rfp").should_succeed <<EOM
bag2/
bag2/item2.json
EOM
end
- it 'knife list --local -Rfp ../roles lists roles' do
- knife('list --local -Rfp ../roles').should_succeed "/roles/role2.json\n"
+ it "knife list --local -Rfp ../roles lists roles" do
+ knife("list --local -Rfp ../roles").should_succeed "/roles/role2.json\n"
end
end
end
- context 'when all _paths except chef_repo_path are set to alternates' do
+ context "when all _paths except chef_repo_path are set to alternates" do
before :each do
- %w(client cookbook data_bag environment node role user).each do |object_name|
+ %w{client cookbook data_bag environment node role user}.each do |object_name|
Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, "#{object_name}s2")
end
end
- context 'when cwd is at the top level' do
- before { cwd '.' }
- it 'knife list --local -Rfp lists everything' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is at the top level" do
+ before { cwd "." }
+ it "knife list --local -Rfp lists everything" do
+ knife("list --local -Rfp").should_succeed <<EOM
clients/
clients/client2.json
cookbooks/
@@ -191,24 +260,24 @@ EOM
end
end
- context 'when cwd is inside the data_bags directory' do
- before { cwd 'data_bags' }
- it 'knife list --local -Rfp fails' do
- knife('list --local -Rfp').should_fail(error_rel_path_outside_repo)
+ context "when cwd is inside the data_bags directory" do
+ before { cwd "data_bags" }
+ it "knife list --local -Rfp fails" do
+ knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
end
end
- context 'when cwd is inside chef_repo2' do
- before { cwd 'chef_repo2' }
- it 'knife list -Rfp fails' do
- knife('list --local -Rfp').should_fail(error_rel_path_outside_repo)
+ context "when cwd is inside chef_repo2" do
+ before { cwd "chef_repo2" }
+ it "knife list -Rfp fails" do
+ knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
end
end
- context 'when cwd is inside data_bags2' do
- before { cwd 'data_bags2' }
- it 'knife list --local -Rfp lists data bags' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside data_bags2" do
+ before { cwd "data_bags2" }
+ it "knife list --local -Rfp lists data bags" do
+ knife("list --local -Rfp").should_succeed <<EOM
bag2/
bag2/item2.json
EOM
@@ -216,32 +285,32 @@ EOM
end
end
- context 'when only chef_repo_path is set to its alternate' do
+ context "when only chef_repo_path is set to its alternate" do
before :each do
- %w(client cookbook data_bag environment node role user).each do |object_name|
+ %w{client cookbook data_bag environment node role user}.each do |object_name|
Chef::Config.delete("#{object_name}_path".to_sym)
end
- Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, 'chef_repo2')
+ Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2")
end
- context 'when cwd is at the top level' do
- before { cwd '.' }
- it 'knife list --local -Rfp fails' do
- knife('list --local -Rfp').should_fail(error_rel_path_outside_repo)
+ context "when cwd is at the top level" do
+ before { cwd "." }
+ it "knife list --local -Rfp fails" do
+ knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
end
end
- context 'when cwd is inside the data_bags directory' do
- before { cwd 'data_bags' }
- it 'knife list --local -Rfp fails' do
- knife('list --local -Rfp').should_fail(error_rel_path_outside_repo)
+ context "when cwd is inside the data_bags directory" do
+ before { cwd "data_bags" }
+ it "knife list --local -Rfp fails" do
+ knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
end
end
- context 'when cwd is inside chef_repo2' do
- before { cwd 'chef_repo2' }
- it 'knife list --local -Rfp lists everything' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside chef_repo2" do
+ before { cwd "chef_repo2" }
+ it "knife list --local -Rfp lists everything" do
+ knife("list --local -Rfp").should_succeed <<EOM
clients/
clients/client3.json
cookbooks/
@@ -262,10 +331,10 @@ EOM
end
end
- context 'when cwd is inside chef_repo2/data_bags' do
- before { cwd 'chef_repo2/data_bags' }
- it 'knife list --local -Rfp lists data bags' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside chef_repo2/data_bags" do
+ before { cwd "chef_repo2/data_bags" }
+ it "knife list --local -Rfp lists data bags" do
+ knife("list --local -Rfp").should_succeed <<EOM
bag3/
bag3/item3.json
EOM
@@ -273,24 +342,24 @@ EOM
end
end
- context 'when paths are set to point to both versions of each' do
+ context "when paths are set to point to both versions of each" do
before :each do
- %w(client cookbook data_bag environment node role user).each do |object_name|
+ %w{client cookbook data_bag environment node role user}.each do |object_name|
Chef::Config["#{object_name}_path".to_sym] = [
File.join(Chef::Config.chef_repo_path, "#{object_name}s"),
- File.join(Chef::Config.chef_repo_path, "#{object_name}s2")
+ File.join(Chef::Config.chef_repo_path, "#{object_name}s2"),
]
end
- Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, 'chef_repo2')
+ Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2")
end
- context 'when there is a directory in clients1 and file in clients2 with the same name' do
+ context "when there is a directory in clients1 and file in clients2 with the same name" do
before do
- directory 'clients/blah.json'
- file 'clients2/blah.json', {}
+ directory "clients/blah.json"
+ file "clients2/blah.json", {}
end
- it 'knife show /clients/blah.json succeeds' do
- knife('show --local /clients/blah.json').should_succeed <<EOM
+ it "knife show /clients/blah.json succeeds" do
+ knife("show --local /clients/blah.json").should_succeed <<EOM
/clients/blah.json:
{
@@ -299,13 +368,13 @@ EOM
end
end
- context 'when there is a file in cookbooks1 and directory in cookbooks2 with the same name' do
+ context "when there is a file in cookbooks1 and directory in cookbooks2 with the same name" do
before do
- file 'cookbooks/blah', ''
- file 'cookbooks2/blah/metadata.rb', ''
+ file "cookbooks/blah", ""
+ file "cookbooks2/blah/metadata.rb", ""
end
- it 'knife list -Rfp cookbooks shows files in blah' do
- knife('list --local -Rfp /cookbooks').should_succeed <<EOM
+ it "knife list -Rfp cookbooks shows files in blah" do
+ knife("list --local -Rfp /cookbooks").should_succeed <<EOM
/cookbooks/blah/
/cookbooks/blah/metadata.rb
/cookbooks/cookbook1/
@@ -316,13 +385,13 @@ EOM
end
end
- context 'when there is an empty directory in cookbooks1 and a real cookbook in cookbooks2 with the same name' do
+ context "when there is an empty directory in cookbooks1 and a real cookbook in cookbooks2 with the same name" do
before do
- directory 'cookbooks/blah'
- file 'cookbooks2/blah/metadata.rb', ''
+ directory "cookbooks/blah"
+ file "cookbooks2/blah/metadata.rb", ""
end
- it 'knife list -Rfp cookbooks shows files in blah' do
- knife('list --local -Rfp /cookbooks').should_succeed(<<EOM, :stderr => "WARN: Cookbook 'blah' is empty or entirely chefignored at #{Chef::Config.cookbook_path[0]}/blah\n")
+ it "knife list -Rfp cookbooks shows files in blah" do
+ knife("list --local -Rfp /cookbooks").should_succeed(<<EOM, :stderr => "WARN: Cookbook 'blah' is empty or entirely chefignored at #{Chef::Config.cookbook_path[0]}/blah\n")
/cookbooks/blah/
/cookbooks/blah/metadata.rb
/cookbooks/cookbook1/
@@ -333,13 +402,13 @@ EOM
end
end
- context 'when there is a cookbook in cookbooks1 and a cookbook in cookbooks2 with the same name' do
+ context "when there is a cookbook in cookbooks1 and a cookbook in cookbooks2 with the same name" do
before do
- file 'cookbooks/blah/metadata.json', {}
- file 'cookbooks2/blah/metadata.rb', ''
+ file "cookbooks/blah/metadata.json", {}
+ file "cookbooks2/blah/metadata.rb", ""
end
- it 'knife list -Rfp cookbooks shows files in the first cookbook and not the second' do
- knife('list --local -Rfp /cookbooks').should_succeed(<<EOM, :stderr => "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.cookbook_path[0]}/blah and #{Chef::Config.cookbook_path[1]}/blah\n")
+ it "knife list -Rfp cookbooks shows files in the first cookbook and not the second" do
+ knife("list --local -Rfp /cookbooks").should_succeed(<<EOM, :stderr => "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.cookbook_path[0]}/blah and #{Chef::Config.cookbook_path[1]}/blah\n")
/cookbooks/blah/
/cookbooks/blah/metadata.json
/cookbooks/cookbook1/
@@ -350,13 +419,13 @@ EOM
end
end
- context 'when there is a file in data_bags1 and a directory in data_bags2 with the same name' do
+ context "when there is a file in data_bags1 and a directory in data_bags2 with the same name" do
before do
- file 'data_bags/blah', ''
- file 'data_bags2/blah/item.json', ''
+ file "data_bags/blah", ""
+ file "data_bags2/blah/item.json", ""
end
- it 'knife list -Rfp data_bags shows files in blah' do
- knife('list --local -Rfp /data_bags').should_succeed <<EOM
+ it "knife list -Rfp data_bags shows files in blah" do
+ knife("list --local -Rfp /data_bags").should_succeed <<EOM
/data_bags/bag/
/data_bags/bag/item.json
/data_bags/bag2/
@@ -367,13 +436,13 @@ EOM
end
end
- context 'when there is a data bag in data_bags1 and a data bag in data_bags2 with the same name' do
+ context "when there is a data bag in data_bags1 and a data bag in data_bags2 with the same name" do
before do
- file 'data_bags/blah/item1.json', ''
- file 'data_bags2/blah/item2.json', ''
+ file "data_bags/blah/item1.json", ""
+ file "data_bags2/blah/item2.json", ""
end
- it 'knife list -Rfp data_bags shows only items in data_bags1' do
- knife('list --local -Rfp /data_bags').should_succeed(<<EOM, :stderr => "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.data_bag_path[0]}/blah and #{Chef::Config.data_bag_path[1]}/blah\n")
+ it "knife list -Rfp data_bags shows only items in data_bags1" do
+ knife("list --local -Rfp /data_bags").should_succeed(<<EOM, :stderr => "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.data_bag_path[0]}/blah and #{Chef::Config.data_bag_path[1]}/blah\n")
/data_bags/bag/
/data_bags/bag/item.json
/data_bags/bag2/
@@ -384,13 +453,13 @@ EOM
end
end
- context 'when there is a directory in environments1 and file in environments2 with the same name' do
+ context "when there is a directory in environments1 and file in environments2 with the same name" do
before do
- directory 'environments/blah.json'
- file 'environments2/blah.json', {}
+ directory "environments/blah.json"
+ file "environments2/blah.json", {}
end
- it 'knife show /environments/blah.json succeeds' do
- knife('show --local /environments/blah.json').should_succeed <<EOM
+ it "knife show /environments/blah.json succeeds" do
+ knife("show --local /environments/blah.json").should_succeed <<EOM
/environments/blah.json:
{
@@ -399,13 +468,13 @@ EOM
end
end
- context 'when there is a directory in nodes1 and file in nodes2 with the same name' do
+ context "when there is a directory in nodes1 and file in nodes2 with the same name" do
before do
- directory 'nodes/blah.json'
- file 'nodes2/blah.json', {}
+ directory "nodes/blah.json"
+ file "nodes2/blah.json", {}
end
- it 'knife show /nodes/blah.json succeeds' do
- knife('show --local /nodes/blah.json').should_succeed <<EOM
+ it "knife show /nodes/blah.json succeeds" do
+ knife("show --local /nodes/blah.json").should_succeed <<EOM
/nodes/blah.json:
{
@@ -414,13 +483,13 @@ EOM
end
end
- context 'when there is a directory in roles1 and file in roles2 with the same name' do
+ context "when there is a directory in roles1 and file in roles2 with the same name" do
before do
- directory 'roles/blah.json'
- file 'roles2/blah.json', {}
+ directory "roles/blah.json"
+ file "roles2/blah.json", {}
end
- it 'knife show /roles/blah.json succeeds' do
- knife('show --local /roles/blah.json').should_succeed <<EOM
+ it "knife show /roles/blah.json succeeds" do
+ knife("show --local /roles/blah.json").should_succeed <<EOM
/roles/blah.json:
{
@@ -429,13 +498,13 @@ EOM
end
end
- context 'when there is a directory in users1 and file in users2 with the same name' do
+ context "when there is a directory in users1 and file in users2 with the same name" do
before do
- directory 'users/blah.json'
- file 'users2/blah.json', {}
+ directory "users/blah.json"
+ file "users2/blah.json", {}
end
- it 'knife show /users/blah.json succeeds' do
- knife('show --local /users/blah.json').should_succeed <<EOM
+ it "knife show /users/blah.json succeeds" do
+ knife("show --local /users/blah.json").should_succeed <<EOM
/users/blah.json:
{
@@ -444,17 +513,17 @@ EOM
end
end
- context 'when cwd is at the top level' do
- before { cwd '.' }
- it 'knife list --local -Rfp fails' do
- knife('list --local -Rfp').should_fail(error_rel_path_outside_repo)
+ context "when cwd is at the top level" do
+ before { cwd "." }
+ it "knife list --local -Rfp fails" do
+ knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
end
end
- context 'when cwd is inside the data_bags directory' do
- before { cwd 'data_bags' }
- it 'knife list --local -Rfp lists data bags' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside the data_bags directory" do
+ before { cwd "data_bags" }
+ it "knife list --local -Rfp lists data bags" do
+ knife("list --local -Rfp").should_succeed <<EOM
bag/
bag/item.json
bag2/
@@ -463,10 +532,10 @@ EOM
end
end
- context 'when cwd is inside chef_repo2' do
- before { cwd 'chef_repo2' }
- it 'knife list --local -Rfp lists everything' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside chef_repo2" do
+ before { cwd "chef_repo2" }
+ it "knife list --local -Rfp lists everything" do
+ knife("list --local -Rfp").should_succeed <<EOM
clients/
clients/client1.json
clients/client2.json
@@ -496,10 +565,10 @@ EOM
end
end
- context 'when cwd is inside data_bags2' do
- before { cwd 'data_bags2' }
- it 'knife list --local -Rfp lists data bags' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside data_bags2" do
+ before { cwd "data_bags2" }
+ it "knife list --local -Rfp lists data bags" do
+ knife("list --local -Rfp").should_succeed <<EOM
bag/
bag/item.json
bag2/
@@ -509,21 +578,21 @@ EOM
end
end
- context 'when when chef_repo_path is set to both places and no other _path is set' do
+ context "when when chef_repo_path is set to both places and no other _path is set" do
before :each do
- %w(client cookbook data_bag environment node role user).each do |object_name|
+ %w{client cookbook data_bag environment node role user}.each do |object_name|
Chef::Config.delete("#{object_name}_path".to_sym)
end
Chef::Config.chef_repo_path = [
Chef::Config.chef_repo_path,
- File.join(Chef::Config.chef_repo_path, 'chef_repo2')
+ File.join(Chef::Config.chef_repo_path, "chef_repo2"),
]
end
- context 'when cwd is at the top level' do
- before { cwd '.' }
- it 'knife list --local -Rfp lists everything' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is at the top level" do
+ before { cwd "." }
+ it "knife list --local -Rfp lists everything" do
+ knife("list --local -Rfp").should_succeed <<EOM
clients/
clients/client1.json
clients/client3.json
@@ -553,10 +622,10 @@ EOM
end
end
- context 'when cwd is inside the data_bags directory' do
- before { cwd 'data_bags' }
- it 'knife list --local -Rfp lists data bags' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside the data_bags directory" do
+ before { cwd "data_bags" }
+ it "knife list --local -Rfp lists data bags" do
+ knife("list --local -Rfp").should_succeed <<EOM
bag/
bag/item.json
bag3/
@@ -565,10 +634,10 @@ EOM
end
end
- context 'when cwd is inside chef_repo2' do
- before { cwd 'chef_repo2' }
- it 'knife list --local -Rfp lists everything' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside chef_repo2" do
+ before { cwd "chef_repo2" }
+ it "knife list --local -Rfp lists everything" do
+ knife("list --local -Rfp").should_succeed <<EOM
clients/
clients/client1.json
clients/client3.json
@@ -598,10 +667,10 @@ EOM
end
end
- context 'when cwd is inside chef_repo2/data_bags' do
- before { cwd 'chef_repo2/data_bags' }
- it 'knife list --local -Rfp lists data bags' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside chef_repo2/data_bags" do
+ before { cwd "chef_repo2/data_bags" }
+ it "knife list --local -Rfp lists data bags" do
+ knife("list --local -Rfp").should_succeed <<EOM
bag/
bag/item.json
bag3/
@@ -611,33 +680,33 @@ EOM
end
end
- context 'when cookbook_path is set and nothing else' do
+ context "when cookbook_path is set and nothing else" do
before :each do
- %w(client data_bag environment node role user).each do |object_name|
+ %w{client data_bag environment node role user}.each do |object_name|
Chef::Config.delete("#{object_name}_path".to_sym)
end
Chef::Config.delete(:chef_repo_path)
- Chef::Config.cookbook_path = File.join(@repository_dir, 'chef_repo2', 'cookbooks')
+ Chef::Config.cookbook_path = File.join(@repository_dir, "chef_repo2", "cookbooks")
end
- context 'when cwd is at the top level' do
- before { cwd '.' }
- it 'knife list --local -Rfp fails' do
- knife('list --local -Rfp').should_fail(error_rel_path_outside_repo)
+ context "when cwd is at the top level" do
+ before { cwd "." }
+ it "knife list --local -Rfp fails" do
+ knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
end
end
- context 'when cwd is inside the data_bags directory' do
- before { cwd 'data_bags' }
- it 'knife list --local -Rfp fails' do
- knife('list --local -Rfp').should_fail(error_rel_path_outside_repo)
+ context "when cwd is inside the data_bags directory" do
+ before { cwd "data_bags" }
+ it "knife list --local -Rfp fails" do
+ knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
end
end
- context 'when cwd is inside chef_repo2' do
- before { cwd 'chef_repo2' }
- it 'knife list --local -Rfp lists everything' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside chef_repo2" do
+ before { cwd "chef_repo2" }
+ it "knife list --local -Rfp lists everything" do
+ knife("list --local -Rfp").should_succeed <<EOM
clients/
clients/client3.json
cookbooks/
@@ -658,10 +727,10 @@ EOM
end
end
- context 'when cwd is inside chef_repo2/data_bags' do
- before { cwd 'chef_repo2/data_bags' }
- it 'knife list --local -Rfp lists data bags' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside chef_repo2/data_bags" do
+ before { cwd "chef_repo2/data_bags" }
+ it "knife list --local -Rfp lists data bags" do
+ knife("list --local -Rfp").should_succeed <<EOM
bag3/
bag3/item3.json
EOM
@@ -669,22 +738,22 @@ EOM
end
end
- context 'when cookbook_path is set to multiple places and nothing else is set' do
+ context "when cookbook_path is set to multiple places and nothing else is set" do
before :each do
- %w(client data_bag environment node role user).each do |object_name|
+ %w{client data_bag environment node role user}.each do |object_name|
Chef::Config.delete("#{object_name}_path".to_sym)
end
Chef::Config.delete(:chef_repo_path)
Chef::Config.cookbook_path = [
- File.join(@repository_dir, 'cookbooks'),
- File.join(@repository_dir, 'chef_repo2', 'cookbooks')
+ File.join(@repository_dir, "cookbooks"),
+ File.join(@repository_dir, "chef_repo2", "cookbooks"),
]
end
- context 'when cwd is at the top level' do
- before { cwd '.' }
- it 'knife list --local -Rfp lists everything' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is at the top level" do
+ before { cwd "." }
+ it "knife list --local -Rfp lists everything" do
+ knife("list --local -Rfp").should_succeed <<EOM
clients/
clients/client1.json
clients/client3.json
@@ -714,10 +783,10 @@ EOM
end
end
- context 'when cwd is inside the data_bags directory' do
- before { cwd 'data_bags' }
- it 'knife list --local -Rfp lists data bags' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside the data_bags directory" do
+ before { cwd "data_bags" }
+ it "knife list --local -Rfp lists data bags" do
+ knife("list --local -Rfp").should_succeed <<EOM
bag/
bag/item.json
bag3/
@@ -726,10 +795,10 @@ EOM
end
end
- context 'when cwd is inside chef_repo2' do
- before { cwd 'chef_repo2' }
- it 'knife list --local -Rfp lists everything' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside chef_repo2" do
+ before { cwd "chef_repo2" }
+ it "knife list --local -Rfp lists everything" do
+ knife("list --local -Rfp").should_succeed <<EOM
clients/
clients/client1.json
clients/client3.json
@@ -759,10 +828,10 @@ EOM
end
end
- context 'when cwd is inside chef_repo2/data_bags' do
- before { cwd 'chef_repo2/data_bags' }
- it 'knife list --local -Rfp lists data bags' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside chef_repo2/data_bags" do
+ before { cwd "chef_repo2/data_bags" }
+ it "knife list --local -Rfp lists data bags" do
+ knife("list --local -Rfp").should_succeed <<EOM
bag/
bag/item.json
bag3/
@@ -772,36 +841,36 @@ EOM
end
end
- context 'when data_bag_path and chef_repo_path are set, and nothing else' do
+ context "when data_bag_path and chef_repo_path are set, and nothing else" do
before :each do
- %w(client cookbook environment node role user).each do |object_name|
+ %w{client cookbook environment node role user}.each do |object_name|
Chef::Config.delete("#{object_name}_path".to_sym)
end
- Chef::Config.data_bag_path = File.join(Chef::Config.chef_repo_path, 'data_bags')
- Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, 'chef_repo2')
+ Chef::Config.data_bag_path = File.join(Chef::Config.chef_repo_path, "data_bags")
+ Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2")
end
- context 'when cwd is at the top level' do
- before { cwd '.' }
- it 'knife list --local -Rfp fails' do
- knife('list --local -Rfp').should_fail(error_rel_path_outside_repo)
+ context "when cwd is at the top level" do
+ before { cwd "." }
+ it "knife list --local -Rfp fails" do
+ knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
end
end
- context 'when cwd is inside the data_bags directory' do
- before { cwd 'data_bags' }
- it 'knife list --local -Rfp lists data bags' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside the data_bags directory" do
+ before { cwd "data_bags" }
+ it "knife list --local -Rfp lists data bags" do
+ knife("list --local -Rfp").should_succeed <<EOM
bag/
bag/item.json
EOM
end
end
- context 'when cwd is inside chef_repo2' do
- before { cwd 'chef_repo2' }
- it 'knife list --local -Rfp lists everything' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside chef_repo2" do
+ before { cwd "chef_repo2" }
+ it "knife list --local -Rfp lists everything" do
+ knife("list --local -Rfp").should_succeed <<EOM
clients/
clients/client3.json
cookbooks/
@@ -822,44 +891,44 @@ EOM
end
end
- context 'when cwd is inside chef_repo2/data_bags' do
- before { cwd 'chef_repo2/data_bags' }
- it 'knife list --local -Rfp fails' do
- knife('list --local -Rfp').should_fail(error_rel_path_outside_repo)
+ context "when cwd is inside chef_repo2/data_bags" do
+ before { cwd "chef_repo2/data_bags" }
+ it "knife list --local -Rfp fails" do
+ knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
end
end
end
- context 'when data_bag_path is set and nothing else' do
+ context "when data_bag_path is set and nothing else" do
include_context "default config options"
before :each do
- %w(client cookbook environment node role user).each do |object_name|
+ %w{client cookbook environment node role user}.each do |object_name|
Chef::Config.delete("#{object_name}_path".to_sym)
end
Chef::Config.delete(:chef_repo_path)
- Chef::Config.data_bag_path = File.join(@repository_dir, 'data_bags')
+ Chef::Config.data_bag_path = File.join(@repository_dir, "data_bags")
end
- it 'knife list --local -Rfp / lists data bags' do
- knife('list --local -Rfp /').should_succeed <<EOM
+ it "knife list --local -Rfp / lists data bags" do
+ knife("list --local -Rfp /").should_succeed <<EOM
/data_bags/
/data_bags/bag/
/data_bags/bag/item.json
EOM
end
- it 'knife list --local -Rfp /data_bags lists data bags' do
- knife('list --local -Rfp /data_bags').should_succeed <<EOM
+ it "knife list --local -Rfp /data_bags lists data bags" do
+ knife("list --local -Rfp /data_bags").should_succeed <<EOM
/data_bags/bag/
/data_bags/bag/item.json
EOM
end
- context 'when cwd is inside the data_bags directory' do
- before { cwd 'data_bags' }
- it 'knife list --local -Rfp lists data bags' do
- knife('list --local -Rfp').should_succeed <<EOM
+ context "when cwd is inside the data_bags directory" do
+ before { cwd "data_bags" }
+ it "knife list --local -Rfp lists data bags" do
+ knife("list --local -Rfp").should_succeed <<EOM
bag/
bag/item.json
EOM
@@ -868,21 +937,21 @@ EOM
end
end
- when_the_repository 'is empty' do
- context 'when the repository _paths point to places that do not exist' do
+ when_the_repository "is empty" do
+ context "when the repository _paths point to places that do not exist" do
before :each do
- %w(client cookbook data_bag environment node role user).each do |object_name|
- Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, 'nowhere', object_name)
+ %w{client cookbook data_bag environment node role user}.each do |object_name|
+ Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, "nowhere", object_name)
end
- Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, 'nowhere')
+ Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "nowhere")
end
- it 'knife list --local -Rfp / fails' do
- knife('list --local -Rfp /').should_succeed ''
+ it "knife list --local -Rfp / fails" do
+ knife("list --local -Rfp /").should_succeed ""
end
- it 'knife list --local -Rfp /data_bags fails' do
- knife('list --local -Rfp /data_bags').should_fail("ERROR: /data_bags: No such file or directory\n")
+ it "knife list --local -Rfp /data_bags fails" do
+ knife("list --local -Rfp /data_bags").should_fail("ERROR: /data_bags: No such file or directory\n")
end
end
end
diff --git a/spec/integration/knife/chef_repository_file_system_spec.rb b/spec/integration/knife/chef_repository_file_system_spec.rb
index 34afd228f3..cc538c98c0 100644
--- a/spec/integration/knife/chef_repository_file_system_spec.rb
+++ b/spec/integration/knife/chef_repository_file_system_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,15 +15,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/list'
-require 'chef/knife/show'
+require "support/shared/integration/integration_helper"
+require "chef/knife/list"
+require "chef/knife/show"
-describe 'General chef_repo file system checks', :workstation do
+describe "General chef_repo file system checks", :workstation do
include IntegrationSupport
include KnifeSupport
- context 'directories and files that should/should not be ignored' do
+ context "directories and files that should/should not be ignored" do
when_the_repository "has empty roles, environments and data bag item directories" do
before do
directory "roles"
@@ -32,7 +32,7 @@ describe 'General chef_repo file system checks', :workstation do
end
it "knife list --local -Rfp / returns them" do
- knife('list --local -Rfp /').should_succeed <<EOM
+ knife("list --local -Rfp /").should_succeed <<EOM
/data_bags/
/data_bags/bag1/
/environments/
@@ -45,25 +45,25 @@ EOM
before { directory "data_bags" }
it "knife list --local / returns it" do
- knife('list --local /').should_succeed "/data_bags\n"
+ knife("list --local /").should_succeed "/data_bags\n"
end
end
when_the_repository "has an empty cookbook directory" do
- before { directory 'cookbooks/cookbook1' }
+ before { directory "cookbooks/cookbook1" }
it "knife list --local -Rfp / does not return it" do
- knife('list --local -Rfp /').should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
+ knife("list --local -Rfp /").should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
/cookbooks/
EOM
end
end
when_the_repository "has only empty cookbook subdirectories" do
- before { directory 'cookbooks/cookbook1/recipes' }
+ before { directory "cookbooks/cookbook1/recipes" }
it "knife list --local -Rfp / does not return it" do
- knife('list --local -Rfp /').should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
+ knife("list --local -Rfp /").should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
/cookbooks/
EOM
end
@@ -71,12 +71,12 @@ EOM
when_the_repository "has empty and non-empty cookbook subdirectories" do
before do
- directory 'cookbooks/cookbook1/recipes'
- file 'cookbooks/cookbook1/templates/default/x.txt', ''
+ directory "cookbooks/cookbook1/recipes"
+ file "cookbooks/cookbook1/templates/default/x.txt", ""
end
it "knife list --local -Rfp / does not return the empty ones" do
- knife('list --local -Rfp /').should_succeed <<EOM
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
/cookbooks/cookbook1/
/cookbooks/cookbook1/templates/
@@ -87,10 +87,10 @@ EOM
end
when_the_repository "has only empty cookbook sub-sub-directories" do
- before { directory 'cookbooks/cookbook1/templates/default' }
+ before { directory "cookbooks/cookbook1/templates/default" }
it "knife list --local -Rfp / does not return it" do
- knife('list --local -Rfp /').should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
+ knife("list --local -Rfp /").should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
/cookbooks/
EOM
end
@@ -98,13 +98,13 @@ EOM
when_the_repository "has empty cookbook sub-sub-directories alongside non-empty ones" do
before do
- file 'cookbooks/cookbook1/templates/default/x.txt', ''
- directory 'cookbooks/cookbook1/templates/rhel'
- directory 'cookbooks/cookbook1/files/default'
+ file "cookbooks/cookbook1/templates/default/x.txt", ""
+ directory "cookbooks/cookbook1/templates/rhel"
+ directory "cookbooks/cookbook1/files/default"
end
it "knife list --local -Rfp / does not return the empty ones" do
- knife('list --local -Rfp /').should_succeed <<EOM
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
/cookbooks/cookbook1/
/cookbooks/cookbook1/templates/
@@ -122,7 +122,7 @@ EOM
end
it "knife list --local -Rfp / should NOT return it" do
- knife('list --local -Rfp /').should_succeed ""
+ knife("list --local -Rfp /").should_succeed ""
end
end
@@ -146,7 +146,7 @@ EOM
end
it "knife list --local -Rfp / should NOT return them" do
- knife('list --local -Rfp /').should_succeed <<EOM
+ knife("list --local -Rfp /").should_succeed <<EOM
/data_bags/
/data_bags/bag1/
/data_bags/bag1/item1.json
@@ -160,62 +160,62 @@ EOM
when_the_repository "has extraneous subdirectories and files under a cookbook" do
before do
- directory 'cookbooks/cookbook1' do
- file 'a.rb', ''
- file 'blarghle/blah.rb', ''
- directory 'attributes' do
- file 'a.rb', ''
- file 'b.json', {}
- file 'c/d.rb', ''
- file 'c/e.json', {}
+ directory "cookbooks/cookbook1" do
+ file "a.rb", ""
+ file "blarghle/blah.rb", ""
+ directory "attributes" do
+ file "a.rb", ""
+ file "b.json", {}
+ file "c/d.rb", ""
+ file "c/e.json", {}
end
- directory 'definitions' do
- file 'a.rb', ''
- file 'b.json', {}
- file 'c/d.rb', ''
- file 'c/e.json', {}
+ directory "definitions" do
+ file "a.rb", ""
+ file "b.json", {}
+ file "c/d.rb", ""
+ file "c/e.json", {}
end
- directory 'recipes' do
- file 'a.rb', ''
- file 'b.json', {}
- file 'c/d.rb', ''
- file 'c/e.json', {}
+ directory "recipes" do
+ file "a.rb", ""
+ file "b.json", {}
+ file "c/d.rb", ""
+ file "c/e.json", {}
end
- directory 'libraries' do
- file 'a.rb', ''
- file 'b.json', {}
- file 'c/d.rb', ''
- file 'c/e.json', {}
+ directory "libraries" do
+ file "a.rb", ""
+ file "b.json", {}
+ file "c/d.rb", ""
+ file "c/e.json", {}
end
- directory 'templates' do
- file 'a.rb', ''
- file 'b.json', {}
- file 'c/d.rb', ''
- file 'c/e.json', {}
+ directory "templates" do
+ file "a.rb", ""
+ file "b.json", {}
+ file "c/d.rb", ""
+ file "c/e.json", {}
end
- directory 'files' do
- file 'a.rb', ''
- file 'b.json', {}
- file 'c/d.rb', ''
- file 'c/e.json', {}
+ directory "files" do
+ file "a.rb", ""
+ file "b.json", {}
+ file "c/d.rb", ""
+ file "c/e.json", {}
end
- directory 'resources' do
- file 'a.rb', ''
- file 'b.json', {}
- file 'c/d.rb', ''
- file 'c/e.json', {}
+ directory "resources" do
+ file "a.rb", ""
+ file "b.json", {}
+ file "c/d.rb", ""
+ file "c/e.json", {}
end
- directory 'providers' do
- file 'a.rb', ''
- file 'b.json', {}
- file 'c/d.rb', ''
- file 'c/e.json', {}
+ directory "providers" do
+ file "a.rb", ""
+ file "b.json", {}
+ file "c/d.rb", ""
+ file "c/e.json", {}
end
end
end
it "knife list --local -Rfp / should NOT return them" do
- knife('list --local -Rfp /').should_succeed <<EOM
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
/cookbooks/cookbook1/
/cookbooks/cookbook1/a.rb
@@ -231,6 +231,10 @@ EOM
/cookbooks/cookbook1/files/c/e.json
/cookbooks/cookbook1/libraries/
/cookbooks/cookbook1/libraries/a.rb
+/cookbooks/cookbook1/libraries/b.json
+/cookbooks/cookbook1/libraries/c/
+/cookbooks/cookbook1/libraries/c/d.rb
+/cookbooks/cookbook1/libraries/c/e.json
/cookbooks/cookbook1/providers/
/cookbooks/cookbook1/providers/a.rb
/cookbooks/cookbook1/providers/c/
@@ -252,41 +256,41 @@ EOM
end
when_the_repository "has a file in cookbooks/" do
- before { file 'cookbooks/file', '' }
- it 'does not show up in list -Rfp' do
- knife('list --local -Rfp /').should_succeed <<EOM
+ before { file "cookbooks/file", "" }
+ it "does not show up in list -Rfp" do
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
EOM
end
end
when_the_repository "has a file in data_bags/" do
- before { file 'data_bags/file', '' }
- it 'does not show up in list -Rfp' do
- knife('list --local -Rfp /').should_succeed <<EOM
+ before { file "data_bags/file", "" }
+ it "does not show up in list -Rfp" do
+ knife("list --local -Rfp /").should_succeed <<EOM
/data_bags/
EOM
end
end
end
- when_the_repository 'has a cookbook starting with .' do
+ when_the_repository "has a cookbook starting with ." do
before do
- file 'cookbooks/.svn/metadata.rb', ''
- file 'cookbooks/a.b/metadata.rb', ''
+ file "cookbooks/.svn/metadata.rb", ""
+ file "cookbooks/a.b/metadata.rb", ""
end
- it 'knife list does not show it' do
- knife('list --local -fp /cookbooks').should_succeed "/cookbooks/a.b/\n"
+ it "knife list does not show it" do
+ knife("list --local -fp /cookbooks").should_succeed "/cookbooks/a.b/\n"
end
end
- when_the_repository 'has a data bag starting with .' do
+ when_the_repository "has a data bag starting with ." do
before do
- file 'data_bags/.svn/x.json', {}
- file 'data_bags/a.b/x.json', {}
+ file "data_bags/.svn/x.json", {}
+ file "data_bags/a.b/x.json", {}
end
- it 'knife list does not show it' do
- knife('list --local -fp /data_bags').should_succeed "/data_bags/a.b/\n"
+ it "knife list does not show it" do
+ knife("list --local -fp /data_bags").should_succeed "/data_bags/a.b/\n"
end
end
end
diff --git a/spec/integration/knife/chefignore_spec.rb b/spec/integration/knife/chefignore_spec.rb
index 34bf391f88..aa5a3979cc 100644
--- a/spec/integration/knife/chefignore_spec.rb
+++ b/spec/integration/knife/chefignore_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,37 +15,37 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/list'
-require 'chef/knife/show'
+require "support/shared/integration/integration_helper"
+require "chef/knife/list"
+require "chef/knife/show"
-describe 'chefignore tests', :workstation do
+describe "chefignore tests", :workstation do
include IntegrationSupport
include KnifeSupport
when_the_repository "has lots of stuff in it" do
before do
- file 'roles/x.json', {}
- file 'environments/x.json', {}
- file 'data_bags/bag1/x.json', {}
- file 'cookbooks/cookbook1/x.json', {}
+ file "roles/x.json", {}
+ file "environments/x.json", {}
+ file "data_bags/bag1/x.json", {}
+ file "cookbooks/cookbook1/x.json", {}
end
context "and has a chefignore everywhere except cookbooks" do
before do
chefignore = "x.json\nroles/x.json\nenvironments/x.json\ndata_bags/bag1/x.json\nbag1/x.json\ncookbooks/cookbook1/x.json\ncookbook1/x.json\n"
- file 'chefignore', chefignore
- file 'roles/chefignore', chefignore
- file 'environments/chefignore', chefignore
- file 'data_bags/chefignore', chefignore
- file 'data_bags/bag1/chefignore', chefignore
- file 'cookbooks/cookbook1/chefignore', chefignore
+ file "chefignore", chefignore
+ file "roles/chefignore", chefignore
+ file "environments/chefignore", chefignore
+ file "data_bags/chefignore", chefignore
+ file "data_bags/bag1/chefignore", chefignore
+ file "cookbooks/cookbook1/chefignore", chefignore
end
- it 'matching files and directories get ignored' do
+ it "matching files and directories get ignored" do
# NOTE: many of the "chefignore" files should probably not show up
# themselves, but we have other tests that talk about that
- knife('list --local -Rfp /').should_succeed <<EOM
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
/cookbooks/cookbook1/
/cookbooks/cookbook1/chefignore
@@ -61,15 +61,15 @@ EOM
end
end
- when_the_repository 'has a cookbook with only chefignored files' do
+ when_the_repository "has a cookbook with only chefignored files" do
before do
- file 'cookbooks/cookbook1/templates/default/x.rb', ''
- file 'cookbooks/cookbook1/libraries/x.rb', ''
- file 'cookbooks/chefignore', "libraries/x.rb\ntemplates/default/x.rb\n"
+ file "cookbooks/cookbook1/templates/default/x.rb", ""
+ file "cookbooks/cookbook1/libraries/x.rb", ""
+ file "cookbooks/chefignore", "libraries/x.rb\ntemplates/default/x.rb\n"
end
- it 'the cookbook is not listed' do
- knife('list --local -Rfp /').should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
+ it "the cookbook is not listed" do
+ knife("list --local -Rfp /").should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
/cookbooks/
EOM
end
@@ -77,17 +77,17 @@ EOM
when_the_repository "has multiple cookbooks" do
before do
- file 'cookbooks/cookbook1/x.json', {}
- file 'cookbooks/cookbook1/y.json', {}
- file 'cookbooks/cookbook2/x.json', {}
- file 'cookbooks/cookbook2/y.json', {}
+ file "cookbooks/cookbook1/x.json", {}
+ file "cookbooks/cookbook1/y.json", {}
+ file "cookbooks/cookbook2/x.json", {}
+ file "cookbooks/cookbook2/y.json", {}
end
- context 'and has a chefignore with filenames' do
- before { file 'cookbooks/chefignore', "x.json\n" }
+ context "and has a chefignore with filenames" do
+ before { file "cookbooks/chefignore", "x.json\n" }
- it 'matching files and directories get ignored in all cookbooks' do
- knife('list --local -Rfp /').should_succeed <<EOM
+ it "matching files and directories get ignored in all cookbooks" do
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
/cookbooks/cookbook1/
/cookbooks/cookbook1/y.json
@@ -99,12 +99,12 @@ EOM
context "and has a chefignore with wildcards" do
before do
- file 'cookbooks/chefignore', "x.*\n"
- file 'cookbooks/cookbook1/x.rb', ''
+ file "cookbooks/chefignore", "x.*\n"
+ file "cookbooks/cookbook1/x.rb", ""
end
- it 'matching files and directories get ignored in all cookbooks' do
- knife('list --local -Rfp /').should_succeed <<EOM
+ it "matching files and directories get ignored in all cookbooks" do
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
/cookbooks/cookbook1/
/cookbooks/cookbook1/y.json
@@ -116,13 +116,13 @@ EOM
context "and has a chefignore with relative paths" do
before do
- file 'cookbooks/cookbook1/recipes/x.rb', ''
- file 'cookbooks/cookbook2/recipes/y.rb', ''
- file 'cookbooks/chefignore', "recipes/x.rb\n"
+ file "cookbooks/cookbook1/recipes/x.rb", ""
+ file "cookbooks/cookbook2/recipes/y.rb", ""
+ file "cookbooks/chefignore", "recipes/x.rb\n"
end
- it 'matching directories get ignored' do
- knife('list --local -Rfp /').should_succeed <<EOM
+ it "matching directories get ignored" do
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
/cookbooks/cookbook1/
/cookbooks/cookbook1/x.json
@@ -138,12 +138,12 @@ EOM
context "and has a chefignore with subdirectories" do
before do
- file 'cookbooks/cookbook1/recipes/y.rb', ''
- file 'cookbooks/chefignore', "recipes\nrecipes/\n"
+ file "cookbooks/cookbook1/recipes/y.rb", ""
+ file "cookbooks/chefignore", "recipes\nrecipes/\n"
end
- it 'matching directories do NOT get ignored' do
- knife('list --local -Rfp /').should_succeed <<EOM
+ it "matching directories do NOT get ignored" do
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
/cookbooks/cookbook1/
/cookbooks/cookbook1/recipes/
@@ -159,13 +159,13 @@ EOM
context "and has a chefignore that ignores all files in a subdirectory" do
before do
- file 'cookbooks/cookbook1/templates/default/x.rb', ''
- file 'cookbooks/cookbook1/libraries/x.rb', ''
- file 'cookbooks/chefignore', "libraries/x.rb\ntemplates/default/x.rb\n"
+ file "cookbooks/cookbook1/templates/default/x.rb", ""
+ file "cookbooks/cookbook1/libraries/x.rb", ""
+ file "cookbooks/chefignore", "libraries/x.rb\ntemplates/default/x.rb\n"
end
- it 'ignores the subdirectory entirely' do
- knife('list --local -Rfp /').should_succeed <<EOM
+ it "ignores the subdirectory entirely" do
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
/cookbooks/cookbook1/
/cookbooks/cookbook1/x.json
@@ -179,11 +179,11 @@ EOM
context "and has an empty chefignore" do
before do
- file 'cookbooks/chefignore', "\n"
+ file "cookbooks/chefignore", "\n"
end
- it 'nothing is ignored' do
- knife('list --local -Rfp /').should_succeed <<EOM
+ it "nothing is ignored" do
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
/cookbooks/cookbook1/
/cookbooks/cookbook1/x.json
@@ -197,11 +197,11 @@ EOM
context "and has a chefignore with comments and empty lines" do
before do
- file 'cookbooks/chefignore', "\n\n # blah\n#\nx.json\n\n"
+ file "cookbooks/chefignore", "\n\n # blah\n#\nx.json\n\n"
end
- it 'matching files and directories get ignored in all cookbooks' do
- knife('list --local -Rfp /').should_succeed <<EOM
+ it "matching files and directories get ignored in all cookbooks" do
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
/cookbooks/cookbook1/
/cookbooks/cookbook1/y.json
@@ -215,25 +215,25 @@ EOM
when_the_repository "has multiple cookbook paths" do
before :each do
Chef::Config.cookbook_path = [
- File.join(Chef::Config.chef_repo_path, 'cookbooks1'),
- File.join(Chef::Config.chef_repo_path, 'cookbooks2')
+ File.join(Chef::Config.chef_repo_path, "cookbooks1"),
+ File.join(Chef::Config.chef_repo_path, "cookbooks2"),
]
end
before do
- file 'cookbooks1/mycookbook/metadata.rb', ''
- file 'cookbooks1/mycookbook/x.json', {}
- file 'cookbooks2/yourcookbook/metadata.rb', ''
- file 'cookbooks2/yourcookbook/x.json', ''
+ file "cookbooks1/mycookbook/metadata.rb", ""
+ file "cookbooks1/mycookbook/x.json", {}
+ file "cookbooks2/yourcookbook/metadata.rb", ""
+ file "cookbooks2/yourcookbook/x.json", ""
end
context "and multiple chefignores" do
before do
- file 'cookbooks1/chefignore', "metadata.rb\n"
- file 'cookbooks2/chefignore', "x.json\n"
+ file "cookbooks1/chefignore", "metadata.rb\n"
+ file "cookbooks2/chefignore", "x.json\n"
end
it "chefignores apply only to the directories they are in" do
- knife('list --local -Rfp /').should_succeed <<EOM
+ knife("list --local -Rfp /").should_succeed <<EOM
/cookbooks/
/cookbooks/mycookbook/
/cookbooks/mycookbook/x.json
@@ -244,14 +244,14 @@ EOM
context "and conflicting cookbooks" do
before do
- file 'cookbooks1/yourcookbook/metadata.rb', ''
- file 'cookbooks1/yourcookbook/x.json', ''
- file 'cookbooks1/yourcookbook/onlyincookbooks1.rb', ''
- file 'cookbooks2/yourcookbook/onlyincookbooks2.rb', ''
+ file "cookbooks1/yourcookbook/metadata.rb", ""
+ file "cookbooks1/yourcookbook/x.json", ""
+ file "cookbooks1/yourcookbook/onlyincookbooks1.rb", ""
+ file "cookbooks2/yourcookbook/onlyincookbooks2.rb", ""
end
it "chefignores apply only to the winning cookbook" do
- knife('list --local -Rfp /').should_succeed(<<EOM, :stderr => "WARN: Child with name 'yourcookbook' found in multiple directories: #{Chef::Config.chef_repo_path}/cookbooks1/yourcookbook and #{Chef::Config.chef_repo_path}/cookbooks2/yourcookbook\n")
+ knife("list --local -Rfp /").should_succeed(<<EOM, :stderr => "WARN: Child with name 'yourcookbook' found in multiple directories: #{Chef::Config.chef_repo_path}/cookbooks1/yourcookbook and #{Chef::Config.chef_repo_path}/cookbooks2/yourcookbook\n")
/cookbooks/
/cookbooks/mycookbook/
/cookbooks/mycookbook/x.json
@@ -264,32 +264,32 @@ EOM
end
end
- when_the_repository 'has a cookbook named chefignore' do
+ when_the_repository "has a cookbook named chefignore" do
before do
- file 'cookbooks/chefignore/metadata.rb', {}
+ file "cookbooks/chefignore/metadata.rb", {}
end
- it 'knife list -Rfp /cookbooks shows it' do
- knife('list --local -Rfp /cookbooks').should_succeed <<EOM
+ it "knife list -Rfp /cookbooks shows it" do
+ knife("list --local -Rfp /cookbooks").should_succeed <<EOM
/cookbooks/chefignore/
/cookbooks/chefignore/metadata.rb
EOM
end
end
- when_the_repository 'has multiple cookbook paths, one with a chefignore file and the other with a cookbook named chefignore' do
+ when_the_repository "has multiple cookbook paths, one with a chefignore file and the other with a cookbook named chefignore" do
before do
- file 'cookbooks1/chefignore', ''
- file 'cookbooks1/blah/metadata.rb', ''
- file 'cookbooks2/chefignore/metadata.rb', ''
+ file "cookbooks1/chefignore", ""
+ file "cookbooks1/blah/metadata.rb", ""
+ file "cookbooks2/chefignore/metadata.rb", ""
end
before :each do
Chef::Config.cookbook_path = [
- File.join(Chef::Config.chef_repo_path, 'cookbooks1'),
- File.join(Chef::Config.chef_repo_path, 'cookbooks2')
+ File.join(Chef::Config.chef_repo_path, "cookbooks1"),
+ File.join(Chef::Config.chef_repo_path, "cookbooks2"),
]
end
- it 'knife list -Rfp /cookbooks shows the chefignore cookbook' do
- knife('list --local -Rfp /cookbooks').should_succeed <<EOM
+ it "knife list -Rfp /cookbooks shows the chefignore cookbook" do
+ knife("list --local -Rfp /cookbooks").should_succeed <<EOM
/cookbooks/blah/
/cookbooks/blah/metadata.rb
/cookbooks/chefignore/
diff --git a/spec/integration/knife/client_bulk_delete_spec.rb b/spec/integration/knife/client_bulk_delete_spec.rb
new file mode 100644
index 0000000000..a422401af6
--- /dev/null
+++ b/spec/integration/knife/client_bulk_delete_spec.rb
@@ -0,0 +1,130 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife client bulk delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some clients" do
+ before do
+ client "concat", {}
+ client "cons", {}
+ client "car", {}
+ client "cdr", {}
+ client "cat", {}
+ end
+
+ it "deletes all matching clients" do
+ knife("client bulk delete ^ca.*", input: "Y").should_succeed <<EOM
+The following clients will be deleted:
+
+car cat
+
+Are you sure you want to delete these clients? (Y/N) Deleted client car
+Deleted client cat
+EOM
+
+ knife("client list").should_succeed <<EOM
+cdr
+chef-validator
+chef-webui
+concat
+cons
+EOM
+ end
+
+ it "deletes all matching clients when unanchored" do
+ knife("client bulk delete ca.*", input: "Y").should_succeed <<EOM
+The following clients will be deleted:
+
+car cat concat
+
+Are you sure you want to delete these clients? (Y/N) Deleted client car
+Deleted client cat
+Deleted client concat
+EOM
+
+ knife("client list").should_succeed <<EOM
+cdr
+chef-validator
+chef-webui
+cons
+EOM
+ end
+ end
+
+ when_the_chef_server "has a validator client" do
+ before do
+ client "cons", {}
+ client "car", {}
+ client "car-validator", { validator: true }
+ client "cdr", {}
+ client "cat", {}
+ end
+
+ it "refuses to delete a validator normally" do
+ knife("client bulk delete ^ca.*", input: "Y").should_succeed <<EOM
+The following clients are validators and will not be deleted:
+
+car-validator
+
+You must specify --delete-validators to delete the validator clients
+The following clients will be deleted:
+
+car cat
+
+Are you sure you want to delete these clients? (Y/N) Deleted client car
+Deleted client cat
+EOM
+
+ knife("client list").should_succeed <<EOM
+car-validator
+cdr
+chef-validator
+chef-webui
+cons
+EOM
+ end
+
+ it "deletes a validator when told to" do
+ knife("client bulk delete ^ca.* -D", input: "Y\nY").should_succeed <<EOM
+The following validators will be deleted:
+
+car-validator
+
+Are you sure you want to delete these validators? (Y/N) Deleted client car-validator
+The following clients will be deleted:
+
+car cat
+
+Are you sure you want to delete these clients? (Y/N) Deleted client car
+Deleted client cat
+EOM
+
+ knife("client list").should_succeed <<EOM
+cdr
+chef-validator
+chef-webui
+cons
+EOM
+ end
+ end
+end
diff --git a/spec/integration/knife/client_create_spec.rb b/spec/integration/knife/client_create_spec.rb
new file mode 100644
index 0000000000..10172833c8
--- /dev/null
+++ b/spec/integration/knife/client_create_spec.rb
@@ -0,0 +1,69 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "openssl"
+
+describe "knife client create", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:out) { "Created client[bah]\n" }
+
+ when_the_chef_server "is empty" do
+ it "creates a new client" do
+ knife("client create -k bah").should_succeed stderr: out
+ end
+
+ it "creates a new validator client" do
+ knife("client create -k --validator bah").should_succeed stderr: out
+ knife("client show bah").should_succeed <<EOM
+admin: false
+chef_type: client
+name: bah
+validator: true
+EOM
+ end
+
+ it "refuses to add an existing client" do
+ pending "Knife client create must not blindly overwrite an existing client"
+ knife("client create -k bah").should_succeed stderr: out
+ expect { knife("client create -k bah") }.to raise_error(Net::HTTPServerException)
+ end
+
+ it "saves the private key to a file" do
+ Dir.mktmpdir do |tgt|
+ knife("client create -f #{tgt}/bah.pem bah").should_succeed stderr: out
+ expect(File).to exist("#{tgt}/bah.pem")
+ end
+ end
+
+ it "reads the public key from a file" do
+ Dir.mktmpdir do |tgt|
+ key = OpenSSL::PKey::RSA.generate(1024)
+ File.open("#{tgt}/public.pem", "w") { |pub| pub.write(key.public_key.to_pem) }
+ knife("client create -p #{tgt}/public.pem bah").should_succeed stderr: out
+ end
+ end
+
+ it "refuses to run if conflicting options are passed" do
+ knife("client create -p public.pem --prevent-keygen blah").should_fail stderr: "FATAL: You cannot pass --public-key and --prevent-keygen\n", stdout: /^USAGE.*/
+ end
+ end
+end
diff --git a/spec/integration/knife/client_delete_spec.rb b/spec/integration/knife/client_delete_spec.rb
new file mode 100644
index 0000000000..d135dd0a5b
--- /dev/null
+++ b/spec/integration/knife/client_delete_spec.rb
@@ -0,0 +1,63 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife client delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some clients" do
+ before do
+ client "cons", {}
+ client "car", {}
+ client "car-validator", { validator: true }
+ client "cdr", {}
+ client "cat", {}
+ end
+
+ it "deletes a client" do
+ knife("client delete car", input: "Y").should_succeed <<EOM
+Do you really want to delete car? (Y/N) Deleted client[car]
+EOM
+
+ knife("client list").should_succeed <<EOM
+car-validator
+cat
+cdr
+chef-validator
+chef-webui
+cons
+EOM
+ end
+
+ it "refuses to delete a validator normally" do
+ knife("client delete car-validator", input: "Y").should_fail exit_code: 2, stdout: "Do you really want to delete car-validator? (Y/N) ", stderr: <<EOM
+FATAL: You must specify --delete-validators to delete the validator client car-validator
+EOM
+ end
+
+ it "deletes a validator correctly" do
+ knife("client delete car-validator -D", input: "Y").should_succeed <<EOM
+Do you really want to delete car-validator? (Y/N) Deleted client[car-validator]
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/client_key_create_spec.rb b/spec/integration/knife/client_key_create_spec.rb
new file mode 100644
index 0000000000..b588afbe50
--- /dev/null
+++ b/spec/integration/knife/client_key_create_spec.rb
@@ -0,0 +1,65 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "openssl"
+
+describe "knife client key create", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:out) { "Created key: new" }
+
+ when_the_chef_server "has a client" do
+ before do
+ client "bah", {}
+ end
+
+ it "creates a new client key" do
+ knife("client key create -k new bah").should_succeed stderr: /^#{out}/, stdout: /.*BEGIN RSA PRIVATE KEY/
+ end
+
+ it "creates a new client key with an expiration date" do
+ date = "2017-12-31T23:59:59Z"
+ knife("client key create -k new -e #{date} bah").should_succeed stderr: /^#{out}/, stdout: /.*BEGIN RSA PRIVATE KEY/
+ knife("client key show bah new").should_succeed /expiration_date:.*#{date}/
+ end
+
+ it "refuses to add an already existing key" do
+ knife("client key create -k new bah")
+ expect { knife("client key create -k new bah") }.to raise_error(Net::HTTPServerException)
+ end
+
+ it "saves the private key to a file" do
+ Dir.mktmpdir do |tgt|
+ knife("client key create -f #{tgt}/bah.pem -k new bah").should_succeed stderr: /^#{out}/
+ expect(File).to exist("#{tgt}/bah.pem")
+ end
+ end
+
+ it "reads the public key from a file" do
+ Dir.mktmpdir do |tgt|
+ key = OpenSSL::PKey::RSA.generate(1024)
+ File.open("#{tgt}/public.pem", "w") { |pub| pub.write(key.public_key.to_pem) }
+ knife("client key create -p #{tgt}/public.pem -k new bah").should_succeed stderr: /^#{out}/
+ end
+ end
+
+ end
+end
diff --git a/spec/integration/knife/client_key_delete_spec.rb b/spec/integration/knife/client_key_delete_spec.rb
new file mode 100644
index 0000000000..d5827aa545
--- /dev/null
+++ b/spec/integration/knife/client_key_delete_spec.rb
@@ -0,0 +1,42 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife client key delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a client" do
+ before do
+ client "car", {}
+ end
+
+ it "deletes a client" do
+ out = "Do you really want to delete the key named new for the client named car? (Y/N) "
+ knife("client key create -k new car")
+ knife("client key delete car new", input: "Y").should_succeed stdout: out, stderr: <<EOM
+Deleted key named new for the client named car
+EOM
+
+ knife("client key list car").should_succeed ""
+ end
+
+ end
+end
diff --git a/spec/integration/knife/client_key_list_spec.rb b/spec/integration/knife/client_key_list_spec.rb
new file mode 100644
index 0000000000..de9894622e
--- /dev/null
+++ b/spec/integration/knife/client_key_list_spec.rb
@@ -0,0 +1,60 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "date"
+
+describe "knife client key list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:now) { DateTime.now }
+ let(:last_month) { (now << 1).strftime("%FT%TZ") }
+ let(:next_month) { (now >> 1).strftime("%FT%TZ") }
+
+ when_the_chef_server "has a client" do
+ before do
+ client "cons", {}
+ knife("client key create cons -k new")
+ knife("client key create cons -k next_month -e #{next_month}")
+ knife("client key create cons -k expired -e #{last_month}")
+ end
+
+ it "lists the keys for a client" do
+ knife("client key list cons").should_succeed "expired\nnew\nnext_month\n"
+ end
+
+ it "shows detailed output" do
+ knife("client key list -w cons").should_succeed <<EOM
+expired: http://127.0.0.1:8900/clients/cons/keys/expired (expired)
+new: http://127.0.0.1:8900/clients/cons/keys/new
+next_month: http://127.0.0.1:8900/clients/cons/keys/next_month
+EOM
+ end
+
+ it "lists the expired keys for a client" do
+ knife("client key list -e cons").should_succeed "expired\n"
+ end
+
+ it "lists the unexpired keys for a client" do
+ knife("client key list -n cons").should_succeed "new\nnext_month\n"
+ end
+
+ end
+end
diff --git a/spec/integration/knife/client_key_show_spec.rb b/spec/integration/knife/client_key_show_spec.rb
new file mode 100644
index 0000000000..e96ff3b6fe
--- /dev/null
+++ b/spec/integration/knife/client_key_show_spec.rb
@@ -0,0 +1,44 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "date"
+
+describe "knife client key show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:now) { DateTime.now }
+ let(:last_month) { (now << 1).strftime("%FT%TZ") }
+ let(:next_month) { (now >> 1).strftime("%FT%TZ") }
+
+ when_the_chef_server "has a client" do
+ before do
+ client "cons", {}
+ knife("client key create cons -k new")
+ knife("client key create cons -k next_month -e #{next_month}")
+ knife("client key create cons -k expired -e #{last_month}")
+ end
+
+ it "shows a key for a client" do
+ knife("client key show cons new").should_succeed stdout: /.*name:.*new/
+ end
+
+ end
+end
diff --git a/spec/integration/knife/client_list_spec.rb b/spec/integration/knife/client_list_spec.rb
new file mode 100644
index 0000000000..4159df73f1
--- /dev/null
+++ b/spec/integration/knife/client_list_spec.rb
@@ -0,0 +1,48 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife client list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some clients" do
+ before do
+ client "cons", {}
+ client "car", {}
+ client "car-validator", { validator: true }
+ client "cdr", {}
+ client "cat", {}
+ end
+
+ it "lists the clients" do
+ knife("client list").should_succeed <<EOM
+car
+car-validator
+cat
+cdr
+chef-validator
+chef-webui
+cons
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/client_show_spec.rb b/spec/integration/knife/client_show_spec.rb
new file mode 100644
index 0000000000..23ac204d77
--- /dev/null
+++ b/spec/integration/knife/client_show_spec.rb
@@ -0,0 +1,36 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife client show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a client" do
+ before do
+ client "cons", {}
+ end
+
+ it "shows a client" do
+ knife("client show cons").should_succeed stdout: /.*name:.*cons/
+ end
+
+ end
+end
diff --git a/spec/integration/knife/common_options_spec.rb b/spec/integration/knife/common_options_spec.rb
index b2e2e3fc2a..c941dcc1ee 100644
--- a/spec/integration/knife/common_options_spec.rb
+++ b/spec/integration/knife/common_options_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,46 +15,46 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/raw'
+require "support/shared/integration/integration_helper"
+require "chef/knife/raw"
-describe 'knife common options', :workstation do
+describe "knife common options", :workstation do
include IntegrationSupport
include KnifeSupport
when_the_repository "has a node" do
- before { file 'nodes/x.json', {} }
+ before { file "nodes/x.json", {} }
- context 'When chef_zero.enabled is true' do
+ context "When chef_zero.enabled is true" do
before(:each) do
Chef::Config.chef_zero.enabled = true
end
- it 'knife raw /nodes/x should retrieve the node' do
- knife('raw /nodes/x').should_succeed( /"name": "x"/ )
+ it "knife raw /nodes/x should retrieve the node" do
+ knife("raw /nodes/x").should_succeed( /"name": "x"/ )
end
- context 'And chef_zero.port is 9999' do
+ context "And chef_zero.port is 9999" do
before(:each) { Chef::Config.chef_zero.port = 9999 }
- it 'knife raw /nodes/x should retrieve the node' do
- knife('raw /nodes/x').should_succeed( /"name": "x"/ )
- expect(Chef::Config.chef_server_url).to eq('chefzero://localhost:9999')
+ it "knife raw /nodes/x should retrieve the node" do
+ knife("raw /nodes/x").should_succeed( /"name": "x"/ )
+ expect(Chef::Config.chef_server_url).to eq("chefzero://localhost:9999")
end
end
# 0.0.0.0 is not a valid address to bind to on windows.
- context 'And chef_zero.host is 0.0.0.0', :unix_only do
- before(:each) { Chef::Config.chef_zero.host = '0.0.0.0' }
+ context "And chef_zero.host is 0.0.0.0", :unix_only do
+ before(:each) { Chef::Config.chef_zero.host = "0.0.0.0" }
- it 'knife raw /nodes/x should retrieve the role' do
- knife('raw /nodes/x').should_succeed( /"name": "x"/ )
+ it "knife raw /nodes/x should retrieve the role" do
+ knife("raw /nodes/x").should_succeed( /"name": "x"/ )
end
end
- context 'and there is a private key' do
+ context "and there is a private key" do
before do
- file 'mykey.pem', <<EOM
+ file "mykey.pem", <<EOM
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEApubutqtYYQ5UiA9QhWP7UvSmsfHsAoPKEVVPdVW/e8Svwpyf
0Xef6OFWVmBE+W442ZjLOe2y6p2nSnaq4y7dg99NFz6X+16mcKiCbj0RCiGqCvCk
@@ -85,29 +85,29 @@ syHLXYFNy0OxMtH/bBAXBGNHd9gf5uOnqh0pYcbe/uRAxumC7Rl0cL509eURiA2T
EOM
end
- it 'knife raw /nodes/x should retrieve the node' do
- knife('raw /nodes/x').should_succeed( /"name": "x"/ )
+ it "knife raw /nodes/x should retrieve the node" do
+ knife("raw /nodes/x").should_succeed( /"name": "x"/ )
end
end
end
- it 'knife raw -z /nodes/x retrieves the node' do
- knife('raw -z /nodes/x').should_succeed( /"name": "x"/ )
+ it "knife raw -z /nodes/x retrieves the node" do
+ knife("raw -z /nodes/x").should_succeed( /"name": "x"/ )
end
- it 'knife raw --local-mode /nodes/x retrieves the node' do
- knife('raw --local-mode /nodes/x').should_succeed( /"name": "x"/ )
+ it "knife raw --local-mode /nodes/x retrieves the node" do
+ knife("raw --local-mode /nodes/x").should_succeed( /"name": "x"/ )
end
- it 'knife raw -z --chef-zero-port=9999 /nodes/x retrieves the node' do
- knife('raw -z --chef-zero-port=9999 /nodes/x').should_succeed( /"name": "x"/ )
- expect(Chef::Config.chef_server_url).to eq('chefzero://localhost:9999')
+ it "knife raw -z --chef-zero-port=9999 /nodes/x retrieves the node" do
+ knife("raw -z --chef-zero-port=9999 /nodes/x").should_succeed( /"name": "x"/ )
+ expect(Chef::Config.chef_server_url).to eq("chefzero://localhost:9999")
end
- context 'when the default port (8889) is already bound' do
+ context "when the default port (8889) is already bound" do
before :each do
begin
- @server = ChefZero::Server.new(:host => 'localhost', :port => 8889)
+ @server = ChefZero::Server.new(:host => "localhost", :port => 8889)
@server.start_background
rescue Errno::EADDRINUSE
# OK. Don't care who has it in use, as long as *someone* does.
@@ -117,16 +117,16 @@ EOM
@server.stop if @server
end
- it 'knife raw -z /nodes/x retrieves the node' do
- knife('raw -z /nodes/x').should_succeed( /"name": "x"/ )
+ it "knife raw -z /nodes/x retrieves the node" do
+ knife("raw -z /nodes/x").should_succeed( /"name": "x"/ )
expect(URI(Chef::Config.chef_server_url).port).to be > 8889
end
end
- context 'when port 9999 is already bound' do
+ context "when port 9999 is already bound" do
before :each do
begin
- @server = ChefZero::Server.new(:host => 'localhost', :port => 9999)
+ @server = ChefZero::Server.new(:host => "localhost", :port => 9999)
@server.start_background
rescue Errno::EADDRINUSE
# OK. Don't care who has it in use, as long as *someone* does.
@@ -136,20 +136,20 @@ EOM
@server.stop if @server
end
- it 'knife raw -z --chef-zero-port=9999-20000 /nodes/x' do
- knife('raw -z --chef-zero-port=9999-20000 /nodes/x').should_succeed( /"name": "x"/ )
+ it "knife raw -z --chef-zero-port=9999-20000 /nodes/x" do
+ knife("raw -z --chef-zero-port=9999-20000 /nodes/x").should_succeed( /"name": "x"/ )
expect(URI(Chef::Config.chef_server_url).port).to be > 9999
end
- it 'knife raw -z --chef-zero-port=9999-9999,19423' do
- knife('raw -z --chef-zero-port=9999-9999,19423 /nodes/x').should_succeed( /"name": "x"/ )
+ it "knife raw -z --chef-zero-port=9999-9999,19423" do
+ knife("raw -z --chef-zero-port=9999-9999,19423 /nodes/x").should_succeed( /"name": "x"/ )
expect(URI(Chef::Config.chef_server_url).port).to be == 19423
end
end
- it 'knife raw -z --chef-zero-port=9999 /nodes/x retrieves the node' do
- knife('raw -z --chef-zero-port=9999 /nodes/x').should_succeed( /"name": "x"/ )
- expect(Chef::Config.chef_server_url).to eq('chefzero://localhost:9999')
+ it "knife raw -z --chef-zero-port=9999 /nodes/x retrieves the node" do
+ knife("raw -z --chef-zero-port=9999 /nodes/x").should_succeed( /"name": "x"/ )
+ expect(Chef::Config.chef_server_url).to eq("chefzero://localhost:9999")
end
end
end
diff --git a/spec/integration/knife/cookbook_api_ipv6_spec.rb b/spec/integration/knife/cookbook_api_ipv6_spec.rb
index 3d468be7f6..0a4a6a6e94 100644
--- a/spec/integration/knife/cookbook_api_ipv6_spec.rb
+++ b/spec/integration/knife/cookbook_api_ipv6_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,15 +15,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'chef/mixin/shell_out'
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
-describe "Knife cookbook API integration with IPv6", :workstation do
+describe "Knife cookbook API integration with IPv6", :workstation, :not_supported_on_gce do
include IntegrationSupport
include Chef::Mixin::ShellOut
when_the_chef_server "is bound to IPv6" do
- let(:chef_zero_opts) { {:host => "::1"} }
+ let(:chef_zero_opts) { { :host => "::1" } }
let(:client_key) do
<<-END_VALIDATION_PEM
@@ -84,8 +84,8 @@ END_CLIENT_RB
end
before do
- file 'config/knife.rb', knife_rb_content
- file 'config/knifeuser.pem', client_key
+ file "config/knife.rb", knife_rb_content
+ file "config/knifeuser.pem", client_key
end
it "successfully uploads a cookbook" do
@@ -102,7 +102,7 @@ END_CLIENT_RB
it "downloads the cookbook" do
shell_out!("knife cookbook download apache2 #{knife_config_flag} -d #{cache_path}", :cwd => chef_dir)
- expect(Dir["#{cache_path}/*"].map {|entry| File.basename(entry)}).to include("apache2-0.0.1")
+ expect(Dir["#{cache_path}/*"].map { |entry| File.basename(entry) }).to include("apache2-0.0.1")
end
end
diff --git a/spec/integration/knife/cookbook_bulk_delete_spec.rb b/spec/integration/knife/cookbook_bulk_delete_spec.rb
new file mode 100644
index 0000000000..4740813ce1
--- /dev/null
+++ b/spec/integration/knife/cookbook_bulk_delete_spec.rb
@@ -0,0 +1,64 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/cookbook_bulk_delete"
+
+describe "knife cookbook bulk delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a cookbook" do
+ before do
+ cookbook "foo", "1.0.0"
+ cookbook "foo", "0.6.5"
+ cookbook "fox", "0.6.0"
+ cookbook "fox", "0.6.5"
+ cookbook "fax", "0.6.0"
+ cookbook "zfa", "0.6.5"
+ end
+
+ # rubocop:disable Style/TrailingWhitespace
+ it "knife cookbook bulk delete deletes all matching cookbooks" do
+ stdout = <<EOM
+All versions of the following cookbooks will be deleted:
+
+foo fox
+
+Do you really want to delete these cookbooks? (Y/N)
+EOM
+
+ stderr = <<EOM
+Deleted cookbook foo [1.0.0]
+Deleted cookbook foo [0.6.5]
+Deleted cookbook fox [0.6.5]
+Deleted cookbook fox [0.6.0]
+EOM
+
+ knife("cookbook bulk delete ^fo.*", input: "Y").should_succeed(stderr: stderr, stdout: stdout)
+
+ knife("cookbook list -a").should_succeed <<EOM
+fax 0.6.0
+zfa 0.6.5
+EOM
+ end
+ # rubocop:enable Style/TrailingWhitespace
+
+ end
+end
diff --git a/spec/integration/knife/cookbook_download_spec.rb b/spec/integration/knife/cookbook_download_spec.rb
new file mode 100644
index 0000000000..2fbffb9dea
--- /dev/null
+++ b/spec/integration/knife/cookbook_download_spec.rb
@@ -0,0 +1,95 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/cookbook_download"
+require "tmpdir"
+
+describe "knife cookbook download", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:tmpdir) { Dir.mktmpdir }
+
+ when_the_chef_server "has only one cookbook" do
+ before do
+ cookbook "x", "1.0.1"
+ end
+
+ it "knife cookbook download downloads the latest version" do
+ knife("cookbook download -d #{tmpdir} x").should_succeed stderr: <<EOM
+Downloading x cookbook version 1.0.1
+Downloading resources
+Downloading providers
+Downloading recipes
+Downloading definitions
+Downloading libraries
+Downloading attributes
+Downloading files
+Downloading templates
+Downloading root_files
+Cookbook downloaded to #{tmpdir}/x-1.0.1
+EOM
+ end
+
+ it "knife cookbook download with a version downloads the specified version" do
+ knife("cookbook download -d #{tmpdir} x 1.0.1").should_succeed stderr: <<EOM
+Downloading x cookbook version 1.0.1
+Downloading resources
+Downloading providers
+Downloading recipes
+Downloading definitions
+Downloading libraries
+Downloading attributes
+Downloading files
+Downloading templates
+Downloading root_files
+Cookbook downloaded to #{tmpdir}/x-1.0.1
+EOM
+ end
+
+ it "knife cookbook download with an unknown version raises an error" do
+ expect { knife("cookbook download -d #{tmpdir} x 1.0.0") }.to raise_error(Net::HTTPServerException)
+ end
+ end
+
+ when_the_chef_server "has multiple cookbook versions" do
+ before do
+ cookbook "x", "1.0.1"
+ cookbook "x", "1.0.0"
+ end
+
+ it "knife cookbook download with no version prompts" do
+ knife("cookbook download -d #{tmpdir} x", input: "2\n").should_succeed(stderr: <<EOM, stdout: "Which version do you want to download?\n1. x 1.0.0\n2. x 1.0.1\n\n"
+Downloading x cookbook version 1.0.1
+Downloading resources
+Downloading providers
+Downloading recipes
+Downloading definitions
+Downloading libraries
+Downloading attributes
+Downloading files
+Downloading templates
+Downloading root_files
+Cookbook downloaded to #{tmpdir}/x-1.0.1
+EOM
+)
+ end
+ end
+end
diff --git a/spec/integration/knife/cookbook_list_spec.rb b/spec/integration/knife/cookbook_list_spec.rb
new file mode 100644
index 0000000000..65578696f2
--- /dev/null
+++ b/spec/integration/knife/cookbook_list_spec.rb
@@ -0,0 +1,54 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/cookbook_list"
+
+describe "knife cookbook list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a cookbook" do
+ before do
+ cookbook "x", "1.0.0"
+ cookbook "x", "0.6.5"
+ cookbook "x", "0.6.0"
+ cookbook "y", "0.6.5"
+ cookbook "y", "0.6.0"
+ cookbook "z", "0.6.5"
+ end
+
+ it "knife cookbook list shows all the cookbooks" do
+ knife("cookbook list").should_succeed <<EOM
+x 1.0.0
+y 0.6.5
+z 0.6.5
+EOM
+ end
+
+ it "knife cookbook list -a shows all the versions of all the cookbooks" do
+ knife("cookbook list -a").should_succeed <<EOM
+x 1.0.0 0.6.5 0.6.0
+y 0.6.5 0.6.0
+z 0.6.5
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/cookbook_show_spec.rb b/spec/integration/knife/cookbook_show_spec.rb
new file mode 100644
index 0000000000..c001d66b97
--- /dev/null
+++ b/spec/integration/knife/cookbook_show_spec.rb
@@ -0,0 +1,159 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/cookbook_show"
+
+describe "knife cookbook show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a cookbook" do
+ before do
+ cookbook "x", "1.0.0", { "recipes" => { "default.rb" => "file 'n'", "x.rb" => "" } }
+ cookbook "x", "0.6.5"
+ end
+
+ it "knife cookbook show x shows all the versions" do
+ knife("cookbook show x").should_succeed "x 1.0.0 0.6.5\n"
+ end
+
+ # rubocop:disable Style/TrailingWhitespace
+ it "knife cookbook show x 1.0.0 shows the correct version" do
+ knife("cookbook show x 1.0.0").should_succeed <<EOM
+attributes:
+chef_type: cookbook_version
+cookbook_name: x
+definitions:
+files:
+frozen?: false
+json_class: Chef::CookbookVersion
+libraries:
+metadata:
+ attributes:
+ chef_versions:
+ conflicting:
+ dependencies:
+ description:
+ gems:
+ groupings:
+ issues_url:
+ license: All rights reserved
+ long_description:
+ maintainer:
+ maintainer_email:
+ name: x
+ ohai_versions:
+ platforms:
+ privacy: false
+ providing:
+ recipes:
+ recommendations:
+ replacing:
+ source_url:
+ suggestions:
+ version: 1.0.0
+name: x-1.0.0
+providers:
+recipes:
+ checksum: 4631b34cf58de10c5ef1304889941b2e
+ name: default.rb
+ path: recipes/default.rb
+ specificity: default
+ url: http://127.0.0.1:8900/file_store/checksums/4631b34cf58de10c5ef1304889941b2e
+
+ checksum: d41d8cd98f00b204e9800998ecf8427e
+ name: x.rb
+ path: recipes/x.rb
+ specificity: default
+ url: http://127.0.0.1:8900/file_store/checksums/d41d8cd98f00b204e9800998ecf8427e
+resources:
+root_files:
+ checksum: 8226671f751ba102dea6a6b6bd32fa8d
+ name: metadata.rb
+ path: metadata.rb
+ specificity: default
+ url: http://127.0.0.1:8900/file_store/checksums/8226671f751ba102dea6a6b6bd32fa8d
+templates:
+version: 1.0.0
+EOM
+ end
+
+ it "knife cookbook show x 1.0.0 metadata shows the metadata" do
+ knife("cookbook show x 1.0.0 metadata").should_succeed <<EOM
+attributes:
+chef_versions:
+conflicting:
+dependencies:
+description:
+gems:
+groupings:
+issues_url:
+license: All rights reserved
+long_description:
+maintainer:
+maintainer_email:
+name: x
+ohai_versions:
+platforms:
+privacy: false
+providing:
+recipes:
+recommendations:
+replacing:
+source_url:
+suggestions:
+version: 1.0.0
+EOM
+ end
+
+ it "knife cookbook show x 1.0.0 recipes shows all the recipes" do
+ knife("cookbook show x 1.0.0 recipes").should_succeed <<EOM
+checksum: 4631b34cf58de10c5ef1304889941b2e
+name: default.rb
+path: recipes/default.rb
+specificity: default
+url: http://127.0.0.1:8900/file_store/checksums/4631b34cf58de10c5ef1304889941b2e
+
+checksum: d41d8cd98f00b204e9800998ecf8427e
+name: x.rb
+path: recipes/x.rb
+specificity: default
+url: http://127.0.0.1:8900/file_store/checksums/d41d8cd98f00b204e9800998ecf8427e
+EOM
+ end
+ # rubocop:enable Style/TrailingWhitespace
+
+ it "knife cookbook show x 1.0.0 recipes default.rb shows the default recipe" do
+ knife("cookbook show x 1.0.0 recipes default.rb").should_succeed "file 'n'\n"
+ end
+
+ it "knife cookbook show with a non-existent file displays an error" do
+ expect { knife("cookbook show x 1.0.0 recipes moose.rb") }.to raise_error(Chef::Exceptions::FileNotFound)
+ end
+
+ it "knife cookbook show with a non-existent version displays an error" do
+ expect { knife("cookbook show x 1.0.1") }.to raise_error(Net::HTTPServerException)
+ end
+
+ it "knife cookbook show with a non-existent cookbook displays an error" do
+ expect { knife("cookbook show y") }.to raise_error(Net::HTTPServerException)
+ end
+ end
+end
diff --git a/spec/integration/knife/cookbook_upload_spec.rb b/spec/integration/knife/cookbook_upload_spec.rb
new file mode 100644
index 0000000000..a0de725603
--- /dev/null
+++ b/spec/integration/knife/cookbook_upload_spec.rb
@@ -0,0 +1,90 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/cookbook_upload"
+
+describe "knife cookbook upload", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let (:cb_dir) { "#{@repository_dir}/cookbooks" }
+
+ when_the_chef_server "is empty" do
+ when_the_repository "has a cookbook" do
+ before do
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ end
+
+ it "knife cookbook upload uploads the cookbook" do
+ knife("cookbook upload x -o #{cb_dir}").should_succeed stderr: <<EOM
+Uploading x [1.0.0]
+Uploaded 1 cookbook.
+EOM
+ end
+
+ it "knife cookbook upload --freeze uploads and freezes the cookbook" do
+ knife("cookbook upload x -o #{cb_dir} --freeze").should_succeed stderr: <<EOM
+Uploading x [1.0.0]
+Uploaded 1 cookbook.
+EOM
+ # Modify the file, attempt to reupload
+ file "cookbooks/x/metadata.rb", 'name "x"; version "1.0.0"#different'
+ knife("cookbook upload x -o #{cb_dir} --freeze").should_fail stderr: <<EOM
+Uploading x [1.0.0]
+ERROR: Version 1.0.0 of cookbook x is frozen. Use --force to override.
+WARNING: Not updating version constraints for x in the environment as the cookbook is frozen.
+ERROR: Failed to upload 1 cookbook.
+EOM
+ end
+ end
+
+ when_the_repository "has a cookbook that depends on another cookbook" do
+ before do
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0", "\ndepends 'y'")
+ file "cookbooks/y/metadata.rb", cb_metadata("y", "1.0.0")
+ end
+
+ it "knife cookbook upload --include-dependencies uploads both cookbooks" do
+ knife("cookbook upload --include-dependencies x -o #{cb_dir}").should_succeed stderr: <<EOM
+Uploading x [1.0.0]
+Uploading y [1.0.0]
+Uploaded 2 cookbooks.
+EOM
+ end
+
+ it "knife cookbook upload fails due to missing dependencies" do
+ knife("cookbook upload x -o #{cb_dir}").should_fail stderr: <<EOM
+Uploading x [1.0.0]
+ERROR: Cookbook x depends on cookbooks which are not currently
+ERROR: being uploaded and cannot be found on the server.
+ERROR: The missing cookbook(s) are: 'y' version '>= 0.0.0'
+EOM
+ end
+
+ it "knife cookbook upload -a uploads both cookbooks" do
+ knife("cookbook upload -a -o #{cb_dir}").should_succeed stderr: <<EOM
+Uploading x [1.0.0]
+Uploading y [1.0.0]
+Uploaded all cookbooks.
+EOM
+ end
+ end
+ end
+end
diff --git a/spec/integration/knife/data_bag_create_spec.rb b/spec/integration/knife/data_bag_create_spec.rb
new file mode 100644
index 0000000000..dc61d55fd5
--- /dev/null
+++ b/spec/integration/knife/data_bag_create_spec.rb
@@ -0,0 +1,55 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/data_bag_create"
+
+describe "knife data bag create", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:err) { "Created data_bag[foo]\n" }
+ let(:out) { "Created data_bag_item[bar]\n" }
+ let(:exists) { "Data bag foo already exists\n" }
+
+ when_the_chef_server "is empty" do
+ it "creates a new data bag" do
+ knife("data bag create foo").should_succeed stderr: err
+ end
+
+ it "creates a new data bag and item" do
+ knife("data bag create foo bar").should_succeed stdout: out, stderr: err
+ end
+
+ it "adds a new item to an existing bag" do
+ knife("data bag create foo").should_succeed stderr: err
+ knife("data bag create foo bar").should_succeed stdout: out, stderr: exists
+ end
+
+ it "refuses to add an existing data bag" do
+ knife("data bag create foo").should_succeed stderr: err
+ knife("data bag create foo").should_succeed stderr: exists
+ end
+
+ it "fails to add an existing item" do
+ knife("data bag create foo bar").should_succeed stdout: out, stderr: err
+ expect { knife("data bag create foo bar") }.to raise_error(Net::HTTPServerException)
+ end
+ end
+end
diff --git a/spec/integration/knife/data_bag_delete_spec.rb b/spec/integration/knife/data_bag_delete_spec.rb
new file mode 100644
index 0000000000..96345b0d2b
--- /dev/null
+++ b/spec/integration/knife/data_bag_delete_spec.rb
@@ -0,0 +1,58 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/data_bag_delete"
+
+describe "knife data bag delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some data bags" do
+ before do
+ data_bag "x", {}
+ data_bag "canteloupe", {}
+ data_bag "rocket", { "falcon9" => { heavy: "true" }, "atlas" => {}, "ariane" => {} }
+ end
+
+ it "with an empty data bag" do
+ knife("data bag delete canteloupe", input: "y").should_succeed <<EOM
+Do you really want to delete canteloupe? (Y/N) Deleted data_bag[canteloupe]
+EOM
+ end
+
+ it "with a bag with some items" do
+ knife("data bag delete rocket", input: "y").should_succeed <<EOM
+Do you really want to delete rocket? (Y/N) Deleted data_bag[rocket]
+EOM
+ end
+
+ it "with a single item" do
+ knife("data bag delete rocket falcon9", input: "y").should_succeed <<EOM
+Do you really want to delete falcon9? (Y/N) Deleted data_bag_item[falcon9]
+EOM
+ end
+
+ it "choosing not to delete" do
+ knife("data bag delete rocket falcon9", input: "n").should_succeed <<EOM, exit_code: 3
+Do you really want to delete falcon9? (Y/N) You said no, so I'm done here.
+EOM
+ end
+ end
+end
diff --git a/spec/integration/knife/data_bag_from_file_spec.rb b/spec/integration/knife/data_bag_from_file_spec.rb
new file mode 100644
index 0000000000..ca8f743487
--- /dev/null
+++ b/spec/integration/knife/data_bag_from_file_spec.rb
@@ -0,0 +1,115 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife data bag from file", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let (:db_dir) { "#{@repository_dir}/data_bags" }
+
+ when_the_chef_server "has an empty data bag" do
+ before do
+ data_bag "foo", {}
+ data_bag "bar", {}
+ end
+
+ when_the_repository "has some data bag items" do
+ before do
+ file "data_bags/foo/bar.json", { "id" => "bar", "foo" => "bar " }
+ file "data_bags/foo/bzr.json", { "id" => "bzr", "foo" => "bar " }
+ file "data_bags/foo/cat.json", { "id" => "cat", "foo" => "bar " }
+ file "data_bags/foo/dog.json", { "id" => "dog", "foo" => "bar " }
+ file "data_bags/foo/encrypted.json", <<EOM
+{
+ "id": "encrypted",
+ "password": {
+ "encrypted_data": "H6ab5RY9a9JAkS8A0RCMspXtOJh0ai8cNeA4Q3gLO8s=\\n",
+ "iv": "uWKKKxrJgtELlGMCOLJdkA==\\n",
+ "version": 1,
+ "cipher": "aes-256-cbc"
+ }
+}
+EOM
+ file "data_bags/bar/round_trip.json", <<EOM
+{
+ "name": "data_bag_item_bar_round_trip",
+ "json_class": "Chef::DataBagItem",
+ "chef_type": "data_bag_item",
+ "data_bag": "bar",
+ "raw_data": {
+ "id": "round_trip",
+ "root_password": {
+ "encrypted_data": "noDOsTpsTAZlTU5sprhmYZzUDfr8du7hH/zRDOjRAmoTJHTZyfYoR221EOOW\\nXJ1D\\n",
+ "iv": "Bnqhfy6n0Hx1wCe9pxHLoA==\\n",
+ "version": 1,
+ "cipher": "aes-256-cbc"
+ },
+ "admin_password": {
+ "encrypted_data": "TcC7dU1gx6OnE5Ab4i/k42UEf0Nnr7cAyuTHId/LNjNOwpNf7XZc27DQSjuy\\nHPlt\\n",
+ "iv": "+TAWJuPWCI2+WB8lGJAyvw==\\n",
+ "version": 1,
+ "cipher": "aes-256-cbc"
+ }
+ }
+}
+EOM
+ end
+
+ it "uploads a single file" do
+ knife("data bag from file foo #{db_dir}/foo/bar.json").should_succeed stderr: <<EOM
+Updated data_bag_item[foo::bar]
+EOM
+ end
+
+ it "uploads a single encrypted file" do
+ knife("data bag from file foo #{db_dir}/foo/encrypted.json").should_succeed stderr: <<EOM
+Updated data_bag_item[foo::encrypted]
+EOM
+ end
+
+ it "uploads a file in chef's internal format" do
+ pending "chef/chef#4815"
+ knife("data bag from file bar #{db_dir}/bar/round_trip.json").should_succeed stderr: <<EOM
+Updated data_bag_item[bar::round_trip]
+EOM
+ end
+
+ it "uploads many files" do
+ knife("data bag from file foo #{db_dir}/foo/bar.json #{db_dir}/foo/bzr.json").should_succeed stderr: <<EOM
+Updated data_bag_item[foo::bar]
+Updated data_bag_item[foo::bzr]
+EOM
+ end
+
+ it "uploads a whole directory" do
+ knife("data bag from file foo #{db_dir}/foo")
+ knife("data bag show foo").should_succeed <<EOM
+bar
+bzr
+cat
+dog
+encrypted
+EOM
+ end
+
+ end
+ end
+end
diff --git a/spec/integration/knife/data_bag_list_spec.rb b/spec/integration/knife/data_bag_list_spec.rb
new file mode 100644
index 0000000000..7db9638660
--- /dev/null
+++ b/spec/integration/knife/data_bag_list_spec.rb
@@ -0,0 +1,43 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/data_bag_list"
+
+describe "knife data bag list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some data bags" do
+ before do
+ data_bag "x", {}
+ data_bag "canteloupe", {}
+ data_bag "rocket", {}
+ end
+
+ it "knife data bag list shows all the cookbooks" do
+ knife("data bag list").should_succeed <<EOM
+canteloupe
+rocket
+x
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/data_bag_show_spec.rb b/spec/integration/knife/data_bag_show_spec.rb
new file mode 100644
index 0000000000..22381adb9e
--- /dev/null
+++ b/spec/integration/knife/data_bag_show_spec.rb
@@ -0,0 +1,53 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/data_bag_show"
+
+describe "knife data bag show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some data bags" do
+ before do
+ data_bag "x", {}
+ data_bag "canteloupe", {}
+ data_bag "rocket", { "falcon9" => { heavy: "true" }, "atlas" => {}, "ariane" => {} }
+ end
+
+ it "with an empty data bag" do
+ knife("data bag show canteloupe").should_succeed "\n"
+ end
+
+ it "with a bag with some items" do
+ knife("data bag show rocket").should_succeed <<EOM
+ariane
+atlas
+falcon9
+EOM
+ end
+
+ it "with a single item" do
+ knife("data bag show rocket falcon9").should_succeed <<EOM, stderr: "WARNING: Unencrypted data bag detected, ignoring any provided secret options.\n"
+heavy: true
+id: falcon9
+EOM
+ end
+ end
+end
diff --git a/spec/integration/knife/delete_spec.rb b/spec/integration/knife/delete_spec.rb
index 733a7ef72b..1c69fbf9c9 100644
--- a/spec/integration/knife/delete_spec.rb
+++ b/spec/integration/knife/delete_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,12 +15,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/delete'
-require 'chef/knife/list'
-require 'chef/knife/raw'
+require "support/shared/integration/integration_helper"
+require "chef/knife/delete"
+require "chef/knife/list"
+require "chef/knife/raw"
-describe 'knife delete', :workstation do
+describe "knife delete", :workstation do
include IntegrationSupport
include KnifeSupport
@@ -100,39 +100,39 @@ EOM
when_the_chef_server "has one of each thing" do
before do
- client 'x', '{}'
- cookbook 'x', '1.0.0'
- data_bag 'x', { 'y' => '{}' }
- environment 'x', '{}'
- node 'x', '{}'
- role 'x', '{}'
- user 'x', '{}'
+ client "x", "{}"
+ cookbook "x", "1.0.0"
+ data_bag "x", { "y" => "{}" }
+ environment "x", "{}"
+ node "x", "{}"
+ role "x", "{}"
+ user "x", "{}"
end
- when_the_repository 'also has one of each thing' do
+ when_the_repository "also has one of each thing" do
before do
- file 'clients/x.json', {}
- file 'cookbooks/x/metadata.rb', ''
- file 'data_bags/x/y.json', {}
- file 'environments/_default.json', {}
- file 'environments/x.json', {}
- file 'nodes/x.json', {}
- file 'roles/x.json', {}
- file 'users/x.json', {}
- end
-
- it 'knife delete --both /cookbooks/x fails' do
- knife('delete --both /cookbooks/x').should_fail <<EOM
+ file "clients/x.json", {}
+ file "cookbooks/x/metadata.rb", ""
+ file "data_bags/x/y.json", {}
+ file "environments/_default.json", {}
+ file "environments/x.json", {}
+ file "nodes/x.json", {}
+ file "roles/x.json", {}
+ file "users/x.json", {}
+ end
+
+ it "knife delete --both /cookbooks/x fails" do
+ knife("delete --both /cookbooks/x").should_fail <<EOM
ERROR: /cookbooks/x (remote) must be deleted recursively! Pass -r to knife delete.
ERROR: /cookbooks/x (local) must be deleted recursively! Pass -r to knife delete.
EOM
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed everything
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed everything
end
- it 'knife delete --both -r /cookbooks/x deletes x' do
- knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
- knife('list -Rf /').should_succeed <<EOM
+ it "knife delete --both -r /cookbooks/x deletes x" do
+ knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+ knife("list -Rf /").should_succeed <<EOM
/clients
/clients/chef-validator.json
/clients/chef-webui.json
@@ -152,7 +152,7 @@ EOM
/users/admin.json
/users/x.json
EOM
- knife('list -Rf --local /').should_succeed <<EOM
+ knife("list -Rf --local /").should_succeed <<EOM
/clients
/clients/x.json
/cookbooks
@@ -171,10 +171,10 @@ EOM
EOM
end
- it 'knife delete -r --local /cookbooks/x deletes x locally but not remotely' do
- knife('delete -r --local /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed <<EOM
+ it "knife delete -r --local /cookbooks/x deletes x locally but not remotely" do
+ knife("delete -r --local /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed <<EOM
/clients
/clients/x.json
/cookbooks
@@ -193,9 +193,9 @@ EOM
EOM
end
- it 'knife delete -r /cookbooks/x deletes x remotely but not locally' do
- knife('delete -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
- knife('list -Rf /').should_succeed <<EOM
+ it "knife delete -r /cookbooks/x deletes x remotely but not locally" do
+ knife("delete -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+ knife("list -Rf /").should_succeed <<EOM
/clients
/clients/chef-validator.json
/clients/chef-webui.json
@@ -215,22 +215,22 @@ EOM
/users/admin.json
/users/x.json
EOM
- knife('list -Rf --local /').should_succeed everything
+ knife("list -Rf --local /").should_succeed everything
end
# TODO delete empty data bag (particularly different on local side)
- context 'with an empty data bag on both' do
+ context "with an empty data bag on both" do
before do
- data_bag 'empty', {}
- directory 'data_bags/empty'
+ data_bag "empty", {}
+ directory "data_bags/empty"
end
- it 'knife delete --both /data_bags/empty fails but deletes local version' do
- knife('delete --both /data_bags/empty').should_fail <<EOM
+ it "knife delete --both /data_bags/empty fails but deletes local version" do
+ knife("delete --both /data_bags/empty").should_fail <<EOM
ERROR: /data_bags/empty (remote) must be deleted recursively! Pass -r to knife delete.
ERROR: /data_bags/empty (local) must be deleted recursively! Pass -r to knife delete.
EOM
- knife('list -Rf /').should_succeed <<EOM
+ knife("list -Rf /").should_succeed <<EOM
/clients
/clients/chef-validator.json
/clients/chef-webui.json
@@ -253,7 +253,7 @@ EOM
/users/admin.json
/users/x.json
EOM
- knife('list -Rf --local /').should_succeed <<EOM
+ knife("list -Rf --local /").should_succeed <<EOM
/clients
/clients/x.json
/cookbooks
@@ -276,18 +276,18 @@ EOM
end
end
- it 'knife delete --both /data_bags/x fails' do
- knife('delete --both /data_bags/x').should_fail <<EOM
+ it "knife delete --both /data_bags/x fails" do
+ knife("delete --both /data_bags/x").should_fail <<EOM
ERROR: /data_bags/x (remote) must be deleted recursively! Pass -r to knife delete.
ERROR: /data_bags/x (local) must be deleted recursively! Pass -r to knife delete.
EOM
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed everything
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed everything
end
- it 'knife delete --both -r /data_bags/x deletes x' do
- knife('delete --both -r /data_bags/x').should_succeed "Deleted /data_bags/x\n"
- knife('list -Rf /').should_succeed <<EOM
+ it "knife delete --both -r /data_bags/x deletes x" do
+ knife("delete --both -r /data_bags/x").should_succeed "Deleted /data_bags/x\n"
+ knife("list -Rf /").should_succeed <<EOM
/clients
/clients/chef-validator.json
/clients/chef-webui.json
@@ -307,7 +307,7 @@ EOM
/users/admin.json
/users/x.json
EOM
- knife('list -Rf --local /').should_succeed <<EOM
+ knife("list -Rf --local /").should_succeed <<EOM
/clients
/clients/x.json
/cookbooks
@@ -326,9 +326,9 @@ EOM
EOM
end
- it 'knife delete --both /environments/x.json deletes x' do
- knife('delete --both /environments/x.json').should_succeed "Deleted /environments/x.json\n"
- knife('list -Rf /').should_succeed <<EOM
+ it "knife delete --both /environments/x.json deletes x" do
+ knife("delete --both /environments/x.json").should_succeed "Deleted /environments/x.json\n"
+ knife("list -Rf /").should_succeed <<EOM
/clients
/clients/chef-validator.json
/clients/chef-webui.json
@@ -349,7 +349,7 @@ EOM
/users/admin.json
/users/x.json
EOM
- knife('list -Rf --local /').should_succeed <<EOM
+ knife("list -Rf --local /").should_succeed <<EOM
/clients
/clients/x.json
/cookbooks
@@ -369,9 +369,9 @@ EOM
EOM
end
- it 'knife delete --both /roles/x.json deletes x' do
- knife('delete --both /roles/x.json').should_succeed "Deleted /roles/x.json\n"
- knife('list -Rf /').should_succeed <<EOM
+ it "knife delete --both /roles/x.json deletes x" do
+ knife("delete --both /roles/x.json").should_succeed "Deleted /roles/x.json\n"
+ knife("list -Rf /").should_succeed <<EOM
/clients
/clients/chef-validator.json
/clients/chef-webui.json
@@ -392,7 +392,7 @@ EOM
/users/admin.json
/users/x.json
EOM
- knife('list -Rf --local /').should_succeed <<EOM
+ knife("list -Rf --local /").should_succeed <<EOM
/clients
/clients/x.json
/cookbooks
@@ -412,10 +412,10 @@ EOM
EOM
end
- it 'knife delete --both /environments/_default.json fails but still deletes the local copy' do
- knife('delete --both /environments/_default.json').should_fail :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n", :stdout => "Deleted /environments/_default.json\n"
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed <<EOM
+ it "knife delete --both /environments/_default.json fails but still deletes the local copy" do
+ knife("delete --both /environments/_default.json").should_fail :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n", :stdout => "Deleted /environments/_default.json\n"
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed <<EOM
/clients
/clients/x.json
/cookbooks
@@ -435,23 +435,23 @@ EOM
EOM
end
- it 'knife delete --both /environments/nonexistent.json fails' do
- knife('delete --both /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed everything
+ it "knife delete --both /environments/nonexistent.json fails" do
+ knife("delete --both /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed everything
end
- it 'knife delete --both / fails' do
- knife('delete --both /').should_fail <<EOM
+ it "knife delete --both / fails" do
+ knife("delete --both /").should_fail <<EOM
ERROR: / (remote) cannot be deleted.
ERROR: / (local) cannot be deleted.
EOM
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed everything
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed everything
end
- it 'knife delete --both -r /* fails' do
- knife('delete --both -r /*').should_fail <<EOM
+ it "knife delete --both -r /* fails" do
+ knife("delete --both -r /*").should_fail <<EOM
ERROR: / (remote) cannot be deleted.
ERROR: / (local) cannot be deleted.
ERROR: /clients (remote) cannot be deleted.
@@ -469,31 +469,31 @@ ERROR: /roles (local) cannot be deleted.
ERROR: /users (remote) cannot be deleted.
ERROR: /users (local) cannot be deleted.
EOM
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed everything
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed everything
end
end
- when_the_repository 'has only top-level directories' do
+ when_the_repository "has only top-level directories" do
before do
- directory 'clients'
- directory 'cookbooks'
- directory 'data_bags'
- directory 'environments'
- directory 'nodes'
- directory 'roles'
- directory 'users'
+ directory "clients"
+ directory "cookbooks"
+ directory "data_bags"
+ directory "environments"
+ directory "nodes"
+ directory "roles"
+ directory "users"
end
- it 'knife delete --both /cookbooks/x fails' do
- knife('delete --both /cookbooks/x').should_fail "ERROR: /cookbooks/x (remote) must be deleted recursively! Pass -r to knife delete.\n"
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed nothing
+ it "knife delete --both /cookbooks/x fails" do
+ knife("delete --both /cookbooks/x").should_fail "ERROR: /cookbooks/x (remote) must be deleted recursively! Pass -r to knife delete.\n"
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed nothing
end
- it 'knife delete --both -r /cookbooks/x deletes x' do
- knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
- knife('list -Rf /').should_succeed <<EOM
+ it "knife delete --both -r /cookbooks/x deletes x" do
+ knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+ knife("list -Rf /").should_succeed <<EOM
/clients
/clients/chef-validator.json
/clients/chef-webui.json
@@ -513,18 +513,18 @@ EOM
/users/admin.json
/users/x.json
EOM
- knife('list -Rf --local /').should_succeed nothing
+ knife("list -Rf --local /").should_succeed nothing
end
- it 'knife delete --both /data_bags/x fails' do
- knife('delete --both /data_bags/x').should_fail "ERROR: /data_bags/x (remote) must be deleted recursively! Pass -r to knife delete.\n"
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed nothing
+ it "knife delete --both /data_bags/x fails" do
+ knife("delete --both /data_bags/x").should_fail "ERROR: /data_bags/x (remote) must be deleted recursively! Pass -r to knife delete.\n"
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed nothing
end
- it 'knife delete --both -r /data_bags/x deletes x' do
- knife('delete --both -r /data_bags/x').should_succeed "Deleted /data_bags/x\n"
- knife('list -Rf /').should_succeed <<EOM
+ it "knife delete --both -r /data_bags/x deletes x" do
+ knife("delete --both -r /data_bags/x").should_succeed "Deleted /data_bags/x\n"
+ knife("list -Rf /").should_succeed <<EOM
/clients
/clients/chef-validator.json
/clients/chef-webui.json
@@ -544,12 +544,12 @@ EOM
/users/admin.json
/users/x.json
EOM
- knife('list -Rf --local /').should_succeed nothing
+ knife("list -Rf --local /").should_succeed nothing
end
- it 'knife delete --both /environments/x.json deletes x' do
- knife('delete --both /environments/x.json').should_succeed "Deleted /environments/x.json\n"
- knife('list -Rf /').should_succeed <<EOM
+ it "knife delete --both /environments/x.json deletes x" do
+ knife("delete --both /environments/x.json").should_succeed "Deleted /environments/x.json\n"
+ knife("list -Rf /").should_succeed <<EOM
/clients
/clients/chef-validator.json
/clients/chef-webui.json
@@ -570,12 +570,12 @@ EOM
/users/admin.json
/users/x.json
EOM
- knife('list -Rf --local /').should_succeed nothing
+ knife("list -Rf --local /").should_succeed nothing
end
- it 'knife delete --both /roles/x.json deletes x' do
- knife('delete --both /roles/x.json').should_succeed "Deleted /roles/x.json\n"
- knife('list -Rf /').should_succeed <<EOM
+ it "knife delete --both /roles/x.json deletes x" do
+ knife("delete --both /roles/x.json").should_succeed "Deleted /roles/x.json\n"
+ knife("list -Rf /").should_succeed <<EOM
/clients
/clients/chef-validator.json
/clients/chef-webui.json
@@ -596,23 +596,23 @@ EOM
/users/admin.json
/users/x.json
EOM
- knife('list -Rf --local /').should_succeed nothing
+ knife("list -Rf --local /").should_succeed nothing
end
- it 'knife delete --both /environments/_default.json fails' do
- knife('delete --both /environments/_default.json').should_fail "", :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n"
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed nothing
+ it "knife delete --both /environments/_default.json fails" do
+ knife("delete --both /environments/_default.json").should_fail "", :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n"
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed nothing
end
- it 'knife delete --both / fails' do
- knife('delete --both /').should_fail "ERROR: / (remote) cannot be deleted.\nERROR: / (local) cannot be deleted.\n"
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed nothing
+ it "knife delete --both / fails" do
+ knife("delete --both /").should_fail "ERROR: / (remote) cannot be deleted.\nERROR: / (local) cannot be deleted.\n"
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed nothing
end
- it 'knife delete --both -r /* fails' do
- knife('delete --both -r /*').should_fail <<EOM
+ it "knife delete --both -r /* fails" do
+ knife("delete --both -r /*").should_fail <<EOM
ERROR: / (remote) cannot be deleted.
ERROR: / (local) cannot be deleted.
ERROR: /clients (remote) cannot be deleted.
@@ -630,21 +630,21 @@ ERROR: /roles (local) cannot be deleted.
ERROR: /users (remote) cannot be deleted.
ERROR: /users (local) cannot be deleted.
EOM
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed nothing
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed nothing
end
- it 'knife delete --both /environments/nonexistent.json fails' do
- knife('delete --both /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
- knife('list -Rf /').should_succeed server_everything
- knife('list -Rf --local /').should_succeed nothing
+ it "knife delete --both /environments/nonexistent.json fails" do
+ knife("delete --both /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
+ knife("list -Rf /").should_succeed server_everything
+ knife("list -Rf --local /").should_succeed nothing
end
- context 'and cwd is at the top level' do
- before { cwd '.' }
- it 'knife delete fails' do
- knife('delete').should_fail "FATAL: Must specify at least one argument. If you want to delete everything in this directory, type \"knife delete --recurse .\"\n", :stdout => /USAGE/
- knife('list -Rf /').should_succeed <<EOM
+ context "and cwd is at the top level" do
+ before { cwd "." }
+ it "knife delete fails" do
+ knife("delete").should_fail "FATAL: You must specify at least one argument. If you want to delete everything in this directory, run \"knife delete --recurse .\"\n", :stdout => /USAGE/
+ knife("list -Rf /").should_succeed <<EOM
clients
clients/chef-validator.json
clients/chef-webui.json
@@ -666,7 +666,7 @@ users
users/admin.json
users/x.json
EOM
- knife('list -Rf --local /').should_succeed <<EOM
+ knife("list -Rf --local /").should_succeed <<EOM
clients
cookbooks
data_bags
@@ -680,29 +680,29 @@ EOM
end
end
- when_the_chef_server 'is empty' do
- when_the_repository 'has one of each thing' do
+ when_the_chef_server "is empty" do
+ when_the_repository "has one of each thing" do
before do
- file 'clients/x.json', {}
- file 'cookbooks/x/metadata.rb', ''
- file 'data_bags/x/y.json', {}
- file 'environments/_default.json', {}
- file 'environments/x.json', {}
- file 'nodes/x.json', {}
- file 'roles/x.json', {}
- file 'users/x.json', {}
- end
-
- it 'knife delete --both /cookbooks/x fails' do
- knife('delete --both /cookbooks/x').should_fail "ERROR: /cookbooks/x (local) must be deleted recursively! Pass -r to knife delete.\n"
- knife('list -Rf /').should_succeed server_nothing
- knife('list -Rf --local /').should_succeed everything
- end
-
- it 'knife delete --both -r /cookbooks/x deletes x' do
- knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
- knife('list -Rf /').should_succeed server_nothing
- knife('list -Rf --local /').should_succeed <<EOM
+ file "clients/x.json", {}
+ file "cookbooks/x/metadata.rb", ""
+ file "data_bags/x/y.json", {}
+ file "environments/_default.json", {}
+ file "environments/x.json", {}
+ file "nodes/x.json", {}
+ file "roles/x.json", {}
+ file "users/x.json", {}
+ end
+
+ it "knife delete --both /cookbooks/x fails" do
+ knife("delete --both /cookbooks/x").should_fail "ERROR: /cookbooks/x (local) must be deleted recursively! Pass -r to knife delete.\n"
+ knife("list -Rf /").should_succeed server_nothing
+ knife("list -Rf --local /").should_succeed everything
+ end
+
+ it "knife delete --both -r /cookbooks/x deletes x" do
+ knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+ knife("list -Rf /").should_succeed server_nothing
+ knife("list -Rf --local /").should_succeed <<EOM
/clients
/clients/x.json
/cookbooks
@@ -721,16 +721,16 @@ EOM
EOM
end
- it 'knife delete --both /data_bags/x fails' do
- knife('delete --both /data_bags/x').should_fail "ERROR: /data_bags/x (local) must be deleted recursively! Pass -r to knife delete.\n"
- knife('list -Rf /').should_succeed server_nothing
- knife('list -Rf --local /').should_succeed everything
+ it "knife delete --both /data_bags/x fails" do
+ knife("delete --both /data_bags/x").should_fail "ERROR: /data_bags/x (local) must be deleted recursively! Pass -r to knife delete.\n"
+ knife("list -Rf /").should_succeed server_nothing
+ knife("list -Rf --local /").should_succeed everything
end
- it 'knife delete --both -r /data_bags/x deletes x' do
- knife('delete --both -r /data_bags/x').should_succeed "Deleted /data_bags/x\n"
- knife('list -Rf /').should_succeed server_nothing
- knife('list -Rf --local /').should_succeed <<EOM
+ it "knife delete --both -r /data_bags/x deletes x" do
+ knife("delete --both -r /data_bags/x").should_succeed "Deleted /data_bags/x\n"
+ knife("list -Rf /").should_succeed server_nothing
+ knife("list -Rf --local /").should_succeed <<EOM
/clients
/clients/x.json
/cookbooks
@@ -749,10 +749,10 @@ EOM
EOM
end
- it 'knife delete --both /environments/x.json deletes x' do
- knife('delete --both /environments/x.json').should_succeed "Deleted /environments/x.json\n"
- knife('list -Rf /').should_succeed server_nothing
- knife('list -Rf --local /').should_succeed <<EOM
+ it "knife delete --both /environments/x.json deletes x" do
+ knife("delete --both /environments/x.json").should_succeed "Deleted /environments/x.json\n"
+ knife("list -Rf /").should_succeed server_nothing
+ knife("list -Rf --local /").should_succeed <<EOM
/clients
/clients/x.json
/cookbooks
@@ -772,10 +772,10 @@ EOM
EOM
end
- it 'knife delete --both /roles/x.json deletes x' do
- knife('delete --both /roles/x.json').should_succeed "Deleted /roles/x.json\n"
- knife('list -Rf /').should_succeed server_nothing
- knife('list -Rf --local /').should_succeed <<EOM
+ it "knife delete --both /roles/x.json deletes x" do
+ knife("delete --both /roles/x.json").should_succeed "Deleted /roles/x.json\n"
+ knife("list -Rf /").should_succeed server_nothing
+ knife("list -Rf --local /").should_succeed <<EOM
/clients
/clients/x.json
/cookbooks
@@ -795,10 +795,10 @@ EOM
EOM
end
- it 'knife delete --both /environments/_default.json fails but still deletes the local copy' do
- knife('delete --both /environments/_default.json').should_fail :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n", :stdout => "Deleted /environments/_default.json\n"
- knife('list -Rf /').should_succeed server_nothing
- knife('list -Rf --local /').should_succeed <<EOM
+ it "knife delete --both /environments/_default.json fails but still deletes the local copy" do
+ knife("delete --both /environments/_default.json").should_fail :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n", :stdout => "Deleted /environments/_default.json\n"
+ knife("list -Rf /").should_succeed server_nothing
+ knife("list -Rf --local /").should_succeed <<EOM
/clients
/clients/x.json
/cookbooks
@@ -818,14 +818,14 @@ EOM
EOM
end
- it 'knife delete --both / fails' do
- knife('delete --both /').should_fail "ERROR: / (remote) cannot be deleted.\nERROR: / (local) cannot be deleted.\n"
- knife('list -Rf /').should_succeed server_nothing
- knife('list -Rf --local /').should_succeed everything
+ it "knife delete --both / fails" do
+ knife("delete --both /").should_fail "ERROR: / (remote) cannot be deleted.\nERROR: / (local) cannot be deleted.\n"
+ knife("list -Rf /").should_succeed server_nothing
+ knife("list -Rf --local /").should_succeed everything
end
- it 'knife delete --both -r /* fails' do
- knife('delete --both -r /*').should_fail <<EOM
+ it "knife delete --both -r /* fails" do
+ knife("delete --both -r /*").should_fail <<EOM
ERROR: / (remote) cannot be deleted.
ERROR: / (local) cannot be deleted.
ERROR: /clients (remote) cannot be deleted.
@@ -843,21 +843,21 @@ ERROR: /roles (local) cannot be deleted.
ERROR: /users (remote) cannot be deleted.
ERROR: /users (local) cannot be deleted.
EOM
- knife('list -Rf /').should_succeed server_nothing
- knife('list -Rf --local /').should_succeed everything
+ knife("list -Rf /").should_succeed server_nothing
+ knife("list -Rf --local /").should_succeed everything
end
- it 'knife delete --both /environments/nonexistent.json fails' do
- knife('delete --both /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
- knife('list -Rf /').should_succeed server_nothing
- knife('list -Rf --local /').should_succeed everything
+ it "knife delete --both /environments/nonexistent.json fails" do
+ knife("delete --both /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
+ knife("list -Rf /").should_succeed server_nothing
+ knife("list -Rf --local /").should_succeed everything
end
- context 'and cwd is at the top level' do
- before { cwd '.' }
- it 'knife delete fails' do
- knife('delete').should_fail "FATAL: Must specify at least one argument. If you want to delete everything in this directory, type \"knife delete --recurse .\"\n", :stdout => /USAGE/
- knife('list -Rf /').should_succeed <<EOM
+ context "and cwd is at the top level" do
+ before { cwd "." }
+ it "knife delete fails" do
+ knife("delete").should_fail "FATAL: You must specify at least one argument. If you want to delete everything in this directory, run \"knife delete --recurse .\"\n", :stdout => /USAGE/
+ knife("list -Rf /").should_succeed <<EOM
clients
clients/chef-validator.json
clients/chef-webui.json
@@ -870,7 +870,7 @@ roles
users
users/admin.json
EOM
- knife('list -Rf --local /').should_succeed <<EOM
+ knife("list -Rf --local /").should_succeed <<EOM
clients
clients/x.json
cookbooks
@@ -894,110 +894,124 @@ EOM
end
end
- when_the_repository 'has a cookbook' do
+ when_the_repository "has a cookbook" do
before do
- file 'cookbooks/x/metadata.rb', 'version "1.0.0"'
- file 'cookbooks/x/onlyin1.0.0.rb', 'old_text'
+ file "cookbooks/x/metadata.rb", 'version "1.0.0"'
+ file "cookbooks/x/onlyin1.0.0.rb", "old_text"
end
- when_the_chef_server 'has a later version for the cookbook' do
+ when_the_chef_server "has a later version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
end
# TODO this seems wrong
- it 'knife delete --both -r /cookbooks/x deletes the latest version on the server and the local version' do
- knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
- knife('raw /cookbooks/x').should_succeed(/1.0.0/)
- knife('list --local /cookbooks').should_succeed ''
+ it "knife delete --both -r /cookbooks/x deletes the latest version on the server and the local version" do
+ knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+ knife("raw /cookbooks/x").should_succeed(/1.0.0/)
+ knife("list --local /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has an earlier version for the cookbook' do
+ when_the_chef_server "has an earlier version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
end
- it 'knife delete --both /cookbooks/x deletes the latest version on the server and the local version' do
- knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
- knife('raw /cookbooks/x').should_succeed(/0.9.9/)
- knife('list --local /cookbooks').should_succeed ''
+ it "knife delete --both /cookbooks/x deletes the latest version on the server and the local version" do
+ knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+ knife("raw /cookbooks/x").should_succeed(/0.9.9/)
+ knife("list --local /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has a later version for the cookbook, and no current version' do
- before { cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' } }
+ when_the_chef_server "has a later version for the cookbook, and no current version" do
+ before { cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" } }
- it 'knife delete --both /cookbooks/x deletes the server and client version of the cookbook' do
- knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
- knife('raw /cookbooks/x').should_fail(/404/)
- knife('list --local /cookbooks').should_succeed ''
+ it "knife delete --both /cookbooks/x deletes the server and client version of the cookbook" do
+ knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+ knife("raw /cookbooks/x").should_fail(/404/)
+ knife("list --local /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
- before { cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' } }
+ when_the_chef_server "has an earlier version for the cookbook, and no current version" do
+ before { cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" } }
- it 'knife delete --both /cookbooks/x deletes the server and client version of the cookbook' do
- knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
- knife('raw /cookbooks/x').should_fail(/404/)
- knife('list --local /cookbooks').should_succeed ''
+ it "knife delete --both /cookbooks/x deletes the server and client version of the cookbook" do
+ knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+ knife("raw /cookbooks/x").should_fail(/404/)
+ knife("list --local /cookbooks").should_succeed ""
end
end
end
- when_the_repository 'is empty' do
- when_the_chef_server 'has two versions of a cookbook' do
+ when_the_repository "is empty" do
+ when_the_chef_server "has two versions of a cookbook" do
before do
- cookbook 'x', '2.0.11'
- cookbook 'x', '11.0.0'
+ cookbook "x", "2.0.11"
+ cookbook "x", "11.0.0"
end
- it 'knife delete deletes the latest version' do
- knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
- knife('raw /cookbooks/x').should_succeed( /2.0.11/ )
+ it "knife delete deletes the latest version" do
+ knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+ knife("raw /cookbooks/x").should_succeed( /2.0.11/ )
end
end
end
when_the_chef_server "is in Enterprise mode", :osc_compat => false, :single_org => false do
before do
- organization 'foo' do
- container 'x', {}
- group 'x', {}
+ organization "foo" do
+ container "x", {}
+ group "x", {}
+ policy "x", "1.2.3", {}
+ policy_group "x", { "policies" => { "x" => { "revision_id" => "1.2.3" } } }
end
end
before :each do
- Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo')
+ Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, "/organizations/foo")
end
- it 'knife delete /acls/containers/environments.json fails with a reasonable error' do
- knife('delete /acls/containers/environments.json').should_fail "ERROR: /acls/containers/environments.json (remote) cannot be deleted.\n"
+ it "knife delete /acls/containers/environments.json fails with a reasonable error" do
+ knife("delete /acls/containers/environments.json").should_fail "ERROR: /acls/containers/environments.json (remote) ACLs cannot be deleted.\n"
end
- it 'knife delete /containers/x.json succeeds' do
- knife('delete /containers/x.json').should_succeed "Deleted /containers/x.json\n"
- knife('raw /containers/x.json').should_fail(/404/)
+ it "knife delete /containers/x.json succeeds" do
+ knife("delete /containers/x.json").should_succeed "Deleted /containers/x.json\n"
+ knife("raw /containers/x.json").should_fail(/404/)
end
- it 'knife delete /groups/x.json succeeds' do
- knife('delete /groups/x.json').should_succeed "Deleted /groups/x.json\n"
- knife('raw /groups/x.json').should_fail(/404/)
+ it "knife delete /groups/x.json succeeds" do
+ knife("delete /groups/x.json").should_succeed "Deleted /groups/x.json\n"
+ knife("raw /groups/x.json").should_fail(/404/)
end
- it 'knife delete /org.json fails with a reasonable error' do
- knife('delete /org.json').should_fail "ERROR: /org.json (remote) cannot be deleted.\n"
+ it "knife delete /policies/x-1.2.3.json succeeds" do
+ knife("raw /policies/x/revisions/1.2.3").should_succeed "{\n \"name\": \"x\",\n \"revision_id\": \"1.2.3\",\n \"run_list\": [\n\n ],\n \"cookbook_locks\": {\n\n }\n}\n"
+ knife("delete /policies/x-1.2.3.json").should_succeed "Deleted /policies/x-1.2.3.json\n"
+ knife("raw /policies/x/revisions/1.2.3").should_fail(/404/)
end
- it 'knife delete /invitations.json fails with a reasonable error' do
- knife('delete /invitations.json').should_fail "ERROR: /invitations.json (remote) cannot be deleted.\n"
+ it "knife delete /policy_groups/x.json succeeds" do
+ knife("raw /policy_groups/x").should_succeed "{\n \"uri\": \"http://127.0.0.1:8900/organizations/foo/policy_groups/x\",\n \"policies\": {\n \"x\": {\n \"revision_id\": \"1.2.3\"\n }\n }\n}\n"
+ knife("delete /policy_groups/x.json").should_succeed "Deleted /policy_groups/x.json\n"
+ knife("raw /policy_groups/x").should_fail(/404/)
end
- it 'knife delete /members.json fails with a reasonable error' do
- knife('delete /members.json').should_fail "ERROR: /members.json (remote) cannot be deleted.\n"
+ it "knife delete /org.json fails with a reasonable error" do
+ knife("delete /org.json").should_fail "ERROR: /org.json (remote) cannot be deleted.\n"
+ end
+
+ it "knife delete /invitations.json fails with a reasonable error" do
+ knife("delete /invitations.json").should_fail "ERROR: /invitations.json (remote) cannot be deleted.\n"
+ end
+
+ it "knife delete /members.json fails with a reasonable error" do
+ knife("delete /members.json").should_fail "ERROR: /members.json (remote) cannot be deleted.\n"
end
end
end
diff --git a/spec/integration/knife/deps_spec.rb b/spec/integration/knife/deps_spec.rb
index b7333cefda..292bce6002 100644
--- a/spec/integration/knife/deps_spec.rb
+++ b/spec/integration/knife/deps_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,33 +15,33 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'support/shared/context/config'
-require 'chef/knife/deps'
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/deps"
-describe 'knife deps', :workstation do
+describe "knife deps", :workstation do
include IntegrationSupport
include KnifeSupport
- context 'local' do
- when_the_repository 'has a role with no run_list' do
- before { file 'roles/starring.json', {} }
- it 'knife deps reports no dependencies' do
- knife('deps /roles/starring.json').should_succeed "/roles/starring.json\n"
+ context "local" do
+ when_the_repository "has a role with no run_list" do
+ before { file "roles/starring.json", {} }
+ it "knife deps reports no dependencies" do
+ knife("deps /roles/starring.json").should_succeed "/roles/starring.json\n"
end
end
- when_the_repository 'has a role with a default run_list' do
+ when_the_repository "has a role with a default run_list" do
before do
- file 'roles/starring.json', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) }
- file 'roles/minor.json', {}
- file 'cookbooks/quiche/metadata.rb', 'name "quiche"'
- file 'cookbooks/quiche/recipes/default.rb', ''
- file 'cookbooks/soup/metadata.rb', 'name "soup"'
- file 'cookbooks/soup/recipes/chicken.rb', ''
- end
- it 'knife deps reports all dependencies' do
- knife('deps /roles/starring.json').should_succeed <<EOM
+ file "roles/starring.json", { "run_list" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} }
+ file "roles/minor.json", {}
+ file "cookbooks/quiche/metadata.rb", 'name "quiche"'
+ file "cookbooks/quiche/recipes/default.rb", ""
+ file "cookbooks/soup/metadata.rb", 'name "soup"'
+ file "cookbooks/soup/recipes/chicken.rb", ""
+ end
+ it "knife deps reports all dependencies" do
+ knife("deps /roles/starring.json").should_succeed <<EOM
/roles/minor.json
/cookbooks/quiche
/cookbooks/soup
@@ -50,17 +50,17 @@ EOM
end
end
- when_the_repository 'has a role with an env_run_list' do
+ when_the_repository "has a role with an env_run_list" do
before do
- file 'roles/starring.json', { 'env_run_lists' => { 'desert' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) } }
- file 'roles/minor.json', {}
- file 'cookbooks/quiche/metadata.rb', 'name "quiche"'
- file 'cookbooks/quiche/recipes/default.rb', ''
- file 'cookbooks/soup/metadata.rb', 'name "soup"'
- file 'cookbooks/soup/recipes/chicken.rb', ''
- end
- it 'knife deps reports all dependencies' do
- knife('deps /roles/starring.json').should_succeed <<EOM
+ file "roles/starring.json", { "env_run_lists" => { "desert" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} } }
+ file "roles/minor.json", {}
+ file "cookbooks/quiche/metadata.rb", 'name "quiche"'
+ file "cookbooks/quiche/recipes/default.rb", ""
+ file "cookbooks/soup/metadata.rb", 'name "soup"'
+ file "cookbooks/soup/recipes/chicken.rb", ""
+ end
+ it "knife deps reports all dependencies" do
+ knife("deps /roles/starring.json").should_succeed <<EOM
/roles/minor.json
/cookbooks/quiche
/cookbooks/soup
@@ -69,32 +69,32 @@ EOM
end
end
- when_the_repository 'has a node with no environment or run_list' do
- before { file 'nodes/mort.json', {} }
- it 'knife deps reports just the node' do
- knife('deps /nodes/mort.json').should_succeed "/nodes/mort.json\n"
+ when_the_repository "has a node with no environment or run_list" do
+ before { file "nodes/mort.json", {} }
+ it "knife deps reports just the node" do
+ knife("deps /nodes/mort.json").should_succeed "/nodes/mort.json\n"
end
end
- when_the_repository 'has a node with an environment' do
+ when_the_repository "has a node with an environment" do
before do
- file 'environments/desert.json', {}
- file 'nodes/mort.json', { 'chef_environment' => 'desert' }
+ file "environments/desert.json", {}
+ file "nodes/mort.json", { "chef_environment" => "desert" }
end
- it 'knife deps reports just the node' do
- knife('deps /nodes/mort.json').should_succeed "/environments/desert.json\n/nodes/mort.json\n"
+ it "knife deps reports just the node" do
+ knife("deps /nodes/mort.json").should_succeed "/environments/desert.json\n/nodes/mort.json\n"
end
end
- when_the_repository 'has a node with roles and recipes in its run_list' do
+ when_the_repository "has a node with roles and recipes in its run_list" do
before do
- file 'roles/minor.json', {}
- file 'cookbooks/quiche/metadata.rb', 'name "quiche"'
- file 'cookbooks/quiche/recipes/default.rb', ''
- file 'cookbooks/soup/metadata.rb', 'name "soup"'
- file 'cookbooks/soup/recipes/chicken.rb', ''
- file 'nodes/mort.json', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) }
- end
- it 'knife deps reports just the node' do
- knife('deps /nodes/mort.json').should_succeed <<EOM
+ file "roles/minor.json", {}
+ file "cookbooks/quiche/metadata.rb", 'name "quiche"'
+ file "cookbooks/quiche/recipes/default.rb", ""
+ file "cookbooks/soup/metadata.rb", 'name "soup"'
+ file "cookbooks/soup/recipes/chicken.rb", ""
+ file "nodes/mort.json", { "run_list" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} }
+ end
+ it "knife deps reports just the node" do
+ knife("deps /nodes/mort.json").should_succeed <<EOM
/roles/minor.json
/cookbooks/quiche
/cookbooks/soup
@@ -102,53 +102,53 @@ EOM
EOM
end
end
- when_the_repository 'has a cookbook with no dependencies' do
+ when_the_repository "has a cookbook with no dependencies" do
before do
- file 'cookbooks/quiche/metadata.rb', 'name "quiche"'
- file 'cookbooks/quiche/recipes/default.rb', ''
+ file "cookbooks/quiche/metadata.rb", 'name "quiche"'
+ file "cookbooks/quiche/recipes/default.rb", ""
end
- it 'knife deps reports just the cookbook' do
- knife('deps /cookbooks/quiche').should_succeed "/cookbooks/quiche\n"
+ it "knife deps reports just the cookbook" do
+ knife("deps /cookbooks/quiche").should_succeed "/cookbooks/quiche\n"
end
end
- when_the_repository 'has a cookbook with dependencies' do
+ when_the_repository "has a cookbook with dependencies" do
before do
- file 'cookbooks/kettle/metadata.rb', 'name "kettle"'
- file 'cookbooks/quiche/metadata.rb', 'name "quiche"
+ file "cookbooks/kettle/metadata.rb", 'name "kettle"'
+ file "cookbooks/quiche/metadata.rb", 'name "quiche"
depends "kettle"'
- file 'cookbooks/quiche/recipes/default.rb', ''
+ file "cookbooks/quiche/recipes/default.rb", ""
end
- it 'knife deps reports just the cookbook' do
- knife('deps /cookbooks/quiche').should_succeed "/cookbooks/kettle\n/cookbooks/quiche\n"
+ it "knife deps reports just the cookbook" do
+ knife("deps /cookbooks/quiche").should_succeed "/cookbooks/kettle\n/cookbooks/quiche\n"
end
end
- when_the_repository 'has a data bag' do
- before { file 'data_bags/bag/item.json', {} }
- it 'knife deps reports just the data bag' do
- knife('deps /data_bags/bag/item.json').should_succeed "/data_bags/bag/item.json\n"
+ when_the_repository "has a data bag" do
+ before { file "data_bags/bag/item.json", {} }
+ it "knife deps reports just the data bag" do
+ knife("deps /data_bags/bag/item.json").should_succeed "/data_bags/bag/item.json\n"
end
end
- when_the_repository 'has an environment' do
- before { file 'environments/desert.json', {} }
- it 'knife deps reports just the environment' do
- knife('deps /environments/desert.json').should_succeed "/environments/desert.json\n"
+ when_the_repository "has an environment" do
+ before { file "environments/desert.json", {} }
+ it "knife deps reports just the environment" do
+ knife("deps /environments/desert.json").should_succeed "/environments/desert.json\n"
end
end
- when_the_repository 'has a deep dependency tree' do
+ when_the_repository "has a deep dependency tree" do
before do
- file 'roles/starring.json', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) }
- file 'roles/minor.json', {}
- file 'cookbooks/quiche/metadata.rb', 'name "quiche"'
- file 'cookbooks/quiche/recipes/default.rb', ''
- file 'cookbooks/soup/metadata.rb', 'name "soup"'
- file 'cookbooks/soup/recipes/chicken.rb', ''
- file 'environments/desert.json', {}
- file 'nodes/mort.json', { 'chef_environment' => 'desert', 'run_list' => [ 'role[starring]' ] }
- file 'nodes/bart.json', { 'run_list' => [ 'role[minor]' ] }
+ file "roles/starring.json", { "run_list" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} }
+ file "roles/minor.json", {}
+ file "cookbooks/quiche/metadata.rb", 'name "quiche"'
+ file "cookbooks/quiche/recipes/default.rb", ""
+ file "cookbooks/soup/metadata.rb", 'name "soup"'
+ file "cookbooks/soup/recipes/chicken.rb", ""
+ file "environments/desert.json", {}
+ file "nodes/mort.json", { "chef_environment" => "desert", "run_list" => [ "role[starring]" ] }
+ file "nodes/bart.json", { "run_list" => [ "role[minor]" ] }
end
- it 'knife deps reports all dependencies' do
- knife('deps /nodes/mort.json').should_succeed <<EOM
+ it "knife deps reports all dependencies" do
+ knife("deps /nodes/mort.json").should_succeed <<EOM
/environments/desert.json
/roles/minor.json
/cookbooks/quiche
@@ -157,8 +157,8 @@ depends "kettle"'
/nodes/mort.json
EOM
end
- it 'knife deps * reports all dependencies of all things' do
- knife('deps /nodes/*').should_succeed <<EOM
+ it "knife deps * reports all dependencies of all things" do
+ knife("deps /nodes/*").should_succeed <<EOM
/roles/minor.json
/nodes/bart.json
/environments/desert.json
@@ -168,8 +168,8 @@ EOM
/nodes/mort.json
EOM
end
- it 'knife deps a b reports all dependencies of a and b' do
- knife('deps /nodes/bart.json /nodes/mort.json').should_succeed <<EOM
+ it "knife deps a b reports all dependencies of a and b" do
+ knife("deps /nodes/bart.json /nodes/mort.json").should_succeed <<EOM
/roles/minor.json
/nodes/bart.json
/environments/desert.json
@@ -179,8 +179,8 @@ EOM
/nodes/mort.json
EOM
end
- it 'knife deps --tree /* shows dependencies in a tree' do
- knife('deps --tree /nodes/*').should_succeed <<EOM
+ it "knife deps --tree /* shows dependencies in a tree" do
+ knife("deps --tree /nodes/*").should_succeed <<EOM
/nodes/bart.json
/roles/minor.json
/nodes/mort.json
@@ -191,8 +191,8 @@ EOM
/cookbooks/soup
EOM
end
- it 'knife deps --tree --no-recurse shows only the first level of dependencies' do
- knife('deps --tree --no-recurse /nodes/*').should_succeed <<EOM
+ it "knife deps --tree --no-recurse shows only the first level of dependencies" do
+ knife("deps --tree --no-recurse /nodes/*").should_succeed <<EOM
/nodes/bart.json
/roles/minor.json
/nodes/mort.json
@@ -202,49 +202,49 @@ EOM
end
end
- context 'circular dependencies' do
- when_the_repository 'has cookbooks with circular dependencies' do
+ context "circular dependencies" do
+ when_the_repository "has cookbooks with circular dependencies" do
before do
- file 'cookbooks/foo/metadata.rb', 'name "foo"
+ file "cookbooks/foo/metadata.rb", 'name "foo"
depends "bar"'
- file 'cookbooks/bar/metadata.rb', 'name "bar"
+ file "cookbooks/bar/metadata.rb", 'name "bar"
depends "baz"'
- file 'cookbooks/baz/metadata.rb', 'name "baz"
+ file "cookbooks/baz/metadata.rb", 'name "baz"
depends "foo"'
- file 'cookbooks/self/metadata.rb', 'name "self"
+ file "cookbooks/self/metadata.rb", 'name "self"
depends "self"'
end
- it 'knife deps prints each once' do
- knife('deps /cookbooks/foo /cookbooks/self').should_succeed(
+ it "knife deps prints each once" do
+ knife("deps /cookbooks/foo /cookbooks/self").should_succeed(
stdout: "/cookbooks/baz\n/cookbooks/bar\n/cookbooks/foo\n/cookbooks/self\n",
stderr: "WARN: Ignoring self-dependency in cookbook self, please remove it (in the future this will be fatal).\n"
)
end
- it 'knife deps --tree prints each once' do
- knife('deps --tree /cookbooks/foo /cookbooks/self').should_succeed(
+ it "knife deps --tree prints each once" do
+ knife("deps --tree /cookbooks/foo /cookbooks/self").should_succeed(
stdout: "/cookbooks/foo\n /cookbooks/bar\n /cookbooks/baz\n /cookbooks/foo\n/cookbooks/self\n",
stderr: "WARN: Ignoring self-dependency in cookbook self, please remove it (in the future this will be fatal).\n"
)
end
end
- when_the_repository 'has roles with circular dependencies' do
+ when_the_repository "has roles with circular dependencies" do
before do
- file 'roles/foo.json', { 'run_list' => [ 'role[bar]' ] }
- file 'roles/bar.json', { 'run_list' => [ 'role[baz]' ] }
- file 'roles/baz.json', { 'run_list' => [ 'role[foo]' ] }
- file 'roles/self.json', { 'run_list' => [ 'role[self]' ] }
+ file "roles/foo.json", { "run_list" => [ "role[bar]" ] }
+ file "roles/bar.json", { "run_list" => [ "role[baz]" ] }
+ file "roles/baz.json", { "run_list" => [ "role[foo]" ] }
+ file "roles/self.json", { "run_list" => [ "role[self]" ] }
end
- it 'knife deps prints each once' do
- knife('deps /roles/foo.json /roles/self.json').should_succeed <<EOM
+ it "knife deps prints each once" do
+ knife("deps /roles/foo.json /roles/self.json").should_succeed <<EOM
/roles/baz.json
/roles/bar.json
/roles/foo.json
/roles/self.json
EOM
end
- it 'knife deps --tree prints each once' do
- knife('deps --tree /roles/foo.json /roles/self.json') do
+ it "knife deps --tree prints each once" do
+ knife("deps --tree /roles/foo.json /roles/self.json") do
expect(stdout).to eq("/roles/foo.json\n /roles/bar.json\n /roles/baz.json\n /roles/foo.json\n/roles/self.json\n /roles/self.json\n")
expect(stderr).to eq("WARNING: No knife configuration file found\n")
end
@@ -252,81 +252,81 @@ EOM
end
end
- context 'missing objects' do
- when_the_repository 'is empty' do
- it 'knife deps /blah reports an error' do
- knife('deps /blah').should_fail(
+ context "missing objects" do
+ when_the_repository "is empty" do
+ it "knife deps /blah reports an error" do
+ knife("deps /blah").should_fail(
:exit_code => 2,
:stdout => "/blah\n",
:stderr => "ERROR: /blah: No such file or directory\n"
)
end
- it 'knife deps /roles/x.json reports an error' do
- knife('deps /roles/x.json').should_fail(
+ it "knife deps /roles/x.json reports an error" do
+ knife("deps /roles/x.json").should_fail(
:exit_code => 2,
:stdout => "/roles/x.json\n",
:stderr => "ERROR: /roles/x.json: No such file or directory\n"
)
end
- it 'knife deps /nodes/x.json reports an error' do
- knife('deps /nodes/x.json').should_fail(
+ it "knife deps /nodes/x.json reports an error" do
+ knife("deps /nodes/x.json").should_fail(
:exit_code => 2,
:stdout => "/nodes/x.json\n",
:stderr => "ERROR: /nodes/x.json: No such file or directory\n"
)
end
- it 'knife deps /environments/x.json reports an error' do
- knife('deps /environments/x.json').should_fail(
+ it "knife deps /environments/x.json reports an error" do
+ knife("deps /environments/x.json").should_fail(
:exit_code => 2,
:stdout => "/environments/x.json\n",
:stderr => "ERROR: /environments/x.json: No such file or directory\n"
)
end
- it 'knife deps /cookbooks/x reports an error' do
- knife('deps /cookbooks/x').should_fail(
+ it "knife deps /cookbooks/x reports an error" do
+ knife("deps /cookbooks/x").should_fail(
:exit_code => 2,
:stdout => "/cookbooks/x\n",
:stderr => "ERROR: /cookbooks/x: No such file or directory\n"
)
end
- it 'knife deps /data_bags/bag/item reports an error' do
- knife('deps /data_bags/bag/item').should_fail(
+ it "knife deps /data_bags/bag/item.json reports an error" do
+ knife("deps /data_bags/bag/item.json").should_fail(
:exit_code => 2,
- :stdout => "/data_bags/bag/item\n",
- :stderr => "ERROR: /data_bags/bag/item: No such file or directory\n"
+ :stdout => "/data_bags/bag/item.json\n",
+ :stderr => "ERROR: /data_bags/bag/item.json: No such file or directory\n"
)
end
end
- when_the_repository 'is missing a dependent cookbook' do
+ when_the_repository "is missing a dependent cookbook" do
before do
- file 'roles/starring.json', { 'run_list' => [ 'recipe[quiche]'] }
+ file "roles/starring.json", { "run_list" => [ "recipe[quiche]"] }
end
- it 'knife deps reports the cookbook, along with an error' do
- knife('deps /roles/starring.json').should_fail(
+ it "knife deps reports the cookbook, along with an error" do
+ knife("deps /roles/starring.json").should_fail(
:exit_code => 2,
:stdout => "/cookbooks/quiche\n/roles/starring.json\n",
:stderr => "ERROR: /cookbooks/quiche: No such file or directory\n"
)
end
end
- when_the_repository 'is missing a dependent environment' do
+ when_the_repository "is missing a dependent environment" do
before do
- file 'nodes/mort.json', { 'chef_environment' => 'desert' }
+ file "nodes/mort.json", { "chef_environment" => "desert" }
end
- it 'knife deps reports the environment, along with an error' do
- knife('deps /nodes/mort.json').should_fail(
+ it "knife deps reports the environment, along with an error" do
+ knife("deps /nodes/mort.json").should_fail(
:exit_code => 2,
:stdout => "/environments/desert.json\n/nodes/mort.json\n",
:stderr => "ERROR: /environments/desert.json: No such file or directory\n"
)
end
end
- when_the_repository 'is missing a dependent role' do
+ when_the_repository "is missing a dependent role" do
before do
- file 'roles/starring.json', { 'run_list' => [ 'role[minor]'] }
+ file "roles/starring.json", { "run_list" => [ "role[minor]"] }
end
- it 'knife deps reports the role, along with an error' do
- knife('deps /roles/starring.json').should_fail(
+ it "knife deps reports the role, along with an error" do
+ knife("deps /roles/starring.json").should_fail(
:exit_code => 2,
:stdout => "/roles/minor.json\n/roles/starring.json\n",
:stderr => "ERROR: /roles/minor.json: No such file or directory\n"
@@ -334,29 +334,29 @@ EOM
end
end
end
- context 'invalid objects' do
- when_the_repository 'is empty' do
- it 'knife deps / reports itself only' do
- knife('deps /').should_succeed("/\n")
+ context "invalid objects" do
+ when_the_repository "is empty" do
+ it "knife deps / reports itself only" do
+ knife("deps /").should_succeed("/\n")
end
- it 'knife deps /roles reports an error' do
- knife('deps /roles').should_fail(
+ it "knife deps /roles reports an error" do
+ knife("deps /roles").should_fail(
:exit_code => 2,
:stderr => "ERROR: /roles: No such file or directory\n",
:stdout => "/roles\n"
)
end
end
- when_the_repository 'has a data bag' do
- before { file 'data_bags/bag/item.json', '' }
- it 'knife deps /data_bags/bag shows no dependencies' do
- knife('deps /data_bags/bag').should_succeed("/data_bags/bag\n")
+ when_the_repository "has a data bag" do
+ before { file "data_bags/bag/item.json", "" }
+ it "knife deps /data_bags/bag shows no dependencies" do
+ knife("deps /data_bags/bag").should_succeed("/data_bags/bag\n")
end
end
- when_the_repository 'has a cookbook' do
- before { file 'cookbooks/blah/metadata.rb', 'name "blah"' }
- it 'knife deps on a cookbook file shows no dependencies' do
- knife('deps /cookbooks/blah/metadata.rb').should_succeed(
+ when_the_repository "has a cookbook" do
+ before { file "cookbooks/blah/metadata.rb", 'name "blah"' }
+ it "knife deps on a cookbook file shows no dependencies" do
+ knife("deps /cookbooks/blah/metadata.rb").should_succeed(
"/cookbooks/blah/metadata.rb\n"
)
end
@@ -364,25 +364,25 @@ EOM
end
end
- context 'remote' do
+ context "remote" do
include_context "default config options"
- when_the_chef_server 'has a role with no run_list' do
- before { role 'starring', {} }
- it 'knife deps reports no dependencies' do
- knife('deps --remote /roles/starring.json').should_succeed "/roles/starring.json\n"
+ when_the_chef_server "has a role with no run_list" do
+ before { role "starring", {} }
+ it "knife deps reports no dependencies" do
+ knife("deps --remote /roles/starring.json").should_succeed "/roles/starring.json\n"
end
end
- when_the_chef_server 'has a role with a default run_list' do
+ when_the_chef_server "has a role with a default run_list" do
before do
- role 'starring', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) }
- role 'minor', {}
- cookbook 'quiche', '1.0.0', { 'metadata.rb' => %Q{name "quiche"\nversion "1.0.0"\n}, 'recipes' => { 'default.rb' => '' } }
- cookbook 'soup', '1.0.0', { 'metadata.rb' => %Q{name "soup"\nversion "1.0.0"\n}, 'recipes' => { 'chicken.rb' => '' } }
+ role "starring", { "run_list" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} }
+ role "minor", {}
+ cookbook "quiche", "1.0.0", { "metadata.rb" => %Q{name "quiche"\nversion "1.0.0"\n}, "recipes" => { "default.rb" => "" } }
+ cookbook "soup", "1.0.0", { "metadata.rb" => %Q{name "soup"\nversion "1.0.0"\n}, "recipes" => { "chicken.rb" => "" } }
end
- it 'knife deps reports all dependencies' do
- knife('deps --remote /roles/starring.json').should_succeed <<EOM
+ it "knife deps reports all dependencies" do
+ knife("deps --remote /roles/starring.json").should_succeed <<EOM
/roles/minor.json
/cookbooks/quiche
/cookbooks/soup
@@ -391,15 +391,15 @@ EOM
end
end
- when_the_chef_server 'has a role with an env_run_list' do
+ when_the_chef_server "has a role with an env_run_list" do
before do
- role 'starring', { 'env_run_lists' => { 'desert' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) } }
- role 'minor', {}
- cookbook 'quiche', '1.0.0', { 'metadata.rb' => %Q{name "quiche"\nversion "1.0.0"\n}, 'recipes' => { 'default.rb' => '' } }
- cookbook 'soup', '1.0.0', { 'metadata.rb' => %Q{name "soup"\nversion "1.0.0"\n}, 'recipes' => { 'chicken.rb' => '' } }
+ role "starring", { "env_run_lists" => { "desert" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} } }
+ role "minor", {}
+ cookbook "quiche", "1.0.0", { "metadata.rb" => %Q{name "quiche"\nversion "1.0.0"\n}, "recipes" => { "default.rb" => "" } }
+ cookbook "soup", "1.0.0", { "metadata.rb" => %Q{name "soup"\nversion "1.0.0"\n}, "recipes" => { "chicken.rb" => "" } }
end
- it 'knife deps reports all dependencies' do
- knife('deps --remote /roles/starring.json').should_succeed <<EOM
+ it "knife deps reports all dependencies" do
+ knife("deps --remote /roles/starring.json").should_succeed <<EOM
/roles/minor.json
/cookbooks/quiche
/cookbooks/soup
@@ -408,30 +408,30 @@ EOM
end
end
- when_the_chef_server 'has a node with no environment or run_list' do
- before { node 'mort', {} }
- it 'knife deps reports just the node' do
- knife('deps --remote /nodes/mort.json').should_succeed "/nodes/mort.json\n"
+ when_the_chef_server "has a node with no environment or run_list" do
+ before { node "mort", {} }
+ it "knife deps reports just the node" do
+ knife("deps --remote /nodes/mort.json").should_succeed "/nodes/mort.json\n"
end
end
- when_the_chef_server 'has a node with an environment' do
+ when_the_chef_server "has a node with an environment" do
before do
- environment 'desert', {}
- node 'mort', { 'chef_environment' => 'desert' }
+ environment "desert", {}
+ node "mort", { "chef_environment" => "desert" }
end
- it 'knife deps reports just the node' do
- knife('deps --remote /nodes/mort.json').should_succeed "/environments/desert.json\n/nodes/mort.json\n"
+ it "knife deps reports just the node" do
+ knife("deps --remote /nodes/mort.json").should_succeed "/environments/desert.json\n/nodes/mort.json\n"
end
end
- when_the_chef_server 'has a node with roles and recipes in its run_list' do
+ when_the_chef_server "has a node with roles and recipes in its run_list" do
before do
- role 'minor', {}
- cookbook 'quiche', '1.0.0', { 'metadata.rb' => %Q{name "quiche"\nversion "1.0.0"\n}, 'recipes' => { 'default.rb' => '' } }
- cookbook 'soup', '1.0.0', { 'metadata.rb' => %Q{name "soup"\nversion "1.0.0"\n}, 'recipes' => { 'chicken.rb' => '' } }
- node 'mort', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) }
+ role "minor", {}
+ cookbook "quiche", "1.0.0", { "metadata.rb" => %Q{name "quiche"\nversion "1.0.0"\n}, "recipes" => { "default.rb" => "" } }
+ cookbook "soup", "1.0.0", { "metadata.rb" => %Q{name "soup"\nversion "1.0.0"\n}, "recipes" => { "chicken.rb" => "" } }
+ node "mort", { "run_list" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} }
end
- it 'knife deps reports just the node' do
- knife('deps --remote /nodes/mort.json').should_succeed <<EOM
+ it "knife deps reports just the node" do
+ knife("deps --remote /nodes/mort.json").should_succeed <<EOM
/roles/minor.json
/cookbooks/quiche
/cookbooks/soup
@@ -439,49 +439,49 @@ EOM
EOM
end
end
- when_the_chef_server 'has a cookbook with no dependencies' do
+ when_the_chef_server "has a cookbook with no dependencies" do
before do
- cookbook 'quiche', '1.0.0', { 'metadata.rb' => %Q{name "quiche"\nversion "1.0.0"\n}, 'recipes' => { 'default.rb' => '' } }
+ cookbook "quiche", "1.0.0", { "metadata.rb" => %Q{name "quiche"\nversion "1.0.0"\n}, "recipes" => { "default.rb" => "" } }
end
- it 'knife deps reports just the cookbook' do
- knife('deps --remote /cookbooks/quiche').should_succeed "/cookbooks/quiche\n"
+ it "knife deps reports just the cookbook" do
+ knife("deps --remote /cookbooks/quiche").should_succeed "/cookbooks/quiche\n"
end
end
- when_the_chef_server 'has a cookbook with dependencies' do
+ when_the_chef_server "has a cookbook with dependencies" do
before do
- cookbook 'kettle', '1.0.0', { 'metadata.rb' => %Q{name "kettle"\nversion "1.0.0"\n} }
- cookbook 'quiche', '1.0.0', { 'metadata.rb' => 'name "quiche"
-depends "kettle"', 'recipes' => { 'default.rb' => '' } }
+ cookbook "kettle", "1.0.0", { "metadata.rb" => %Q{name "kettle"\nversion "1.0.0"\n} }
+ cookbook "quiche", "1.0.0", { "metadata.rb" => 'name "quiche"
+depends "kettle"', "recipes" => { "default.rb" => "" } }
end
- it 'knife deps reports the cookbook and its dependencies' do
- knife('deps --remote /cookbooks/quiche').should_succeed "/cookbooks/kettle\n/cookbooks/quiche\n"
+ it "knife deps reports the cookbook and its dependencies" do
+ knife("deps --remote /cookbooks/quiche").should_succeed "/cookbooks/kettle\n/cookbooks/quiche\n"
end
end
- when_the_chef_server 'has a data bag' do
- before { data_bag 'bag', { 'item' => {} } }
- it 'knife deps reports just the data bag' do
- knife('deps --remote /data_bags/bag/item.json').should_succeed "/data_bags/bag/item.json\n"
+ when_the_chef_server "has a data bag" do
+ before { data_bag "bag", { "item" => {} } }
+ it "knife deps reports just the data bag" do
+ knife("deps --remote /data_bags/bag/item.json").should_succeed "/data_bags/bag/item.json\n"
end
end
- when_the_chef_server 'has an environment' do
- before { environment 'desert', {} }
- it 'knife deps reports just the environment' do
- knife('deps --remote /environments/desert.json').should_succeed "/environments/desert.json\n"
+ when_the_chef_server "has an environment" do
+ before { environment "desert", {} }
+ it "knife deps reports just the environment" do
+ knife("deps --remote /environments/desert.json").should_succeed "/environments/desert.json\n"
end
end
- when_the_chef_server 'has a deep dependency tree' do
+ when_the_chef_server "has a deep dependency tree" do
before do
- role 'starring', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) }
- role 'minor', {}
- cookbook 'quiche', '1.0.0', { 'metadata.rb' => %Q{name "quiche"\nversion "1.0.0"\n}, 'recipes' => { 'default.rb' => '' } }
- cookbook 'soup', '1.0.0', { 'metadata.rb' => %Q{name "soup"\nversion "1.0.0"\n}, 'recipes' => { 'chicken.rb' => '' } }
- environment 'desert', {}
- node 'mort', { 'chef_environment' => 'desert', 'run_list' => [ 'role[starring]' ] }
- node 'bart', { 'run_list' => [ 'role[minor]' ] }
+ role "starring", { "run_list" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} }
+ role "minor", {}
+ cookbook "quiche", "1.0.0", { "metadata.rb" => %Q{name "quiche"\nversion "1.0.0"\n}, "recipes" => { "default.rb" => "" } }
+ cookbook "soup", "1.0.0", { "metadata.rb" => %Q{name "soup"\nversion "1.0.0"\n}, "recipes" => { "chicken.rb" => "" } }
+ environment "desert", {}
+ node "mort", { "chef_environment" => "desert", "run_list" => [ "role[starring]" ] }
+ node "bart", { "run_list" => [ "role[minor]" ] }
end
- it 'knife deps reports all dependencies' do
- knife('deps --remote /nodes/mort.json').should_succeed <<EOM
+ it "knife deps reports all dependencies" do
+ knife("deps --remote /nodes/mort.json").should_succeed <<EOM
/environments/desert.json
/roles/minor.json
/cookbooks/quiche
@@ -490,8 +490,8 @@ depends "kettle"', 'recipes' => { 'default.rb' => '' } }
/nodes/mort.json
EOM
end
- it 'knife deps * reports all dependencies of all things' do
- knife('deps --remote /nodes/*').should_succeed <<EOM
+ it "knife deps * reports all dependencies of all things" do
+ knife("deps --remote /nodes/*").should_succeed <<EOM
/roles/minor.json
/nodes/bart.json
/environments/desert.json
@@ -501,8 +501,8 @@ EOM
/nodes/mort.json
EOM
end
- it 'knife deps a b reports all dependencies of a and b' do
- knife('deps --remote /nodes/bart.json /nodes/mort.json').should_succeed <<EOM
+ it "knife deps a b reports all dependencies of a and b" do
+ knife("deps --remote /nodes/bart.json /nodes/mort.json").should_succeed <<EOM
/roles/minor.json
/nodes/bart.json
/environments/desert.json
@@ -512,8 +512,8 @@ EOM
/nodes/mort.json
EOM
end
- it 'knife deps --tree /* shows dependencies in a tree' do
- knife('deps --remote --tree /nodes/*').should_succeed <<EOM
+ it "knife deps --tree /* shows dependencies in a tree" do
+ knife("deps --remote --tree /nodes/*").should_succeed <<EOM
/nodes/bart.json
/roles/minor.json
/nodes/mort.json
@@ -524,8 +524,8 @@ EOM
/cookbooks/soup
EOM
end
- it 'knife deps --tree --no-recurse shows only the first level of dependencies' do
- knife('deps --remote --tree --no-recurse /nodes/*').should_succeed <<EOM
+ it "knife deps --tree --no-recurse shows only the first level of dependencies" do
+ knife("deps --remote --tree --no-recurse /nodes/*").should_succeed <<EOM
/nodes/bart.json
/roles/minor.json
/nodes/mort.json
@@ -535,28 +535,28 @@ EOM
end
end
- context 'circular dependencies' do
- when_the_chef_server 'has cookbooks with circular dependencies' do
+ context "circular dependencies" do
+ when_the_chef_server "has cookbooks with circular dependencies" do
before do
- cookbook 'foo', '1.0.0', { 'metadata.rb' => 'name "foo"
+ cookbook "foo", "1.0.0", { "metadata.rb" => 'name "foo"
depends "bar"' }
- cookbook 'bar', '1.0.0', { 'metadata.rb' => 'name "bar"
+ cookbook "bar", "1.0.0", { "metadata.rb" => 'name "bar"
depends "baz"' }
- cookbook 'baz', '1.0.0', { 'metadata.rb' => 'name "baz"
+ cookbook "baz", "1.0.0", { "metadata.rb" => 'name "baz"
depends "foo"' }
- cookbook 'self', '1.0.0', { 'metadata.rb' => 'name "self"
+ cookbook "self", "1.0.0", { "metadata.rb" => 'name "self"
depends "self"' }
end
- it 'knife deps prints each once' do
- knife('deps --remote /cookbooks/foo /cookbooks/self').should_succeed <<EOM
+ it "knife deps prints each once" do
+ knife("deps --remote /cookbooks/foo /cookbooks/self").should_succeed <<EOM
/cookbooks/baz
/cookbooks/bar
/cookbooks/foo
/cookbooks/self
EOM
end
- it 'knife deps --tree prints each once' do
- knife('deps --remote --tree /cookbooks/foo /cookbooks/self').should_succeed <<EOM
+ it "knife deps --tree prints each once" do
+ knife("deps --remote --tree /cookbooks/foo /cookbooks/self").should_succeed <<EOM
/cookbooks/foo
/cookbooks/bar
/cookbooks/baz
@@ -566,23 +566,23 @@ EOM
EOM
end
end
- when_the_chef_server 'has roles with circular dependencies' do
+ when_the_chef_server "has roles with circular dependencies" do
before do
- role 'foo', { 'run_list' => [ 'role[bar]' ] }
- role 'bar', { 'run_list' => [ 'role[baz]' ] }
- role 'baz', { 'run_list' => [ 'role[foo]' ] }
- role 'self', { 'run_list' => [ 'role[self]' ] }
+ role "foo", { "run_list" => [ "role[bar]" ] }
+ role "bar", { "run_list" => [ "role[baz]" ] }
+ role "baz", { "run_list" => [ "role[foo]" ] }
+ role "self", { "run_list" => [ "role[self]" ] }
end
- it 'knife deps prints each once' do
- knife('deps --remote /roles/foo.json /roles/self.json').should_succeed <<EOM
+ it "knife deps prints each once" do
+ knife("deps --remote /roles/foo.json /roles/self.json").should_succeed <<EOM
/roles/baz.json
/roles/bar.json
/roles/foo.json
/roles/self.json
EOM
end
- it 'knife deps --tree prints each once' do
- knife('deps --remote --tree /roles/foo.json /roles/self.json') do
+ it "knife deps --tree prints each once" do
+ knife("deps --remote --tree /roles/foo.json /roles/self.json") do
expect(stdout).to eq("/roles/foo.json\n /roles/bar.json\n /roles/baz.json\n /roles/foo.json\n/roles/self.json\n /roles/self.json\n")
expect(stderr).to eq("WARNING: No knife configuration file found\n")
end
@@ -590,81 +590,81 @@ EOM
end
end
- context 'missing objects' do
- when_the_chef_server 'is empty' do
- it 'knife deps /blah reports an error' do
- knife('deps --remote /blah').should_fail(
+ context "missing objects" do
+ when_the_chef_server "is empty" do
+ it "knife deps /blah reports an error" do
+ knife("deps --remote /blah").should_fail(
:exit_code => 2,
:stdout => "/blah\n",
:stderr => "ERROR: /blah: No such file or directory\n"
)
end
- it 'knife deps /roles/x.json reports an error' do
- knife('deps --remote /roles/x.json').should_fail(
+ it "knife deps /roles/x.json reports an error" do
+ knife("deps --remote /roles/x.json").should_fail(
:exit_code => 2,
:stdout => "/roles/x.json\n",
:stderr => "ERROR: /roles/x.json: No such file or directory\n"
)
end
- it 'knife deps /nodes/x.json reports an error' do
- knife('deps --remote /nodes/x.json').should_fail(
+ it "knife deps /nodes/x.json reports an error" do
+ knife("deps --remote /nodes/x.json").should_fail(
:exit_code => 2,
:stdout => "/nodes/x.json\n",
:stderr => "ERROR: /nodes/x.json: No such file or directory\n"
)
end
- it 'knife deps /environments/x.json reports an error' do
- knife('deps --remote /environments/x.json').should_fail(
+ it "knife deps /environments/x.json reports an error" do
+ knife("deps --remote /environments/x.json").should_fail(
:exit_code => 2,
:stdout => "/environments/x.json\n",
:stderr => "ERROR: /environments/x.json: No such file or directory\n"
)
end
- it 'knife deps /cookbooks/x reports an error' do
- knife('deps --remote /cookbooks/x').should_fail(
+ it "knife deps /cookbooks/x reports an error" do
+ knife("deps --remote /cookbooks/x").should_fail(
:exit_code => 2,
:stdout => "/cookbooks/x\n",
:stderr => "ERROR: /cookbooks/x: No such file or directory\n"
)
end
- it 'knife deps /data_bags/bag/item reports an error' do
- knife('deps --remote /data_bags/bag/item').should_fail(
+ it "knife deps /data_bags/bag/item reports an error" do
+ knife("deps --remote /data_bags/bag/item.json").should_fail(
:exit_code => 2,
- :stdout => "/data_bags/bag/item\n",
- :stderr => "ERROR: /data_bags/bag/item: No such file or directory\n"
+ :stdout => "/data_bags/bag/item.json\n",
+ :stderr => "ERROR: /data_bags/bag/item.json: No such file or directory\n"
)
end
end
- when_the_chef_server 'is missing a dependent cookbook' do
+ when_the_chef_server "is missing a dependent cookbook" do
before do
- role 'starring', { 'run_list' => [ 'recipe[quiche]'] }
+ role "starring", { "run_list" => [ "recipe[quiche]"] }
end
- it 'knife deps reports the cookbook, along with an error' do
- knife('deps --remote /roles/starring.json').should_fail(
+ it "knife deps reports the cookbook, along with an error" do
+ knife("deps --remote /roles/starring.json").should_fail(
:exit_code => 2,
:stdout => "/cookbooks/quiche\n/roles/starring.json\n",
:stderr => "ERROR: /cookbooks/quiche: No such file or directory\n"
)
end
end
- when_the_chef_server 'is missing a dependent environment' do
+ when_the_chef_server "is missing a dependent environment" do
before do
- node 'mort', { 'chef_environment' => 'desert' }
+ node "mort", { "chef_environment" => "desert" }
end
- it 'knife deps reports the environment, along with an error' do
- knife('deps --remote /nodes/mort.json').should_fail(
+ it "knife deps reports the environment, along with an error" do
+ knife("deps --remote /nodes/mort.json").should_fail(
:exit_code => 2,
:stdout => "/environments/desert.json\n/nodes/mort.json\n",
:stderr => "ERROR: /environments/desert.json: No such file or directory\n"
)
end
end
- when_the_chef_server 'is missing a dependent role' do
+ when_the_chef_server "is missing a dependent role" do
before do
- role 'starring', { 'run_list' => [ 'role[minor]'] }
+ role "starring", { "run_list" => [ "role[minor]"] }
end
- it 'knife deps reports the role, along with an error' do
- knife('deps --remote /roles/starring.json').should_fail(
+ it "knife deps reports the role, along with an error" do
+ knife("deps --remote /roles/starring.json").should_fail(
:exit_code => 2,
:stdout => "/roles/minor.json\n/roles/starring.json\n",
:stderr => "ERROR: /roles/minor.json: No such file or directory\n"
@@ -672,27 +672,27 @@ EOM
end
end
end
- context 'invalid objects' do
- when_the_chef_server 'is empty' do
- it 'knife deps / reports an error' do
- knife('deps --remote /').should_succeed("/\n")
+ context "invalid objects" do
+ when_the_chef_server "is empty" do
+ it "knife deps / reports an error" do
+ knife("deps --remote /").should_succeed("/\n")
end
- it 'knife deps /roles reports an error' do
- knife('deps --remote /roles').should_succeed("/roles\n")
+ it "knife deps /roles reports an error" do
+ knife("deps --remote /roles").should_succeed("/roles\n")
end
end
- when_the_chef_server 'has a data bag' do
- before { data_bag 'bag', { 'item' => {} } }
- it 'knife deps /data_bags/bag shows no dependencies' do
- knife('deps --remote /data_bags/bag').should_succeed("/data_bags/bag\n")
+ when_the_chef_server "has a data bag" do
+ before { data_bag "bag", { "item" => {} } }
+ it "knife deps /data_bags/bag shows no dependencies" do
+ knife("deps --remote /data_bags/bag").should_succeed("/data_bags/bag\n")
end
end
- when_the_chef_server 'has a cookbook' do
+ when_the_chef_server "has a cookbook" do
before do
- cookbook 'blah', '1.0.0', { 'metadata.rb' => 'name "blah"' }
+ cookbook "blah", "1.0.0", { "metadata.rb" => 'name "blah"' }
end
- it 'knife deps on a cookbook file shows no dependencies' do
- knife('deps --remote /cookbooks/blah/metadata.rb').should_succeed(
+ it "knife deps on a cookbook file shows no dependencies" do
+ knife("deps --remote /cookbooks/blah/metadata.rb").should_succeed(
"/cookbooks/blah/metadata.rb\n"
)
end
@@ -700,7 +700,7 @@ EOM
end
end
- it 'knife deps --no-recurse reports an error' do
- knife('deps --no-recurse /').should_fail("ERROR: --no-recurse requires --tree\n")
+ it "knife deps --no-recurse reports an error" do
+ knife("deps --no-recurse /").should_fail("ERROR: --no-recurse requires --tree\n")
end
end
diff --git a/spec/integration/knife/diff_spec.rb b/spec/integration/knife/diff_spec.rb
index 465383437f..b3bd23f48e 100644
--- a/spec/integration/knife/diff_spec.rb
+++ b/spec/integration/knife/diff_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,38 +15,38 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/diff'
+require "support/shared/integration/integration_helper"
+require "chef/knife/diff"
-describe 'knife diff', :workstation do
+describe "knife diff", :workstation do
include IntegrationSupport
include KnifeSupport
- context 'without versioned cookbooks' do
+ context "without versioned cookbooks" do
when_the_chef_server "has one of each thing" do
before do
- client 'x', '{}'
- cookbook 'x', '1.0.0'
- data_bag 'x', { 'y' => '{}' }
- environment 'x', '{}'
- node 'x', '{}'
- role 'x', '{}'
- user 'x', '{}'
+ client "x", "{}"
+ cookbook "x", "1.0.0"
+ data_bag "x", { "y" => "{}" }
+ environment "x", "{}"
+ node "x", "{}"
+ role "x", "{}"
+ user "x", "{}"
end
- when_the_repository 'has only top-level directories' do
+ when_the_repository "has only top-level directories" do
before do
- directory 'clients'
- directory 'cookbooks'
- directory 'data_bags'
- directory 'environments'
- directory 'nodes'
- directory 'roles'
- directory 'users'
+ directory "clients"
+ directory "cookbooks"
+ directory "data_bags"
+ directory "environments"
+ directory "nodes"
+ directory "roles"
+ directory "users"
end
- it 'knife diff reports everything as deleted' do
- knife('diff --name-status /').should_succeed <<EOM
+ it "knife diff reports everything as deleted" do
+ knife("diff --name-status /").should_succeed <<EOM
D\t/clients/chef-validator.json
D\t/clients/chef-webui.json
D\t/clients/x.json
@@ -59,68 +59,68 @@ D\t/roles/x.json
D\t/users/admin.json
D\t/users/x.json
EOM
+ end
end
- end
- when_the_repository 'has an identical copy of each thing' do
+ when_the_repository "has an identical copy of each thing" do
before do
- file 'clients/chef-validator.json', { 'validator' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
- file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
- file 'data_bags/x/y.json', {}
- file 'environments/_default.json', { "description" => "The default Chef environment" }
- file 'environments/x.json', {}
- file 'nodes/x.json', {}
- file 'roles/x.json', {}
- file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+ file "clients/chef-validator.json", { "validator" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "clients/chef-webui.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ file "data_bags/x/y.json", {}
+ file "environments/_default.json", { "description" => "The default Chef environment" }
+ file "environments/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
+ file "roles/x.json", {}
+ file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
end
- it 'knife diff reports no differences' do
- knife('diff /').should_succeed ''
+ it "knife diff reports no differences" do
+ knife("diff /").should_succeed ""
end
- it 'knife diff /environments/nonexistent.json reports an error' do
- knife('diff /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory on remote or local\n"
+ it "knife diff /environments/nonexistent.json reports an error" do
+ knife("diff /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory on remote or local\n"
end
- it 'knife diff /environments/*.txt reports an error' do
- knife('diff /environments/*.txt').should_fail "ERROR: /environments/*.txt: No such file or directory on remote or local\n"
+ it "knife diff /environments/*.txt reports an error" do
+ knife("diff /environments/*.txt").should_fail "ERROR: /environments/*.txt: No such file or directory on remote or local\n"
end
- context 'except the role file' do
+ context "except the role file" do
before do
- file 'roles/x.json', <<EOM
+ file "roles/x.json", <<EOM
{
"foo": "bar"
}
EOM
end
- it 'knife diff reports the role as different' do
- knife('diff --name-status /').should_succeed <<EOM
+ it "knife diff reports the role as different" do
+ knife("diff --name-status /").should_succeed <<EOM
M\t/roles/x.json
EOM
end
end
- context 'as well as one extra copy of each thing' do
+ context "as well as one extra copy of each thing" do
before do
- file 'clients/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
- file 'cookbooks/x/blah.rb', ''
- file 'cookbooks/y/metadata.rb', cb_metadata("y", "1.0.0")
- file 'data_bags/x/z.json', {}
- file 'data_bags/y/zz.json', {}
- file 'environments/y.json', {}
- file 'nodes/y.json', {}
- file 'roles/y.json', {}
- file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+ file "clients/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "cookbooks/x/blah.rb", ""
+ file "cookbooks/y/metadata.rb", cb_metadata("y", "1.0.0")
+ file "data_bags/x/z.json", {}
+ file "data_bags/y/zz.json", {}
+ file "environments/y.json", {}
+ file "nodes/y.json", {}
+ file "roles/y.json", {}
+ file "users/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
end
- it 'knife diff reports the new files as added' do
- knife('diff --name-status /').should_succeed <<EOM
+ it "knife diff reports the new files as added" do
+ knife("diff --name-status /").should_succeed <<EOM
A\t/clients/y.json
A\t/cookbooks/x/blah.rb
A\t/cookbooks/y
@@ -133,16 +133,16 @@ A\t/users/y.json
EOM
end
- context 'when cwd is the data_bags directory' do
- before { cwd 'data_bags' }
- it 'knife diff reports different data bags' do
- knife('diff --name-status').should_succeed <<EOM
+ context "when cwd is the data_bags directory" do
+ before { cwd "data_bags" }
+ it "knife diff reports different data bags" do
+ knife("diff --name-status").should_succeed <<EOM
A\tx/z.json
A\ty
EOM
end
- it 'knife diff * reports different data bags' do
- knife('diff --name-status *').should_succeed <<EOM
+ it "knife diff * reports different data bags" do
+ knife("diff --name-status *").should_succeed <<EOM
A\tx/z.json
A\ty
EOM
@@ -151,9 +151,9 @@ EOM
end
end
- when_the_repository 'is empty' do
- it 'knife diff reports everything as deleted' do
- knife('diff --name-status /').should_succeed <<EOM
+ when_the_repository "is empty" do
+ it "knife diff reports everything as deleted" do
+ knife("diff --name-status /").should_succeed <<EOM
D\t/clients
D\t/cookbooks
D\t/data_bags
@@ -166,51 +166,51 @@ EOM
end
end
- when_the_repository 'has a cookbook' do
+ when_the_repository "has a cookbook" do
before do
- file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
- file 'cookbooks/x/onlyin1.0.0.rb', ''
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ file "cookbooks/x/onlyin1.0.0.rb", ""
end
- when_the_chef_server 'has a later version for the cookbook' do
+ when_the_chef_server "has a later version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => '' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "" }
end
- it 'knife diff /cookbooks/x shows differences' do
- knife('diff --name-status /cookbooks/x').should_succeed <<EOM
+ it "knife diff /cookbooks/x shows differences" do
+ knife("diff --name-status /cookbooks/x").should_succeed <<EOM
M\t/cookbooks/x/metadata.rb
D\t/cookbooks/x/onlyin1.0.1.rb
A\t/cookbooks/x/onlyin1.0.0.rb
EOM
end
- it 'knife diff --diff-filter=MAT does not show deleted files' do
- knife('diff --diff-filter=MAT --name-status /cookbooks/x').should_succeed <<EOM
+ it "knife diff --diff-filter=MAT does not show deleted files" do
+ knife("diff --diff-filter=MAT --name-status /cookbooks/x").should_succeed <<EOM
M\t/cookbooks/x/metadata.rb
A\t/cookbooks/x/onlyin1.0.0.rb
EOM
end
end
- when_the_chef_server 'has an earlier version for the cookbook' do
+ when_the_chef_server "has an earlier version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => '' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "" }
end
- it 'knife diff /cookbooks/x shows no differences' do
- knife('diff --name-status /cookbooks/x').should_succeed ''
+ it "knife diff /cookbooks/x shows no differences" do
+ knife("diff --name-status /cookbooks/x").should_succeed ""
end
end
- when_the_chef_server 'has a later version for the cookbook, and no current version' do
+ when_the_chef_server "has a later version for the cookbook, and no current version" do
before do
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => '' }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "" }
end
- it 'knife diff /cookbooks/x shows the differences' do
- knife('diff --name-status /cookbooks/x').should_succeed <<EOM
+ it "knife diff /cookbooks/x shows the differences" do
+ knife("diff --name-status /cookbooks/x").should_succeed <<EOM
M\t/cookbooks/x/metadata.rb
D\t/cookbooks/x/onlyin1.0.1.rb
A\t/cookbooks/x/onlyin1.0.0.rb
@@ -218,13 +218,13 @@ EOM
end
end
- when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
+ when_the_chef_server "has an earlier version for the cookbook, and no current version" do
before do
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => '' }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "" }
end
- it 'knife diff /cookbooks/x shows the differences' do
- knife('diff --name-status /cookbooks/x').should_succeed <<EOM
+ it "knife diff /cookbooks/x shows the differences" do
+ knife("diff --name-status /cookbooks/x").should_succeed <<EOM
M\t/cookbooks/x/metadata.rb
D\t/cookbooks/x/onlyin0.9.9.rb
A\t/cookbooks/x/onlyin1.0.0.rb
@@ -233,22 +233,22 @@ EOM
end
end
- context 'json diff tests' do
- when_the_repository 'has an empty environment file' do
+ context "json diff tests" do
+ when_the_repository "has an empty environment file" do
before do
- file 'environments/x.json', {}
+ file "environments/x.json", {}
end
- when_the_chef_server 'has an empty environment' do
- before { environment 'x', {} }
- it 'knife diff returns no differences' do
- knife('diff /environments/x.json').should_succeed ''
+ when_the_chef_server "has an empty environment" do
+ before { environment "x", {} }
+ it "knife diff returns no differences" do
+ knife("diff /environments/x.json").should_succeed ""
end
end
- when_the_chef_server 'has an environment with a different value' do
- before { environment 'x', { 'description' => 'hi' } }
- it 'knife diff reports the difference', :skip => (RUBY_VERSION < "1.9") do
- knife('diff /environments/x.json').should_succeed(/
+ when_the_chef_server "has an environment with a different value" do
+ before { environment "x", { "description" => "hi" } }
+ it "knife diff reports the difference", :skip => (RUBY_VERSION < "1.9") do
+ knife("diff /environments/x.json").should_succeed(/
{
- "name": "x",
- "description": "hi"
@@ -259,26 +259,26 @@ EOM
end
end
- when_the_repository 'has an environment file with a value in it' do
+ when_the_repository "has an environment file with a value in it" do
before do
- file 'environments/x.json', { 'description' => 'hi' }
+ file "environments/x.json", { "description" => "hi" }
end
- when_the_chef_server 'has an environment with the same value' do
+ when_the_chef_server "has an environment with the same value" do
before do
- environment 'x', { 'description' => 'hi' }
+ environment "x", { "description" => "hi" }
end
- it 'knife diff returns no differences' do
- knife('diff /environments/x.json').should_succeed ''
+ it "knife diff returns no differences" do
+ knife("diff /environments/x.json").should_succeed ""
end
end
- when_the_chef_server 'has an environment with no value' do
+ when_the_chef_server "has an environment with no value" do
before do
- environment 'x', {}
+ environment "x", {}
end
- it 'knife diff reports the difference', :skip => (RUBY_VERSION < "1.9") do
- knife('diff /environments/x.json').should_succeed(/
+ it "knife diff reports the difference", :skip => (RUBY_VERSION < "1.9") do
+ knife("diff /environments/x.json").should_succeed(/
{
- "name": "x"
\+ "name": "x",
@@ -287,12 +287,12 @@ EOM
/)
end
end
- when_the_chef_server 'has an environment with a different value' do
+ when_the_chef_server "has an environment with a different value" do
before do
- environment 'x', { 'description' => 'lo' }
+ environment "x", { "description" => "lo" }
end
- it 'knife diff reports the difference', :skip => (RUBY_VERSION < "1.9") do
- knife('diff /environments/x.json').should_succeed(/
+ it "knife diff reports the difference", :skip => (RUBY_VERSION < "1.9") do
+ knife("diff /environments/x.json").should_succeed(/
{
"name": "x",
- "description": "lo"
@@ -304,14 +304,14 @@ EOM
end
end
- when_the_chef_server 'has an environment' do
- before { environment 'x', {} }
- when_the_repository 'has an environment with bad JSON' do
- before { file 'environments/x.json', '{' }
- it 'knife diff reports an error and does a textual diff' do
+ when_the_chef_server "has an environment" do
+ before { environment "x", {} }
+ when_the_repository "has an environment with bad JSON" do
+ before { file "environments/x.json", "{" }
+ it "knife diff reports an error and does a textual diff" do
error_text = "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error: premature EOF"
error_match = Regexp.new(Regexp.escape(error_text))
- knife('diff /environments/x.json').should_succeed(/- "name": "x"/, :stderr => error_match)
+ knife("diff /environments/x.json").should_succeed(/- "name": "x"/, :stderr => error_match)
end
end
end
@@ -320,28 +320,28 @@ EOM
with_versioned_cookbooks do
when_the_chef_server "has one of each thing" do
before do
- client 'x', '{}'
- cookbook 'x', '1.0.0'
- data_bag 'x', { 'y' => '{}' }
- environment 'x', '{}'
- node 'x', '{}'
- role 'x', '{}'
- user 'x', '{}'
+ client "x", "{}"
+ cookbook "x", "1.0.0"
+ data_bag "x", { "y" => "{}" }
+ environment "x", "{}"
+ node "x", "{}"
+ role "x", "{}"
+ user "x", "{}"
end
- when_the_repository 'has only top-level directories' do
+ when_the_repository "has only top-level directories" do
before do
- directory 'clients'
- directory 'cookbooks'
- directory 'data_bags'
- directory 'environments'
- directory 'nodes'
- directory 'roles'
- directory 'users'
+ directory "clients"
+ directory "cookbooks"
+ directory "data_bags"
+ directory "environments"
+ directory "nodes"
+ directory "roles"
+ directory "users"
end
- it 'knife diff reports everything as deleted' do
- knife('diff --name-status /').should_succeed <<EOM
+ it "knife diff reports everything as deleted" do
+ knife("diff --name-status /").should_succeed <<EOM
D\t/clients/chef-validator.json
D\t/clients/chef-webui.json
D\t/clients/x.json
@@ -354,68 +354,68 @@ D\t/roles/x.json
D\t/users/admin.json
D\t/users/x.json
EOM
+ end
end
- end
- when_the_repository 'has an identical copy of each thing' do
+ when_the_repository "has an identical copy of each thing" do
before do
- file 'clients/chef-validator.json', { 'validator' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
- file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata("x", "1.0.0")
- file 'data_bags/x/y.json', {}
- file 'environments/_default.json', { "description" => "The default Chef environment" }
- file 'environments/x.json', {}
- file 'nodes/x.json', {}
- file 'roles/x.json', {}
- file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+ file "clients/chef-validator.json", { "validator" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "clients/chef-webui.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+ file "data_bags/x/y.json", {}
+ file "environments/_default.json", { "description" => "The default Chef environment" }
+ file "environments/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
+ file "roles/x.json", {}
+ file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
end
- it 'knife diff reports no differences' do
- knife('diff /').should_succeed ''
+ it "knife diff reports no differences" do
+ knife("diff /").should_succeed ""
end
- it 'knife diff /environments/nonexistent.json reports an error' do
- knife('diff /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory on remote or local\n"
+ it "knife diff /environments/nonexistent.json reports an error" do
+ knife("diff /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory on remote or local\n"
end
- it 'knife diff /environments/*.txt reports an error' do
- knife('diff /environments/*.txt').should_fail "ERROR: /environments/*.txt: No such file or directory on remote or local\n"
+ it "knife diff /environments/*.txt reports an error" do
+ knife("diff /environments/*.txt").should_fail "ERROR: /environments/*.txt: No such file or directory on remote or local\n"
end
- context 'except the role file' do
+ context "except the role file" do
before do
- file 'roles/x.json', <<EOM
+ file "roles/x.json", <<EOM
{
"foo": "bar"
}
EOM
end
- it 'knife diff reports the role as different' do
- knife('diff --name-status /').should_succeed <<EOM
+ it "knife diff reports the role as different" do
+ knife("diff --name-status /").should_succeed <<EOM
M\t/roles/x.json
EOM
end
end
- context 'as well as one extra copy of each thing' do
+ context "as well as one extra copy of each thing" do
before do
- file 'clients/y.json', {}
- file 'cookbooks/x-1.0.0/blah.rb', ''
- file 'cookbooks/x-2.0.0/metadata.rb', cb_metadata("x", "2.0.0")
- file 'cookbooks/y-1.0.0/metadata.rb', cb_metadata("y", "1.0.0")
- file 'data_bags/x/z.json', {}
- file 'data_bags/y/zz.json', {}
- file 'environments/y.json', {}
- file 'nodes/y.json', {}
- file 'roles/y.json', {}
- file 'users/y.json', {}
+ file "clients/y.json", {}
+ file "cookbooks/x-1.0.0/blah.rb", ""
+ file "cookbooks/x-2.0.0/metadata.rb", cb_metadata("x", "2.0.0")
+ file "cookbooks/y-1.0.0/metadata.rb", cb_metadata("y", "1.0.0")
+ file "data_bags/x/z.json", {}
+ file "data_bags/y/zz.json", {}
+ file "environments/y.json", {}
+ file "nodes/y.json", {}
+ file "roles/y.json", {}
+ file "users/y.json", {}
end
- it 'knife diff reports the new files as added' do
- knife('diff --name-status /').should_succeed <<EOM
+ it "knife diff reports the new files as added" do
+ knife("diff --name-status /").should_succeed <<EOM
A\t/clients/y.json
A\t/cookbooks/x-1.0.0/blah.rb
A\t/cookbooks/x-2.0.0
@@ -429,16 +429,16 @@ A\t/users/y.json
EOM
end
- context 'when cwd is the data_bags directory' do
- before { cwd 'data_bags' }
- it 'knife diff reports different data bags' do
- knife('diff --name-status').should_succeed <<EOM
+ context "when cwd is the data_bags directory" do
+ before { cwd "data_bags" }
+ it "knife diff reports different data bags" do
+ knife("diff --name-status").should_succeed <<EOM
A\tx/z.json
A\ty
EOM
end
- it 'knife diff * reports different data bags' do
- knife('diff --name-status *').should_succeed <<EOM
+ it "knife diff * reports different data bags" do
+ knife("diff --name-status *").should_succeed <<EOM
A\tx/z.json
A\ty
EOM
@@ -447,9 +447,9 @@ EOM
end
end
- when_the_repository 'is empty' do
- it 'knife diff reports everything as deleted' do
- knife('diff --name-status /').should_succeed <<EOM
+ when_the_repository "is empty" do
+ it "knife diff reports everything as deleted" do
+ knife("diff --name-status /").should_succeed <<EOM
D\t/clients
D\t/cookbooks
D\t/data_bags
@@ -462,59 +462,59 @@ EOM
end
end
- when_the_repository 'has a cookbook' do
+ when_the_repository "has a cookbook" do
before do
- file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata("x", "1.0.0")
- file 'cookbooks/x-1.0.0/onlyin1.0.0.rb', ''
+ file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+ file "cookbooks/x-1.0.0/onlyin1.0.0.rb", ""
end
- when_the_chef_server 'has a later version for the cookbook' do
+ when_the_chef_server "has a later version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => '' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "" }
end
- it 'knife diff /cookbooks shows differences' do
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife diff /cookbooks shows differences" do
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
D\t/cookbooks/x-1.0.1
EOM
end
- it 'knife diff --diff-filter=MAT does not show deleted files' do
- knife('diff --diff-filter=MAT --name-status /cookbooks').should_succeed ''
+ it "knife diff --diff-filter=MAT does not show deleted files" do
+ knife("diff --diff-filter=MAT --name-status /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has an earlier version for the cookbook' do
+ when_the_chef_server "has an earlier version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => '' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "" }
end
- it 'knife diff /cookbooks shows the differences' do
- knife('diff --name-status /cookbooks').should_succeed "D\t/cookbooks/x-0.9.9\n"
+ it "knife diff /cookbooks shows the differences" do
+ knife("diff --name-status /cookbooks").should_succeed "D\t/cookbooks/x-0.9.9\n"
end
end
- when_the_chef_server 'has a later version for the cookbook, and no current version' do
+ when_the_chef_server "has a later version for the cookbook, and no current version" do
before do
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => '' }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "" }
end
- it 'knife diff /cookbooks shows the differences' do
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife diff /cookbooks shows the differences" do
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
D\t/cookbooks/x-1.0.1
A\t/cookbooks/x-1.0.0
EOM
end
end
- when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
+ when_the_chef_server "has an earlier version for the cookbook, and no current version" do
before do
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => '' }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "" }
end
- it 'knife diff /cookbooks shows the differences' do
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife diff /cookbooks shows the differences" do
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
D\t/cookbooks/x-0.9.9
A\t/cookbooks/x-1.0.0
EOM
@@ -522,19 +522,19 @@ EOM
end
end
- context 'json diff tests' do
- when_the_repository 'has an empty environment file' do
- before { file 'environments/x.json', {} }
- when_the_chef_server 'has an empty environment' do
- before { environment 'x', {} }
- it 'knife diff returns no differences' do
- knife('diff /environments/x.json').should_succeed ''
+ context "json diff tests" do
+ when_the_repository "has an empty environment file" do
+ before { file "environments/x.json", {} }
+ when_the_chef_server "has an empty environment" do
+ before { environment "x", {} }
+ it "knife diff returns no differences" do
+ knife("diff /environments/x.json").should_succeed ""
end
end
- when_the_chef_server 'has an environment with a different value' do
- before { environment 'x', { 'description' => 'hi' } }
- it 'knife diff reports the difference', :skip => (RUBY_VERSION < "1.9") do
- knife('diff /environments/x.json').should_succeed(/
+ when_the_chef_server "has an environment with a different value" do
+ before { environment "x", { "description" => "hi" } }
+ it "knife diff reports the difference", :skip => (RUBY_VERSION < "1.9") do
+ knife("diff /environments/x.json").should_succeed(/
{
- "name": "x",
- "description": "hi"
@@ -545,23 +545,23 @@ EOM
end
end
- when_the_repository 'has an environment file with a value in it' do
+ when_the_repository "has an environment file with a value in it" do
before do
- file 'environments/x.json', { 'description' => 'hi' }
+ file "environments/x.json", { "description" => "hi" }
end
- when_the_chef_server 'has an environment with the same value' do
+ when_the_chef_server "has an environment with the same value" do
before do
- environment 'x', { 'description' => 'hi' }
+ environment "x", { "description" => "hi" }
end
- it 'knife diff returns no differences' do
- knife('diff /environments/x.json').should_succeed ''
+ it "knife diff returns no differences" do
+ knife("diff /environments/x.json").should_succeed ""
end
end
- when_the_chef_server 'has an environment with no value' do
- before { environment 'x', {} }
- it 'knife diff reports the difference', :skip => (RUBY_VERSION < "1.9") do
- knife('diff /environments/x.json').should_succeed(/
+ when_the_chef_server "has an environment with no value" do
+ before { environment "x", {} }
+ it "knife diff reports the difference", :skip => (RUBY_VERSION < "1.9") do
+ knife("diff /environments/x.json").should_succeed(/
{
- "name": "x"
\+ "name": "x",
@@ -570,12 +570,12 @@ EOM
/)
end
end
- when_the_chef_server 'has an environment with a different value' do
+ when_the_chef_server "has an environment with a different value" do
before do
- environment 'x', { 'description' => 'lo' }
+ environment "x", { "description" => "lo" }
end
- it 'knife diff reports the difference', :skip => (RUBY_VERSION < "1.9") do
- knife('diff /environments/x.json').should_succeed(/
+ it "knife diff reports the difference", :skip => (RUBY_VERSION < "1.9") do
+ knife("diff /environments/x.json").should_succeed(/
{
"name": "x",
- "description": "lo"
@@ -587,14 +587,14 @@ EOM
end
end
- when_the_chef_server 'has an environment' do
- before { environment 'x', {} }
- when_the_repository 'has an environment with bad JSON' do
- before { file 'environments/x.json', '{' }
- it 'knife diff reports an error and does a textual diff' do
+ when_the_chef_server "has an environment" do
+ before { environment "x", {} }
+ when_the_repository "has an environment with bad JSON" do
+ before { file "environments/x.json", "{" }
+ it "knife diff reports an error and does a textual diff" do
error_text = "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error: premature EOF"
error_match = Regexp.new(Regexp.escape(error_text))
- knife('diff /environments/x.json').should_succeed(/- "name": "x"/, :stderr => error_match)
+ knife("diff /environments/x.json").should_succeed(/- "name": "x"/, :stderr => error_match)
end
end
end
diff --git a/spec/integration/knife/download_spec.rb b/spec/integration/knife/download_spec.rb
index b8a19061b7..be0fc9d708 100644
--- a/spec/integration/knife/download_spec.rb
+++ b/spec/integration/knife/download_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,40 +15,40 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/download'
-require 'chef/knife/diff'
+require "support/shared/integration/integration_helper"
+require "chef/knife/download"
+require "chef/knife/diff"
-describe 'knife download', :workstation do
+describe "knife download", :workstation do
include IntegrationSupport
include KnifeSupport
- context 'without versioned cookbooks' do
+ context "without versioned cookbooks" do
when_the_chef_server "has one of each thing" do
before do
- client 'x', {}
- cookbook 'x', '1.0.0'
- data_bag 'x', { 'y' => {} }
- environment 'x', {}
- node 'x', {}
- role 'x', {}
- user 'x', {}
+ client "x", {}
+ cookbook "x", "1.0.0"
+ data_bag "x", { "y" => {} }
+ environment "x", {}
+ node "x", {}
+ role "x", {}
+ user "x", {}
end
- when_the_repository 'has only top-level directories' do
+ when_the_repository "has only top-level directories" do
before do
- directory 'clients'
- directory 'cookbooks'
- directory 'data_bags'
- directory 'environments'
- directory 'nodes'
- directory 'roles'
- directory 'users'
+ directory "clients"
+ directory "cookbooks"
+ directory "data_bags"
+ directory "environments"
+ directory "nodes"
+ directory "roles"
+ directory "users"
end
- it 'knife download downloads everything' do
- knife('download /').should_succeed <<EOM
+ it "knife download downloads everything" do
+ knife("download /").should_succeed <<EOM
Created /clients/chef-validator.json
Created /clients/chef-webui.json
Created /clients/x.json
@@ -63,38 +63,38 @@ Created /roles/x.json
Created /users/admin.json
Created /users/x.json
EOM
- knife('diff --name-status /').should_succeed ''
+ knife("diff --name-status /").should_succeed ""
end
end
- when_the_repository 'has an identical copy of each thing' do
+ when_the_repository "has an identical copy of each thing" do
before do
- file 'clients/chef-validator.json', { 'validator' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
- file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
- file 'data_bags/x/y.json', {}
- file 'environments/_default.json', { "description" => "The default Chef environment" }
- file 'environments/x.json', {}
- file 'nodes/x.json', {}
- file 'roles/x.json', {}
- file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+ file "clients/chef-validator.json", { "validator" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "clients/chef-webui.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ file "data_bags/x/y.json", {}
+ file "environments/_default.json", { "description" => "The default Chef environment" }
+ file "environments/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
+ file "roles/x.json", {}
+ file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
end
- it 'knife download makes no changes' do
- knife('download /').should_succeed ''
- knife('diff --name-status /').should_succeed ''
+ it "knife download makes no changes" do
+ knife("download /").should_succeed ""
+ knife("diff --name-status /").should_succeed ""
end
- it 'knife download --purge makes no changes' do
- knife('download --purge /').should_succeed ''
- knife('diff --name-status /').should_succeed ''
+ it "knife download --purge makes no changes" do
+ knife("download --purge /").should_succeed ""
+ knife("diff --name-status /").should_succeed ""
end
- context 'except the role file' do
+ context "except the role file" do
before do
- file 'roles/x.json', <<EOM
+ file "roles/x.json", <<EOM
{
"chef_type": "role",
"default_attributes": {
@@ -113,20 +113,20 @@ EOM
EOM
end
- it 'knife download changes the role' do
- knife('download /').should_succeed "Updated /roles/x.json\n"
- knife('diff --name-status /').should_succeed ''
+ it "knife download changes the role" do
+ knife("download /").should_succeed "Updated /roles/x.json\n"
+ knife("diff --name-status /").should_succeed ""
end
- it 'knife download --no-diff does not change the role' do
- knife('download --no-diff /').should_succeed ''
- knife('diff --name-status /').should_succeed "M\t/roles/x.json\n"
+ it "knife download --no-diff does not change the role" do
+ knife("download --no-diff /").should_succeed ""
+ knife("diff --name-status /").should_succeed "M\t/roles/x.json\n"
end
end
- context 'except the role file is textually different, but not ACTUALLY different' do
+ context "except the role file is textually different, but not ACTUALLY different" do
before do
- file 'roles/x.json', <<EOM
+ file "roles/x.json", <<EOM
{
"chef_type": "role",
"default_attributes": {
@@ -145,28 +145,28 @@ EOM
EOM
end
- it 'knife download / does not change anything' do
- knife('download /').should_succeed ''
- knife('diff --name-status /').should_succeed ''
+ it "knife download / does not change anything" do
+ knife("download /").should_succeed ""
+ knife("diff --name-status /").should_succeed ""
end
end
- context 'as well as one extra copy of each thing' do
+ context "as well as one extra copy of each thing" do
before do
- file 'clients/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
- file 'cookbooks/x/blah.rb', ''
- file 'cookbooks/y/metadata.rb', cb_metadata("x", "1.0.0")
- file 'data_bags/x/z.json', {}
- file 'data_bags/y/zz.json', {}
- file 'environments/y.json', {}
- file 'nodes/y.json', {}
- file 'roles/y.json', {}
- file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+ file "clients/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "cookbooks/x/blah.rb", ""
+ file "cookbooks/y/metadata.rb", cb_metadata("x", "1.0.0")
+ file "data_bags/x/z.json", {}
+ file "data_bags/y/zz.json", {}
+ file "environments/y.json", {}
+ file "nodes/y.json", {}
+ file "roles/y.json", {}
+ file "users/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
end
- it 'knife download does nothing' do
- knife('download /').should_succeed ''
- knife('diff --name-status /').should_succeed <<EOM
+ it "knife download does nothing" do
+ knife("download /").should_succeed ""
+ knife("diff --name-status /").should_succeed <<EOM
A\t/clients/y.json
A\t/cookbooks/x/blah.rb
A\t/cookbooks/y
@@ -179,8 +179,8 @@ A\t/users/y.json
EOM
end
- it 'knife download --purge deletes the extra files' do
- knife('download --purge /').should_succeed <<EOM
+ it "knife download --purge deletes the extra files" do
+ knife("download --purge /").should_succeed <<EOM
Deleted extra entry /clients/y.json (purge is on)
Deleted extra entry /cookbooks/x/blah.rb (purge is on)
Deleted extra entry /cookbooks/y (purge is on)
@@ -191,14 +191,14 @@ Deleted extra entry /nodes/y.json (purge is on)
Deleted extra entry /roles/y.json (purge is on)
Deleted extra entry /users/y.json (purge is on)
EOM
- knife('diff --name-status /').should_succeed ''
+ knife("diff --name-status /").should_succeed ""
end
end
end
- when_the_repository 'is empty' do
- it 'knife download creates the extra files' do
- knife('download /').should_succeed <<EOM
+ when_the_repository "is empty" do
+ it "knife download creates the extra files" do
+ knife("download /").should_succeed <<EOM
Created /clients
Created /clients/chef-validator.json
Created /clients/chef-webui.json
@@ -220,11 +220,11 @@ Created /users
Created /users/admin.json
Created /users/x.json
EOM
- knife('diff --name-status /').should_succeed ''
+ knife("diff --name-status /").should_succeed ""
end
- it 'knife download --no-diff creates the extra files' do
- knife('download --no-diff /').should_succeed <<EOM
+ it "knife download --no-diff creates the extra files" do
+ knife("download --no-diff /").should_succeed <<EOM
Created /clients
Created /clients/chef-validator.json
Created /clients/chef-webui.json
@@ -246,41 +246,41 @@ Created /users
Created /users/admin.json
Created /users/x.json
EOM
- knife('diff --name-status /').should_succeed ''
+ knife("diff --name-status /").should_succeed ""
end
- context 'when current directory is top level' do
+ context "when current directory is top level" do
before do
- cwd '.'
+ cwd "."
end
- it 'knife download with no parameters reports an error' do
- knife('download').should_fail "FATAL: Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
+ it "knife download with no parameters reports an error" do
+ knife("download").should_fail "FATAL: You must specify at least one argument. If you want to download everything in this directory, run \"knife download .\"\n", :stdout => /USAGE/
end
end
end
end
# Test download of an item when the other end doesn't even have the container
- when_the_repository 'is empty' do
- when_the_chef_server 'has two data bag items' do
+ when_the_repository "is empty" do
+ when_the_chef_server "has two data bag items" do
before do
- data_bag 'x', { 'y' => {}, 'z' => {} }
+ data_bag "x", { "y" => {}, "z" => {} }
end
- it 'knife download of one data bag item itself succeeds' do
- knife('download /data_bags/x/y.json').should_succeed <<EOM
+ it "knife download of one data bag item itself succeeds" do
+ knife("download /data_bags/x/y.json").should_succeed <<EOM
Created /data_bags
Created /data_bags/x
Created /data_bags/x/y.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/z.json
EOM
end
- it 'knife download /data_bags/x /data_bags/x/y.json downloads x once' do
- knife('download /data_bags/x /data_bags/x/y.json').should_succeed <<EOM
+ it "knife download /data_bags/x /data_bags/x/y.json downloads x once" do
+ knife("download /data_bags/x /data_bags/x/y.json").should_succeed <<EOM
Created /data_bags
Created /data_bags/x
Created /data_bags/x/y.json
@@ -290,285 +290,304 @@ EOM
end
end
- when_the_repository 'has three data bag items' do
+ when_the_repository "has three data bag items" do
before do
- file 'data_bags/x/deleted.json', <<EOM
+ file "data_bags/x/deleted.json", <<EOM
{
"id": "deleted"
}
EOM
- file 'data_bags/x/modified.json', <<EOM
+ file "data_bags/x/modified.json", <<EOM
{
"id": "modified"
}
EOM
- file 'data_bags/x/unmodified.json', <<EOM
+ file "data_bags/x/unmodified.json", <<EOM
{
"id": "unmodified"
}
EOM
end
- when_the_chef_server 'has a modified, unmodified, added and deleted data bag item' do
+ when_the_chef_server "has a modified, unmodified, added and deleted data bag item" do
before do
- data_bag 'x', {
- 'added' => {},
- 'modified' => { 'foo' => 'bar' },
- 'unmodified' => {}
+ data_bag "x", {
+ "added" => {},
+ "modified" => { "foo" => "bar" },
+ "unmodified" => {},
}
end
- it 'knife download of the modified file succeeds' do
- knife('download /data_bags/x/modified.json').should_succeed <<EOM
+ it "knife download of the modified file succeeds" do
+ knife("download /data_bags/x/modified.json").should_succeed <<EOM
Updated /data_bags/x/modified.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/added.json
A\t/data_bags/x/deleted.json
EOM
end
- it 'knife download of the unmodified file does nothing' do
- knife('download /data_bags/x/unmodified.json').should_succeed ''
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ it "knife download of the unmodified file does nothing" do
+ knife("download /data_bags/x/unmodified.json").should_succeed ""
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/added.json
M\t/data_bags/x/modified.json
A\t/data_bags/x/deleted.json
EOM
end
- it 'knife download of the added file succeeds' do
- knife('download /data_bags/x/added.json').should_succeed <<EOM
+ it "knife download of the added file succeeds" do
+ knife("download /data_bags/x/added.json").should_succeed <<EOM
Created /data_bags/x/added.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
M\t/data_bags/x/modified.json
A\t/data_bags/x/deleted.json
EOM
end
- it 'knife download of the deleted file does nothing' do
- knife('download /data_bags/x/deleted.json').should_succeed ''
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ it "knife download of the deleted file does nothing" do
+ knife("download /data_bags/x/deleted.json").should_succeed ""
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/added.json
M\t/data_bags/x/modified.json
A\t/data_bags/x/deleted.json
EOM
end
- it 'knife download --purge of the deleted file deletes it' do
- knife('download --purge /data_bags/x/deleted.json').should_succeed <<EOM
+ it "knife download --purge of the deleted file deletes it" do
+ knife("download --purge /data_bags/x/deleted.json").should_succeed <<EOM
Deleted extra entry /data_bags/x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/added.json
M\t/data_bags/x/modified.json
EOM
end
- it 'knife download of the entire data bag downloads everything' do
- knife('download /data_bags/x').should_succeed <<EOM
+ it "knife download of the entire data bag downloads everything" do
+ knife("download /data_bags/x").should_succeed <<EOM
Created /data_bags/x/added.json
Updated /data_bags/x/modified.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
A\t/data_bags/x/deleted.json
EOM
end
- it 'knife download --purge of the entire data bag downloads everything' do
- knife('download --purge /data_bags/x').should_succeed <<EOM
+ it "knife download --purge of the entire data bag downloads everything" do
+ knife("download --purge /data_bags/x").should_succeed <<EOM
Created /data_bags/x/added.json
Updated /data_bags/x/modified.json
Deleted extra entry /data_bags/x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed ''
+ knife("diff --name-status /data_bags").should_succeed ""
end
- context 'when cwd is the /data_bags directory' do
+ context "when cwd is the /data_bags directory" do
before do
- cwd 'data_bags'
+ cwd "data_bags"
end
- it 'knife download fails' do
- knife('download').should_fail "FATAL: Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
+ it "knife download fails" do
+ knife("download").should_fail "FATAL: You must specify at least one argument. If you want to download everything in this directory, run \"knife download .\"\n", :stdout => /USAGE/
end
- it 'knife download --purge . downloads everything' do
- knife('download --purge .').should_succeed <<EOM
+ it "knife download --purge . downloads everything" do
+ knife("download --purge .").should_succeed <<EOM
Created x/added.json
Updated x/modified.json
Deleted extra entry x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed ''
+ knife("diff --name-status /data_bags").should_succeed ""
end
- it 'knife download --purge * downloads everything' do
- knife('download --purge *').should_succeed <<EOM
+ it "knife download --purge * downloads everything" do
+ knife("download --purge *").should_succeed <<EOM
Created x/added.json
Updated x/modified.json
Deleted extra entry x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed ''
+ knife("diff --name-status /data_bags").should_succeed ""
end
end
end
end
- when_the_repository 'has a cookbook' do
+ when_the_repository "has a cookbook" do
before do
- file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
- file 'cookbooks/x/z.rb', ''
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ file "cookbooks/x/z.rb", ""
end
- when_the_chef_server 'has a modified, added and deleted file for the cookbook' do
+ when_the_chef_server "has a modified, added and deleted file for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'metadata.rb' => cb_metadata("x", "1.0.0", "#extra content"), 'y.rb' => 'hi' }
+ cookbook "x", "1.0.0", { "metadata.rb" => cb_metadata("x", "1.0.0", "#extra content"), "y.rb" => "hi" }
end
- it 'knife download of a modified file succeeds' do
- knife('download /cookbooks/x/metadata.rb').should_succeed "Updated /cookbooks/x/metadata.rb\n"
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife download of a modified file succeeds" do
+ knife("download /cookbooks/x/metadata.rb").should_succeed "Updated /cookbooks/x/metadata.rb\n"
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
D\t/cookbooks/x/y.rb
A\t/cookbooks/x/z.rb
EOM
end
- it 'knife download of a deleted file does nothing' do
- knife('download /cookbooks/x/z.rb').should_succeed ''
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife download of a deleted file does nothing" do
+ knife("download /cookbooks/x/z.rb").should_succeed ""
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
M\t/cookbooks/x/metadata.rb
D\t/cookbooks/x/y.rb
A\t/cookbooks/x/z.rb
EOM
end
- it 'knife download --purge of a deleted file succeeds' do
- knife('download --purge /cookbooks/x/z.rb').should_succeed "Deleted extra entry /cookbooks/x/z.rb (purge is on)\n"
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife download --purge of a deleted file succeeds" do
+ knife("download --purge /cookbooks/x/z.rb").should_succeed "Deleted extra entry /cookbooks/x/z.rb (purge is on)\n"
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
M\t/cookbooks/x/metadata.rb
D\t/cookbooks/x/y.rb
EOM
end
- it 'knife download of an added file succeeds' do
- knife('download /cookbooks/x/y.rb').should_succeed "Created /cookbooks/x/y.rb\n"
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife download of an added file succeeds" do
+ knife("download /cookbooks/x/y.rb").should_succeed "Created /cookbooks/x/y.rb\n"
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
M\t/cookbooks/x/metadata.rb
A\t/cookbooks/x/z.rb
EOM
end
- it 'knife download of the cookbook itself succeeds' do
- knife('download /cookbooks/x').should_succeed <<EOM
+ it "knife download of the cookbook itself succeeds" do
+ knife("download /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x/metadata.rb
Created /cookbooks/x/y.rb
EOM
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
A\t/cookbooks/x/z.rb
EOM
end
- it 'knife download --purge of the cookbook itself succeeds' do
- knife('download --purge /cookbooks/x').should_succeed <<EOM
+ it "knife download --purge of the cookbook itself succeeds" do
+ knife("download --purge /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x/metadata.rb
Created /cookbooks/x/y.rb
Deleted extra entry /cookbooks/x/z.rb (purge is on)
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
end
- when_the_repository 'has a cookbook' do
+ when_the_repository "has a cookbook" do
before do
- file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
- file 'cookbooks/x/onlyin1.0.0.rb', 'old_text'
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ file "cookbooks/x/onlyin1.0.0.rb", "old_text"
end
- when_the_chef_server 'has a later version for the cookbook' do
+ when_the_chef_server "has a later version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
end
- it 'knife download /cookbooks/x downloads the latest version' do
- knife('download --purge /cookbooks/x').should_succeed <<EOM
+ it "knife download /cookbooks/x downloads the latest version" do
+ knife("download --purge /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x/metadata.rb
Created /cookbooks/x/onlyin1.0.1.rb
Deleted extra entry /cookbooks/x/onlyin1.0.0.rb (purge is on)
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has an earlier version for the cookbook' do
+ when_the_chef_server "has an earlier version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
end
- it 'knife download /cookbooks/x downloads the updated file' do
- knife('download --purge /cookbooks/x').should_succeed <<EOM
+ it "knife download /cookbooks/x downloads the updated file" do
+ knife("download --purge /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x/onlyin1.0.0.rb
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has a later version for the cookbook, and no current version' do
+ when_the_chef_server "has a later version for the cookbook, and no current version" do
before do
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
end
- it 'knife download /cookbooks/x downloads the latest version' do
- knife('download --purge /cookbooks/x').should_succeed <<EOM
+ it "knife download /cookbooks/x downloads the latest version" do
+ knife("download --purge /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x/metadata.rb
Created /cookbooks/x/onlyin1.0.1.rb
Deleted extra entry /cookbooks/x/onlyin1.0.0.rb (purge is on)
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
+ when_the_chef_server "has an earlier version for the cookbook, and no current version" do
before do
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
end
- it 'knife download /cookbooks/x downloads the old version' do
- knife('download --purge /cookbooks/x').should_succeed <<EOM
+ it "knife download /cookbooks/x downloads the old version" do
+ knife("download --purge /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x/metadata.rb
Created /cookbooks/x/onlyin0.9.9.rb
Deleted extra entry /cookbooks/x/onlyin1.0.0.rb (purge is on)
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
end
- when_the_chef_server 'has an environment' do
+ when_the_chef_server "has a role" do
before do
- environment 'x', {}
+ role "x", {}
end
- when_the_repository 'has an environment with bad JSON' do
+ when_the_repository "has the role in ruby" do
before do
- file 'environments/x.json', '{'
+ file "roles/x.rb", <<EOM
+name "x"
+description "x"
+EOM
+ end
+
+ it "knife download refuses to change the role" do
+ knife("download /roles/x.json").should_succeed "", :stderr => "WARNING: /roles/x.rb cannot be updated (can't safely update ruby files).\n"
+ knife("diff --name-status /roles/x.json").should_succeed "M\t/roles/x.rb\n"
end
- it 'knife download succeeds' do
+ end
+ end
+
+ when_the_chef_server "has an environment" do
+ before do
+ environment "x", {}
+ end
+ when_the_repository "has an environment with bad JSON" do
+ before do
+ file "environments/x.json", "{"
+ end
+ it "knife download succeeds" do
warning = <<-EOH
WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error: premature EOF
{
(right here) ------^
EOH
- knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n", :stderr => warning
- knife('diff --name-status /environments/x.json').should_succeed ''
+ knife("download /environments/x.json").should_succeed "Updated /environments/x.json\n", :stderr => warning
+ knife("diff --name-status /environments/x.json").should_succeed ""
end
end
- when_the_repository 'has the same environment with the wrong name in the file' do
+ when_the_repository "has the same environment with the wrong name in the file" do
before do
- file 'environments/x.json', { 'name' => 'y' }
+ file "environments/x.json", { "name" => "y" }
end
- it 'knife download succeeds' do
- knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n"
- knife('diff --name-status /environments/x.json').should_succeed ''
+ it "knife download succeeds" do
+ knife("download /environments/x.json").should_succeed "Updated /environments/x.json\n"
+ knife("diff --name-status /environments/x.json").should_succeed ""
end
end
- when_the_repository 'has the same environment with no name in the file' do
+ when_the_repository "has the same environment with no name in the file" do
before do
- file 'environments/x.json', { 'description' => 'hi' }
+ file "environments/x.json", { "description" => "hi" }
end
- it 'knife download succeeds' do
- knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n"
- knife('diff --name-status /environments/x.json').should_succeed ''
+ it "knife download succeeds" do
+ knife("download /environments/x.json").should_succeed "Updated /environments/x.json\n"
+ knife("diff --name-status /environments/x.json").should_succeed ""
end
end
end
@@ -577,28 +596,28 @@ EOH
with_versioned_cookbooks do
when_the_chef_server "has one of each thing" do
before do
- client 'x', {}
- cookbook 'x', '1.0.0'
- data_bag 'x', { 'y' => {} }
- environment 'x', {}
- node 'x', {}
- role 'x', {}
- user 'x', {}
+ client "x", {}
+ cookbook "x", "1.0.0"
+ data_bag "x", { "y" => {} }
+ environment "x", {}
+ node "x", {}
+ role "x", {}
+ user "x", {}
end
- when_the_repository 'has only top-level directories' do
+ when_the_repository "has only top-level directories" do
before do
- directory 'clients'
- directory 'cookbooks'
- directory 'data_bags'
- directory 'environments'
- directory 'nodes'
- directory 'roles'
- directory 'users'
+ directory "clients"
+ directory "cookbooks"
+ directory "data_bags"
+ directory "environments"
+ directory "nodes"
+ directory "roles"
+ directory "users"
end
- it 'knife download downloads everything' do
- knife('download /').should_succeed <<EOM
+ it "knife download downloads everything" do
+ knife("download /").should_succeed <<EOM
Created /clients/chef-validator.json
Created /clients/chef-webui.json
Created /clients/x.json
@@ -613,49 +632,49 @@ Created /roles/x.json
Created /users/admin.json
Created /users/x.json
EOM
- knife('diff --name-status /').should_succeed ''
+ knife("diff --name-status /").should_succeed ""
end
end
- when_the_repository 'has an identical copy of each thing' do
+ when_the_repository "has an identical copy of each thing" do
before do
- file 'clients/chef-validator.json', { 'validator' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
- file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata("x", "1.0.0")
- file 'data_bags/x/y.json', {}
- file 'environments/_default.json', { "description" => "The default Chef environment" }
- file 'environments/x.json', {}
- file 'nodes/x.json', {}
- file 'roles/x.json', {}
- file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+ file "clients/chef-validator.json", { "validator" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "clients/chef-webui.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+ file "data_bags/x/y.json", {}
+ file "environments/_default.json", { "description" => "The default Chef environment" }
+ file "environments/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
+ file "roles/x.json", {}
+ file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
end
- it 'knife download makes no changes' do
- knife('download /').should_succeed ''
- knife('diff --name-status /').should_succeed ''
+ it "knife download makes no changes" do
+ knife("download /").should_succeed ""
+ knife("diff --name-status /").should_succeed ""
end
- it 'knife download --purge makes no changes' do
- knife('download --purge /').should_succeed ''
- knife('diff --name-status /').should_succeed ''
+ it "knife download --purge makes no changes" do
+ knife("download --purge /").should_succeed ""
+ knife("diff --name-status /").should_succeed ""
end
- context 'except the role file' do
+ context "except the role file" do
before do
- file 'roles/x.json', { "description" => "blarghle" }
+ file "roles/x.json", { "description" => "blarghle" }
end
- it 'knife download changes the role' do
- knife('download /').should_succeed "Updated /roles/x.json\n"
- knife('diff --name-status /').should_succeed ''
+ it "knife download changes the role" do
+ knife("download /").should_succeed "Updated /roles/x.json\n"
+ knife("diff --name-status /").should_succeed ""
end
end
- context 'except the role file is textually different, but not ACTUALLY different' do
+ context "except the role file is textually different, but not ACTUALLY different" do
before do
- file 'roles/x.json', <<EOM
+ file "roles/x.json", <<EOM
{
"chef_type": "role" ,
"default_attributes": {
@@ -674,29 +693,29 @@ EOM
EOM
end
- it 'knife download / does not change anything' do
- knife('download /').should_succeed ''
- knife('diff --name-status /').should_succeed ''
+ it "knife download / does not change anything" do
+ knife("download /").should_succeed ""
+ knife("diff --name-status /").should_succeed ""
end
end
- context 'as well as one extra copy of each thing' do
+ context "as well as one extra copy of each thing" do
before do
- file 'clients/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
- file 'cookbooks/x-1.0.0/blah.rb', ''
- file 'cookbooks/x-2.0.0/metadata.rb', 'version "2.0.0"'
- file 'cookbooks/y-1.0.0/metadata.rb', 'version "1.0.0"'
- file 'data_bags/x/z.json', {}
- file 'data_bags/y/zz.json', {}
- file 'environments/y.json', {}
- file 'nodes/y.json', {}
- file 'roles/y.json', {}
- file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+ file "clients/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "cookbooks/x-1.0.0/blah.rb", ""
+ file "cookbooks/x-2.0.0/metadata.rb", 'version "2.0.0"'
+ file "cookbooks/y-1.0.0/metadata.rb", 'version "1.0.0"'
+ file "data_bags/x/z.json", {}
+ file "data_bags/y/zz.json", {}
+ file "environments/y.json", {}
+ file "nodes/y.json", {}
+ file "roles/y.json", {}
+ file "users/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
end
- it 'knife download does nothing' do
- knife('download /').should_succeed ''
- knife('diff --name-status /').should_succeed <<EOM
+ it "knife download does nothing" do
+ knife("download /").should_succeed ""
+ knife("diff --name-status /").should_succeed <<EOM
A\t/clients/y.json
A\t/cookbooks/x-1.0.0/blah.rb
A\t/cookbooks/x-2.0.0
@@ -710,8 +729,8 @@ A\t/users/y.json
EOM
end
- it 'knife download --purge deletes the extra files' do
- knife('download --purge /').should_succeed <<EOM
+ it "knife download --purge deletes the extra files" do
+ knife("download --purge /").should_succeed <<EOM
Deleted extra entry /clients/y.json (purge is on)
Deleted extra entry /cookbooks/x-1.0.0/blah.rb (purge is on)
Deleted extra entry /cookbooks/x-2.0.0 (purge is on)
@@ -723,14 +742,14 @@ Deleted extra entry /nodes/y.json (purge is on)
Deleted extra entry /roles/y.json (purge is on)
Deleted extra entry /users/y.json (purge is on)
EOM
- knife('diff --name-status /').should_succeed ''
+ knife("diff --name-status /").should_succeed ""
end
end
end
- when_the_repository 'is empty' do
- it 'knife download creates the extra files' do
- knife('download /').should_succeed <<EOM
+ when_the_repository "is empty" do
+ it "knife download creates the extra files" do
+ knife("download /").should_succeed <<EOM
Created /clients
Created /clients/chef-validator.json
Created /clients/chef-webui.json
@@ -752,324 +771,324 @@ Created /users
Created /users/admin.json
Created /users/x.json
EOM
- knife('diff --name-status /').should_succeed ''
+ knife("diff --name-status /").should_succeed ""
end
- context 'when current directory is top level' do
+ context "when current directory is top level" do
before do
- cwd '.'
+ cwd "."
end
- it 'knife download with no parameters reports an error' do
- knife('download').should_fail "FATAL: Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
+ it "knife download with no parameters reports an error" do
+ knife("download").should_fail "FATAL: You must specify at least one argument. If you want to download everything in this directory, run \"knife download .\"\n", :stdout => /USAGE/
end
end
end
end
# Test download of an item when the other end doesn't even have the container
- when_the_repository 'is empty' do
- when_the_chef_server 'has two data bag items' do
+ when_the_repository "is empty" do
+ when_the_chef_server "has two data bag items" do
before do
- data_bag 'x', { 'y' => {}, 'z' => {} }
+ data_bag "x", { "y" => {}, "z" => {} }
end
- it 'knife download of one data bag item itself succeeds' do
- knife('download /data_bags/x/y.json').should_succeed <<EOM
+ it "knife download of one data bag item itself succeeds" do
+ knife("download /data_bags/x/y.json").should_succeed <<EOM
Created /data_bags
Created /data_bags/x
Created /data_bags/x/y.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/z.json
EOM
end
end
end
- when_the_repository 'has three data bag items' do
+ when_the_repository "has three data bag items" do
before do
- file 'data_bags/x/deleted.json', <<EOM
+ file "data_bags/x/deleted.json", <<EOM
{
"id": "deleted"
}
EOM
- file 'data_bags/x/modified.json', <<EOM
+ file "data_bags/x/modified.json", <<EOM
{
"id": "modified"
}
EOM
- file 'data_bags/x/unmodified.json', <<EOM
+ file "data_bags/x/unmodified.json", <<EOM
{
"id": "unmodified"
}
EOM
end
- when_the_chef_server 'has a modified, unmodified, added and deleted data bag item' do
+ when_the_chef_server "has a modified, unmodified, added and deleted data bag item" do
before do
- data_bag 'x', {
- 'added' => {},
- 'modified' => { 'foo' => 'bar' },
- 'unmodified' => {}
+ data_bag "x", {
+ "added" => {},
+ "modified" => { "foo" => "bar" },
+ "unmodified" => {},
}
end
- it 'knife download of the modified file succeeds' do
- knife('download /data_bags/x/modified.json').should_succeed <<EOM
+ it "knife download of the modified file succeeds" do
+ knife("download /data_bags/x/modified.json").should_succeed <<EOM
Updated /data_bags/x/modified.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/added.json
A\t/data_bags/x/deleted.json
EOM
end
- it 'knife download of the unmodified file does nothing' do
- knife('download /data_bags/x/unmodified.json').should_succeed ''
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ it "knife download of the unmodified file does nothing" do
+ knife("download /data_bags/x/unmodified.json").should_succeed ""
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/added.json
M\t/data_bags/x/modified.json
A\t/data_bags/x/deleted.json
EOM
end
- it 'knife download of the added file succeeds' do
- knife('download /data_bags/x/added.json').should_succeed <<EOM
+ it "knife download of the added file succeeds" do
+ knife("download /data_bags/x/added.json").should_succeed <<EOM
Created /data_bags/x/added.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
M\t/data_bags/x/modified.json
A\t/data_bags/x/deleted.json
EOM
end
- it 'knife download of the deleted file does nothing' do
- knife('download /data_bags/x/deleted.json').should_succeed ''
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ it "knife download of the deleted file does nothing" do
+ knife("download /data_bags/x/deleted.json").should_succeed ""
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/added.json
M\t/data_bags/x/modified.json
A\t/data_bags/x/deleted.json
EOM
end
- it 'knife download --purge of the deleted file deletes it' do
- knife('download --purge /data_bags/x/deleted.json').should_succeed <<EOM
+ it "knife download --purge of the deleted file deletes it" do
+ knife("download --purge /data_bags/x/deleted.json").should_succeed <<EOM
Deleted extra entry /data_bags/x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/added.json
M\t/data_bags/x/modified.json
EOM
end
- it 'knife download of the entire data bag downloads everything' do
- knife('download /data_bags/x').should_succeed <<EOM
+ it "knife download of the entire data bag downloads everything" do
+ knife("download /data_bags/x").should_succeed <<EOM
Created /data_bags/x/added.json
Updated /data_bags/x/modified.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
A\t/data_bags/x/deleted.json
EOM
end
- it 'knife download --purge of the entire data bag downloads everything' do
- knife('download --purge /data_bags/x').should_succeed <<EOM
+ it "knife download --purge of the entire data bag downloads everything" do
+ knife("download --purge /data_bags/x").should_succeed <<EOM
Created /data_bags/x/added.json
Updated /data_bags/x/modified.json
Deleted extra entry /data_bags/x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed ''
+ knife("diff --name-status /data_bags").should_succeed ""
end
- context 'when cwd is the /data_bags directory' do
+ context "when cwd is the /data_bags directory" do
before do
- cwd 'data_bags'
+ cwd "data_bags"
end
- it 'knife download fails' do
- knife('download').should_fail "FATAL: Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
+ it "knife download fails" do
+ knife("download").should_fail "FATAL: You must specify at least one argument. If you want to download everything in this directory, run \"knife download .\"\n", :stdout => /USAGE/
end
- it 'knife download --purge . downloads everything' do
- knife('download --purge .').should_succeed <<EOM
+ it "knife download --purge . downloads everything" do
+ knife("download --purge .").should_succeed <<EOM
Created x/added.json
Updated x/modified.json
Deleted extra entry x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed ''
+ knife("diff --name-status /data_bags").should_succeed ""
end
- it 'knife download --purge * downloads everything' do
- knife('download --purge *').should_succeed <<EOM
+ it "knife download --purge * downloads everything" do
+ knife("download --purge *").should_succeed <<EOM
Created x/added.json
Updated x/modified.json
Deleted extra entry x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed ''
+ knife("diff --name-status /data_bags").should_succeed ""
end
end
end
end
- when_the_repository 'has a cookbook' do
+ when_the_repository "has a cookbook" do
before do
- file 'cookbooks/x-1.0.0/metadata.rb', 'name "x"; version "1.0.0"#unmodified'
- file 'cookbooks/x-1.0.0/z.rb', ''
+ file "cookbooks/x-1.0.0/metadata.rb", 'name "x"; version "1.0.0"#unmodified'
+ file "cookbooks/x-1.0.0/z.rb", ""
end
- when_the_chef_server 'has a modified, added and deleted file for the cookbook' do
+ when_the_chef_server "has a modified, added and deleted file for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'y.rb' => 'hi' }
+ cookbook "x", "1.0.0", { "y.rb" => "hi" }
end
- it 'knife download of a modified file succeeds' do
- knife('download /cookbooks/x-1.0.0/metadata.rb').should_succeed "Updated /cookbooks/x-1.0.0/metadata.rb\n"
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife download of a modified file succeeds" do
+ knife("download /cookbooks/x-1.0.0/metadata.rb").should_succeed "Updated /cookbooks/x-1.0.0/metadata.rb\n"
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
D\t/cookbooks/x-1.0.0/y.rb
A\t/cookbooks/x-1.0.0/z.rb
EOM
end
- it 'knife download of a deleted file does nothing' do
- knife('download /cookbooks/x-1.0.0/z.rb').should_succeed ''
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife download of a deleted file does nothing" do
+ knife("download /cookbooks/x-1.0.0/z.rb").should_succeed ""
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
M\t/cookbooks/x-1.0.0/metadata.rb
D\t/cookbooks/x-1.0.0/y.rb
A\t/cookbooks/x-1.0.0/z.rb
EOM
end
- it 'knife download --purge of a deleted file succeeds' do
- knife('download --purge /cookbooks/x-1.0.0/z.rb').should_succeed "Deleted extra entry /cookbooks/x-1.0.0/z.rb (purge is on)\n"
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife download --purge of a deleted file succeeds" do
+ knife("download --purge /cookbooks/x-1.0.0/z.rb").should_succeed "Deleted extra entry /cookbooks/x-1.0.0/z.rb (purge is on)\n"
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
M\t/cookbooks/x-1.0.0/metadata.rb
D\t/cookbooks/x-1.0.0/y.rb
EOM
end
- it 'knife download of an added file succeeds' do
- knife('download /cookbooks/x-1.0.0/y.rb').should_succeed "Created /cookbooks/x-1.0.0/y.rb\n"
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife download of an added file succeeds" do
+ knife("download /cookbooks/x-1.0.0/y.rb").should_succeed "Created /cookbooks/x-1.0.0/y.rb\n"
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
M\t/cookbooks/x-1.0.0/metadata.rb
A\t/cookbooks/x-1.0.0/z.rb
EOM
end
- it 'knife download of the cookbook itself succeeds' do
- knife('download /cookbooks/x-1.0.0').should_succeed <<EOM
+ it "knife download of the cookbook itself succeeds" do
+ knife("download /cookbooks/x-1.0.0").should_succeed <<EOM
Updated /cookbooks/x-1.0.0/metadata.rb
Created /cookbooks/x-1.0.0/y.rb
EOM
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
A\t/cookbooks/x-1.0.0/z.rb
EOM
end
- it 'knife download --purge of the cookbook itself succeeds' do
- knife('download --purge /cookbooks/x-1.0.0').should_succeed <<EOM
+ it "knife download --purge of the cookbook itself succeeds" do
+ knife("download --purge /cookbooks/x-1.0.0").should_succeed <<EOM
Updated /cookbooks/x-1.0.0/metadata.rb
Created /cookbooks/x-1.0.0/y.rb
Deleted extra entry /cookbooks/x-1.0.0/z.rb (purge is on)
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
end
- when_the_repository 'has a cookbook' do
+ when_the_repository "has a cookbook" do
before do
- file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata("x", "1.0.0")
- file 'cookbooks/x-1.0.0/onlyin1.0.0.rb', 'old_text'
+ file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+ file "cookbooks/x-1.0.0/onlyin1.0.0.rb", "old_text"
end
- when_the_chef_server 'has a later version for the cookbook' do
+ when_the_chef_server "has a later version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
end
- it 'knife download /cookbooks/x downloads the latest version' do
- knife('download --purge /cookbooks').should_succeed <<EOM
+ it "knife download /cookbooks/x downloads the latest version" do
+ knife("download --purge /cookbooks").should_succeed <<EOM
Updated /cookbooks/x-1.0.0/onlyin1.0.0.rb
Created /cookbooks/x-1.0.1
Created /cookbooks/x-1.0.1/metadata.rb
Created /cookbooks/x-1.0.1/onlyin1.0.1.rb
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has an earlier version for the cookbook' do
+ when_the_chef_server "has an earlier version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
end
- it 'knife download /cookbooks downloads the updated file' do
- knife('download --purge /cookbooks').should_succeed <<EOM
+ it "knife download /cookbooks downloads the updated file" do
+ knife("download --purge /cookbooks").should_succeed <<EOM
Created /cookbooks/x-0.9.9
Created /cookbooks/x-0.9.9/metadata.rb
Created /cookbooks/x-0.9.9/onlyin0.9.9.rb
Updated /cookbooks/x-1.0.0/onlyin1.0.0.rb
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has a later version for the cookbook, and no current version' do
+ when_the_chef_server "has a later version for the cookbook, and no current version" do
before do
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
end
- it 'knife download /cookbooks/x downloads the latest version' do
- knife('download --purge /cookbooks').should_succeed <<EOM
+ it "knife download /cookbooks/x downloads the latest version" do
+ knife("download --purge /cookbooks").should_succeed <<EOM
Created /cookbooks/x-1.0.1
Created /cookbooks/x-1.0.1/metadata.rb
Created /cookbooks/x-1.0.1/onlyin1.0.1.rb
Deleted extra entry /cookbooks/x-1.0.0 (purge is on)
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
+ when_the_chef_server "has an earlier version for the cookbook, and no current version" do
before do
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
end
- it 'knife download --purge /cookbooks downloads the old version and deletes the new version' do
- knife('download --purge /cookbooks').should_succeed <<EOM
+ it "knife download --purge /cookbooks downloads the old version and deletes the new version" do
+ knife("download --purge /cookbooks").should_succeed <<EOM
Created /cookbooks/x-0.9.9
Created /cookbooks/x-0.9.9/metadata.rb
Created /cookbooks/x-0.9.9/onlyin0.9.9.rb
Deleted extra entry /cookbooks/x-1.0.0 (purge is on)
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
end
- when_the_chef_server 'has an environment' do
+ when_the_chef_server "has an environment" do
before do
- environment 'x', {}
+ environment "x", {}
end
- when_the_repository 'has the same environment with the wrong name in the file' do
+ when_the_repository "has the same environment with the wrong name in the file" do
before do
- file 'environments/x.json', { 'name' => 'y' }
+ file "environments/x.json", { "name" => "y" }
end
- it 'knife download succeeds' do
- knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n"
- knife('diff --name-status /environments/x.json').should_succeed ''
+ it "knife download succeeds" do
+ knife("download /environments/x.json").should_succeed "Updated /environments/x.json\n"
+ knife("diff --name-status /environments/x.json").should_succeed ""
end
end
- when_the_repository 'has the same environment with no name in the file' do
+ when_the_repository "has the same environment with no name in the file" do
before do
- file 'environments/x.json', { 'description' => 'hi' }
+ file "environments/x.json", { "description" => "hi" }
end
- it 'knife download succeeds' do
- knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n"
- knife('diff --name-status /environments/x.json').should_succeed ''
+ it "knife download succeeds" do
+ knife("download /environments/x.json").should_succeed "Updated /environments/x.json\n"
+ knife("diff --name-status /environments/x.json").should_succeed ""
end
end
end
end # with versioned cookbooks
- when_the_chef_server 'has a cookbook' do
+ when_the_chef_server "has a cookbook" do
before do
- cookbook 'x', '1.0.0'
+ cookbook "x", "1.0.0"
end
- when_the_repository 'is empty' do
- it 'knife download /cookbooks/x signs all requests' do
+ when_the_repository "is empty" do
+ it "knife download /cookbooks/x signs all requests" do
# Check that BasicClient.request() always gets called with X-OPS-USERID
original_new = Chef::HTTP::BasicClient.method(:new)
@@ -1077,13 +1096,13 @@ EOM
new_result = original_new.call(*args)
original_request = new_result.method(:request)
expect(new_result).to receive(:request) { |method, url, body, headers, &response_handler|
- expect(headers['X-OPS-USERID']).not_to be_nil
+ expect(headers["X-OPS-USERID"]).not_to be_nil
original_request.call(method, url, body, headers, &response_handler)
}.at_least(:once)
new_result
}.at_least(:once)
- knife('download /cookbooks/x').should_succeed <<EOM
+ knife("download /cookbooks/x").should_succeed <<EOM
Created /cookbooks
Created /cookbooks/x
Created /cookbooks/x/metadata.rb
@@ -1094,28 +1113,19 @@ EOM
when_the_chef_server "is in Enterprise mode", :osc_compat => false, :single_org => false do
before do
- organization 'foo' do
- container 'x', {}
- group 'x', {}
- end
+ user "foo", {}
+ user "bar", {}
+ user "foobar", {}
+ organization "foo", { "full_name" => "Something" }
end
before :each do
- Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo')
+ Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, "/organizations/foo")
end
- when_the_repository 'has existing top level files' do
- before do
- file 'invitations.json', {}
- end
- it "can still download top level files" do
- knife('download /invitations.json').should_succeed
- end
- end
-
- when_the_repository 'is empty' do
- it 'knife download / downloads everything' do
- knife('download /').should_succeed <<EOM
+ when_the_repository "has all the default stuff" do
+ before do
+ knife("download /").should_succeed <<EOM
Created /acls
Created /acls/clients
Created /acls/clients/foo-validator.json
@@ -1129,9 +1139,10 @@ Created /acls/containers/environments.json
Created /acls/containers/groups.json
Created /acls/containers/nodes.json
Created /acls/containers/policies.json
+Created /acls/containers/policy_groups.json
Created /acls/containers/roles.json
Created /acls/containers/sandboxes.json
-Created /acls/containers/x.json
+Created /acls/cookbook_artifacts
Created /acls/cookbooks
Created /acls/data_bags
Created /acls/environments
@@ -1141,8 +1152,9 @@ Created /acls/groups/admins.json
Created /acls/groups/billing-admins.json
Created /acls/groups/clients.json
Created /acls/groups/users.json
-Created /acls/groups/x.json
Created /acls/nodes
+Created /acls/policies
+Created /acls/policy_groups
Created /acls/roles
Created /acls/organization.json
Created /clients
@@ -1157,9 +1169,10 @@ Created /containers/environments.json
Created /containers/groups.json
Created /containers/nodes.json
Created /containers/policies.json
+Created /containers/policy_groups.json
Created /containers/roles.json
Created /containers/sandboxes.json
-Created /containers/x.json
+Created /cookbook_artifacts
Created /cookbooks
Created /data_bags
Created /environments
@@ -1169,14 +1182,151 @@ Created /groups/admins.json
Created /groups/billing-admins.json
Created /groups/clients.json
Created /groups/users.json
-Created /groups/x.json
Created /invitations.json
Created /members.json
Created /nodes
Created /org.json
+Created /policies
+Created /policy_groups
Created /roles
EOM
- knife('diff --name-status /').should_succeed ''
+ end
+
+ context "and the server has one of each thing" do
+ before do
+ # acl_for %w(organizations foo groups blah)
+ client "x", {}
+ cookbook "x", "1.0.0"
+ cookbook_artifact "x", "1x1", { "metadata.rb" => cb_metadata("x", "1.0.0") }
+ container "x", {}
+ data_bag "x", { "y" => {} }
+ environment "x", {}
+ group "x", {}
+ org_invite "foo"
+ org_member "bar"
+ node "x", {}
+ policy "x", "1.0.0", {}
+ policy "blah", "1.0.0", {}
+ policy_group "x", {
+ "policies" => {
+ "x" => { "revision_id" => "1.0.0" },
+ "blah" => { "revision_id" => "1.0.0" },
+ },
+ }
+ role "x", {}
+ end
+
+ before do
+ knife("download /acls /groups/clients.json /groups/users.json").should_succeed <<-EOM
+Created /acls/clients/x.json
+Created /acls/containers/x.json
+Created /acls/cookbook_artifacts/x.json
+Created /acls/cookbooks/x.json
+Created /acls/data_bags/x.json
+Created /acls/environments/x.json
+Created /acls/groups/x.json
+Created /acls/nodes/x.json
+Created /acls/policies/blah.json
+Created /acls/policies/x.json
+Created /acls/policy_groups/x.json
+Created /acls/roles/x.json
+Updated /groups/clients.json
+Updated /groups/users.json
+EOM
+ end
+
+ it "knife download / downloads everything" do
+ knife("download /").should_succeed <<EOM
+Created /clients/x.json
+Created /containers/x.json
+Created /cookbook_artifacts/x-1x1
+Created /cookbook_artifacts/x-1x1/metadata.rb
+Created /cookbooks/x
+Created /cookbooks/x/metadata.rb
+Created /data_bags/x
+Created /data_bags/x/y.json
+Created /environments/x.json
+Created /groups/x.json
+Updated /invitations.json
+Updated /members.json
+Created /nodes/x.json
+Created /policies/blah-1.0.0.json
+Created /policies/x-1.0.0.json
+Created /policy_groups/x.json
+Created /roles/x.json
+EOM
+ knife("diff --name-status /").should_succeed ""
+ end
+
+ context "and the repository has an identical copy of each thing" do
+ before do
+ # TODO We have to upload acls for an existing group due to a lack of
+ # dependency detection during upload. Fix that!
+ file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "containers/x.json", {}
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ file "cookbook_artifacts/x-1x1/metadata.rb", cb_metadata("x", "1.0.0")
+ file "data_bags/x/y.json", {}
+ file "environments/x.json", {}
+ file "groups/x.json", {}
+ file "invitations.json", [ "foo" ]
+ file "members.json", [ "bar" ]
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
+ file "org.json", { "full_name" => "Something" }
+ file "policies/x-1.0.0.json", {}
+ file "policies/blah-1.0.0.json", {}
+ file "policy_groups/x.json", { "policies" => { "x" => { "revision_id" => "1.0.0" }, "blah" => { "revision_id" => "1.0.0" } } }
+ file "roles/x.json", {}
+ end
+
+ it "knife download makes no changes" do
+ knife("download /").should_succeed ""
+ end
+ end
+
+ context "and the repository has a slightly different copy of each thing" do
+ before do
+ # acl_for %w(organizations foo groups blah)
+ file "clients/x.json", { "validator" => true }
+ file "containers/x.json", {}
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.1")
+ file "cookbook_artifacts/x-1x1/metadata.rb", cb_metadata("x", "1.0.1")
+ file "data_bags/x/y.json", { "a" => "b" }
+ file "environments/x.json", { "description" => "foo" }
+ file "groups/x.json", { "description" => "foo" }
+ file "groups/x.json", { "groups" => [ "admin" ] }
+ file "nodes/x.json", { "normal" => { "tags" => [] }, "run_list" => [ "blah" ] }
+ file "org.json", { "full_name" => "Something Else " }
+ file "policies/x-1.0.0.json", { "run_list" => [ "blah" ] }
+ file "policy_groups/x.json", {
+ "policies" => {
+ "x" => { "revision_id" => "1.0.1" },
+ "y" => { "revision_id" => "1.0.0" },
+ },
+ }
+ file "roles/x.json", { "run_list" => [ "blah" ] }
+ end
+
+ it "knife download updates everything" do
+ knife("download /").should_succeed <<EOM
+Updated /clients/x.json
+Updated /cookbook_artifacts/x-1x1/metadata.rb
+Updated /cookbooks/x/metadata.rb
+Updated /data_bags/x/y.json
+Updated /environments/x.json
+Updated /groups/x.json
+Updated /invitations.json
+Updated /members.json
+Updated /nodes/x.json
+Updated /org.json
+Created /policies/blah-1.0.0.json
+Updated /policies/x-1.0.0.json
+Updated /policy_groups/x.json
+Updated /roles/x.json
+EOM
+ knife("diff --name-status /").should_succeed ""
+ end
+ end
end
end
end
diff --git a/spec/integration/knife/environment_compare_spec.rb b/spec/integration/knife/environment_compare_spec.rb
new file mode 100644
index 0000000000..3259b27d1b
--- /dev/null
+++ b/spec/integration/knife/environment_compare_spec.rb
@@ -0,0 +1,74 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife environment compare", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some environments" do
+ before do
+ cookbook "blah", "1.0.1"
+ cookbook "blah", "1.1.1"
+ cookbook "krad", "1.1.1"
+ environment "x", {
+ "cookbook_versions" => {
+ "blah" => "= 1.0.0",
+ "krad" => ">= 1.0.0",
+ },
+ }
+ environment "y", {
+ "cookbook_versions" => {
+ "blah" => "= 1.1.0",
+ "krad" => ">= 1.0.0",
+ },
+ }
+ end
+
+ # rubocop:disable Style/TrailingWhitespace
+ it "displays the cookbooks for a single environment" do
+ knife("environment compare x").should_succeed <<EOM
+ x
+blah = 1.0.0
+krad >= 1.0.0
+
+EOM
+ end
+
+ it "compares the cookbooks for two environments" do
+ knife("environment compare x y").should_succeed <<EOM
+ x y
+blah = 1.0.0 = 1.1.0
+krad >= 1.0.0 >= 1.0.0
+
+EOM
+ end
+
+ it "compares the cookbooks for all environments" do
+ knife("environment compare --all").should_succeed <<EOM
+ x y
+blah = 1.0.0 = 1.1.0
+krad >= 1.0.0 >= 1.0.0
+
+EOM
+ end
+ # rubocop:enable Style/TrailingWhitespace
+ end
+end
diff --git a/spec/integration/knife/environment_create_spec.rb b/spec/integration/knife/environment_create_spec.rb
new file mode 100644
index 0000000000..03fd4e63f7
--- /dev/null
+++ b/spec/integration/knife/environment_create_spec.rb
@@ -0,0 +1,40 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife environment create", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:out) { "Created bah\n" }
+
+ when_the_chef_server "is empty" do
+ it "creates a new environment" do
+ knife("environment create bah").should_succeed out
+ end
+
+ it "refuses to add an existing environment" do
+ pending "Knife environment create must not blindly overwrite an existing environment"
+ knife("environment create bah").should_succeed out
+ expect { knife("environment create bah") }.to raise_error(Net::HTTPServerException)
+ end
+
+ end
+end
diff --git a/spec/integration/knife/environment_delete_spec.rb b/spec/integration/knife/environment_delete_spec.rb
new file mode 100644
index 0000000000..0f1fe5c4a8
--- /dev/null
+++ b/spec/integration/knife/environment_delete_spec.rb
@@ -0,0 +1,36 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife environment delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has an environment" do
+ before do
+ environment "y", {}
+ end
+
+ it "deletes an environment" do
+ knife("environment delete y", input: "y").should_succeed "Do you really want to delete y? (Y/N) Deleted y\n"
+ end
+
+ end
+end
diff --git a/spec/integration/knife/environment_from_file_spec.rb b/spec/integration/knife/environment_from_file_spec.rb
new file mode 100644
index 0000000000..67d4373939
--- /dev/null
+++ b/spec/integration/knife/environment_from_file_spec.rb
@@ -0,0 +1,115 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife environment from file", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ # include_context "default config options"
+
+ let (:env_dir) { "#{@repository_dir}/environments" }
+
+ when_the_chef_server "is empty" do
+ when_the_repository "has some environments" do
+ before do
+
+ file "environments/cons.json", <<EOM
+{
+ "name": "cons",
+ "description": "An environment",
+ "cookbook_versions": {
+
+ },
+ "json_class": "Chef::Environment",
+ "chef_type": "environment",
+ "default_attributes": {
+ "hola": "Amigos!"
+ },
+ "override_attributes": {
+
+ }
+}
+EOM
+
+ file "environments/car.json", <<EOM
+{
+ "name": "car",
+ "description": "An environment for list nodes",
+ "cookbook_versions": {
+
+ },
+ "json_class": "Chef::Environment",
+ "chef_type": "environment",
+ "default_attributes": {
+ "hola": "Amigos!"
+ },
+ "override_attributes": {
+
+ }
+}
+EOM
+
+ file "environments/cdr.json", <<EOM
+{
+ "name": "cdr",
+ "description": "An environment for last nodes",
+ "cookbook_versions": {
+
+ },
+ "json_class": "Chef::Environment",
+ "chef_type": "environment",
+ "default_attributes": {
+ "hola": "Amigos!"
+ },
+ "override_attributes": {
+
+ }
+}
+EOM
+
+ end
+
+ it "uploads a single file" do
+ knife("environment from file #{env_dir}/cons.json").should_succeed stderr: <<EOM
+Updated Environment cons
+EOM
+ end
+
+ it "uploads many files" do
+ knife("environment from file #{env_dir}/cons.json #{env_dir}/car.json #{env_dir}/cdr.json").should_succeed stderr: <<EOM
+Updated Environment cons
+Updated Environment car
+Updated Environment cdr
+EOM
+ end
+
+ it "uploads all environments in the repository" do
+ cwd(".")
+ knife("environment from file --all")
+ knife("environment list").should_succeed <<EOM
+_default
+car
+cdr
+cons
+EOM
+ end
+
+ end
+ end
+end
diff --git a/spec/integration/knife/environment_list_spec.rb b/spec/integration/knife/environment_list_spec.rb
new file mode 100644
index 0000000000..5e74453d1f
--- /dev/null
+++ b/spec/integration/knife/environment_list_spec.rb
@@ -0,0 +1,41 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife environment list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some environments" do
+ before do
+ environment "b", {}
+ environment "y", {}
+ end
+
+ it "lists all the environments" do
+ knife("environment list").should_succeed <<EOM
+_default
+b
+y
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/environment_show_spec.rb b/spec/integration/knife/environment_show_spec.rb
new file mode 100644
index 0000000000..56422dc1a5
--- /dev/null
+++ b/spec/integration/knife/environment_show_spec.rb
@@ -0,0 +1,76 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife environment show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some environments" do
+ before do
+ environment "b", {
+ "default_attributes" => { "foo" => "bar", "baz" => { "raz.my" => "mataz" } },
+ }
+ end
+
+ # rubocop:disable Style/TrailingWhitespace
+ it "shows an environment" do
+ knife("environment show b").should_succeed <<EOM
+chef_type: environment
+cookbook_versions:
+default_attributes:
+ baz:
+ raz.my: mataz
+ foo: bar
+description:
+json_class: Chef::Environment
+name: b
+override_attributes:
+EOM
+ end
+ # rubocop:enable Style/TrailingWhitespace
+
+ it "shows the requested attribute of an environment" do
+ knife("environment show b -a default_attributes").should_succeed <<EOM
+b:
+ default_attributes:
+ baz:
+ raz.my: mataz
+ foo: bar
+EOM
+ end
+
+ it "shows the requested nested attribute of an environment" do
+ knife("environment show b -a default_attributes.baz").should_succeed <<EON
+b:
+ default_attributes.baz:
+ raz.my: mataz
+EON
+ end
+
+ it "shows the requested attribute of an environment with custom field separator" do
+ knife("environment show b -S: -a default_attributes:baz").should_succeed <<EOT
+b:
+ default_attributes:baz:
+ raz.my: mataz
+EOT
+ end
+ end
+end
diff --git a/spec/integration/knife/list_spec.rb b/spec/integration/knife/list_spec.rb
index b289642c7d..4aa74f3f0e 100644
--- a/spec/integration/knife/list_spec.rb
+++ b/spec/integration/knife/list_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,11 +15,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'support/shared/context/config'
-require 'chef/knife/list'
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/list"
-describe 'knife list', :workstation do
+describe "knife list", :workstation do
include IntegrationSupport
include KnifeSupport
@@ -27,7 +27,7 @@ describe 'knife list', :workstation do
when_the_chef_server "is empty" do
it "knife list / returns all top level directories" do
- knife('list /').should_succeed <<EOM
+ knife("list /").should_succeed <<-EOM
/clients
/cookbooks
/data_bags
@@ -39,7 +39,7 @@ EOM
end
it "knife list -R / returns everything" do
- knife('list -R /').should_succeed <<EOM
+ knife("list -R /").should_succeed <<-EOM
/:
clients
cookbooks
@@ -72,24 +72,27 @@ EOM
when_the_chef_server "has plenty of stuff in it" do
before do
- client 'client1', {}
- client 'client2', {}
- cookbook 'cookbook1', '1.0.0'
- cookbook 'cookbook2', '1.0.1', { 'recipes' => { 'default.rb' => '' } }
- data_bag 'bag1', { 'item1' => {}, 'item2' => {} }
- data_bag 'bag2', { 'item1' => {}, 'item2' => {} }
- environment 'environment1', {}
- environment 'environment2', {}
- node 'node1', {}
- node 'node2', {}
- role 'role1', {}
- role 'role2', {}
- user 'user1', {}
- user 'user2', {}
+ client "client1", {}
+ client "client2", {}
+ cookbook "cookbook1", "1.0.0"
+ cookbook "cookbook2", "1.0.1", { "recipes" => { "default.rb" => "" } }
+ data_bag "bag1", { "item1" => {}, "item2" => {} }
+ data_bag "bag2", { "item1" => {}, "item2" => {} }
+ environment "environment1", {}
+ environment "environment2", {}
+ node "node1", {}
+ node "node2", {}
+ policy "policy1", "1.2.3", {}
+ policy "policy2", "1.2.3", {}
+ policy "policy2", "1.3.5", {}
+ role "role1", {}
+ role "role2", {}
+ user "user1", {}
+ user "user2", {}
end
it "knife list / returns all top level directories" do
- knife('list /').should_succeed <<EOM
+ knife("list /").should_succeed <<-EOM
/clients
/cookbooks
/data_bags
@@ -101,7 +104,7 @@ EOM
end
it "knife list -R / returns everything" do
- knife('list -R /').should_succeed <<EOM
+ knife("list -R /").should_succeed <<-EOM
/:
clients
cookbooks
@@ -164,7 +167,7 @@ EOM
end
it "knife list -R --flat / returns everything" do
- knife('list -R --flat /').should_succeed <<EOM
+ knife("list -R --flat /").should_succeed <<-EOM
/clients
/clients/chef-validator.json
/clients/chef-webui.json
@@ -202,7 +205,7 @@ EOM
end
it "knife list -Rfp / returns everything" do
- knife('list -Rfp /').should_succeed <<EOM
+ knife("list -Rfp /").should_succeed <<-EOM
/clients/
/clients/chef-validator.json
/clients/chef-webui.json
@@ -240,18 +243,18 @@ EOM
end
it "knife list /cookbooks returns the list of cookbooks" do
- knife('list /cookbooks').should_succeed <<EOM
+ knife("list /cookbooks").should_succeed <<-EOM
/cookbooks/cookbook1
/cookbooks/cookbook2
EOM
end
it "knife list /cookbooks/*2/*/*.rb returns the one file" do
- knife('list /cookbooks/*2/*/*.rb').should_succeed "/cookbooks/cookbook2/recipes/default.rb\n"
+ knife("list /cookbooks/*2/*/*.rb").should_succeed "/cookbooks/cookbook2/recipes/default.rb\n"
end
it "knife list /**.rb returns all ruby files" do
- knife('list /**.rb').should_succeed <<EOM
+ knife("list /**.rb").should_succeed <<-EOM
/cookbooks/cookbook1/metadata.rb
/cookbooks/cookbook2/metadata.rb
/cookbooks/cookbook2/recipes/default.rb
@@ -259,7 +262,7 @@ EOM
end
it "knife list /cookbooks/**.rb returns all ruby files" do
- knife('list /cookbooks/**.rb').should_succeed <<EOM
+ knife("list /cookbooks/**.rb").should_succeed <<-EOM
/cookbooks/cookbook1/metadata.rb
/cookbooks/cookbook2/metadata.rb
/cookbooks/cookbook2/recipes/default.rb
@@ -267,7 +270,7 @@ EOM
end
it "knife list /**.json returns all json files" do
- knife('list /**.json').should_succeed <<EOM
+ knife("list /**.json").should_succeed <<-EOM
/clients/chef-validator.json
/clients/chef-webui.json
/clients/client1.json
@@ -290,7 +293,7 @@ EOM
end
it "knife list /data**.json returns all data bag json files" do
- knife('list /data**.json').should_succeed <<EOM
+ knife("list /data**.json").should_succeed <<-EOM
/data_bags/bag1/item1.json
/data_bags/bag1/item2.json
/data_bags/bag2/item1.json
@@ -299,30 +302,22 @@ EOM
end
it "knife list /environments/missing_file.json reports missing file" do
- knife('list /environments/missing_file.json').should_fail "ERROR: /environments/missing_file.json: No such file or directory\n"
+ knife("list /environments/missing_file.json").should_fail "ERROR: /environments/missing_file.json: No such file or directory\n"
end
context "missing file/directory exact match tests" do
it "knife list /blarghle reports missing directory" do
- knife('list /blarghle').should_fail "ERROR: /blarghle: No such file or directory\n"
- end
-
- it "knife list /roles/blarghle reports missing directory" do
- knife('list /roles/blarghle').should_fail "ERROR: /roles/blarghle: No such file or directory\n"
- end
-
- it "knife list /roles/blarghle/blorghle reports missing directory" do
- knife('list /roles/blarghle/blorghle').should_fail "ERROR: /roles/blarghle/blorghle: No such file or directory\n"
+ knife("list /blarghle").should_fail "ERROR: /blarghle: No such file or directory\n"
end
end
- context 'symlink tests' do
- when_the_repository 'is empty' do
- context 'when cwd is at the top of the repository' do
- before { cwd '.' }
+ context "symlink tests" do
+ when_the_repository "is empty" do
+ context "when cwd is at the top of the repository" do
+ before { cwd "." }
it "knife list -Rfp returns everything" do
- knife('list -Rfp').should_succeed <<EOM
+ knife("list -Rfp").should_succeed <<-EOM
clients/
clients/chef-validator.json
clients/chef-webui.json
@@ -361,13 +356,13 @@ EOM
end
end
- when_the_repository 'has a cookbooks directory' do
- before { directory 'cookbooks' }
- context 'when cwd is in cookbooks/' do
- before { cwd 'cookbooks' }
+ when_the_repository "has a cookbooks directory" do
+ before { directory "cookbooks" }
+ context "when cwd is in cookbooks/" do
+ before { cwd "cookbooks" }
it "knife list -Rfp / returns everything" do
- knife('list -Rfp /').should_succeed <<EOM
+ knife("list -Rfp /").should_succeed <<-EOM
/clients/
/clients/chef-validator.json
/clients/chef-webui.json
@@ -405,7 +400,7 @@ EOM
end
it "knife list -Rfp .. returns everything" do
- knife('list -Rfp ..').should_succeed <<EOM
+ knife("list -Rfp ..").should_succeed <<-EOM
/clients/
/clients/chef-validator.json
/clients/chef-webui.json
@@ -443,7 +438,7 @@ EOM
end
it "knife list -Rfp returns cookbooks" do
- knife('list -Rfp').should_succeed <<EOM
+ knife("list -Rfp").should_succeed <<-EOM
cookbook1/
cookbook1/metadata.rb
cookbook2/
@@ -455,14 +450,14 @@ EOM
end
end
- when_the_repository 'has a cookbooks/cookbook2 directory' do
- before { directory 'cookbooks/cookbook2' }
+ when_the_repository "has a cookbooks/cookbook2 directory" do
+ before { directory "cookbooks/cookbook2" }
- context 'when cwd is in cookbooks/cookbook2' do
- before { cwd 'cookbooks/cookbook2' }
+ context "when cwd is in cookbooks/cookbook2" do
+ before { cwd "cookbooks/cookbook2" }
it "knife list -Rfp returns cookbooks" do
- knife('list -Rfp').should_succeed <<EOM
+ knife("list -Rfp").should_succeed <<-EOM
metadata.rb
recipes/
recipes/default.rb
@@ -471,17 +466,17 @@ EOM
end
end
- when_the_repository 'has a cookbooks directory and a symlinked cookbooks directory', :skip => (Chef::Platform.windows?) do
+ when_the_repository "has a cookbooks directory and a symlinked cookbooks directory", :skip => (Chef::Platform.windows?) do
before do
- directory 'cookbooks'
- symlink 'symlinked', 'cookbooks'
+ directory "cookbooks"
+ symlink "symlinked", "cookbooks"
end
- context 'when cwd is in cookbooks/' do
- before { cwd 'cookbooks' }
+ context "when cwd is in cookbooks/" do
+ before { cwd "cookbooks" }
it "knife list -Rfp returns cookbooks" do
- knife('list -Rfp').should_succeed <<EOM
+ knife("list -Rfp").should_succeed <<-EOM
cookbook1/
cookbook1/metadata.rb
cookbook2/
@@ -492,11 +487,11 @@ EOM
end
end
- context 'when cwd is in symlinked/' do
- before { cwd 'symlinked' }
+ context "when cwd is in symlinked/" do
+ before { cwd "symlinked" }
it "knife list -Rfp returns cookbooks" do
- knife('list -Rfp').should_succeed <<EOM
+ knife("list -Rfp").should_succeed <<-EOM
cookbook1/
cookbook1/metadata.rb
cookbook2/
@@ -508,17 +503,17 @@ EOM
end
end
- when_the_repository 'has a real_cookbooks directory and a cookbooks symlink to it', :skip => (Chef::Platform.windows?) do
+ when_the_repository "has a real_cookbooks directory and a cookbooks symlink to it", :skip => (Chef::Platform.windows?) do
before do
- directory 'real_cookbooks'
- symlink 'cookbooks', 'real_cookbooks'
+ directory "real_cookbooks"
+ symlink "cookbooks", "real_cookbooks"
end
- context 'when cwd is in real_cookbooks/' do
- before { cwd 'real_cookbooks' }
+ context "when cwd is in real_cookbooks/" do
+ before { cwd "real_cookbooks" }
it "knife list -Rfp returns cookbooks" do
- knife('list -Rfp').should_succeed <<EOM
+ knife("list -Rfp").should_succeed <<-EOM
cookbook1/
cookbook1/metadata.rb
cookbook2/
@@ -529,11 +524,11 @@ EOM
end
end
- context 'when cwd is in cookbooks/' do
- before { cwd 'cookbooks' }
+ context "when cwd is in cookbooks/" do
+ before { cwd "cookbooks" }
it "knife list -Rfp returns cookbooks" do
- knife('list -Rfp').should_succeed <<EOM
+ knife("list -Rfp").should_succeed <<-EOM
cookbook1/
cookbook1/metadata.rb
cookbook2/
@@ -550,50 +545,51 @@ EOM
context "--local" do
when_the_repository "is empty" do
it "knife list --local / returns nothing" do
- knife('list --local /').should_succeed ""
+ knife("list --local /").should_succeed ""
end
it "knife list /roles returns nothing" do
- knife('list --local /roles').should_fail "ERROR: /roles: No such file or directory\n"
+ knife("list --local /roles").should_fail "ERROR: /roles: No such file or directory\n"
end
end
when_the_repository "has a bunch of stuff" do
before do
- file 'clients/client1.json', {}
- file 'clients/client2.json', {}
+ file "clients/client1.json", {}
+ file "clients/client2.json", {}
- directory 'cookbooks/cookbook1' do
- file 'metadata.rb', cb_metadata("cookbook1", "1.0.0")
+ directory "cookbooks/cookbook1" do
+ file "metadata.rb", cb_metadata("cookbook1", "1.0.0")
end
- directory 'cookbooks/cookbook2' do
- file 'metadata.rb', cb_metadata("cookbook2", "2.0.0")
- file 'recipes/default.rb', ''
+ directory "cookbooks/cookbook2" do
+ file "metadata.rb", cb_metadata("cookbook2", "2.0.0")
+ file "recipes/default.rb", ""
end
- directory 'data_bags' do
- directory 'bag1' do
- file 'item1.json', {}
- file 'item2.json', {}
+ directory "data_bags" do
+ directory "bag1" do
+ file "item1.json", {}
+ file "item2.json", {}
end
- directory 'bag2' do
- file 'item1.json', {}
- file 'item2.json', {}
+ directory "bag2" do
+ file "item1.json", {}
+ file "item2.json", {}
end
end
- file 'environments/environment1.json', {}
- file 'environments/environment2.json', {}
- file 'nodes/node1.json', {}
- file 'nodes/node2.json', {}
- file 'roles/role1.json', {}
- file 'roles/role2.json', {}
- file 'users/user1.json', {}
- file 'users/user2.json', {}
+ file "environments/environment1.json", {}
+ file "environments/environment2.json", {}
+ file "nodes/node1.json", {}
+ file "nodes/node2.json", {}
+
+ file "roles/role1.json", {}
+ file "roles/role2.json", {}
+ file "users/user1.json", {}
+ file "users/user2.json", {}
end
it "knife list -Rfp / returns everything" do
- knife('list -Rp --local --flat /').should_succeed <<EOM
+ knife("list -Rp --local --flat /").should_succeed <<-EOM
/clients/
/clients/client1.json
/clients/client2.json
@@ -628,15 +624,15 @@ EOM
context "missing file/directory tests" do
it "knife list --local /blarghle reports missing directory" do
- knife('list --local /blarghle').should_fail "ERROR: /blarghle: No such file or directory\n"
+ knife("list --local /blarghle").should_fail "ERROR: /blarghle: No such file or directory\n"
end
it "knife list /roles/blarghle reports missing directory" do
- knife('list --local /roles/blarghle').should_fail "ERROR: /roles/blarghle: No such file or directory\n"
+ knife("list --local /roles/blarghle").should_fail "ERROR: /roles/blarghle: No such file or directory\n"
end
it "knife list /roles/blarghle/blorghle reports missing directory" do
- knife('list --local /roles/blarghle/blorghle').should_fail "ERROR: /roles/blarghle/blorghle: No such file or directory\n"
+ knife("list --local /roles/blarghle/blorghle").should_fail "ERROR: /roles/blarghle/blorghle: No such file or directory\n"
end
end
end
@@ -644,19 +640,20 @@ EOM
when_the_chef_server "is in Enterprise mode", :osc_compat => false, :single_org => false do
before do
- organization 'foo'
+ organization "foo"
end
before :each do
- Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo')
+ Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, "/organizations/foo")
end
- context 'and is empty' do
+ context "and is empty" do
it "knife list / returns all top level directories" do
- knife('list /').should_succeed <<EOM
+ knife("list /").should_succeed <<-EOM
/acls
/clients
/containers
+/cookbook_artifacts
/cookbooks
/data_bags
/environments
@@ -665,16 +662,19 @@ EOM
/members.json
/nodes
/org.json
+/policies
+/policy_groups
/roles
EOM
end
it "knife list -R / returns everything" do
- knife('list -R /').should_succeed <<EOM
+ knife("list -R /").should_succeed <<-EOM
/:
acls
clients
containers
+cookbook_artifacts
cookbooks
data_bags
environments
@@ -683,17 +683,22 @@ invitations.json
members.json
nodes
org.json
+policies
+policy_groups
roles
/acls:
clients
containers
+cookbook_artifacts
cookbooks
data_bags
environments
groups
nodes
organization.json
+policies
+policy_groups
roles
/acls/clients:
@@ -709,9 +714,12 @@ environments.json
groups.json
nodes.json
policies.json
+policy_groups.json
roles.json
sandboxes.json
+/acls/cookbook_artifacts:
+
/acls/cookbooks:
/acls/data_bags:
@@ -727,6 +735,10 @@ users.json
/acls/nodes:
+/acls/policies:
+
+/acls/policy_groups:
+
/acls/roles:
/clients:
@@ -742,9 +754,12 @@ environments.json
groups.json
nodes.json
policies.json
+policy_groups.json
roles.json
sandboxes.json
+/cookbook_artifacts:
+
/cookbooks:
/data_bags:
@@ -760,27 +775,22 @@ users.json
/nodes:
+/policies:
+
+/policy_groups:
+
/roles:
EOM
end
end
- end
-
- when_the_chef_server "is in Enterprise mode", :osc_compat => false, :single_org => false do
- before do
- organization 'foo'
- end
- before :each do
- Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo')
- end
-
- it 'knife list -R / returns everything' do
- knife('list -R /').should_succeed <<EOM
+ it "knife list -R / returns everything" do
+ knife("list -R /").should_succeed <<-EOM
/:
acls
clients
containers
+cookbook_artifacts
cookbooks
data_bags
environments
@@ -789,17 +799,22 @@ invitations.json
members.json
nodes
org.json
+policies
+policy_groups
roles
/acls:
clients
containers
+cookbook_artifacts
cookbooks
data_bags
environments
groups
nodes
organization.json
+policies
+policy_groups
roles
/acls/clients:
@@ -815,9 +830,12 @@ environments.json
groups.json
nodes.json
policies.json
+policy_groups.json
roles.json
sandboxes.json
+/acls/cookbook_artifacts:
+
/acls/cookbooks:
/acls/data_bags:
@@ -833,6 +851,10 @@ users.json
/acls/nodes:
+/acls/policies:
+
+/acls/policy_groups:
+
/acls/roles:
/clients:
@@ -848,9 +870,12 @@ environments.json
groups.json
nodes.json
policies.json
+policy_groups.json
roles.json
sandboxes.json
+/cookbook_artifacts:
+
/cookbooks:
/data_bags:
@@ -866,8 +891,169 @@ users.json
/nodes:
+/policies:
+
+/policy_groups:
+
/roles:
EOM
end
+
+ context "has plenty of stuff in it" do
+ before do
+ client "client1", {}
+ client "client2", {}
+ container "container1", {}
+ container "container2", {}
+ cookbook "cookbook1", "1.0.0"
+ cookbook "cookbook2", "1.0.1", { "recipes" => { "default.rb" => "" } }
+ cookbook_artifact "cookbook_artifact1", "1x1"
+ cookbook_artifact "cookbook_artifact2", "2x2", { "recipes" => { "default.rb" => "" } }
+ data_bag "bag1", { "item1" => {}, "item2" => {} }
+ data_bag "bag2", { "item1" => {}, "item2" => {} }
+ environment "environment1", {}
+ environment "environment2", {}
+ group "group1", {}
+ group "group2", {}
+ node "node1", {}
+ node "node2", {}
+ org_invite "user1"
+ org_member "user2"
+ policy "policy1", "1.2.3", {}
+ policy "policy2", "1.2.3", {}
+ policy "policy2", "1.3.5", {}
+ policy_group "policy_group1", { "policies" => { "policy1" => { "revision_id" => "1.2.3" } } }
+ policy_group "policy_group2", { "policies" => { "policy2" => { "revision_id" => "1.3.5" } } }
+ role "role1", {}
+ role "role2", {}
+ user "user1", {}
+ user "user2", {}
+ end
+
+ it "knife list -Rfp / returns everything" do
+ knife("list -Rfp /").should_succeed <<-EOM
+/acls/
+/acls/clients/
+/acls/clients/client1.json
+/acls/clients/client2.json
+/acls/clients/foo-validator.json
+/acls/containers/
+/acls/containers/clients.json
+/acls/containers/container1.json
+/acls/containers/container2.json
+/acls/containers/containers.json
+/acls/containers/cookbook_artifacts.json
+/acls/containers/cookbooks.json
+/acls/containers/data.json
+/acls/containers/environments.json
+/acls/containers/groups.json
+/acls/containers/nodes.json
+/acls/containers/policies.json
+/acls/containers/policy_groups.json
+/acls/containers/roles.json
+/acls/containers/sandboxes.json
+/acls/cookbook_artifacts/
+/acls/cookbook_artifacts/cookbook_artifact1.json
+/acls/cookbook_artifacts/cookbook_artifact2.json
+/acls/cookbooks/
+/acls/cookbooks/cookbook1.json
+/acls/cookbooks/cookbook2.json
+/acls/data_bags/
+/acls/data_bags/bag1.json
+/acls/data_bags/bag2.json
+/acls/environments/
+/acls/environments/_default.json
+/acls/environments/environment1.json
+/acls/environments/environment2.json
+/acls/groups/
+/acls/groups/admins.json
+/acls/groups/billing-admins.json
+/acls/groups/clients.json
+/acls/groups/group1.json
+/acls/groups/group2.json
+/acls/groups/users.json
+/acls/nodes/
+/acls/nodes/node1.json
+/acls/nodes/node2.json
+/acls/organization.json
+/acls/policies/
+/acls/policies/policy1.json
+/acls/policies/policy2.json
+/acls/policy_groups/
+/acls/policy_groups/policy_group1.json
+/acls/policy_groups/policy_group2.json
+/acls/roles/
+/acls/roles/role1.json
+/acls/roles/role2.json
+/clients/
+/clients/client1.json
+/clients/client2.json
+/clients/foo-validator.json
+/containers/
+/containers/clients.json
+/containers/container1.json
+/containers/container2.json
+/containers/containers.json
+/containers/cookbook_artifacts.json
+/containers/cookbooks.json
+/containers/data.json
+/containers/environments.json
+/containers/groups.json
+/containers/nodes.json
+/containers/policies.json
+/containers/policy_groups.json
+/containers/roles.json
+/containers/sandboxes.json
+/cookbook_artifacts/
+/cookbook_artifacts/cookbook_artifact1-1x1/
+/cookbook_artifacts/cookbook_artifact1-1x1/metadata.rb
+/cookbook_artifacts/cookbook_artifact2-2x2/
+/cookbook_artifacts/cookbook_artifact2-2x2/metadata.rb
+/cookbook_artifacts/cookbook_artifact2-2x2/recipes/
+/cookbook_artifacts/cookbook_artifact2-2x2/recipes/default.rb
+/cookbooks/
+/cookbooks/cookbook1/
+/cookbooks/cookbook1/metadata.rb
+/cookbooks/cookbook2/
+/cookbooks/cookbook2/metadata.rb
+/cookbooks/cookbook2/recipes/
+/cookbooks/cookbook2/recipes/default.rb
+/data_bags/
+/data_bags/bag1/
+/data_bags/bag1/item1.json
+/data_bags/bag1/item2.json
+/data_bags/bag2/
+/data_bags/bag2/item1.json
+/data_bags/bag2/item2.json
+/environments/
+/environments/_default.json
+/environments/environment1.json
+/environments/environment2.json
+/groups/
+/groups/admins.json
+/groups/billing-admins.json
+/groups/clients.json
+/groups/group1.json
+/groups/group2.json
+/groups/users.json
+/invitations.json
+/members.json
+/nodes/
+/nodes/node1.json
+/nodes/node2.json
+/org.json
+/policies/
+/policies/policy1-1.2.3.json
+/policies/policy2-1.2.3.json
+/policies/policy2-1.3.5.json
+/policy_groups/
+/policy_groups/policy_group1.json
+/policy_groups/policy_group2.json
+/roles/
+/roles/role1.json
+/roles/role2.json
+EOM
+ end
+ end
end
end
diff --git a/spec/integration/knife/node_bulk_delete_spec.rb b/spec/integration/knife/node_bulk_delete_spec.rb
new file mode 100644
index 0000000000..fa706cbd2b
--- /dev/null
+++ b/spec/integration/knife/node_bulk_delete_spec.rb
@@ -0,0 +1,51 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node bulk delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some nodes" do
+ before do
+ node "cons", {}
+ node "car", {}
+ node "cdr", {}
+ node "cat", {}
+ end
+
+ it "deletes all matching nodes" do
+ knife("node bulk delete ^ca.*", input: "Y").should_succeed <<EOM
+The following nodes will be deleted:
+
+car cat
+
+Are you sure you want to delete these nodes? (Y/N) Deleted node car
+Deleted node cat
+EOM
+
+ knife("node list").should_succeed <<EOM
+cdr
+cons
+EOM
+ end
+ end
+
+end
diff --git a/spec/integration/knife/node_create_spec.rb b/spec/integration/knife/node_create_spec.rb
new file mode 100644
index 0000000000..93a2f9ce6f
--- /dev/null
+++ b/spec/integration/knife/node_create_spec.rb
@@ -0,0 +1,46 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "openssl"
+
+describe "knife node create", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:out) { "Created node[bah]\n" }
+
+ when_the_chef_server "is empty" do
+ it "creates a new node" do
+ knife("node create bah").should_succeed out
+ end
+
+ it "creates a new validator node" do
+ knife("node create bah").should_succeed out
+ knife("node show bah").should_succeed /Node Name: bah/
+ end
+
+ it "refuses to add an existing node" do
+ pending "Knife node create must not blindly overwrite an existing node"
+ knife("node create bah").should_succeed out
+ expect { knife("node create bah") }.to raise_error(Net::HTTPServerException)
+ end
+
+ end
+end
diff --git a/spec/integration/knife/node_delete_spec.rb b/spec/integration/knife/node_delete_spec.rb
new file mode 100644
index 0000000000..5d88af6d4f
--- /dev/null
+++ b/spec/integration/knife/node_delete_spec.rb
@@ -0,0 +1,47 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some nodes" do
+ before do
+ node "cons", {}
+ node "car", {}
+ node "cdr", {}
+ node "cat", {}
+ end
+
+ it "deletes a node" do
+ knife("node delete car", input: "Y").should_succeed <<EOM
+Do you really want to delete car? (Y/N) Deleted node[car]
+EOM
+
+ knife("node list").should_succeed <<EOM
+cat
+cdr
+cons
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/node_environment_set_spec.rb b/spec/integration/knife/node_environment_set_spec.rb
new file mode 100644
index 0000000000..10fec5723f
--- /dev/null
+++ b/spec/integration/knife/node_environment_set_spec.rb
@@ -0,0 +1,45 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node environment set", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a node and an environment" do
+ before do
+ node "cons", {}
+ environment "lisp", {}
+ end
+
+ it "sets an environment on a node" do
+ knife("node environment set cons lisp").should_succeed /chef_environment:.*lisp/
+ knife("node show cons -a chef_environment").should_succeed <<EOM
+cons:
+ chef_environment: lisp
+EOM
+ end
+
+ it "with no environment" do
+ knife("node environment set adam").should_fail stderr: "FATAL: You must specify a node name and an environment.\n",
+ stdout: /^USAGE: knife node environment set NODE ENVIRONMENT\n/
+ end
+ end
+end
diff --git a/spec/integration/knife/node_from_file_spec.rb b/spec/integration/knife/node_from_file_spec.rb
new file mode 100644
index 0000000000..3430967a21
--- /dev/null
+++ b/spec/integration/knife/node_from_file_spec.rb
@@ -0,0 +1,58 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node from file", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ # include_context "default config options"
+
+ let (:node_dir) { "#{@repository_dir}/nodes" }
+
+ when_the_chef_server "is empty" do
+ when_the_repository "has some nodes" do
+ before do
+
+ file "nodes/cons.json", <<EOM
+{
+ "name": "cons",
+ "chef_environment": "_default",
+ "run_list": [
+ "recipe[cons]"
+]
+,
+ "normal": {
+ "tags": [
+
+ ]
+ }
+}
+EOM
+
+ end
+
+ it "uploads a single file" do
+ knife("node from file #{node_dir}/cons.json").should_succeed stderr: <<EOM
+Updated Node cons
+EOM
+ end
+
+ end
+ end
+end
diff --git a/spec/integration/knife/node_list_spec.rb b/spec/integration/knife/node_list_spec.rb
new file mode 100644
index 0000000000..76f5861e03
--- /dev/null
+++ b/spec/integration/knife/node_list_spec.rb
@@ -0,0 +1,44 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some nodes" do
+ before do
+ node "cons", {}
+ node "car", {}
+ node "cdr", {}
+ node "cat", {}
+ end
+
+ it "lists all cookbooks" do
+ knife("node list").should_succeed <<EOM
+car
+cat
+cdr
+cons
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/node_run_list_add_spec.rb b/spec/integration/knife/node_run_list_add_spec.rb
new file mode 100644
index 0000000000..87d08e1975
--- /dev/null
+++ b/spec/integration/knife/node_run_list_add_spec.rb
@@ -0,0 +1,53 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node run list add", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a node with no run_list" do
+ before do
+ node "cons", {}
+ end
+
+ it "sets the run list" do
+ knife("node run list add cons recipe[foo]").should_succeed /run_list:\s*recipe\[foo\]\n/
+ end
+ end
+
+ when_the_chef_server "has a node with a run_list" do
+ before do
+ node "cons", { run_list: ["recipe[bar]"] }
+ end
+
+ it "appends to the run list" do
+ knife("node run list add cons recipe[foo]").should_succeed /run_list:\n\s*recipe\[bar\]\n\s*recipe\[foo\]\n/m
+ end
+
+ it "adds to the run list before the specified item" do
+ knife("node run list add cons -b recipe[bar] recipe[foo]").should_succeed /run_list:\n\s*recipe\[foo\]\n\s*recipe\[bar\]\n/m
+ end
+
+ it "adds to the run list after the specified item" do
+ knife("node run list add cons -a recipe[bar] recipe[foo]").should_succeed /run_list:\n\s*recipe\[bar\]\n\s*recipe\[foo\]\n/m
+ end
+ end
+end
diff --git a/spec/integration/knife/node_run_list_remove_spec.rb b/spec/integration/knife/node_run_list_remove_spec.rb
new file mode 100644
index 0000000000..e85e3ed8e8
--- /dev/null
+++ b/spec/integration/knife/node_run_list_remove_spec.rb
@@ -0,0 +1,35 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node run list remove", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a node with a run_list" do
+ before do
+ node "cons", { run_list: ["recipe[bar]", "recipe[foo]"] }
+ end
+
+ it "removes the item from the run list" do
+ knife("node run list remove cons recipe[bar]").should_succeed /run_list:\s*recipe\[foo\]\n/m
+ end
+ end
+end
diff --git a/spec/integration/knife/node_run_list_set_spec.rb b/spec/integration/knife/node_run_list_set_spec.rb
new file mode 100644
index 0000000000..ec6b08fb97
--- /dev/null
+++ b/spec/integration/knife/node_run_list_set_spec.rb
@@ -0,0 +1,40 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node run list set", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a node with a run_list" do
+ before do
+ node "cons", { run_list: ["recipe[bar]", "recipe[foo]"] }
+ end
+
+ it "sets the run list" do
+ knife("node run list set cons recipe[bar]").should_succeed /run_list:\s*recipe\[bar\]\n/m
+ end
+
+ it "with no role or recipe" do
+ knife("node run list set cons").should_fail stderr: "FATAL: You must supply both a node name and a run list.\n",
+ stdout: /^USAGE: knife node run_list set NODE ENTRIES \(options\)/m
+ end
+ end
+end
diff --git a/spec/integration/knife/node_show_spec.rb b/spec/integration/knife/node_show_spec.rb
new file mode 100644
index 0000000000..dd890aed59
--- /dev/null
+++ b/spec/integration/knife/node_show_spec.rb
@@ -0,0 +1,35 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a node with a run_list" do
+ before do
+ node "cons", { run_list: ["recipe[bar]", "recipe[foo]"] }
+ end
+
+ it "shows the node" do
+ knife("node show cons").should_succeed /Run List:\s*recipe\[bar\], recipe\[foo\]\n/m
+ end
+ end
+end
diff --git a/spec/integration/knife/raw_spec.rb b/spec/integration/knife/raw_spec.rb
index 75fc8fa55e..5e0d3a3d11 100644
--- a/spec/integration/knife/raw_spec.rb
+++ b/spec/integration/knife/raw_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,12 +15,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'support/shared/context/config'
-require 'chef/knife/raw'
-require 'chef/knife/show'
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/raw"
+require "chef/knife/show"
-describe 'knife raw', :workstation do
+describe "knife raw", :workstation do
include IntegrationSupport
include KnifeSupport
include AppServerSupport
@@ -29,17 +29,17 @@ describe 'knife raw', :workstation do
when_the_chef_server "has one of each thing" do
before do
- client 'x', '{}'
- cookbook 'x', '1.0.0'
- data_bag 'x', { 'y' => '{}' }
- environment 'x', '{}'
- node 'x', '{}'
- role 'x', '{}'
- user 'x', '{}'
+ client "x", "{}"
+ cookbook "x", "1.0.0"
+ data_bag "x", { "y" => "{}" }
+ environment "x", "{}"
+ node "x", "{}"
+ role "x", "{}"
+ user "x", "{}"
end
- it 'knife raw /nodes/x returns the node', :skip => (RUBY_VERSION < "1.9") do
- knife('raw /nodes/x').should_succeed <<EOM
+ it "knife raw /nodes/x returns the node", :skip => (RUBY_VERSION < "1.9") do
+ knife("raw /nodes/x").should_succeed <<EOM
{
"name": "x",
"json_class": "Chef::Node",
@@ -49,7 +49,9 @@ describe 'knife raw', :workstation do
},
"normal": {
+ "tags": [
+ ]
},
"default": {
@@ -64,12 +66,12 @@ describe 'knife raw', :workstation do
EOM
end
- it 'knife raw /blarghle returns 404' do
- knife('raw /blarghle').should_fail(/ERROR: Server responded with error 404 "Not Found\s*"/)
+ it "knife raw /blarghle returns 404" do
+ knife("raw /blarghle").should_fail(/ERROR: Server responded with error 404 "Not Found\s*"/)
end
- it 'knife raw -m DELETE /roles/x succeeds', :skip => (RUBY_VERSION < "1.9") do
- knife('raw -m DELETE /roles/x').should_succeed <<EOM
+ it "knife raw -m DELETE /roles/x succeeds", :skip => (RUBY_VERSION < "1.9") do
+ knife("raw -m DELETE /roles/x").should_succeed <<EOM
{
"name": "x",
"description": "",
@@ -89,11 +91,11 @@ EOM
}
}
EOM
- knife('show /roles/x.json').should_fail "ERROR: /roles/x.json: No such file or directory\n"
+ knife("show /roles/x.json").should_fail "ERROR: /roles/x.json: No such file or directory\n"
end
- it 'knife raw -m PUT -i blah.txt /roles/x succeeds', :skip => (RUBY_VERSION < "1.9") do
- Tempfile.open('raw_put_input') do |file|
+ it "knife raw -m PUT -i blah.txt /roles/x succeeds", :skip => (RUBY_VERSION < "1.9") do
+ Tempfile.open("raw_put_input") do |file|
file.write <<EOM
{
"name": "x",
@@ -136,7 +138,7 @@ EOM
}
}
EOM
- knife('show /roles/x.json').should_succeed <<EOM
+ knife("show /roles/x.json").should_succeed <<EOM
/roles/x.json:
{
"name": "x",
@@ -146,8 +148,8 @@ EOM
end
end
- it 'knife raw -m POST -i blah.txt /roles succeeds', :skip => (RUBY_VERSION < "1.9") do
- Tempfile.open('raw_put_input') do |file|
+ it "knife raw -m POST -i blah.txt /roles succeeds", :skip => (RUBY_VERSION < "1.9") do
+ Tempfile.open("raw_put_input") do |file|
file.write <<EOM
{
"name": "y",
@@ -172,7 +174,7 @@ EOM
"uri": "#{Chef::Config.chef_server_url}/roles/y"
}
EOM
- knife('show /roles/y.json').should_succeed <<EOM
+ knife("show /roles/y.json").should_succeed <<EOM
/roles/y.json:
{
"name": "y",
@@ -182,11 +184,11 @@ EOM
end
end
- context 'When a server returns raw json' do
+ context "When a server returns raw json" do
before :each do
Chef::Config.chef_server_url = "http://localhost:9018"
app = lambda do |env|
- [200, {'Content-Type' => 'application/json' }, ['{ "x": "y", "a": "b" }'] ]
+ [200, { "Content-Type" => "application/json" }, ['{ "x": "y", "a": "b" }'] ]
end
@raw_server, @raw_server_thread = start_app_server(app, 9018)
end
@@ -196,8 +198,8 @@ EOM
@raw_server_thread.kill if @raw_server_thread
end
- it 'knife raw /blah returns the prettified json', :skip => (RUBY_VERSION < "1.9") do
- knife('raw /blah').should_succeed <<EOM
+ it "knife raw /blah returns the prettified json", :skip => (RUBY_VERSION < "1.9") do
+ knife("raw /blah").should_succeed <<EOM
{
"x": "y",
"a": "b"
@@ -205,18 +207,18 @@ EOM
EOM
end
- it 'knife raw --no-pretty /blah returns the raw json' do
- knife('raw --no-pretty /blah').should_succeed <<EOM
+ it "knife raw --no-pretty /blah returns the raw json" do
+ knife("raw --no-pretty /blah").should_succeed <<EOM
{ "x": "y", "a": "b" }
EOM
end
end
- context 'When a server returns text' do
+ context "When a server returns text" do
before :each do
Chef::Config.chef_server_url = "http://localhost:9018"
app = lambda do |env|
- [200, {'Content-Type' => 'text' }, ['{ "x": "y", "a": "b" }'] ]
+ [200, { "Content-Type" => "text" }, ['{ "x": "y", "a": "b" }'] ]
end
@raw_server, @raw_server_thread = start_app_server(app, 9018)
end
@@ -226,14 +228,14 @@ EOM
@raw_server_thread.kill if @raw_server_thread
end
- it 'knife raw /blah returns the raw text' do
- knife('raw /blah').should_succeed(<<EOM)
+ it "knife raw /blah returns the raw text" do
+ knife("raw /blah").should_succeed(<<EOM)
{ "x": "y", "a": "b" }
EOM
end
- it 'knife raw --no-pretty /blah returns the raw text' do
- knife('raw --no-pretty /blah').should_succeed(<<EOM)
+ it "knife raw --no-pretty /blah returns the raw text" do
+ knife("raw --no-pretty /blah").should_succeed(<<EOM)
{ "x": "y", "a": "b" }
EOM
end
diff --git a/spec/integration/knife/redirection_spec.rb b/spec/integration/knife/redirection_spec.rb
index 77bda99453..29c1ee6ffb 100644
--- a/spec/integration/knife/redirection_spec.rb
+++ b/spec/integration/knife/redirection_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,26 +15,26 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'support/shared/context/config'
-require 'chef/knife/list'
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/list"
-describe 'redirection', :workstation do
+describe "redirection", :workstation do
include IntegrationSupport
include KnifeSupport
include AppServerSupport
include_context "default config options"
- when_the_chef_server 'has a role' do
- before { role 'x', {} }
+ when_the_chef_server "has a role" do
+ before { role "x", {} }
- context 'and another server redirects to it with 302' do
+ context "and another server redirects to it with 302" do
before :each do
real_chef_server_url = Chef::Config.chef_server_url
Chef::Config.chef_server_url = "http://localhost:9018"
app = lambda do |env|
- [302, {'Content-Type' => 'text','Location' => "#{real_chef_server_url}#{env['PATH_INFO']}" }, ['302 found'] ]
+ [302, { "Content-Type" => "text", "Location" => "#{real_chef_server_url}#{env['PATH_INFO']}" }, ["302 found"] ]
end
@redirector_server, @redirector_server_thread = start_app_server(app, 9018)
end
@@ -44,8 +44,8 @@ describe 'redirection', :workstation do
@redirector_thread.kill if @redirector_thread
end
- it 'knife list /roles returns the role' do
- knife('list /roles').should_succeed "/roles/x.json\n"
+ it "knife list /roles returns the role" do
+ knife("list /roles").should_succeed "/roles/x.json\n"
end
end
end
diff --git a/spec/integration/knife/role_bulk_delete_spec.rb b/spec/integration/knife/role_bulk_delete_spec.rb
new file mode 100644
index 0000000000..0e7ff941e2
--- /dev/null
+++ b/spec/integration/knife/role_bulk_delete_spec.rb
@@ -0,0 +1,51 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife role bulk delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some roles" do
+ before do
+ role "cons", {}
+ role "car", {}
+ role "cdr", {}
+ role "cat", {}
+ end
+
+ it "deletes all matching roles" do
+ knife("role bulk delete ^ca.*", input: "Y").should_succeed <<EOM
+The following roles will be deleted:
+
+car cat
+
+Are you sure you want to delete these roles? (Y/N) Deleted role car
+Deleted role cat
+EOM
+
+ knife("role list").should_succeed <<EOM
+cdr
+cons
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/role_create_spec.rb b/spec/integration/knife/role_create_spec.rb
new file mode 100644
index 0000000000..941eaf5cb6
--- /dev/null
+++ b/spec/integration/knife/role_create_spec.rb
@@ -0,0 +1,40 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife role create", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:out) { "Created role[bah]\n" }
+
+ when_the_chef_server "is empty" do
+ it "creates a new role" do
+ knife("role create bah").should_succeed out
+ end
+
+ it "refuses to add an existing role" do
+ pending "Knife role create must not blindly overwrite an existing role"
+ knife("role create bah").should_succeed out
+ expect { knife("role create bah") }.to raise_error(Net::HTTPServerException)
+ end
+
+ end
+end
diff --git a/spec/integration/knife/role_delete_spec.rb b/spec/integration/knife/role_delete_spec.rb
new file mode 100644
index 0000000000..9fbd3758b9
--- /dev/null
+++ b/spec/integration/knife/role_delete_spec.rb
@@ -0,0 +1,47 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife role delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some roles" do
+ before do
+ role "cons", {}
+ role "car", {}
+ role "cdr", {}
+ role "cat", {}
+ end
+
+ it "deletes a role" do
+ knife("role delete car", input: "Y").should_succeed <<EOM
+Do you really want to delete car? (Y/N) Deleted role[car]
+EOM
+
+ knife("role list").should_succeed <<EOM
+cat
+cdr
+cons
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/role_from_file_spec.rb b/spec/integration/knife/role_from_file_spec.rb
new file mode 100644
index 0000000000..60caa3fa88
--- /dev/null
+++ b/spec/integration/knife/role_from_file_spec.rb
@@ -0,0 +1,95 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife role from file", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ # include_context "default config options"
+
+ let (:role_dir) { "#{@repository_dir}/roles" }
+
+ when_the_chef_server "is empty" do
+ when_the_repository "has some roles" do
+ before do
+
+ file "roles/cons.json", <<EOM
+{
+ "name": "cons",
+ "description": "An role",
+ "json_class": "Chef::role",
+ "chef_type": "role",
+ "default_attributes": {
+ "hola": "Amigos!"
+ },
+ "override_attributes": {
+
+ }
+}
+EOM
+
+ file "roles/car.json", <<EOM
+{
+ "name": "car",
+ "description": "A role for list nodes",
+ "json_class": "Chef::Role",
+ "chef_type": "role",
+ "default_attributes": {
+ "hola": "Amigos!"
+ },
+ "override_attributes": {
+
+ }
+}
+EOM
+
+ file "roles/cdr.json", <<EOM
+{
+ "name": "cdr",
+ "description": "A role for last nodes",
+ "json_class": "Chef::Role",
+ "chef_type": "role",
+ "default_attributes": {
+ "hola": "Amigos!"
+ },
+ "override_attributes": {
+
+ }
+}
+EOM
+
+ end
+
+ it "uploads a single file" do
+ knife("role from file #{role_dir}/cons.json").should_succeed stderr: <<EOM
+Updated Role cons
+EOM
+ end
+
+ it "uploads many files" do
+ knife("role from file #{role_dir}/cons.json #{role_dir}/car.json #{role_dir}/cdr.json").should_succeed stderr: <<EOM
+Updated Role cons
+Updated Role car
+Updated Role cdr
+EOM
+ end
+
+ end
+ end
+end
diff --git a/spec/integration/knife/role_list_spec.rb b/spec/integration/knife/role_list_spec.rb
new file mode 100644
index 0000000000..36dc76be4c
--- /dev/null
+++ b/spec/integration/knife/role_list_spec.rb
@@ -0,0 +1,44 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife role list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some roles" do
+ before do
+ role "cons", {}
+ role "car", {}
+ role "cdr", {}
+ role "cat", {}
+ end
+
+ it "lists all cookbooks" do
+ knife("role list").should_succeed <<EOM
+car
+cat
+cdr
+cons
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/role_show_spec.rb b/spec/integration/knife/role_show_spec.rb
new file mode 100644
index 0000000000..df2572447c
--- /dev/null
+++ b/spec/integration/knife/role_show_spec.rb
@@ -0,0 +1,50 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife role show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some roles" do
+ before do
+ role "cons", {}
+ role "car", {}
+ role "cdr", {}
+ role "cat", {}
+ end
+
+ # rubocop:disable Style/TrailingWhitespace
+ it "shows a cookbook" do
+ knife("role show cons").should_succeed <<EOM
+chef_type: role
+default_attributes:
+description:
+env_run_lists:
+json_class: Chef::Role
+name: cons
+override_attributes:
+run_list:
+EOM
+ end
+ # rubocop:enable Style/TrailingWhitespace
+
+ end
+end
diff --git a/spec/integration/knife/serve_spec.rb b/spec/integration/knife/serve_spec.rb
index 7bf7d29b40..72f0bb59ed 100644
--- a/spec/integration/knife/serve_spec.rb
+++ b/spec/integration/knife/serve_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,34 +15,34 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/serve'
-require 'chef/server_api'
+require "support/shared/integration/integration_helper"
+require "chef/knife/serve"
+require "chef/server_api"
-describe 'knife serve', :workstation do
+describe "knife serve", :workstation do
include IntegrationSupport
include KnifeSupport
include AppServerSupport
- when_the_repository 'also has one of each thing' do
- before { file 'nodes/x.json', { 'foo' => 'bar' } }
+ when_the_repository "also has one of each thing" do
+ before { file "nodes/x.json", { "foo" => "bar" } }
- it 'knife serve serves up /nodes/x' do
+ it "knife serve serves up /nodes/x" do
exception = nil
t = Thread.new do
begin
- knife('serve --chef-zero-port=8890')
+ knife("serve --chef-zero-port=8890")
rescue
exception = $!
end
end
begin
Chef::Config.log_level = :debug
- Chef::Config.chef_server_url = 'http://localhost:8890'
+ Chef::Config.chef_server_url = "http://localhost:8890"
Chef::Config.node_name = nil
Chef::Config.client_key = nil
api = Chef::ServerAPI.new
- expect(api.get('nodes/x')['name']).to eq('x')
+ expect(api.get("nodes/x")["name"]).to eq("x")
rescue
if exception
raise exception
diff --git a/spec/integration/knife/show_spec.rb b/spec/integration/knife/show_spec.rb
index 8f1887e738..ed4802fef9 100644
--- a/spec/integration/knife/show_spec.rb
+++ b/spec/integration/knife/show_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,11 +15,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'support/shared/context/config'
-require 'chef/knife/show'
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/show"
-describe 'knife show', :workstation do
+describe "knife show", :workstation do
include IntegrationSupport
include KnifeSupport
@@ -27,81 +27,81 @@ describe 'knife show', :workstation do
when_the_chef_server "has one of each thing" do
before do
- client 'x', '{}'
- cookbook 'x', '1.0.0'
- data_bag 'x', { 'y' => '{}' }
- environment 'x', '{}'
- node 'x', '{}'
- role 'x', '{}'
- user 'x', '{}'
+ client "x", "{}"
+ cookbook "x", "1.0.0"
+ data_bag "x", { "y" => "{}" }
+ environment "x", "{}"
+ node "x", "{}"
+ role "x", "{}"
+ user "x", "{}"
end
- when_the_repository 'also has one of each thing' do
+ when_the_repository "also has one of each thing" do
before do
- file 'clients/x.json', { 'foo' => 'bar' }
- file 'cookbooks/x/metadata.rb', cb_metadata('x', '1.0.0')
- file 'data_bags/x/y.json', { 'foo' => 'bar' }
- file 'environments/_default.json', { 'foo' => 'bar' }
- file 'environments/x.json', { 'foo' => 'bar' }
- file 'nodes/x.json', { 'foo' => 'bar' }
- file 'roles/x.json', { 'foo' => 'bar' }
- file 'users/x.json', { 'foo' => 'bar' }
+ file "clients/x.json", { "foo" => "bar" }
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ file "data_bags/x/y.json", { "foo" => "bar" }
+ file "environments/_default.json", { "foo" => "bar" }
+ file "environments/x.json", { "foo" => "bar" }
+ file "nodes/x.json", { "foo" => "bar" }
+ file "roles/x.json", { "foo" => "bar" }
+ file "users/x.json", { "foo" => "bar" }
end
- it 'knife show /cookbooks/x/metadata.rb shows the remote version' do
- knife('show /cookbooks/x/metadata.rb').should_succeed <<EOM
+ it "knife show /cookbooks/x/metadata.rb shows the remote version" do
+ knife("show /cookbooks/x/metadata.rb").should_succeed <<EOM
/cookbooks/x/metadata.rb:
name "x"; version "1.0.0"
EOM
end
- it 'knife show --local /cookbooks/x/metadata.rb shows the local version' do
- knife('show --local /cookbooks/x/metadata.rb').should_succeed <<EOM
+ it "knife show --local /cookbooks/x/metadata.rb shows the local version" do
+ knife("show --local /cookbooks/x/metadata.rb").should_succeed <<EOM
/cookbooks/x/metadata.rb:
name "x"; version "1.0.0"
EOM
end
- it 'knife show /data_bags/x/y.json shows the remote version' do
- knife('show /data_bags/x/y.json').should_succeed <<EOM
+ it "knife show /data_bags/x/y.json shows the remote version" do
+ knife("show /data_bags/x/y.json").should_succeed <<EOM
/data_bags/x/y.json:
{
"id": "y"
}
EOM
end
- it 'knife show --local /data_bags/x/y.json shows the local version' do
- knife('show --local /data_bags/x/y.json').should_succeed <<EOM
+ it "knife show --local /data_bags/x/y.json shows the local version" do
+ knife("show --local /data_bags/x/y.json").should_succeed <<EOM
/data_bags/x/y.json:
{
"foo": "bar"
}
EOM
end
- it 'knife show /environments/x.json shows the remote version', :skip => (RUBY_VERSION < "1.9") do
- knife('show /environments/x.json').should_succeed <<EOM
+ it "knife show /environments/x.json shows the remote version", :skip => (RUBY_VERSION < "1.9") do
+ knife("show /environments/x.json").should_succeed <<EOM
/environments/x.json:
{
"name": "x"
}
EOM
end
- it 'knife show --local /environments/x.json shows the local version' do
- knife('show --local /environments/x.json').should_succeed <<EOM
+ it "knife show --local /environments/x.json shows the local version" do
+ knife("show --local /environments/x.json").should_succeed <<EOM
/environments/x.json:
{
"foo": "bar"
}
EOM
end
- it 'knife show /roles/x.json shows the remote version', :skip => (RUBY_VERSION < "1.9") do
- knife('show /roles/x.json').should_succeed <<EOM
+ it "knife show /roles/x.json shows the remote version", :skip => (RUBY_VERSION < "1.9") do
+ knife("show /roles/x.json").should_succeed <<EOM
/roles/x.json:
{
"name": "x"
}
EOM
end
- it 'knife show --local /roles/x.json shows the local version' do
- knife('show --local /roles/x.json').should_succeed <<EOM
+ it "knife show --local /roles/x.json shows the local version" do
+ knife("show --local /roles/x.json").should_succeed <<EOM
/roles/x.json:
{
"foo": "bar"
@@ -109,34 +109,34 @@ EOM
EOM
end
# show directory
- it 'knife show /data_bags/x fails' do
- knife('show /data_bags/x').should_fail "ERROR: /data_bags/x: is a directory\n"
+ it "knife show /data_bags/x fails" do
+ knife("show /data_bags/x").should_fail "ERROR: /data_bags/x: is a directory\n"
end
- it 'knife show --local /data_bags/x fails' do
- knife('show --local /data_bags/x').should_fail "ERROR: /data_bags/x: is a directory\n"
+ it "knife show --local /data_bags/x fails" do
+ knife("show --local /data_bags/x").should_fail "ERROR: /data_bags/x: is a directory\n"
end
# show nonexistent file
- it 'knife show /environments/nonexistent.json fails' do
- knife('show /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
+ it "knife show /environments/nonexistent.json fails" do
+ knife("show /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
end
- it 'knife show --local /environments/nonexistent.json fails' do
- knife('show --local /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
+ it "knife show --local /environments/nonexistent.json fails" do
+ knife("show --local /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
end
end
end
- when_the_chef_server 'has a hash with multiple keys' do
+ when_the_chef_server "has a hash with multiple keys" do
before do
- environment 'x', {
- 'default_attributes' => { 'foo' => 'bar' },
- 'cookbook_versions' => { 'blah' => '= 1.0.0'},
- 'override_attributes' => { 'x' => 'y' },
- 'description' => 'woo',
- 'name' => 'x'
+ environment "x", {
+ "default_attributes" => { "foo" => "bar" },
+ "cookbook_versions" => { "blah" => "= 1.0.0" },
+ "override_attributes" => { "x" => "y" },
+ "description" => "woo",
+ "name" => "x",
}
end
- it 'knife show shows the attributes in a predetermined order', :skip => (RUBY_VERSION < "1.9") do
- knife('show /environments/x.json').should_succeed <<EOM
+ it "knife show shows the attributes in a predetermined order", :skip => (RUBY_VERSION < "1.9") do
+ knife("show /environments/x.json").should_succeed <<EOM
/environments/x.json:
{
"name": "x",
@@ -155,10 +155,10 @@ EOM
end
end
- when_the_repository 'has an environment with bad JSON' do
- before { file 'environments/x.json', '{' }
- it 'knife show succeeds' do
- knife('show --local /environments/x.json').should_succeed <<EOM
+ when_the_repository "has an environment with bad JSON" do
+ before { file "environments/x.json", "{" }
+ it "knife show succeeds" do
+ knife("show --local /environments/x.json").should_succeed <<EOM
/environments/x.json:
{
EOM
diff --git a/spec/integration/knife/upload_spec.rb b/spec/integration/knife/upload_spec.rb
index 6ca8c3d8ce..d372a83a35 100644
--- a/spec/integration/knife/upload_spec.rb
+++ b/spec/integration/knife/upload_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,44 +15,44 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/upload'
-require 'chef/knife/diff'
-require 'chef/knife/raw'
-require 'chef/json_compat'
+require "support/shared/integration/integration_helper"
+require "chef/knife/upload"
+require "chef/knife/diff"
+require "chef/knife/raw"
+require "chef/json_compat"
-describe 'knife upload', :workstation do
+describe "knife upload", :workstation do
include IntegrationSupport
include KnifeSupport
- context 'without versioned cookbooks' do
+ context "without versioned cookbooks" do
when_the_chef_server "has one of each thing" do
before do
- client 'x', {}
- cookbook 'x', '1.0.0'
- data_bag 'x', { 'y' => {} }
- environment 'x', {}
- node 'x', {}
- role 'x', {}
- user 'x', {}
+ client "x", {}
+ cookbook "x", "1.0.0"
+ data_bag "x", { "y" => {} }
+ environment "x", {}
+ node "x", {}
+ role "x", {}
+ user "x", {}
end
- when_the_repository 'has only top-level directories' do
+ when_the_repository "has only top-level directories" do
before do
- directory 'clients'
- directory 'cookbooks'
- directory 'data_bags'
- directory 'environments'
- directory 'nodes'
- directory 'roles'
- directory 'users'
- end
-
- it 'knife upload does nothing' do
- knife('upload /').should_succeed ''
- knife('diff --name-status /').should_succeed <<EOM
+ directory "clients"
+ directory "cookbooks"
+ directory "data_bags"
+ directory "environments"
+ directory "nodes"
+ directory "roles"
+ directory "users"
+ end
+
+ it "knife upload does nothing" do
+ knife("upload /").should_succeed ""
+ knife("diff --name-status /").should_succeed <<EOM
D\t/clients/chef-validator.json
D\t/clients/chef-webui.json
D\t/clients/x.json
@@ -67,8 +67,8 @@ D\t/users/x.json
EOM
end
- it 'knife upload --purge deletes everything' do
- knife('upload --purge /').should_succeed(<<EOM, :stderr => "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n")
+ it "knife upload --purge deletes everything" do
+ knife("upload --purge /").should_succeed(<<EOM, :stderr => "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n")
Deleted extra entry /clients/chef-validator.json (purge is on)
Deleted extra entry /clients/chef-webui.json (purge is on)
Deleted extra entry /clients/x.json (purge is on)
@@ -80,56 +80,56 @@ Deleted extra entry /roles/x.json (purge is on)
Deleted extra entry /users/admin.json (purge is on)
Deleted extra entry /users/x.json (purge is on)
EOM
- knife('diff --name-status /').should_succeed <<EOM
+ knife("diff --name-status /").should_succeed <<EOM
D\t/environments/_default.json
EOM
end
end
- when_the_repository 'has an identical copy of each thing' do
+ when_the_repository "has an identical copy of each thing" do
before do
- file 'clients/chef-validator.json', { 'validator' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
- file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
- file 'data_bags/x/y.json', {}
- file 'environments/_default.json', { "description" => "The default Chef environment" }
- file 'environments/x.json', {}
- file 'nodes/x.json', {}
- file 'roles/x.json', {}
- file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+ file "clients/chef-validator.json", { "validator" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "clients/chef-webui.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ file "data_bags/x/y.json", {}
+ file "environments/_default.json", { "description" => "The default Chef environment" }
+ file "environments/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
+ file "roles/x.json", {}
+ file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
end
- it 'knife upload makes no changes' do
- knife('upload /cookbooks/x').should_succeed ''
- knife('diff --name-status /').should_succeed ''
+ it "knife upload makes no changes" do
+ knife("upload /cookbooks/x").should_succeed ""
+ knife("diff --name-status /").should_succeed ""
end
- it 'knife upload --purge makes no changes' do
- knife('upload --purge /').should_succeed ''
- knife('diff --name-status /').should_succeed ''
+ it "knife upload --purge makes no changes" do
+ knife("upload --purge /").should_succeed ""
+ knife("diff --name-status /").should_succeed ""
end
- context 'except the role file' do
+ context "except the role file" do
before do
- file 'roles/x.json', { 'description' => 'blarghle' }
+ file "roles/x.json", { "description" => "blarghle" }
end
- it 'knife upload changes the role' do
- knife('upload /').should_succeed "Updated /roles/x.json\n"
- knife('diff --name-status /').should_succeed ''
+ it "knife upload changes the role" do
+ knife("upload /").should_succeed "Updated /roles/x.json\n"
+ knife("diff --name-status /").should_succeed ""
end
- it 'knife upload --no-diff does not change the role' do
- knife('upload --no-diff /').should_succeed ''
- knife('diff --name-status /').should_succeed "M\t/roles/x.json\n"
+ it "knife upload --no-diff does not change the role" do
+ knife("upload --no-diff /").should_succeed ""
+ knife("diff --name-status /").should_succeed "M\t/roles/x.json\n"
end
end
- context 'except the role file is textually different, but not ACTUALLY different' do
+ context "except the role file is textually different, but not ACTUALLY different" do
before do
- file 'roles/x.json', <<EOM
+ file "roles/x.json", <<EOM
{
"chef_type": "role",
"default_attributes": {
@@ -148,45 +148,64 @@ EOM
EOM
end
- it 'knife upload / does not change anything' do
- knife('upload /').should_succeed ''
- knife('diff --name-status /').should_succeed ''
+ it "knife upload / does not change anything" do
+ knife("upload /").should_succeed ""
+ knife("diff --name-status /").should_succeed ""
end
end
- context 'when cookbook metadata has a self-dependency' do
+ context "the role is in ruby" do
before do
- file 'cookbooks/x/metadata.rb', "name 'x'; version '1.0.0'; depends 'x'"
+ file "roles/x.rb", <<EOM
+name "x"
+description "blargle"
+EOM
+ end
+
+ it "knife upload changes the role" do
+ knife("upload /").should_succeed "Updated /roles/x.json\n"
+ knife("diff --name-status /").should_succeed ""
+ end
+
+ it "knife upload --no-diff does not change the role" do
+ knife("upload --no-diff /").should_succeed ""
+ knife("diff --name-status /").should_succeed "M\t/roles/x.rb\n"
end
+ end
- it "should warn", :chef_lt_13_only do
- knife('upload /cookbooks').should_succeed(
+ context "when cookbook metadata has a self-dependency" do
+ before do
+ file "cookbooks/x/metadata.rb", "name 'x'; version '1.0.0'; depends 'x'"
+ end
+
+ it "should warn", chef: "< 13" do
+ knife("upload /cookbooks").should_succeed(
stdout: "Updated /cookbooks/x\n",
stderr: "WARN: Ignoring self-dependency in cookbook x, please remove it (in the future this will be fatal).\n"
)
- knife('diff --name-status /').should_succeed ''
+ knife("diff --name-status /").should_succeed ""
end
- it "should fail in Chef 13", :chef_gte_13_only do
- knife('upload /cookbooks').should_fail ''
+ it "should fail in Chef 13", chef: ">= 13" do
+ knife("upload /cookbooks").should_fail ""
# FIXME: include the error message here
end
end
- context 'as well as one extra copy of each thing' do
+ context "as well as one extra copy of each thing" do
before do
- file 'clients/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
- file 'cookbooks/x/blah.rb', ''
- file 'cookbooks/y/metadata.rb', cb_metadata("y", "1.0.0")
- file 'data_bags/x/z.json', {}
- file 'data_bags/y/zz.json', {}
- file 'environments/y.json', {}
- file 'nodes/y.json', {}
- file 'roles/y.json', {}
- file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+ file "clients/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "cookbooks/x/blah.rb", ""
+ file "cookbooks/y/metadata.rb", cb_metadata("y", "1.0.0")
+ file "data_bags/x/z.json", {}
+ file "data_bags/y/zz.json", {}
+ file "environments/y.json", {}
+ file "nodes/y.json", {}
+ file "roles/y.json", {}
+ file "users/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
end
- it 'knife upload adds the new files' do
- knife('upload /').should_succeed <<EOM
+ it "knife upload adds the new files" do
+ knife("upload /").should_succeed <<EOM
Created /clients/y.json
Updated /cookbooks/x
Created /cookbooks/y
@@ -198,11 +217,11 @@ Created /nodes/y.json
Created /roles/y.json
Created /users/y.json
EOM
- knife('diff /').should_succeed ''
+ knife("diff /").should_succeed ""
end
- it 'knife upload --no-diff adds the new files' do
- knife('upload --no-diff /').should_succeed <<EOM
+ it "knife upload --no-diff adds the new files" do
+ knife("upload --no-diff /").should_succeed <<EOM
Created /clients/y.json
Updated /cookbooks/x
Created /cookbooks/y
@@ -214,15 +233,15 @@ Created /nodes/y.json
Created /roles/y.json
Created /users/y.json
EOM
- knife('diff --name-status /').should_succeed ''
+ knife("diff --name-status /").should_succeed ""
end
end
end
- when_the_repository 'is empty' do
- it 'knife upload does nothing' do
- knife('upload /').should_succeed ''
- knife('diff --name-status /').should_succeed <<EOM
+ when_the_repository "is empty" do
+ it "knife upload does nothing" do
+ knife("upload /").should_succeed ""
+ knife("diff --name-status /").should_succeed <<EOM
D\t/clients
D\t/cookbooks
D\t/data_bags
@@ -233,8 +252,8 @@ D\t/users
EOM
end
- it 'knife upload --purge deletes nothing' do
- knife('upload --purge /').should_fail <<EOM
+ it "knife upload --purge deletes nothing" do
+ knife("upload --purge /").should_fail <<EOM
ERROR: /clients cannot be deleted.
ERROR: /cookbooks cannot be deleted.
ERROR: /data_bags cannot be deleted.
@@ -243,7 +262,7 @@ ERROR: /nodes cannot be deleted.
ERROR: /roles cannot be deleted.
ERROR: /users cannot be deleted.
EOM
- knife('diff --name-status /').should_succeed <<EOM
+ knife("diff --name-status /").should_succeed <<EOM
D\t/clients
D\t/cookbooks
D\t/data_bags
@@ -254,178 +273,178 @@ D\t/users
EOM
end
- context 'when current directory is top level' do
+ context "when current directory is top level" do
before do
- cwd '.'
+ cwd "."
end
- it 'knife upload with no parameters reports an error' do
- knife('upload').should_fail "FATAL: Must specify at least one argument. If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/
+ it "knife upload with no parameters reports an error" do
+ knife("upload").should_fail "FATAL: You must specify at least one argument. If you want to upload everything in this directory, run \"knife upload .\"\n", :stdout => /USAGE/
end
end
end
end
- when_the_chef_server 'is empty' do
- when_the_repository 'has a data bag item' do
+ when_the_chef_server "is empty" do
+ when_the_repository "has a data bag item" do
before do
- file 'data_bags/x/y.json', { 'foo' => 'bar' }
+ file "data_bags/x/y.json", { "foo" => "bar" }
end
- it 'knife upload of the data bag uploads only the values in the data bag item and no other' do
- knife('upload /data_bags/x/y.json').should_succeed <<EOM
+ it "knife upload of the data bag uploads only the values in the data bag item and no other" do
+ knife("upload /data_bags/x/y.json").should_succeed <<EOM
Created /data_bags/x
Created /data_bags/x/y.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
EOM
- expect(Chef::JSONCompat.parse(knife('raw /data/x/y').stdout, :create_additions => false).keys.sort).to eq([ 'foo', 'id' ])
+ expect(Chef::JSONCompat.parse(knife("raw /data/x/y").stdout, :create_additions => false).keys.sort).to eq(%w{foo id})
end
- it 'knife upload /data_bags/x /data_bags/x/y.json uploads x once' do
- knife('upload /data_bags/x /data_bags/x/y.json').should_succeed <<EOM
+ it "knife upload /data_bags/x /data_bags/x/y.json uploads x once" do
+ knife("upload /data_bags/x /data_bags/x/y.json").should_succeed <<EOM
Created /data_bags/x
Created /data_bags/x/y.json
EOM
end
end
- when_the_repository 'has a data bag item with keys chef_type and data_bag' do
+ when_the_repository "has a data bag item with keys chef_type and data_bag" do
before do
- file 'data_bags/x/y.json', { 'chef_type' => 'aaa', 'data_bag' => 'bbb' }
+ file "data_bags/x/y.json", { "chef_type" => "aaa", "data_bag" => "bbb" }
end
- it 'upload preserves chef_type and data_bag' do
- knife('upload /data_bags/x/y.json').should_succeed <<EOM
+ it "upload preserves chef_type and data_bag" do
+ knife("upload /data_bags/x/y.json").should_succeed <<EOM
Created /data_bags/x
Created /data_bags/x/y.json
EOM
- knife('diff --name-status /data_bags').should_succeed ''
- result = Chef::JSONCompat.parse(knife('raw /data/x/y').stdout, :create_additions => false)
- expect(result.keys.sort).to eq([ 'chef_type', 'data_bag', 'id' ])
- expect(result['chef_type']).to eq('aaa')
- expect(result['data_bag']).to eq('bbb')
+ knife("diff --name-status /data_bags").should_succeed ""
+ result = Chef::JSONCompat.parse(knife("raw /data/x/y").stdout, :create_additions => false)
+ expect(result.keys.sort).to eq(%w{chef_type data_bag id})
+ expect(result["chef_type"]).to eq("aaa")
+ expect(result["data_bag"]).to eq("bbb")
end
end
# Test upload of an item when the other end doesn't even have the container
- when_the_repository 'has two data bag items' do
+ when_the_repository "has two data bag items" do
before do
- file 'data_bags/x/y.json', {}
- file 'data_bags/x/z.json', {}
+ file "data_bags/x/y.json", {}
+ file "data_bags/x/z.json", {}
end
- it 'knife upload of one data bag item itself succeeds' do
- knife('upload /data_bags/x/y.json').should_succeed <<EOM
+ it "knife upload of one data bag item itself succeeds" do
+ knife("upload /data_bags/x/y.json").should_succeed <<EOM
Created /data_bags/x
Created /data_bags/x/y.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
A\t/data_bags/x/z.json
EOM
end
end
end
- when_the_chef_server 'has three data bag items' do
+ when_the_chef_server "has three data bag items" do
before do
- data_bag 'x', { 'deleted' => {}, 'modified' => {}, 'unmodified' => {} }
+ data_bag "x", { "deleted" => {}, "modified" => {}, "unmodified" => {} }
end
- when_the_repository 'has a modified, unmodified, added and deleted data bag item' do
+ when_the_repository "has a modified, unmodified, added and deleted data bag item" do
before do
- file 'data_bags/x/added.json', {}
- file 'data_bags/x/modified.json', { 'foo' => 'bar' }
- file 'data_bags/x/unmodified.json', {}
+ file "data_bags/x/added.json", {}
+ file "data_bags/x/modified.json", { "foo" => "bar" }
+ file "data_bags/x/unmodified.json", {}
end
- it 'knife upload of the modified file succeeds' do
- knife('upload /data_bags/x/modified.json').should_succeed <<EOM
+ it "knife upload of the modified file succeeds" do
+ knife("upload /data_bags/x/modified.json").should_succeed <<EOM
Updated /data_bags/x/modified.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/deleted.json
A\t/data_bags/x/added.json
EOM
end
- it 'knife upload of the unmodified file does nothing' do
- knife('upload /data_bags/x/unmodified.json').should_succeed ''
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ it "knife upload of the unmodified file does nothing" do
+ knife("upload /data_bags/x/unmodified.json").should_succeed ""
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/deleted.json
M\t/data_bags/x/modified.json
A\t/data_bags/x/added.json
EOM
end
- it 'knife upload of the added file succeeds' do
- knife('upload /data_bags/x/added.json').should_succeed <<EOM
+ it "knife upload of the added file succeeds" do
+ knife("upload /data_bags/x/added.json").should_succeed <<EOM
Created /data_bags/x/added.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/deleted.json
M\t/data_bags/x/modified.json
EOM
end
- it 'knife upload of the deleted file does nothing' do
- knife('upload /data_bags/x/deleted.json').should_succeed ''
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ it "knife upload of the deleted file does nothing" do
+ knife("upload /data_bags/x/deleted.json").should_succeed ""
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/deleted.json
M\t/data_bags/x/modified.json
A\t/data_bags/x/added.json
EOM
end
- it 'knife upload --purge of the deleted file deletes it' do
- knife('upload --purge /data_bags/x/deleted.json').should_succeed <<EOM
+ it "knife upload --purge of the deleted file deletes it" do
+ knife("upload --purge /data_bags/x/deleted.json").should_succeed <<EOM
Deleted extra entry /data_bags/x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
M\t/data_bags/x/modified.json
A\t/data_bags/x/added.json
EOM
end
- it 'knife upload of the entire data bag uploads everything' do
- knife('upload /data_bags/x').should_succeed <<EOM
+ it "knife upload of the entire data bag uploads everything" do
+ knife("upload /data_bags/x").should_succeed <<EOM
Created /data_bags/x/added.json
Updated /data_bags/x/modified.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/deleted.json
EOM
end
- it 'knife upload --purge of the entire data bag uploads everything' do
- knife('upload --purge /data_bags/x').should_succeed <<EOM
+ it "knife upload --purge of the entire data bag uploads everything" do
+ knife("upload --purge /data_bags/x").should_succeed <<EOM
Created /data_bags/x/added.json
Updated /data_bags/x/modified.json
Deleted extra entry /data_bags/x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed ''
+ knife("diff --name-status /data_bags").should_succeed ""
end
- context 'when cwd is the /data_bags directory' do
+ context "when cwd is the /data_bags directory" do
before do
- cwd 'data_bags'
+ cwd "data_bags"
end
- it 'knife upload fails' do
- knife('upload').should_fail "FATAL: Must specify at least one argument. If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/
+ it "knife upload fails" do
+ knife("upload").should_fail "FATAL: You must specify at least one argument. If you want to upload everything in this directory, run \"knife upload .\"\n", :stdout => /USAGE/
end
- it 'knife upload --purge . uploads everything' do
- knife('upload --purge .').should_succeed <<EOM
+ it "knife upload --purge . uploads everything" do
+ knife("upload --purge .").should_succeed <<EOM
Created x/added.json
Updated x/modified.json
Deleted extra entry x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed ''
+ knife("diff --name-status /data_bags").should_succeed ""
end
- it 'knife upload --purge * uploads everything' do
- knife('upload --purge *').should_succeed <<EOM
+ it "knife upload --purge * uploads everything" do
+ knife("upload --purge *").should_succeed <<EOM
Created x/added.json
Updated x/modified.json
Deleted extra entry x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed ''
+ knife("diff --name-status /data_bags").should_succeed ""
end
end
end
@@ -434,128 +453,128 @@ EOM
# Cookbook upload is a funny thing ... direct cookbook upload works, but
# upload of a file is designed not to work at present. Make sure that is the
# case.
- when_the_chef_server 'has a cookbook' do
+ when_the_chef_server "has a cookbook" do
before do
- cookbook 'x', '1.0.0', { 'z.rb' => '' }
+ cookbook "x", "1.0.0", { "z.rb" => "" }
end
- when_the_repository 'has a modified, extra and missing file for the cookbook' do
+ when_the_repository "has a modified, extra and missing file for the cookbook" do
before do
- file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0", "#modified")
- file 'cookbooks/x/y.rb', 'hi'
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0", "#modified")
+ file "cookbooks/x/y.rb", "hi"
end
- it 'knife upload of any individual file fails' do
- knife('upload /cookbooks/x/metadata.rb').should_fail "ERROR: /cookbooks/x/metadata.rb cannot be updated.\n"
- knife('upload /cookbooks/x/y.rb').should_fail "ERROR: /cookbooks/x cannot have a child created under it.\n"
- knife('upload --purge /cookbooks/x/z.rb').should_fail "ERROR: /cookbooks/x/z.rb cannot be deleted.\n"
+ it "knife upload of any individual file fails" do
+ knife("upload /cookbooks/x/metadata.rb").should_fail "ERROR: /cookbooks/x/metadata.rb cannot be updated.\n"
+ knife("upload /cookbooks/x/y.rb").should_fail "ERROR: /cookbooks/x cannot have a child created under it.\n"
+ knife("upload --purge /cookbooks/x/z.rb").should_fail "ERROR: /cookbooks/x/z.rb cannot be deleted.\n"
end
# TODO this is a bit of an inconsistency: if we didn't specify --purge,
# technically we shouldn't have deleted missing files. But ... cookbooks
# are a special case.
- it 'knife upload of the cookbook itself succeeds' do
- knife('upload /cookbooks/x').should_succeed <<EOM
+ it "knife upload of the cookbook itself succeeds" do
+ knife("upload /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
- it 'knife upload --purge of the cookbook itself succeeds' do
- knife('upload /cookbooks/x').should_succeed <<EOM
+ it "knife upload --purge of the cookbook itself succeeds" do
+ knife("upload /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_repository 'has a missing file for the cookbook' do
+ when_the_repository "has a missing file for the cookbook" do
before do
- file 'cookbooks/x/metadata.rb', cb_metadata('x', '1.0.0')
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
end
- it 'knife upload of the cookbook succeeds' do
- knife('upload /cookbooks/x').should_succeed <<EOM
+ it "knife upload of the cookbook succeeds" do
+ knife("upload /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_repository 'has an extra file for the cookbook' do
+ when_the_repository "has an extra file for the cookbook" do
before do
- file 'cookbooks/x/metadata.rb', cb_metadata('x', '1.0.0')
- file 'cookbooks/x/z.rb', ''
- file 'cookbooks/x/blah.rb', ''
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ file "cookbooks/x/z.rb", ""
+ file "cookbooks/x/blah.rb", ""
end
- it 'knife upload of the cookbook succeeds' do
- knife('upload /cookbooks/x').should_succeed <<EOM
+ it "knife upload of the cookbook succeeds" do
+ knife("upload /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_repository 'has a different file in the cookbook' do
+ when_the_repository "has a different file in the cookbook" do
before do
- file 'cookbooks/x/metadata.rb', cb_metadata('x', '1.0.0')
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
end
- it 'knife upload --freeze freezes the cookbook' do
- knife('upload --freeze /cookbooks/x').should_succeed <<EOM
+ it "knife upload --freeze freezes the cookbook" do
+ knife("upload --freeze /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x
EOM
# Modify a file and attempt to upload
- file 'cookbooks/x/metadata.rb', 'name "x"; version "1.0.0"#different'
- knife('upload /cookbooks/x').should_fail "ERROR: /cookbooks failed to write: Cookbook x is frozen\n"
+ file "cookbooks/x/metadata.rb", 'name "x"; version "1.0.0"#different'
+ knife("upload /cookbooks/x").should_fail "ERROR: /cookbooks failed to write: Cookbook x is frozen\n"
end
end
end
- when_the_chef_server 'has a frozen cookbook' do
+ when_the_chef_server "has a frozen cookbook" do
before do
- cookbook 'frozencook', '1.0.0', {}, :frozen => true
+ cookbook "frozencook", "1.0.0", {}, :frozen => true
end
- when_the_repository 'has an update to said cookbook' do
+ when_the_repository "has an update to said cookbook" do
before do
- file 'cookbooks/frozencook/metadata.rb', cb_metadata("frozencook", "1.0.0", "# This is different")
+ file "cookbooks/frozencook/metadata.rb", cb_metadata("frozencook", "1.0.0", "# This is different")
end
- it 'knife upload fails to upload the frozen cookbook' do
- knife('upload /cookbooks/frozencook').should_fail "ERROR: /cookbooks failed to write: Cookbook frozencook is frozen\n"
+ it "knife upload fails to upload the frozen cookbook" do
+ knife("upload /cookbooks/frozencook").should_fail "ERROR: /cookbooks failed to write: Cookbook frozencook is frozen\n"
end
- it 'knife upload --force uploads the frozen cookbook' do
- knife('upload --force /cookbooks/frozencook').should_succeed <<EOM
+ it "knife upload --force uploads the frozen cookbook" do
+ knife("upload --force /cookbooks/frozencook").should_succeed <<EOM
Updated /cookbooks/frozencook
EOM
end
end
end
- when_the_repository 'has a cookbook' do
+ when_the_repository "has a cookbook" do
before do
- file 'cookbooks/x/metadata.rb', cb_metadata('x', '1.0.0')
- file 'cookbooks/x/onlyin1.0.0.rb', 'old_text'
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ file "cookbooks/x/onlyin1.0.0.rb", "old_text"
end
- when_the_chef_server 'has a later version for the cookbook' do
+ when_the_chef_server "has a later version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
end
- it 'knife upload /cookbooks/x uploads the local version' do
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife upload /cookbooks/x uploads the local version" do
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
M\t/cookbooks/x/metadata.rb
D\t/cookbooks/x/onlyin1.0.1.rb
A\t/cookbooks/x/onlyin1.0.0.rb
EOM
- knife('upload --purge /cookbooks/x').should_succeed <<EOM
+ knife("upload --purge /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x
EOM
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
M\t/cookbooks/x/metadata.rb
D\t/cookbooks/x/onlyin1.0.1.rb
A\t/cookbooks/x/onlyin1.0.0.rb
@@ -563,35 +582,35 @@ EOM
end
end
- when_the_chef_server 'has an earlier version for the cookbook' do
+ when_the_chef_server "has an earlier version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
end
- it 'knife upload /cookbooks/x uploads the local version' do
- knife('upload --purge /cookbooks/x').should_succeed <<EOM
+ it "knife upload /cookbooks/x uploads the local version" do
+ knife("upload --purge /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has a later version for the cookbook, and no current version' do
+ when_the_chef_server "has a later version for the cookbook, and no current version" do
before do
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
end
- it 'knife upload /cookbooks/x uploads the local version' do
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife upload /cookbooks/x uploads the local version" do
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
M\t/cookbooks/x/metadata.rb
D\t/cookbooks/x/onlyin1.0.1.rb
A\t/cookbooks/x/onlyin1.0.0.rb
EOM
- knife('upload --purge /cookbooks/x').should_succeed <<EOM
+ knife("upload --purge /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x
EOM
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
M\t/cookbooks/x/metadata.rb
D\t/cookbooks/x/onlyin1.0.1.rb
A\t/cookbooks/x/onlyin1.0.0.rb
@@ -599,31 +618,31 @@ EOM
end
end
- when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
+ when_the_chef_server "has an earlier version for the cookbook, and no current version" do
before do
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
end
- it 'knife upload /cookbooks/x uploads the new version' do
- knife('upload --purge /cookbooks/x').should_succeed <<EOM
+ it "knife upload /cookbooks/x uploads the new version" do
+ knife("upload --purge /cookbooks/x").should_succeed <<EOM
Updated /cookbooks/x
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
end
- when_the_chef_server 'has an environment' do
+ when_the_chef_server "has an environment" do
before do
- environment 'x', {}
+ environment "x", {}
end
- when_the_repository 'has an environment with bad JSON' do
+ when_the_repository "has an environment with bad JSON" do
before do
- file 'environments/x.json', '{'
+ file "environments/x.json", "{"
end
- it 'knife upload tries and fails' do
+ it "knife upload tries and fails" do
error1 = <<-EOH
WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error: premature EOF
{
@@ -632,70 +651,83 @@ WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error
ERROR: /environments/x.json failed to write: Parse error reading JSON: parse error: premature EOF
{
(right here) ------^
-EOH
+ EOH
warn = <<-EOH
WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error: premature EOF
{
(right here) ------^
-EOH
- knife('upload /environments/x.json').should_fail(error1)
- knife('diff --name-status /environments/x.json').should_succeed("M\t/environments/x.json\n", :stderr => warn)
+ EOH
+ knife("upload /environments/x.json").should_fail(error1)
+ knife("diff --name-status /environments/x.json").should_succeed("M\t/environments/x.json\n", :stderr => warn)
end
end
- when_the_repository 'has the same environment with the wrong name in the file' do
+ when_the_repository "has the same environment with the wrong name in the file" do
before do
- file 'environments/x.json', { 'name' => 'y' }
+ file "environments/x.json", { "name" => "y" }
end
- it 'knife upload fails' do
- knife('upload /environments/x.json').should_fail "ERROR: /environments/x.json failed to write: Name must be 'x' (is 'y')\n"
- knife('diff --name-status /environments/x.json').should_succeed "M\t/environments/x.json\n"
+ it "knife upload fails" do
+ knife("upload /environments/x.json").should_fail "ERROR: /environments/x.json failed to write: Name must be 'x' (is 'y')\n"
+ knife("diff --name-status /environments/x.json").should_succeed "M\t/environments/x.json\n"
end
end
- when_the_repository 'has the same environment with no name in the file' do
+ when_the_repository "has the same environment with no name in the file" do
before do
- file 'environments/x.json', { 'description' => 'hi' }
+ file "environments/x.json", { "description" => "hi" }
end
- it 'knife upload succeeds' do
- knife('upload /environments/x.json').should_succeed "Updated /environments/x.json\n"
- knife('diff --name-status /environments/x.json').should_succeed ''
+ it "knife upload succeeds" do
+ knife("upload /environments/x.json").should_succeed "Updated /environments/x.json\n"
+ knife("diff --name-status /environments/x.json").should_succeed ""
end
end
end
- when_the_chef_server 'is empty' do
+ when_the_chef_server "is empty" do
- when_the_repository 'has an environment with the wrong name in the file' do
+ when_the_repository "has an environment with the wrong name in the file" do
before do
- file 'environments/x.json', { 'name' => 'y' }
+ file "environments/x.json", { "name" => "y" }
end
- it 'knife upload fails' do
- knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Error creating 'x.json': Name must be 'x' (is 'y')\n"
- knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n"
+ it "knife upload fails" do
+ knife("upload /environments/x.json").should_fail "ERROR: /environments failed to create_child: Error creating 'x.json': Name must be 'x' (is 'y')\n"
+ knife("diff --name-status /environments/x.json").should_succeed "A\t/environments/x.json\n"
end
end
- when_the_repository 'has an environment with no name in the file' do
+ when_the_repository "has an environment with no name in the file" do
before do
- file 'environments/x.json', { 'description' => 'hi' }
+ file "environments/x.json", { "description" => "hi" }
end
- it 'knife upload succeeds' do
- knife('upload /environments/x.json').should_succeed "Created /environments/x.json\n"
- knife('diff --name-status /environments/x.json').should_succeed ''
+ it "knife upload succeeds" do
+ knife("upload /environments/x.json").should_succeed "Created /environments/x.json\n"
+ knife("diff --name-status /environments/x.json").should_succeed ""
end
end
- when_the_repository 'has a data bag with no id in the file' do
+ when_the_repository "has a data bag with no id in the file" do
before do
- file 'data_bags/bag/x.json', { 'foo' => 'bar' }
+ file "data_bags/bag/x.json", { "foo" => "bar" }
end
- it 'knife upload succeeds' do
- knife('upload /data_bags/bag/x.json').should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n"
- knife('diff --name-status /data_bags/bag/x.json').should_succeed ''
+ it "knife upload succeeds" do
+ knife("upload /data_bags/bag/x.json").should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n"
+ knife("diff --name-status /data_bags/bag/x.json").should_succeed ""
+ end
+ end
+ end
+ when_the_chef_server "is empty" do
+ when_the_repository "has a cookbook with an invalid chef_version constraint in it" do
+ before do
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0", "\nchef_version '~> 999.0'")
+ end
+ it "knife upload succeeds" do
+ knife("upload /cookbooks/x").should_succeed <<EOM
+Created /cookbooks/x
+EOM
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
end
@@ -705,29 +737,29 @@ EOH
when_the_chef_server "has one of each thing" do
before do
- client 'x', {}
- cookbook 'x', '1.0.0'
- data_bag 'x', { 'y' => {} }
- environment 'x', {}
- node 'x', {}
- role 'x', {}
- user 'x', {}
+ client "x", {}
+ cookbook "x", "1.0.0"
+ data_bag "x", { "y" => {} }
+ environment "x", {}
+ node "x", {}
+ role "x", {}
+ user "x", {}
end
- when_the_repository 'has only top-level directories' do
+ when_the_repository "has only top-level directories" do
before do
- directory 'clients'
- directory 'cookbooks'
- directory 'data_bags'
- directory 'environments'
- directory 'nodes'
- directory 'roles'
- directory 'users'
- end
-
- it 'knife upload does nothing' do
- knife('upload /').should_succeed ''
- knife('diff --name-status /').should_succeed <<EOM
+ directory "clients"
+ directory "cookbooks"
+ directory "data_bags"
+ directory "environments"
+ directory "nodes"
+ directory "roles"
+ directory "users"
+ end
+
+ it "knife upload does nothing" do
+ knife("upload /").should_succeed ""
+ knife("diff --name-status /").should_succeed <<EOM
D\t/clients/chef-validator.json
D\t/clients/chef-webui.json
D\t/clients/x.json
@@ -742,8 +774,8 @@ D\t/users/x.json
EOM
end
- it 'knife upload --purge deletes everything' do
- knife('upload --purge /').should_succeed(<<EOM, :stderr => "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n")
+ it "knife upload --purge deletes everything" do
+ knife("upload --purge /").should_succeed(<<EOM, :stderr => "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n")
Deleted extra entry /clients/chef-validator.json (purge is on)
Deleted extra entry /clients/chef-webui.json (purge is on)
Deleted extra entry /clients/x.json (purge is on)
@@ -755,52 +787,52 @@ Deleted extra entry /roles/x.json (purge is on)
Deleted extra entry /users/admin.json (purge is on)
Deleted extra entry /users/x.json (purge is on)
EOM
- knife('diff --name-status /').should_succeed <<EOM
+ knife("diff --name-status /").should_succeed <<EOM
D\t/environments/_default.json
EOM
end
end
- when_the_repository 'has an identical copy of each thing' do
+ when_the_repository "has an identical copy of each thing" do
before do
- file 'clients/chef-validator.json', { 'validator' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
- file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata('x', '1.0.0')
- file 'data_bags/x/y.json', {}
- file 'environments/_default.json', { 'description' => 'The default Chef environment' }
- file 'environments/x.json', {}
- file 'nodes/x.json', {}
- file 'roles/x.json', {}
- file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
- file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+ file "clients/chef-validator.json", { "validator" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "clients/chef-webui.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+ file "data_bags/x/y.json", {}
+ file "environments/_default.json", { "description" => "The default Chef environment" }
+ file "environments/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
+ file "roles/x.json", {}
+ file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+ file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
end
- it 'knife upload makes no changes' do
- knife('upload /cookbooks/x-1.0.0').should_succeed ''
- knife('diff --name-status /').should_succeed ''
+ it "knife upload makes no changes" do
+ knife("upload /cookbooks/x-1.0.0").should_succeed ""
+ knife("diff --name-status /").should_succeed ""
end
- it 'knife upload --purge makes no changes' do
- knife('upload --purge /').should_succeed ''
- knife('diff --name-status /').should_succeed ''
+ it "knife upload --purge makes no changes" do
+ knife("upload --purge /").should_succeed ""
+ knife("diff --name-status /").should_succeed ""
end
- context 'except the role file' do
+ context "except the role file" do
before do
- file 'roles/x.json', { 'description' => 'blarghle' }
+ file "roles/x.json", { "description" => "blarghle" }
end
- it 'knife upload changes the role' do
- knife('upload /').should_succeed "Updated /roles/x.json\n"
- knife('diff --name-status /').should_succeed ''
+ it "knife upload changes the role" do
+ knife("upload /").should_succeed "Updated /roles/x.json\n"
+ knife("diff --name-status /").should_succeed ""
end
end
- context 'except the role file is textually different, but not ACTUALLY different' do
+ context "except the role file is textually different, but not ACTUALLY different" do
before do
- file 'roles/x.json', <<EOM
+ file "roles/x.json", <<EOM
{
"chef_type": "role",
"default_attributes": {
@@ -819,28 +851,28 @@ EOM
EOM
end
- it 'knife upload / does not change anything' do
- knife('upload /').should_succeed ''
- knife('diff --name-status /').should_succeed ''
+ it "knife upload / does not change anything" do
+ knife("upload /").should_succeed ""
+ knife("diff --name-status /").should_succeed ""
end
end
- context 'as well as one extra copy of each thing' do
+ context "as well as one extra copy of each thing" do
before do
- file 'clients/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
- file 'cookbooks/x-1.0.0/blah.rb', ''
- file 'cookbooks/x-2.0.0/metadata.rb', cb_metadata('x', '2.0.0')
- file 'cookbooks/y-1.0.0/metadata.rb', cb_metadata('y', '1.0.0')
- file 'data_bags/x/z.json', {}
- file 'data_bags/y/zz.json', {}
- file 'environments/y.json', {}
- file 'nodes/y.json', {}
- file 'roles/y.json', {}
- file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+ file "clients/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "cookbooks/x-1.0.0/blah.rb", ""
+ file "cookbooks/x-2.0.0/metadata.rb", cb_metadata("x", "2.0.0")
+ file "cookbooks/y-1.0.0/metadata.rb", cb_metadata("y", "1.0.0")
+ file "data_bags/x/z.json", {}
+ file "data_bags/y/zz.json", {}
+ file "environments/y.json", {}
+ file "nodes/y.json", {}
+ file "roles/y.json", {}
+ file "users/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
end
- it 'knife upload adds the new files' do
- knife('upload /').should_succeed <<EOM
+ it "knife upload adds the new files" do
+ knife("upload /").should_succeed <<EOM
Created /clients/y.json
Updated /cookbooks/x-1.0.0
Created /cookbooks/x-2.0.0
@@ -853,15 +885,15 @@ Created /nodes/y.json
Created /roles/y.json
Created /users/y.json
EOM
- knife('diff --name-status /').should_succeed ''
+ knife("diff --name-status /").should_succeed ""
end
end
end
- when_the_repository 'is empty' do
- it 'knife upload does nothing' do
- knife('upload /').should_succeed ''
- knife('diff --name-status /').should_succeed <<EOM
+ when_the_repository "is empty" do
+ it "knife upload does nothing" do
+ knife("upload /").should_succeed ""
+ knife("diff --name-status /").should_succeed <<EOM
D\t/clients
D\t/cookbooks
D\t/data_bags
@@ -872,8 +904,8 @@ D\t/users
EOM
end
- it 'knife upload --purge deletes nothing' do
- knife('upload --purge /').should_fail <<EOM
+ it "knife upload --purge deletes nothing" do
+ knife("upload --purge /").should_fail <<EOM
ERROR: /clients cannot be deleted.
ERROR: /cookbooks cannot be deleted.
ERROR: /data_bags cannot be deleted.
@@ -882,7 +914,7 @@ ERROR: /nodes cannot be deleted.
ERROR: /roles cannot be deleted.
ERROR: /users cannot be deleted.
EOM
- knife('diff --name-status /').should_succeed <<EOM
+ knife("diff --name-status /").should_succeed <<EOM
D\t/clients
D\t/cookbooks
D\t/data_bags
@@ -893,130 +925,130 @@ D\t/users
EOM
end
- context 'when current directory is top level' do
+ context "when current directory is top level" do
before do
- cwd '.'
+ cwd "."
end
- it 'knife upload with no parameters reports an error' do
- knife('upload').should_fail "FATAL: Must specify at least one argument. If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/
+ it "knife upload with no parameters reports an error" do
+ knife("upload").should_fail "FATAL: You must specify at least one argument. If you want to upload everything in this directory, run \"knife upload .\"\n", :stdout => /USAGE/
end
end
end
end
# Test upload of an item when the other end doesn't even have the container
- when_the_chef_server 'is empty' do
- when_the_repository 'has two data bag items' do
+ when_the_chef_server "is empty" do
+ when_the_repository "has two data bag items" do
before do
- file 'data_bags/x/y.json', {}
- file 'data_bags/x/z.json', {}
+ file "data_bags/x/y.json", {}
+ file "data_bags/x/z.json", {}
end
- it 'knife upload of one data bag item itself succeeds' do
- knife('upload /data_bags/x/y.json').should_succeed <<EOM
+ it "knife upload of one data bag item itself succeeds" do
+ knife("upload /data_bags/x/y.json").should_succeed <<EOM
Created /data_bags/x
Created /data_bags/x/y.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
A\t/data_bags/x/z.json
EOM
end
end
end
- when_the_chef_server 'has three data bag items' do
+ when_the_chef_server "has three data bag items" do
before do
- data_bag 'x', { 'deleted' => {}, 'modified' => {}, 'unmodified' => {} }
+ data_bag "x", { "deleted" => {}, "modified" => {}, "unmodified" => {} }
end
- when_the_repository 'has a modified, unmodified, added and deleted data bag item' do
+ when_the_repository "has a modified, unmodified, added and deleted data bag item" do
before do
- file 'data_bags/x/added.json', {}
- file 'data_bags/x/modified.json', { 'foo' => 'bar' }
- file 'data_bags/x/unmodified.json', {}
+ file "data_bags/x/added.json", {}
+ file "data_bags/x/modified.json", { "foo" => "bar" }
+ file "data_bags/x/unmodified.json", {}
end
- it 'knife upload of the modified file succeeds' do
- knife('upload /data_bags/x/modified.json').should_succeed <<EOM
+ it "knife upload of the modified file succeeds" do
+ knife("upload /data_bags/x/modified.json").should_succeed <<EOM
Updated /data_bags/x/modified.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/deleted.json
A\t/data_bags/x/added.json
EOM
end
- it 'knife upload of the unmodified file does nothing' do
- knife('upload /data_bags/x/unmodified.json').should_succeed ''
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ it "knife upload of the unmodified file does nothing" do
+ knife("upload /data_bags/x/unmodified.json").should_succeed ""
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/deleted.json
M\t/data_bags/x/modified.json
A\t/data_bags/x/added.json
EOM
end
- it 'knife upload of the added file succeeds' do
- knife('upload /data_bags/x/added.json').should_succeed <<EOM
+ it "knife upload of the added file succeeds" do
+ knife("upload /data_bags/x/added.json").should_succeed <<EOM
Created /data_bags/x/added.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/deleted.json
M\t/data_bags/x/modified.json
EOM
end
- it 'knife upload of the deleted file does nothing' do
- knife('upload /data_bags/x/deleted.json').should_succeed ''
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ it "knife upload of the deleted file does nothing" do
+ knife("upload /data_bags/x/deleted.json").should_succeed ""
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/deleted.json
M\t/data_bags/x/modified.json
A\t/data_bags/x/added.json
EOM
end
- it 'knife upload --purge of the deleted file deletes it' do
- knife('upload --purge /data_bags/x/deleted.json').should_succeed <<EOM
+ it "knife upload --purge of the deleted file deletes it" do
+ knife("upload --purge /data_bags/x/deleted.json").should_succeed <<EOM
Deleted extra entry /data_bags/x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
M\t/data_bags/x/modified.json
A\t/data_bags/x/added.json
EOM
end
- it 'knife upload of the entire data bag uploads everything' do
- knife('upload /data_bags/x').should_succeed <<EOM
+ it "knife upload of the entire data bag uploads everything" do
+ knife("upload /data_bags/x").should_succeed <<EOM
Created /data_bags/x/added.json
Updated /data_bags/x/modified.json
EOM
- knife('diff --name-status /data_bags').should_succeed <<EOM
+ knife("diff --name-status /data_bags").should_succeed <<EOM
D\t/data_bags/x/deleted.json
EOM
end
- it 'knife upload --purge of the entire data bag uploads everything' do
- knife('upload --purge /data_bags/x').should_succeed <<EOM
+ it "knife upload --purge of the entire data bag uploads everything" do
+ knife("upload --purge /data_bags/x").should_succeed <<EOM
Created /data_bags/x/added.json
Updated /data_bags/x/modified.json
Deleted extra entry /data_bags/x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed ''
+ knife("diff --name-status /data_bags").should_succeed ""
end
- context 'when cwd is the /data_bags directory' do
+ context "when cwd is the /data_bags directory" do
before do
- cwd 'data_bags'
+ cwd "data_bags"
end
- it 'knife upload fails' do
- knife('upload').should_fail "FATAL: Must specify at least one argument. If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/
+ it "knife upload fails" do
+ knife("upload").should_fail "FATAL: You must specify at least one argument. If you want to upload everything in this directory, run \"knife upload .\"\n", :stdout => /USAGE/
end
- it 'knife upload --purge . uploads everything' do
- knife('upload --purge .').should_succeed <<EOM
+ it "knife upload --purge . uploads everything" do
+ knife("upload --purge .").should_succeed <<EOM
Created x/added.json
Updated x/modified.json
Deleted extra entry x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed ''
+ knife("diff --name-status /data_bags").should_succeed ""
end
- it 'knife upload --purge * uploads everything' do
- knife('upload --purge *').should_succeed <<EOM
+ it "knife upload --purge * uploads everything" do
+ knife("upload --purge *").should_succeed <<EOM
Created x/added.json
Updated x/modified.json
Deleted extra entry x/deleted.json (purge is on)
EOM
- knife('diff --name-status /data_bags').should_succeed ''
+ knife("diff --name-status /data_bags").should_succeed ""
end
end
end
@@ -1025,256 +1057,275 @@ EOM
# Cookbook upload is a funny thing ... direct cookbook upload works, but
# upload of a file is designed not to work at present. Make sure that is the
# case.
- when_the_chef_server 'has a cookbook' do
+ when_the_chef_server "has a cookbook" do
before do
- cookbook 'x', '1.0.0', { 'z.rb' => '' }
+ cookbook "x", "1.0.0", { "z.rb" => "" }
end
- when_the_repository 'has a modified, extra and missing file for the cookbook' do
+ when_the_repository "has a modified, extra and missing file for the cookbook" do
before do
- file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata('x', '1.0.0', '#modified')
- file 'cookbooks/x-1.0.0/y.rb', 'hi'
+ file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0", "#modified")
+ file "cookbooks/x-1.0.0/y.rb", "hi"
end
- it 'knife upload of any individual file fails' do
- knife('upload /cookbooks/x-1.0.0/metadata.rb').should_fail "ERROR: /cookbooks/x-1.0.0/metadata.rb cannot be updated.\n"
- knife('upload /cookbooks/x-1.0.0/y.rb').should_fail "ERROR: /cookbooks/x-1.0.0 cannot have a child created under it.\n"
- knife('upload --purge /cookbooks/x-1.0.0/z.rb').should_fail "ERROR: /cookbooks/x-1.0.0/z.rb cannot be deleted.\n"
+ it "knife upload of any individual file fails" do
+ knife("upload /cookbooks/x-1.0.0/metadata.rb").should_fail "ERROR: /cookbooks/x-1.0.0/metadata.rb cannot be updated.\n"
+ knife("upload /cookbooks/x-1.0.0/y.rb").should_fail "ERROR: /cookbooks/x-1.0.0 cannot have a child created under it.\n"
+ knife("upload --purge /cookbooks/x-1.0.0/z.rb").should_fail "ERROR: /cookbooks/x-1.0.0/z.rb cannot be deleted.\n"
end
# TODO this is a bit of an inconsistency: if we didn't specify --purge,
# technically we shouldn't have deleted missing files. But ... cookbooks
# are a special case.
- it 'knife upload of the cookbook itself succeeds' do
- knife('upload /cookbooks/x-1.0.0').should_succeed <<EOM
+ it "knife upload of the cookbook itself succeeds" do
+ knife("upload /cookbooks/x-1.0.0").should_succeed <<EOM
Updated /cookbooks/x-1.0.0
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
- it 'knife upload --purge of the cookbook itself succeeds' do
- knife('upload /cookbooks/x-1.0.0').should_succeed <<EOM
+ it "knife upload --purge of the cookbook itself succeeds" do
+ knife("upload /cookbooks/x-1.0.0").should_succeed <<EOM
Updated /cookbooks/x-1.0.0
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_repository 'has a missing file for the cookbook' do
+ when_the_repository "has a missing file for the cookbook" do
before do
- file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata('x', "1.0.0")
+ file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
end
- it 'knife upload of the cookbook succeeds' do
- knife('upload /cookbooks/x-1.0.0').should_succeed <<EOM
+ it "knife upload of the cookbook succeeds" do
+ knife("upload /cookbooks/x-1.0.0").should_succeed <<EOM
Updated /cookbooks/x-1.0.0
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_repository 'has an extra file for the cookbook' do
+ when_the_repository "has an extra file for the cookbook" do
before do
- file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata('x', '1.0.0')
- file 'cookbooks/x-1.0.0/z.rb', ''
- file 'cookbooks/x-1.0.0/blah.rb', ''
+ file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+ file "cookbooks/x-1.0.0/z.rb", ""
+ file "cookbooks/x-1.0.0/blah.rb", ""
end
- it 'knife upload of the cookbook succeeds' do
- knife('upload /cookbooks/x-1.0.0').should_succeed <<EOM
+ it "knife upload of the cookbook succeeds" do
+ knife("upload /cookbooks/x-1.0.0").should_succeed <<EOM
Updated /cookbooks/x-1.0.0
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
end
- when_the_repository 'has a cookbook' do
+ when_the_repository "has a cookbook" do
before do
- file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata('x', '1.0.0')
- file 'cookbooks/x-1.0.0/onlyin1.0.0.rb', 'old_text'
+ file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+ file "cookbooks/x-1.0.0/onlyin1.0.0.rb", "old_text"
end
- when_the_chef_server 'has a later version for the cookbook' do
+ when_the_chef_server "has a later version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
end
- it 'knife upload /cookbooks uploads the local version' do
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife upload /cookbooks uploads the local version" do
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
M\t/cookbooks/x-1.0.0/onlyin1.0.0.rb
D\t/cookbooks/x-1.0.1
EOM
- knife('upload --purge /cookbooks').should_succeed <<EOM
+ knife("upload --purge /cookbooks").should_succeed <<EOM
Updated /cookbooks/x-1.0.0
Deleted extra entry /cookbooks/x-1.0.1 (purge is on)
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has an earlier version for the cookbook' do
+ when_the_chef_server "has an earlier version for the cookbook" do
before do
- cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+ cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
end
- it 'knife upload /cookbooks uploads the local version' do
- knife('upload --purge /cookbooks').should_succeed <<EOM
+ it "knife upload /cookbooks uploads the local version" do
+ knife("upload --purge /cookbooks").should_succeed <<EOM
Updated /cookbooks/x-1.0.0
Deleted extra entry /cookbooks/x-0.9.9 (purge is on)
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has a later version for the cookbook, and no current version' do
+ when_the_chef_server "has a later version for the cookbook, and no current version" do
before do
- cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+ cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
end
- it 'knife upload /cookbooks/x uploads the local version' do
- knife('diff --name-status /cookbooks').should_succeed <<EOM
+ it "knife upload /cookbooks/x uploads the local version" do
+ knife("diff --name-status /cookbooks").should_succeed <<EOM
D\t/cookbooks/x-1.0.1
A\t/cookbooks/x-1.0.0
EOM
- knife('upload --purge /cookbooks').should_succeed <<EOM
+ knife("upload --purge /cookbooks").should_succeed <<EOM
Created /cookbooks/x-1.0.0
Deleted extra entry /cookbooks/x-1.0.1 (purge is on)
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
- when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
+ when_the_chef_server "has an earlier version for the cookbook, and no current version" do
before do
- cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+ cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
end
- it 'knife upload /cookbooks/x uploads the new version' do
- knife('upload --purge /cookbooks').should_succeed <<EOM
+ it "knife upload /cookbooks/x uploads the new version" do
+ knife("upload --purge /cookbooks").should_succeed <<EOM
Created /cookbooks/x-1.0.0
Deleted extra entry /cookbooks/x-0.9.9 (purge is on)
EOM
- knife('diff --name-status /cookbooks').should_succeed ''
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
end
- when_the_chef_server 'has an environment' do
+ when_the_chef_server "has an environment" do
before do
- environment 'x', {}
+ environment "x", {}
end
- when_the_repository 'has the same environment with the wrong name in the file' do
+ when_the_repository "has the same environment with the wrong name in the file" do
before do
- file 'environments/x.json', { 'name' => 'y' }
+ file "environments/x.json", { "name" => "y" }
end
- it 'knife upload fails' do
- knife('upload /environments/x.json').should_fail "ERROR: /environments/x.json failed to write: Name must be 'x' (is 'y')\n"
- knife('diff --name-status /environments/x.json').should_succeed "M\t/environments/x.json\n"
+ it "knife upload fails" do
+ knife("upload /environments/x.json").should_fail "ERROR: /environments/x.json failed to write: Name must be 'x' (is 'y')\n"
+ knife("diff --name-status /environments/x.json").should_succeed "M\t/environments/x.json\n"
end
end
- when_the_repository 'has the same environment with no name in the file' do
+ when_the_repository "has the same environment with no name in the file" do
before do
- file 'environments/x.json', { 'description' => 'hi' }
+ file "environments/x.json", { "description" => "hi" }
end
- it 'knife upload succeeds' do
- knife('upload /environments/x.json').should_succeed "Updated /environments/x.json\n"
- knife('diff --name-status /environments/x.json').should_succeed ''
+ it "knife upload succeeds" do
+ knife("upload /environments/x.json").should_succeed "Updated /environments/x.json\n"
+ knife("diff --name-status /environments/x.json").should_succeed ""
end
end
end
- when_the_chef_server 'is empty' do
+ when_the_chef_server "is empty" do
- when_the_repository 'has an environment with the wrong name in the file' do
+ when_the_repository "has an environment with the wrong name in the file" do
before do
- file 'environments/x.json', { 'name' => 'y' }
+ file "environments/x.json", { "name" => "y" }
end
- it 'knife upload fails' do
- knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Error creating 'x.json': Name must be 'x' (is 'y')\n"
- knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n"
+ it "knife upload fails" do
+ knife("upload /environments/x.json").should_fail "ERROR: /environments failed to create_child: Error creating 'x.json': Name must be 'x' (is 'y')\n"
+ knife("diff --name-status /environments/x.json").should_succeed "A\t/environments/x.json\n"
end
end
- when_the_repository 'has an environment with no name in the file' do
+ when_the_repository "has an environment with no name in the file" do
before do
- file 'environments/x.json', { 'description' => 'hi' }
+ file "environments/x.json", { "description" => "hi" }
end
- it 'knife upload succeeds' do
- knife('upload /environments/x.json').should_succeed "Created /environments/x.json\n"
- knife('diff --name-status /environments/x.json').should_succeed ''
+ it "knife upload succeeds" do
+ knife("upload /environments/x.json").should_succeed "Created /environments/x.json\n"
+ knife("diff --name-status /environments/x.json").should_succeed ""
end
end
- when_the_repository 'has a data bag with no id in the file' do
+ when_the_repository "has a data bag with no id in the file" do
+ before do
+ file "data_bags/bag/x.json", { "foo" => "bar" }
+ end
+ it "knife upload succeeds" do
+ knife("upload /data_bags/bag/x.json").should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n"
+ knife("diff --name-status /data_bags/bag/x.json").should_succeed ""
+ end
+ end
+ end
+
+ when_the_chef_server "is empty" do
+ when_the_repository "has a cookbook with an invalid chef_version constraint in it" do
before do
- file 'data_bags/bag/x.json', { 'foo' => 'bar' }
+ file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0", "\nchef_version '~> 999.0'")
end
- it 'knife upload succeeds' do
- knife('upload /data_bags/bag/x.json').should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n"
- knife('diff --name-status /data_bags/bag/x.json').should_succeed ''
+ it "knife upload succeeds" do
+ knife("upload /cookbooks/x-1.0.0").should_succeed <<EOM
+Created /cookbooks/x-1.0.0
+EOM
+ knife("diff --name-status /cookbooks").should_succeed ""
end
end
end
end # with versioned cookbooks
- when_the_chef_server 'has a user' do
+ when_the_chef_server "has a user" do
before do
- user 'x', {}
+ user "x", {}
end
- when_the_repository 'has the same user with json_class in it' do
+ when_the_repository "has the same user with json_class in it" do
before do
- file 'users/x.json', { 'admin' => true, 'json_class' => 'Chef::WebUIUser' }
+ file "users/x.json", { "admin" => true, "json_class" => "Chef::WebUIUser" }
end
- it 'knife upload /users/x.json succeeds' do
- knife('upload /users/x.json').should_succeed "Updated /users/x.json\n"
+ it "knife upload /users/x.json succeeds" do
+ knife("upload /users/x.json").should_succeed "Updated /users/x.json\n"
end
end
end
when_the_chef_server "is in Enterprise mode", :osc_compat => false, :single_org => false do
before do
- user 'foo', {}
- user 'bar', {}
- user 'foobar', {}
- organization 'foo', { 'full_name' => 'Something'}
+ user "foo", {}
+ user "bar", {}
+ user "foobar", {}
+ organization "foo", { "full_name" => "Something" }
end
before :each do
- Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo')
+ Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, "/organizations/foo")
end
- context 'and has nothing but a single group named blah' do
- group 'blah', {}
+ context "and has nothing but a single group named blah" do
+ group "blah", {}
- when_the_repository 'has one of each thing' do
+ when_the_repository "has at least one of each thing" do
before do
# TODO We have to upload acls for an existing group due to a lack of
# dependency detection during upload. Fix that!
- file 'acls/groups/blah.json', {}
- file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
- file 'containers/x.json', {}
- file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
- file 'data_bags/x/y.json', {}
- file 'environments/x.json', {}
- file 'groups/x.json', {}
- file 'invitations.json', [ 'foo' ]
- file 'members.json', [ 'bar' ]
- file 'nodes/x.json', {}
- file 'org.json', { 'full_name' => 'wootles' }
- file 'roles/x.json', {}
- end
-
- it 'knife upload / uploads everything' do
- knife('upload /').should_succeed <<EOM
+ file "acls/groups/blah.json", {}
+ file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+ file "containers/x.json", {}
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ file "cookbook_artifacts/x-1x1/metadata.rb", cb_metadata("x", "1.0.0")
+ file "data_bags/x/y.json", {}
+ file "environments/x.json", {}
+ file "groups/x.json", {}
+ file "invitations.json", [ "foo" ]
+ file "members.json", [ "bar" ]
+ file "org.json", { "full_name" => "wootles" }
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
+ file "policies/x-1.0.0.json", {}
+ file "policies/blah-1.0.0.json", {}
+ file "policy_groups/x.json", { "policies" => { "x" => { "revision_id" => "1.0.0" }, "blah" => { "revision_id" => "1.0.0" } } }
+ file "roles/x.json", {}
+ end
+
+ it "knife upload / uploads everything" do
+ knife("upload /").should_succeed <<EOM
Updated /acls/groups/blah.json
Created /clients/x.json
Created /containers/x.json
+Created /cookbook_artifacts/x-1x1
Created /cookbooks/x
Created /data_bags/x
Created /data_bags/x/y.json
@@ -1284,105 +1335,211 @@ Updated /invitations.json
Updated /members.json
Created /nodes/x.json
Updated /org.json
+Created /policies/blah-1.0.0.json
+Created /policies/x-1.0.0.json
+Created /policy_groups/x.json
Created /roles/x.json
EOM
- expect(api.get('association_requests').map { |a| a['username'] }).to eq([ 'foo' ])
- expect(api.get('users').map { |a| a['user']['username'] }).to eq([ 'bar' ])
+ expect(api.get("association_requests").map { |a| a["username"] }).to eq([ "foo" ])
+ expect(api.get("users").map { |a| a["user"]["username"] }).to eq([ "bar" ])
+ knife("diff --name-status --diff-filter=AMT /").should_succeed ""
+ end
+
+ context "When the chef server has an identical copy of each thing" do
+ before do
+ file "invitations.json", [ "foo" ]
+ file "members.json", [ "bar" ]
+ file "org.json", { "full_name" => "Something" }
+
+ # acl_for %w(organizations foo groups blah)
+ client "x", {}
+ cookbook "x", "1.0.0"
+ cookbook_artifact "x", "1x1", "metadata.rb" => cb_metadata("x", "1.0.0")
+ container "x", {}
+ data_bag "x", { "y" => {} }
+ environment "x", {}
+ group "x", {}
+ org_invite "foo"
+ org_member "bar"
+ node "x", {}
+ policy "x", "1.0.0", {}
+ policy "blah", "1.0.0", {}
+ policy_group "x", {
+ "policies" => {
+ "x" => { "revision_id" => "1.0.0" },
+ "blah" => { "revision_id" => "1.0.0" },
+ },
+ }
+ role "x", {}
+ end
+
+ it "knife upload makes no changes" do
+ knife("upload /").should_succeed <<EOM
+Updated /acls/groups/blah.json
+EOM
+ end
+ end
+
+ context "When the chef server has a slightly different copy of the policy revision" do
+ before do
+ policy "x", "1.0.0", { "run_list" => [ "blah" ] }
+ end
+
+ it "should fail because policies are not updateable" do
+ knife("upload /policies/x-1.0.0.json").should_fail <<EOM
+ERROR: /policies/x-1.0.0.json cannot be updated: policy revisions are immutable once uploaded. If you want to change the policy, create a new revision with your changes.
+EOM
+ end
+ end
+
+ context "When the chef server has a slightly different copy of the cookbook artifact" do
+ before do
+ cookbook_artifact "x", "1x1", { "recipes" => { "default.rb" => "" } }
+ end
+
+ it "should fail because cookbook_artifacts cannot be updated" do
+ knife("upload /cookbook_artifacts/x-1x1").should_fail <<EOM
+ERROR: /cookbook_artifacts/x-1x1 cannot be updated: cookbook artifacts are immutable once uploaded.
+EOM
+ end
+ end
+
+ context "When the chef server has a slightly different copy of each thing (except policy revisions)" do
+ before do
+ # acl_for %w(organizations foo groups blah)
+ client "x", { "validator" => true }
+ container "x", {}
+ cookbook "x", "1.0.0", { "recipes" => { "default.rb" => "" } }
+ cookbook_artifact "x", "1x1", { "metadata.rb" => cb_metadata("x", "1.0.0") }
+ data_bag "x", { "y" => { "a" => "b" } }
+ environment "x", { "description" => "foo" }
+ group "x", { "groups" => [ "admin" ] }
+ node "x", { "run_list" => [ "blah" ] }
+ policy "x", "1.0.0", {}
+ policy "x", "1.0.1", {}
+ policy "y", "1.0.0", {}
+ policy_group "x", {
+ "policies" => {
+ "x" => { "revision_id" => "1.0.1" },
+ "y" => { "revision_id" => "1.0.0" },
+ },
+ }
+ role "x", { "run_list" => [ "blah" ] }
+ end
+
+ it "knife upload updates everything" do
+ knife("upload /").should_succeed <<EOM
+Updated /acls/groups/blah.json
+Updated /clients/x.json
+Updated /cookbooks/x
+Updated /data_bags/x/y.json
+Updated /environments/x.json
+Updated /groups/x.json
+Updated /invitations.json
+Updated /members.json
+Updated /nodes/x.json
+Updated /org.json
+Created /policies/blah-1.0.0.json
+Updated /policy_groups/x.json
+Updated /roles/x.json
+EOM
+ knife("diff --name-status --diff-filter=AMT /").should_succeed ""
+ end
end
end
- when_the_repository 'has an org.json that does not change full_name' do
+ when_the_repository "has an org.json that does not change full_name" do
before do
- file 'org.json', { 'full_name' => 'Something' }
+ file "org.json", { "full_name" => "Something" }
end
- it 'knife upload / emits a warning for bar and adds foo and foobar' do
- knife('upload /').should_succeed ''
- expect(api.get('/')['full_name']).to eq('Something')
+ it "knife upload / emits a warning for bar and adds foo and foobar" do
+ knife("upload /").should_succeed ""
+ expect(api.get("/")["full_name"]).to eq("Something")
end
end
- when_the_repository 'has an org.json that changes full_name' do
+ when_the_repository "has an org.json that changes full_name" do
before do
- file 'org.json', { 'full_name' => 'Something Else'}
+ file "org.json", { "full_name" => "Something Else" }
end
- it 'knife upload / emits a warning for bar and adds foo and foobar' do
- knife('upload /').should_succeed "Updated /org.json\n"
- expect(api.get('/')['full_name']).to eq('Something Else')
+ it "knife upload / emits a warning for bar and adds foo and foobar" do
+ knife("upload /").should_succeed "Updated /org.json\n"
+ expect(api.get("/")["full_name"]).to eq("Something Else")
end
end
- context 'and has invited foo and bar is already a member' do
- org_invite 'foo'
- org_member 'bar'
+ context "and has invited foo and bar is already a member" do
+ org_invite "foo"
+ org_member "bar"
- when_the_repository 'wants to invite foo, bar and foobar' do
+ when_the_repository "wants to invite foo, bar and foobar" do
before do
- file 'invitations.json', [ 'foo', 'bar', 'foobar' ]
+ file "invitations.json", %w{foo bar foobar}
end
- it 'knife upload / emits a warning for bar and invites foobar' do
- knife('upload /').should_succeed "Updated /invitations.json\n", :stderr => "WARN: Could not invite bar to organization foo: User bar is already in organization foo\n"
- expect(api.get('association_requests').map { |a| a['username'] }).to eq([ 'foo', 'foobar' ])
- expect(api.get('users').map { |a| a['user']['username'] }).to eq([ 'bar' ])
+ it "knife upload / emits a warning for bar and invites foobar" do
+ knife("upload /").should_succeed "Updated /invitations.json\n", :stderr => "WARN: Could not invite bar to organization foo: User bar is already in organization foo\n"
+ expect(api.get("association_requests").map { |a| a["username"] }).to eq(%w{foo foobar})
+ expect(api.get("users").map { |a| a["user"]["username"] }).to eq([ "bar" ])
end
end
- when_the_repository 'wants to make foo, bar and foobar members' do
+ when_the_repository "wants to make foo, bar and foobar members" do
before do
- file 'members.json', [ 'foo', 'bar', 'foobar' ]
+ file "members.json", %w{foo bar foobar}
end
- it 'knife upload / emits a warning for bar and adds foo and foobar' do
- knife('upload /').should_succeed "Updated /members.json\n"
- expect(api.get('association_requests').map { |a| a['username'] }).to eq([ ])
- expect(api.get('users').map { |a| a['user']['username'] }).to eq([ 'bar', 'foo', 'foobar' ])
+ it "knife upload / emits a warning for bar and adds foo and foobar" do
+ knife("upload /").should_succeed "Updated /members.json\n"
+ expect(api.get("association_requests").map { |a| a["username"] }).to eq([ ])
+ expect(api.get("users").map { |a| a["user"]["username"] }).to eq(%w{bar foo foobar})
end
end
- when_the_repository 'wants to invite foo and have bar as a member' do
+ when_the_repository "wants to invite foo and have bar as a member" do
before do
- file 'invitations.json', [ 'foo' ]
- file 'members.json', [ 'bar' ]
+ file "invitations.json", [ "foo" ]
+ file "members.json", [ "bar" ]
end
- it 'knife upload / does nothing' do
- knife('upload /').should_succeed ''
- expect(api.get('association_requests').map { |a| a['username'] }).to eq([ 'foo' ])
- expect(api.get('users').map { |a| a['user']['username'] }).to eq([ 'bar' ])
+ it "knife upload / does nothing" do
+ knife("upload /").should_succeed ""
+ expect(api.get("association_requests").map { |a| a["username"] }).to eq([ "foo" ])
+ expect(api.get("users").map { |a| a["user"]["username"] }).to eq([ "bar" ])
end
end
end
- context 'and has invited bar and foo' do
- org_invite 'bar', 'foo'
+ context "and has invited bar and foo" do
+ org_invite "bar", "foo"
- when_the_repository 'wants to invite foo and bar (different order)' do
+ when_the_repository "wants to invite foo and bar (different order)" do
before do
- file 'invitations.json', [ 'foo', 'bar' ]
+ file "invitations.json", %w{foo bar}
end
- it 'knife upload / does nothing' do
- knife('upload /').should_succeed ''
- expect(api.get('association_requests').map { |a| a['username'] }).to eq([ 'bar', 'foo' ])
- expect(api.get('users').map { |a| a['user']['username'] }).to eq([ ])
+ it "knife upload / does nothing" do
+ knife("upload /").should_succeed ""
+ expect(api.get("association_requests").map { |a| a["username"] }).to eq(%w{bar foo})
+ expect(api.get("users").map { |a| a["user"]["username"] }).to eq([ ])
end
end
end
- context 'and has already added bar and foo as members of the org' do
- org_member 'bar', 'foo'
+ context "and has already added bar and foo as members of the org" do
+ org_member "bar", "foo"
- when_the_repository 'wants to add foo and bar (different order)' do
+ when_the_repository "wants to add foo and bar (different order)" do
before do
- file 'members.json', [ 'foo', 'bar' ]
+ file "members.json", %w{foo bar}
end
- it 'knife upload / does nothing' do
- knife('upload /').should_succeed ''
- expect(api.get('association_requests').map { |a| a['username'] }).to eq([ ])
- expect(api.get('users').map { |a| a['user']['username'] }).to eq([ 'bar', 'foo' ])
+ it "knife upload / does nothing" do
+ knife("upload /").should_succeed ""
+ expect(api.get("association_requests").map { |a| a["username"] }).to eq([ ])
+ expect(api.get("users").map { |a| a["user"]["username"] }).to eq(%w{bar foo})
end
end
end
diff --git a/spec/integration/recipes/accumulator_spec.rb b/spec/integration/recipes/accumulator_spec.rb
new file mode 100644
index 0000000000..e6afe09b8c
--- /dev/null
+++ b/spec/integration/recipes/accumulator_spec.rb
@@ -0,0 +1,232 @@
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
+
+describe "Accumulators" do
+ include IntegrationSupport
+ include Chef::Mixin::ShellOut
+
+ let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) }
+
+ # Invoke `chef-client` as `ruby PATH/TO/chef-client`. This ensures the
+ # following constraints are satisfied:
+ # * Windows: windows can only run batch scripts as bare executables. Rubygems
+ # creates batch wrappers for installed gems, but we don't have batch wrappers
+ # in the source tree.
+ # * Other `chef-client` in PATH: A common case is running the tests on a
+ # machine that has omnibus chef installed. In that case we need to ensure
+ # we're running `chef-client` from the source tree and not the external one.
+ # cf. CHEF-4914
+ let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+
+ let(:aliases_temppath) do
+ t = Tempfile.new("chef_accumulator_test")
+ path = t.path
+ t.close
+ t.unlink
+ path
+ end
+
+ when_the_repository "edit_resource-based delayed accumulators work" do
+ before do
+ directory "cookbooks/x" do
+ file "resources/email_alias.rb", <<-EOM
+ provides :email_alias
+ resource_name :email_alias
+
+ property :address, String, name_property: true, identity: true
+ property :recipients, Array
+
+ default_action :create
+
+ action :create do
+ with_run_context :root do
+ edit_resource(:template, "#{aliases_temppath}") do |new_resource|
+ source "aliases.erb"
+ variables[:aliases] ||= {}
+ variables[:aliases][new_resource.address] ||= []
+ variables[:aliases][new_resource.address] += new_resource.recipients
+ action :nothing
+ delayed_action :create
+ end
+ end
+ end
+ EOM
+
+ file "resources/nested.rb", <<-EOM
+ provides :nested
+ resource_name :nested
+
+ property :address, String, name_property: true, identity: true
+ property :recipients, Array
+
+ default_action :create
+
+ action :create do
+ email_alias address do
+ recipients new_resource.recipients
+ end
+ end
+ EOM
+
+ file "resources/doubly_nested.rb", <<-EOM
+ provides :doubly_nested
+ resource_name :doubly_nested
+
+ property :address, String, name_property: true, identity: true
+ property :recipients, Array
+
+ default_action :create
+
+ action :create do
+ nested address do
+ recipients new_resource.recipients
+ end
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ email_alias "outer1" do
+ recipients [ "out1a", "out1b" ]
+ end
+
+ nested "nested1" do
+ recipients [ "nested1a", "nested1b" ]
+ end
+
+ email_alias "outer2" do
+ recipients [ "out2a", "out2b" ]
+ end
+
+ doubly_nested "nested2" do
+ recipients [ "nested2a", "nested2b" ]
+ end
+
+ email_alias "outer3" do
+ recipients [ "out3a", "out3b" ]
+ end
+ EOM
+
+ file "templates/aliases.erb", <<-EOM.gsub(/^\s+/, "")
+ <%= pp @aliases %>
+ EOM
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<-EOM
+ local_mode true
+ cookbook_path "#{path_to('cookbooks')}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir)
+ result.error!
+ # runs only a single template resource (in the outer run context, as a delayed resource)
+ expect(result.stdout.scan(/template\S+ action create/).size).to eql(1)
+ # hash order is insertion order in ruby >= 1.9, so this next line does test that all calls were in the correct order
+ expect(IO.read(aliases_temppath).chomp).to eql('{"outer1"=>["out1a", "out1b"], "nested1"=>["nested1a", "nested1b"], "outer2"=>["out2a", "out2b"], "nested2"=>["nested2a", "nested2b"], "outer3"=>["out3a", "out3b"]}')
+ end
+ end
+
+ when_the_repository "find_resource-based delayed accumulators work" do
+ before do
+ directory "cookbooks/x" do
+ file "resources/email_alias.rb", <<-EOM
+ provides :email_alias
+ resource_name :email_alias
+
+ property :address, String, name_property: true, identity: true
+ property :recipients, Array
+
+ default_action :create
+
+ action :create do
+ r = with_run_context :root do
+ find_resource(:template, "#{aliases_temppath}") do
+ source "aliases.erb"
+ variables[:aliases] = {}
+ action :nothing
+ delayed_action :create
+ end
+ end
+ r.variables[:aliases][address] ||= []
+ r.variables[:aliases][address] += new_resource.recipients
+ end
+ EOM
+
+ file "resources/nested.rb", <<-EOM
+ provides :nested
+ resource_name :nested
+
+ property :address, String, name_property: true, identity: true
+ property :recipients, Array
+
+ default_action :create
+
+ action :create do
+ email_alias address do
+ recipients new_resource.recipients
+ end
+ end
+ EOM
+
+ file "resources/doubly_nested.rb", <<-EOM
+ provides :doubly_nested
+ resource_name :doubly_nested
+
+ property :address, String, name_property: true, identity: true
+ property :recipients, Array
+
+ default_action :create
+
+ action :create do
+ nested address do
+ recipients new_resource.recipients
+ end
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ email_alias "outer1" do
+ recipients [ "out1a", "out1b" ]
+ end
+
+ nested "nested1" do
+ recipients [ "nested1a", "nested1b" ]
+ end
+
+ email_alias "outer2" do
+ recipients [ "out2a", "out2b" ]
+ end
+
+ doubly_nested "nested2" do
+ recipients [ "nested2a", "nested2b" ]
+ end
+
+ email_alias "outer3" do
+ recipients [ "out3a", "out3b" ]
+ end
+ EOM
+
+ file "templates/aliases.erb", <<-EOM.gsub(/^\s+/, "")
+ <%= pp @aliases %>
+ EOM
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<-EOM
+ local_mode true
+ cookbook_path "#{path_to('cookbooks')}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir)
+ result.error!
+ # runs only a single template resource (in the outer run context, as a delayed resource)
+ expect(result.stdout.scan(/template\S+ action create/).size).to eql(1)
+ # hash order is insertion order in ruby >= 1.9, so this next line does test that all calls were in the correct order
+ expect(IO.read(aliases_temppath).chomp).to eql('{"outer1"=>["out1a", "out1b"], "nested1"=>["nested1a", "nested1b"], "outer2"=>["out2a", "out2b"], "nested2"=>["nested2a", "nested2b"], "outer3"=>["out3a", "out3b"]}')
+ end
+ end
+end
diff --git a/spec/integration/recipes/lwrp_inline_resources_spec.rb b/spec/integration/recipes/lwrp_inline_resources_spec.rb
index e70605d3d3..65931d4764 100644
--- a/spec/integration/recipes/lwrp_inline_resources_spec.rb
+++ b/spec/integration/recipes/lwrp_inline_resources_spec.rb
@@ -1,5 +1,5 @@
-require 'support/shared/integration/integration_helper'
-require 'chef/mixin/shell_out'
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
describe "LWRPs with inline resources" do
include IntegrationSupport
@@ -18,41 +18,138 @@ describe "LWRPs with inline resources" do
# cf. CHEF-4914
let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ context "with a use_inline_resources provider with 'def action_a' instead of action :a" do
+ class LwrpInlineResourcesTest < Chef::Resource::LWRPBase
+ resource_name :lwrp_inline_resources_test
+ actions :a, :nothing
+ default_action :a
+ property :ran_a
+ class Provider < Chef::Provider::LWRPBase
+ provides :lwrp_inline_resources_test
+ use_inline_resources
+ def action_a
+ r = new_resource
+ ruby_block "run a" do
+ block { r.ran_a "ran a" }
+ end
+ end
+ end
+ end
+
+ it "this is totally a bug, but for backcompat purposes, it adds the resources to the main resource collection and does not get marked updated" do
+ r = nil
+ expect_recipe do
+ r = lwrp_inline_resources_test "hi"
+ end.to have_updated("ruby_block[run a]", :run)
+ expect(r.ran_a).to eq "ran a"
+ end
+ end
+
+ context "with an inline resource with a property that shadows the enclosing provider's property" do
+ class LwrpShadowedPropertyTest < Chef::Resource::LWRPBase
+ PATH = ::File.join(Dir.tmpdir, "shadow-property.txt")
+ use_automatic_resource_name
+ actions :fiddle
+ property :content
+ action :fiddle do
+ file PATH do
+ content new_resource.content
+ action [:create, :delete]
+ end
+ end
+ end
+
+ after { File.delete(LwrpShadowedPropertyTest::PATH) if File.exists?(LwrpShadowedPropertyTest::PATH) }
+
+ # https://github.com/chef/chef/issues/4334
+ it "does not warn spuriously" do
+ expect(Chef::Log).to_not receive(:warn).with(/is declared in both/)
+ expect_recipe do
+ lwrp_shadowed_property_test "fnord" do
+ action :fiddle
+ end
+ end
+ end
+ end
+
+ context "with an inline_resources provider with two actions, one calling the other" do
+ class LwrpInlineResourcesTest2 < Chef::Resource::LWRPBase
+ resource_name :lwrp_inline_resources_test2
+ actions :a, :b, :nothing
+ default_action :b
+ property :ran_a
+ property :ran_b
+ class Provider < Chef::Provider::LWRPBase
+ provides :lwrp_inline_resources_test2
+ use_inline_resources
+
+ action :a do
+ r = new_resource
+ ruby_block "run a" do
+ block { r.ran_a "ran a" }
+ end
+ end
+
+ action :b do
+ action_a
+ r = new_resource
+ # Grab ran_a right now, before we converge
+ ran_a = r.ran_a
+ ruby_block "run b" do
+ block { r.ran_b "ran b: ran_a value was #{ran_a.inspect}" }
+ end
+ end
+ end
+ end
+
+ it "resources declared in b are executed immediately inline" do
+ r = nil
+ expect_recipe do
+ r = lwrp_inline_resources_test2 "hi" do
+ action :b
+ end
+ end.to have_updated("lwrp_inline_resources_test2[hi]", :b).
+ and have_updated("ruby_block[run a]", :run).
+ and have_updated("ruby_block[run b]", :run)
+ expect(r.ran_b).to eq "ran b: ran_a value was \"ran a\""
+ end
+ end
+
when_the_repository "has a cookbook with a nested LWRP" do
before do
- directory 'cookbooks/x' do
+ directory "cookbooks/x" do
- file 'resources/do_nothing.rb', <<EOM
-actions :create, :nothing
-default_action :create
-EOM
- file 'providers/do_nothing.rb', <<EOM
-action :create do
-end
-EOM
+ file "resources/do_nothing.rb", <<-EOM
+ actions :create, :nothing
+ default_action :create
+ EOM
+ file "providers/do_nothing.rb", <<-EOM
+ action :create do
+ end
+ EOM
- file 'resources/my_machine.rb', <<EOM
-actions :create, :nothing
-default_action :create
-EOM
- file 'providers/my_machine.rb', <<EOM
-use_inline_resources
-action :create do
- x_do_nothing 'a'
- x_do_nothing 'b'
-end
-EOM
+ file "resources/my_machine.rb", <<-EOM
+ actions :create, :nothing
+ default_action :create
+ EOM
+ file "providers/my_machine.rb", <<-EOM
+ use_inline_resources
+ action :create do
+ x_do_nothing 'a'
+ x_do_nothing 'b'
+ end
+ EOM
- file 'recipes/default.rb', <<EOM
-x_my_machine "me"
-x_my_machine "you"
-EOM
+ file "recipes/default.rb", <<-EOM
+ x_my_machine "me"
+ x_my_machine "you"
+ EOM
end # directory 'cookbooks/x'
end
it "should complete with success" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
log_level :warn
diff --git a/spec/integration/recipes/lwrp_spec.rb b/spec/integration/recipes/lwrp_spec.rb
index 7ecdfc7c3a..3bc008d4f8 100644
--- a/spec/integration/recipes/lwrp_spec.rb
+++ b/spec/integration/recipes/lwrp_spec.rb
@@ -1,5 +1,5 @@
-require 'support/shared/integration/integration_helper'
-require 'chef/mixin/shell_out'
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
describe "LWRPs" do
include IntegrationSupport
@@ -20,17 +20,17 @@ describe "LWRPs" do
when_the_repository "has a cookbook named l-w-r-p" do
before do
- directory 'cookbooks/l-w-r-p' do
+ directory "cookbooks/l-w-r-p" do
- file 'resources/foo.rb', <<EOM
+ file "resources/foo.rb", <<EOM
default_action :create
EOM
- file 'providers/foo.rb', <<EOM
+ file "providers/foo.rb", <<EOM
action :create do
end
EOM
- file 'recipes/default.rb', <<EOM
+ file "recipes/default.rb", <<EOM
l_w_r_p_foo "me"
EOM
@@ -38,7 +38,7 @@ EOM
end
it "should complete with success" do
- file 'config/client.rb', <<EOM
+ file "config/client.rb", <<EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
log_level :warn
diff --git a/spec/integration/recipes/noop_resource_spec.rb b/spec/integration/recipes/noop_resource_spec.rb
new file mode 100644
index 0000000000..e0cf47c371
--- /dev/null
+++ b/spec/integration/recipes/noop_resource_spec.rb
@@ -0,0 +1,24 @@
+require "support/shared/integration/integration_helper"
+
+describe "Resources with a no-op provider" do
+ include IntegrationSupport
+
+ context "with noop provider providing foo" do
+ before(:context) do
+ class NoOpFoo < Chef::Resource
+ resource_name "hi_there"
+ default_action :update
+ end
+ Chef::Provider::Noop.provides :hi_there
+ end
+
+ it "does not blow up a run with a noop'd resource" do
+ recipe = converge do
+ hi_there "blah" do
+ action :update
+ end
+ end
+ expect(recipe.logged_warnings).to eq ""
+ end
+ end
+end
diff --git a/spec/integration/recipes/notifies_spec.rb b/spec/integration/recipes/notifies_spec.rb
new file mode 100644
index 0000000000..000f5e37bf
--- /dev/null
+++ b/spec/integration/recipes/notifies_spec.rb
@@ -0,0 +1,334 @@
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
+
+describe "notifications" do
+ include IntegrationSupport
+ include Chef::Mixin::ShellOut
+
+ let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) }
+ let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+
+ when_the_repository "notifies delayed one" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/notifying_test.rb", <<EOM
+default_action :run
+provides :notifying_test
+resource_name :notifying_test
+
+action :run do
+ log "bar" do
+ notifies :write, 'log[foo]', :delayed
+ end
+end
+EOM
+
+ file "recipes/default.rb", <<EOM
+log "foo" do
+ action :nothing
+end
+notifying_test "whatever"
+log "baz"
+EOM
+
+ end
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+log_level :warn
+EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir)
+ # our delayed notification should run at the end of the parent run_context after the baz resource
+ expect(result.stdout).to match(/\* log\[bar\] action write\s+\* log\[baz\] action write\s+\* log\[foo\] action write/)
+ result.error!
+ end
+ end
+
+ when_the_repository "notifies delayed two" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/notifying_test.rb", <<EOM
+default_action :run
+provides :notifying_test
+resource_name :notifying_test
+
+action :run do
+ log "bar" do
+ notifies :write, 'log[foo]', :delayed
+ end
+end
+EOM
+
+ file "recipes/default.rb", <<EOM
+log "foo" do
+ action :nothing
+end
+notifying_test "whatever"
+log "baz" do
+ notifies :write, 'log[foo]', :delayed
+end
+EOM
+
+ end
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+log_level :warn
+EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir)
+ # our delayed notification should run at the end of the parent run_context after the baz resource
+ expect(result.stdout).to match(/\* log\[bar\] action write\s+\* log\[baz\] action write\s+\* log\[foo\] action write/)
+ # and only run once
+ expect(result.stdout).not_to match(/\* log\[foo\] action write.*\* log\[foo\] action write/)
+ result.error!
+ end
+ end
+
+ when_the_repository "notifies delayed three" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/notifying_test.rb", <<EOM
+default_action :run
+provides :notifying_test
+resource_name :notifying_test
+
+action :run do
+ log "bar" do
+ notifies :write, 'log[foo]', :delayed
+ end
+end
+EOM
+
+ file "recipes/default.rb", <<EOM
+log "foo" do
+ action :nothing
+end
+log "quux" do
+ notifies :write, 'log[foo]', :delayed
+ notifies :write, 'log[baz]', :delayed
+end
+notifying_test "whatever"
+log "baz"
+EOM
+
+ end
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+log_level :warn
+EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir)
+ # the delayed notification from the sub-resource is de-duplicated by the notification already in the parent run_context
+ expect(result.stdout).to match(/\* log\[quux\] action write\s+\* notifying_test\[whatever\] action run\s+\* log\[bar\] action write\s+\* log\[baz\] action write\s+\* log\[foo\] action write\s+\* log\[baz\] action write/)
+ # and only run once
+ expect(result.stdout).not_to match(/\* log\[foo\] action write.*\* log\[foo\] action write/)
+ result.error!
+ end
+ end
+
+ when_the_repository "notifies delayed four" do
+ before do
+ directory "cookbooks/x" do
+ file "recipes/default.rb", <<EOM
+log "foo" do
+ action :nothing
+end
+log "bar" do
+ notifies :write, 'log[foo]', :delayed
+end
+log "baz" do
+ notifies :write, 'log[foo]', :delayed
+end
+EOM
+
+ end
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+log_level :warn
+EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir)
+ # the delayed notification from the sub-resource is de-duplicated by the notification already in the parent run_context
+ expect(result.stdout).to match(/\* log\[bar\] action write\s+\* log\[baz\] action write\s+\* log\[foo\] action write/)
+ # and only run once
+ expect(result.stdout).not_to match(/\* log\[foo\] action write.*\* log\[foo\] action write/)
+ result.error!
+ end
+ end
+
+ when_the_repository "notifies immediately" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/notifying_test.rb", <<EOM
+default_action :run
+provides :notifying_test
+resource_name :notifying_test
+
+action :run do
+ log "bar" do
+ notifies :write, 'log[foo]', :immediately
+ end
+end
+EOM
+
+ file "recipes/default.rb", <<EOM
+log "foo" do
+ action :nothing
+end
+notifying_test "whatever"
+log "baz"
+EOM
+
+ end
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+log_level :warn
+EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir)
+ expect(result.stdout).to match(/\* log\[bar\] action write\s+\* log\[foo\] action write\s+\* log\[baz\] action write/)
+ result.error!
+ end
+ end
+
+ when_the_repository "uses old notifies syntax" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/notifying_test.rb", <<EOM
+default_action :run
+provides :notifying_test
+resource_name :notifying_test
+
+action :run do
+ log "bar" do
+ notifies :write, resources(log: "foo"), :immediately
+ end
+end
+EOM
+
+ file "recipes/default.rb", <<EOM
+log "foo" do
+ action :nothing
+end
+notifying_test "whatever"
+log "baz"
+EOM
+
+ end
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+log_level :warn
+EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir)
+ expect(result.stdout).to match(/\* log\[bar\] action write\s+\* log\[foo\] action write\s+\* log\[baz\] action write/)
+ result.error!
+ end
+ end
+
+ when_the_repository "does not have a matching resource" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/notifying_test.rb", <<EOM
+default_action :run
+provides :notifying_test
+resource_name :notifying_test
+
+action :run do
+ log "bar" do
+ notifies :write, "log[foo]"
+ end
+end
+EOM
+
+ file "recipes/default.rb", <<EOM
+notifying_test "whatever"
+log "baz"
+EOM
+
+ end
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+log_level :warn
+EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir)
+ expect(result.stdout).to match(/Chef::Exceptions::ResourceNotFound/)
+ expect(result.exitstatus).not_to eql(0)
+ end
+ end
+
+ when_the_repository "encounters identical resources in parent and child resource collections" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/cloning_test.rb", <<EOM
+default_action :run
+provides :cloning_test
+resource_name :cloning_test
+
+action :run do
+ log "bar" do
+ level :info
+ end
+end
+EOM
+
+ file "recipes/default.rb", <<EOM
+log "bar" do
+ level :warn
+end
+
+cloning_test "whatever"
+EOM
+
+ end
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+log_level :warn
+EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir)
+ expect(result.stdout).not_to match(/CHEF-3694/)
+ result.error!
+ end
+ end
+end
diff --git a/spec/integration/recipes/notifying_block_spec.rb b/spec/integration/recipes/notifying_block_spec.rb
new file mode 100644
index 0000000000..6a1287c7b1
--- /dev/null
+++ b/spec/integration/recipes/notifying_block_spec.rb
@@ -0,0 +1,111 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
+
+describe "notifying_block" do
+ include IntegrationSupport
+ include Chef::Mixin::ShellOut
+
+ let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) }
+ let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+
+ when_the_repository "notifying_block test one" do
+ before do
+ directory "cookbooks/x" do
+ file "recipes/default.rb", <<-EOM
+ notifying_block do
+ log "gamma" do
+ action :nothing
+ end
+ log "alpha" do
+ notifies :write, "log[gamma]", :delayed
+ end
+ log "beta" do
+ notifies :write, "log[gamma]", :delayed
+ end
+ end
+ log "delta"
+ EOM
+ end
+ file "config/client.rb", <<-EOM
+ local_mode true
+ cookbook_path "#{path_to('cookbooks')}"
+ log_level :warn
+ EOM
+ end
+
+ # implicitly tests -
+ # 1. notifying block opens up a subcontext
+ # 2. delayed notifications are de-dup'd in the subcontext
+ # 3. delayed notifications (to resources inside the subcontext) are run at the end of the subcontext
+ it "should run alpha, beta, gamma, and delta in that order" do
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir)
+ expect(result.stdout).to match(/\* log\[alpha\] action write\s+\* log\[beta\] action write\s+\* log\[gamma\] action write\s+Converging 1 resources\s+\* log\[delta\] action write/)
+ result.error!
+ end
+ end
+
+ when_the_repository "notifying_block test two" do
+ before do
+ directory "cookbooks/x" do
+ file "resources/nb_test.rb", <<-EOM
+ default_action :run
+ provides :nb_test
+ resource_name :nb_test
+
+ action :run do
+ notifying_block do
+ log "foo" do
+ notifies :write, 'log[bar]', :delayed
+ end
+ end
+ end
+ EOM
+ file "recipes/default.rb", <<-EOM
+ log "bar" do
+ action :nothing
+ end
+ log "baz" do
+ action :nothing
+ end
+
+ nb_test "testing" do
+ notifies :write, 'log[baz]', :delayed
+ end
+
+ log "quux"
+ EOM
+ end
+ file "config/client.rb", <<-EOM
+ local_mode true
+ cookbook_path "#{path_to('cookbooks')}"
+ log_level :warn
+ EOM
+ end
+
+ # implicitly tests -
+ # 1. notifying block will correctly update wrapping new_resource updated_by_last_action status
+ # 2. delayed notifications from a subcontext inside a resource will notify resources in their outer run_context
+ it "should run foo, quux, bar, and baz in that order" do
+ result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir)
+ expect(result.stdout).to match(/\* log\[foo\] action write\s+\* log\[quux\] action write\s+\* log\[bar\] action write\s+\* log\[baz\] action write/)
+ result.error!
+ end
+ end
+end
diff --git a/spec/integration/recipes/provider_choice.rb b/spec/integration/recipes/provider_choice.rb
index 01537b2c05..1895d93891 100644
--- a/spec/integration/recipes/provider_choice.rb
+++ b/spec/integration/recipes/provider_choice.rb
@@ -1,4 +1,4 @@
-require 'support/shared/integration/integration_helper'
+require "support/shared/integration/integration_helper"
describe "Recipe DSL methods" do
include IntegrationSupport
@@ -18,6 +18,7 @@ describe "Recipe DSL methods" do
class Chef::Provider::ProviderThingy < Chef::Provider
def load_current_resource
end
+
def action_create
Chef::Log.warn("hello from #{self.class.name}")
end
@@ -25,9 +26,9 @@ describe "Recipe DSL methods" do
end
it "provider_thingy 'blah' runs the provider and warns" do
- recipe = converge {
- provider_thingy 'blah' do; end
- }
+ recipe = converge do
+ provider_thingy("blah") {}
+ end
expect(recipe.logged_warnings).to match /hello from Chef::Provider::ProviderThingy/
expect(recipe.logged_warnings).to match /you must use 'provides' to provide DSL/i
end
diff --git a/spec/integration/recipes/recipe_dsl_spec.rb b/spec/integration/recipes/recipe_dsl_spec.rb
index 52bca87c99..e2fa7df1fc 100644
--- a/spec/integration/recipes/recipe_dsl_spec.rb
+++ b/spec/integration/recipes/recipe_dsl_spec.rb
@@ -1,4 +1,4 @@
-require 'support/shared/integration/integration_helper'
+require "support/shared/integration/integration_helper"
describe "Recipe DSL methods" do
include IntegrationSupport
@@ -12,10 +12,10 @@ describe "Recipe DSL methods" do
before { Namer.current_index += 1 }
context "with resource 'base_thingy' declared as BaseThingy" do
- before(:context) {
+ before(:context) do
class BaseThingy < Chef::Resource
- resource_name 'base_thingy'
+ resource_name "base_thingy"
default_action :create
class<<self
@@ -30,6 +30,7 @@ describe "Recipe DSL methods" do
class Provider < Chef::Provider
def load_current_resource
end
+
def action_create
BaseThingy.created_name = new_resource.name
BaseThingy.created_resource = new_resource.class
@@ -42,7 +43,7 @@ describe "Recipe DSL methods" do
module RecipeDSLSpecNamespace; end
module RecipeDSLSpecNamespace::Bar; end
- }
+ end
before :each do
BaseThingy.created_resource = nil
@@ -50,28 +51,28 @@ describe "Recipe DSL methods" do
end
it "creates base_thingy when you call base_thingy in a recipe" do
- recipe = converge {
- base_thingy 'blah' do; end
- }
- expect(recipe.logged_warnings).to eq ''
- expect(BaseThingy.created_name).to eq 'blah'
+ recipe = converge do
+ base_thingy("blah") {}
+ end
+ expect(recipe.logged_warnings).to eq ""
+ expect(BaseThingy.created_name).to eq "blah"
expect(BaseThingy.created_resource).to eq BaseThingy
end
it "errors out when you call base_thingy do ... end in a recipe" do
- expect_converge {
- base_thingy do; end
- }.to raise_error(ArgumentError, 'You must supply a name when declaring a base_thingy resource')
+ expect_converge do
+ base_thingy { ; }
+ end.to raise_error(ArgumentError, "You must supply a name when declaring a base_thingy resource")
end
it "emits a warning when you call base_thingy 'foo', 'bar' do ... end in a recipe" do
Chef::Config[:treat_deprecation_warnings_as_errors] = false
- recipe = converge {
- base_thingy 'foo', 'bar' do
+ recipe = converge do
+ base_thingy "foo", "bar" do
end
- }
+ end
expect(recipe.logged_warnings).to match(/Cannot create resource base_thingy with more than one argument. All arguments except the name \("foo"\) will be ignored. This will cause an error in Chef 13. Arguments: \["foo", "bar"\]/)
- expect(BaseThingy.created_name).to eq 'foo'
+ expect(BaseThingy.created_name).to eq "foo"
expect(BaseThingy.created_resource).to eq BaseThingy
end
@@ -81,7 +82,7 @@ describe "Recipe DSL methods" do
end
context "with a resource 'backcompat_thingy' declared in Chef::Resource and Chef::Provider" do
- before(:context) {
+ before(:context) do
class Chef::Resource::BackcompatThingy < Chef::Resource
default_action :create
@@ -89,36 +90,37 @@ describe "Recipe DSL methods" do
class Chef::Provider::BackcompatThingy < Chef::Provider
def load_current_resource
end
+
def action_create
BaseThingy.created_resource = new_resource.class
BaseThingy.created_provider = self.class
end
end
- }
+ end
it "backcompat_thingy creates a Chef::Resource::BackcompatThingy" do
- recipe = converge {
- backcompat_thingy 'blah' do; end
- }
+ recipe = converge do
+ backcompat_thingy("blah") {}
+ end
expect(BaseThingy.created_resource).to eq Chef::Resource::BackcompatThingy
expect(BaseThingy.created_provider).to eq Chef::Provider::BackcompatThingy
end
context "and another resource 'backcompat_thingy' in BackcompatThingy with 'provides'" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::BackcompatThingy < BaseThingy
provides :backcompat_thingy
resource_name :backcompat_thingy
end
- }
+ end
it "backcompat_thingy creates a BackcompatThingy" do
- recipe = converge {
- backcompat_thingy 'blah' do; end
- }
+ recipe = converge do
+ backcompat_thingy("blah") {}
+ end
expect(recipe.logged_warnings).to match(/Class Chef::Provider::BackcompatThingy does not declare 'provides :backcompat_thingy'./)
expect(BaseThingy.created_resource).not_to be_nil
end
@@ -126,307 +128,307 @@ describe "Recipe DSL methods" do
end
context "with a resource named RecipeDSLSpecNamespace::Bar::BarThingy" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Bar::BarThingy < BaseThingy
end
- }
+ end
it "bar_thingy does not work" do
- expect_converge {
- bar_thingy 'blah' do; end
- }.to raise_error(NoMethodError)
+ expect_converge do
+ bar_thingy("blah") {}
+ end.to raise_error(NoMethodError)
end
end
context "with a resource named Chef::Resource::NoNameThingy with resource_name nil" do
- before(:context) {
+ before(:context) do
class Chef::Resource::NoNameThingy < BaseThingy
resource_name nil
end
- }
+ end
it "no_name_thingy does not work" do
- expect_converge {
- no_name_thingy 'blah' do; end
- }.to raise_error(NoMethodError)
+ expect_converge do
+ no_name_thingy("blah") {}
+ end.to raise_error(NoMethodError)
end
end
context "with a resource named AnotherNoNameThingy with resource_name :another_thingy_name" do
- before(:context) {
+ before(:context) do
class AnotherNoNameThingy < BaseThingy
resource_name :another_thingy_name
end
- }
+ end
it "another_no_name_thingy does not work" do
- expect_converge {
- another_no_name_thingy 'blah' do; end
- }.to raise_error(NoMethodError)
+ expect_converge do
+ another_no_name_thingy("blah") {}
+ end.to raise_error(NoMethodError)
end
it "another_thingy_name works" do
- recipe = converge {
- another_thingy_name 'blah' do; end
- }
- expect(recipe.logged_warnings).to eq ''
+ recipe = converge do
+ another_thingy_name("blah") {}
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq(AnotherNoNameThingy)
end
end
context "with a resource named AnotherNoNameThingy2 with resource_name :another_thingy_name2; resource_name :another_thingy_name3" do
- before(:context) {
+ before(:context) do
class AnotherNoNameThingy2 < BaseThingy
resource_name :another_thingy_name2
resource_name :another_thingy_name3
end
- }
+ end
it "another_no_name_thingy does not work" do
- expect_converge {
- another_no_name_thingy2 'blah' do; end
- }.to raise_error(NoMethodError)
+ expect_converge do
+ another_no_name_thingy2("blah") {}
+ end.to raise_error(NoMethodError)
end
it "another_thingy_name2 does not work" do
- expect_converge {
- another_thingy_name2 'blah' do; end
- }.to raise_error(NoMethodError)
+ expect_converge do
+ another_thingy_name2("blah") {}
+ end.to raise_error(NoMethodError)
end
it "yet_another_thingy_name3 works" do
- recipe = converge {
- another_thingy_name3 'blah' do; end
- }
- expect(recipe.logged_warnings).to eq ''
+ recipe = converge do
+ another_thingy_name3("blah") {}
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq(AnotherNoNameThingy2)
end
end
context "provides overriding resource_name" do
context "with a resource named AnotherNoNameThingy3 with provides :another_no_name_thingy3, os: 'blarghle'" do
- before(:context) {
+ before(:context) do
class AnotherNoNameThingy3 < BaseThingy
resource_name :another_no_name_thingy_3
- provides :another_no_name_thingy3, os: 'blarghle'
+ provides :another_no_name_thingy3, os: "blarghle"
end
- }
+ end
it "and os = linux, another_no_name_thingy3 does not work" do
- expect_converge {
+ expect_converge do
# TODO this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'linux'
- another_no_name_thingy3 'blah' do; end
- }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+ run_context.node.automatic[:os] = "linux"
+ another_no_name_thingy3("blah") {}
+ end.to raise_error(Chef::Exceptions::NoSuchResourceType)
end
it "and os = blarghle, another_no_name_thingy3 works" do
- recipe = converge {
+ recipe = converge do
# TODO this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'blarghle'
- another_no_name_thingy3 'blah' do; end
- }
- expect(recipe.logged_warnings).to eq ''
+ run_context.node.automatic[:os] = "blarghle"
+ another_no_name_thingy3("blah") {}
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy3)
end
end
context "with a resource named AnotherNoNameThingy4 with two provides" do
- before(:context) {
+ before(:context) do
class AnotherNoNameThingy4 < BaseThingy
resource_name :another_no_name_thingy_4
- provides :another_no_name_thingy4, os: 'blarghle'
- provides :another_no_name_thingy4, platform_family: 'foo'
+ provides :another_no_name_thingy4, os: "blarghle"
+ provides :another_no_name_thingy4, platform_family: "foo"
end
- }
+ end
it "and os = linux, another_no_name_thingy4 does not work" do
- expect_converge {
+ expect_converge do
# TODO this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'linux'
- another_no_name_thingy4 'blah' do; end
- }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+ run_context.node.automatic[:os] = "linux"
+ another_no_name_thingy4("blah") {}
+ end.to raise_error(Chef::Exceptions::NoSuchResourceType)
end
it "and os = blarghle, another_no_name_thingy4 works" do
- recipe = converge {
+ recipe = converge do
# TODO this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'blarghle'
- another_no_name_thingy4 'blah' do; end
- }
- expect(recipe.logged_warnings).to eq ''
+ run_context.node.automatic[:os] = "blarghle"
+ another_no_name_thingy4("blah") {}
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy4)
end
it "and platform_family = foo, another_no_name_thingy4 works" do
- recipe = converge {
+ recipe = converge do
# TODO this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:platform_family] = 'foo'
- another_no_name_thingy4 'blah' do; end
- }
- expect(recipe.logged_warnings).to eq ''
+ run_context.node.automatic[:platform_family] = "foo"
+ another_no_name_thingy4("blah") {}
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy4)
end
end
context "with a resource named AnotherNoNameThingy5, a different resource_name, and a provides with the original resource_name" do
- before(:context) {
+ before(:context) do
class AnotherNoNameThingy5 < BaseThingy
resource_name :another_thingy_name_for_another_no_name_thingy5
- provides :another_no_name_thingy5, os: 'blarghle'
+ provides :another_no_name_thingy5, os: "blarghle"
end
- }
+ end
it "and os = linux, another_no_name_thingy5 does not work" do
- expect_converge {
+ expect_converge do
# this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'linux'
- another_no_name_thingy5 'blah' do; end
- }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+ run_context.node.automatic[:os] = "linux"
+ another_no_name_thingy5("blah") {}
+ end.to raise_error(Chef::Exceptions::NoSuchResourceType)
end
it "and os = blarghle, another_no_name_thingy5 works" do
- recipe = converge {
+ recipe = converge do
# this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'blarghle'
- another_no_name_thingy5 'blah' do; end
- }
- expect(recipe.logged_warnings).to eq ''
+ run_context.node.automatic[:os] = "blarghle"
+ another_no_name_thingy5("blah") {}
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy5)
end
it "the new resource name can be used in a recipe" do
- recipe = converge {
- another_thingy_name_for_another_no_name_thingy5 'blah' do; end
- }
- expect(recipe.logged_warnings).to eq ''
+ recipe = converge do
+ another_thingy_name_for_another_no_name_thingy5("blah") {}
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy5)
end
end
context "with a resource named AnotherNoNameThingy6, a provides with the original resource name, and a different resource_name" do
- before(:context) {
+ before(:context) do
class AnotherNoNameThingy6 < BaseThingy
- provides :another_no_name_thingy6, os: 'blarghle'
+ provides :another_no_name_thingy6, os: "blarghle"
resource_name :another_thingy_name_for_another_no_name_thingy6
end
- }
+ end
it "and os = linux, another_no_name_thingy6 does not work" do
- expect_converge {
+ expect_converge do
# this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'linux'
- another_no_name_thingy6 'blah' do; end
- }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+ run_context.node.automatic[:os] = "linux"
+ another_no_name_thingy6("blah") {}
+ end.to raise_error(Chef::Exceptions::NoSuchResourceType)
end
it "and os = blarghle, another_no_name_thingy6 works" do
- recipe = converge {
+ recipe = converge do
# this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'blarghle'
- another_no_name_thingy6 'blah' do; end
- }
- expect(recipe.logged_warnings).to eq ''
+ run_context.node.automatic[:os] = "blarghle"
+ another_no_name_thingy6("blah") {}
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy6)
end
it "the new resource name can be used in a recipe" do
- recipe = converge {
- another_thingy_name_for_another_no_name_thingy6 'blah' do; end
- }
- expect(recipe.logged_warnings).to eq ''
+ recipe = converge do
+ another_thingy_name_for_another_no_name_thingy6("blah") {}
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy6)
end
end
context "with a resource named AnotherNoNameThingy7, a new resource_name, and provides with that new resource name" do
- before(:context) {
+ before(:context) do
class AnotherNoNameThingy7 < BaseThingy
resource_name :another_thingy_name_for_another_no_name_thingy7
- provides :another_thingy_name_for_another_no_name_thingy7, os: 'blarghle'
+ provides :another_thingy_name_for_another_no_name_thingy7, os: "blarghle"
end
- }
+ end
it "and os = linux, another_thingy_name_for_another_no_name_thingy7 does not work" do
- expect_converge {
+ expect_converge do
# this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'linux'
- another_thingy_name_for_another_no_name_thingy7 'blah' do; end
- }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+ run_context.node.automatic[:os] = "linux"
+ another_thingy_name_for_another_no_name_thingy7("blah") {}
+ end.to raise_error(Chef::Exceptions::NoSuchResourceType)
end
it "and os = blarghle, another_thingy_name_for_another_no_name_thingy7 works" do
- recipe = converge {
+ recipe = converge do
# this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'blarghle'
- another_thingy_name_for_another_no_name_thingy7 'blah' do; end
- }
- expect(recipe.logged_warnings).to eq ''
+ run_context.node.automatic[:os] = "blarghle"
+ another_thingy_name_for_another_no_name_thingy7("blah") {}
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy7)
end
it "the old resource name does not work" do
- expect_converge {
+ expect_converge do
# this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'linux'
- another_no_name_thingy_7 'blah' do; end
- }.to raise_error(NoMethodError)
+ run_context.node.automatic[:os] = "linux"
+ another_no_name_thingy_7("blah") {}
+ end.to raise_error(NoMethodError)
end
end
# opposite order from the previous test (provides, then resource_name)
context "with a resource named AnotherNoNameThingy8, a provides with a new resource name, and resource_name with that new resource name" do
- before(:context) {
+ before(:context) do
class AnotherNoNameThingy8 < BaseThingy
- provides :another_thingy_name_for_another_no_name_thingy8, os: 'blarghle'
+ provides :another_thingy_name_for_another_no_name_thingy8, os: "blarghle"
resource_name :another_thingy_name_for_another_no_name_thingy8
end
- }
+ end
it "and os = linux, another_thingy_name_for_another_no_name_thingy8 does not work" do
- expect_converge {
+ expect_converge do
# this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'linux'
- another_thingy_name_for_another_no_name_thingy8 'blah' do; end
- }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+ run_context.node.automatic[:os] = "linux"
+ another_thingy_name_for_another_no_name_thingy8("blah") {}
+ end.to raise_error(Chef::Exceptions::NoSuchResourceType)
end
it "and os = blarghle, another_thingy_name_for_another_no_name_thingy8 works" do
- recipe = converge {
+ recipe = converge do
# this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'blarghle'
- another_thingy_name_for_another_no_name_thingy8 'blah' do; end
- }
- expect(recipe.logged_warnings).to eq ''
+ run_context.node.automatic[:os] = "blarghle"
+ another_thingy_name_for_another_no_name_thingy8("blah") {}
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy8)
end
it "the old resource name does not work" do
- expect_converge {
+ expect_converge do
# this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'linux'
- another_thingy_name8 'blah' do; end
- }.to raise_error(NoMethodError)
+ run_context.node.automatic[:os] = "linux"
+ another_thingy_name8("blah") {}
+ end.to raise_error(NoMethodError)
end
end
end
@@ -434,64 +436,64 @@ describe "Recipe DSL methods" do
context "provides" do
context "when MySupplier provides :hemlock" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::MySupplier < BaseThingy
resource_name :hemlock
end
- }
+ end
it "my_supplier does not work in a recipe" do
- expect_converge {
- my_supplier 'blah' do; end
- }.to raise_error(NoMethodError)
+ expect_converge do
+ my_supplier("blah") {}
+ end.to raise_error(NoMethodError)
end
it "hemlock works in a recipe" do
- expect_recipe {
- hemlock 'blah' do; end
- }.to emit_no_warnings_or_errors
+ expect_recipe do
+ hemlock("blah") {}
+ end.to emit_no_warnings_or_errors
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::MySupplier
end
end
context "when Thingy3 has resource_name :thingy3" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Thingy3 < BaseThingy
resource_name :thingy3
end
- }
+ end
it "thingy3 works in a recipe" do
- expect_recipe {
- thingy3 'blah' do; end
- }.to emit_no_warnings_or_errors
+ expect_recipe do
+ thingy3("blah") {}
+ end.to emit_no_warnings_or_errors
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
end
context "and Thingy4 has resource_name :thingy3" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Thingy4 < BaseThingy
resource_name :thingy3
end
- }
+ end
it "thingy3 works in a recipe and yields Thingy3 (the alphabetical one)" do
- recipe = converge {
- thingy3 'blah' do; end
- }
+ recipe = converge do
+ thingy3("blah") {}
+ end
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
end
it "thingy4 does not work in a recipe" do
- expect_converge {
- thingy4 'blah' do; end
- }.to raise_error(NoMethodError)
+ expect_converge do
+ thingy4("blah") {}
+ end.to raise_error(NoMethodError)
end
it "resource_matching_short_name returns Thingy4" do
@@ -501,7 +503,7 @@ describe "Recipe DSL methods" do
end
context "when Thingy5 has resource_name :thingy5 and provides :thingy5reverse, :thingy5_2 and :thingy5_2reverse" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Thingy5 < BaseThingy
resource_name :thingy5
@@ -510,36 +512,36 @@ describe "Recipe DSL methods" do
provides :thingy5_2reverse
end
- }
+ end
it "thingy5 works in a recipe" do
- expect_recipe {
- thingy5 'blah' do; end
- }.to emit_no_warnings_or_errors
+ expect_recipe do
+ thingy5("blah") {}
+ end.to emit_no_warnings_or_errors
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy5
end
context "and Thingy6 provides :thingy5" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Thingy6 < BaseThingy
resource_name :thingy6
provides :thingy5
end
- }
+ end
it "thingy6 works in a recipe and yields Thingy6" do
- recipe = converge {
- thingy6 'blah' do; end
- }
+ recipe = converge do
+ thingy6("blah") {}
+ end
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy6
end
it "thingy5 works in a recipe and yields Foo::Thingy5 (the alphabetical one)" do
- recipe = converge {
- thingy5 'blah' do; end
- }
+ recipe = converge do
+ thingy5("blah") {}
+ end
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy5
end
@@ -548,24 +550,24 @@ describe "Recipe DSL methods" do
end
context "and AThingy5 provides :thingy5reverse" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::AThingy5 < BaseThingy
resource_name :thingy5reverse
end
- }
+ end
it "thingy5reverse works in a recipe and yields AThingy5 (the alphabetical one)" do
- recipe = converge {
- thingy5reverse 'blah' do; end
- }
+ recipe = converge do
+ thingy5reverse("blah") {}
+ end
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::AThingy5
end
end
context "and ZRecipeDSLSpecNamespace::Thingy5 provides :thingy5_2" do
- before(:context) {
+ before(:context) do
module ZRecipeDSLSpecNamespace
class Thingy5 < BaseThingy
@@ -573,18 +575,18 @@ describe "Recipe DSL methods" do
end
end
- }
+ end
it "thingy5_2 works in a recipe and yields the RecipeDSLSpaceNamespace one (the alphabetical one)" do
- recipe = converge {
- thingy5_2 'blah' do; end
- }
+ recipe = converge do
+ thingy5_2("blah") {}
+ end
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy5
end
end
context "and ARecipeDSLSpecNamespace::Thingy5 provides :thingy5_2" do
- before(:context) {
+ before(:context) do
module ARecipeDSLSpecNamespace
class Thingy5 < BaseThingy
@@ -592,53 +594,53 @@ describe "Recipe DSL methods" do
end
end
- }
+ end
it "thingy5_2reverse works in a recipe and yields the ARecipeDSLSpaceNamespace one (the alphabetical one)" do
- recipe = converge {
- thingy5_2reverse 'blah' do; end
- }
+ recipe = converge do
+ thingy5_2reverse("blah") {}
+ end
expect(BaseThingy.created_resource).to eq ARecipeDSLSpecNamespace::Thingy5
end
end
end
context "when Thingy3 has resource_name :thingy3" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Thingy3 < BaseThingy
resource_name :thingy3
end
- }
+ end
it "thingy3 works in a recipe" do
- expect_recipe {
- thingy3 'blah' do; end
- }.to emit_no_warnings_or_errors
+ expect_recipe do
+ thingy3("blah") {}
+ end.to emit_no_warnings_or_errors
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
end
context "and Thingy4 has resource_name :thingy3" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Thingy4 < BaseThingy
resource_name :thingy3
end
- }
+ end
it "thingy3 works in a recipe and yields Thingy3 (the alphabetical one)" do
- recipe = converge {
- thingy3 'blah' do; end
- }
+ recipe = converge do
+ thingy3("blah") {}
+ end
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
end
it "thingy4 does not work in a recipe" do
- expect_converge {
- thingy4 'blah' do; end
- }.to raise_error(NoMethodError)
+ expect_converge do
+ thingy4("blah") {}
+ end.to raise_error(NoMethodError)
end
it "resource_matching_short_name returns Thingy4" do
@@ -647,25 +649,25 @@ describe "Recipe DSL methods" do
end
context "and Thingy4 has resource_name :thingy3" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Thingy4 < BaseThingy
resource_name :thingy3
end
- }
+ end
it "thingy3 works in a recipe and yields Thingy3 (the alphabetical one)" do
- recipe = converge {
- thingy3 'blah' do; end
- }
+ recipe = converge do
+ thingy3("blah") {}
+ end
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
end
it "thingy4 does not work in a recipe" do
- expect_converge {
- thingy4 'blah' do; end
- }.to raise_error(NoMethodError)
+ expect_converge do
+ thingy4("blah") {}
+ end.to raise_error(NoMethodError)
end
it "resource_matching_short_name returns Thingy4" do
@@ -677,35 +679,35 @@ describe "Recipe DSL methods" do
end
context "when Thingy7 provides :thingy8" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Thingy7 < BaseThingy
resource_name :thingy7
provides :thingy8
end
- }
+ end
context "and Thingy8 has resource_name :thingy8" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Thingy8 < BaseThingy
resource_name :thingy8
end
- }
+ end
it "thingy7 works in a recipe and yields Thingy7" do
- recipe = converge {
- thingy7 'blah' do; end
- }
+ recipe = converge do
+ thingy7("blah") {}
+ end
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy7
end
it "thingy8 works in a recipe and yields Thingy7 (alphabetical)" do
- recipe = converge {
- thingy8 'blah' do; end
- }
+ recipe = converge do
+ thingy8("blah") {}
+ end
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy7
end
@@ -716,7 +718,7 @@ describe "Recipe DSL methods" do
end
context "when Thingy12 provides :thingy12, :twizzle and :twizzle2" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Thingy12 < BaseThingy
resource_name :thingy12
@@ -724,49 +726,49 @@ describe "Recipe DSL methods" do
provides :twizzle2
end
- }
+ end
it "thingy12 works in a recipe and yields Thingy12" do
- expect_recipe {
- thingy12 'blah' do; end
- }.to emit_no_warnings_or_errors
+ expect_recipe do
+ thingy12("blah") {}
+ end.to emit_no_warnings_or_errors
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy12
end
it "twizzle works in a recipe and yields Thingy12" do
- expect_recipe {
- twizzle 'blah' do; end
- }.to emit_no_warnings_or_errors
+ expect_recipe do
+ twizzle("blah") {}
+ end.to emit_no_warnings_or_errors
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy12
end
it "twizzle2 works in a recipe and yields Thingy12" do
- expect_recipe {
- twizzle2 'blah' do; end
- }.to emit_no_warnings_or_errors
+ expect_recipe do
+ twizzle2("blah") {}
+ end.to emit_no_warnings_or_errors
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy12
end
end
context "with platform-specific resources 'my_super_thingy_foo' and 'my_super_thingy_bar'" do
- before(:context) {
+ before(:context) do
class MySuperThingyFoo < BaseThingy
resource_name :my_super_thingy_foo
- provides :my_super_thingy, platform: 'foo'
+ provides :my_super_thingy, platform: "foo"
end
class MySuperThingyBar < BaseThingy
resource_name :my_super_thingy_bar
- provides :my_super_thingy, platform: 'bar'
+ provides :my_super_thingy, platform: "bar"
end
- }
+ end
it "A run with platform 'foo' uses MySuperThingyFoo" do
r = Cheffish::ChefRun.new(chef_config)
- r.client.run_context.node.automatic['platform'] = 'foo'
- r.compile_recipe {
- my_super_thingy 'blah' do; end
- }
+ r.client.run_context.node.automatic["platform"] = "foo"
+ r.compile_recipe do
+ my_super_thingy("blah") {}
+ end
r.converge
expect(r).to emit_no_warnings_or_errors
expect(BaseThingy.created_resource).to eq MySuperThingyFoo
@@ -774,10 +776,10 @@ describe "Recipe DSL methods" do
it "A run with platform 'bar' uses MySuperThingyBar" do
r = Cheffish::ChefRun.new(chef_config)
- r.client.run_context.node.automatic['platform'] = 'bar'
- r.compile_recipe {
- my_super_thingy 'blah' do; end
- }
+ r.client.run_context.node.automatic["platform"] = "bar"
+ r.compile_recipe do
+ my_super_thingy("blah") {}
+ end
r.converge
expect(r).to emit_no_warnings_or_errors
expect(BaseThingy.created_resource).to eq MySuperThingyBar
@@ -785,21 +787,21 @@ describe "Recipe DSL methods" do
it "A run with platform 'x' reports that my_super_thingy is not supported" do
r = Cheffish::ChefRun.new(chef_config)
- r.client.run_context.node.automatic['platform'] = 'x'
- expect {
- r.compile_recipe {
- my_super_thingy 'blah' do; end
- }
- }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+ r.client.run_context.node.automatic["platform"] = "x"
+ expect do
+ r.compile_recipe do
+ my_super_thingy("blah") {}
+ end
+ end.to raise_error(Chef::Exceptions::NoSuchResourceType)
end
end
context "when Thingy10 provides :thingy10" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Thingy10 < BaseThingy
resource_name :thingy10
end
- }
+ end
it "declaring a resource providing the same :thingy10 with override: true does not produce a warning" do
expect(Chef::Log).not_to receive(:warn)
@@ -810,16 +812,16 @@ describe "Recipe DSL methods" do
end
context "when Thingy11 provides :thingy11" do
- before(:context) {
+ before(:context) do
class RecipeDSLSpecNamespace::Thingy11 < BaseThingy
resource_name :thingy10
end
- }
+ end
it "declaring a resource providing the same :thingy11 with os: 'linux' does not produce a warning" do
expect(Chef::Log).not_to receive(:warn)
class RecipeDSLSpecNamespace::Thingy11AlternateProvider < BaseThingy
- provides :thingy11, os: 'linux'
+ provides :thingy11, os: "linux"
end
end
end
@@ -827,39 +829,43 @@ describe "Recipe DSL methods" do
context "with a resource named 'B' with resource name :two_classes_one_dsl" do
let(:two_classes_one_dsl) { :"two_classes_one_dsl#{Namer.current_index}" }
- let(:resource_class) {
+ let(:resource_class) do
result = Class.new(BaseThingy) do
def self.name
"B"
end
+
def self.to_s; name; end
+
def self.inspect; name.inspect; end
end
result.resource_name two_classes_one_dsl
result
- }
+ end
before { resource_class } # pull on it so it gets defined before the recipe runs
context "and another resource named 'A' with resource_name :two_classes_one_dsl" do
- let(:resource_class_a) {
+ let(:resource_class_a) do
result = Class.new(BaseThingy) do
def self.name
"A"
end
+
def self.to_s; name; end
+
def self.inspect; name.inspect; end
end
result.resource_name two_classes_one_dsl
result
- }
+ end
before { resource_class_a } # pull on it so it gets defined before the recipe runs
it "two_classes_one_dsl resolves to A (alphabetically earliest)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq resource_class_a
end
@@ -869,25 +875,27 @@ describe "Recipe DSL methods" do
end
context "and another resource named 'Z' with resource_name :two_classes_one_dsl" do
- let(:resource_class_z) {
+ let(:resource_class_z) do
result = Class.new(BaseThingy) do
def self.name
"Z"
end
+
def self.to_s; name; end
+
def self.inspect; name.inspect; end
end
result.resource_name two_classes_one_dsl
result
- }
+ end
before { resource_class_z } # pull on it so it gets defined before the recipe runs
it "two_classes_one_dsl resolves to B (alphabetically earliest)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq resource_class
end
@@ -901,11 +909,11 @@ describe "Recipe DSL methods" do
end
it "two_classes_one_dsl resolves to Z (respects the priority array)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq resource_class_z
end
@@ -919,11 +927,11 @@ describe "Recipe DSL methods" do
end
it "two_classes_one_dsl resolves to B (picks the next thing in the priority array)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq resource_class
end
@@ -940,11 +948,11 @@ describe "Recipe DSL methods" do
end
it "two_classes_one_dsl resolves to Z (respects the most recent priority array)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq resource_class_z
end
@@ -958,11 +966,11 @@ describe "Recipe DSL methods" do
end
it "two_classes_one_dsl resolves to B (picks the first match from the other priority array)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq resource_class
end
@@ -983,11 +991,11 @@ describe "Recipe DSL methods" do
end
it "two_classes_one_dsl resolves to B (picks the first match outside the priority array)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq resource_class
end
@@ -1004,39 +1012,43 @@ describe "Recipe DSL methods" do
resource_class.send(:define_method, :provider) { nil }
end
- let(:provider_class) {
+ let(:provider_class) do
result = Class.new(BaseThingy::Provider) do
def self.name
"B"
end
+
def self.to_s; name; end
+
def self.inspect; name.inspect; end
end
result.provides two_classes_one_dsl
result
- }
+ end
before { provider_class } # pull on it so it gets defined before the recipe runs
context "and another provider named 'A'" do
- let(:provider_class_a) {
+ let(:provider_class_a) do
result = Class.new(BaseThingy::Provider) do
def self.name
"A"
end
+
def self.to_s; name; end
+
def self.inspect; name.inspect; end
end
result
- }
+ end
context "which provides :two_classes_one_dsl" do
before { provider_class_a.provides two_classes_one_dsl }
it "two_classes_one_dsl resolves to A (alphabetically earliest)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_provider).to eq provider_class_a
end
end
@@ -1044,38 +1056,40 @@ describe "Recipe DSL methods" do
before { provider_class_a.provides(two_classes_one_dsl) { false } }
it "two_classes_one_dsl resolves to B (since A declined)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_provider).to eq provider_class
end
end
end
context "and another provider named 'Z'" do
- let(:provider_class_z) {
+ let(:provider_class_z) do
result = Class.new(BaseThingy::Provider) do
def self.name
"Z"
end
+
def self.to_s; name; end
+
def self.inspect; name.inspect; end
end
result
- }
+ end
before { provider_class_z } # pull on it so it gets defined before the recipe runs
context "which provides :two_classes_one_dsl" do
before { provider_class_z.provides two_classes_one_dsl }
it "two_classes_one_dsl resolves to B (alphabetically earliest)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_provider).to eq provider_class
end
@@ -1083,11 +1097,11 @@ describe "Recipe DSL methods" do
before { Chef.set_provider_priority_array two_classes_one_dsl, [ provider_class_z, provider_class ] }
it "two_classes_one_dsl resolves to Z (respects the priority map)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_provider).to eq provider_class_z
end
end
@@ -1100,11 +1114,11 @@ describe "Recipe DSL methods" do
before { Chef.set_provider_priority_array two_classes_one_dsl, [ provider_class_z, provider_class ] }
it "two_classes_one_dsl resolves to B (the next one in the priority map)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_provider).to eq provider_class
end
end
@@ -1114,11 +1128,11 @@ describe "Recipe DSL methods" do
before { Chef.set_provider_priority_array two_classes_one_dsl, [ provider_class ] }
it "two_classes_one_dsl resolves to B (the one in the next priority map)" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
- instance_eval("#{two_classes_one_dsl} 'blah'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
+ instance_eval("#{temp_two_classes_one_dsl} 'blah'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_provider).to eq provider_class
end
end
@@ -1127,76 +1141,80 @@ describe "Recipe DSL methods" do
end
context "and another resource Blarghle with provides :two_classes_one_dsl, os: 'blarghle'" do
- let(:resource_class_blarghle) {
+ let(:resource_class_blarghle) do
result = Class.new(BaseThingy) do
def self.name
"Blarghle"
end
+
def self.to_s; name; end
+
def self.inspect; name.inspect; end
end
result.resource_name two_classes_one_dsl
- result.provides two_classes_one_dsl, os: 'blarghle'
+ result.provides two_classes_one_dsl, os: "blarghle"
result
- }
+ end
before { resource_class_blarghle } # pull on it so it gets defined before the recipe runs
it "on os = blarghle, two_classes_one_dsl resolves to Blarghle" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
# this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'blarghle'
- instance_eval("#{two_classes_one_dsl} 'blah' do; end")
- }
- expect(recipe.logged_warnings).to eq ''
+ run_context.node.automatic[:os] = "blarghle"
+ instance_eval("#{temp_two_classes_one_dsl} 'blah' do; end")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq resource_class_blarghle
end
it "on os = linux, two_classes_one_dsl resolves to B" do
- two_classes_one_dsl = self.two_classes_one_dsl
- recipe = converge {
+ temp_two_classes_one_dsl = two_classes_one_dsl
+ recipe = converge do
# this is an ugly way to test, make Cheffish expose node attrs
- run_context.node.automatic[:os] = 'linux'
- instance_eval("#{two_classes_one_dsl} 'blah' do; end")
- }
- expect(recipe.logged_warnings).to eq ''
+ run_context.node.automatic[:os] = "linux"
+ instance_eval("#{temp_two_classes_one_dsl} 'blah' do; end")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq resource_class
end
end
end
context "with a resource MyResource" do
- let(:resource_class) { Class.new(BaseThingy) do
- def self.called_provides
- @called_provides
- end
- def to_s
- "MyResource"
- end
- end }
+ let(:resource_class) do
+ Class.new(BaseThingy) do
+ def self.called_provides
+ @called_provides
+ end
+
+ def to_s
+ "MyResource"
+ end
+ end end
let(:my_resource) { :"my_resource#{Namer.current_index}" }
let(:blarghle_blarghle_little_star) { :"blarghle_blarghle_little_star#{Namer.current_index}" }
context "with resource_name :my_resource" do
- before {
+ before do
resource_class.resource_name my_resource
- }
+ end
context "with provides? returning true to my_resource" do
- before {
- my_resource = self.my_resource
+ before do
+ temp_my_resource = my_resource
resource_class.define_singleton_method(:provides?) do |node, resource_name|
@called_provides = true
- resource_name == my_resource
+ resource_name == temp_my_resource
end
- }
+ end
it "my_resource returns the resource and calls provides?, but does not emit a warning" do
- dsl_name = self.my_resource
- recipe = converge {
+ dsl_name = my_resource
+ recipe = converge do
instance_eval("#{dsl_name} 'foo'")
- }
- expect(recipe.logged_warnings).to eq ''
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_resource).to eq resource_class
expect(resource_class.called_provides).to be_truthy
end
@@ -1204,27 +1222,27 @@ describe "Recipe DSL methods" do
context "with provides? returning true to blarghle_blarghle_little_star and not resource_name" do
before do
- blarghle_blarghle_little_star = self.blarghle_blarghle_little_star
+ temp_blarghle_blarghle_little_star = blarghle_blarghle_little_star
resource_class.define_singleton_method(:provides?) do |node, resource_name|
@called_provides = true
- resource_name == blarghle_blarghle_little_star
+ resource_name == temp_blarghle_blarghle_little_star
end
end
it "my_resource does not return the resource" do
- dsl_name = self.my_resource
- expect_converge {
+ dsl_name = my_resource
+ expect_converge do
instance_eval("#{dsl_name} 'foo'")
- }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+ end.to raise_error(Chef::Exceptions::NoSuchResourceType)
expect(resource_class.called_provides).to be_truthy
end
it "blarghle_blarghle_little_star 'foo' returns the resource and emits a warning" do
Chef::Config[:treat_deprecation_warnings_as_errors] = false
- dsl_name = self.blarghle_blarghle_little_star
- recipe = converge {
+ dsl_name = blarghle_blarghle_little_star
+ recipe = converge do
instance_eval("#{dsl_name} 'foo'")
- }
+ end
expect(recipe.logged_warnings).to include "WARN: #{resource_class}.provides? returned true when asked if it provides DSL #{dsl_name}, but provides :#{dsl_name} was never called!"
expect(BaseThingy.created_resource).to eq resource_class
expect(resource_class.called_provides).to be_truthy
@@ -1237,8 +1255,11 @@ describe "Recipe DSL methods" do
def self.name
"MyProvider"
end
+
def self.to_s; name; end
+
def self.inspect; name.inspect; end
+
def self.called_provides
@called_provides
end
@@ -1256,15 +1277,15 @@ describe "Recipe DSL methods" do
context "with supports? returning true" do
before do
- provider_class.define_singleton_method(:supports?) { |resource,action| true }
+ provider_class.define_singleton_method(:supports?) { |resource, action| true }
end
it "my_resource runs the provider and does not emit a warning" do
- my_resource = self.my_resource
- recipe = converge {
- instance_eval("#{my_resource} 'foo'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_my_resource = my_resource
+ recipe = converge do
+ instance_eval("#{temp_my_resource} 'foo'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_provider).to eq provider_class
end
@@ -1274,8 +1295,11 @@ describe "Recipe DSL methods" do
def self.name
"MyProvider2"
end
+
def self.to_s; name; end
+
def self.inspect; name.inspect; end
+
def self.called_provides
@called_provides
end
@@ -1287,11 +1311,11 @@ describe "Recipe DSL methods" do
end
it "my_resource runs the first provider" do
- my_resource = self.my_resource
- recipe = converge {
- instance_eval("#{my_resource} 'foo'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_my_resource = my_resource
+ recipe = converge do
+ instance_eval("#{temp_my_resource} 'foo'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_provider).to eq provider_class
end
end
@@ -1299,32 +1323,35 @@ describe "Recipe DSL methods" do
context "with supports? returning false" do
before do
- provider_class.define_singleton_method(:supports?) { |resource,action| false }
+ provider_class.define_singleton_method(:supports?) { |resource, action| false }
end
# TODO no warning? ick
it "my_resource runs the provider anyway" do
- my_resource = self.my_resource
- recipe = converge {
- instance_eval("#{my_resource} 'foo'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_my_resource = my_resource
+ recipe = converge do
+ instance_eval("#{temp_my_resource} 'foo'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_provider).to eq provider_class
end
context "and another provider supporting :my_resource with supports? true" do
let(:provider_class2) do
- my_resource = self.my_resource
+ temp_my_resource = my_resource
Class.new(BaseThingy::Provider) do
def self.name
"MyProvider2"
end
+
def self.to_s; name; end
+
def self.inspect; name.inspect; end
+
def self.called_provides
@called_provides
end
- provides my_resource
+ provides temp_my_resource
def self.supports?(resource, action)
true
end
@@ -1333,11 +1360,11 @@ describe "Recipe DSL methods" do
before { provider_class2 } # make sure the provider class shows up
it "my_resource runs the other provider" do
- my_resource = self.my_resource
- recipe = converge {
- instance_eval("#{my_resource} 'foo'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_my_resource = my_resource
+ recipe = converge do
+ instance_eval("#{temp_my_resource} 'foo'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_provider).to eq provider_class2
end
end
@@ -1345,25 +1372,25 @@ describe "Recipe DSL methods" do
end
context "with provides? returning true" do
- before {
- my_resource = self.my_resource
+ before do
+ temp_my_resource = my_resource
provider_class.define_singleton_method(:provides?) do |node, resource|
@called_provides = true
- resource.declared_type == my_resource
+ resource.declared_type == temp_my_resource
end
- }
+ end
context "that provides :my_resource" do
- before {
+ before do
provider_class.provides my_resource
- }
+ end
it "my_resource calls the provider (and calls provides?), but does not emit a warning" do
- my_resource = self.my_resource
- recipe = converge {
- instance_eval("#{my_resource} 'foo'")
- }
- expect(recipe.logged_warnings).to eq ''
+ temp_my_resource = my_resource
+ recipe = converge do
+ instance_eval("#{temp_my_resource} 'foo'")
+ end
+ expect(recipe.logged_warnings).to eq ""
expect(BaseThingy.created_provider).to eq provider_class
expect(provider_class.called_provides).to be_truthy
end
@@ -1372,10 +1399,10 @@ describe "Recipe DSL methods" do
context "that does not call provides :my_resource" do
it "my_resource calls the provider (and calls provides?), and emits a warning" do
Chef::Config[:treat_deprecation_warnings_as_errors] = false
- my_resource = self.my_resource
- recipe = converge {
- instance_eval("#{my_resource} 'foo'")
- }
+ temp_my_resource = my_resource
+ recipe = converge do
+ instance_eval("#{temp_my_resource} 'foo'")
+ end
expect(recipe.logged_warnings).to include("WARN: #{provider_class}.provides? returned true when asked if it provides DSL #{my_resource}, but provides :#{my_resource} was never called!")
expect(BaseThingy.created_provider).to eq provider_class
expect(provider_class.called_provides).to be_truthy
@@ -1384,34 +1411,36 @@ describe "Recipe DSL methods" do
end
context "with provides? returning false to my_resource" do
- before {
- my_resource = self.my_resource
+ before do
+ temp_my_resource = my_resource
provider_class.define_singleton_method(:provides?) do |node, resource|
@called_provides = true
false
end
- }
+ end
context "that provides :my_resource" do
- before {
+ before do
provider_class.provides my_resource
- }
+ end
it "my_resource fails to find a provider (and calls provides)" do
- my_resource = self.my_resource
- expect_converge {
- instance_eval("#{my_resource} 'foo'")
- }.to raise_error(Chef::Exceptions::ProviderNotFound)
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ temp_my_resource = my_resource
+ expect_converge do
+ instance_eval("#{temp_my_resource} 'foo'")
+ end.to raise_error(Chef::Exceptions::ProviderNotFound)
expect(provider_class.called_provides).to be_truthy
end
end
context "that does not provide :my_resource" do
it "my_resource fails to find a provider (and calls provides)" do
- my_resource = self.my_resource
- expect_converge {
- instance_eval("#{my_resource} 'foo'")
- }.to raise_error(Chef::Exceptions::ProviderNotFound)
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ temp_my_resource = my_resource
+ expect_converge do
+ instance_eval("#{temp_my_resource} 'foo'")
+ end.to raise_error(Chef::Exceptions::ProviderNotFound)
expect(provider_class.called_provides).to be_truthy
end
end
@@ -1425,15 +1454,15 @@ describe "Recipe DSL methods" do
before { Namer.current_index += 1 }
context "with an LWRP that declares actions" do
- let(:resource_class) {
+ let(:resource_class) do
Class.new(Chef::Resource::LWRPBase) do
provides :"recipe_dsl_spec#{Namer.current_index}"
actions :create
end
- }
- let(:resource) {
+ end
+ let(:resource) do
resource_class.new("blah", run_context)
- }
+ end
it "The actions are part of actions along with :nothing" do
expect(resource_class.actions).to eq [ :nothing, :create ]
end
@@ -1442,15 +1471,15 @@ describe "Recipe DSL methods" do
end
context "and a subclass that declares more actions" do
- let(:subresource_class) {
+ let(:subresource_class) do
Class.new(Chef::Resource::LWRPBase) do
provides :"recipe_dsl_spec_sub#{Namer.current_index}"
actions :delete
end
- }
- let(:subresource) {
+ end
+ let(:subresource) do
subresource_class.new("subblah", run_context)
- }
+ end
it "The parent class actions are not part of actions" do
expect(subresource_class.actions).to eq [ :nothing, :delete ]
@@ -1475,6 +1504,7 @@ describe "Recipe DSL methods" do
class Chef::Provider::LwResourceWithHwProviderTestCase < Chef::Provider
def load_current_resource
end
+
def action_create
new_resource.created_provider = self.class
end
@@ -1482,10 +1512,11 @@ describe "Recipe DSL methods" do
end
it "looks up the provider in Chef::Provider converting the resource name from snake case to camel case" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
resource = nil
- recipe = converge {
- resource = lw_resource_with_hw_provider_test_case 'blah' do; end
- }
+ recipe = converge do
+ resource = lw_resource_with_hw_provider_test_case("blah") {}
+ end
expect(resource.created_provider).to eq(Chef::Provider::LwResourceWithHwProviderTestCase)
end
end
diff --git a/spec/integration/recipes/remote_directory.rb b/spec/integration/recipes/remote_directory.rb
index a1988ccd52..77fe183136 100644
--- a/spec/integration/recipes/remote_directory.rb
+++ b/spec/integration/recipes/remote_directory.rb
@@ -1,4 +1,4 @@
-require 'support/shared/integration/integration_helper'
+require "support/shared/integration/integration_helper"
describe Chef::Resource::RemoteDirectory do
include IntegrationSupport
@@ -20,7 +20,7 @@ describe Chef::Resource::RemoteDirectory do
when_the_repository "has a cookbook with a source_dir with two subdirectories, each with one file and subdir in a different alphabetical order" do
before do
- file 'config/client.rb', <<-EOM
+ file "config/client.rb", <<-EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
EOM
diff --git a/spec/integration/recipes/resource_action_spec.rb b/spec/integration/recipes/resource_action_spec.rb
index 6f3f5ab47e..f11696bae4 100644
--- a/spec/integration/recipes/resource_action_spec.rb
+++ b/spec/integration/recipes/resource_action_spec.rb
@@ -1,131 +1,150 @@
-require 'support/shared/integration/integration_helper'
+require "support/shared/integration/integration_helper"
-describe "Resource.action" do
- include IntegrationSupport
+# Houses any classes we declare
+module ResourceActionSpec
- shared_context "ActionJackson" do
- it "the default action is the first declared action" do
- converge <<-EOM, __FILE__, __LINE__+1
- #{resource_dsl} 'hi' do
- foo 'foo!'
- end
- EOM
- expect(ActionJackson.ran_action).to eq :access_recipe_dsl
- expect(ActionJackson.succeeded).to eq true
- end
+ describe "Resource.action" do
+ include IntegrationSupport
- it "the action can access recipe DSL" do
- converge <<-EOM, __FILE__, __LINE__+1
- #{resource_dsl} 'hi' do
- foo 'foo!'
- action :access_recipe_dsl
- end
- EOM
- expect(ActionJackson.ran_action).to eq :access_recipe_dsl
- expect(ActionJackson.succeeded).to eq true
- end
+ shared_context "ActionJackson" do
+ it "the default action is the first declared action" do
+ converge <<-EOM, __FILE__, __LINE__ + 1
+ #{resource_dsl} "hi" do
+ foo "foo!"
+ end
+ EOM
+ expect(ActionJackson.ran_action).to eq :access_recipe_dsl
+ expect(ActionJackson.succeeded).to eq true
+ end
- it "the action can access attributes" do
- converge <<-EOM, __FILE__, __LINE__+1
- #{resource_dsl} 'hi' do
- foo 'foo!'
- action :access_attribute
+ context "when running in whyrun mode" do
+ before do
+ Chef::Config[:why_run] = true
end
- EOM
- expect(ActionJackson.ran_action).to eq :access_attribute
- expect(ActionJackson.succeeded).to eq 'foo!'
- end
- it "the action can access public methods" do
- converge <<-EOM, __FILE__, __LINE__+1
- #{resource_dsl} 'hi' do
- foo 'foo!'
- action :access_method
+ it "the default action runs" do
+ converge <<-EOM, __FILE__, __LINE__ + 1
+ #{resource_dsl} "hi" do
+ foo "foo!"
+ end
+ EOM
+ expect(ActionJackson.ran_action).to eq :access_recipe_dsl
+ expect(ActionJackson.succeeded).to eq true
end
- EOM
- expect(ActionJackson.ran_action).to eq :access_method
- expect(ActionJackson.succeeded).to eq 'foo_public!'
- end
+ end
- it "the action can access protected methods" do
- converge <<-EOM, __FILE__, __LINE__+1
- #{resource_dsl} 'hi' do
- foo 'foo!'
- action :access_protected_method
- end
- EOM
- expect(ActionJackson.ran_action).to eq :access_protected_method
- expect(ActionJackson.succeeded).to eq 'foo_protected!'
- end
+ it "the action can access recipe DSL" do
+ converge <<-EOM, __FILE__, __LINE__ + 1
+ #{resource_dsl} "hi" do
+ foo "foo!"
+ action :access_recipe_dsl
+ end
+ EOM
+ expect(ActionJackson.ran_action).to eq :access_recipe_dsl
+ expect(ActionJackson.succeeded).to eq true
+ end
- it "the action cannot access private methods" do
- expect {
- converge(<<-EOM, __FILE__, __LINE__+1)
- #{resource_dsl} 'hi' do
- foo 'foo!'
- action :access_private_method
+ it "the action can access attributes" do
+ converge <<-EOM, __FILE__, __LINE__ + 1
+ #{resource_dsl} "hi" do
+ foo "foo!"
+ action :access_attribute
end
EOM
- }.to raise_error(NameError)
- expect(ActionJackson.ran_action).to eq :access_private_method
- end
+ expect(ActionJackson.ran_action).to eq :access_attribute
+ expect(ActionJackson.succeeded).to eq "foo!"
+ end
- it "the action cannot access resource instance variables" do
- converge <<-EOM, __FILE__, __LINE__+1
- #{resource_dsl} 'hi' do
- foo 'foo!'
- action :access_instance_variable
- end
- EOM
- expect(ActionJackson.ran_action).to eq :access_instance_variable
- expect(ActionJackson.succeeded).to be_nil
- end
+ it "the action can access public methods" do
+ converge <<-EOM, __FILE__, __LINE__ + 1
+ #{resource_dsl} "hi" do
+ foo "foo!"
+ action :access_method
+ end
+ EOM
+ expect(ActionJackson.ran_action).to eq :access_method
+ expect(ActionJackson.succeeded).to eq "foo_public!"
+ end
- it "the action does not compile until the prior resource has converged" do
- converge <<-EOM, __FILE__, __LINE__+1
- ruby_block 'wow' do
- block do
- ActionJackson.ruby_block_converged = 'ruby_block_converged!'
+ it "the action can access protected methods" do
+ converge <<-EOM, __FILE__, __LINE__ + 1
+ #{resource_dsl} "hi" do
+ foo "foo!"
+ action :access_protected_method
end
- end
+ EOM
+ expect(ActionJackson.ran_action).to eq :access_protected_method
+ expect(ActionJackson.succeeded).to eq "foo_protected!"
+ end
- #{resource_dsl} 'hi' do
- foo 'foo!'
- action :access_class_method
- end
- EOM
- expect(ActionJackson.ran_action).to eq :access_class_method
- expect(ActionJackson.succeeded).to eq 'ruby_block_converged!'
- end
+ it "the action cannot access private methods" do
+ expect do
+ converge(<<-EOM, __FILE__, __LINE__ + 1)
+ #{resource_dsl} "hi" do
+ foo "foo!"
+ action :access_private_method
+ end
+ EOM
+ end.to raise_error(NameError)
+ expect(ActionJackson.ran_action).to eq :access_private_method
+ end
+
+ it "the action cannot access resource instance variables" do
+ converge <<-EOM, __FILE__, __LINE__ + 1
+ #{resource_dsl} "hi" do
+ foo "foo!"
+ action :access_instance_variable
+ end
+ EOM
+ expect(ActionJackson.ran_action).to eq :access_instance_variable
+ expect(ActionJackson.succeeded).to be_nil
+ end
+
+ it "the action does not compile until the prior resource has converged" do
+ converge <<-EOM, __FILE__, __LINE__ + 1
+ ruby_block "wow" do
+ block do
+ ResourceActionSpec::ActionJackson.ruby_block_converged = "ruby_block_converged!"
+ end
+ end
- it "the action's resources converge before the next resource converges" do
- converge <<-EOM, __FILE__, __LINE__+1
- #{resource_dsl} 'hi' do
- foo 'foo!'
+ #{resource_dsl} "hi" do
+ foo "foo!"
+ action :access_class_method
+ end
+ EOM
+ expect(ActionJackson.ran_action).to eq :access_class_method
+ expect(ActionJackson.succeeded).to eq "ruby_block_converged!"
+ end
+
+ it "the action's resources converge before the next resource converges" do
+ converge <<-EOM, __FILE__, __LINE__ + 1
+ #{resource_dsl} "hi" do
+ foo "foo!"
action :access_attribute
end
- ruby_block 'wow' do
+ ruby_block "wow" do
block do
- ActionJackson.ruby_block_converged = ActionJackson.succeeded
+ ResourceActionSpec::ActionJackson.ruby_block_converged = ResourceActionSpec::ActionJackson.succeeded
end
end
EOM
- expect(ActionJackson.ran_action).to eq :access_attribute
- expect(ActionJackson.succeeded).to eq 'foo!'
- expect(ActionJackson.ruby_block_converged).to eq 'foo!'
+ expect(ActionJackson.ran_action).to eq :access_attribute
+ expect(ActionJackson.succeeded).to eq "foo!"
+ expect(ActionJackson.ruby_block_converged).to eq "foo!"
+ end
end
- end
- context "With resource 'action_jackson'" do
- before(:context) {
+ context "With resource 'action_jackson'" do
class ActionJackson < Chef::Resource
use_automatic_resource_name
- def foo(value=nil)
+ def foo(value = nil)
@foo = value if value
@foo
end
- def blarghle(value=nil)
+
+ def blarghle(value = nil)
@blarghle = value if value
@blarghle
end
@@ -136,23 +155,9 @@ describe "Resource.action" do
attr_accessor :ruby_block_converged
end
- public
- def foo_public
- 'foo_public!'
- end
- protected
- def foo_protected
- 'foo_protected!'
- end
- private
- def foo_private
- 'foo_private!'
- end
-
- public
action :access_recipe_dsl do
ActionJackson.ran_action = :access_recipe_dsl
- ruby_block 'hi there' do
+ whyrun_safe_ruby_block "hi there" do
block do
ActionJackson.succeeded = true
end
@@ -190,45 +195,61 @@ describe "Resource.action" do
ActionJackson.ran_action = :access_class_method
ActionJackson.succeeded = ActionJackson.ruby_block_converged
end
- end
- }
- before(:each) {
- ActionJackson.ran_action = :error
- ActionJackson.succeeded = :error
- ActionJackson.ruby_block_converged = :error
- }
-
- it_behaves_like "ActionJackson" do
- let(:resource_dsl) { :action_jackson }
- end
- it "Can retrieve ancestors of action class without crashing" do
- converge { action_jackson 'hi' }
- expect { ActionJackson.action_class.ancestors.join(",") }.not_to raise_error
- end
+ def foo_public
+ "foo_public!"
+ end
- context "And 'action_jackgrandson' inheriting from ActionJackson and changing nothing" do
- before(:context) {
- class ActionJackgrandson < ActionJackson
- use_automatic_resource_name
+ protected
+
+ def foo_protected
+ "foo_protected!"
end
- }
+
+ private
+
+ def foo_private
+ "foo_private!"
+ end
+ end
+
+ before(:each) do
+ ActionJackson.ran_action = :error
+ ActionJackson.succeeded = :error
+ ActionJackson.ruby_block_converged = :error
+ end
it_behaves_like "ActionJackson" do
- let(:resource_dsl) { :action_jackgrandson }
+ let(:resource_dsl) { :action_jackson }
+ end
+
+ it "Can retrieve ancestors of action class without crashing" do
+ converge { action_jackson "hi" }
+ expect { ActionJackson.action_class.ancestors.join(",") }.not_to raise_error
end
- end
- context "And 'action_jackalope' inheriting from ActionJackson with an extra attribute, action and custom method" do
- before(:context) {
+ context "And 'action_jackgrandson' inheriting from ActionJackson and changing nothing" do
+ before(:context) do
+ class ActionJackgrandson < ActionJackson
+ use_automatic_resource_name
+ end
+ end
+
+ it_behaves_like "ActionJackson" do
+ let(:resource_dsl) { :action_jackgrandson }
+ end
+ end
+
+ context "And 'action_jackalope' inheriting from ActionJackson with an extra attribute, action and custom method" do
class ActionJackalope < ActionJackson
use_automatic_resource_name
- def foo(value=nil)
+ def foo(value = nil)
@foo = "#{value}alope" if value
@foo
end
- def bar(value=nil)
+
+ def bar(value = nil)
@bar = "#{value}alope" if value
@bar
end
@@ -246,78 +267,76 @@ describe "Resource.action" do
ActionJackalope.succeeded = ActionJackson.succeeded
end
end
- }
- before do
- ActionJackalope.jackalope_ran = nil
- ActionJackalope.load_current_resource_ran = nil
- end
-
- context "action_jackson still behaves the same" do
- it_behaves_like "ActionJackson" do
- let(:resource_dsl) { :action_jackson }
+ before do
+ ActionJackalope.jackalope_ran = nil
+ ActionJackalope.load_current_resource_ran = nil
end
- end
- it "the default action remains the same even though new actions were specified first" do
- converge {
- action_jackalope 'hi' do
- foo 'foo!'
- bar 'bar!'
+ context "action_jackson still behaves the same" do
+ it_behaves_like "ActionJackson" do
+ let(:resource_dsl) { :action_jackson }
end
- }
- expect(ActionJackson.ran_action).to eq :access_recipe_dsl
- expect(ActionJackson.succeeded).to eq true
- end
+ end
- it "new actions run, and can access overridden, new, and overridden attributes" do
- converge {
- action_jackalope 'hi' do
- foo 'foo!'
- bar 'bar!'
- blarghle 'blarghle!'
- action :access_jackalope
- end
- }
- expect(ActionJackalope.jackalope_ran).to eq :access_jackalope
- expect(ActionJackalope.succeeded).to eq "foo!alope blarghle! bar!alope"
- end
+ it "the default action remains the same even though new actions were specified first" do
+ converge do
+ action_jackalope "hi" do
+ foo "foo!"
+ bar "bar!"
+ end
+ end
+ expect(ActionJackson.ran_action).to eq :access_recipe_dsl
+ expect(ActionJackson.succeeded).to eq true
+ end
- it "overridden actions run, call super, and can access overridden, new, and overridden attributes" do
- converge {
- action_jackalope 'hi' do
- foo 'foo!'
- bar 'bar!'
- blarghle 'blarghle!'
- action :access_attribute
+ it "new actions run, and can access overridden, new, and overridden attributes" do
+ converge do
+ action_jackalope "hi" do
+ foo "foo!"
+ bar "bar!"
+ blarghle "blarghle!"
+ action :access_jackalope
+ end
end
- }
- expect(ActionJackson.ran_action).to eq :access_attribute
- expect(ActionJackson.succeeded).to eq "foo!alope blarghle! bar!alope"
- expect(ActionJackalope.jackalope_ran).to eq :access_attribute
- expect(ActionJackalope.succeeded).to eq "foo!alope blarghle! bar!alope"
- end
+ expect(ActionJackalope.jackalope_ran).to eq :access_jackalope
+ expect(ActionJackalope.succeeded).to eq "foo!alope blarghle! bar!alope"
+ end
- it "non-overridden actions run and can access overridden and non-overridden variables (but not necessarily new ones)" do
- converge {
- action_jackalope 'hi' do
- foo 'foo!'
- bar 'bar!'
- blarghle 'blarghle!'
- action :access_attribute2
- end
- }
- expect(ActionJackson.ran_action).to eq :access_attribute2
- expect(ActionJackson.succeeded).to eq("foo!alope blarghle! bar!alope").or(eq("foo!alope blarghle!"))
+ it "overridden actions run, call super, and can access overridden, new, and overridden attributes" do
+ converge do
+ action_jackalope "hi" do
+ foo "foo!"
+ bar "bar!"
+ blarghle "blarghle!"
+ action :access_attribute
+ end
+ end
+ expect(ActionJackson.ran_action).to eq :access_attribute
+ expect(ActionJackson.succeeded).to eq "foo!alope blarghle! bar!alope"
+ expect(ActionJackalope.jackalope_ran).to eq :access_attribute
+ expect(ActionJackalope.succeeded).to eq "foo!alope blarghle! bar!alope"
+ end
+
+ it "non-overridden actions run and can access overridden and non-overridden variables (but not necessarily new ones)" do
+ converge do
+ action_jackalope "hi" do
+ foo "foo!"
+ bar "bar!"
+ blarghle "blarghle!"
+ action :access_attribute2
+ end
+ end
+ expect(ActionJackson.ran_action).to eq :access_attribute2
+ expect(ActionJackson.succeeded).to eq("foo!alope blarghle! bar!alope").or(eq("foo!alope blarghle!"))
+ end
end
end
- end
- context "With a resource with no actions" do
- before(:context) {
+ context "With a resource with no actions" do
class NoActionJackson < Chef::Resource
use_automatic_resource_name
- def foo(value=nil)
+ def foo(value = nil)
@foo = value if value
@foo
end
@@ -326,20 +345,19 @@ describe "Resource.action" do
attr_accessor :action_was
end
end
- }
- it "the default action is :nothing" do
- converge {
- no_action_jackson 'hi' do
- foo 'foo!'
- NoActionJackson.action_was = action
- end
- }
- expect(NoActionJackson.action_was).to eq [:nothing]
+
+ it "the default action is :nothing" do
+ converge do
+ no_action_jackson "hi" do
+ foo "foo!"
+ NoActionJackson.action_was = action
+ end
+ end
+ expect(NoActionJackson.action_was).to eq [:nothing]
+ end
end
- end
- context "With a resource with action a-b-c d" do
- before(:context) {
+ context "With a resource with action a-b-c d" do
class WeirdActionJackson < Chef::Resource
use_automatic_resource_name
@@ -351,13 +369,213 @@ describe "Resource.action" do
WeirdActionJackson.action_was = action
end
end
- }
- it "Running the action works" do
- expect_recipe {
- weird_action_jackson 'hi'
- }.to be_up_to_date
- expect(WeirdActionJackson.action_was).to eq :"a-b-c d"
+ it "Running the action works" do
+ expect_recipe do
+ weird_action_jackson "hi"
+ end.to be_up_to_date
+ expect(WeirdActionJackson.action_was).to eq :"a-b-c d"
+ end
+ end
+
+ context "With a resource with property x" do
+ class ResourceActionSpecWithX < Chef::Resource
+ resource_name :resource_action_spec_with_x
+ property :x, default: 20
+ action :set do
+ # Access x during converge to ensure that we emit no warnings there
+ x
+ end
+ end
+
+ context "And another resource with a property x and an action that sets property x to its value" do
+ class ResourceActionSpecAlsoWithX < Chef::Resource
+ resource_name :resource_action_spec_also_with_x
+ property :x
+ action :set_x_to_x do
+ resource_action_spec_with_x "hi" do
+ x x
+ end
+ end
+ def self.x_warning_line
+ __LINE__ - 4
+ end
+ action :set_x_to_x_in_non_initializer do
+ r = resource_action_spec_with_x "hi" do
+ x 10
+ end
+ x_times_2 = r.x * 2
+ end
+ action :set_x_to_10 do
+ resource_action_spec_with_x "hi" do
+ x 10
+ end
+ end
+ end
+
+ attr_reader :x_warning_line
+
+ it "Using the enclosing resource to set x to x emits a warning that you're using the wrong x" do
+ recipe = converge do
+ resource_action_spec_also_with_x "hi" do
+ x 1
+ action :set_x_to_x
+ end
+ end
+ warnings = recipe.logs.lines.select { |l| l =~ /warn/i }
+ expect(warnings.size).to eq 1
+ expect(warnings[0]).to match(/property x is declared in both resource_action_spec_with_x\[hi\] and resource_action_spec_also_with_x\[hi\] action :set_x_to_x. Use new_resource.x instead. At #{__FILE__}:#{ResourceActionSpecAlsoWithX.x_warning_line}/)
+ end
+
+ it "Using the enclosing resource to set x to x outside the initializer emits no warning" do
+ expect_recipe do
+ resource_action_spec_also_with_x "hi" do
+ x 1
+ action :set_x_to_x_in_non_initializer
+ end
+ end.to emit_no_warnings_or_errors
+ end
+
+ it "Using the enclosing resource to set x to 10 emits no warning" do
+ expect_recipe do
+ resource_action_spec_also_with_x "hi" do
+ x 1
+ action :set_x_to_10
+ end
+ end.to emit_no_warnings_or_errors
+ end
+
+ it "Using the enclosing resource to set x to 10 emits no warning" do
+ expect_recipe do
+ r = resource_action_spec_also_with_x "hi"
+ r.x 1
+ r.action :set_x_to_10
+ end.to emit_no_warnings_or_errors
+ end
+ end
+
+ end
+
+ context "With a resource with a set_or_return property named group (same name as a resource)" do
+ class ResourceActionSpecWithGroupAction < Chef::Resource
+ resource_name :resource_action_spec_set_group_to_nil
+ action :set_group_to_nil do
+ # Access x during converge to ensure that we emit no warnings there
+ resource_action_spec_with_group "hi" do
+ group nil
+ action :nothing
+ end
+ end
+ end
+
+ class ResourceActionSpecWithGroup < Chef::Resource
+ resource_name :resource_action_spec_with_group
+ def group(value = nil)
+ set_or_return(:group, value, {})
+ end
+ end
+
+ it "Setting group to nil in an action does not emit a warning about it being defined in two places" do
+ expect_recipe do
+ resource_action_spec_set_group_to_nil "hi" do
+ action :set_group_to_nil
+ end
+ end.to emit_no_warnings_or_errors
+ end
+ end
+
+ context "When a resource has a property with the same name as another resource" do
+ class HasPropertyNamedTemplate < Chef::Resource
+ use_automatic_resource_name
+ property :template
+ action :create do
+ template "x" do
+ "blah"
+ end
+ end
+ end
+
+ it "Raises an error when attempting to use a template in the action" do
+ expect_converge do
+ has_property_named_template "hi"
+ end.to raise_error(/Property `template` of `has_property_named_template\[hi\]` was incorrectly passed a block. Possible property-resource collision. To call a resource named `template` either rename the property or else use `declare_resource\(:template, ...\)`/)
+ end
+ end
+
+ context "When a resource declares methods in action_class and declare_action_class" do
+ class DeclaresActionClassMethods < Chef::Resource
+ use_automatic_resource_name
+ property :x
+ action :create do
+ new_resource.x = a + b + c + d
+ end
+ action_class do
+ def a
+ 1
+ end
+ end
+ declare_action_class do
+ def b
+ 2
+ end
+ end
+ action_class do
+ def c
+ 3
+ end
+ end
+ declare_action_class do
+ def d
+ 4
+ end
+ end
+ end
+
+ it "the methods are not available on the resource" do
+ expect { DeclaresActionClassMethods.new("hi").a }.to raise_error(NameError)
+ expect { DeclaresActionClassMethods.new("hi").b }.to raise_error(NameError)
+ expect { DeclaresActionClassMethods.new("hi").c }.to raise_error(NameError)
+ expect { DeclaresActionClassMethods.new("hi").d }.to raise_error(NameError)
+ end
+
+ it "the methods are available to the action" do
+ r = nil
+ expect_recipe do
+ r = declares_action_class_methods "hi"
+ end.to emit_no_warnings_or_errors
+ expect(r.x).to eq(10)
+ end
+
+ context "And a subclass also creates a method" do
+ class DeclaresActionClassMethodsToo < DeclaresActionClassMethods
+ use_automatic_resource_name
+ action :create do
+ new_resource.x a + b + c + d + e
+ end
+ action_class do
+ def e
+ 5
+ end
+ end
+ end
+
+ it "the methods are not available on the resource" do
+ expect { DeclaresActionClassMethods.new("hi").a }.to raise_error(NameError)
+ expect { DeclaresActionClassMethods.new("hi").b }.to raise_error(NameError)
+ expect { DeclaresActionClassMethods.new("hi").c }.to raise_error(NameError)
+ expect { DeclaresActionClassMethods.new("hi").d }.to raise_error(NameError)
+ expect { DeclaresActionClassMethods.new("hi").e }.to raise_error(NameError)
+ end
+
+ it "the methods are available to the action" do
+ r = nil
+ expect_recipe do
+ r = declares_action_class_methods_too "hi"
+ end.to emit_no_warnings_or_errors
+ expect(r.x).to eq(15)
+ end
+ end
end
end
+
end
diff --git a/spec/integration/recipes/resource_converge_if_changed_spec.rb b/spec/integration/recipes/resource_converge_if_changed_spec.rb
index 82d38a8faf..89d831ddec 100644
--- a/spec/integration/recipes/resource_converge_if_changed_spec.rb
+++ b/spec/integration/recipes/resource_converge_if_changed_spec.rb
@@ -1,4 +1,4 @@
-require 'support/shared/integration/integration_helper'
+require "support/shared/integration/integration_helper"
describe "Resource::ActionClass#converge_if_changed" do
include IntegrationSupport
@@ -19,14 +19,15 @@ describe "Resource::ActionClass#converge_if_changed" do
context "when the resource has identity, state and control properties" do
let(:resource_name) { :"converge_if_changed_dsl#{Namer.current_index}" }
- let(:resource_class) {
+ let(:resource_class) do
result = Class.new(Chef::Resource) do
- def self.to_s; resource_name; end
+ def self.to_s; resource_name.to_s; end
+
def self.inspect; resource_name.inspect; end
- property :identity1, identity: true, default: 'default_identity1'
- property :control1, desired_state: false, default: 'default_control1'
- property :state1, default: 'default_state1'
- property :state2, default: 'default_state2'
+ property :identity1, identity: true, default: "default_identity1"
+ property :control1, desired_state: false, default: "default_control1"
+ property :state1, default: "default_state1"
+ property :state2, default: "default_state2"
attr_accessor :converged
def initialize(*args)
super
@@ -35,7 +36,7 @@ describe "Resource::ActionClass#converge_if_changed" do
end
result.resource_name resource_name
result
- }
+ end
let(:converged_recipe) { converge(converge_recipe) }
let(:resource) { converged_recipe.resources.first }
@@ -51,8 +52,8 @@ describe "Resource::ActionClass#converge_if_changed" do
context "and current_resource with state1=current, state2=current" do
before :each do
resource_class.load_current_value do
- state1 'current_state1'
- state2 'current_state2'
+ state1 "current_state1"
+ state2 "current_state2"
end
end
@@ -69,13 +70,13 @@ describe "Resource::ActionClass#converge_if_changed" do
end
context "and state1 is set to a new value" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
<<-EOM
#{resource_name} 'blah' do
state1 'new_state1'
end
EOM
- }
+ end
it "the resource updates state1" do
expect(resource.converged).to eq 1
@@ -89,14 +90,14 @@ describe "Resource::ActionClass#converge_if_changed" do
end
context "and state1 and state2 are set to new values" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
<<-EOM
#{resource_name} 'blah' do
state1 'new_state1'
state2 'new_state2'
end
EOM
- }
+ end
it "the resource updates state1 and state2" do
expect(resource.converged).to eq 1
@@ -110,15 +111,38 @@ EOM
end
end
+ context "and state1 and state2 are set to new sensitive values" do
+ let(:converge_recipe) do
+ <<-EOM
+ #{resource_name} 'blah' do
+ sensitive true
+ state1 'new_state1'
+ state2 'new_state2'
+ end
+ EOM
+ end
+
+ it "the resource updates state1 and state2" do
+ expect(resource.converged).to eq 1
+ expect(resource.updated?).to be_truthy
+ expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+ - update default_identity1
+ - set state1 to (suppressed sensitive property)
+ - set state2 to (suppressed sensitive property)
+EOM
+ end
+ end
+
context "and state1 is set to its current value but state2 is set to a new value" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
<<-EOM
#{resource_name} 'blah' do
state1 'current_state1'
state2 'new_state2'
end
EOM
- }
+ end
it "the resource updates state2" do
expect(resource.converged).to eq 1
@@ -132,14 +156,14 @@ EOM
end
context "and state1 and state2 are set to their current values" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
<<-EOM
#{resource_name} 'blah' do
state1 'current_state1'
state2 'current_state2'
end
EOM
- }
+ end
it "the resource updates nothing" do
expect(resource.converged).to eq 0
@@ -151,14 +175,14 @@ EOM
end
context "and identity1 and control1 are set to new values" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
<<-EOM
#{resource_name} 'blah' do
identity1 'new_identity1'
control1 'new_control1'
end
EOM
- }
+ end
# Because the identity value is copied over to the new resource, by
# default they do not register as "changed"
@@ -175,20 +199,20 @@ EOM
context "and current_resource with identity1=current, control1=current" do
before :each do
resource_class.load_current_value do
- identity1 'current_identity1'
- control1 'current_control1'
+ identity1 "current_identity1"
+ control1 "current_control1"
end
end
context "and identity1 and control1 are set to new values" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
<<-EOM
#{resource_name} 'blah' do
identity1 'new_identity1'
control1 'new_control1'
end
EOM
- }
+ end
# Control values are not desired state and are therefore not considered
# a reason for converging.
@@ -228,14 +252,14 @@ EOM
end
context "and state1 and state2 are set" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
<<-EOM
#{resource_name} 'blah' do
state1 'new_state1'
state2 'new_state2'
end
EOM
- }
+ end
it "the resource is created" do
expect(resource.converged).to eq 1
@@ -249,6 +273,30 @@ EOM
EOM
end
end
+
+ context "and state1 and state2 are set with sensitive property" do
+ let(:converge_recipe) do
+ <<-EOM
+ #{resource_name} 'blah' do
+ sensitive true
+ state1 'new_state1'
+ state2 'new_state2'
+ end
+ EOM
+ end
+
+ it "the resource is created" do
+ expect(resource.converged).to eq 1
+ expect(resource.updated?).to be_truthy
+ expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+ - create default_identity1
+ - set identity1 to (suppressed sensitive property) (default value)
+ - set state1 to (suppressed sensitive property)
+ - set state2 to (suppressed sensitive property)
+EOM
+ end
+ end
end
end
@@ -267,8 +315,8 @@ EOM
context "and current_resource with state1=current, state2=current" do
before :each do
resource_class.load_current_value do
- state1 'current_state1'
- state2 'current_state2'
+ state1 "current_state1"
+ state2 "current_state2"
end
end
@@ -286,13 +334,13 @@ EOM
context "and state1 is set to a new value" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
<<-EOM
#{resource_name} 'blah' do
state1 'new_state1'
end
EOM
- }
+ end
it "the resource updates state1" do
expect(resource.converged).to eq 1
@@ -306,14 +354,14 @@ EOM
end
context "and state1 and state2 are set to new values" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
<<-EOM
#{resource_name} 'blah' do
state1 'new_state1'
state2 'new_state2'
end
EOM
- }
+ end
it "the resource updates state1 and state2" do
expect(resource.converged).to eq 2
@@ -329,14 +377,14 @@ EOM
end
context "and state1 is set to its current value but state2 is set to a new value" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
<<-EOM
#{resource_name} 'blah' do
state1 'current_state1'
state2 'new_state2'
end
EOM
- }
+ end
it "the resource updates state2" do
expect(resource.converged).to eq 1
@@ -350,14 +398,14 @@ EOM
end
context "and state1 and state2 are set to their current values" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
<<-EOM
#{resource_name} 'blah' do
state1 'current_state1'
state2 'current_state2'
end
EOM
- }
+ end
it "the resource updates nothing" do
expect(resource.converged).to eq 0
@@ -377,9 +425,9 @@ EOM
end
context "and nothing is set" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
"#{resource_name} 'blah'"
- }
+ end
it "the resource is created" do
expect(resource.converged).to eq 2
@@ -395,14 +443,14 @@ EOM
end
context "and state1 and state2 are set to new values" do
- let(:converge_recipe) {
+ let(:converge_recipe) do
<<-EOM
#{resource_name} 'blah' do
state1 'new_state1'
state2 'new_state2'
end
EOM
- }
+ end
it "the resource is created" do
expect(resource.converged).to eq 2
@@ -416,6 +464,31 @@ EOM
EOM
end
end
+
+ context "and state1 and state2 are set to new sensitive values" do
+ let(:converge_recipe) do
+ <<-EOM
+ #{resource_name} 'blah' do
+ sensitive true
+ state1 'new_state1'
+ state2 'new_state2'
+ end
+ EOM
+ end
+
+ it "the resource is created" do
+ expect(resource.converged).to eq 2
+ expect(resource.updated?).to be_truthy
+ expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+ - create default_identity1
+ - set state1 to (suppressed sensitive property)
+ - create default_identity1
+ - set state2 to (suppressed sensitive property)
+EOM
+ end
+ end
+
end
end
diff --git a/spec/integration/recipes/resource_load_spec.rb b/spec/integration/recipes/resource_load_spec.rb
index 556201efd8..791b83c23a 100644
--- a/spec/integration/recipes/resource_load_spec.rb
+++ b/spec/integration/recipes/resource_load_spec.rb
@@ -1,4 +1,4 @@
-require 'support/shared/integration/integration_helper'
+require "support/shared/integration/integration_helper"
describe "Resource.load_current_value" do
include IntegrationSupport
@@ -18,14 +18,16 @@ describe "Resource.load_current_value" do
before { Namer.incrementing_value = 0 }
let(:resource_name) { :"load_current_value_dsl#{Namer.current_index}" }
- let(:resource_class) {
+ let(:resource_class) do
result = Class.new(Chef::Resource) do
- def self.to_s; resource_name; end
+ def self.to_s; resource_name.to_s; end
+
def self.inspect; resource_name.inspect; end
property :x, default: lazy { "default #{Namer.incrementing_value}" }
def self.created_x=(value)
@created = value
end
+
def self.created_x
@created
end
@@ -35,7 +37,7 @@ describe "Resource.load_current_value" do
end
result.resource_name resource_name
result
- }
+ end
# Pull on resource_class to initialize it
before { resource_class }
@@ -43,10 +45,10 @@ describe "Resource.load_current_value" do
context "with a resource with load_current_value" do
before :each do
resource_class.load_current_value do
- x "loaded #{Namer.incrementing_value} (#{self.class.properties.sort_by { |name,p| name }.
- select { |name,p| p.is_set?(self) }.
- map { |name,p| "#{name}=#{p.get(self)}" }.
- join(", ") })"
+ x "loaded #{Namer.incrementing_value} (#{self.class.properties.sort_by { |name, p| name }.
+ select { |name, p| p.is_set?(self) }.
+ map { |name, p| "#{name}=#{p.get(self)}" }.
+ join(", ")})"
end
end
@@ -54,65 +56,65 @@ describe "Resource.load_current_value" do
let(:resource) do
e = self
r = nil
- converge {
- r = public_send(e.resource_name, 'blah') do
- x 'desired'
+ converge do
+ r = public_send(e.resource_name, "blah") do
+ x "desired"
end
- }
+ end
r
end
it "current_resource is passed name but not x" do
- expect(resource.current_value.x).to eq 'loaded 2 (name=blah)'
+ expect(resource.current_value.x).to eq "loaded 2 (name=blah)"
end
it "resource.current_value returns a different resource" do
- expect(resource.current_value.x).to eq 'loaded 2 (name=blah)'
- expect(resource.x).to eq 'desired'
+ expect(resource.current_value.x).to eq "loaded 2 (name=blah)"
+ expect(resource.x).to eq "desired"
end
it "resource.current_value constructs the resource anew each time" do
- expect(resource.current_value.x).to eq 'loaded 2 (name=blah)'
- expect(resource.current_value.x).to eq 'loaded 3 (name=blah)'
+ expect(resource.current_value.x).to eq "loaded 2 (name=blah)"
+ expect(resource.current_value.x).to eq "loaded 3 (name=blah)"
end
it "the provider accesses the current value of x" do
- expect(resource.class.created_x).to eq 'desired'
+ expect(resource.class.created_x).to eq "desired"
end
context "and identity: :i and :d with desired_state: false" do
- before {
+ before do
resource_class.class_eval do
property :i, identity: true
property :d, desired_state: false
end
- }
+ end
- before {
- resource.i 'desired_i'
- resource.d 'desired_d'
- }
+ before do
+ resource.i "desired_i"
+ resource.d "desired_d"
+ end
it "i, name and d are passed to load_current_value, but not x" do
- expect(resource.current_value.x).to eq 'loaded 2 (d=desired_d, i=desired_i, name=blah)'
+ expect(resource.current_value.x).to eq "loaded 2 (d=desired_d, i=desired_i, name=blah)"
end
end
context "and name_property: :i and :d with desired_state: false" do
- before {
+ before do
resource_class.class_eval do
property :i, name_property: true
property :d, desired_state: false
end
- }
+ end
- before {
- resource.i 'desired_i'
- resource.d 'desired_d'
- }
+ before do
+ resource.i "desired_i"
+ resource.d "desired_d"
+ end
it "i, name and d are passed to load_current_value, but not x" do
- expect(resource.current_value.x).to eq 'loaded 2 (d=desired_d, i=desired_i, name=blah)'
+ expect(resource.current_value.x).to eq "loaded 2 (d=desired_d, i=desired_i, name=blah)"
end
end
end
@@ -121,28 +123,28 @@ describe "Resource.load_current_value" do
let(:resource) do
e = self
r = nil
- converge {
- r = public_send(e.resource_name, 'blah') do
+ converge do
+ r = public_send(e.resource_name, "blah") do
end
- }
+ end
r
end
it "the provider accesses values from load_current_value" do
- expect(resource.class.created_x).to eq 'loaded 1 (name=blah)'
+ expect(resource.class.created_x).to eq "loaded 1 (name=blah)"
end
end
- let (:subresource_name) {
+ let (:subresource_name) do
:"load_current_value_subresource_dsl#{Namer.current_index}"
- }
- let (:subresource_class) {
+ end
+ let (:subresource_class) do
r = Class.new(resource_class) do
property :y, default: lazy { "default_y #{Namer.incrementing_value}" }
end
r.resource_name subresource_name
r
- }
+ end
# Pull on subresource_class to initialize it
before { subresource_class }
@@ -150,17 +152,17 @@ describe "Resource.load_current_value" do
let(:subresource) do
e = self
r = nil
- converge {
- r = public_send(e.subresource_name, 'blah') do
- x 'desired'
+ converge do
+ r = public_send(e.subresource_name, "blah") do
+ x "desired"
end
- }
+ end
r
end
context "and a child resource class with no load_current_value" do
it "the parent load_current_value is used" do
- expect(subresource.current_value.x).to eq 'loaded 2 (name=blah)'
+ expect(subresource.current_value.x).to eq "loaded 2 (name=blah)"
end
it "load_current_value yields a copy of the child class" do
expect(subresource.current_value).to be_kind_of(subresource_class)
@@ -168,37 +170,37 @@ describe "Resource.load_current_value" do
end
context "And a child resource class with load_current_value" do
- before {
+ before do
subresource_class.load_current_value do
- y "loaded_y #{Namer.incrementing_value} (#{self.class.properties.sort_by { |name,p| name }.
- select { |name,p| p.is_set?(self) }.
- map { |name,p| "#{name}=#{p.get(self)}" }.
- join(", ") })"
+ y "loaded_y #{Namer.incrementing_value} (#{self.class.properties.sort_by { |name, p| name }.
+ select { |name, p| p.is_set?(self) }.
+ map { |name, p| "#{name}=#{p.get(self)}" }.
+ join(", ")})"
end
- }
+ end
it "the overridden load_current_value is used" do
current_resource = subresource.current_value
- expect(current_resource.x).to eq 'default 3'
- expect(current_resource.y).to eq 'loaded_y 2 (name=blah)'
+ expect(current_resource.x).to eq "default 3"
+ expect(current_resource.y).to eq "loaded_y 2 (name=blah)"
end
end
context "and a child resource class with load_current_value calling super()" do
- before {
+ before do
subresource_class.load_current_value do
super()
- y "loaded_y #{Namer.incrementing_value} (#{self.class.properties.sort_by { |name,p| name }.
- select { |name,p| p.is_set?(self) }.
- map { |name,p| "#{name}=#{p.get(self)}" }.
- join(", ") })"
+ y "loaded_y #{Namer.incrementing_value} (#{self.class.properties.sort_by { |name, p| name }.
+ select { |name, p| p.is_set?(self) }.
+ map { |name, p| "#{name}=#{p.get(self)}" }.
+ join(", ")})"
end
- }
+ end
it "the original load_current_value is called as well as the child one" do
current_resource = subresource.current_value
- expect(current_resource.x).to eq 'loaded 3 (name=blah)'
- expect(current_resource.y).to eq 'loaded_y 4 (name=blah, x=loaded 3 (name=blah))'
+ expect(current_resource.x).to eq "loaded 3 (name=blah)"
+ expect(current_resource.y).to eq "loaded_y 4 (name=blah, x=loaded 3 (name=blah))"
end
end
end
diff --git a/spec/integration/solo/solo_spec.rb b/spec/integration/solo/solo_spec.rb
index f45933c799..f6cb2e43ef 100644
--- a/spec/integration/solo/solo_spec.rb
+++ b/spec/integration/solo/solo_spec.rb
@@ -1,9 +1,10 @@
-require 'support/shared/integration/integration_helper'
-require 'chef/mixin/shell_out'
-require 'chef/run_lock'
-require 'chef/config'
-require 'timeout'
-require 'fileutils'
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
+require "chef/run_lock"
+require "chef/config"
+require "timeout"
+require "fileutils"
+require "chef/win32/security" if Chef::Platform.windows?
describe "chef-solo" do
include IntegrationSupport
@@ -15,16 +16,65 @@ describe "chef-solo" do
let(:cookbook_ancient_100_metadata_rb) { cb_metadata("ancient", "1.0.0") }
- let(:chef_solo) { "ruby bin/chef-solo --minimal-ohai" }
+ let(:chef_solo) { "ruby bin/chef-solo --legacy-mode --minimal-ohai" }
+
+ when_the_repository "creates nodes" do
+ let(:nodes_dir) { File.join(@repository_dir, "nodes") }
+ let(:node_file) { Dir[File.join(nodes_dir, "*.json")][0] }
+
+ before do
+ file "config/solo.rb", <<EOM
+chef_repo_path "#{@repository_dir}"
+EOM
+ result = shell_out("ruby bin/chef-solo -c \"#{path_to('config/solo.rb')}\" -l debug", :cwd => chef_dir)
+ result.error!
+ end
+
+ describe "on unix", :unix_only do
+ describe "the nodes directory" do
+ it "has the correct permissions" do
+ expect(File.stat(nodes_dir).mode.to_s(8)[2..5]).to eq("700")
+ end
+ end
+
+ describe "the node file" do
+ it "has the correct permissions" do
+ expect(File.stat(node_file).mode.to_s(8)[2..5]).to eq("0600")
+ end
+ end
+ end
+
+ describe "on windows", :windows_only do
+ let(:read_mask) { Chef::ReservedNames::Win32::API::Security::GENERIC_READ }
+ let(:write_mask) { Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE }
+ let(:execute_mask) { Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE }
+
+ describe "the nodes directory" do
+ it "has the correct permissions" do
+ expect(Chef::ReservedNames::Win32::File.file_access_check(nodes_dir, read_mask)).to be(true)
+ expect(Chef::ReservedNames::Win32::File.file_access_check(nodes_dir, write_mask)).to be(true)
+ expect(Chef::ReservedNames::Win32::File.file_access_check(nodes_dir, execute_mask)).to be(true)
+ end
+ end
+
+ describe "the node file" do
+ it "has the correct permissions" do
+ expect(Chef::ReservedNames::Win32::File.file_access_check(node_file, read_mask)).to be(true)
+ expect(Chef::ReservedNames::Win32::File.file_access_check(node_file, write_mask)).to be(true)
+ expect(Chef::ReservedNames::Win32::File.file_access_check(node_file, execute_mask)).to be(false)
+ end
+ end
+ end
+ end
when_the_repository "has a cookbook with a basic recipe" do
before do
- file 'cookbooks/x/metadata.rb', cookbook_x_100_metadata_rb
- file 'cookbooks/x/recipes/default.rb', 'puts "ITWORKS"'
+ file "cookbooks/x/metadata.rb", cookbook_x_100_metadata_rb
+ file "cookbooks/x/recipes/default.rb", 'puts "ITWORKS"'
end
it "should complete with success" do
- file 'config/solo.rb', <<EOM
+ file "config/solo.rb", <<EOM
cookbook_path "#{path_to('cookbooks')}"
file_cache_path "#{path_to('config/cache')}"
EOM
@@ -34,12 +84,12 @@ EOM
end
it "should evaluate its node.json file" do
- file 'config/solo.rb', <<EOM
+ file "config/solo.rb", <<EOM
cookbook_path "#{path_to('cookbooks')}"
file_cache_path "#{path_to('config/cache')}"
EOM
- file 'config/node.json',<<-E
+ file "config/node.json", <<-E
{"run_list":["x::default"]}
E
@@ -52,15 +102,15 @@ E
when_the_repository "has a cookbook with an undeclared dependency" do
before do
- file 'cookbooks/x/metadata.rb', cookbook_x_100_metadata_rb
- file 'cookbooks/x/recipes/default.rb', 'include_recipe "ancient::aliens"'
+ file "cookbooks/x/metadata.rb", cookbook_x_100_metadata_rb
+ file "cookbooks/x/recipes/default.rb", 'include_recipe "ancient::aliens"'
- file 'cookbooks/ancient/metadata.rb', cookbook_ancient_100_metadata_rb
- file 'cookbooks/ancient/recipes/aliens.rb', 'print "it was aliens"'
+ file "cookbooks/ancient/metadata.rb", cookbook_ancient_100_metadata_rb
+ file "cookbooks/ancient/recipes/aliens.rb", 'print "it was aliens"'
end
it "should exit with an error" do
- file 'config/solo.rb', <<EOM
+ file "config/solo.rb", <<EOM
cookbook_path "#{path_to('cookbooks')}"
file_cache_path "#{path_to('config/cache')}"
EOM
@@ -70,73 +120,97 @@ EOM
end
end
+ when_the_repository "has a cookbook with an incompatible chef_version" do
+ before do
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0", "\nchef_version '~> 999.0'")
+ file "cookbooks/x/recipes/default.rb", 'puts "ITWORKS"'
+ file "config/solo.rb", <<EOM
+cookbook_path "#{path_to('cookbooks')}"
+file_cache_path "#{path_to('config/cache')}"
+EOM
+ end
+
+ it "should exit with an error" do
+ result = shell_out("#{chef_solo} -c \"#{path_to('config/solo.rb')}\" -o 'x::default' -l debug", :cwd => chef_dir)
+ expect(result.exitstatus).to eq(1)
+ expect(result.stdout).to include("Chef::Exceptions::CookbookChefVersionMismatch")
+ end
+ end
+
+ when_the_repository "has a cookbook with an incompatible ohai_version" do
+ before do
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0", "\nohai_version '~> 999.0'")
+ file "cookbooks/x/recipes/default.rb", 'puts "ITWORKS"'
+ file "config/solo.rb", <<EOM
+cookbook_path "#{path_to('cookbooks')}"
+file_cache_path "#{path_to('config/cache')}"
+EOM
+ end
+
+ it "should exit with an error" do
+ result = shell_out("#{chef_solo} -c \"#{path_to('config/solo.rb')}\" -o 'x::default' -l debug", :cwd => chef_dir)
+ expect(result.exitstatus).to eq(1)
+ expect(result.stdout).to include("Chef::Exceptions::CookbookOhaiVersionMismatch")
+ end
+ end
when_the_repository "has a cookbook with a recipe with sleep" do
before do
- directory 'logs'
- file 'logs/runs.log', ''
- file 'cookbooks/x/metadata.rb', cookbook_x_100_metadata_rb
- file 'cookbooks/x/recipes/default.rb', <<EOM
+ directory "logs"
+ file "logs/runs.log", ""
+ file "cookbooks/x/metadata.rb", cookbook_x_100_metadata_rb
+ file "cookbooks/x/recipes/default.rb", <<EOM
ruby_block "sleeping" do
block do
- sleep 5
+ retries = 200
+ while IO.read(Chef::Config[:log_location]) !~ /Chef client .* is running, will wait for it to finish and then run./
+ sleep 0.1
+ raise "we ran out of retries" if ( retries -= 1 ) <= 0
+ end
end
end
EOM
end
it "while running solo concurrently" do
- file 'config/solo.rb', <<EOM
+ file "config/solo.rb", <<EOM
cookbook_path "#{path_to('cookbooks')}"
file_cache_path "#{path_to('config/cache')}"
EOM
# We have a timeout protection here so that if due to some bug
# run_lock gets stuck we can discover it.
- expect {
+ expect do
Timeout.timeout(120) do
chef_dir = File.join(File.dirname(__FILE__), "..", "..", "..")
- # Instantiate the first chef-solo run
- s1 = Process.spawn("#{chef_solo} -c \"#{path_to('config/solo.rb')}\" -o 'x::default' \
--l debug -L #{path_to('logs/runs.log')}", :chdir => chef_dir)
+ threads = []
- # Give it some time to progress
- sleep 1
+ # Instantiate the first chef-solo run
+ threads << Thread.new do
+ s1 = Process.spawn("#{chef_solo} -c \"#{path_to('config/solo.rb')}\" -o 'x::default' -l debug -L #{path_to('logs/runs.log')}", :chdir => chef_dir)
+ Process.waitpid(s1)
+ end
# Instantiate the second chef-solo run
- s2 = Process.spawn("#{chef_solo} -c \"#{path_to('config/solo.rb')}\" -o 'x::default' \
--l debug -L #{path_to('logs/runs.log')}", :chdir => chef_dir)
+ threads << Thread.new do
+ s2 = Process.spawn("#{chef_solo} -c \"#{path_to('config/solo.rb')}\" -o 'x::default' -l debug -L #{path_to('logs/runs.log')}", :chdir => chef_dir)
+ Process.waitpid(s2)
+ end
- Process.waitpid(s1)
- Process.waitpid(s2)
+ threads.each(&:join)
end
- }.not_to raise_error
+ end.not_to raise_error
# Unfortunately file / directory helpers in integration tests
# are implemented using before(:each) so we need to do all below
# checks in one example.
- run_log = File.read(path_to('logs/runs.log'))
-
- # both of the runs should succeed
- expect(run_log.lines.reject {|l| !l.include? "INFO: Chef Run complete in"}.length).to eq(2)
+ run_log = File.read(path_to("logs/runs.log"))
# second run should have a message which indicates it's waiting for the first run
- pid_lines = run_log.lines.reject {|l| !l.include? "Chef-client pid:"}
- expect(pid_lines.length).to eq(2)
- pids = pid_lines.map {|l| l.split(" ").last}
- expect(run_log).to include("Chef client #{pids[0]} is running, will wait for it to finish and then run.")
-
- # second run should start after first run ends
- starts = [ ]
- ends = [ ]
- run_log.lines.each_with_index do |line, index|
- if line.include? "Chef-client pid:"
- starts << index
- elsif line.include? "INFO: Chef Run complete in"
- ends << index
- end
- end
- expect(starts[1]).to be > ends[0]
+ expect(run_log).to match(/Chef client .* is running, will wait for it to finish and then run./)
+
+ # both of the runs should succeed
+ expect(run_log.lines.reject { |l| !l.include? "INFO: Chef Run complete in" }.length).to eq(2)
end
end
diff --git a/spec/scripts/ssl-serve.rb b/spec/scripts/ssl-serve.rb
index 24ed70addc..3f4e343926 100644
--- a/spec/scripts/ssl-serve.rb
+++ b/spec/scripts/ssl-serve.rb
@@ -5,11 +5,10 @@
# You can use it to test various HTTP behaviors in chef, like chef-client's
# `-j` and `-c` options and remote_file with https connections.
#
-require 'pp'
-require 'openssl'
-require 'webrick'
-require 'webrick/https'
-
+require "pp"
+require "openssl"
+require "webrick"
+require "webrick/https"
$ssl = true
@@ -21,23 +20,21 @@ key = OpenSSL::PKey::RSA.new(key_text)
server_opts = {}
if $ssl
-server_opts.merge!( { :SSLEnable => true,
- :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
- :SSLCertificate => cert,
- :SSLPrivateKey => key })
+ server_opts.merge!( { :SSLEnable => true,
+ :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
+ :SSLCertificate => cert,
+ :SSLPrivateKey => key })
end
-
-
# 5 == debug, 3 == warning
LOGGER = WEBrick::Log.new(STDOUT, 5)
DEFAULT_OPTIONS = {
- :server => 'webrick',
+ :server => "webrick",
:Port => 9000,
- :Host => 'localhost',
+ :Host => "localhost",
:environment => :none,
:Logger => LOGGER,
- :DocumentRoot => File.expand_path("/tmp/chef-118-sampledata")
+ :DocumentRoot => File.expand_path("#{Dir.tmpdir}/chef-118-sampledata")
#:AccessLog => [] # Remove this option to enable the access log when debugging.
}
@@ -45,8 +42,6 @@ webrick_opts = DEFAULT_OPTIONS.merge(server_opts)
pp :webrick_opts => webrick_opts
server = WEBrick::HTTPServer.new(webrick_opts)
-trap 'INT' do server.shutdown end
+trap("INT") { server.shutdown }
server.start
-
-
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 4f7fde8eaf..50ad2a3fb6 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,16 +27,15 @@ end
# Ruby 1.9 Compat
$:.unshift File.expand_path("../..", __FILE__)
-
-require 'rubygems'
-require 'rspec/mocks'
+require "rubygems"
+require "rspec/mocks"
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
$:.unshift(File.expand_path("../lib", __FILE__))
$:.unshift(File.dirname(__FILE__))
if ENV["COVERAGE"]
- require 'simplecov'
+ require "simplecov"
SimpleCov.start do
add_filter "/spec/"
add_group "Remote File", "remote_file"
@@ -46,34 +45,42 @@ if ENV["COVERAGE"]
end
end
-require 'chef'
-require 'chef/knife'
+require "chef"
+require "chef/knife"
+
+Dir["lib/chef/knife/**/*.rb"].
+ map { |f| f.gsub("lib/", "") }.
+ map { |f| f.gsub(%r{\.rb$}, "") }.
+ each { |f| require f }
+
+require "chef/resource_resolver"
+require "chef/provider_resolver"
-Dir['lib/chef/knife/**/*.rb'].
- map {|f| f.gsub('lib/', '') }.
- map {|f| f.gsub(%r[\.rb$], '') }.
- each {|f| require f }
+require "chef/mixins"
+require "chef/dsl"
+require "chef/application"
+require "chef/applications"
-require 'chef/resource_resolver'
-require 'chef/provider_resolver'
+require "chef/shell"
+require "chef/util/file_edit"
-require 'chef/mixins'
-require 'chef/dsl'
-require 'chef/application'
-require 'chef/applications'
+require "chef/config"
-require 'chef/shell'
-require 'chef/util/file_edit'
+require "chef/chef_fs/file_system_cache"
-require 'chef/config'
+require "chef/api_client_v1"
+
+if ENV["CHEF_FIPS"] == "1"
+ Chef::Config.init_openssl
+end
# If you want to load anything into the testing environment
# without versioning it, add it to spec/support/local_gems.rb
-require 'spec/support/local_gems.rb' if File.exists?(File.join(File.dirname(__FILE__), 'support', 'local_gems.rb'))
+require "spec/support/local_gems.rb" if File.exists?(File.join(File.dirname(__FILE__), "support", "local_gems.rb"))
# Explicitly require spec helpers that need to load first
-require 'spec/support/platform_helpers'
-require 'spec/support/shared/unit/mock_shellout'
+require "spec/support/platform_helpers"
+require "spec/support/shared/unit/mock_shellout"
# Autoloads support files
# Excludes support/platforms by default
@@ -81,21 +88,23 @@ require 'spec/support/shared/unit/mock_shellout'
Dir["spec/support/**/*.rb"].
reject { |f| f =~ %r{^spec/support/platforms} }.
reject { |f| f =~ %r{^spec/support/pedant} }.
- map { |f| f.gsub(%r{.rb$}, '') }.
- map { |f| f.gsub(%r[spec/], '')}.
+ map { |f| f.gsub(%r{.rb$}, "") }.
+ map { |f| f.gsub(%r{spec/}, "") }.
each { |f| require f }
OHAI_SYSTEM = Ohai::System.new
-OHAI_SYSTEM.all_plugins("platform")
+OHAI_SYSTEM.all_plugins(["platform", "hostname", "languages/powershell"])
test_node = Chef::Node.new
-test_node.automatic['os'] = (OHAI_SYSTEM['os'] || 'unknown_os').dup.freeze
-test_node.automatic['platform_family'] = (OHAI_SYSTEM['platform_family'] || 'unknown_platform_family').dup.freeze
-test_node.automatic['platform'] = (OHAI_SYSTEM['platform'] || 'unknown_platform').dup.freeze
-test_node.automatic['platform_version'] = (OHAI_SYSTEM['platform_version'] || 'unknown_platform_version').dup.freeze
+test_node.automatic["os"] = (OHAI_SYSTEM["os"] || "unknown_os").dup.freeze
+test_node.automatic["platform_family"] = (OHAI_SYSTEM["platform_family"] || "unknown_platform_family").dup.freeze
+test_node.automatic["platform"] = (OHAI_SYSTEM["platform"] || "unknown_platform").dup.freeze
+test_node.automatic["platform_version"] = (OHAI_SYSTEM["platform_version"] || "unknown_platform_version").dup.freeze
TEST_NODE = test_node.freeze
-TEST_PLATFORM = TEST_NODE['platform']
-TEST_PLATFORM_VERSION = TEST_NODE['platform_version']
+TEST_OS = TEST_NODE["os"]
+TEST_PLATFORM = TEST_NODE["platform"]
+TEST_PLATFORM_VERSION = TEST_NODE["platform_version"]
+TEST_PLATFORM_FAMILY = TEST_NODE["platform_family"]
RSpec.configure do |config|
config.include(Matchers)
@@ -112,7 +121,7 @@ RSpec.configure do |config|
end
# Only run these tests on platforms that are also chef workstations
- config.filter_run_excluding :workstation if solaris? or aix?
+ config.filter_run_excluding :workstation if solaris? || aix?
# Tests that randomly fail, but may have value.
config.filter_run_excluding :volatile => true
@@ -121,15 +130,18 @@ RSpec.configure do |config|
config.filter_run_excluding :skip_appveyor => true if ENV["APPVEYOR"]
config.filter_run_excluding :appveyor_only => true unless ENV["APPVEYOR"]
+ config.filter_run_excluding :skip_travis => true if ENV["TRAVIS"]
config.filter_run_excluding :windows_only => true unless windows?
config.filter_run_excluding :not_supported_on_mac_osx_106 => true if mac_osx_106?
- config.filter_run_excluding :not_supported_on_mac_osx=> true if mac_osx?
- config.filter_run_excluding :mac_osx_only=> true if !mac_osx?
+ config.filter_run_excluding :not_supported_on_mac_osx => true if mac_osx?
+ config.filter_run_excluding :mac_osx_only => true if !mac_osx?
config.filter_run_excluding :not_supported_on_win2k3 => true if windows_win2k3?
config.filter_run_excluding :not_supported_on_solaris => true if solaris?
+ config.filter_run_excluding :not_supported_on_gce => true if gce?
config.filter_run_excluding :not_supported_on_nano => true if windows_nano_server?
config.filter_run_excluding :win2k3_only => true unless windows_win2k3?
+ config.filter_run_excluding :win2012r2_only => true unless windows_2012r2?
config.filter_run_excluding :windows_2008r2_or_later => true unless windows_2008r2_or_later?
config.filter_run_excluding :windows64_only => true unless windows64?
config.filter_run_excluding :windows32_only => true unless windows32?
@@ -140,41 +152,48 @@ RSpec.configure do |config|
config.filter_run_excluding :windows_powershell_no_dsc_only => true unless ! windows_powershell_dsc?
config.filter_run_excluding :windows_domain_joined_only => true unless windows_domain_joined?
config.filter_run_excluding :windows_not_domain_joined_only => true if windows_domain_joined?
+ # We think this line was causing rspec tests to not run on the Jenkins windows
+ # testers. If we ever fix it we should restore it.
+ # config.filter_run_excluding :windows_service_requires_assign_token => true if !STDOUT.isatty && !windows_user_right?("SeAssignPrimaryTokenPrivilege")
+ config.filter_run_excluding :windows_service_requires_assign_token => true
config.filter_run_excluding :solaris_only => true unless solaris?
config.filter_run_excluding :system_windows_service_gem_only => true unless system_windows_service_gem?
config.filter_run_excluding :unix_only => true unless unix?
+ config.filter_run_excluding :linux_only => true unless linux?
config.filter_run_excluding :aix_only => true unless aix?
+ config.filter_run_excluding :debian_family_only => true unless debian_family?
config.filter_run_excluding :supports_cloexec => true unless supports_cloexec?
config.filter_run_excluding :selinux_only => true unless selinux_enabled?
- config.filter_run_excluding :ruby_20_only => true unless ruby_20?
- # chef_gte_XX_only and chef_lt_XX_only pair up correctly with the same XX
- # number. please conserve this pattern & resist filling out all the operators
- config.filter_run_excluding :chef_gte_13_only => true unless chef_gte_13?
- config.filter_run_excluding :chef_lt_13_only => true unless chef_lt_13?
config.filter_run_excluding :requires_root => true unless root?
- config.filter_run_excluding :requires_root_or_running_windows => true unless (root? || windows?)
+ config.filter_run_excluding :requires_root_or_running_windows => true unless root? || windows?
config.filter_run_excluding :requires_unprivileged_user => true if root?
config.filter_run_excluding :uses_diff => true unless has_diff?
config.filter_run_excluding :openssl_gte_101 => true unless openssl_gte_101?
config.filter_run_excluding :openssl_lt_101 => true unless openssl_lt_101?
config.filter_run_excluding :aes_256_gcm_only => true unless aes_256_gcm?
config.filter_run_excluding :broken => true
+ config.filter_run_excluding :not_wpar => true unless wpar?
+ config.filter_run_excluding :not_supported_under_fips => true if fips?
+
+ # these let us use chef: ">= 13" or ruby: "~> 2.0.0" or any other Gem::Dependency-style constraint
+ config.filter_run_excluding chef: DependencyProc.with(Chef::VERSION)
+ config.filter_run_excluding ruby: DependencyProc.with(RUBY_VERSION)
running_platform_arch = `uname -m`.strip unless windows?
- config.filter_run_excluding :arch => lambda {|target_arch|
+ config.filter_run_excluding :arch => lambda { |target_arch|
running_platform_arch != target_arch
}
# Functional Resource tests that are provider-specific:
# context "on platforms that use useradd", :provider => {:user => Chef::Provider::User::Useradd}} do #...
- config.filter_run_excluding :provider => lambda {|criteria|
+ config.filter_run_excluding :provider => lambda { |criteria|
type, target_provider = criteria.first
node = TEST_NODE.dup
resource_class = Chef::ResourceResolver.resolve(type, node: node)
if resource_class
- resource = resource_class.new('test', Chef::RunContext.new(node, nil, nil))
+ resource = resource_class.new("test", Chef::RunContext.new(node, nil, nil))
begin
provider = resource.provider_for_action(Array(resource_class.default_action).first)
provider.class != target_provider
@@ -191,13 +210,22 @@ RSpec.configure do |config|
config.before(:each) do
Chef.reset!
+ Chef::ChefFS::FileSystemCache.instance.reset!
+
Chef::Config.reset
# By default, treat deprecation warnings as errors in tests.
Chef::Config.treat_deprecation_warnings_as_errors(true)
# Set environment variable so the setting persists in child processes
- ENV['CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS'] = "1"
+ ENV["CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS"] = "1"
+ end
+
+ # raise if anyone commits any test to CI with :focus set on it
+ if ENV["CI"]
+ config.before(:example, :focus) do
+ raise "This example was committed with `:focus` and should not have been"
+ end
end
config.before(:suite) do
@@ -205,7 +233,8 @@ RSpec.configure do |config|
end
end
-require 'webrick/utils'
+require "webrick/utils"
+require "thread"
# Webrick uses a centralized/synchronized timeout manager. It works by
# starting a thread to check for timeouts on an interval. The timeout
@@ -224,11 +253,16 @@ module WEBrick
module Utils
class TimeoutHandler
def initialize
- @timeout_info = Hash.new
+ end
+
+ def register(*args)
+ end
+
+ def cancel(*args)
end
end
end
end
# Enough stuff needs json serialization that I'm just adding it here for equality asserts
-require 'chef/json_compat'
+require "chef/json_compat"
diff --git a/spec/stress/win32/file_spec.rb b/spec/stress/win32/file_spec.rb
index 6c4b26b05c..f1c81eb9c6 100644
--- a/spec/stress/win32/file_spec.rb
+++ b/spec/stress/win32/file_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/win32/file' if windows?
+require "spec_helper"
+require "chef/win32/file" if windows?
-describe 'Chef::ReservedNames::Win32::File', :windows_only do
+describe "Chef::ReservedNames::Win32::File", :windows_only do
before(:each) do
@path = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "data", "old_home_dir", "my-dot-emacs"))
end
diff --git a/spec/stress/win32/memory_spec.rb b/spec/stress/win32/memory_spec.rb
index ed3ad306d0..f5f429fefc 100644
--- a/spec/stress/win32/memory_spec.rb
+++ b/spec/stress/win32/memory_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-describe 'Chef::ReservedNames::Win32::Memory', :windows_only do
+describe "Chef::ReservedNames::Win32::Memory", :windows_only do
end
diff --git a/spec/stress/win32/security_spec.rb b/spec/stress/win32/security_spec.rb
index cb520e515e..3c03a657b2 100644
--- a/spec/stress/win32/security_spec.rb
+++ b/spec/stress/win32/security_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,22 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
if windows?
- require 'chef/win32/security'
- require 'tmpdir'
- require 'fileutils'
+ require "chef/win32/security"
+ require "tmpdir"
+ require "fileutils"
end
-describe 'Chef::ReservedNames::Win32::Security', :windows_only do
+describe "Chef::ReservedNames::Win32::Security", :windows_only do
def monkeyfoo
- File.join(CHEF_SPEC_DATA, "monkeyfoo").gsub("/", "\\")
+ File.join(CHEF_SPEC_DATA, "monkeyfoo").tr("/", "\\")
end
before :all do
- @test_tempdir = File.join(Dir::tmpdir, "cheftests", "chef_win32_security")
+ @test_tempdir = File.join(Dir.tmpdir, "cheftests", "chef_win32_security")
FileUtils.mkdir_p(@test_tempdir)
@monkeyfoo = File.join(@test_tempdir, "monkeyfoo.txt")
end
@@ -49,21 +49,21 @@ describe 'Chef::ReservedNames::Win32::Security', :windows_only do
end
it "should not leak when retrieving and reading the ACE from a file", :volatile do
- expect {
+ expect do
sids = Chef::ReservedNames::Win32::Security::SecurableObject.new(@monkeyfoo).security_descriptor.dacl.select { |ace| ace.sid }
GC.start
- }.not_to leak_memory(:warmup => 50, :iterations => 100)
+ end.not_to leak_memory(:warmup => 50, :iterations => 100)
end
it "should not leak when creating a new ACL and setting it on a file", :volatile do
securable_object = Security::SecurableObject.new(@monkeyfoo)
- expect {
+ expect do
securable_object.dacl = Chef::ReservedNames::Win32::Security::ACL.create([
Chef::ReservedNames::Win32::Security::ACE.access_allowed(Chef::ReservedNames::Win32::Security::SID.Everyone, Chef::ReservedNames::Win32::API::Security::GENERIC_READ),
- Chef::ReservedNames::Win32::Security::ACE.access_denied(Chef::ReservedNames::Win32::Security::SID.from_account("Users"), Chef::ReservedNames::Win32::API::Security::GENERIC_ALL)
+ Chef::ReservedNames::Win32::Security::ACE.access_denied(Chef::ReservedNames::Win32::Security::SID.from_account("Users"), Chef::ReservedNames::Win32::API::Security::GENERIC_ALL),
])
GC.start
- }.not_to leak_memory(:warmup => 50, :iterations => 100)
+ end.not_to leak_memory(:warmup => 50, :iterations => 100)
end
end
diff --git a/spec/support/chef_helpers.rb b/spec/support/chef_helpers.rb
index 851b1dce0a..444e5a30c8 100644
--- a/spec/support/chef_helpers.rb
+++ b/spec/support/chef_helpers.rb
@@ -1,4 +1,4 @@
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
#
CHEF_SPEC_DATA = File.expand_path(File.dirname(__FILE__) + "/../data/")
CHEF_SPEC_ASSETS = File.expand_path(File.dirname(__FILE__) + "/../functional/assets/")
-CHEF_SPEC_BACKUP_PATH = File.join(Dir.tmpdir, 'test-backup-path')
+CHEF_SPEC_BACKUP_PATH = File.join(Dir.tmpdir, "test-backup-path")
Chef::Config[:log_level] = :fatal
Chef::Config[:persistent_queue] = false
@@ -25,9 +25,8 @@ Chef::Log.init(StringIO.new)
Chef::Log.level(Chef::Config.log_level)
Chef::Config.solo(false)
-
def sha256_checksum(path)
- Digest::SHA256.hexdigest(File.read(path))
+ OpenSSL::Digest::SHA256.hexdigest(File.read(path))
end
# From Ruby 1.9.2+
@@ -54,13 +53,11 @@ end
# This is a temporary fix to get tests passing on systems that have no `diff`
# until we can replace shelling out to `diff` with ruby diff-lcs
def has_diff?
- begin
- diff_cmd = Mixlib::ShellOut.new("diff -v")
- diff_cmd.run_command
- true
- rescue Errno::ENOENT
- false
- end
+ diff_cmd = Mixlib::ShellOut.new("diff -v")
+ diff_cmd.run_command
+ true
+rescue Errno::ENOENT
+ false
end
# This is a helper to determine if the ruby in the PATH contains
@@ -82,12 +79,34 @@ end
# This is a helper to canonicalize paths that we're using in the file
# tests.
def canonicalize_path(path)
- windows? ? path.gsub('/', '\\') : path
+ windows? ? path.tr("/", '\\') : path
+end
+
+# Makes a temp directory with a canonical path on any platform.
+# Only really needed to work around an issue on Windows where
+# Ruby's temp library generates paths with short names.
+def make_canonical_temp_directory
+ temp_directory = Dir.mktmpdir
+ if windows?
+ # On Windows, temporary file / directory path names may have shortened
+ # subdirectory names due to reliance on the TMP and TEMP environment variables
+ # in some Windows APIs and duplicated logic in Ruby's temp file implementation.
+ # To work around this in the unit test context, we obtain the long (canonical)
+ # path name via a Windows system call so that this path name can be used
+ # in expectations that assume the ability to canonically name paths in comparisons.
+ # Note that this was not an issue prior to Ruby 2.2 -- with Ruby 2.2,
+ # some Chef code started to use long file names, while Ruby's temp file implementation
+ # continued to return the shortened names -- this would cause these particular tests to
+ # fail if the username happened to be longer than 8 characters.
+ Chef::ReservedNames::Win32::File.get_long_path_name(temp_directory)
+ else
+ temp_directory
+ end
end
# Check if a cmd exists on the PATH
def which(cmd)
- paths = ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/bin', '/usr/bin', '/sbin', '/usr/sbin' ]
+ paths = ENV["PATH"].split(File::PATH_SEPARATOR) + [ "/bin", "/usr/bin", "/sbin", "/usr/sbin" ]
paths.each do |path|
filename = File.join(path, cmd)
return filename if File.executable?(filename)
diff --git a/spec/support/key_helpers.rb b/spec/support/key_helpers.rb
index 076f709380..33b8b32de9 100644
--- a/spec/support/key_helpers.rb
+++ b/spec/support/key_helpers.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
shared_examples_for "a knife key command" do
let(:stderr) { StringIO.new }
diff --git a/spec/support/lib/chef/provider/easy.rb b/spec/support/lib/chef/provider/easy.rb
index a4d285a838..54f1bff2a3 100644
--- a/spec/support/lib/chef/provider/easy.rb
+++ b/spec/support/lib/chef/provider/easy.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/spec/support/lib/chef/provider/openldap_includer.rb b/spec/support/lib/chef/provider/openldap_includer.rb
index afb0c7cf01..302d6002e9 100644
--- a/spec/support/lib/chef/provider/openldap_includer.rb
+++ b/spec/support/lib/chef/provider/openldap_includer.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/spec/support/lib/chef/provider/snakeoil.rb b/spec/support/lib/chef/provider/snakeoil.rb
index 485d37329f..f7769ebfc8 100644
--- a/spec/support/lib/chef/provider/snakeoil.rb
+++ b/spec/support/lib/chef/provider/snakeoil.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +19,7 @@
class Chef
class Provider
class SnakeOil < Chef::Provider
+ provides :cat
def load_current_resource
true
diff --git a/spec/support/lib/chef/resource/cat.rb b/spec/support/lib/chef/resource/cat.rb
index efc78aa59c..38cbd60f0b 100644
--- a/spec/support/lib/chef/resource/cat.rb
+++ b/spec/support/lib/chef/resource/cat.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,16 +19,17 @@
class Chef
class Resource
class Cat < Chef::Resource
+ provides :cat
attr_accessor :action
- def initialize(name, run_context=nil)
+ def initialize(name, run_context = nil)
super
@action = "sell"
end
- def pretty_kitty(arg=nil)
- if arg == true or arg == false
+ def pretty_kitty(arg = nil)
+ if arg == true || arg == false
@pretty_kitty = arg
end
@pretty_kitty
diff --git a/spec/support/lib/chef/resource/one_two_three_four.rb b/spec/support/lib/chef/resource/one_two_three_four.rb
index 8f273a0cda..ef03a1133e 100644
--- a/spec/support/lib/chef/resource/one_two_three_four.rb
+++ b/spec/support/lib/chef/resource/one_two_three_four.rb
@@ -1,6 +1,6 @@
#
# Author:: John Hampton (<john@cleanoffer.com>)
-# Copyright:: Copyright (c) 2009 CleanOffer, Inc.
+# Copyright:: Copyright 2009-2016, CleanOffer, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +19,7 @@
class Chef
class Resource
class OneTwoThreeFour < Chef::Resource
+ provides :one_two_three_four
attr_reader :i_can_count
@@ -26,8 +27,8 @@ class Chef
@i_can_count = tf
end
- def something(arg=nil)
- if arg == true or arg == false
+ def something(arg = nil)
+ if arg == true || arg == false
@something = arg
end
@something
diff --git a/spec/support/lib/chef/resource/openldap_includer.rb b/spec/support/lib/chef/resource/openldap_includer.rb
index 6f443b4c7c..356d622e38 100644
--- a/spec/support/lib/chef/resource/openldap_includer.rb
+++ b/spec/support/lib/chef/resource/openldap_includer.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,11 @@
# limitations under the License.
#
-
class Chef
class Resource
class OpenldapIncluder < Chef::Resource::LWRPBase
+ provides :openldap_includer
+
allowed_actions :run
default_action :run
end
diff --git a/spec/support/lib/chef/resource/with_state.rb b/spec/support/lib/chef/resource/with_state.rb
index 773ae7ddb8..444191da62 100644
--- a/spec/support/lib/chef/resource/with_state.rb
+++ b/spec/support/lib/chef/resource/with_state.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,14 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/json_compat'
+require "chef/knife"
+require "chef/json_compat"
class Chef
class Resource
class WithState < Chef::Resource
+ provides :with_state
+
attr_accessor :state
end
end
diff --git a/spec/support/lib/chef/resource/zen_follower.rb b/spec/support/lib/chef/resource/zen_follower.rb
index 155e6ae729..84fc71cc99 100644
--- a/spec/support/lib/chef/resource/zen_follower.rb
+++ b/spec/support/lib/chef/resource/zen_follower.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/json_compat'
+require "chef/knife"
+require "chef/json_compat"
class Chef
class Resource
@@ -24,7 +24,7 @@ class Chef
provides :follower, platform: "zen"
- def master(arg=nil)
+ def master(arg = nil)
if !arg.nil?
@master = arg
end
diff --git a/spec/support/lib/chef/resource/zen_master.rb b/spec/support/lib/chef/resource/zen_master.rb
index 4106549d79..99d761c8cf 100644
--- a/spec/support/lib/chef/resource/zen_master.rb
+++ b/spec/support/lib/chef/resource/zen_master.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,22 @@
# limitations under the License.
#
-require 'chef/knife'
-require 'chef/json_compat'
+require "chef/knife"
+require "chef/json_compat"
class Chef
class Resource
class ZenMaster < Chef::Resource
+ provides :zen_master
allowed_actions :win, :score
attr_reader :peace
-
def peace(tf)
@peace = tf
end
- def something(arg=nil)
+ def something(arg = nil)
if !arg.nil?
@something = arg
end
diff --git a/spec/support/lib/library_load_order.rb b/spec/support/lib/library_load_order.rb
index c47a2f2c74..6b4c54fe4f 100644
--- a/spec/support/lib/library_load_order.rb
+++ b/spec/support/lib/library_load_order.rb
@@ -18,5 +18,3 @@ module LibraryLoadOrder
load_order << file
end
end
-
-
diff --git a/spec/support/matchers/leak.rb b/spec/support/matchers/leak.rb
index 01d1e53f92..5f22c1c151 100644
--- a/spec/support/matchers/leak.rb
+++ b/spec/support/matchers/leak.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@ module Matchers
module LeakBase
include RSpec::Matchers
- def initialize(opts={}, &block)
+ def initialize(opts = {})
@warmup = opts[:warmup] || 5
@iterations = opts[:iterations] || 100
@variance = opts[:variance] || 5000
@@ -35,6 +35,7 @@ module Matchers
end
private
+
def match(measure, given_proc)
profiler.start
@@ -60,10 +61,10 @@ module Matchers
def profiler
@profiler ||= begin
if Chef::Platform.windows?
- require File.join(File.dirname(__FILE__), '..', 'platforms', 'prof', 'win32')
+ require File.join(File.dirname(__FILE__), "..", "platforms", "prof", "win32")
RSpec::Prof::Win32::Profiler.new
else
- require File.join(File.dirname(__FILE__), '..', 'prof', 'gc')
+ require File.join(File.dirname(__FILE__), "..", "prof", "gc")
RSpec::Prof::GC::Profiler.new
end
end
@@ -90,6 +91,7 @@ module Matchers
def leak_memory(opts, &block)
Matchers::LeakMemory.new(opts, &block)
end
+
def leak_handles(opts, &block)
Matchers::LeakHandles.new(opts, &block)
end
diff --git a/spec/support/mock/constant.rb b/spec/support/mock/constant.rb
index c706ad29dd..3a23b4d8d8 100644
--- a/spec/support/mock/constant.rb
+++ b/spec/support/mock/constant.rb
@@ -4,16 +4,16 @@
# http://missingbit.blogspot.com/2011/07/stubbing-constants-in-rspec_20.html
# http://digitaldumptruck.jotabout.com/?p=551
-def mock_constants(constants, &block)
+def mock_constants(constants)
saved_constants = {}
constants.each do |constant, val|
source_object, const_name = parse_constant(constant)
saved_constants[constant] = source_object.const_get(const_name)
- with_warnings(nil) {source_object.const_set(const_name, val) }
+ with_warnings(nil) { source_object.const_set(const_name, val) }
end
begin
- block.call
+ yield
ensure
constants.each do |constant, val|
source_object, const_name = parse_constant(constant)
@@ -23,7 +23,7 @@ def mock_constants(constants, &block)
end
def parse_constant(constant)
- source, _, constant_name = constant.to_s.rpartition('::')
+ source, _, constant_name = constant.to_s.rpartition("::")
[constantize(source), constant_name]
end
@@ -41,7 +41,7 @@ end
# File activesupport/lib/active_support/inflector/methods.rb, line 209
def constantize(camel_cased_word)
- names = camel_cased_word.split('::')
+ names = camel_cased_word.split("::")
names.shift if names.empty? || names.first.empty?
constant = Object
diff --git a/spec/support/mock/platform.rb b/spec/support/mock/platform.rb
index 7eae82fe7d..c6670827f9 100644
--- a/spec/support/mock/platform.rb
+++ b/spec/support/mock/platform.rb
@@ -5,9 +5,9 @@
# 'i386-mingw32' (windows) or 'x86_64-darwin11.2.0' (unix). Usueful for
# testing code that mixes in platform specific modules like +Chef::Mixin::Securable+
# or +Chef::FileAccessControl+
-def platform_mock(platform = :unix, &block)
+def platform_mock(platform = :unix)
allow(ChefConfig).to receive(:windows?).and_return(platform == :windows ? true : false)
- ENV['SYSTEMDRIVE'] = (platform == :windows ? 'C:' : nil)
+ ENV["SYSTEMDRIVE"] = (platform == :windows ? "C:" : nil)
if platform == :windows
Chef::Config.set_defaults_for_windows
@@ -16,10 +16,10 @@ def platform_mock(platform = :unix, &block)
end
if block_given?
- mock_constants({"RUBY_PLATFORM" => (platform == :windows ? 'i386-mingw32' : 'x86_64-darwin11.2.0'),
- "File::PATH_SEPARATOR" => (platform == :windows ? ";" : ":"),
- "File::ALT_SEPARATOR" => (platform == :windows ? "\\" : nil) }) do
-yield
+ mock_constants({ "RUBY_PLATFORM" => (platform == :windows ? "i386-mingw32" : "x86_64-darwin11.2.0"),
+ "File::PATH_SEPARATOR" => (platform == :windows ? ";" : ":"),
+ "File::ALT_SEPARATOR" => (platform == :windows ? "\\" : nil) }) do
+ yield
end
end
end
diff --git a/spec/support/pedant/Gemfile b/spec/support/pedant/Gemfile
deleted file mode 100644
index d4224cd439..0000000000
--- a/spec/support/pedant/Gemfile
+++ /dev/null
@@ -1,3 +0,0 @@
-source "https://rubygems.org"
-
-gem 'chef-pedant', :github => 'opscode/chef-pedant', :ref => "server-cli-option"
diff --git a/spec/support/pedant/pedant_config.rb b/spec/support/pedant/pedant_config.rb
deleted file mode 100644
index 3f8219fc59..0000000000
--- a/spec/support/pedant/pedant_config.rb
+++ /dev/null
@@ -1,129 +0,0 @@
-# Copyright: Copyright (c) 2012 Opscode, Inc.
-# License: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This annotated Pedant configuration file details the various
-# configuration settings available to you. It is separate from the
-# actual Pedant::Config class because not all settings have sane
-# defaults, and not all settings are appropriate in all settings.
-
-################################################################################
-# You MUST specify the address of the server the API requests will be
-# sent to. Only specify protocol, hostname, and port.
-# NOTE this is assigned in run_pedant.rb, because it's possible 8889 will not be the port chosen.
-#chef_server 'http://127.0.0.1:8889'
-
-# If you are doing development testing, you can specify the address of
-# the Solr server. The presence of this parameter will enable tests
-# to force commits to Solr, greatly decreasing the amount of time
-# needed for testing the search endpoint. This is only an
-# optimization for development! If you are testing a "live" Chef
-# Server, or otherwise do not have access to the Solr server from your
-# testing location, you should not specify a value for this parameter.
-# The tests will still run, albeit slower, as they will now need to
-# poll for a period to ensure they are querying committed results.
-#search_server "http://localhost:8983"
-
-# Related to the 'search_server' parameter, this specifies the maximum
-# amount of time (in seconds) that search endpoint requests should be
-# retried before giving up. If not explicitly set, it will default to
-# 65 seconds; only set it if you know that your Solr commit interval
-# differs significantly from this.
-maximum_search_time 0
-
-# OSC sends erchef a host header with a port, so this option needs
-# # to be enabled for Pedant tests to work correctly
-explicit_port_url true
-
-# We're starting to break tests up into groups based on different
-# criteria. The proper API tests (the results of which are viewable
-# to OPC customers) should be the only ones run by Pedant embedded in
-# OPC installs. There are other specs that help us keep track of API
-# cruft that we want to come back and fix later; these shouldn't be
-# viewable to customers, but we should be able to run them in
-# development and CI environments. If this parameter is missing or
-# explicitly `false` only the customer-friendly tests will be run.
-#
-# This is mainly here for documentation purposes, since the
-# command-line `opscode-pedant` utility ultimately determines this
-# value.
-include_internal false
-
-# Test users. The five users specified below are required; their
-# names (:user, :non_org_user, etc.) are indicative of their role
-# within the tests. All users must have a ':name' key. If they have
-# a ':create_me' key, Pedant will create these users for you. If you
-# are using pre-existing users, you must supply a ':key_file' key,
-# which should be the fully-qualified path /on the machine Pedant is
-# running on/ to a private key for that user.
-key = 'spec/support/pedant/stickywicket.pem'
-superuser_name 'admin'
-superuser_key key
-webui_key key
-
-# When we updated Chef to RSpec 3 there were gem conflicts with chef-pedant.
-# We removed chef as a chef-pedant gem dependency in pedant.gemfile, but this
-# caused chef-pedant to fail because it could not query for the chef version
-# on the box pedant is running on. X-Chef-Version isn't needed in server
-# requests for these tests, so we've disabled it.
-ingore_x_chef_version true
-
-# Set the platform_class
-platform_class Pedant::OpenSourcePlatform
-
-requestors({
- :clients => {
- # The the admin user, for the purposes of getting things rolling
- :admin => {
- :name => "pedant_admin_client",
- :create_me => true,
- :create_knife => true,
- :admin => true
- },
- :non_admin => {
- :name => 'pedant_client',
- :create_me => true,
- :create_knife => true
- },
- :bad => {
- :name => 'bad_client',
- :bogus => true
- }
- },
- :users => {
- :admin => {
- :name => "admin",
- :key_file => key,
- :create_me => false,
- :create_knife => false,
- :admin => true
- },
- :non_admin => {
- :name => "pedant_non_admin_user",
- :create_me => true,
- :create_knife => true,
- :admin => false
- },
- # A user for Knife tests. A knife.rb and key files will be set up
- # for this user
- :knife_user => {
- :name => "knifey",
- :create_me => true,
- :create_knife => true
- }
- }
-})
-
-self[:tags] = [:validation, :authentication, :authorization]
-verify_error_messages false
diff --git a/spec/support/pedant/run_pedant.rb b/spec/support/pedant/run_pedant.rb
deleted file mode 100644
index aac2c2df1a..0000000000
--- a/spec/support/pedant/run_pedant.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env ruby
-require 'bundler'
-require 'bundler/setup'
-require 'chef_zero/server'
-require 'rspec/core'
-require 'chef/chef_fs/chef_fs_data_store'
-require 'chef/chef_fs/config'
-require 'tmpdir'
-require 'fileutils'
-require 'chef/version'
-require 'chef/mixin/shell_out'
-
-def start_server(chef_repo_path)
- Dir.mkdir(chef_repo_path) if !File.exists?(chef_repo_path)
-
- # 11.6 and below had a bug where it couldn't create the repo children automatically
- if Chef::VERSION.to_f < 11.8
- %w(clients cookbooks data_bags environments nodes roles users).each do |child|
- Dir.mkdir("#{chef_repo_path}/#{child}") if !File.exists?("#{chef_repo_path}/#{child}")
- end
- end
-
- # Start the new server
- Chef::Config.repo_mode = 'everything'
- Chef::Config.chef_repo_path = chef_repo_path
- Chef::Config.versioned_cookbooks = true
- chef_fs = Chef::ChefFS::Config.new.local_fs
- data_store = Chef::ChefFS::ChefFSDataStore.new(chef_fs)
- server = ChefZero::Server.new(:port => 8889.upto(9999), :data_store => data_store)#, :log_level => :debug)
- server.start_background
- server
-end
-
-tmpdir = Dir.mktmpdir
-begin
- # Create chef repository
- chef_repo_path = "#{tmpdir}/repo"
-
- # Capture setup data into master_chef_repo_path
- server = start_server(chef_repo_path)
- so = nil
-
- include Chef::Mixin::ShellOut
-
- Bundler.with_clean_env do
-
- shell_out("bundle install --gemfile spec/support/pedant/Gemfile", :live_stream => STDOUT)
-
- pedant_cmd = "chef-pedant " +
- " --config spec/support/pedant/pedant_config.rb" +
- " --server '#{server.url}'" +
- " --skip-knife --skip-validation --skip-authentication" +
- " --skip-authorization --skip-omnibus"
- so = shell_out("bundle exec #{pedant_cmd}", :live_stream => STDOUT, :env => {'BUNDLE_GEMFILE' => 'spec/support/pedant/Gemfile'})
-
- end
-
-ensure
- server.stop if server && server.running?
- FileUtils.remove_entry_secure(tmpdir) if tmpdir
-end
-
-exit(so.exitstatus)
diff --git a/spec/support/pedant/stickywicket.pem b/spec/support/pedant/stickywicket.pem
deleted file mode 100644
index ff09e73903..0000000000
--- a/spec/support/pedant/stickywicket.pem
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpQIBAAKCAQEApNCkX2k+lFGDWRVhX4uClaVQrumG9XXvk6X7M2izrIg7RzMP
-Dk4thhZkpx5gr22By7PZQdMEjWC/Zo8MBjtoJ0GV0jw8npefbU1MGKs2dtpYgo0N
-Fq8fX8MdFPu4h2W3g0dMEdhT8icc2H4EjhZmdeUhUn3RIEt2duCgp3YDYnUUZx3j
-N7MHcTIdzD58ikr6zQrZzHOv+OOI86Xk9EpyEEQizOLoQxkICNrhqN7ElQDuvXaX
-BSBrYDRKH2umBMMcXzvsR/SvkmqxoEESSpIlW8zeKAWQ+znNjDC0tmTg7jZmgSP7
-siKrwo4t4ebjcmjpIoi/JKww/nGN3Uhz1ZOZuwIDAQABAoIBAQCaJQD2s0nyEeKU
-uKhfYe155Cl3zbWJcQnmv4AXbr9MiAVY6+oS6Q8ur1bn7kNjDzoruENjiuZhC7E3
-TGZklb8tp+tluyy+7vQOmBKpp8fClSfewekR5CultqhGbb8B8yIVR+NfdUHd4rLZ
-z9KWyWB+txPZQQ8L80gSmrfmpzs3IuT7oPvmtBU1Wq9QapC4n/rUohHUpUV1du4G
-0wCIF4zQTg6cbYW2YXozwVQvw+P7P3RVEqZt+aZlbVcy0fNr6jNao0hi1KFC9OH2
-VjjU+PioreoA/NU3aZPIUzmJpWtsu31yuOZxXmytAkYooCZgiEQNEHnJlNPv0RmC
-6BPMzVoBAoGBAM7yZoSNJpzdP/q1/4+H3zyy7o4I0VTW9u/GqUzhnbjm5poK30X9
-YXh/7WOVV0OoVqdO6ljRKygP3Oggf41ZEbi1C6bbsO57pksBWgx9bD9V35XscZ0J
-F1ERe//kMHwVQy74R8/cIuRwm75haLSBj5/fwGbLeeVDglJkCVqPjtuBAoGBAMvh
-qsAGG5k9u6voTcXlFwS+B5YjULhK4NSxdJ2BnOxzYzxQ3IYQZMlb2xt8yZYx/ZZK
-wjkr9rcAPEQIQZ2A6NUbGq6qCD7sSmg6UAi0CgiqTokQ/Wtag0UDvFMzwerdg/On
-37uxffpxpte8z1jYi/MxRaoTYueuc1UVnqofVIM7AoGBALZJzwPzUY/bVAADUJmd
-lYZiFsAGBF42/E05MOgH1GaK/ZWy/fkouDLsfK67XaK7JZk6ajLSDLG9R1kxRym6
-y2FoGFtiKPfo8xIenrNhx3gCrG/jVjB9UYyXWiKNXifukr9M8/SkdBfFGWsZYqGd
-fmXVMiVaFoVcce8hLxwWWEABAoGBAKcyhKX/HEj6YFqlIoqkydDAylXs1jicZ27l
-rF2yum8KXZpMMdzbutuKsdAD8Ql0K6NB4a+jByuiTMn5/11cJxUEqkgM9sArZQW+
-tH2+r+/VQpyTS0/rpXVGj/2nl2K1kI2T4R36e/aTl6CanWweAf9JK/lC9rxKyxg+
-p6SaFuObAoGACP6TKCkp2oymXlKgdUUgPrnsaz2VAw8jD5QHtx10U4wty0C8gxsk
-MLe00h09iLPyFmvJpD+MgbxV/r6RrZeVdsKdU/5LG52YgiVSTaizyy+ciEfW7xoQ
-CL5EtZd8Cn5OKinBEzzFpELqunlqepIKCIDOcLKz/cjR+3a+E6Zx5Wo=
------END RSA PRIVATE KEY-----
diff --git a/spec/support/platform_helpers.rb b/spec/support/platform_helpers.rb
index 9c6c3fdf72..fb50ee2298 100644
--- a/spec/support/platform_helpers.rb
+++ b/spec/support/platform_helpers.rb
@@ -1,37 +1,33 @@
-require 'fcntl'
-require 'chef/mixin/shell_out'
-
+require "fcntl"
+require "chef/mixin/shell_out"
+require "ohai/mixin/gce_metadata"
class ShellHelpers
extend Chef::Mixin::ShellOut
end
-def ruby_lt_20?
- !ruby_gte_20?
-end
+# magic stolen from bundler/spec/support/less_than_proc.rb
+class DependencyProc < Proc
+ attr_accessor :present
-def chef_gte_13?
- Chef::VERSION.split('.').first.to_i >= 13
-end
-
-def chef_lt_13?
- Chef::VERSION.split('.').first.to_i < 13
-end
-
-def ruby_gte_19?
- RUBY_VERSION.to_f >= 1.9
-end
+ def self.with(present)
+ provided = Gem::Version.new(present.dup)
+ new do |required|
+ !Gem::Requirement.new(required).satisfied_by?(provided)
+ end.tap { |l| l.present = present }
+ end
-def ruby_20?
- !!(RUBY_VERSION =~ /^2.0/)
+ def inspect
+ "\"#{present}\""
+ end
end
def ruby_64bit?
- !!(RbConfig::CONFIG['host_cpu'] =~ /x86_64/)
+ !!(RbConfig::CONFIG["host_cpu"] =~ /x86_64/)
end
def ruby_32bit?
- !!(RbConfig::CONFIG['host_cpu'] =~ /i686/)
+ !!(RbConfig::CONFIG["host_cpu"] =~ /i686/)
end
def windows?
@@ -43,39 +39,47 @@ def ohai
OHAI_SYSTEM
end
-require 'wmi-lite/wmi' if windows?
+require "wmi-lite/wmi" if windows?
def windows_domain_joined?
return false unless windows?
wmi = WmiLite::Wmi.new
- computer_system = wmi.first_of('Win32_ComputerSystem')
- computer_system['partofdomain']
+ computer_system = wmi.first_of("Win32_ComputerSystem")
+ computer_system["partofdomain"]
end
def windows_win2k3?
return false unless windows?
- wmi = WmiLite::Wmi.new
- host = wmi.first_of('Win32_OperatingSystem')
- (host['version'] && host['version'].start_with?("5.2"))
+ (host_version && host_version.start_with?("5.2"))
end
def windows_2008r2_or_later?
return false unless windows?
- wmi = WmiLite::Wmi.new
- host = wmi.first_of('Win32_OperatingSystem')
- version = host['version']
- return false unless version
- components = version.split('.').map do | component |
+ return false unless host_version
+ components = host_version.split(".").map do |component|
component.to_i
end
- components.length >=2 && components[0] >= 6 && components[1] >= 1
+ components.length >= 2 && components[0] >= 6 && components[1] >= 1
+end
+
+def windows_2012r2?
+ return false unless windows?
+ (host_version && host_version.start_with?("6.3"))
+end
+
+def host_version
+ @host_version ||= begin
+ wmi = WmiLite::Wmi.new
+ host = wmi.first_of("Win32_OperatingSystem")
+ host["version"]
+ end
end
def windows_powershell_dsc?
return false unless windows?
supports_dsc = false
begin
- wmi = WmiLite::Wmi.new('root/microsoft/windows/desiredstateconfiguration')
+ wmi = WmiLite::Wmi.new("root/microsoft/windows/desiredstateconfiguration")
lcm = wmi.query("SELECT * FROM meta_class WHERE __this ISA 'MSFT_DSCLocalConfigurationManager'")
supports_dsc = !! lcm
rescue WmiLite::WmiException
@@ -84,10 +88,16 @@ def windows_powershell_dsc?
end
def windows_nano_server?
- require 'chef/platform/query_helpers'
+ require "chef/platform/query_helpers"
Chef::Platform.windows_nano_server?
end
+def windows_user_right?(right)
+ return false unless windows?
+ require "chef/win32/security"
+ Chef::ReservedNames::Win32::Security.get_account_right(ENV["USERNAME"]).include?(right)
+end
+
def mac_osx_106?
if File.exists? "/usr/bin/sw_vers"
result = ShellHelpers.shell_out("/usr/bin/sw_vers")
@@ -114,10 +124,9 @@ def mac_osx?
false
end
-
# detects if the hardware is 64-bit (evaluates to true in "WOW64" mode in a 32-bit app on a 64-bit system)
def windows64?
- windows? && ( ENV['PROCESSOR_ARCHITECTURE'] == 'AMD64' || ENV['PROCESSOR_ARCHITEW6432'] == 'AMD64' )
+ windows? && ( ENV["PROCESSOR_ARCHITECTURE"] == "AMD64" || ENV["PROCESSOR_ARCHITEW6432"] == "AMD64" )
end
# detects if the hardware is 32-bit
@@ -131,6 +140,10 @@ def unix?
!windows?
end
+def linux?
+ !!(RUBY_PLATFORM =~ /linux/)
+end
+
def os_x?
!!(RUBY_PLATFORM =~ /darwin/)
end
@@ -143,22 +156,30 @@ def freebsd?
!!(RUBY_PLATFORM =~ /freebsd/)
end
+def debian_family?
+ !!(ohai[:platform_family] == "debian")
+end
+
def aix?
!!(RUBY_PLATFORM =~ /aix/)
end
+def wpar?
+ !((ohai[:virtualization] || {})[:wpar_no].nil?)
+end
+
def supports_cloexec?
- Fcntl.const_defined?('F_SETFD') && Fcntl.const_defined?('FD_CLOEXEC')
+ Fcntl.const_defined?("F_SETFD") && Fcntl.const_defined?("FD_CLOEXEC")
end
-DEV_NULL = windows? ? 'NUL' : '/dev/null'
+DEV_NULL = windows? ? "NUL" : "/dev/null"
def selinux_enabled?
# This code is currently copied from lib/chef/util/selinux to make
# specs independent of product.
selinuxenabled_path = which("selinuxenabled")
if selinuxenabled_path
- cmd = Mixlib::ShellOut.new(selinuxenabled_path, :returns => [0,1])
+ cmd = Mixlib::ShellOut.new(selinuxenabled_path, :returns => [0, 1])
cmd_result = cmd.run_command
case cmd_result.exitstatus
when 1
@@ -166,7 +187,7 @@ def selinux_enabled?
when 0
return true
else
- raise RuntimeError, "Unknown exit code from command #{selinuxenabled_path}: #{cmd.exitstatus}"
+ raise "Unknown exit code from command #{selinuxenabled_path}: #{cmd.exitstatus}"
end
else
# We assume selinux is not enabled if selinux utils are not
@@ -195,3 +216,17 @@ end
def aes_256_gcm?
OpenSSL::Cipher.ciphers.include?("aes-256-gcm")
end
+
+def fips?
+ ENV["CHEF_FIPS"] == "1"
+end
+
+class GCEDetector
+ extend Ohai::Mixin::GCEMetadata
+end
+
+def gce?
+ GCEDetector.can_metadata_connect?(Ohai::Mixin::GCEMetadata::GCE_METADATA_ADDR, 80)
+rescue SocketError
+ false
+end
diff --git a/spec/support/platforms/prof/gc.rb b/spec/support/platforms/prof/gc.rb
index 6ca50df648..b494ff9646 100644
--- a/spec/support/platforms/prof/gc.rb
+++ b/spec/support/platforms/prof/gc.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,12 +35,10 @@ module RSpec
end
def working_set_size
- begin
- ::GC.start
- ::GC::Profiler.result.scan(LINE_PATTERN)[-1][2].to_i if ::GC::Profiler.enabled?
- ensure
- ::GC::Profiler.clear
- end
+ ::GC.start
+ ::GC::Profiler.result.scan(LINE_PATTERN)[-1][2].to_i if ::GC::Profiler.enabled?
+ ensure
+ ::GC::Profiler.clear
end
def handle_count
@@ -51,4 +49,3 @@ module RSpec
end
end
end
-
diff --git a/spec/support/platforms/prof/win32.rb b/spec/support/platforms/prof/win32.rb
index ab256ff0fc..1cfbecc95d 100644
--- a/spec/support/platforms/prof/win32.rb
+++ b/spec/support/platforms/prof/win32.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/win32/process'
+require "chef/win32/process"
module RSpec
module Prof
@@ -43,4 +43,3 @@ module RSpec
end
end
end
-
diff --git a/spec/support/platforms/win32/spec_service.rb b/spec/support/platforms/win32/spec_service.rb
index 3e1f6c3638..5548a79afc 100644
--- a/spec/support/platforms/win32/spec_service.rb
+++ b/spec/support/platforms/win32/spec_service.rb
@@ -1,6 +1,6 @@
#
# Author:: Serdar Sutay (<serdar@lambda.local>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'win32/daemon'
+require "win32/daemon"
class SpecService < ::Win32::Daemon
def service_init
@@ -24,9 +24,9 @@ class SpecService < ::Win32::Daemon
end
def service_main(*startup_parameters)
- while running? do
+ while running?
if !File.exists?(@test_service_file)
- File.open(@test_service_file, 'wb') do |f|
+ File.open(@test_service_file, "wb") do |f|
f.write("This file is created by SpecService")
end
end
diff --git a/spec/support/shared/context/client.rb b/spec/support/shared/context/client.rb
index eb537e9889..c65650e6b1 100644
--- a/spec/support/shared/context/client.rb
+++ b/spec/support/shared/context/client.rb
@@ -1,5 +1,5 @@
-require 'spec_helper'
+require "spec_helper"
# Stubs a basic client object
shared_context "client" do
@@ -15,7 +15,7 @@ shared_context "client" do
:hostname => hostname,
:machinename => machinename,
:platform => platform,
- :platform_version => platform_version
+ :platform_version => platform_version,
}
end
@@ -68,9 +68,11 @@ shared_context "a client run" do
let(:api_client_exists?) { false }
let(:enable_fork) { false }
- let(:http_cookbook_sync) { double("Chef::REST (cookbook sync)") }
- let(:http_node_load) { double("Chef::REST (node)") }
- let(:http_node_save) { double("Chef::REST (node save)") }
+ let(:http_data_collector) { double("Chef::ServerAPI (data collector)") }
+ let(:http_cookbook_sync) { double("Chef::ServerAPI (cookbook sync)") }
+ let(:http_node_load) { double("Chef::ServerAPI (node)") }
+ let(:http_node_save) { double("Chef::ServerAPI (node save)") }
+ let(:reporting_rest_client) { double("Chef::ServerAPI (reporting client)") }
let(:runner) { instance_double("Chef::Runner") }
let(:audit_runner) { instance_double("Chef::Audit::Runner", :failed? => false) }
@@ -91,12 +93,20 @@ shared_context "a client run" do
end
end
+ def stub_for_data_collector_init
+ expect(Chef::ServerAPI).to receive(:new).
+ with(Chef::Config[:data_collector][:server_url], validate_utf8: false).
+ exactly(:once).
+ and_return(http_data_collector)
+ end
+
def stub_for_node_load
# Client.register will then turn around create another
- # Chef::REST object, this time with the client key it got from the
+ # Chef::ServerAPI object, this time with the client key it got from the
# previous step.
- expect(Chef::REST).to receive(:new).
- with(Chef::Config[:chef_server_url], fqdn, Chef::Config[:client_key]).
+ expect(Chef::ServerAPI).to receive(:new).
+ with(Chef::Config[:chef_server_url], client_name: fqdn,
+ signing_key_filename: Chef::Config[:client_key]).
exactly(:once).
and_return(http_node_load)
@@ -110,14 +120,18 @@ shared_context "a client run" do
expect_any_instance_of(Chef::ResourceReporter).to receive(:node_load_completed)
end
+ def stub_rest_clean
+ allow(client).to receive(:rest_clean).and_return(reporting_rest_client)
+ end
+
def stub_for_sync_cookbooks
# --Client#setup_run_context
# ---Client#sync_cookbooks -- downloads the list of cookbooks to sync
#
expect_any_instance_of(Chef::CookbookSynchronizer).to receive(:sync_cookbooks)
- expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
+ expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
expect(http_cookbook_sync).to receive(:post).
- with("environments/_default/cookbook_versions", {:run_list => []}).
+ with("environments/_default/cookbook_versions", { :run_list => [] }).
and_return({})
end
@@ -139,14 +153,16 @@ shared_context "a client run" do
before do
Chef::Config[:client_fork] = enable_fork
- Chef::Config[:cache_path] = windows? ? 'C:\chef' : '/var/chef'
+ Chef::Config[:cache_path] = windows? ? 'C:\chef' : "/var/chef"
Chef::Config[:why_run] = false
Chef::Config[:audit_mode] = :enabled
stub_const("Chef::Client::STDOUT_FD", stdout)
stub_const("Chef::Client::STDERR_FD", stderr)
+ stub_rest_clean
stub_for_register
+ stub_for_data_collector_init
stub_for_node_load
stub_for_sync_cookbooks
stub_for_converge
@@ -175,8 +191,9 @@ shared_context "converge completed" do
allow(node).to receive(:data_for_save).and_return(node.for_json)
# --Client#save_updated_node
- expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url], fqdn, Chef::Config[:client_key], validate_utf8: false).and_return(http_node_save)
- expect(http_node_save).to receive(:put_rest).with("nodes/#{fqdn}", node.for_json).and_return(true)
+ expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url], client_name: fqdn,
+ signing_key_filename: Chef::Config[:client_key], validate_utf8: false).and_return(http_node_save)
+ expect(http_node_save).to receive(:put).with("nodes/#{fqdn}", node.for_json).and_return(true)
end
end
@@ -222,8 +239,9 @@ shared_context "audit phase failed with error" do
end
shared_context "audit phase completed with failed controls" do
- let(:audit_runner) { instance_double("Chef::Audit::Runner", :failed? => true,
- :num_failed => 1, :num_total => 3) }
+ let(:audit_runner) do
+ instance_double("Chef::Audit::Runner", :failed? => true,
+ :num_failed => 1, :num_total => 3) end
let(:audit_error) do
err = Chef::Exceptions::AuditsFailed.new(audit_runner.num_failed, audit_runner.num_total)
diff --git a/spec/support/shared/context/config.rb b/spec/support/shared/context/config.rb
index 1412356f3a..bb4ff7e0d1 100644
--- a/spec/support/shared/context/config.rb
+++ b/spec/support/shared/context/config.rb
@@ -5,15 +5,15 @@
#
# Required chef files here:
-require 'chef/config'
+require "chef/config"
# Required spec files here:
-require 'spec_helper'
+require "spec_helper"
# Basic config. Nothing fancy.
shared_context "default config options" do
before do
- Chef::Config[:cache_path] = windows? ? 'C:\chef' : '/var/chef'
+ Chef::Config[:cache_path] = windows? ? 'C:\chef' : "/var/chef"
end
# Don't need to have an after block to reset the config...
diff --git a/spec/support/shared/context/win32.rb b/spec/support/shared/context/win32.rb
index 3dbe876114..98f7f906c1 100644
--- a/spec/support/shared/context/win32.rb
+++ b/spec/support/shared/context/win32.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,17 +18,17 @@
RSpec.shared_context "Win32" do
before(:all) do
@original_win32 = if defined?(Win32)
- win32 = Object.send(:const_get, 'Win32')
- Object.send(:remove_const, 'Win32')
- win32
- else
- nil
- end
+ win32 = Object.send(:const_get, "Win32")
+ Object.send(:remove_const, "Win32")
+ win32
+ else
+ nil
+ end
Win32 = Module.new
end
after(:all) do
- Object.send(:remove_const, 'Win32') if defined?(Win32)
- Object.send(:const_set, 'Win32', @original_win32) if @original_win32
+ Object.send(:remove_const, "Win32") if defined?(Win32)
+ Object.send(:const_set, "Win32", @original_win32) if @original_win32
end
end
diff --git a/spec/support/shared/examples/client.rb b/spec/support/shared/examples/client.rb
index 330cb40ac6..3c13cd767e 100644
--- a/spec/support/shared/examples/client.rb
+++ b/spec/support/shared/examples/client.rb
@@ -1,6 +1,6 @@
-require 'spec_helper'
-require 'spec/support/shared/context/client'
+require "spec_helper"
+require "spec/support/shared/context/client"
# requires platform and platform_version be defined
shared_examples "a completed run" do
@@ -24,7 +24,7 @@ shared_examples "a completed run with audit failure" do
end
it "converges, runs audits, saves the node and raises the error in a wrapping error" do
- expect{ client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
+ expect { client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
expect(error.wrapped_errors.size).to eq(run_errors.size)
run_errors.each do |run_error|
expect(error.wrapped_errors).to include(run_error)
@@ -42,7 +42,7 @@ shared_examples "a failed run" do
include_context "run failed"
it "skips node save and raises the error in a wrapping error" do
- expect{ client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
+ expect { client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
expect(error.wrapped_errors.size).to eq(run_errors.size)
run_errors.each do |run_error|
expect(error.wrapped_errors).to include(run_error)
diff --git a/spec/support/shared/functional/diff_disabled.rb b/spec/support/shared/functional/diff_disabled.rb
index 7ee9808a94..c40b1e6e49 100644
--- a/spec/support/shared/functional/diff_disabled.rb
+++ b/spec/support/shared/functional/diff_disabled.rb
@@ -1,5 +1,5 @@
-shared_context "diff disabled" do
+shared_context "diff disabled" do
before do
Chef::Config[:diff_disabled] = true
end
diff --git a/spec/support/shared/functional/directory_resource.rb b/spec/support/shared/functional/directory_resource.rb
index 39bdc313e5..5e5e2bb360 100644
--- a/spec/support/shared/functional/directory_resource.rb
+++ b/spec/support/shared/functional/directory_resource.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@ shared_examples_for "a directory resource" do
include_context "diff disabled"
- let(:expect_updated?) {true}
+ let(:expect_updated?) { true }
context "when the target directory does not exist" do
before do
@@ -48,7 +48,7 @@ shared_examples_for "a directory resource" do
expect(File).not_to exist(path)
resource.recursive(true)
- @recursive_path = File.join(path, 'red-headed-stepchild')
+ @recursive_path = File.join(path, "red-headed-stepchild")
resource.path(@recursive_path)
resource.run_action(:create)
end
@@ -68,14 +68,14 @@ shared_examples_for "a directory resource" do
def allowed_acl(sid, expected_perms)
[
ACE.access_allowed(sid, expected_perms[:specific]),
- ACE.access_allowed(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE))
+ ACE.access_allowed(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE)),
]
end
def denied_acl(sid, expected_perms)
[
ACE.access_denied(sid, expected_perms[:specific]),
- ACE.access_denied(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE))
+ ACE.access_denied(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE)),
]
end
@@ -133,7 +133,7 @@ shared_examples_for "a directory resource" do
context "with the recursive option" do
before do
- FileUtils.mkdir(File.join(path, 'red-headed-stepchild'))
+ FileUtils.mkdir(File.join(path, "red-headed-stepchild"))
resource.recursive(true)
resource.run_action(:delete)
end
@@ -152,7 +152,7 @@ shared_context Chef::Resource::Directory do
# deployment strategies more completely.
let(:test_file_dir) do
if windows?
- File.join(ENV['systemdrive'], "test-dir")
+ File.join(ENV["systemdrive"], "test-dir")
else
File.join(CHEF_SPEC_DATA, "test-dir")
end
@@ -163,11 +163,11 @@ shared_context Chef::Resource::Directory do
end
before do
- FileUtils::mkdir_p(test_file_dir)
+ FileUtils.mkdir_p(test_file_dir)
end
after do
- FileUtils::rm_rf(test_file_dir)
+ FileUtils.rm_rf(test_file_dir)
end
after(:each) do
diff --git a/spec/support/shared/functional/execute_resource.rb b/spec/support/shared/functional/execute_resource.rb
new file mode 100644
index 0000000000..4f7cea1cd1
--- /dev/null
+++ b/spec/support/shared/functional/execute_resource.rb
@@ -0,0 +1,150 @@
+#
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+shared_context "a non-admin Windows user" do
+ include Chef::Mixin::ShellOut
+
+ let(:windows_nonadmin_user_domain) { ENV["COMPUTERNAME"] }
+ let(:windows_nonadmin_user_qualified) { "#{windows_nonadmin_user_domain}\\#{windows_nonadmin_user}" }
+ let(:temp_profile_path) { "#{ENV['USERPROFILE']}\\..\\cheftesttempuser" }
+ before do
+ shell_out!("net.exe user /delete #{windows_nonadmin_user}", returns: [0, 2])
+
+ # Supply a profile path when creating a user to avoid an apparent Windows bug where deleting
+ # the user actually creates the profile when it did not immediately exist before executing
+ # net user /delete! For some reason, specifying an explicit path ensures that the path
+ # profile doesn't get created at deletion.
+ shell_out!("net.exe user /add #{windows_nonadmin_user} \"#{windows_nonadmin_user_password}\" /profilepath:#{temp_profile_path}")
+ end
+
+ after do
+ shell_out!("net.exe user /delete #{windows_nonadmin_user}", returns: [0, 2])
+ end
+end
+
+shared_context "alternate user identity" do
+ let(:windows_alternate_user) { "chef%02d%02d%02d" % [Time.now.year % 100, Time.now.month, Time.now.day] }
+ let(:windows_alternate_user_password) { "lj28;fx3T!x,2" }
+ let(:windows_alternate_user_qualified) { "#{ENV['COMPUTERNAME']}\\#{windows_alternate_user}" }
+
+ let(:windows_nonadmin_user) { windows_alternate_user }
+ let(:windows_nonadmin_user_password) { windows_alternate_user_password }
+
+ include_context "a non-admin Windows user"
+end
+
+shared_context "a command that can be executed as an alternate user" do
+ include_context "alternate user identity"
+
+ let(:script_output_dir) { Dir.mktmpdir }
+ let(:script_output_path) { File.join(script_output_dir, make_tmpname("chef_execute_identity_test")) }
+ let(:script_output) { File.read(script_output_path) }
+
+ include Chef::Mixin::ShellOut
+
+ before do
+ shell_out!("icacls \"#{script_output_dir.gsub(/\//, '\\')}\" /grant \"authenticated users:(F)\"")
+ end
+
+ after do
+ File.delete(script_output_path) if File.exists?(script_output_path)
+ Dir.rmdir(script_output_dir) if Dir.exists?(script_output_dir)
+ end
+end
+
+shared_examples_for "an execute resource that supports alternate user identity" do
+ context "when running on Windows", :windows_only, :windows_service_requires_assign_token do
+
+ include_context "a command that can be executed as an alternate user"
+
+ let(:windows_current_user) { ENV["USERNAME"] }
+ let(:windows_current_user_qualified) { "#{ENV['USERDOMAIN'] || ENV['COMPUTERNAME']}\\#{windows_current_user}" }
+ let(:resource_identity_command) { "powershell.exe -noprofile -command \"import-module microsoft.powershell.utility;([Security.Principal.WindowsPrincipal]([Security.Principal.WindowsIdentity]::GetCurrent())).identity.name | out-file -encoding ASCII '#{script_output_path}'\"" }
+
+ let(:execute_resource) do
+ resource.user(windows_alternate_user)
+ resource.password(windows_alternate_user_password)
+ resource.send(resource_command_property, resource_identity_command)
+ resource
+ end
+
+ it "executes the process as an alternate user" do
+ expect(windows_current_user.length).to be > 0
+ expect { execute_resource.run_action(:run) }.not_to raise_error
+ expect(script_output.chomp.length).to be > 0
+ expect(script_output.chomp.downcase).to eq(windows_alternate_user_qualified.downcase)
+ expect(script_output.chomp.downcase).not_to eq(windows_current_user.downcase)
+ expect(script_output.chomp.downcase).not_to eq(windows_current_user_qualified.downcase)
+ end
+
+ let(:windows_alternate_user_password_invalid) { "#{windows_alternate_user_password}x" }
+
+ it "raises an exception if the user's password is invalid" do
+ execute_resource.password(windows_alternate_user_password_invalid)
+ expect { execute_resource.run_action(:run) }.to raise_error(SystemCallError)
+ end
+ end
+end
+
+shared_examples_for "a resource with a guard specifying an alternate user identity" do
+ context "when running on Windows", :windows_only, :windows_service_requires_assign_token do
+ include_context "alternate user identity"
+
+ let(:resource_command_property) { :command }
+
+ let(:powershell_equal_to_alternate_user) { "-eq" }
+ let(:powershell_not_equal_to_alternate_user) { "-ne" }
+ let(:guard_identity_command) { "powershell.exe -noprofile -command \"import-module microsoft.powershell.utility;exit @(392,0)[[int32](([Security.Principal.WindowsPrincipal]([Security.Principal.WindowsIdentity]::GetCurrent())).Identity.Name #{comparison_to_alternate_user} '#{windows_alternate_user_qualified}')]\"" }
+
+ before do
+ resource.guard_interpreter(guard_interpreter_resource)
+ end
+
+ context "when the guard expression is true if the user is alternate and false otherwise" do
+ let(:comparison_to_alternate_user) { powershell_equal_to_alternate_user }
+
+ it "causes the resource to be updated for only_if" do
+ resource.only_if(guard_identity_command, { user: windows_alternate_user, password: windows_alternate_user_password })
+ resource.run_action(:run)
+ expect(resource).to be_updated_by_last_action
+ end
+
+ it "causes the resource to not be updated for not_if" do
+ resource.not_if(guard_identity_command, { user: windows_alternate_user, password: windows_alternate_user_password })
+ resource.run_action(:run)
+ expect(resource).not_to be_updated_by_last_action
+ end
+ end
+
+ context "when the guard expression is false if the user is alternate and true otherwise" do
+ let(:comparison_to_alternate_user) { powershell_not_equal_to_alternate_user }
+
+ it "causes the resource not to be updated for only_if" do
+ resource.only_if(guard_identity_command, { user: windows_alternate_user, password: windows_alternate_user_password })
+ resource.run_action(:run)
+ expect(resource).not_to be_updated_by_last_action
+ end
+
+ it "causes the resource to be updated for not_if" do
+ resource.not_if(guard_identity_command, { user: windows_alternate_user, password: windows_alternate_user_password })
+ resource.run_action(:run)
+ expect(resource).to be_updated_by_last_action
+ end
+ end
+ end
+end
diff --git a/spec/support/shared/functional/file_resource.rb b/spec/support/shared/functional/file_resource.rb
index 3ce3c9c94e..eb7a378db9 100644
--- a/spec/support/shared/functional/file_resource.rb
+++ b/spec/support/shared/functional/file_resource.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -44,7 +44,6 @@ shared_context "deploying via destdir" do
end
end
-
shared_examples_for "a file with the wrong content" do
before do
# Assert starting state is as expected
@@ -103,7 +102,7 @@ shared_examples_for "a file with the wrong content" do
end
it "raises an exception" do
- expect{ resource.run_action(:create) }.to raise_error(Chef::Exceptions::ChecksumMismatch)
+ expect { resource.run_action(:create) }.to raise_error(Chef::Exceptions::ChecksumMismatch)
end
end
end
@@ -144,7 +143,7 @@ shared_examples_for "a file with the wrong content" do
end
context "when diff is enabled" do
- describe 'sensitive attribute' do
+ describe "sensitive attribute" do
context "should be insensitive by default" do
it { expect(resource.sensitive).to(be_falsey) }
end
@@ -165,7 +164,7 @@ shared_examples_for "a file with the wrong content" do
end
it "should suppress the diff" do
- expect(resource.diff).to(include('suppressed sensitive resource'))
+ expect(resource.diff).to(include("suppressed sensitive resource"))
expect(reporter_messages[1]).to eq("suppressed sensitive resource")
end
@@ -308,14 +307,14 @@ shared_examples_for "a file resource" do
describe "when setting atomic_update" do
it "booleans should work" do
- expect {resource.atomic_update(true)}.not_to raise_error
- expect {resource.atomic_update(false)}.not_to raise_error
+ expect { resource.atomic_update(true) }.not_to raise_error
+ expect { resource.atomic_update(false) }.not_to raise_error
end
it "anything else should raise an error" do
- expect {resource.atomic_update(:copy)}.to raise_error(ArgumentError)
- expect {resource.atomic_update(:move)}.to raise_error(ArgumentError)
- expect {resource.atomic_update(958)}.to raise_error(ArgumentError)
+ expect { resource.atomic_update(:copy) }.to raise_error(ArgumentError)
+ expect { resource.atomic_update(:move) }.to raise_error(ArgumentError)
+ expect { resource.atomic_update(958) }.to raise_error(ArgumentError)
end
end
@@ -351,13 +350,13 @@ shared_examples_for "file resource not pointing to a real file" do
describe "when force_unlink is set to false" do
it ":create raises an error" do
- expect {resource.run_action(:create) }.to raise_error(Chef::Exceptions::FileTypeMismatch)
+ expect { resource.run_action(:create) }.to raise_error(Chef::Exceptions::FileTypeMismatch)
end
end
describe "when force_unlink is not set (default)" do
it ":create raises an error" do
- expect {resource.run_action(:create) }.to raise_error(Chef::Exceptions::FileTypeMismatch)
+ expect { resource.run_action(:create) }.to raise_error(Chef::Exceptions::FileTypeMismatch)
end
end
end
@@ -401,10 +400,9 @@ shared_examples_for "a configured file resource" do
end
context "when the target file is a symlink", :not_supported_on_win2k3 do
- let(:symlink_target) {
+ let(:symlink_target) do
File.join(CHEF_SPEC_DATA, "file-test-target")
- }
-
+ end
describe "when configured not to manage symlink's target" do
before(:each) do
@@ -574,7 +572,6 @@ shared_examples_for "a configured file resource" do
File.open(path, "wb") { |f| f.write(expected_content) }
end
-
include_context "setup broken permissions"
include_examples "a securable resource with existing target"
@@ -721,7 +718,7 @@ shared_examples_for "a configured file resource" do
it_behaves_like "file resource not pointing to a real file"
end
- context "when the target file is a blockdev",:unix_only, :requires_root, :not_supported_on_solaris do
+ context "when the target file is a blockdev", :unix_only, :requires_root, :not_supported_on_solaris do
include Chef::Mixin::ShellOut
let(:path) do
File.join(CHEF_SPEC_DATA, "testdev")
@@ -739,7 +736,7 @@ shared_examples_for "a configured file resource" do
it_behaves_like "file resource not pointing to a real file"
end
- context "when the target file is a chardev",:unix_only, :requires_root, :not_supported_on_solaris do
+ context "when the target file is a chardev", :unix_only, :requires_root, :not_supported_on_solaris do
include Chef::Mixin::ShellOut
let(:path) do
File.join(CHEF_SPEC_DATA, "testdev")
@@ -757,7 +754,7 @@ shared_examples_for "a configured file resource" do
it_behaves_like "file resource not pointing to a real file"
end
- context "when the target file is a pipe",:unix_only do
+ context "when the target file is a pipe", :unix_only do
include Chef::Mixin::ShellOut
let(:path) do
File.join(CHEF_SPEC_DATA, "testpipe")
@@ -775,8 +772,8 @@ shared_examples_for "a configured file resource" do
it_behaves_like "file resource not pointing to a real file"
end
- context "when the target file is a socket",:unix_only do
- require 'socket'
+ context "when the target file is a socket", :unix_only do
+ require "socket"
# It turns out that the path to a socket can have at most ~104
# bytes. Therefore we are creating our sockets in tmpdir so that
@@ -784,11 +781,11 @@ shared_examples_for "a configured file resource" do
let(:test_socket_dir) { File.join(Dir.tmpdir, "sockets") }
before do
- FileUtils::mkdir_p(test_socket_dir)
+ FileUtils.mkdir_p(test_socket_dir)
end
after do
- FileUtils::rm_rf(test_socket_dir)
+ FileUtils.rm_rf(test_socket_dir)
end
let(:path) do
@@ -823,9 +820,9 @@ shared_examples_for "a configured file resource" do
end
describe "when path is specified with windows separator", :windows_only do
- let(:path) {
+ let(:path) do
File.join(test_file_dir, make_tmpname(file_base)).gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR)
- }
+ end
before do
@notified_resource = Chef::Resource.new("punk", resource.run_context)
@@ -1018,16 +1015,16 @@ shared_examples_for "a configured file resource" do
end
-shared_context Chef::Resource::File do
+shared_context Chef::Resource::File do
if windows?
- require 'chef/win32/file'
+ require "chef/win32/file"
end
# We create the files in a different directory than tmp to exercise
# different file deployment strategies more completely.
let(:test_file_dir) do
if windows?
- File.join(ENV['systemdrive'], "test-dir")
+ File.join(ENV["systemdrive"], "test-dir")
else
File.join(CHEF_SPEC_DATA, "test-dir")
end
@@ -1038,7 +1035,8 @@ shared_context Chef::Resource::File do
end
before do
- FileUtils::mkdir_p(test_file_dir)
+ FileUtils.rm_rf(test_file_dir)
+ FileUtils.mkdir_p(test_file_dir)
end
after(:each) do
@@ -1047,6 +1045,6 @@ shared_context Chef::Resource::File do
end
after do
- FileUtils::rm_rf(test_file_dir)
+ FileUtils.rm_rf(test_file_dir)
end
end
diff --git a/spec/support/shared/functional/http.rb b/spec/support/shared/functional/http.rb
index 963fbf1c5b..76faaaed47 100644
--- a/spec/support/shared/functional/http.rb
+++ b/spec/support/shared/functional/http.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,11 +22,11 @@
module ChefHTTPShared
def nyan_uncompressed_filename
- File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png')
+ File.join(CHEF_SPEC_DATA, "remote_file", "nyan_cat.png")
end
def nyan_compressed_filename
- File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png.gz')
+ File.join(CHEF_SPEC_DATA, "remote_file", "nyan_cat.png.gz")
end
def binread(file)
@@ -37,7 +37,7 @@ module ChefHTTPShared
content
end
- def start_tiny_server(server_opts={})
+ def start_tiny_server(server_opts = {})
nyan_uncompressed_size = File::Stat.new(nyan_uncompressed_filename).size
nyan_compressed_size = File::Stat.new(nyan_compressed_filename).size
@@ -52,27 +52,27 @@ module ChefHTTPShared
# just a normal file
# (expected_content should be uncompressed)
- @api.get("/nyan_cat.png", 200) {
+ @api.get("/nyan_cat.png", 200) do
File.open(nyan_uncompressed_filename, "rb") do |f|
f.read
end
- }
+ end
# this ends in .gz, we do not uncompress it and drop it on the filesystem as a .gz file (the internet often lies)
# (expected_content should be compressed)
- @api.get("/nyan_cat.png.gz", 200, nil, { 'Content-Type' => 'application/gzip', 'Content-Encoding' => 'gzip' } ) {
+ @api.get("/nyan_cat.png.gz", 200, nil, { "Content-Type" => "application/gzip", "Content-Encoding" => "gzip" } ) do
File.open(nyan_compressed_filename, "rb") do |f|
f.read
end
- }
+ end
# this is an uncompressed file that was compressed by some mod_gzip-ish webserver thingy, so we will expand it
# (expected_content should be uncompressed)
- @api.get("/nyan_cat_compressed.png", 200, nil, { 'Content-Type' => 'application/gzip', 'Content-Encoding' => 'gzip' } ) {
+ @api.get("/nyan_cat_compressed.png", 200, nil, { "Content-Type" => "application/gzip", "Content-Encoding" => "gzip" } ) do
File.open(nyan_compressed_filename, "rb") do |f|
f.read
end
- }
+ end
#
# endpoints that set Content-Length correctly
@@ -81,26 +81,26 @@ module ChefHTTPShared
# (expected_content should be uncompressed)
@api.get("/nyan_cat_content_length.png", 200, nil,
{
- 'Content-Length' => nyan_uncompressed_size.to_s,
+ "Content-Length" => nyan_uncompressed_size.to_s,
}
- ) {
+ ) do
File.open(nyan_uncompressed_filename, "rb") do |f|
f.read
end
- }
+ end
# (expected_content should be uncompressed)
@api.get("/nyan_cat_content_length_compressed.png", 200, nil,
{
- 'Content-Length' => nyan_compressed_size.to_s,
- 'Content-Type' => 'application/gzip',
- 'Content-Encoding' => 'gzip'
+ "Content-Length" => nyan_compressed_size.to_s,
+ "Content-Type" => "application/gzip",
+ "Content-Encoding" => "gzip",
}
- ) {
+ ) do
File.open(nyan_compressed_filename, "rb") do |f|
f.read
end
- }
+ end
#
# endpoints that simulate truncated downloads (bad content-length header)
@@ -109,26 +109,26 @@ module ChefHTTPShared
# (expected_content should be uncompressed)
@api.get("/nyan_cat_truncated.png", 200, nil,
{
- 'Content-Length' => (nyan_uncompressed_size + 1).to_s,
+ "Content-Length" => (nyan_uncompressed_size + 1).to_s,
}
- ) {
+ ) do
File.open(nyan_uncompressed_filename, "rb") do |f|
f.read
end
- }
+ end
# (expected_content should be uncompressed)
@api.get("/nyan_cat_truncated_compressed.png", 200, nil,
{
- 'Content-Length' => (nyan_compressed_size + 1).to_s,
- 'Content-Type' => 'application/gzip',
- 'Content-Encoding' => 'gzip'
+ "Content-Length" => (nyan_compressed_size + 1).to_s,
+ "Content-Type" => "application/gzip",
+ "Content-Encoding" => "gzip",
}
- ) {
+ ) do
File.open(nyan_compressed_filename, "rb") do |f|
f.read
end
- }
+ end
#
# in the presence of a transfer-encoding header, we must ignore the content-length (this bad content-length should work)
@@ -137,32 +137,31 @@ module ChefHTTPShared
# (expected_content should be uncompressed)
@api.get("/nyan_cat_transfer_encoding.png", 200, nil,
{
- 'Content-Length' => (nyan_uncompressed_size + 1).to_s,
- 'Transfer-Encoding' => 'anything',
+ "Content-Length" => (nyan_uncompressed_size + 1).to_s,
+ "Transfer-Encoding" => "anything",
}
- ) {
+ ) do
File.open(nyan_uncompressed_filename, "rb") do |f|
f.read
end
- }
+ end
#
# 403 with a Content-Length
#
- @api.get('/forbidden', 403, 'Forbidden',
+ @api.get("/forbidden", 403, "Forbidden",
{
- 'Content-Length' => 'Forbidden'.bytesize.to_s
+ "Content-Length" => "Forbidden".bytesize.to_s,
}
)
- @api.post('/posty', 200, 'Hi!')
+ @api.post("/posty", 200, "Hi!")
#
# 400 with an error
#
- @api.get('/bad_request', 400, '{ "error": [ "Your request is just terrible." ] }')
- @api.post('/bad_request', 400, '{ "error": [ "Your request is just terrible." ] }')
-
+ @api.get("/bad_request", 400, '{ "error": [ "Your request is just terrible." ] }')
+ @api.post("/bad_request", 400, '{ "error": [ "Your request is just terrible." ] }')
end
def stop_tiny_server
@@ -175,14 +174,14 @@ end
shared_examples_for "downloading all the things" do
describe "when downloading a simple uncompressed file" do
- let(:source) { 'http://localhost:9000/nyan_cat.png' }
+ let(:source) { "http://localhost:9000/nyan_cat.png" }
let(:expected_content) { binread(nyan_uncompressed_filename) }
it_behaves_like "downloads requests correctly"
end
describe "when downloading a compressed file that should be left compressed" do
- let(:source) { 'http://localhost:9000/nyan_cat.png.gz' }
+ let(:source) { "http://localhost:9000/nyan_cat.png.gz" }
let(:expected_content) { binread(nyan_compressed_filename) }
# its the callers responsibility to disable_gzip when downloading a .gz url
@@ -192,57 +191,57 @@ shared_examples_for "downloading all the things" do
end
describe "when downloading a file that has been compressed by the webserver" do
- let(:source) { 'http://localhost:9000/nyan_cat_compressed.png' }
+ let(:source) { "http://localhost:9000/nyan_cat_compressed.png" }
let(:expected_content) { binread(nyan_uncompressed_filename) }
it_behaves_like "downloads requests correctly"
end
describe "when downloading an uncompressed file with a correct content_length" do
- let(:source) { 'http://localhost:9000/nyan_cat_content_length.png' }
+ let(:source) { "http://localhost:9000/nyan_cat_content_length.png" }
let(:expected_content) { binread(nyan_uncompressed_filename) }
it_behaves_like "downloads requests correctly"
end
describe "when downloading a file that has been compressed by the webserver with a correct content_length" do
- let(:source) { 'http://localhost:9000/nyan_cat_content_length_compressed.png' }
+ let(:source) { "http://localhost:9000/nyan_cat_content_length_compressed.png" }
let(:expected_content) { binread(nyan_uncompressed_filename) }
it_behaves_like "downloads requests correctly"
end
describe "when downloading an uncompressed file that is truncated" do
- let(:source) { 'http://localhost:9000/nyan_cat_truncated.png' }
+ let(:source) { "http://localhost:9000/nyan_cat_truncated.png" }
let(:expected_content) { binread(nyan_uncompressed_filename) }
it_behaves_like "validates content length and throws an exception"
end
describe "when downloading a file that has been compressed by the webserver that is truncated" do
- let(:source) { 'http://localhost:9000/nyan_cat_truncated_compressed.png' }
+ let(:source) { "http://localhost:9000/nyan_cat_truncated_compressed.png" }
let(:expected_content) { binread(nyan_uncompressed_filename) }
it_behaves_like "validates content length and throws an exception"
end
describe "when downloading a file that has transfer encoding set with a bad content length that should be ignored" do
- let(:source) { 'http://localhost:9000/nyan_cat_transfer_encoding.png' }
+ let(:source) { "http://localhost:9000/nyan_cat_transfer_encoding.png" }
let(:expected_content) { binread(nyan_uncompressed_filename) }
it_behaves_like "downloads requests correctly"
end
describe "when downloading an endpoint that 403s" do
- let(:source) { 'http://localhost:9000/forbidden' }
+ let(:source) { "http://localhost:9000/forbidden" }
it_behaves_like "an endpoint that 403s"
end
describe "when downloading an endpoint that 403s" do
- let(:source) { 'http://localhost:9000/nyan_cat_content_length_compressed.png' }
+ let(:source) { "http://localhost:9000/nyan_cat_content_length_compressed.png" }
let(:expected_content) { binread(nyan_uncompressed_filename) }
- let(:source2) { 'http://localhost:9000/forbidden' }
+ let(:source2) { "http://localhost:9000/forbidden" }
it_behaves_like "a 403 after a successful request when reusing the request object"
end
diff --git a/spec/support/shared/functional/knife.rb b/spec/support/shared/functional/knife.rb
index e96de7c27a..694d0de5d1 100644
--- a/spec/support/shared/functional/knife.rb
+++ b/spec/support/shared/functional/knife.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: AJ Christensen (<aj@junglist.gen.nz>)
-# Author:: Ho-Sheng Hsiao (<hosh@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/spec/support/shared/functional/securable_resource.rb b/spec/support/shared/functional/securable_resource.rb
index b3c32356aa..95f4f4bd49 100644
--- a/spec/support/shared/functional/securable_resource.rb
+++ b/spec/support/shared/functional/securable_resource.rb
@@ -1,8 +1,8 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Author:: Mark Mzyk (<mmzyk@opscode.com>)
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Author:: Mark Mzyk (<mmzyk@chef.io>)
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
# limitations under the License.
#
-require 'etc'
-require 'functional/resource/base'
+require "etc"
+require "functional/resource/base"
shared_context "setup correct permissions" do
if windows?
@@ -38,9 +38,9 @@ shared_context "setup correct permissions" do
# Root only context.
before :each, :unix_only, :requires_root do
if ohai[:platform] == "aix"
- File.chown(Etc.getpwnam('guest').uid, 1337, path)
+ File.chown(Etc.getpwnam("guest").uid, 1337, path)
else
- File.chown(Etc.getpwnam('nobody').uid, 1337, path)
+ File.chown(Etc.getpwnam("nobody").uid, 1337, path)
end
end
@@ -81,7 +81,7 @@ shared_context "use Windows permissions", :windows_only do
SID ||= Chef::ReservedNames::Win32::Security::SID
ACE ||= Chef::ReservedNames::Win32::Security::ACE
ACL ||= Chef::ReservedNames::Win32::Security::ACL
- SecurableObject ||= Chef::ReservedNames::Win32::Security::SecurableObject
+ SecurableObject ||= Chef::ReservedNames::Win32::Security::SecurableObject # rubocop:disable Style/ConstantName
end
def get_security_descriptor(path)
@@ -111,36 +111,36 @@ shared_context "use Windows permissions", :windows_only do
let(:expected_read_execute_perms) do
{
:generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE,
- :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE,
}
end
let(:expected_write_perms) do
{
:generic => Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE,
- :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE,
}
end
let(:expected_modify_perms) do
{
:generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::DELETE,
- :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::DELETE
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::DELETE,
}
end
let(:expected_full_control_perms) do
{
:generic => Chef::ReservedNames::Win32::API::Security::GENERIC_ALL,
- :specific => Chef::ReservedNames::Win32::API::Security::FILE_ALL_ACCESS
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_ALL_ACCESS,
}
end
RSpec::Matchers.define :have_expected_properties do |mask, type, flags|
match do |ace|
- ace.mask == mask
- ace.type == type
- ace.flags == flags
+ ace.mask == mask &&
+ ace.type == type &&
+ ace.flags == flags
end
end
@@ -155,9 +155,9 @@ shared_examples_for "a securable resource with existing target" do
context "on Unix", :unix_only do
if ohai[:platform] == "aix"
- let(:expected_user_name) { 'guest' }
+ let(:expected_user_name) { "guest" }
else
- let(:expected_user_name) { 'nobody' }
+ let(:expected_user_name) { "nobody" }
end
let(:expected_uid) { Etc.getpwnam(expected_user_name).uid }
let(:desired_gid) { 1337 }
@@ -197,7 +197,7 @@ shared_examples_for "a securable resource with existing target" do
describe "when setting the permissions from octal given as a String" do
before do
- @mode_string = '776'
+ @mode_string = "776"
resource.mode @mode_string
resource.run_action(:create)
end
@@ -258,7 +258,7 @@ shared_examples_for "a securable resource with existing target" do
describe "when setting group" do
before do
- resource.group('Administrators')
+ resource.group("Administrators")
resource.run_action(:create)
end
@@ -273,8 +273,8 @@ shared_examples_for "a securable resource with existing target" do
describe "when setting rights and deny_rights" do
before do
- resource.deny_rights(:modify, 'Guest')
- resource.rights(:read, 'Guest')
+ resource.deny_rights(:modify, "Guest")
+ resource.rights(:read, "Guest")
resource.run_action(:create)
end
@@ -303,13 +303,13 @@ shared_examples_for "a securable resource without existing target" do
end
it "sets owner when owner is specified" do
- resource.owner 'Guest'
+ resource.owner "Guest"
resource.run_action(:create)
expect(descriptor.owner).to eq(SID.Guest)
end
it "fails to set owner when owner has invalid characters" do
- expect { resource.owner 'Lance "The Nose" Glindenberry III' }.to raise_error#(Chef::Exceptions::ValidationFailed)
+ expect { resource.owner 'Lance "The Nose" Glindenberry III' }.to raise_error(Chef::Exceptions::ValidationFailed)
end
it "sets owner when owner is specified with a \\" do
@@ -322,7 +322,7 @@ shared_examples_for "a securable resource without existing target" do
arbitrary_non_default_owner = SID.Guest
expect(arbitrary_non_default_owner).not_to eq(SID.default_security_object_owner)
- resource.owner 'Guest' # Change to arbitrary_non_default_owner once issue #1508 is fixed
+ resource.owner "Guest" # Change to arbitrary_non_default_owner once issue #1508 is fixed
resource.run_action(:create)
expect(descriptor.owner).to eq(arbitrary_non_default_owner)
@@ -340,7 +340,7 @@ shared_examples_for "a securable resource without existing target" do
end
it "sets group when group is specified" do
- resource.group 'Everyone'
+ resource.group "Everyone"
resource.run_action(:create)
expect(descriptor.group).to eq(SID.Everyone)
end
@@ -353,7 +353,7 @@ shared_examples_for "a securable resource without existing target" do
arbitrary_non_default_group = SID.Everyone
expect(arbitrary_non_default_group).not_to eq(SID.default_security_object_group)
- resource.group 'Everyone' # Change to arbitrary_non_default_group once issue #1508 is fixed
+ resource.group "Everyone" # Change to arbitrary_non_default_group once issue #1508 is fixed
resource.run_action(:create)
expect(descriptor.group).to eq(arbitrary_non_default_group)
@@ -366,45 +366,45 @@ shared_examples_for "a securable resource without existing target" do
describe "with rights and deny_rights attributes" do
it "correctly sets :read rights" do
- resource.rights(:read, 'Guest')
+ resource.rights(:read, "Guest")
resource.run_action(:create)
expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_perms))
end
it "correctly sets :read_execute rights" do
- resource.rights(:read_execute, 'Guest')
+ resource.rights(:read_execute, "Guest")
resource.run_action(:create)
expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_execute_perms))
end
it "correctly sets :write rights" do
- resource.rights(:write, 'Guest')
+ resource.rights(:write, "Guest")
resource.run_action(:create)
expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_write_perms))
end
it "correctly sets :modify rights" do
- resource.rights(:modify, 'Guest')
+ resource.rights(:modify, "Guest")
resource.run_action(:create)
expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_modify_perms))
end
it "correctly sets :full_control rights" do
- resource.rights(:full_control, 'Guest')
+ resource.rights(:full_control, "Guest")
resource.run_action(:create)
expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_full_control_perms))
end
it "correctly sets deny_rights" do
# deny is an ACE with full rights, but is a deny type ace, not an allow type
- resource.deny_rights(:full_control, 'Guest')
+ resource.deny_rights(:full_control, "Guest")
resource.run_action(:create)
expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_full_control_perms))
end
it "Sets multiple rights" do
- resource.rights(:read, 'Everyone')
- resource.rights(:modify, 'Guest')
+ resource.rights(:read, "Everyone")
+ resource.rights(:modify, "Guest")
resource.run_action(:create)
expect(explicit_aces).to eq(
@@ -414,8 +414,8 @@ shared_examples_for "a securable resource without existing target" do
end
it "Sets deny_rights ahead of rights" do
- resource.rights(:read, 'Everyone')
- resource.deny_rights(:modify, 'Guest')
+ resource.rights(:read, "Everyone")
+ resource.deny_rights(:modify, "Guest")
resource.run_action(:create)
expect(explicit_aces).to eq(
@@ -425,8 +425,8 @@ shared_examples_for "a securable resource without existing target" do
end
it "Sets deny_rights ahead of rights when specified in reverse order" do
- resource.deny_rights(:modify, 'Guest')
- resource.rights(:read, 'Everyone')
+ resource.deny_rights(:modify, "Guest")
+ resource.rights(:read, "Everyone")
resource.run_action(:create)
expect(explicit_aces).to eq(
@@ -439,15 +439,15 @@ shared_examples_for "a securable resource without existing target" do
context "with a mode attribute" do
if windows?
- Security ||= Chef::ReservedNames::Win32::API::Security
+ Security ||= Chef::ReservedNames::Win32::API::Security # rubocop:disable Style/ConstantName
end
it "respects mode in string form as an octal number" do
#on windows, mode cannot modify owner and/or group permissons
#unless the owner and/or group as appropriate is specified
- resource.mode '400'
- resource.owner 'Guest'
- resource.group 'Everyone'
+ resource.mode "400"
+ resource.owner "Guest"
+ resource.group "Everyone"
resource.run_action(:create)
expect(explicit_aces).to eq([ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ) ])
@@ -455,7 +455,7 @@ shared_examples_for "a securable resource without existing target" do
it "respects mode in numeric form as a ruby-interpreted octal" do
resource.mode 0700
- resource.owner 'Guest'
+ resource.owner "Guest"
resource.run_action(:create)
expect(explicit_aces).to eq([ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_WRITE | Security::FILE_GENERIC_EXECUTE | Security::DELETE) ])
@@ -463,31 +463,31 @@ shared_examples_for "a securable resource without existing target" do
it "respects the owner, group and everyone bits of mode" do
resource.mode 0754
- resource.owner 'Guest'
- resource.group 'Administrators'
+ resource.owner "Guest"
+ resource.group "Administrators"
resource.run_action(:create)
expect(explicit_aces).to eq([
ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_WRITE | Security::FILE_GENERIC_EXECUTE | Security::DELETE),
ACE.access_allowed(SID.Administrators, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_EXECUTE),
- ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_READ)
+ ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_READ),
])
end
it "respects the individual read, write and execute bits of mode" do
resource.mode 0421
- resource.owner 'Guest'
- resource.group 'Administrators'
+ resource.owner "Guest"
+ resource.group "Administrators"
resource.run_action(:create)
expect(explicit_aces).to eq([
ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ),
ACE.access_allowed(SID.Administrators, Security::FILE_GENERIC_WRITE | Security::DELETE),
- ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_EXECUTE)
+ ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_EXECUTE),
])
end
- it 'warns when mode tries to set owner bits but owner is not specified' do
+ it "warns when mode tries to set owner bits but owner is not specified" do
@warn = []
allow(Chef::Log).to receive(:warn) { |msg| @warn << msg }
@@ -497,7 +497,7 @@ shared_examples_for "a securable resource without existing target" do
expect(@warn.include?("Mode 400 includes bits for the owner, but owner is not specified")).to be_truthy
end
- it 'warns when mode tries to set group bits but group is not specified' do
+ it "warns when mode tries to set group bits but group is not specified" do
@warn = []
allow(Chef::Log).to receive(:warn) { |msg| @warn << msg }
@@ -511,11 +511,11 @@ shared_examples_for "a securable resource without existing target" do
it "does not inherit aces if inherits is set to false" do
# We need at least one ACE if we're creating a securable without
# inheritance
- resource.rights(:full_control, 'Administrators')
+ resource.rights(:full_control, "Administrators")
resource.inherits(false)
resource.run_action(:create)
- descriptor.dacl.each do | ace |
+ descriptor.dacl.each do |ace|
expect(ace.inherited?).to eq(false)
end
end
diff --git a/spec/support/shared/functional/securable_resource_with_reporting.rb b/spec/support/shared/functional/securable_resource_with_reporting.rb
index 3176ebba0d..0bec29783a 100644
--- a/spec/support/shared/functional/securable_resource_with_reporting.rb
+++ b/spec/support/shared/functional/securable_resource_with_reporting.rb
@@ -1,5 +1,5 @@
-require 'functional/resource/base'
+require "functional/resource/base"
ALL_EXPANDED_PERMISSIONS = ["generic read",
"generic write",
@@ -21,7 +21,6 @@ ALL_EXPANDED_PERMISSIONS = ["generic read",
"read attributes",
"write attributes"]
-
shared_examples_for "a securable resource with reporting" do
include_context "diff disabled"
@@ -76,9 +75,9 @@ shared_examples_for "a securable resource with reporting" do
# TODO/bug: duplicated from the "securable resource" tests
if ohai[:platform] == "aix"
- let(:expected_user_name) { 'guest' }
+ let(:expected_user_name) { "guest" }
else
- let(:expected_user_name) { 'nobody' }
+ let(:expected_user_name) { "nobody" }
end
before do
@@ -96,9 +95,9 @@ shared_examples_for "a securable resource with reporting" do
# TODO: duplicated from "securable resource"
if ohai[:platform] == "aix"
- let(:expected_user_name) { 'guest' }
+ let(:expected_user_name) { "guest" }
else
- let(:expected_user_name) { 'nobody' }
+ let(:expected_user_name) { "nobody" }
end
let(:expected_uid) { Etc.getpwnam(expected_user_name).uid }
let(:desired_gid) { 1337 }
@@ -273,7 +272,6 @@ shared_examples_for "a securable resource with reporting" do
# Windows reporting data should look like this (+/- ish):
# { "owner" => "bob", "checksum" => "ffff", "access control" => { "bob" => { "permissions" => ["perm1", "perm2", ...], "flags" => [] }}}
-
before do
resource.action(:create)
end
@@ -293,17 +291,16 @@ shared_examples_for "a securable resource with reporting" do
resource.run_action(:create)
# TODO: most stable way to specify?
expect(resource.owner).to eq(etc.getpwuid(process.uid).name)
- expect(resource.state[:expanded_rights]).to eq({ "CURRENTUSER" => { "permissions" => ALL_EXPANDED_PERMISSIONS, "flags" => [] }})
+ expect(resource.state[:expanded_rights]).to eq({ "CURRENTUSER" => { "permissions" => ALL_EXPANDED_PERMISSIONS, "flags" => [] } })
expect(resource.state[:expanded_deny_rights]).to eq({})
expect(resource.state[:inherits]).to be_truthy
end
end
-
- context "and owner is specified with a string (username) in new_resource" do
+ context "and owner is specified with a string (username) in new_resource" do
# TODO/bug: duplicated from the "securable resource" tests
- let(:expected_user_name) { 'Guest' }
+ let(:expected_user_name) { "Guest" }
before do
resource.owner(expected_user_name)
@@ -392,7 +389,6 @@ shared_examples_for "a securable resource with reporting" do
end
end
-
end
end
end
diff --git a/spec/support/shared/functional/win32_service.rb b/spec/support/shared/functional/win32_service.rb
index 2ee1a8ad88..3199caa34f 100644
--- a/spec/support/shared/functional/win32_service.rb
+++ b/spec/support/shared/functional/win32_service.rb
@@ -1,5 +1,5 @@
-require 'chef/application/windows_service_manager'
+require "chef/application/windows_service_manager"
shared_context "using Win32::Service" do
# Some helper methods.
@@ -23,9 +23,7 @@ shared_context "using Win32::Service" do
# We can only uninstall when the service is stopped.
if test_service_state != "stopped"
::Win32::Service.send("stop", "spec-service")
- while test_service_state != "stopped"
- sleep 1
- end
+ sleep 1 while test_service_state != "stopped"
end
::Win32::Service.delete("spec-service")
@@ -35,27 +33,25 @@ shared_context "using Win32::Service" do
if File.exists?(test_service_file)
File.delete(test_service_file)
end
-
end
-
# Definition for the test-service
- let(:test_service) {
+ let(:test_service) do
{
:service_name => "spec-service",
:service_display_name => "Spec Test Service",
:service_description => "Service for testing Chef::Application::WindowsServiceManager.",
- :service_file_path => File.expand_path(File.join(File.dirname(__FILE__), '../../platforms/win32/spec_service.rb')),
- :delayed_start => true
+ :service_file_path => File.expand_path(File.join(File.dirname(__FILE__), "../../platforms/win32/spec_service.rb")),
+ :delayed_start => true,
}
- }
+ end
# Test service creates a file for us to verify that it is running.
# Since our test service is running as Local System we should look
# for the file it creates under SYSTEM temp directory
- let(:test_service_file) {
+ let(:test_service_file) do
"#{ENV['SystemDrive']}\\windows\\temp\\spec_service_file"
- }
+ end
end
diff --git a/spec/support/shared/functional/windows_script.rb b/spec/support/shared/functional/windows_script.rb
index d84c06c86b..e5ac0741bd 100644
--- a/spec/support/shared/functional/windows_script.rb
+++ b/spec/support/shared/functional/windows_script.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,15 +19,15 @@
# Shared context used by both Powershell and Batch script provider
# tests.
-require 'chef/platform/query_helpers'
+require "chef/platform/query_helpers"
shared_context Chef::Resource::WindowsScript do
before(:all) do
@ohai_reader = Ohai::System.new
- @ohai_reader.all_plugins(["platform", "kernel"])
+ @ohai_reader.all_plugins(%w{platform kernel})
new_node = Chef::Node.new
- new_node.consume_external_attrs(@ohai_reader.data,{})
+ new_node.consume_external_attrs(@ohai_reader.data, {})
events = Chef::EventDispatch::Dispatcher.new
@@ -46,21 +46,17 @@ shared_context Chef::Resource::WindowsScript do
File.delete(script_output_path) if File.exists?(script_output_path)
end
- let!(:resource) do
- Chef::Resource::WindowsScript::Batch.new("Batch resource functional test", @run_context)
- end
-
shared_examples_for "a script resource with architecture attribute" do
context "with the given architecture attribute value" do
let(:expected_architecture) do
if resource_architecture
expected_architecture = resource_architecture
else
- expected_architecture = @ohai_reader.data['kernel']['machine'].to_sym
+ expected_architecture = @ohai_reader.data["kernel"]["machine"].to_sym
end
end
let(:expected_architecture_output) do
- expected_architecture == :i386 ? 'X86' : 'AMD64'
+ expected_architecture == :i386 ? "X86" : "AMD64"
end
let(:guard_script_suffix) do
"guard"
@@ -99,7 +95,7 @@ shared_context Chef::Resource::WindowsScript do
it "executes a 64-bit guard", :windows64_only do
resource.only_if resource_guard_command, :architecture => guard_architecture
resource.run_action(:run)
- expect(get_guard_process_architecture).to eq('amd64')
+ expect(get_guard_process_architecture).to eq("amd64")
end
end
@@ -108,7 +104,7 @@ shared_context Chef::Resource::WindowsScript do
it "executes a 32-bit guard" do
resource.only_if resource_guard_command, :architecture => guard_architecture
resource.run_action(:run)
- expect(get_guard_process_architecture).to eq('x86')
+ expect(get_guard_process_architecture).to eq("x86")
end
end
@@ -116,7 +112,7 @@ shared_context Chef::Resource::WindowsScript do
let (:guard_architecture) { :i386 }
it "raises an error" do
resource.only_if resource_guard_command, :architecture => guard_architecture
- expect{ resource.run_action(:run) }.to raise_error(
+ expect { resource.run_action(:run) }.to raise_error(
Chef::Exceptions::Win32ArchitectureIncorrect,
/cannot execute script with requested architecture 'i386' on Windows Nano Server/)
end
@@ -125,6 +121,55 @@ shared_context Chef::Resource::WindowsScript do
end
shared_examples_for "a Windows script running on Windows" do
+ shared_examples_for "a script that cannot be accessed by other users if they are not administrators" do
+ include Chef::Mixin::ShellOut
+
+ let(:script_provider) { resource.provider_for_action(:run) }
+ let(:script_file) { script_provider.script_file }
+ let(:script_file_path) { script_file.to_path }
+
+ let(:read_access_denied_command) { "::File.read('#{script_file_path}')" }
+ let(:modify_access_denied_command) { "::File.write('#{script_file_path}', 'stuff')" }
+ let(:delete_access_denied_command) { "::File.delete('#{script_file_path}')" }
+ let(:access_denied_sentinel) { 7334 }
+ let(:access_allowed_sentinel) { 1586 }
+ let(:access_command_invalid) { 0 }
+
+ let(:ruby_interpreter_path) { RbConfig.ruby }
+ let(:ruby_command_template) { "require 'FileUtils';status = 0;begin; #{ruby_access_command};rescue Exception => e; puts e; status = e.class == Errno::EACCES ? #{access_denied_sentinel} : #{access_allowed_sentinel};end;exit status" }
+ let(:command_template) { "set BUNDLE_GEMFILE=&#{ruby_interpreter_path} -e \"#{ruby_command_template}\"" }
+ let(:access_command) { command_template }
+
+ before do
+ expect(script_provider).to receive(:unlink_script_file)
+ resource.code("echo hi")
+ script_provider.action_run
+ end
+
+ after do
+ script_file.close! if script_file
+ ::File.delete(script_file.to_path) if script_file && ::File.exists?(script_file.to_path)
+ end
+
+ include_context "alternate user identity"
+
+ shared_examples_for "a script whose file system location cannot be accessed by other non-admin users" do
+ let(:ruby_access_command) { file_access_command }
+ it "generates a script in the local file system that prevents read access to other non-admin users" do
+ shell_out!(access_command, { user: windows_nonadmin_user, password: windows_nonadmin_user_password, returns: [access_denied_sentinel] })
+ end
+ end
+
+ context "when a different non-admin user attempts write (modify) to access the script" do
+ let(:file_access_command) { modify_access_denied_command }
+ it_behaves_like "a script whose file system location cannot be accessed by other non-admin users"
+ end
+
+ context "when a different non-admin user attempts write (delete) to access the script" do
+ let(:file_access_command) { delete_access_denied_command }
+ it_behaves_like "a script whose file system location cannot be accessed by other non-admin users"
+ end
+ end
describe "when the run action is invoked on Windows" do
it "executes the script code" do
@@ -132,14 +177,29 @@ shared_context Chef::Resource::WindowsScript do
resource.returns(0)
resource.run_action(:run)
end
+
+ context "the script is executed with the identity of the current user", :windows_service_requires_assign_token do
+ it_behaves_like "a script that cannot be accessed by other users if they are not administrators"
+ end
+
+ context "the script is executed with an alternate non-admin identity", :windows_service_requires_assign_token do
+ include_context "alternate user identity"
+
+ before do
+ resource.user(windows_alternate_user)
+ resource.password(windows_alternate_user_password)
+ end
+
+ it_behaves_like "a script that cannot be accessed by other users if they are not administrators"
+ end
end
context "when $env:TMP has a space" do
before(:each) do
@dir = Dir.mktmpdir("Jerry Smith")
@original_env = ENV.to_hash.dup
- ENV.delete('TMP')
- ENV['TMP'] = @dir
+ ENV.delete("TMP")
+ ENV["TMP"] = @dir
end
after(:each) do
@@ -165,6 +225,11 @@ shared_context Chef::Resource::WindowsScript do
expect(resource.class).to receive(:new).and_call_original
expect(resource.should_skip?(:run)).to be_falsey
end
+
+ context "when this resource is used as a guard and it is specified with an alternate user identity" do
+ let(:guard_interpreter_resource) { resource.resource_name }
+ it_behaves_like "a resource with a guard specifying an alternate user identity"
+ end
end
context "when the architecture attribute is not set" do
@@ -181,9 +246,14 @@ shared_context Chef::Resource::WindowsScript do
let(:resource_architecture) { :x86_64 }
it_behaves_like "a script resource with architecture attribute"
end
+
+ describe "when running with an alternate user identity" do
+ let(:resource_command_property) { :code }
+ it_behaves_like "an execute resource that supports alternate user identity"
+ end
end
- def get_windows_script_output(suffix = '')
+ def get_windows_script_output(suffix = "")
File.read("#{script_output_path}#{suffix}")
end
@@ -195,7 +265,7 @@ shared_context Chef::Resource::WindowsScript do
get_process_architecture(guard_script_suffix)
end
- def get_process_architecture(suffix = '')
+ def get_process_architecture(suffix = "")
get_windows_script_output(suffix).strip.downcase
end
diff --git a/spec/support/shared/integration/app_server_support.rb b/spec/support/shared/integration/app_server_support.rb
index a0d5e7fa5c..e2bb3812ea 100644
--- a/spec/support/shared/integration/app_server_support.rb
+++ b/spec/support/shared/integration/app_server_support.rb
@@ -1,7 +1,7 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Author:: Ho-Sheng Hsiao (<hosh@opscode.com>)
-# Copyright:: Copyright (c) 2012, 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
+# Copyright:: Copyright 2012-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'rack'
-require 'stringio'
+require "rack"
+require "stringio"
module AppServerSupport
def start_app_server(app, port)
@@ -27,15 +27,13 @@ module AppServerSupport
Rack::Handler::WEBrick.run(app,
:Port => 9018,
:AccessLog => [],
- :Logger => WEBrick::Log::new(StringIO.new, 7)
+ :Logger => WEBrick::Log.new(StringIO.new, 7)
) do |found_server|
server = found_server
end
end
- Timeout::timeout(5) do
- until server && server.status == :Running
- sleep(0.01)
- end
+ Timeout.timeout(30) do
+ sleep(0.01) until server && server.status == :Running
end
[server, thread]
end
diff --git a/spec/support/shared/integration/integration_helper.rb b/spec/support/shared/integration/integration_helper.rb
index 927ff2f42b..29f2eef50f 100644
--- a/spec/support/shared/integration/integration_helper.rb
+++ b/spec/support/shared/integration/integration_helper.rb
@@ -1,7 +1,7 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Author:: Ho-Sheng Hsiao (<hosh@opscode.com>)
-# Copyright:: Copyright (c) 2012, 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,21 @@
# limitations under the License.
#
-require 'tmpdir'
-require 'fileutils'
-require 'chef/config'
-require 'chef/json_compat'
-require 'chef/server_api'
-require 'support/shared/integration/knife_support'
-require 'support/shared/integration/app_server_support'
-require 'cheffish/rspec/chef_run_support'
-require 'spec_helper'
+require "tmpdir"
+require "fileutils"
+require "chef/config"
+require "chef/json_compat"
+require "chef/server_api"
+require "support/shared/integration/knife_support"
+require "support/shared/integration/app_server_support"
+require "cheffish/rspec/chef_run_support"
+require "spec_helper"
+
+module Cheffish
+ class BasicChefClient
+ def_delegators :@run_context, :before_notifications
+ end
+end
module IntegrationSupport
include ChefZero::RSpec
@@ -69,8 +75,8 @@ module IntegrationSupport
def file(relative_path, contents)
filename = path_to(relative_path)
dir = File.dirname(filename)
- FileUtils.mkdir_p(dir) unless dir == '.'
- File.open(filename, 'w') do |file|
+ FileUtils.mkdir_p(dir) unless dir == "."
+ File.open(filename, "w") do |file|
raw = case contents
when Hash, Array
Chef::JSONCompat.to_json_pretty(contents)
@@ -84,7 +90,7 @@ module IntegrationSupport
def symlink(relative_path, relative_dest)
filename = path_to(relative_path)
dir = File.dirname(filename)
- FileUtils.mkdir_p(dir) unless dir == '.'
+ FileUtils.mkdir_p(dir) unless dir == "."
dest_filename = path_to(relative_dest)
File.symlink(dest_filename, filename)
end
@@ -93,7 +99,7 @@ module IntegrationSupport
File.expand_path(relative_path, (@parent_path || @repository_dir))
end
- def cb_metadata(name, version, extra_text="")
+ def cb_metadata(name, version, extra_text = "")
"name #{name.inspect}; version #{version.inspect}#{extra_text}"
end
@@ -105,9 +111,9 @@ module IntegrationSupport
RSpec.shared_context "with a chef repo" do
before :each do
raise "Can only create one directory per test" if @repository_dir
- @repository_dir = Dir.mktmpdir('chef_repo')
+ @repository_dir = Dir.mktmpdir("chef_repo")
Chef::Config.chef_repo_path = @repository_dir
- %w(client cookbook data_bag environment node role user).each do |object_name|
+ %w{client cookbook data_bag environment node role user}.each do |object_name|
Chef::Config.delete("#{object_name}_path".to_sym)
end
end
@@ -115,14 +121,14 @@ module IntegrationSupport
after :each do
if @repository_dir
begin
- %w(client cookbook data_bag environment node role user).each do |object_name|
+ %w{client cookbook data_bag environment node role user}.each do |object_name|
Chef::Config.delete("#{object_name}_path".to_sym)
end
Chef::Config.delete(:chef_repo_path)
# TODO: "force" actually means "silence all exceptions". this
# silences a weird permissions error on Windows that we should track
# down, but for now there's no reason for it to blow up our CI.
- FileUtils.remove_entry_secure(@repository_dir, force=Chef::Platform.windows?)
+ FileUtils.remove_entry_secure(@repository_dir, force = Chef::Platform.windows?)
ensure
@repository_dir = nil
end
@@ -134,7 +140,7 @@ module IntegrationSupport
# Versioned cookbooks
- RSpec.shared_context 'with versioned cookbooks', :versioned_cookbooks => true do
+ RSpec.shared_context "with versioned cookbooks", :versioned_cookbooks => true do
before(:each) { Chef::Config[:versioned_cookbooks] = true }
after(:each) { Chef::Config.delete(:versioned_cookbooks) }
end
diff --git a/spec/support/shared/integration/knife_support.rb b/spec/support/shared/integration/knife_support.rb
index 30293be6cf..4efa30a003 100644
--- a/spec/support/shared/integration/knife_support.rb
+++ b/spec/support/shared/integration/knife_support.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,15 +15,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'chef/config'
-require 'chef/knife'
-require 'chef/application/knife'
-require 'logger'
-require 'chef/log'
+require "chef/config"
+require "chef/knife"
+require "chef/application/knife"
+require "logger"
+require "chef/log"
+require "chef/chef_fs/file_system_cache"
module KnifeSupport
- DEBUG = ENV['DEBUG']
- def knife(*args, &block)
+ DEBUG = ENV["DEBUG"]
+ def knife(*args, input: nil)
# Allow knife('role from file roles/blah.json') rather than requiring the
# arguments to be split like knife('role', 'from', 'file', 'roles/blah.json')
# If any argument will have actual spaces in it, the long form is required.
@@ -37,16 +38,23 @@ module KnifeSupport
Chef::Config[:concurrency] = 1
# Work on machines where we can't access /var
- checksums_cache_dir = Dir.mktmpdir('checksums') do |checksums_cache_dir|
+ Dir.mktmpdir("checksums") do |checksums_cache_dir|
Chef::Config[:cache_options] = {
:path => checksums_cache_dir,
- :skip_expires => true
+ :skip_expires => true,
}
# This is Chef::Knife.run without load_commands--we'll load stuff
# ourselves, thank you very much
stdout = StringIO.new
stderr = StringIO.new
+
+ stdin = if input
+ StringIO.new(input)
+ else
+ STDIN
+ end
+
old_loggers = Chef::Log.loggers
old_log_level = Chef::Log.level
begin
@@ -56,13 +64,19 @@ module KnifeSupport
subcommand_class.load_deps
instance = subcommand_class.new(args)
+ # Load configs
+ instance.merge_configs
+
# Capture stdout/stderr
- instance.ui = Chef::Knife::UI.new(stdout, stderr, STDIN, {})
+ instance.ui = Chef::Knife::UI.new(stdout, stderr, stdin, instance.config.merge(disable_editing: true))
# Don't print stuff
Chef::Config[:verbosity] = ( DEBUG ? 2 : 0 )
instance.config[:config_file] = File.join(CHEF_SPEC_DATA, "null_config.rb")
+ # Ensure the ChefFS cache is empty
+ Chef::ChefFS::FileSystemCache.instance.reset!
+
# Configure chef with a (mostly) blank knife.rb
# We set a global and then mutate it in our stub knife.rb so we can be
# extra sure that we're not loading someone's real knife.rb and then
@@ -100,8 +114,6 @@ module KnifeSupport
end
end
- private
-
class KnifeResult
include ::RSpec::Matchers
@@ -146,11 +158,11 @@ module KnifeSupport
private
def should_result_in(expected)
- expected[:stdout] = '' if !expected[:stdout]
- expected[:stderr] = '' if !expected[:stderr]
+ expected[:stdout] = "" if !expected[:stdout]
+ expected[:stderr] = "" if !expected[:stderr]
expected[:exit_code] = 0 if !expected[:exit_code]
# TODO make this go away
- stderr_actual = @stderr.sub(/^WARNING: No knife configuration file found\n/, '')
+ stderr_actual = @stderr.sub(/^WARNING: No knife configuration file found\n/, "")
if expected[:stderr].is_a?(Regexp)
expect(stderr_actual).to match(expected[:stderr])
diff --git a/spec/support/shared/matchers/exit_with_code.rb b/spec/support/shared/matchers/exit_with_code.rb
index 32ebf8db15..a9f1af81ce 100644
--- a/spec/support/shared/matchers/exit_with_code.rb
+++ b/spec/support/shared/matchers/exit_with_code.rb
@@ -1,4 +1,4 @@
-require 'rspec/expectations'
+require "rspec/expectations"
# Lifted from http://stackoverflow.com/questions/1480537/how-can-i-validate-exits-and-aborts-in-rspec
RSpec::Matchers.define :exit_with_code do |exp_code|
@@ -9,12 +9,12 @@ RSpec::Matchers.define :exit_with_code do |exp_code|
rescue SystemExit => e
actual = e.status
end
- actual and actual == exp_code
+ actual && actual == exp_code
end
failure_message do |block|
"expected block to call exit(#{exp_code}) but exit" +
- (actual.nil? ? " not called" : "(#{actual}) was called")
+ (actual.nil? ? " not called" : "(#{actual}) was called")
end
failure_message_when_negated do |block|
diff --git a/spec/support/shared/matchers/match_environment_variable.rb b/spec/support/shared/matchers/match_environment_variable.rb
index c8c905f44a..393775ea29 100644
--- a/spec/support/shared/matchers/match_environment_variable.rb
+++ b/spec/support/shared/matchers/match_environment_variable.rb
@@ -1,6 +1,6 @@
-require 'rspec/expectations'
-require 'spec/support/platform_helpers'
+require "rspec/expectations"
+require "spec/support/platform_helpers"
RSpec::Matchers.define :match_environment_variable do |varname|
match do |actual|
diff --git a/spec/support/shared/shared_examples.rb b/spec/support/shared/shared_examples.rb
index 550fa2eb68..0c031bbafd 100644
--- a/spec/support/shared/shared_examples.rb
+++ b/spec/support/shared/shared_examples.rb
@@ -3,9 +3,9 @@
# Any object which defines a .to_json should import this test
shared_examples "to_json equivalent to Chef::JSONCompat.to_json" do
- let(:jsonable) {
+ let(:jsonable) do
raise "You must define the subject when including this test"
- }
+ end
it "should allow consumers to call #to_json or Chef::JSONCompat.to_json" do
expect(jsonable.to_json).to eq(Chef::JSONCompat.to_json(jsonable))
diff --git a/spec/support/shared/unit/api_error_inspector.rb b/spec/support/shared/unit/api_error_inspector.rb
index 29faa07f29..45bfcc67da 100644
--- a/spec/support/shared/unit/api_error_inspector.rb
+++ b/spec/support/shared/unit/api_error_inspector.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,6 @@
# limitations under the License.
#
-
-
# == API Error Inspector Examples
# These tests are work in progress. They exercise the code enough to ensure it
# runs without error, but don't make assertions about the output. This is
@@ -34,7 +32,7 @@ shared_examples_for "an api error inspector" do
:validation_key => "/etc/chef/testorg-validator.pem",
:chef_server_url => "https://chef-api.example.com",
:node_name => "testnode-name",
- :client_key => "/etc/chef/client.pem"
+ :client_key => "/etc/chef/client.pem",
}
@description = Chef::Formatters::ErrorDescription.new("Error registering the node:")
@outputter = Chef::Formatters::IndentableOutputStream.new(StringIO.new, STDERR)
diff --git a/spec/support/shared/unit/api_versioning.rb b/spec/support/shared/unit/api_versioning.rb
index 05a4117f8e..28141b73b1 100644
--- a/spec/support/shared/unit/api_versioning.rb
+++ b/spec/support/shared/unit/api_versioning.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,7 @@
require "chef/exceptions"
shared_examples_for "version handling" do
- let(:response_406) { OpenStruct.new(:code => '406') }
+ let(:response_406) { OpenStruct.new(:code => "406") }
let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) }
before do
@@ -32,35 +32,35 @@ shared_examples_for "version handling" do
end
it "raises the original exception" do
- expect{ object.send(method) }.to raise_error(exception_406)
+ expect { object.send(method) }.to raise_error(exception_406)
end
end # when the server does not support the min or max server API version that Chef::UserV1 supports
end # version handling
shared_examples_for "user and client reregister" do
- let(:response_406) { OpenStruct.new(:code => '406') }
+ let(:response_406) { OpenStruct.new(:code => "406") }
let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) }
let(:generic_exception) { Exception.new }
let(:min_version) { "2" }
let(:max_version) { "5" }
- let(:return_hash_406) {
+ let(:return_hash_406) do
{
"min_version" => min_version,
"max_version" => max_version,
- "request_version" => "30"
+ "request_version" => "30",
}
- }
+ end
context "when V0 is not supported by the server" do
context "when the exception is 406 and returns x-ops-server-api-version header" do
before do
allow(rest_v0).to receive(:put).and_raise(exception_406)
- allow(response_406).to receive(:[]).with('x-ops-server-api-version').and_return(Chef::JSONCompat.to_json(return_hash_406))
+ allow(response_406).to receive(:[]).with("x-ops-server-api-version").and_return(Chef::JSONCompat.to_json(return_hash_406))
end
it "raises an error about only V0 being supported" do
expect(object).to receive(:reregister_only_v0_supported_error_msg).with(max_version, min_version)
- expect{ object.reregister }.to raise_error(Chef::Exceptions::OnlyApiVersion0SupportedForAction)
+ expect { object.reregister }.to raise_error(Chef::Exceptions::OnlyApiVersion0SupportedForAction)
end
end
@@ -70,7 +70,7 @@ shared_examples_for "user and client reregister" do
end
it "raises the original error" do
- expect{ object.reregister }.to raise_error(generic_exception)
+ expect { object.reregister }.to raise_error(generic_exception)
end
end
end
diff --git a/spec/support/shared/unit/application_dot_d.rb b/spec/support/shared/unit/application_dot_d.rb
new file mode 100644
index 0000000000..da4eb88edd
--- /dev/null
+++ b/spec/support/shared/unit/application_dot_d.rb
@@ -0,0 +1,73 @@
+#
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+shared_examples_for "an application that loads a dot d" do
+ before do
+ Chef::Config[dot_d_config_name] = client_d_dir
+ end
+
+ context "when client_d_dir is set to nil" do
+ let(:client_d_dir) { nil }
+
+ it "does not raise an exception" do
+ expect { app.reconfigure }.not_to raise_error
+ end
+ end
+
+ context "when client_d_dir is set to a directory with configuration" do
+ # We're not going to mock out globbing the directory. We want to
+ # make sure that we are correctly globbing.
+ let(:client_d_dir) do
+ Chef::Util::PathHelper.cleanpath(
+ File.join(File.dirname(__FILE__), "../../../data/client.d_00")) end
+
+ it "loads the configuration in order" do
+ expect(IO).to receive(:read).with(Pathname.new("#{client_d_dir}/00-foo.rb").cleanpath.to_s).and_return("foo 0")
+ expect(IO).to receive(:read).with(Pathname.new("#{client_d_dir}/01-bar.rb").cleanpath.to_s).and_return("bar 0")
+ allow(app).to receive(:apply_config).with(anything(), Chef::Config.platform_specific_path("/etc/chef/client.rb")).and_call_original.ordered
+ expect(app).to receive(:apply_config).with("foo 0", Pathname.new("#{client_d_dir}/00-foo.rb").cleanpath.to_s).and_call_original.ordered
+ expect(app).to receive(:apply_config).with("bar 0", Pathname.new("#{client_d_dir}/01-bar.rb").cleanpath.to_s).and_call_original.ordered
+ app.reconfigure
+ end
+ end
+
+ context "when client_d_dir is set to a directory without configuration" do
+ let(:client_d_dir) do
+ Chef::Util::PathHelper.cleanpath(
+ File.join(File.dirname(__FILE__), "../../data/client.d_01")) end
+
+ # client.d_01 has a nested folder with a rb file that if
+ # executed, would raise an exception. If it is executed,
+ # it means we are loading configs that are deeply nested
+ # inside of client.d. For example, client.d/foo/bar.rb
+ # should not run, but client.d/foo.rb should.
+ it "does not raise an exception" do
+ expect { app.reconfigure }.not_to raise_error
+ end
+ end
+
+ context "when client_d_dir is set to a directory containing a directory named foo.rb" do
+ # foo.rb as a directory should be ignored
+ let(:client_d_dir) do
+ Chef::Util::PathHelper.cleanpath(
+ File.join(File.dirname(__FILE__), "../../data/client.d_02")) end
+
+ it "does not raise an exception" do
+ expect { app.reconfigure }.not_to raise_error
+ end
+ end
+end
diff --git a/spec/support/shared/unit/execute_resource.rb b/spec/support/shared/unit/execute_resource.rb
index e969a2ebd5..ab6ed2b86b 100644
--- a/spec/support/shared/unit/execute_resource.rb
+++ b/spec/support/shared/unit/execute_resource.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
shared_examples_for "an execute resource" do
@@ -76,13 +76,13 @@ shared_examples_for "an execute resource" do
expect(@resource.group).to eql(1)
end
- it "should accept an array for the execution path in Chef-12 and log deprecation message", :chef_lt_13_only do
+ it "should accept an array for the execution path in Chef-12 and log deprecation message", chef: "< 13" do
expect(Chef::Log).to receive(:warn).at_least(:once)
@resource.path ["woot"]
expect(@resource.path).to eql(["woot"])
end
- it "should raise an exception in chef-13", :chef_gte_13_only do
+ it "should raise an exception in chef-13", chef: ">= 13" do
expect(@resource.path [ "woot" ]).to raise_error
end
@@ -106,11 +106,53 @@ shared_examples_for "an execute resource" do
expect(@resource.user).to eql(1)
end
+ it "should accept a string for the domain" do
+ @resource.domain "mothership"
+ expect(@resource.domain).to eql("mothership")
+ end
+
+ it "should accept a string for the password" do
+ @resource.password "we.funk!"
+ expect(@resource.password).to eql("we.funk!")
+ end
+
it "should accept a string for creates" do
@resource.creates "something"
expect(@resource.creates).to eql("something")
end
+ it "should accept a boolean for live streaming" do
+ @resource.live_stream true
+ expect(@resource.live_stream).to be true
+ end
+
+ describe "the resource's sensitive attribute" do
+ it "should be false by default" do
+ expect(@resource.sensitive).to eq(false)
+ end
+
+ it "should be true if set to true" do
+ expect(@resource.sensitive).to eq(false)
+ @resource.sensitive true
+ expect(@resource.sensitive).to eq(true)
+ end
+
+ it "should be true if the password is non-nil" do
+ expect(@resource.sensitive).to eq(false)
+ @resource.password("we.funk!")
+ expect(@resource.sensitive).to eq(true)
+ end
+
+ it "should be true if the password is non-nil but the value is explicitly set to false" do
+ expect(@resource.sensitive).to eq(false)
+ @resource.password("we.funk!")
+ expect(@resource.sensitive).to eq(true)
+ @resource.sensitive false
+ expect(@resource.sensitive).to eq(true)
+ end
+
+ end
+
describe "when it has cwd, environment, group, path, return value, and a user" do
before do
@resource.command("grep")
diff --git a/spec/support/shared/unit/file_system_support.rb b/spec/support/shared/unit/file_system_support.rb
index 358f0c405c..32bdb1456e 100644
--- a/spec/support/shared/unit/file_system_support.rb
+++ b/spec/support/shared/unit/file_system_support.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,32 +16,32 @@
# limitations under the License.
#
-require 'chef/chef_fs/file_system'
-require 'chef/chef_fs/file_system/memory_root'
-require 'chef/chef_fs/file_system/memory_dir'
-require 'chef/chef_fs/file_system/memory_file'
+require "chef/chef_fs/file_system"
+require "chef/chef_fs/file_system/memory/memory_root"
+require "chef/chef_fs/file_system/memory/memory_dir"
+require "chef/chef_fs/file_system/memory/memory_file"
module FileSystemSupport
def memory_fs(pretty_name, value, cannot_be_in_regex = nil)
if !value.is_a?(Hash)
raise "memory_fs() must take a Hash"
end
- dir = Chef::ChefFS::FileSystem::MemoryRoot.new(pretty_name, cannot_be_in_regex)
+ dir = Chef::ChefFS::FileSystem::Memory::MemoryRoot.new(pretty_name, cannot_be_in_regex)
value.each do |key, child|
dir.add_child(memory_fs_value(child, key.to_s, dir))
end
dir
end
- def memory_fs_value(value, name = '', parent = nil)
+ def memory_fs_value(value, name = "", parent = nil)
if value.is_a?(Hash)
- dir = Chef::ChefFS::FileSystem::MemoryDir.new(name, parent)
+ dir = Chef::ChefFS::FileSystem::Memory::MemoryDir.new(name, parent)
value.each do |key, child|
dir.add_child(memory_fs_value(child, key.to_s, dir))
end
dir
else
- Chef::ChefFS::FileSystem::MemoryFile.new(name, parent, value || "#{name}\n")
+ Chef::ChefFS::FileSystem::Memory::MemoryFile.new(name, parent, value || "#{name}\n")
end
end
@@ -54,9 +54,9 @@ module FileSystemSupport
end
def no_blocking_calls_allowed
- [ Chef::ChefFS::FileSystem::MemoryFile, Chef::ChefFS::FileSystem::MemoryDir ].each do |c|
+ [ Chef::ChefFS::FileSystem::Memory::MemoryFile, Chef::ChefFS::FileSystem::Memory::MemoryDir ].each do |c|
[ :children, :exists?, :read ].each do |m|
- allow_any_instance_of(c).to receive(m).and_raise("#{m.to_s} should not be called")
+ allow_any_instance_of(c).to receive(m).and_raise("#{m} should not be called")
end
end
end
@@ -67,4 +67,3 @@ module FileSystemSupport
expect(result_paths).to match_array(expected_paths)
end
end
-
diff --git a/spec/support/shared/unit/knife_shared.rb b/spec/support/shared/unit/knife_shared.rb
index 8c9010f3cf..0af05ffb80 100644
--- a/spec/support/shared/unit/knife_shared.rb
+++ b/spec/support/shared/unit/knife_shared.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,6 @@
# limitations under the License.
#
-
shared_examples_for "mandatory field missing" do
context "when field is nil" do
before do
diff --git a/spec/support/shared/unit/mock_shellout.rb b/spec/support/shared/unit/mock_shellout.rb
index 7c3e49ec82..dac51be798 100644
--- a/spec/support/shared/unit/mock_shellout.rb
+++ b/spec/support/shared/unit/mock_shellout.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser <jkeiser@chef.io>
-# Copyright:: Copyright (c) 2015 John Keiser.
+# Copyright:: Copyright 2015-2016, John Keiser.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,15 +31,18 @@ class MockShellout
@properties = {
stdout: "",
stderr: "",
- exitstatus: 0
+ exitstatus: 0,
}.merge(properties)
end
+
def method_missing(name, *args)
@properties[name.to_sym]
end
+
def error?
exitstatus != 0
end
+
def error!
raise Mixlib::ShellOut::ShellCommandFailed, "Expected process to exit with 0, but received #{exitstatus}" if error?
end
diff --git a/spec/support/shared/unit/platform_introspector.rb b/spec/support/shared/unit/platform_introspector.rb
index df24370fde..7b9cc0f94e 100644
--- a/spec/support/shared/unit/platform_introspector.rb
+++ b/spec/support/shared/unit/platform_introspector.rb
@@ -1,7 +1,7 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010, 2012 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,29 +17,28 @@
# limitations under the License.
#
-
shared_examples_for "a platform introspector" do
before(:each) do
@platform_hash = {}
%w{openbsd freebsd}.each do |x|
@platform_hash[x] = {
"default" => x,
- "1.2.3" => "#{x}-1.2.3"
+ "1.2.3" => "#{x}-1.2.3",
}
end
- @platform_hash["debian"] = {["5", "6"] => "debian-5/6", "default" => "debian"}
+ @platform_hash["debian"] = { %w{5 6} => "debian-5/6", "default" => "debian" }
@platform_hash["default"] = "default"
# The following @platform_hash keys are used for testing version constraints
- @platform_hash['exact_match'] = { '1.2.3' => 'exact', '>= 1.0' => 'not exact'}
- @platform_hash['multiple_matches'] = { '~> 2.3.4' => 'matched ~> 2.3.4', '>= 2.3' => 'matched >=2.3' }
- @platform_hash['invalid_cookbook_version'] = {'>= 21' => 'Matches a single number'}
- @platform_hash['successful_matches'] = { '< 3.0' => 'matched < 3.0', '>= 3.0' => 'matched >= 3.0' }
+ @platform_hash["exact_match"] = { "1.2.3" => "exact", ">= 1.0" => "not exact" }
+ @platform_hash["multiple_matches"] = { "~> 2.3.4" => "matched ~> 2.3.4", ">= 2.3" => "matched >=2.3" }
+ @platform_hash["invalid_cookbook_version"] = { ">= 21" => "Matches a single number" }
+ @platform_hash["successful_matches"] = { "< 3.0" => "matched < 3.0", ">= 3.0" => "matched >= 3.0" }
@platform_family_hash = {
"debian" => "debian value",
[:rhel, :fedora] => "redhatty value",
"suse" => "suse value",
- :default => "default value"
+ :default => "default value",
}
end
@@ -84,28 +83,28 @@ shared_examples_for "a platform introspector" do
expect(platform_introspector.value_for_platform(@platform_hash)).to eq("openbsd")
end
- it 'returns the exact match' do
- node.automatic_attrs[:platform] = 'exact_match'
- node.automatic_attrs[:platform_version] = '1.2.3'
- expect(platform_introspector.value_for_platform(@platform_hash)).to eq('exact')
+ it "returns the exact match" do
+ node.automatic_attrs[:platform] = "exact_match"
+ node.automatic_attrs[:platform_version] = "1.2.3"
+ expect(platform_introspector.value_for_platform(@platform_hash)).to eq("exact")
end
- it 'raises RuntimeError' do
- node.automatic_attrs[:platform] = 'multiple_matches'
- node.automatic_attrs[:platform_version] = '2.3.4'
- expect {platform_introspector.value_for_platform(@platform_hash)}.to raise_error(RuntimeError)
+ it "raises RuntimeError" do
+ node.automatic_attrs[:platform] = "multiple_matches"
+ node.automatic_attrs[:platform_version] = "2.3.4"
+ expect { platform_introspector.value_for_platform(@platform_hash) }.to raise_error(RuntimeError)
end
- it 'should not require .0 to match >= 21.0' do
- node.automatic_attrs[:platform] = 'invalid_cookbook_version'
- node.automatic_attrs[:platform_version] = '21'
- expect(platform_introspector.value_for_platform(@platform_hash)).to eq('Matches a single number')
+ it "should not require .0 to match >= 21.0" do
+ node.automatic_attrs[:platform] = "invalid_cookbook_version"
+ node.automatic_attrs[:platform_version] = "21"
+ expect(platform_introspector.value_for_platform(@platform_hash)).to eq("Matches a single number")
end
- it 'should return the value for that match' do
- node.automatic_attrs[:platform] = 'successful_matches'
- node.automatic_attrs[:platform_version] = '2.9'
- expect(platform_introspector.value_for_platform(@platform_hash)).to eq('matched < 3.0')
+ it "should return the value for that match" do
+ node.automatic_attrs[:platform] = "successful_matches"
+ node.automatic_attrs[:platform_version] = "2.9"
+ expect(platform_introspector.value_for_platform(@platform_hash)).to eq("matched < 3.0")
end
describe "when platform versions is an array" do
@@ -125,17 +124,17 @@ shared_examples_for "a platform introspector" do
describe "when checking platform?" do
it "returns true if the node is a provided platform and platforms are provided as symbols" do
- node.automatic_attrs[:platform] = 'ubuntu'
+ node.automatic_attrs[:platform] = "ubuntu"
expect(platform_introspector.platform?([:redhat, :ubuntu])).to eq(true)
end
it "returns true if the node is a provided platform and platforms are provided as strings" do
- node.automatic_attrs[:platform] = 'ubuntu'
- expect(platform_introspector.platform?(["redhat", "ubuntu"])).to eq(true)
+ node.automatic_attrs[:platform] = "ubuntu"
+ expect(platform_introspector.platform?(%w{redhat ubuntu})).to eq(true)
end
it "returns false if the node is not of the provided platforms" do
- node.automatic_attrs[:platform] = 'ubuntu'
+ node.automatic_attrs[:platform] = "ubuntu"
expect(platform_introspector.platform?(:splatlinux)).to eq(false)
end
end
@@ -143,17 +142,17 @@ shared_examples_for "a platform introspector" do
describe "when checking platform_family?" do
it "returns true if the node is in a provided platform family and families are provided as symbols" do
- node.automatic_attrs[:platform_family] = 'debian'
+ node.automatic_attrs[:platform_family] = "debian"
expect(platform_introspector.platform_family?([:rhel, :debian])).to eq(true)
end
it "returns true if the node is a provided platform and platforms are provided as strings" do
- node.automatic_attrs[:platform_family] = 'rhel'
- expect(platform_introspector.platform_family?(["rhel", "debian"])).to eq(true)
+ node.automatic_attrs[:platform_family] = "rhel"
+ expect(platform_introspector.platform_family?(%w{rhel debian})).to eq(true)
end
it "returns false if the node is not of the provided platforms" do
- node.automatic_attrs[:platform_family] = 'suse'
+ node.automatic_attrs[:platform_family] = "suse"
expect(platform_introspector.platform_family?(:splatlinux)).to eq(false)
end
@@ -171,21 +170,20 @@ shared_examples_for "a platform introspector" do
"centos" => { "default" => [ :restart, :reload, :status ] },
"redhat" => { "default" => [ :restart, :reload, :status ] },
"fedora" => { "default" => [ :restart, :reload, :status ] },
- "default" => { "default" => [:restart, :reload ] }}
+ "default" => { "default" => [:restart, :reload ] } }
end
it "returns the correct default for a given platform" do
node.automatic_attrs[:platform] = "debian"
- node.automatic_attrs[:platform_version] = '9000'
+ node.automatic_attrs[:platform_version] = "9000"
expect(platform_introspector.value_for_platform(@platform_hash)).to eq([ :restart, :reload, :status ])
end
it "returns the correct platform+version specific value " do
node.automatic_attrs[:platform] = "debian"
- node.automatic_attrs[:platform_version] = '4.0'
+ node.automatic_attrs[:platform_version] = "4.0"
expect(platform_introspector.value_for_platform(@platform_hash)).to eq([:restart, :reload])
end
end
end
-
diff --git a/spec/support/shared/unit/provider/file.rb b/spec/support/shared/unit/provider/file.rb
index ff9e271a0a..b58159fcc9 100644
--- a/spec/support/shared/unit/provider/file.rb
+++ b/spec/support/shared/unit/provider/file.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
if windows?
- require 'chef/win32/file'
+ require "chef/win32/file"
end
# Filesystem stubs
@@ -37,7 +37,7 @@ end
# forwards-vs-reverse slashes on windows sucks
def windows_path
- windows? ? normalized_path.gsub(/\\/, '/') : normalized_path
+ windows? ? normalized_path.tr('\\', "/") : normalized_path
end
# this is all getting a bit stupid, CHEF-4802 cut to remove all this
@@ -117,7 +117,7 @@ class BasicTempfile < ::File
end
def self.new(basename)
- super(make_tmp_path(basename), File::RDWR|File::CREAT|File::EXCL, 0600)
+ super(make_tmp_path(basename), File::RDWR | File::CREAT | File::EXCL, 0600)
end
def unlink
@@ -142,7 +142,7 @@ shared_examples_for Chef::Provider::File do
end
after do
- tempfile.close if (tempfile && !tempfile.closed?)
+ tempfile.close if tempfile && !tempfile.closed?
File.unlink(tempfile.path) rescue nil
end
@@ -419,12 +419,12 @@ shared_examples_for Chef::Provider::File do
[:create, :create_if_missing, :touch].each do |action|
context "action #{action}" do
it "raises EnclosingDirectoryDoesNotExist" do
- expect {provider.run_action(action)}.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
+ expect { provider.run_action(action) }.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
end
it "does not raise an exception in why-run mode" do
Chef::Config[:why_run] = true
- expect {provider.run_action(action)}.not_to raise_error
+ expect { provider.run_action(action) }.not_to raise_error
Chef::Config[:why_run] = false
end
end
@@ -435,19 +435,19 @@ shared_examples_for Chef::Provider::File do
before { setup_unwritable_file }
it "action delete raises InsufficientPermissions" do
- expect {provider.run_action(:delete)}.to raise_error(Chef::Exceptions::InsufficientPermissions)
+ expect { provider.run_action(:delete) }.to raise_error(Chef::Exceptions::InsufficientPermissions)
end
it "action delete also raises InsufficientPermissions in why-run mode" do
Chef::Config[:why_run] = true
- expect {provider.run_action(:delete)}.to raise_error(Chef::Exceptions::InsufficientPermissions)
+ expect { provider.run_action(:delete) }.to raise_error(Chef::Exceptions::InsufficientPermissions)
Chef::Config[:why_run] = false
end
end
end
context "action create" do
- it "should create the file, update its contents and then set the acls on the file" do
+ it "should create the file, update its contents and then set the acls on the file" do
setup_missing_file
expect(provider).to receive(:do_create_file)
expect(provider).to receive(:do_contents_changes)
@@ -459,35 +459,24 @@ shared_examples_for Chef::Provider::File do
context "do_validate_content" do
before { setup_normal_file }
- let(:tempfile) {
- t = double('Tempfile', :path => "/tmp/foo-bar-baz", :closed? => true)
+ let(:tempfile) do
+ t = double("Tempfile", :path => "/tmp/foo-bar-baz", :closed? => true)
allow(content).to receive(:tempfile).and_return(t)
t
- }
-
- let(:verification) { instance_double(Chef::Resource::File::Verification) }
- let(:verification_fail) { instance_double(Chef::Resource::File::Verification) }
+ end
context "with user-supplied verifications" do
it "calls #verify on each verification with tempfile path" do
- allow(Chef::Resource::File::Verification).to(
- receive(:new).with(anything(), "true", anything()).and_return(verification))
- provider.new_resource.verify "true"
- provider.new_resource.verify "true"
- expect(verification).to receive(:verify).with(tempfile.path).twice.and_return(true)
+ provider.new_resource.verify windows? ? "REM" : "true"
+ provider.new_resource.verify windows? ? "REM" : "true"
provider.send(:do_validate_content)
end
it "raises an exception if any verification fails" do
- allow(Chef::Resource::File::Verification).to(
- receive(:new).with(anything(), "true", anything()).and_return(verification))
- allow(Chef::Resource::File::Verification).to(
- receive(:new).with(anything(), "false", anything()).and_return(verification_fail))
- provider.new_resource.verify "true"
- provider.new_resource.verify "false"
- expect(verification).to receive(:verify).with(tempfile.path).and_return(true)
- expect(verification_fail).to receive(:verify).with(tempfile.path).and_return(false)
- expect{provider.send(:do_validate_content)}.to raise_error(Chef::Exceptions::ValidationFailed)
+ allow(File).to receive(:directory?).with("C:\\Windows\\system32/cmd.exe").and_return(false)
+ provider.new_resource.verify windows? ? "REM" : "true"
+ provider.new_resource.verify windows? ? "cmd.exe /c exit 1" : "false"
+ expect { provider.send(:do_validate_content) }.to raise_error(Chef::Exceptions::ValidationFailed)
end
end
end
@@ -518,7 +507,7 @@ shared_examples_for Chef::Provider::File do
before do
setup_normal_file
provider.load_current_resource
- tempfile = double('Tempfile', :path => "/tmp/foo-bar-baz")
+ tempfile = double("Tempfile", :path => "/tmp/foo-bar-baz")
allow(content).to receive(:tempfile).and_return(tempfile)
expect(File).to receive(:exists?).with("/tmp/foo-bar-baz").and_return(true)
expect(tempfile).to receive(:close).once
@@ -531,14 +520,14 @@ shared_examples_for Chef::Provider::File do
let(:diff_for_reporting) { "+++\n---\n+foo\n-bar\n" }
before do
allow(provider).to receive(:contents_changed?).and_return(true)
- diff = double('Diff', :for_output => ['+++','---','+foo','-bar'],
+ diff = double("Diff", :for_output => ["+++", "---", "+foo", "-bar"],
:for_reporting => diff_for_reporting )
allow(diff).to receive(:diff).with(resource_path, tempfile_path).and_return(true)
expect(provider).to receive(:diff).at_least(:once).and_return(diff)
expect(provider).to receive(:checksum).with(tempfile_path).and_return(tempfile_sha256)
allow(provider).to receive(:managing_content?).and_return(true)
allow(provider).to receive(:checksum).with(resource_path).and_return(tempfile_sha256)
- expect(resource).not_to receive(:checksum).with(tempfile_sha256) # do not mutate the new resource
+ expect(resource).not_to receive(:checksum).with(tempfile_sha256) # do not mutate the new resource
expect(provider.deployment_strategy).to receive(:deploy).with(tempfile_path, normalized_path)
end
context "when the file was created" do
@@ -560,7 +549,7 @@ shared_examples_for Chef::Provider::File do
end
context "when the file was not created" do
before do
- allow(provider).to receive(:do_backup) # stub do_backup
+ allow(provider).to receive(:do_backup) # stub do_backup
expect(provider).to receive(:needs_creating?).at_least(:once).and_return(false)
end
@@ -581,7 +570,7 @@ shared_examples_for Chef::Provider::File do
end
end
- it "does nothing when the contents have not changed" do
+ it "does nothing when the contents have not changed" do
allow(provider).to receive(:contents_changed?).and_return(false)
expect(provider).not_to receive(:diff)
provider.send(:do_contents_changes)
@@ -591,20 +580,20 @@ shared_examples_for Chef::Provider::File do
it "does nothing when there is no content to deploy (tempfile returned from contents is nil)" do
expect(provider.send(:content)).to receive(:tempfile).at_least(:once).and_return(nil)
expect(provider).not_to receive(:diff)
- expect{ provider.send(:do_contents_changes) }.not_to raise_error
+ expect { provider.send(:do_contents_changes) }.not_to raise_error
end
it "raises an exception when the content object returns a tempfile with a nil path" do
- tempfile = double('Tempfile', :path => nil)
+ tempfile = double("Tempfile", :path => nil)
expect(provider.send(:content)).to receive(:tempfile).at_least(:once).and_return(tempfile)
- expect{ provider.send(:do_contents_changes) }.to raise_error
+ expect { provider.send(:do_contents_changes) }.to raise_error(RuntimeError)
end
it "raises an exception when the content object returns a tempfile that does not exist" do
- tempfile = double('Tempfile', :path => "/tmp/foo-bar-baz")
+ tempfile = double("Tempfile", :path => "/tmp/foo-bar-baz")
expect(provider.send(:content)).to receive(:tempfile).at_least(:once).and_return(tempfile)
expect(File).to receive(:exists?).with("/tmp/foo-bar-baz").and_return(false)
- expect{ provider.send(:do_contents_changes) }.to raise_error
+ expect { provider.send(:do_contents_changes) }.to raise_error(RuntimeError)
end
end
@@ -694,6 +683,16 @@ shared_examples_for Chef::Provider::File do
end
end
+ context "in why run mode" do
+ before { Chef::Config[:why_run] = true }
+ after { Chef::Config[:why_run] = false }
+
+ it "does not modify new_resource" do
+ setup_missing_file
+ expect(provider).not_to receive(:load_resource_attributes_from_file).with(provider.new_resource)
+ provider.run_action(:create)
+ end
+ end
end
context "action delete" do
@@ -723,7 +722,7 @@ shared_examples_for Chef::Provider::File do
it "should not try to backup or delete the file, and should not be updated by last action" do
expect(provider).not_to receive(:do_backup)
expect(File).not_to receive(:delete)
- expect { provider.run_action(:delete) }.to raise_error()
+ expect { provider.run_action(:delete) }.to raise_error(Chef::Exceptions::InsufficientPermissions)
expect(resource).not_to be_updated_by_last_action
end
end
diff --git a/spec/support/shared/unit/provider/useradd_based_user_provider.rb b/spec/support/shared/unit/provider/useradd_based_user_provider.rb
index fc7c79ef7d..86076122a4 100644
--- a/spec/support/shared/unit/provider/useradd_based_user_provider.rb
+++ b/spec/support/shared/unit/provider/useradd_based_user_provider.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010, 2013 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
#
# License:: Apache License, Version 2.0
#
@@ -18,13 +18,18 @@
# limitations under the License.
#
+# XXX: this used to be shared by solaris and linux classes, but at some
+# point became linux-specific. it is now a misnomer to call these 'shared'
+# examples and they should either realy get turned into shared examples or
+# should be copypasta'd back directly into the linux tests.
+
shared_examples_for "a useradd-based user provider" do |supported_useradd_options|
before(:each) do
@node = Chef::Node.new
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::User.new("adam", @run_context)
+ @new_resource = Chef::Resource::User::LinuxUser.new("adam", @run_context)
@new_resource.comment "Adam Jacob"
@new_resource.uid 1000
@new_resource.gid 1000
@@ -35,7 +40,7 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
@new_resource.manage_home false
@new_resource.force false
@new_resource.non_unique false
- @current_resource = Chef::Resource::User.new("adam", @run_context)
+ @current_resource = Chef::Resource::User::LinuxUser.new("adam", @run_context)
@current_resource.comment "Adam Jacob"
@current_resource.uid 1000
@current_resource.gid 1000
@@ -46,7 +51,6 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
@current_resource.manage_home false
@current_resource.force false
@current_resource.non_unique false
- @current_resource.supports({:manage_home => false, :non_unique => false})
end
describe "when setting option" do
@@ -60,14 +64,14 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
it "should set the option for #{attribute} if the new resources #{attribute} is not nil" do
allow(@new_resource).to receive(attribute).and_return("hola")
- expect(provider.universal_options).to eql([option, 'hola'])
+ expect(provider.universal_options).to eql([option, "hola"])
end
it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management" do
- allow(@new_resource).to receive(:supports).and_return({:manage_home => false,
- :non_unique => false})
+ allow(@new_resource).to receive(:supports).and_return({ :manage_home => false,
+ :non_unique => false })
allow(@new_resource).to receive(attribute).and_return("hola")
- expect(provider.universal_options).to eql([option, 'hola'])
+ expect(provider.universal_options).to eql([option, "hola"])
end
it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management (using real attributes)" do
@@ -75,15 +79,15 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
allow(@new_resource).to receive(:non_unique).and_return(false)
allow(@new_resource).to receive(:non_unique).and_return(false)
allow(@new_resource).to receive(attribute).and_return("hola")
- expect(provider.universal_options).to eql([option, 'hola'])
+ expect(provider.universal_options).to eql([option, "hola"])
end
end
it "should combine all the possible options" do
combined_opts = []
- supported_useradd_options.sort{ |a,b| a[0] <=> b[0] }.each do |attribute, option|
+ supported_useradd_options.sort { |a, b| a[0] <=> b[0] }.each do |attribute, option|
allow(@new_resource).to receive(attribute).and_return("hola")
- combined_opts << option << 'hola'
+ combined_opts << option << "hola"
end
expect(provider.universal_options).to eql(combined_opts)
end
@@ -96,77 +100,64 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
it "should set useradd -r" do
@new_resource.system(true)
- expect(provider.useradd_options).to eq([ "-r" ])
+ expect(provider.useradd_options).to eq([ "-r", "-m" ])
end
end
describe "when the resource has a different home directory and supports home directory management" do
before do
- allow(@new_resource).to receive(:home).and_return("/wowaweea")
- allow(@new_resource).to receive(:supports).and_return({:manage_home => true,
- :non_unique => false})
+ @new_resource.home "/wowaweea"
+ @new_resource.manage_home true
end
it "should set -m -d /homedir" do
- expect(provider.universal_options).to eq(%w[-d /wowaweea -m])
- expect(provider.useradd_options).to eq([])
+ expect(provider.universal_options).to eq(%w{-d /wowaweea})
+ expect(provider.usermod_options).to eq(%w{-m})
end
end
describe "when the resource has a different home directory and supports home directory management (using real attributes)" do
before do
- allow(@new_resource).to receive(:home).and_return("/wowaweea")
- allow(@new_resource).to receive(:manage_home).and_return(true)
- allow(@new_resource).to receive(:non_unique).and_return(false)
+ @new_resource.home("/wowaweea")
+ @new_resource.manage_home true
+ @new_resource.non_unique false
end
it "should set -m -d /homedir" do
- expect(provider.universal_options).to eql(%w[-d /wowaweea -m])
- expect(provider.useradd_options).to eq([])
+ expect(provider.universal_options).to eq(%w{-d /wowaweea})
+ expect(provider.usermod_options).to eq(%w{-m})
end
end
- describe "when the resource supports non_unique ids" do
- before do
- allow(@new_resource).to receive(:supports).and_return({:manage_home => false,
- :non_unique => true})
- end
-
- it "should set -m -o" do
- expect(provider.universal_options).to eql([ "-o" ])
- end
+ it "when non_unique is false should not set -m" do
+ @new_resource.non_unique false
+ expect(provider.universal_options).to eql([ ])
end
- describe "when the resource supports non_unique ids (using real attributes)" do
- before do
- allow(@new_resource).to receive(:manage_home).and_return(false)
- allow(@new_resource).to receive(:non_unique).and_return(true)
- end
-
- it "should set -m -o" do
- expect(provider.universal_options).to eql([ "-o" ])
- end
+ it "when non_unique is true should set -o" do
+ @new_resource.non_unique true
+ expect(provider.universal_options).to eql([ "-o" ])
end
end
describe "when creating a user" do
before(:each) do
- @current_resource = Chef::Resource::User.new(@new_resource.name, @run_context)
+ @current_resource = Chef::Resource::User::LinuxUser.new(@new_resource.name, @run_context)
@current_resource.username(@new_resource.username)
provider.current_resource = @current_resource
provider.new_resource.manage_home true
provider.new_resource.home "/Users/mud"
- provider.new_resource.gid '23'
+ provider.new_resource.gid "23"
end
it "runs useradd with the computed command options" do
command = ["useradd",
- "-c", 'Adam Jacob',
- "-g", '23' ]
- command.concat(["-p", 'abracadabra']) if supported_useradd_options.key?("password")
- command.concat([ "-s", '/usr/bin/zsh',
- "-u", '1000',
- "-d", '/Users/mud',
+ "-c", "Adam Jacob",
+ "-g", "23" ]
+ command.concat(["-p", "abracadabra"]) if supported_useradd_options.key?("password")
+ command.concat([ "-s", "/usr/bin/zsh",
+ "-u", "1000",
+ "-d", "/Users/mud",
"-m",
"adam" ])
expect(provider).to receive(:shell_out!).with(*command).and_return(true)
@@ -183,12 +174,12 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
it "should not include -m or -d in the command options" do
command = ["useradd",
- "-c", 'Adam Jacob',
- "-g", '23']
- command.concat(["-p", 'abracadabra']) if supported_useradd_options.key?("password")
- command.concat([ "-s", '/usr/bin/zsh',
- "-u", '1000',
- "-r",
+ "-c", "Adam Jacob",
+ "-g", "23"]
+ command.concat(["-p", "abracadabra"]) if supported_useradd_options.key?("password")
+ command.concat([ "-s", "/usr/bin/zsh",
+ "-u", "1000",
+ "-r", "-m",
"adam" ])
expect(provider).to receive(:shell_out!).with(*command).and_return(true)
provider.create_user
@@ -202,15 +193,15 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
before(:each) do
provider.new_resource.manage_home true
provider.new_resource.home "/Users/mud"
- provider.new_resource.gid '23'
+ provider.new_resource.gid "23"
end
# CHEF-3423, -m must come before the username
# CHEF-4305, -d must come before -m to support CentOS/RHEL 5
it "runs usermod with the computed command options" do
command = ["usermod",
- "-g", '23',
- "-d", '/Users/mud',
+ "-g", "23",
+ "-d", "/Users/mud",
"-m",
"adam" ]
expect(provider).to receive(:shell_out!).with(*command).and_return(true)
@@ -220,8 +211,8 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
it "does not set the -r option to usermod" do
@new_resource.system(true)
command = ["usermod",
- "-g", '23',
- "-d", '/Users/mud',
+ "-g", "23",
+ "-d", "/Users/mud",
"-m",
"adam" ]
expect(provider).to receive(:shell_out!).with(*command).and_return(true)
@@ -229,9 +220,9 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
end
it "CHEF-3429: does not set -m if we aren't changing the home directory" do
- expect(provider).to receive(:updating_home?).and_return(false)
+ expect(provider).to receive(:updating_home?).at_least(:once).and_return(false)
command = ["usermod",
- "-g", '23',
+ "-g", "23",
"adam" ]
expect(provider).to receive(:shell_out!).with(*command).and_return(true)
provider.manage_user
@@ -246,15 +237,12 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
end
it "should run userdel with the new resources user name and -r if manage_home is true" do
- @new_resource.supports({ :manage_home => true,
- :non_unique => false})
+ @new_resource.manage_home true
expect(provider).to receive(:shell_out!).with("userdel", "-r", @new_resource.username).and_return(true)
provider.remove_user
end
it "should run userdel with the new resources user name if non_unique is true" do
- @new_resource.supports({ :manage_home => false,
- :non_unique => true})
expect(provider).to receive(:shell_out!).with("userdel", @new_resource.username).and_return(true)
provider.remove_user
end
@@ -269,7 +257,7 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
describe "when checking the lock" do
# lazy initialize so we can modify stdout and stderr strings
let(:passwd_s_status) do
- double("Mixlib::ShellOut command", :exitstatus => 0, :stdout => @stdout, :stderr => @stderr)
+ double("Mixlib::ShellOut command", :exitstatus => 0, :stdout => @stdout, :stderr => @stderr, :error! => nil)
end
before(:each) do
@@ -284,73 +272,54 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
end
it "should return false if status begins with P" do
- expect(provider).to receive(:shell_out!).
- with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+ expect(provider).to receive(:shell_out).
+ with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
and_return(passwd_s_status)
expect(provider.check_lock).to eql(false)
end
it "should return false if status begins with N" do
@stdout = "root N"
- expect(provider).to receive(:shell_out!).
- with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+ expect(provider).to receive(:shell_out).
+ with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
and_return(passwd_s_status)
expect(provider.check_lock).to eql(false)
end
it "should return true if status begins with L" do
@stdout = "root L"
- expect(provider).to receive(:shell_out!).
- with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+ expect(provider).to receive(:shell_out).
+ with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
and_return(passwd_s_status)
expect(provider.check_lock).to eql(true)
end
- it "should raise a Chef::Exceptions::User if passwd -S fails on anything other than redhat/centos" do
- @node.automatic_attrs[:platform] = 'ubuntu'
- expect(provider).to receive(:shell_out!).
- with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+ it "should raise a ShellCommandFailed exception if passwd -S exits with something other than 0 or 1" do
+ expect(passwd_s_status).to receive(:error!).and_raise(Mixlib::ShellOut::ShellCommandFailed)
+ expect(provider).to receive(:shell_out).
+ with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
and_return(passwd_s_status)
- expect(passwd_s_status).to receive(:exitstatus).and_return(1)
- expect { provider.check_lock }.to raise_error(Chef::Exceptions::User)
+ expect { provider.check_lock }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
end
- ['redhat', 'centos'].each do |os|
- it "should not raise a Chef::Exceptions::User if passwd -S exits with 1 on #{os} and the passwd package is version 0.73-1" do
- @node.automatic_attrs[:platform] = os
- expect(passwd_s_status).to receive(:exitstatus).and_return(1)
- expect(provider).to receive(:shell_out!).
- with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
- and_return(passwd_s_status)
- rpm_status = double("Mixlib::ShellOut command", :exitstatus => 0, :stdout => "passwd-0.73-1\n", :stderr => "")
- expect(provider).to receive(:shell_out!).with("rpm -q passwd").and_return(rpm_status)
- expect { provider.check_lock }.not_to raise_error
- end
-
- it "should raise a Chef::Exceptions::User if passwd -S exits with 1 on #{os} and the passwd package is not version 0.73-1" do
- @node.automatic_attrs[:platform] = os
- expect(passwd_s_status).to receive(:exitstatus).and_return(1)
- expect(provider).to receive(:shell_out!).
- with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
- and_return(passwd_s_status)
- rpm_status = double("Mixlib::ShellOut command", :exitstatus => 0, :stdout => "passwd-0.73-2\n", :stderr => "")
- expect(provider).to receive(:shell_out!).with("rpm -q passwd").and_return(rpm_status)
- expect { provider.check_lock }.to raise_error(Chef::Exceptions::User)
- end
-
- it "should raise a ShellCommandFailed exception if passwd -S exits with something other than 0 or 1 on #{os}" do
- @node.automatic_attrs[:platform] = os
- expect(provider).to receive(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed)
- expect { provider.check_lock }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
- end
+ it "should raise an error if the output isn't parsable" do
+ expect(passwd_s_status).to receive(:stdout).and_return("")
+ expect(passwd_s_status).to receive(:stderr).and_return("")
+ expect(provider).to receive(:shell_out).
+ with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
+ and_return(passwd_s_status)
+ expect { provider.check_lock }.to raise_error(Chef::Exceptions::User)
end
context "when in why run mode" do
before do
passwd_status = double("Mixlib::ShellOut command", :exitstatus => 0, :stdout => "", :stderr => "passwd: user 'chef-test' does not exist\n")
- expect(provider).to receive(:shell_out!).
- with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+ expect(provider).to receive(:shell_out).
+ with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
and_return(passwd_status)
+ # ubuntu returns 252 on user-does-not-exist so will raise if #error! is called or if
+ # shell_out! is used
+ allow(passwd_status).to receive(:error!).and_raise(Mixlib::ShellOut::ShellCommandFailed)
Chef::Config[:why_run] = true
end
@@ -384,25 +353,25 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
"action" => "should return false if home matches",
"current_resource_home" => [ "/home/laurent" ],
"new_resource_home" => [ "/home/laurent" ],
- "expected_result" => false
+ "expected_result" => false,
},
{
"action" => "should return true if home doesn't match",
"current_resource_home" => [ "/home/laurent" ],
"new_resource_home" => [ "/something/else" ],
- "expected_result" => true
+ "expected_result" => true,
},
{
"action" => "should return false if home only differs by trailing slash",
"current_resource_home" => [ "/home/laurent" ],
"new_resource_home" => [ "/home/laurent/", "/home/laurent" ],
- "expected_result" => false
+ "expected_result" => false,
},
{
"action" => "should return false if home is an equivalent path",
"current_resource_home" => [ "/home/laurent" ],
"new_resource_home" => [ "/home/./laurent", "/home/laurent" ],
- "expected_result" => false
+ "expected_result" => false,
},
].each do |home_check|
it home_check["action"] do
@@ -420,9 +389,9 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
end
end
it "should return true if the current home does not exist but a home is specified by the new resource" do
- @new_resource = Chef::Resource::User.new("adam", @run_context)
- @current_resource = Chef::Resource::User.new("adam", @run_context)
- provider = Chef::Provider::User::Useradd.new(@new_resource, @run_context)
+ @new_resource = Chef::Resource::User::LinuxUser.new("adam", @run_context)
+ @current_resource = Chef::Resource::User::LinuxUser.new("adam", @run_context)
+ provider = Chef::Provider::User::Linux.new(@new_resource, @run_context)
provider.current_resource = @current_resource
@current_resource.home nil
@new_resource.home "/home/kitten"
@@ -431,4 +400,3 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
end
end
end
-
diff --git a/spec/support/shared/unit/resource/static_provider_resolution.rb b/spec/support/shared/unit/resource/static_provider_resolution.rb
index 2bc4c70d95..e68b805d7d 100644
--- a/spec/support/shared/unit/resource/static_provider_resolution.rb
+++ b/spec/support/shared/unit/resource/static_provider_resolution.rb
@@ -1,6 +1,6 @@
#
# Author:: Lamont Granquist (<lamont@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,6 @@
# limitations under the License.
#
-
-
#
# This is for typical "static" provider resolution which maps resources onto
# providers based only on the node data. Its not really 'static' because it
@@ -25,7 +23,7 @@
# a static mapping for the node (unlike the service resource which is
# complicated).
#
-def static_provider_resolution(opts={})
+def static_provider_resolution(opts = {})
action = opts[:action]
provider_class = opts[:provider]
resource_class = opts[:resource]
@@ -35,13 +33,13 @@ def static_provider_resolution(opts={})
platform_version = opts[:platform_version]
describe resource_class, "static provider initialization" do
- let(:node) {
+ let(:node) do
node = Chef::Node.new
node.automatic_attrs[:os] = os
node.automatic_attrs[:platform_family] = platform_family
node.automatic_attrs[:platform_version] = platform_version
node
- }
+ end
let(:events) { Chef::EventDispatch::Dispatcher.new }
let(:run_context) { Chef::RunContext.new(node, {}, events) }
let(:resource) { resource_class.new("foo", run_context) }
@@ -63,4 +61,3 @@ def static_provider_resolution(opts={})
end
end
end
-
diff --git a/spec/support/shared/unit/script_resource.rb b/spec/support/shared/unit/script_resource.rb
index 18ee94606e..27864e1625 100644
--- a/spec/support/shared/unit/script_resource.rb
+++ b/spec/support/shared/unit/script_resource.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
shared_examples_for "a script resource" do
@@ -30,11 +30,11 @@ shared_examples_for "a script resource" do
expect(script_resource.resource_name).to eql(resource_name)
end
- it "should set command to nil on the resource", :chef_gte_13_only do
+ it "should set command to nil on the resource", chef: ">= 13" do
expect(script_resource.command).to be nil
end
- it "should set command to the name on the resource", :chef_lt_13_only do
+ it "should set command to the name on the resource", chef: "< 13" do
expect(script_resource.command).to eql script_resource.name
end
@@ -48,27 +48,27 @@ shared_examples_for "a script resource" do
expect(script_resource.flags).to eql("-f")
end
- it "should raise an exception if users set command on the resource", :chef_gte_13_only do
- expect { script_resource.command('foo') }.to raise_error(Chef::Exceptions::Script)
+ it "should raise an exception if users set command on the resource", chef: ">= 13" do
+ expect { script_resource.command("foo") }.to raise_error(Chef::Exceptions::Script)
end
- it "should not raise an exception if users set command on the resource", :chef_lt_13_only do
- expect { script_resource.command('foo') }.not_to raise_error
+ it "should not raise an exception if users set command on the resource", chef: "< 13" do
+ expect { script_resource.command("foo") }.not_to raise_error
end
describe "when executing guards" do
- let(:resource) {
+ let(:resource) do
resource = script_resource
resource.run_context = run_context
- resource.code 'echo hi'
+ resource.code "echo hi"
resource
- }
- let(:node) {
+ end
+ let(:node) do
node = Chef::Node.new
node.automatic[:platform] = "debian"
node.automatic[:platform_version] = "6.0"
node
- }
+ end
let(:events) { Chef::EventDispatch::Dispatcher.new }
let(:run_context) { Chef::RunContext.new(node, {}, events) }
@@ -83,7 +83,7 @@ shared_examples_for "a script resource" do
expect_any_instance_of(Chef::Resource::Conditional).not_to receive(:evaluate_block)
expect_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).not_to receive(:evaluate_action)
expect_any_instance_of(Chef::GuardInterpreter::DefaultGuardInterpreter).to receive(:evaluate).and_return(true)
- resource.only_if 'echo hi'
+ resource.only_if "echo hi"
expect(resource.should_skip?(:run)).to eq(nil)
end
@@ -91,7 +91,7 @@ shared_examples_for "a script resource" do
expect_any_instance_of(Chef::GuardInterpreter::DefaultGuardInterpreter).not_to receive(:evaluate)
expect_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(true)
resource.guard_interpreter :script
- resource.only_if 'echo hi'
+ resource.only_if "echo hi"
expect(resource.should_skip?(:run)).to eq(nil)
end
end
diff --git a/spec/support/shared/unit/user_and_client_shared.rb b/spec/support/shared/unit/user_and_client_shared.rb
index bc5ffa07c2..6c31ca22d1 100644
--- a/spec/support/shared/unit/user_and_client_shared.rb
+++ b/spec/support/shared/unit/user_and_client_shared.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,7 +27,7 @@ shared_examples_for "user or client create" do
it "creates a new object via the API with a public_key when it exists" do
object.public_key "some_public_key"
- expect(rest_v1).to receive(:post).with(url, payload.merge({:public_key => "some_public_key"})).and_return({})
+ expect(rest_v1).to receive(:post).with(url, payload.merge({ :public_key => "some_public_key" })).and_return({})
object.create
end
@@ -49,19 +49,19 @@ shared_examples_for "user or client create" do
end
it "creates a new object via the API with create_key" do
- expect(rest_v1).to receive(:post).with(url, payload.merge({:create_key => true})).and_return({})
+ expect(rest_v1).to receive(:post).with(url, payload.merge({ :create_key => true })).and_return({})
object.create
end
end
context "when chef_key is returned by the server" do
- let(:chef_key) {
+ let(:chef_key) do
{
"chef_key" => {
- "public_key" => "some_public_key"
- }
+ "public_key" => "some_public_key",
+ },
}
- }
+ end
it "puts the public key into the objectr returned by create" do
expect(rest_v1).to receive(:post).with(url, payload).and_return(payload.merge(chef_key))
@@ -70,14 +70,14 @@ shared_examples_for "user or client create" do
end
context "when private_key is returned in chef_key" do
- let(:chef_key) {
+ let(:chef_key) do
{
"chef_key" => {
"public_key" => "some_public_key",
- "private_key" => "some_private_key"
- }
+ "private_key" => "some_private_key",
+ },
}
- }
+ end
it "puts the private key into the object returned by create" do
expect(rest_v1).to receive(:post).with(url, payload).and_return(payload.merge(chef_key))
@@ -104,7 +104,7 @@ shared_examples_for "user or client create" do
it "creates a new object via the API with a public_key when it exists" do
object.public_key "some_public_key"
- expect(rest_v0).to receive(:post).with(url, payload.merge({:public_key => "some_public_key"})).and_return({})
+ expect(rest_v0).to receive(:post).with(url, payload.merge({ :public_key => "some_public_key" })).and_return({})
object.create
end
@@ -112,4 +112,3 @@ shared_examples_for "user or client create" do
end # when server API V1 is not valid on the Chef Server receiving the request
end # user or client create
-
diff --git a/spec/support/shared/unit/windows_script_resource.rb b/spec/support/shared/unit/windows_script_resource.rb
index a2fc884ff2..5b559bb83b 100644
--- a/spec/support/shared/unit/windows_script_resource.rb
+++ b/spec/support/shared/unit/windows_script_resource.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'support/shared/unit/execute_resource'
-require 'support/shared/unit/script_resource'
+require "support/shared/unit/execute_resource"
+require "support/shared/unit/script_resource"
shared_examples_for "a Windows script resource" do
before(:each) do
@@ -51,7 +51,7 @@ shared_examples_for "a Windows script resource" do
it "should use a resource to evaluate the guard when guard_interpreter is not specified" do
expect_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(true)
expect_any_instance_of(Chef::GuardInterpreter::DefaultGuardInterpreter).not_to receive(:evaluate)
- @resource.only_if 'echo hi'
+ @resource.only_if "echo hi"
expect(@resource.should_skip?(:run)).to eq(nil)
end
@@ -64,7 +64,7 @@ shared_examples_for "a Windows script resource" do
it "should raise an exception if the guard_interpreter is overridden from its default value" do
@resource.guard_interpreter :bash
@resource.only_if { true }
- expect { @resource.should_skip?(:run) }.to raise_error
+ expect { @resource.should_skip?(:run) }.to raise_error(ArgumentError)
end
end
end
@@ -78,4 +78,3 @@ shared_examples_for "a Windows script resource" do
end
end
-
diff --git a/spec/tiny_server.rb b/spec/tiny_server.rb
index a2cfe168d5..83c5bf4a42 100644
--- a/spec/tiny_server.rb
+++ b/spec/tiny_server.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,97 +16,86 @@
# limitations under the License.
#
-require 'rubygems'
-require 'webrick'
-require 'webrick/https'
-require 'rack'
-#require 'thin'
-require 'singleton'
-require 'open-uri'
-require 'chef/config'
+require "rubygems"
+require "webrick"
+require "webrick/https"
+require "rack"
+require "thread"
+require "singleton"
+require "open-uri"
+require "chef/config"
module TinyServer
- class Server < Rack::Server
-
- attr_writer :app
-
- def self.setup(options=nil, &block)
- tiny_app = new(options)
- app_code = Rack::Builder.new(&block).to_app
- tiny_app.app = app_code
- tiny_app
- end
-
- def shutdown
- server.shutdown
- end
- end
-
class Manager
# 5 == debug, 3 == warning
LOGGER = WEBrick::Log.new(STDOUT, 3)
DEFAULT_OPTIONS = {
- :server => 'webrick',
- :Port => 9000,
- :Host => 'localhost',
- :environment => :none,
- :Logger => LOGGER,
- :AccessLog => [] # Remove this option to enable the access log when debugging.
+ Port: 9000,
+ Host: "localhost",
+ Logger: LOGGER,
+ # SSLEnable: options[:ssl],
+ # SSLCertName: [ [ 'CN', WEBrick::Utils::getservername ] ],
+ AccessLog: [], # Remove this option to enable the access log when debugging.
}
- def initialize(options=nil)
- @options = options ? DEFAULT_OPTIONS.merge(options) : DEFAULT_OPTIONS
+ def initialize(**options)
+ @options = DEFAULT_OPTIONS.merge(options)
@creator = caller.first
end
- def start
+ attr_reader :options
+ attr_reader :creator
+ attr_reader :server
+
+ def start(timeout = 5)
+ raise "Server already started!" if server
+
+ # Create the server (but don't start yet)
+ start_queue = Queue.new
+ @server = create_server(StartCallback: proc { start_queue << true })
+
@server_thread = Thread.new do
- @server = Server.setup(@options) do
- run API.instance
- end
- @server.start
+ # Ensure any exceptions will cause the main rspec thread to fail too
+ Thread.current.abort_on_exception = true
+ server.start
end
- block_until_started
- end
- def url
- "http://localhost:#{@options[:Port]}"
+ # Wait for the StartCallback to tell us we've started
+ Timeout.timeout(timeout) do
+ start_queue.pop
+ end
end
- def block_until_started
- 200.times do
- if started? && !@server.nil?
- return true
+ def stop(timeout = 5)
+ if server
+ server.shutdown
+ @server = nil
+ end
+
+ if server_thread
+ begin
+ # Wait for a normal shutdown
+ server_thread.join(timeout)
+ rescue
+ # If it wouldn't shut down normally, kill it.
+ server_thread.kill
+ server_thread.join(timeout)
end
+ @server_thread = nil
end
- raise "ivar weirdness" if started? && @server.nil?
- raise "TinyServer failed to boot :/"
end
- def started?
- open(url)
- true
- rescue OpenURI::HTTPError
- true
- rescue Errno::ECONNREFUSED, EOFError, Errno::ECONNRESET => e
- sleep 0.1
- # If the host has ":::1 localhost" in its hosts file and if IPv6
- # is not enabled we can get NetworkUnreachable exception...
- rescue Errno::ENETUNREACH => e
- sleep 0.1
- false
- end
+ private
- def stop
- # yes, this is terrible.
- @server.shutdown
- @server_thread.kill
- @server_thread.join
- @server_thread = nil
- end
+ attr_reader :server_thread
+ def create_server(**extra_options)
+ server = WEBrick::HTTPServer.new(**options, **extra_options)
+ server.mount("/", Rack::Handler::WEBrick, API.instance)
+ server
+ end
end
class API
@@ -124,22 +113,22 @@ module TinyServer
end
def clear
- @routes = {GET => [], PUT => [], POST => [], DELETE => []}
+ @routes = { GET => [], PUT => [], POST => [], DELETE => [] }
end
- def get(path, response_code, data=nil, headers=nil, &block)
+ def get(path, response_code, data = nil, headers = nil, &block)
@routes[GET] << Route.new(path, Response.new(response_code, data, headers, &block))
end
- def put(path, response_code, data=nil, headers=nil, &block)
+ def put(path, response_code, data = nil, headers = nil, &block)
@routes[PUT] << Route.new(path, Response.new(response_code, data, headers, &block))
end
- def post(path, response_code, data=nil, headers=nil, &block)
+ def post(path, response_code, data = nil, headers = nil, &block)
@routes[POST] << Route.new(path, Response.new(response_code, data, headers, &block))
end
- def delete(path, response_code, data=nil, headers=nil, &block)
+ def delete(path, response_code, data = nil, headers = nil, &block)
@routes[DELETE] << Route.new(path, Response.new(response_code, data, headers, &block))
end
@@ -147,11 +136,11 @@ module TinyServer
if response = response_for_request(env)
response.call
else
- debug_info = {:message => "no data matches the request for #{env['REQUEST_URI']}",
- :available_routes => @routes, :request => env}
+ debug_info = { :message => "no data matches the request for #{env['REQUEST_URI']}",
+ :available_routes => @routes, :request => env }
# Uncomment me for glorious debugging
# pp :not_found => debug_info
- [404, {'Content-Type' => 'application/json'}, [ Chef::JSONCompat.to_json(debug_info) ]]
+ [404, { "Content-Type" => "application/json" }, [ Chef::JSONCompat.to_json(debug_info) ]]
end
end
@@ -181,9 +170,9 @@ module TinyServer
end
class Response
- HEADERS = {'Content-Type' => 'application/json'}
+ HEADERS = { "Content-Type" => "application/json" }
- def initialize(response_code=200, data=nil, headers=nil, &block)
+ def initialize(response_code = 200, data = nil, headers = nil, &block)
@response_code, @data = response_code, data
@response_headers = headers ? HEADERS.merge(headers) : HEADERS
@block = block_given? ? block : nil
@@ -195,7 +184,7 @@ module TinyServer
end
def to_s
- "#{@response_code} => #{(@data|| @block)}"
+ "#{@response_code} => #{(@data || @block)}"
end
end
diff --git a/spec/unit/api_client/registration_spec.rb b/spec/unit/api_client/registration_spec.rb
index d6230afb6a..0f036766da 100644
--- a/spec/unit/api_client/registration_spec.rb
+++ b/spec/unit/api_client/registration_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tempfile'
+require "spec_helper"
+require "tempfile"
-require 'chef/api_client/registration'
+require "chef/api_client/registration"
describe Chef::ApiClient::Registration do
@@ -32,10 +32,10 @@ describe Chef::ApiClient::Registration do
subject(:registration) { Chef::ApiClient::Registration.new(client_name, key_location) }
let(:private_key_data) do
- File.open(Chef::Config[:validation_key], "r") {|f| f.read.chomp }
+ File.open(Chef::Config[:validation_key], "r") { |f| f.read.chomp }
end
- let(:http_mock) { double("Chef::REST mock") }
+ let(:http_mock) { double("Chef::ServerAPI mock") }
let(:expected_post_data) do
{ :name => client_name, :admin => false, :public_key => generated_public_key.to_pem }
@@ -46,8 +46,10 @@ describe Chef::ApiClient::Registration do
end
let(:server_v10_response) do
- {"uri" => "https://chef.local/clients/#{client_name}",
- "private_key" => "--begin rsa key etc--"}
+ {
+ "uri" => "https://chef.local/clients/#{client_name}",
+ "private_key" => "--begin rsa key etc--",
+ }
end
# Server v11 includes `json_class` on all replies
@@ -61,30 +63,31 @@ describe Chef::ApiClient::Registration do
let(:response_409) { Net::HTTPConflict.new("1.1", "409", "Conflict") }
let(:exception_409) { Net::HTTPServerException.new("409 conflict", response_409) }
- let(:generated_private_key_pem) { IO.read(File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)) }
+ let(:generated_private_key_pem) { IO.read(File.expand_path("ssl/private_key.pem", CHEF_SPEC_DATA)) }
let(:generated_private_key) { OpenSSL::PKey::RSA.new(generated_private_key_pem) }
let(:generated_public_key) { generated_private_key.public_key }
-
let(:create_with_pkey_response) do
{
"uri" => "",
- "public_key" => generated_public_key.to_pem
+ "chef_key" => {
+ "public_key" => generated_public_key.to_pem,
+ },
}
end
let(:update_with_pkey_response) do
- {"name"=>client_name,
- "admin"=>false,
- "public_key"=> generated_public_key,
- "validator"=>false,
- "private_key"=>false,
- "clientname"=>client_name}
+ { "name" => client_name,
+ "admin" => false,
+ "public_key" => generated_public_key,
+ "validator" => false,
+ "private_key" => false,
+ "clientname" => client_name }
end
before do
Chef::Config[:validation_client_name] = "test-validator"
- Chef::Config[:validation_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)
+ Chef::Config[:validation_key] = File.expand_path("ssl/private_key.pem", CHEF_SPEC_DATA)
allow(OpenSSL::PKey::RSA).to receive(:generate).with(2048).and_return(generated_private_key)
end
@@ -93,9 +96,10 @@ describe Chef::ApiClient::Registration do
end
it "has an HTTP client configured with validator credentials" do
- expect(registration.http_api).to be_a_kind_of(Chef::REST)
- expect(registration.http_api.client_name).to eq("test-validator")
- expect(registration.http_api.signing_key).to eq(private_key_data)
+ expect(registration.http_api).to be_a_kind_of(Chef::ServerAPI)
+ expect(registration.http_api.options[:client_name]).to eq("test-validator")
+ auth = registration.http_api.middlewares.find { |klass| klass.kind_of? Chef::HTTP::Authenticator }
+ expect(auth.client_name).to eq("test-validator")
end
describe "when creating/updating the client on the server" do
@@ -107,8 +111,8 @@ describe Chef::ApiClient::Registration do
expect(http_mock).to receive(:post).
with("clients", expected_post_data).
and_return(create_with_pkey_response)
- expect(registration.create_or_update).to eq(create_with_pkey_response)
- expect(registration.private_key).to eq(generated_private_key_pem)
+ expect(registration.run.public_key).to eq(create_with_pkey_response["chef_key"]["public_key"])
+ expect(OpenSSL::PKey::RSA.new(registration.private_key).to_s).to eq(OpenSSL::PKey::RSA.new(generated_private_key_pem).to_s)
end
it "puts a locally generated public key to the server to update a client" do
@@ -118,8 +122,8 @@ describe Chef::ApiClient::Registration do
expect(http_mock).to receive(:put).
with("clients/#{client_name}", expected_put_data).
and_return(update_with_pkey_response)
- expect(registration.create_or_update).to eq(update_with_pkey_response)
- expect(registration.private_key).to eq(generated_private_key_pem)
+ expect(registration.run.public_key).to eq(update_with_pkey_response["public_key"].to_pem)
+ expect(OpenSSL::PKey::RSA.new(registration.private_key).to_s).to eq(OpenSSL::PKey::RSA.new(generated_private_key_pem).to_s)
end
it "writes the generated private key to disk" do
@@ -127,7 +131,7 @@ describe Chef::ApiClient::Registration do
with("clients", expected_post_data).
and_return(create_with_pkey_response)
registration.run
- expect(IO.read(key_location)).to eq(generated_private_key_pem)
+ expect(OpenSSL::PKey::RSA.new(IO.read(key_location)).to_s).to eq(OpenSSL::PKey::RSA.new(generated_private_key_pem).to_s)
end
context "and the client already exists on a Chef 11 server" do
@@ -136,8 +140,8 @@ describe Chef::ApiClient::Registration do
expect(http_mock).to receive(:put).
with("clients/#{client_name}", expected_put_data).
and_return(update_with_pkey_response)
- expect(registration.create_or_update).to eq(update_with_pkey_response)
- expect(registration.private_key).to eq(generated_private_key_pem)
+ expect(registration.run.public_key).to eq(update_with_pkey_response["public_key"].to_pem)
+ expect(OpenSSL::PKey::RSA.new(registration.private_key).to_s).to eq(OpenSSL::PKey::RSA.new(generated_private_key_pem).to_s)
end
end
@@ -160,7 +164,7 @@ describe Chef::ApiClient::Registration do
expect(http_mock).to receive(:post).
with("clients", expected_post_data).
and_return(server_v10_response)
- expect(registration.create_or_update).to eq(server_v10_response)
+ expect(registration.run.private_key).to eq(server_v10_response["private_key"])
expect(registration.private_key).to eq("--begin rsa key etc--")
end
@@ -170,7 +174,7 @@ describe Chef::ApiClient::Registration do
expect(http_mock).to receive(:put).
with("clients/#{client_name}", expected_put_data).
and_return(server_v11_response)
- expect(registration.create_or_update).to eq(server_v11_response)
+ expect(registration.run).to eq(server_v11_response)
expect(registration.private_key).to eq("--begin rsa key etc--")
end
end
@@ -182,7 +186,7 @@ describe Chef::ApiClient::Registration do
expect(http_mock).to receive(:put).
with("clients/#{client_name}", expected_put_data).
and_return(server_v10_response)
- expect(registration.create_or_update).to eq(server_v10_response)
+ expect(registration.run.private_key).to eq(server_v10_response["private_key"])
expect(registration.private_key).to eq("--begin rsa key etc--")
end
end
@@ -191,7 +195,7 @@ describe Chef::ApiClient::Registration do
describe "when writing the private key to disk" do
before do
- allow(registration).to receive(:private_key).and_return('--begin rsa key etc--')
+ allow(registration).to receive(:private_key).and_return("--begin rsa key etc--")
end
# Permission read via File.stat is busted on windows, though creating the
@@ -210,9 +214,9 @@ describe Chef::ApiClient::Registration do
expect(IO.read(key_location)).to eq("--begin rsa key etc--")
end
- context 'when the client key location is a symlink' do
- it 'does not follow the symlink', :unix_only do
- expected_flags = (File::CREAT|File::TRUNC|File::RDWR)
+ context "when the client key location is a symlink" do
+ it "does not follow the symlink", :unix_only do
+ expected_flags = (File::CREAT | File::TRUNC | File::RDWR)
if defined?(File::NOFOLLOW)
expected_flags |= File::NOFOLLOW
@@ -221,13 +225,13 @@ describe Chef::ApiClient::Registration do
expect(registration.file_flags).to eq(expected_flags)
end
- context 'with follow_client_key_symlink set to true' do
+ context "with follow_client_key_symlink set to true" do
before do
Chef::Config[:follow_client_key_symlink] = true
end
- it 'follows the symlink', :unix_only do
- expect(registration.file_flags).to eq(File::CREAT|File::TRUNC|File::RDWR)
+ it "follows the symlink", :unix_only do
+ expect(registration.file_flags).to eq(File::CREAT | File::TRUNC | File::RDWR)
end
end
end
@@ -242,7 +246,7 @@ describe Chef::ApiClient::Registration do
it "creates the client on the server and writes the key" do
expect(http_mock).to receive(:post).ordered.and_return(server_v10_response)
registration.run
- expect(IO.read(key_location)).to eq(generated_private_key_pem)
+ expect(OpenSSL::PKey::RSA.new(IO.read(key_location)).to_s).to eq(OpenSSL::PKey::RSA.new(generated_private_key_pem).to_s)
end
it "retries up to 5 times" do
@@ -257,7 +261,7 @@ describe Chef::ApiClient::Registration do
expect(http_mock).to receive(:post).ordered.and_return(server_v10_response)
registration.run
- expect(IO.read(key_location)).to eq(generated_private_key_pem)
+ expect(OpenSSL::PKey::RSA.new(IO.read(key_location)).to_s).to eq(OpenSSL::PKey::RSA.new(generated_private_key_pem).to_s)
end
it "gives up retrying after the max attempts" do
@@ -266,7 +270,7 @@ describe Chef::ApiClient::Registration do
expect(http_mock).to receive(:post).exactly(6).times.and_raise(exception_500)
- expect {registration.run}.to raise_error(Net::HTTPFatalError)
+ expect { registration.run }.to raise_error(Net::HTTPFatalError)
end
end
diff --git a/spec/unit/api_client_spec.rb b/spec/unit/api_client_spec.rb
index a0e399b470..a8ac4f747b 100644
--- a/spec/unit/api_client_spec.rb
+++ b/spec/unit/api_client_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/api_client'
-require 'tempfile'
+require "chef/api_client"
+require "tempfile"
# DEPRECATION NOTE
#
@@ -82,7 +82,6 @@ describe Chef::ApiClient do
expect { @client.public_key Hash.new }.to raise_error(ArgumentError)
end
-
it "has a private key attribute" do
@client.private_key("super private")
expect(@client.private_key).to eq("super private")
@@ -176,12 +175,12 @@ describe Chef::ApiClient do
"private_key" => "monkeypants",
"admin" => true,
"validator" => true,
- "json_class" => "Chef::ApiClient"
+ "json_class" => "Chef::ApiClient",
}
end
let(:client) do
- Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(client_hash))
+ Chef::ApiClient.from_hash(Chef::JSONCompat.parse(Chef::JSONCompat.to_json(client_hash)))
end
it "should deserialize to a Chef::ApiClient object" do
@@ -221,12 +220,12 @@ describe Chef::ApiClient do
"private_key" => "monkeypants",
"admin" => true,
"validator" => true,
- "json_class" => "Chef::ApiClient"
+ "json_class" => "Chef::ApiClient",
}
@http_client = double("Chef::ServerAPI mock")
allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
expect(@http_client).to receive(:get).with("clients/black").and_return(client)
- @client = Chef::ApiClient.load(client['name'])
+ @client = Chef::ApiClient.load(client["name"])
end
it "should deserialize to a Chef::ApiClient object" do
@@ -258,7 +257,7 @@ describe Chef::ApiClient do
describe "with correctly configured API credentials" do
before do
Chef::Config[:node_name] = "silent-bob"
- Chef::Config[:client_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)
+ Chef::Config[:client_key] = File.expand_path("ssl/private_key.pem", CHEF_SPEC_DATA)
end
after do
@@ -267,15 +266,14 @@ describe Chef::ApiClient do
end
let :private_key_data do
- File.open(Chef::Config[:client_key], "r") {|f| f.read.chomp }
+ File.open(Chef::Config[:client_key], "r") { |f| f.read.chomp }
end
end
-
describe "when requesting a new key" do
before do
- @http_client = double("Chef::REST mock")
+ @http_client = double("Chef::ServerAPI mock")
allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
end
@@ -299,7 +297,6 @@ describe Chef::ApiClient do
expect(@http_client).to receive(:get).with("clients/lost-my-key").and_return(@api_client_without_key)
end
-
context "and the client exists on a Chef 11-like server" do
before do
@api_client_with_key = Chef::ApiClient.new
@@ -322,7 +319,7 @@ describe Chef::ApiClient do
context "and the client exists on a Chef 10-like server" do
before do
- @api_client_with_key = {"name" => "lost-my-key", "private_key" => "the new private key"}
+ @api_client_with_key = { "name" => "lost-my-key", "private_key" => "the new private key" }
expect(@http_client).to receive(:put).
with("clients/lost-my-key", :name => "lost-my-key", :admin => false, :validator => false, :private_key => true).
and_return(@api_client_with_key)
diff --git a/spec/unit/api_client_v1_spec.rb b/spec/unit/api_client_v1_spec.rb
index 17aba8c3af..9c643fa492 100644
--- a/spec/unit/api_client_v1_spec.rb
+++ b/spec/unit/api_client_v1_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/api_client_v1'
-require 'tempfile'
+require "chef/api_client_v1"
+require "tempfile"
describe Chef::ApiClientV1 do
before(:each) do
@@ -91,7 +91,6 @@ describe Chef::ApiClientV1 do
expect { @client.public_key Hash.new }.to raise_error(ArgumentError)
end
-
it "has a private key attribute" do
@client.private_key("super private")
expect(@client.private_key).to eq("super private")
@@ -199,7 +198,7 @@ describe Chef::ApiClientV1 do
"private_key" => "monkeypants",
"admin" => true,
"validator" => true,
- "create_key" => true
+ "create_key" => true,
}
end
@@ -248,13 +247,13 @@ describe Chef::ApiClientV1 do
"private_key" => "monkeypants",
"admin" => true,
"create_key" => true,
- "validator" => true
+ "validator" => true,
}
@http_client = double("Chef::ServerAPI mock")
allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
expect(@http_client).to receive(:get).with("clients/black").and_return(client)
- @client = Chef::ApiClientV1.load(client['name'])
+ @client = Chef::ApiClientV1.load(client["name"])
end
it "should deserialize to a Chef::ApiClientV1 object" do
@@ -290,7 +289,7 @@ describe Chef::ApiClientV1 do
describe "with correctly configured API credentials" do
before do
Chef::Config[:node_name] = "silent-bob"
- Chef::Config[:client_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)
+ Chef::Config[:client_key] = File.expand_path("ssl/private_key.pem", CHEF_SPEC_DATA)
end
after do
@@ -299,12 +298,11 @@ describe Chef::ApiClientV1 do
end
let :private_key_data do
- File.open(Chef::Config[:client_key], "r") {|f| f.read.chomp }
+ File.open(Chef::Config[:client_key], "r") { |f| f.read.chomp }
end
end
-
describe "when requesting a new key" do
before do
@http_client = double("Chef::ServerAPI mock")
@@ -326,20 +324,20 @@ describe Chef::ApiClientV1 do
end
describe "Versioned API Interactions" do
- let(:response_406) { OpenStruct.new(:code => '406') }
+ let(:response_406) { OpenStruct.new(:code => "406") }
let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) }
- let(:payload) {
+ let(:payload) do
{
:name => "some_name",
:validator => true,
- :admin => true
+ :admin => true,
}
- }
+ end
before do
@client = Chef::ApiClientV1.new
- allow(@client).to receive(:chef_rest_v0).and_return(double('chef rest root v0 object'))
- allow(@client).to receive(:chef_rest_v1).and_return(double('chef rest root v1 object'))
+ allow(@client).to receive(:chef_rest_v0).and_return(double("chef rest root v0 object"))
+ allow(@client).to receive(:chef_rest_v1).and_return(double("chef rest root v1 object"))
@client.name "some_name"
@client.validator true
@client.admin true
@@ -391,7 +389,7 @@ describe Chef::ApiClientV1 do
end
it "updates the client with only the name" do
- expect(rest). to receive(:put).with("clients/some_name", {:name => "some_name"}).and_return({:name => "some_name"})
+ expect(rest). to receive(:put).with("clients/some_name", { :name => "some_name" }).and_return({ :name => "some_name" })
@client.update
end
end
@@ -439,7 +437,7 @@ describe Chef::ApiClientV1 do
describe "reregister" do
context "when server API V0 is valid on the Chef Server receiving the request" do
it "creates a new object via the API" do
- expect(@client.chef_rest_v0).to receive(:put).with("clients/#{@client.name}", payload.merge({:private_key => true})).and_return({})
+ expect(@client.chef_rest_v0).to receive(:put).with("clients/#{@client.name}", payload.merge({ :private_key => true })).and_return({})
@client.reregister
end
end # when server API V0 is valid on the Chef Server receiving the request
diff --git a/spec/unit/application/apply_spec.rb b/spec/unit/application/apply_spec.rb
index f6cd0bae03..0af3916134 100644
--- a/spec/unit/application/apply_spec.rb
+++ b/spec/unit/application/apply_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan W. Berry (<bryan.berry@gmail.com>)
-# Copyright:: Copyright (c) 2012 Bryan W. Berry
+# Copyright:: Copyright 2012-2016, Bryan W. Berry
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,21 +15,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
+require "spec_helper"
describe Chef::Application::Apply do
before do
@app = Chef::Application::Apply.new
allow(@app).to receive(:configure_logging).and_return(true)
+ allow(Chef::Log).to receive(:debug).with("FIPS mode is enabled.")
@recipe_text = "package 'nyancat'"
- Chef::Config[:solo] = true
+ Chef::Config[:solo_legacy_mode] = true
end
describe "configuring the application" do
it "should set solo mode to true" do
@app.reconfigure
- expect(Chef::Config[:solo]).to be_truthy
+ expect(Chef::Config[:solo_legacy_mode]).to be_truthy
end
end
describe "read_recipe_file" do
@@ -51,7 +52,8 @@ describe Chef::Application::Apply do
describe "when recipe is nil" do
it "should raise a fatal with the missing filename message" do
- expect(Chef::Application).to receive(:fatal!).with("No recipe file was provided", 1)
+ expect(Chef::Application).to receive(:fatal!).with("No recipe file was provided",
+ Chef::Exceptions::RecipeNotFound.new)
@app.read_recipe_file(nil)
end
end
@@ -60,7 +62,8 @@ describe Chef::Application::Apply do
allow(File).to receive(:exist?).with(@recipe_path).and_return(false)
end
it "should raise a fatal with the file doesn't exist message" do
- expect(Chef::Application).to receive(:fatal!).with(/^No file exists at/, 1)
+ expect(Chef::Application).to receive(:fatal!).with(/^No file exists at/,
+ Chef::Exceptions::RecipeNotFound.new)
@app.read_recipe_file(@recipe_file_name)
end
end
@@ -92,7 +95,7 @@ describe Chef::Application::Apply do
end
describe "when the json_attribs configuration option is specified" do
- let(:json_attribs) { {"a" => "b"} }
+ let(:json_attribs) { { "a" => "b" } }
let(:config_fetcher) { double(Chef::ConfigFetcher, :fetch_json => json_attribs) }
let(:json_source) { "https://foo.com/foo.json" }
diff --git a/spec/unit/application/client_spec.rb b/spec/unit/application/client_spec.rb
index 727536f1f8..30fc58b84c 100644
--- a/spec/unit/application/client_spec.rb
+++ b/spec/unit/application/client_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@junglist.gen.nz>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,56 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
+require "spec_helper"
+
+shared_context "with signal handlers" do
+ before do
+ Chef::Config[:specific_recipes] = [] # normally gets set in @app.reconfigure
+
+ @app = Chef::Application::Client.new
+ @app.setup_signal_handlers
+ # Default logger doesn't work correctly when logging from a trap handler.
+ @app.configure_logging
+ end
+end
+
+shared_context "with interval_sleep" do
+ before do
+ run_count = 0
+
+ # uncomment to debug failures...
+ # Chef::Log.init($stderr)
+ # Chef::Log.level = :debug
+
+ allow(@app).to receive(:run_chef_client) do
+ run_count += 1
+ if run_count > 3
+ exit 0
+ end
+
+ # If everything is fine, sending USR1 to self should prevent
+ # app to go into splay sleep forever.
+ Process.kill("USR1", Process.pid)
+ # On Ruby < 2.1, we need to give the signal handlers a little
+ # more time, otherwise the test will fail because interleavings.
+ sleep 1
+ end
+
+ number_of_sleep_calls = 0
+
+ # This is a very complicated way of writing
+ # @app.should_receive(:sleep).once.
+ # We have to do it this way because the main loop of
+ # Chef::Application::Client swallows most exceptions, and we need to be
+ # able to expose our expectation failures to the parent process in the test.
+ allow(@app).to receive(:interval_sleep) do |arg|
+ number_of_sleep_calls += 1
+ if number_of_sleep_calls > 1
+ exit 127
+ end
+ end
+ end
+end
describe Chef::Application::Client, "reconfigure" do
let(:app) do
@@ -25,7 +74,10 @@ describe Chef::Application::Client, "reconfigure" do
end
before do
+ Chef::Config.reset
+
allow(Kernel).to receive(:trap).and_return(:ok)
+ allow(::File).to receive(:read).and_call_original
allow(::File).to receive(:read).with(Chef::Config.platform_specific_path("/etc/chef/client.rb")).and_return("")
@original_argv = ARGV.dup
@@ -36,29 +88,93 @@ describe Chef::Application::Client, "reconfigure" do
Chef::Config[:interval] = 10
Chef::Config[:once] = false
+
+ # protect the unit tests against accidental --delete-entire-chef-repo from firing
+ # for real during tests. DO NOT delete this line.
+ expect(FileUtils).not_to receive(:rm_rf)
end
after do
ARGV.replace(@original_argv)
end
- describe 'parse cli_arguments' do
- it 'should call set_specific_recipes' do
+ describe "parse cli_arguments" do
+ it "should call set_specific_recipes" do
expect(app).to receive(:set_specific_recipes).and_return(true)
app.reconfigure
end
- context "when given a named_run_list" do
+ shared_examples "sets the configuration" do |cli_arguments, expected_config|
+ describe cli_arguments do
+ before do
+ ARGV.replace(cli_arguments.split)
+ app.reconfigure
+ end
- before do
- ARGV.replace( %w[ --named-run-list arglebargle-example ] )
- app.reconfigure
+ it "sets #{expected_config}" do
+ expect(Chef::Config.configuration).to include expected_config
+ end
+ end
+ end
+
+ describe "--named-run-list" do
+ it_behaves_like "sets the configuration",
+ "--named-run-list arglebargle-example",
+ :named_run_list => "arglebargle-example"
+ end
+
+ describe "--no-listen" do
+ it_behaves_like "sets the configuration", "--no-listen", :listen => false
+ end
+
+ describe "--daemonize", :unix_only do
+ context "with no value" do
+ it_behaves_like "sets the configuration", "--daemonize",
+ :daemonize => true
end
- it "sets named_run_list in Chef::Config" do
- expect(Chef::Config[:named_run_list]).to eq("arglebargle-example")
+ context "with an integer value" do
+ it_behaves_like "sets the configuration", "--daemonize 5",
+ :daemonize => 5
+ end
+
+ context "with a non-integer value" do
+ it_behaves_like "sets the configuration", "--daemonize foo",
+ :daemonize => true
+ end
+ end
+
+ describe "--config-option" do
+ context "with a single value" do
+ it_behaves_like "sets the configuration", "--config-option chef_server_url=http://example",
+ :chef_server_url => "http://example"
+ end
+
+ context "with two values" do
+ it_behaves_like "sets the configuration", "--config-option chef_server_url=http://example --config-option policy_name=web",
+ :chef_server_url => "http://example", :policy_name => "web"
+ end
+
+ context "with a boolean value" do
+ it_behaves_like "sets the configuration", "--config-option minimal_ohai=true",
+ :minimal_ohai => true
+ end
+
+ context "with an empty value" do
+ it "should terminate with message" do
+ expect(Chef::Application).to receive(:fatal!).with('Unparsable config option ""').and_raise("so ded")
+ ARGV.replace(["--config-option", ""])
+ expect { app.reconfigure }.to raise_error "so ded"
+ end
end
+ context "with an invalid value" do
+ it "should terminate with message" do
+ expect(Chef::Application).to receive(:fatal!).with('Unparsable config option "asdf"').and_raise("so ded")
+ ARGV.replace(["--config-option", "asdf"])
+ expect { app.reconfigure }.to raise_error "so ded"
+ end
+ end
end
end
@@ -112,15 +228,46 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
end
end
- describe "when in daemonized mode and no interval has been set" do
+ describe "daemonized mode", :unix_only do
+ let(:daemonize) { true }
+
before do
- Chef::Config[:daemonize] = true
- Chef::Config[:interval] = nil
+ Chef::Config[:daemonize] = daemonize
+ allow(Chef::Daemon).to receive(:daemonize)
end
- it "should set the interval to 1800" do
- app.reconfigure
- expect(Chef::Config.interval).to eq(1800)
+ context "when no interval has been set" do
+ before do
+ Chef::Config[:interval] = nil
+ end
+
+ it "should set the interval to 1800" do
+ app.reconfigure
+ expect(Chef::Config.interval).to eq(1800)
+ end
+ end
+
+ context "when the daemonize option is an integer" do
+ include_context "with signal handlers"
+ include_context "with interval_sleep"
+
+ let(:wait_secs) { 1 }
+ let(:daemonize) { wait_secs }
+
+ before do
+ allow(@app).to receive(:interval_sleep).with(wait_secs).and_return true
+ allow(@app).to receive(:interval_sleep).with(0).and_call_original
+ end
+
+ it "sleeps for the amount of time passed" do
+ pid = fork do
+ expect(@app).to receive(:interval_sleep).with(wait_secs)
+ @app.run_application
+ end
+ _pid, result = Process.waitpid2(pid)
+
+ expect(result.exitstatus).to eq 0
+ end
end
end
@@ -144,19 +291,9 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
end
- describe "when --no-listen is set" do
-
- it "configures listen = false" do
- app.config[:listen] = false
- app.reconfigure
- expect(Chef::Config[:listen]).to eq(false)
- end
-
- end
-
describe "when the json_attribs configuration option is specified" do
- let(:json_attribs) { {"a" => "b"} }
+ let(:json_attribs) { { "a" => "b" } }
let(:config_fetcher) { double(Chef::ConfigFetcher, :fetch_json => json_attribs) }
let(:json_source) { "https://foo.com/foo.json" }
@@ -253,8 +390,11 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
expect { app.reconfigure }.to raise_error(Chef::Exceptions::PIDFileLockfileMatch)
end
end
-end
+ it_behaves_like "an application that loads a dot d" do
+ let(:dot_d_config_name) { :client_d_dir }
+ end
+end
describe Chef::Application::Client, "setup_application" do
before do
@@ -298,21 +438,16 @@ describe Chef::Application::Client, "configure_chef" do
end
describe Chef::Application::Client, "run_application", :unix_only do
- before(:each) do
- Chef::Config[:specific_recipes] = [] # normally gets set in @app.reconfigure
-
- @app = Chef::Application::Client.new
- @app.setup_signal_handlers
- # Default logger doesn't work correctly when logging from a trap handler.
- @app.configure_logging
+ include_context "with signal handlers"
+ before(:each) do
@pipe = IO.pipe
@client = Chef::Client.new
allow(Chef::Client).to receive(:new).and_return(@client)
allow(@client).to receive(:run) do
- @pipe[1].puts 'started'
+ @pipe[1].puts "started"
sleep 1
- @pipe[1].puts 'finished'
+ @pipe[1].puts "finished"
end
end
@@ -376,44 +511,11 @@ describe Chef::Application::Client, "run_application", :unix_only do
end
describe "when splay is set" do
+ include_context "with interval_sleep"
+
before do
Chef::Config[:splay] = 10
Chef::Config[:interval] = 10
-
- run_count = 0
-
- # uncomment to debug failures...
- # Chef::Log.init($stderr)
- # Chef::Log.level = :debug
-
- allow(@app).to receive(:run_chef_client) do
-
- run_count += 1
- if run_count > 3
- exit 0
- end
-
- # If everything is fine, sending USR1 to self should prevent
- # app to go into splay sleep forever.
- Process.kill("USR1", Process.pid)
- # On Ruby < 2.1, we need to give the signal handlers a little
- # more time, otherwise the test will fail because interleavings.
- sleep 1
- end
-
- number_of_sleep_calls = 0
-
- # This is a very complicated way of writing
- # @app.should_receive(:sleep).once.
- # We have to do it this way because the main loop of
- # Chef::Application::Client swallows most exceptions, and we need to be
- # able to expose our expectation failures to the parent process in the test.
- allow(@app).to receive(:interval_sleep) do |arg|
- number_of_sleep_calls += 1
- if number_of_sleep_calls > 1
- exit 127
- end
- end
end
it "shouldn't sleep when sent USR1" do
diff --git a/spec/unit/application/exit_code_spec.rb b/spec/unit/application/exit_code_spec.rb
new file mode 100644
index 0000000000..5abf19fc02
--- /dev/null
+++ b/spec/unit/application/exit_code_spec.rb
@@ -0,0 +1,229 @@
+#
+# Author:: Steven Murawski (<smurawski@chef.io>)
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef"
+require "spec_helper"
+
+require "chef/application/exit_code"
+
+describe Chef::Application::ExitCode do
+
+ let(:exit_codes) { Chef::Application::ExitCode }
+
+ let(:valid_rfc_exit_codes) { Chef::Application::ExitCode::VALID_RFC_062_EXIT_CODES.values }
+
+ context "Validates the return codes from RFC 062" do
+
+ before do
+ allow(Chef::Config).to receive(:[]).with(:exit_status).and_return(:enabled)
+ end
+
+ it "validates a SUCCESS return code of 0" do
+ expect(valid_rfc_exit_codes.include?(0)).to eq(true)
+ end
+
+ it "validates a GENERIC_FAILURE return code of 1" do
+ expect(valid_rfc_exit_codes.include?(1)).to eq(true)
+ end
+
+ it "validates a SIGINT_RECEIVED return code of 2" do
+ expect(valid_rfc_exit_codes.include?(2)).to eq(true)
+ end
+
+ it "validates a SIGTERM_RECEIVED return code of 3" do
+ expect(valid_rfc_exit_codes.include?(3)).to eq(true)
+ end
+
+ it "validates a AUDIT_MODE_FAILURE return code of 42" do
+ expect(valid_rfc_exit_codes.include?(42)).to eq(true)
+ end
+
+ it "validates a REBOOT_SCHEDULED return code of 35" do
+ expect(valid_rfc_exit_codes.include?(35)).to eq(true)
+ end
+
+ it "validates a REBOOT_NEEDED return code of 37" do
+ expect(valid_rfc_exit_codes.include?(37)).to eq(true)
+ end
+
+ it "validates a REBOOT_FAILED return code of 41" do
+ expect(valid_rfc_exit_codes.include?(41)).to eq(true)
+ end
+
+ it "validates a CLIENT_UPGRADED return code of 213" do
+ expect(valid_rfc_exit_codes.include?(213)).to eq(true)
+ end
+ end
+
+ context "when Chef::Config :exit_status is not configured" do
+ before do
+ allow(Chef::Config).to receive(:[]).with(:exit_status).and_return(nil)
+ allow(Chef::Config).to receive(:[]).with(:treat_deprecation_warnings_as_errors).and_return(false)
+ end
+
+ it "writes a deprecation warning" do
+ expect(Chef).to receive(:deprecated).with(:exit_code, /^Chef RFC 062/)
+ expect(exit_codes.normalize_exit_code(151)).to eq(151)
+ end
+
+ it "does not modify non-RFC exit codes" do
+ expect(exit_codes.normalize_exit_code(151)).to eq(151)
+ end
+
+ it "returns DEPRECATED_FAILURE when no exit code is specified" do
+ expect(exit_codes.normalize_exit_code()).to eq(-1)
+ end
+
+ it "returns SIGINT_RECEIVED when a SIGINT is received" do
+ expect(exit_codes.normalize_exit_code(Chef::Exceptions::SigInt.new("BOOM"))).to eq(2)
+ end
+
+ it "returns SIGTERM_RECEIVED when a SIGTERM is received" do
+ expect(exit_codes.normalize_exit_code(Chef::Exceptions::SigTerm.new("BOOM"))).to eq(3)
+ end
+
+ it "returns SIGINT_RECEIVED when a deprecated exit code error is received" do
+ expect(exit_codes.normalize_exit_code(Chef::Exceptions::DeprecatedExitCode.new("BOOM"))).to eq(2)
+ end
+
+ it "returns GENERIC_FAILURE when an exception is specified" do
+ expect(exit_codes.normalize_exit_code(Exception.new("BOOM"))).to eq(1)
+ end
+
+ end
+
+ context "when Chef::Config :exit_status is configured to not validate exit codes" do
+ before do
+ allow(Chef::Config).to receive(:[]).with(:exit_status).and_return(:disabled)
+ allow(Chef::Config).to receive(:[]).with(:treat_deprecation_warnings_as_errors).and_return(false)
+ end
+
+ it "does not write a deprecation warning" do
+ expect(Chef).not_to receive(:deprecated).with(:exit_code, /^Chef RFC 062/)
+ expect(exit_codes.normalize_exit_code(151)).to eq(151)
+ end
+
+ it "does not modify non-RFC exit codes" do
+ expect(exit_codes.normalize_exit_code(151)).to eq(151)
+ end
+
+ it "returns DEPRECATED_FAILURE when no exit code is specified" do
+ expect(exit_codes.normalize_exit_code()).to eq(-1)
+ end
+
+ it "returns GENERIC_FAILURE when an exception is specified" do
+ expect(exit_codes.normalize_exit_code(Exception.new("BOOM"))).to eq(1)
+ end
+
+ it "returns SUCCESS when a reboot is pending" do
+ allow(Chef::DSL::RebootPending).to receive(:reboot_pending?).and_return(true)
+ expect(exit_codes.normalize_exit_code(0)).to eq(0)
+ end
+
+ it "returns SIGINT_RECEIVED when a SIGINT is received" do
+ expect(exit_codes.normalize_exit_code(Chef::Exceptions::SigInt.new("BOOM"))).to eq(2)
+ end
+
+ it "returns SIGTERM_RECEIVED when a SIGTERM is received" do
+ expect(exit_codes.normalize_exit_code(Chef::Exceptions::SigTerm.new("BOOM"))).to eq(3)
+ end
+
+ it "returns SIGINT_RECEIVED when a deprecated exit code error is received" do
+ expect(exit_codes.normalize_exit_code(Chef::Exceptions::DeprecatedExitCode.new("BOOM"))).to eq(2)
+ end
+ end
+
+ context "when Chef::Config :exit_status is configured to validate exit codes" do
+ before do
+ allow(Chef::Config).to receive(:[]).with(:exit_status).and_return(:enabled)
+ allow(Chef::Config).to receive(:[]).with(:treat_deprecation_warnings_as_errors).and_return(false)
+ end
+
+ it "does write a deprecation warning" do
+ expect(Chef).to receive(:deprecated).with(:exit_code, /^Chef RFC 062/)
+ expect(exit_codes.normalize_exit_code(151)).to eq(1)
+ end
+
+ it "returns a GENERIC_FAILURE for non-RFC exit codes" do
+ expect(exit_codes.normalize_exit_code(151)).to eq(1)
+ end
+
+ it "returns GENERIC_FAILURE when no exit code is specified" do
+ expect(exit_codes.normalize_exit_code()).to eq(1)
+ end
+
+ it "returns SIGINT_RECEIVED when a SIGINT is received" do
+ expect(exit_codes.normalize_exit_code(Chef::Exceptions::SigInt.new("BOOM"))).to eq(2)
+ end
+
+ it "returns SIGTERM_RECEIVED when a SIGTERM is received" do
+ expect(exit_codes.normalize_exit_code(Chef::Exceptions::SigTerm.new("BOOM"))).to eq(3)
+ end
+
+ it "returns GENERIC_FAILURE when a deprecated exit code error is received" do
+ expect(exit_codes.normalize_exit_code(Chef::Exceptions::DeprecatedExitCode.new("BOOM"))).to eq(1)
+ end
+
+ it "returns GENERIC_FAILURE when an exception is specified" do
+ expect(exit_codes.normalize_exit_code(Exception.new("BOOM"))).to eq(1)
+ end
+
+ it "returns AUDIT_MODE_FAILURE when there is an audit error" do
+ audit_error = Chef::Exceptions::AuditError.new("BOOM")
+ runtime_error = Chef::Exceptions::RunFailedWrappingError.new(audit_error)
+ expect(exit_codes.normalize_exit_code(runtime_error)).to eq(42)
+ end
+
+ it "returns REBOOT_SCHEDULED when there is an reboot requested" do
+ reboot_error = Chef::Exceptions::Reboot.new("BOOM")
+ runtime_error = Chef::Exceptions::RunFailedWrappingError.new(reboot_error)
+ expect(exit_codes.normalize_exit_code(runtime_error)).to eq(35)
+ end
+
+ it "returns REBOOT_FAILED when the reboot command fails" do
+ reboot_error = Chef::Exceptions::RebootFailed.new("BOOM")
+ runtime_error = Chef::Exceptions::RunFailedWrappingError.new(reboot_error)
+ expect(exit_codes.normalize_exit_code(runtime_error)).to eq(41)
+ end
+
+ it "returns REBOOT_NEEDED when a reboot is pending" do
+ reboot_error = Chef::Exceptions::RebootPending.new("BOOM")
+ runtime_error = Chef::Exceptions::RunFailedWrappingError.new(reboot_error)
+ expect(exit_codes.normalize_exit_code(runtime_error)).to eq(37)
+ end
+
+ it "returns CLIENT_UPGRADED when the client was upgraded during converge" do
+ client_upgraded_error = Chef::Exceptions::ClientUpgraded.new("BOOM")
+ runtime_error = Chef::Exceptions::RunFailedWrappingError.new(client_upgraded_error)
+ expect(exit_codes.normalize_exit_code(runtime_error)).to eq(213)
+ end
+
+ it "returns SIGINT_RECEIVED when a SIGINT is received." do
+ sigint_error = Chef::Exceptions::SigInt.new("BOOM")
+ runtime_error = Chef::Exceptions::RunFailedWrappingError.new(sigint_error)
+ expect(exit_codes.normalize_exit_code(runtime_error)).to eq(2)
+ end
+
+ it "returns SIGTERM_RECEIVED when a SIGTERM is received." do
+ sigterm_error = Chef::Exceptions::SigTerm.new("BOOM")
+ runtime_error = Chef::Exceptions::RunFailedWrappingError.new(sigterm_error)
+ expect(exit_codes.normalize_exit_code(runtime_error)).to eq(3)
+ end
+ end
+
+end
diff --git a/spec/unit/application/knife_spec.rb b/spec/unit/application/knife_spec.rb
index 8894e86240..90ecde608e 100644
--- a/spec/unit/application/knife_spec.rb
+++ b/spec/unit/application/knife_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@junglist.gen.nz>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
+require "spec_helper"
require "#{CHEF_SPEC_DATA}/knife_subcommand/test_yourself"
describe Chef::Application::Knife do
@@ -82,9 +82,61 @@ describe Chef::Application::Knife do
end
end
+ context "when given fips flags" do
+ context "when Chef::Config[:fips]=false" do
+ before do
+ # This is required because the chef-fips pipeline does
+ # has a default value of true for fips
+ Chef::Config[:fips] = false
+ end
+
+ it "does not initialize fips mode when no flags are passed" do
+ with_argv(*%w{noop knife command}) do
+ expect(@knife).to receive(:exit).with(0)
+ expect(Chef::Config).not_to receive(:enable_fips_mode)
+ @knife.run
+ expect(Chef::Config[:fips]).to eq(false)
+ end
+ end
+
+ it "overwrites the Chef::Config value when passed --fips" do
+ with_argv(*%w{noop knife command --fips}) do
+ expect(@knife).to receive(:exit).with(0)
+ expect(Chef::Config).to receive(:enable_fips_mode)
+ @knife.run
+ expect(Chef::Config[:fips]).to eq(true)
+ end
+ end
+ end
+
+ context "when Chef::Config[:fips]=true" do
+ before do
+ Chef::Config[:fips] = true
+ end
+
+ it "initializes fips mode when passed --fips" do
+ with_argv(*%w{noop knife command --fips}) do
+ expect(@knife).to receive(:exit).with(0)
+ expect(Chef::Config).to receive(:enable_fips_mode)
+ @knife.run
+ expect(Chef::Config[:fips]).to eq(true)
+ end
+ end
+
+ it "overwrites the Chef::Config value when passed --no-fips" do
+ with_argv(*%w{noop knife command --no-fips}) do
+ expect(@knife).to receive(:exit).with(0)
+ expect(Chef::Config).not_to receive(:enable_fips_mode)
+ @knife.run
+ expect(Chef::Config[:fips]).to eq(false)
+ end
+ end
+ end
+ end
+
describe "when given a path to the client key" do
it "expands a relative path relative to the CWD" do
- relative_path = '.chef/client.pem'
+ relative_path = ".chef/client.pem"
allow(Dir).to receive(:pwd).and_return(CHEF_SPEC_DATA)
with_argv(*%W{noop knife command -k #{relative_path}}) do
expect(@knife).to receive(:exit).with(0)
@@ -94,20 +146,20 @@ describe Chef::Application::Knife do
end
it "expands a ~/home/path to the correct full path" do
- home_path = '~/.chef/client.pem'
+ home_path = "~/.chef/client.pem"
with_argv(*%W{noop knife command -k #{home_path}}) do
expect(@knife).to receive(:exit).with(0)
@knife.run
end
- expect(Chef::Config[:client_key]).to eq(File.join(ENV['HOME'], '.chef/client.pem').gsub((File::ALT_SEPARATOR || '\\'), File::SEPARATOR))
+ expect(Chef::Config[:client_key]).to eq(File.join(ENV["HOME"], ".chef/client.pem").gsub((File::ALT_SEPARATOR || '\\'), File::SEPARATOR))
end
it "does not expand a full path" do
full_path = if windows?
- 'C:/chef/client.pem'
- else
- '/etc/chef/client.pem'
- end
+ "C:/chef/client.pem"
+ else
+ "/etc/chef/client.pem"
+ end
with_argv(*%W{noop knife command -k #{full_path}}) do
expect(@knife).to receive(:exit).with(0)
@knife.run
@@ -130,38 +182,38 @@ describe Chef::Application::Knife do
end
it "should load the environment from the config file" do
- config_file = File.join(CHEF_SPEC_DATA,"environment-config.rb")
+ config_file = File.join(CHEF_SPEC_DATA, "environment-config.rb")
with_argv(*%W{noop knife command -c #{config_file}}) do
expect(@knife).to receive(:exit).with(0)
@knife.run
end
- expect(Chef::Config[:environment]).to eq('production')
+ expect(Chef::Config[:environment]).to eq("production")
end
it "should load the environment from the CLI options" do
- with_argv(*%W{noop knife command -E development}) do
+ with_argv(*%w{noop knife command -E development}) do
expect(@knife).to receive(:exit).with(0)
@knife.run
end
- expect(Chef::Config[:environment]).to eq('development')
+ expect(Chef::Config[:environment]).to eq("development")
end
it "should override the config file environment with the CLI environment" do
- config_file = File.join(CHEF_SPEC_DATA,"environment-config.rb")
+ config_file = File.join(CHEF_SPEC_DATA, "environment-config.rb")
with_argv(*%W{noop knife command -c #{config_file} -E override}) do
expect(@knife).to receive(:exit).with(0)
@knife.run
end
- expect(Chef::Config[:environment]).to eq('override')
+ expect(Chef::Config[:environment]).to eq("override")
end
it "should override the config file environment with the CLI environment regardless of order" do
- config_file = File.join(CHEF_SPEC_DATA,"environment-config.rb")
+ config_file = File.join(CHEF_SPEC_DATA, "environment-config.rb")
with_argv(*%W{noop knife command -E override -c #{config_file}}) do
expect(@knife).to receive(:exit).with(0)
@knife.run
end
- expect(Chef::Config[:environment]).to eq('override')
+ expect(Chef::Config[:environment]).to eq("override")
end
it "should run a sub command with the applications command line option prototype" do
diff --git a/spec/unit/application/solo_spec.rb b/spec/unit/application/solo_spec.rb
index 7013bfa0bc..686ae745d8 100644
--- a/spec/unit/application/solo_spec.rb
+++ b/spec/unit/application/solo_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@junglist.gen.nz>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
+require "spec_helper"
describe Chef::Application::Solo do
@@ -28,159 +28,205 @@ describe Chef::Application::Solo do
allow(app).to receive(:configure_logging).and_return(true)
allow(app).to receive(:trap)
- Chef::Config[:recipe_url] = false
Chef::Config[:json_attribs] = false
Chef::Config[:solo] = true
- end
+ Chef::Config[:solo_legacy_mode] = true
- describe "configuring the application" do
- it 'should call set_specific_recipes' do
- expect(app).to receive(:set_specific_recipes)
- app.reconfigure
- end
+ # protect the unit tests against accidental --delete-entire-chef-repo from firing
+ # for real during tests. DO NOT delete this line.
+ expect(FileUtils).not_to receive(:rm_rf)
+ end
- it "should set solo mode to true" do
- app.reconfigure
- expect(Chef::Config[:solo]).to be_truthy
- end
+ context "in legacy mode" do
+ describe "configuring the application" do
+ it "should call set_specific_recipes" do
+ expect(app).to receive(:set_specific_recipes)
+ app.reconfigure
+ end
- it "should set audit-mode to :disabled" do
- app.reconfigure
- expect(Chef::Config[:audit_mode]).to be :disabled
- end
+ it "should set solo mode to true" do
+ app.reconfigure
+ expect(Chef::Config[:solo]).to be_truthy
+ end
- describe "when configured to not fork the client process" do
- before do
- Chef::Config[:client_fork] = false
- Chef::Config[:daemonize] = false
- Chef::Config[:interval] = nil
- Chef::Config[:splay] = nil
+ it "should set audit-mode to :disabled" do
+ app.reconfigure
+ expect(Chef::Config[:audit_mode]).to be :disabled
end
- context "when interval is given" do
+ describe "when configured to not fork the client process" do
before do
- Chef::Config[:interval] = 600
+ Chef::Config[:client_fork] = false
+ Chef::Config[:daemonize] = false
+ Chef::Config[:interval] = nil
+ Chef::Config[:splay] = nil
end
- it "should terminate with message" do
- expect(Chef::Application).to receive(:fatal!).with(
-"Unforked chef-client interval runs are disabled in Chef 12.
+ context "when interval is given" do
+ before do
+ Chef::Config[:interval] = 600
+ end
+
+ it "should terminate with message" do
+ expect(Chef::Application).to receive(:fatal!).with(
+ "Unforked chef-client interval runs are disabled in Chef 12.
Configuration settings:
interval = 600 seconds
Enable chef-client interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options."
- )
- app.reconfigure
+ )
+ app.reconfigure
+ end
end
end
- end
- describe "when in daemonized mode and no interval has been set" do
- before do
- Chef::Config[:daemonize] = true
- end
+ describe "when in daemonized mode and no interval has been set" do
+ before do
+ Chef::Config[:daemonize] = true
+ end
- it "should set the interval to 1800" do
- Chef::Config[:interval] = nil
- app.reconfigure
- expect(Chef::Config[:interval]).to eq(1800)
+ it "should set the interval to 1800" do
+ Chef::Config[:interval] = nil
+ app.reconfigure
+ expect(Chef::Config[:interval]).to eq(1800)
+ end
end
- end
- describe "when the json_attribs configuration option is specified" do
- let(:json_attribs) { {"a" => "b"} }
- let(:config_fetcher) { double(Chef::ConfigFetcher, :fetch_json => json_attribs) }
- let(:json_source) { "https://foo.com/foo.json" }
+ describe "when the json_attribs configuration option is specified" do
+ let(:json_attribs) { { "a" => "b" } }
+ let(:config_fetcher) { double(Chef::ConfigFetcher, :fetch_json => json_attribs) }
+ let(:json_source) { "https://foo.com/foo.json" }
- before do
- Chef::Config[:json_attribs] = json_source
- expect(Chef::ConfigFetcher).to receive(:new).with(json_source).
- and_return(config_fetcher)
- end
+ before do
+ Chef::Config[:json_attribs] = json_source
+ expect(Chef::ConfigFetcher).to receive(:new).with(json_source).
+ and_return(config_fetcher)
+ end
- it "reads the JSON attributes from the specified source" do
- app.reconfigure
- expect(app.chef_client_json).to eq(json_attribs)
+ it "reads the JSON attributes from the specified source" do
+ app.reconfigure
+ expect(app.chef_client_json).to eq(json_attribs)
+ end
end
- end
- describe "when the recipe_url configuration option is specified" do
- let(:tarfile) { StringIO.new("remote_tarball_content") }
- let(:target_file) { StringIO.new }
- let(:shellout) { double(run_command: nil, error!: nil, stdout: '') }
-
- before do
+ it "downloads a tarball when the recipe_url configuration option is specified" do
Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks"
Chef::Config[:recipe_url] = "http://junglist.gen.nz/recipes.tgz"
- allow(FileUtils).to receive(:rm_rf).and_return(true)
- allow(FileUtils).to receive(:mkdir_p).and_return(true)
+ expect(FileUtils).to receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true)
- allow(app).to receive(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(tarfile)
- allow(File).to receive(:open).with("#{Dir.tmpdir}/chef-solo/recipes.tgz", "wb").and_yield(target_file)
+ tarfile = StringIO.new("remote_tarball_content")
+ target_file = StringIO.new
- allow(Mixlib::ShellOut).to receive(:new).and_return(shellout)
- end
+ expect(app).to receive(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(tarfile)
+ expect(File).to receive(:open).with("#{Dir.tmpdir}/chef-solo/recipes.tgz", "wb").and_yield(target_file)
- it "should create the recipes path based on the parent of the cookbook path" do
- expect(FileUtils).to receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true)
+ archive = double(Mixlib::Archive)
+
+ expect(Mixlib::Archive).to receive(:new).with("#{Dir.tmpdir}/chef-solo/recipes.tgz").and_return(archive)
+ expect(archive).to receive(:extract).with("#{Dir.tmpdir}/chef-solo", { perms: false, ignore: /^\.$/ })
app.reconfigure
+ expect(target_file.string).to eq("remote_tarball_content")
end
- it "should download the recipes" do
- expect(app).to receive(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(tarfile)
+ it "fetches the recipe_url first when both json_attribs and recipe_url are specified" do
+ json_attribs = { "a" => "b" }
+ config_fetcher = instance_double("Chef::ConfigFetcher", :fetch_json => json_attribs)
+
+ Chef::Config[:json_attribs] = "https://foo.com/foo.json"
+ Chef::Config[:recipe_url] = "http://icanhas.cheezburger.com/lolcats"
+ Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks"
+ expect(FileUtils).to receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true)
+
+ archive = double(Mixlib::Archive)
+
+ expect(Mixlib::Archive).to receive(:new).with("#{Dir.tmpdir}/chef-solo/recipes.tgz").and_return(archive)
+ expect(archive).to receive(:extract).with("#{Dir.tmpdir}/chef-solo", { perms: false, ignore: /^\.$/ })
+ expect(app).to receive(:fetch_recipe_tarball).ordered
+ expect(Chef::ConfigFetcher).to receive(:new).ordered.and_return(config_fetcher)
app.reconfigure
end
+ end
- it "should write the recipes to the target path" do
- app.reconfigure
- expect(target_file.string).to eq("remote_tarball_content")
+ describe "after the application has been configured" do
+ before do
+ Chef::Config[:solo] = true
+ Chef::Config[:solo_legacy_mode] = true
+
+ allow(Chef::Daemon).to receive(:change_privilege)
+ chef_client = double("Chef::Client")
+ allow(Chef::Client).to receive(:new).and_return(chef_client)
+ # this is all stuff the reconfigure method needs
+ allow(app).to receive(:configure_opt_parser).and_return(true)
+ allow(app).to receive(:configure_chef).and_return(true)
+ allow(app).to receive(:configure_logging).and_return(true)
end
- it "should untar the target file to the parent of the cookbook path" do
- expect(Mixlib::ShellOut).to receive(:new).with("tar zxvf #{Dir.tmpdir}/chef-solo/recipes.tgz -C #{Dir.tmpdir}/chef-solo")
- app.reconfigure
+ it "should change privileges" do
+ expect(Chef::Daemon).to receive(:change_privilege).and_return(true)
+ app.setup_application
end
end
- end
- describe "when the json_attribs and recipe_url configuration options are both specified" do
- let(:json_attribs) { {"a" => "b"} }
- let(:config_fetcher) { double(Chef::ConfigFetcher, :fetch_json => json_attribs) }
- let(:json_source) { "https://foo.com/foo.json" }
+ it_behaves_like "an application that loads a dot d" do
+ let(:dot_d_config_name) { :solo_d_dir }
+ end
+ end
+ context "in local mode" do
before do
- Chef::Config[:json_attribs] = json_source
- Chef::Config[:recipe_url] = "http://icanhas.cheezburger.com/lolcats"
- Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks"
- allow(FileUtils).to receive(:rm_rf).and_return(true)
- allow(FileUtils).to receive(:mkdir_p).and_return(true)
- allow(Chef::Mixin::Command).to receive(:run_command).and_return(true)
+ Chef::Config[:solo_legacy_mode] = false
end
- it "should fetch the recipe_url first" do
- expect(app).to receive(:fetch_recipe_tarball).ordered
- expect(Chef::ConfigFetcher).to receive(:new).ordered.and_return(config_fetcher)
+ it "sets solo mode to true" do
app.reconfigure
+ expect(Chef::Config[:solo]).to be_truthy
end
- end
- describe "after the application has been configured" do
- before do
- Chef::Config[:solo] = true
+ it "sets local mode to true" do
+ app.reconfigure
+ expect(Chef::Config[:local_mode]).to be_truthy
+ end
+
+ context "argv gets tidied up" do
+ before do
+ @original_argv = ARGV.dup
+ ARGV.clear
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ end
+
+ after do
+ ARGV.replace(@original_argv)
+ end
+
+ it "deletes --ez" do
+ ARGV << "--ez"
+ app.reconfigure
+ expect(ARGV.include?("--ez")).to be_falsey
+ end
- allow(Chef::Daemon).to receive(:change_privilege)
- chef_client = double("Chef::Client")
- allow(Chef::Client).to receive(:new).and_return(chef_client)
- # this is all stuff the reconfigure method needs
- allow(app).to receive(:configure_opt_parser).and_return(true)
+ it "replaces -r with --recipe-url" do
+ ARGV.push("-r", "http://junglist.gen.nz/recipes.tgz")
+ app.reconfigure
+ expect(ARGV.include?("-r")).to be_falsey
+ expect(ARGV.include?("--recipe-url")).to be_truthy
+ end
+ end
+
+ it "sets the repo path" do
+ expect(Chef::Config).to receive(:find_chef_repo_path).and_return("/var/chef")
+ app.reconfigure
+ expect(Chef::Config.has_key?(:chef_repo_path)).to be_truthy
+ expect(Chef::Config[:chef_repo_path]).to eq ("/var/chef")
+ end
+
+ it "runs chef-client in local mode" do
+ allow(app).to receive(:setup_application).and_return(true)
+ allow(app).to receive(:run_application).and_return(true)
allow(app).to receive(:configure_chef).and_return(true)
allow(app).to receive(:configure_logging).and_return(true)
+ expect(Chef::Application::Client).to receive_message_chain(:new, :run)
+ app.run
end
- it "should change privileges" do
- expect(Chef::Daemon).to receive(:change_privilege).and_return(true)
- app.setup_application
- end
end
-
end
diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb
index f5a2c72aa0..867cd3f9c2 100644
--- a/spec/unit/application_spec.rb
+++ b/spec/unit/application_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: AJ Christensen (<aj@junglist.gen.nz>)
-# Author:: Mark Mzyk (mmzyk@opscode.com)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Mark Mzyk (mmzyk@chef.io)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
+require "spec_helper"
describe Chef::Application do
before do
@@ -34,392 +34,259 @@ describe Chef::Application do
ARGV.replace(@original_argv)
end
- describe "reconfigure" do
- before do
- @app = Chef::Application.new
- allow(@app).to receive(:configure_chef).and_return(true)
- allow(@app).to receive(:configure_logging).and_return(true)
- allow(@app).to receive(:configure_proxy_environment_variables).and_return(true)
- end
-
- it "should configure chef" do
- expect(@app).to receive(:configure_chef).and_return(true)
- @app.reconfigure
- end
-
- it "should configure logging" do
- expect(@app).to receive(:configure_logging).and_return(true)
- @app.reconfigure
- end
-
- it "should configure environment variables" do
- expect(@app).to receive(:configure_proxy_environment_variables).and_return(true)
- @app.reconfigure
- end
+ context "when there are no configuration errors" do
- it 'should not receive set_specific_recipes' do
- expect(@app).to_not receive(:set_specific_recipes)
- @app.reconfigure
- end
- end
-
- describe Chef::Application do
before do
- @app = Chef::Application.new
+ expect(Chef::Log).to_not receive(:fatal)
+ expect(Chef::Application).to_not receive(:fatal!)
end
- describe "run" do
+ describe "reconfigure" do
before do
- allow(@app).to receive(:setup_application).and_return(true)
- allow(@app).to receive(:run_application).and_return(true)
+ @app = Chef::Application.new
allow(@app).to receive(:configure_chef).and_return(true)
allow(@app).to receive(:configure_logging).and_return(true)
end
- it "should reconfigure the application before running" do
- expect(@app).to receive(:reconfigure).and_return(true)
- @app.run
+ it "should configure chef" do
+ expect(@app).to receive(:configure_chef).and_return(true)
+ @app.reconfigure
end
- it "should setup the application before running it" do
- expect(@app).to receive(:setup_application).and_return(true)
- @app.run
+ it "should configure logging" do
+ expect(@app).to receive(:configure_logging).and_return(true)
+ @app.reconfigure
end
- it "should run the actual application" do
- expect(@app).to receive(:run_application).and_return(true)
- @app.run
+ it "should not receive set_specific_recipes" do
+ expect(@app).to_not receive(:set_specific_recipes)
+ @app.reconfigure
end
end
- end
-
- describe "configure_chef" do
- before do
- # Silence warnings when no config file exists
- allow(Chef::Log).to receive(:warn)
-
- @app = Chef::Application.new
- #Chef::Config.stub(:merge!).and_return(true)
- allow(@app).to receive(:parse_options).and_return(true)
- end
-
- it "should parse the commandline options" do
- expect(@app).to receive(:parse_options).and_return(true)
- @app.config[:config_file] = "/etc/chef/default.rb" #have a config file set, to prevent triggering error block
- @app.configure_chef
- end
-
- describe "when a config_file is present" do
- let(:config_content) { "rspec_ran('true')" }
- let(:config_location) { "/etc/chef/default.rb" }
-
- let(:config_location_pathname) do
- p = Pathname.new(config_location)
- allow(p).to receive(:realpath).and_return(config_location)
- p
- end
+ describe Chef::Application do
before do
- @app.config[:config_file] = config_location
-
- # force let binding to get evaluated or else we stub Pathname.new before we try to use it.
- config_location_pathname
- allow(Pathname).to receive(:new).with(config_location).and_return(config_location_pathname)
- expect(File).to receive(:read).
- with(config_location).
- and_return(config_content)
+ @app = Chef::Application.new
end
- it "should configure chef::config from a file" do
- expect(Chef::Config).to receive(:from_string).with(config_content, config_location)
- @app.configure_chef
- end
-
- it "should merge the local config hash into chef::config" do
- #File.should_receive(:open).with("/etc/chef/default.rb").and_yield(@config_file)
- @app.configure_chef
- expect(Chef::Config.rspec_ran).to eq("true")
- end
+ describe "run" do
+ before do
+ allow(@app).to receive(:setup_application).and_return(true)
+ allow(@app).to receive(:run_application).and_return(true)
+ allow(@app).to receive(:configure_chef).and_return(true)
+ allow(@app).to receive(:configure_logging).and_return(true)
+ end
- end
+ it "should reconfigure the application before running" do
+ expect(@app).to receive(:reconfigure).and_return(true)
+ @app.run
+ end
- describe "when there is no config_file defined" do
- before do
- @app.config[:config_file] = nil
- end
+ it "should setup the application before running it" do
+ expect(@app).to receive(:setup_application).and_return(true)
+ @app.run
+ end
- it "should emit a warning" do
- expect(Chef::Config).not_to receive(:from_file).with("/etc/chef/default.rb")
- expect(Chef::Log).to receive(:warn).with("No config file found or specified on command line, using command line options.")
- @app.configure_chef
+ it "should run the actual application" do
+ expect(@app).to receive(:run_application).and_return(true)
+ @app.run
+ end
end
end
- describe "when the config file is set and not found" do
+ describe "configure_chef" do
before do
- @app.config[:config_file] = "/etc/chef/notfound"
+ # Silence warnings when no config file exists
+ allow(Chef::Log).to receive(:warn)
+
+ @app = Chef::Application.new
+ allow(@app).to receive(:parse_options).and_return(true)
+ expect(Chef::Config).to receive(:export_proxies).and_return(true)
end
- it "should use the passed in command line options and defaults" do
- expect(Chef::Config).to receive(:merge!)
+
+ it "should parse the commandline options" do
+ expect(@app).to receive(:parse_options).and_return(true)
+ @app.config[:config_file] = "/etc/chef/default.rb" #have a config file set, to prevent triggering error block
@app.configure_chef
end
- end
- end
- describe "when configuring the logger" do
- before do
- @app = Chef::Application.new
- allow(Chef::Log).to receive(:init)
- end
-
- it "should initialise the chef logger" do
- allow(Chef::Log).to receive(:level=)
- @monologger = double("Monologger")
- expect(MonoLogger).to receive(:new).with(Chef::Config[:log_location]).and_return(@monologger)
- expect(Chef::Log).to receive(:init).with(@monologger)
- @app.configure_logging
- end
+ describe "when a config_file is present" do
+ let(:config_content) { "rspec_ran('true')" }
+ let(:config_location) { "/etc/chef/default.rb" }
- it "should raise fatals if log location is invalid" do
- Chef::Config[:log_location] = "/tmp/non-existing-dir/logfile"
- expect(Chef::Log).to receive(:fatal).at_least(:once)
- expect(Process).to receive(:exit)
- @app.configure_logging
- end
+ let(:config_location_pathname) do
+ p = Pathname.new(config_location)
+ allow(p).to receive(:realpath).and_return(config_location)
+ p
+ end
- shared_examples_for "log_level_is_auto" do
- context "when STDOUT is to a tty" do
before do
- allow(STDOUT).to receive(:tty?).and_return(true)
+ @app.config[:config_file] = config_location
+
+ # force let binding to get evaluated or else we stub Pathname.new before we try to use it.
+ config_location_pathname
+ allow(Pathname).to receive(:new).with(config_location).and_return(config_location_pathname)
+ expect(File).to receive(:read).
+ with(config_location).
+ and_return(config_content)
end
- it "configures the log level to :warn" do
- @app.configure_logging
- expect(Chef::Log.level).to eq(:warn)
+ it "should configure chef::config from a file" do
+ expect(Chef::Config).to receive(:from_string).with(config_content, File.expand_path(config_location))
+ @app.configure_chef
end
- context "when force_logger is configured" do
+ it "should merge the local config hash into chef::config" do
+ #File.should_receive(:open).with("/etc/chef/default.rb").and_yield(@config_file)
+ @app.configure_chef
+ expect(Chef::Config.rspec_ran).to eq("true")
+ end
+
+ context "when openssl fips" do
before do
- Chef::Config[:force_logger] = true
+ allow(Chef::Config).to receive(:fips).and_return(true)
end
- it "configures the log level to info" do
- @app.configure_logging
- expect(Chef::Log.level).to eq(:info)
+ it "sets openssl in fips mode" do
+ expect(Chef::Config).to receive(:enable_fips_mode)
+ @app.configure_chef
end
end
end
- context "when STDOUT is not to a tty" do
+ describe "when there is no config_file defined" do
before do
- allow(STDOUT).to receive(:tty?).and_return(false)
+ @app.config[:config_file] = nil
end
- it "configures the log level to :info" do
- @app.configure_logging
- expect(Chef::Log.level).to eq(:info)
- end
-
- context "when force_formatter is configured" do
- before do
- Chef::Config[:force_formatter] = true
- end
- it "sets the log level to :warn" do
- @app.configure_logging
- expect(Chef::Log.level).to eq(:warn)
- end
+ it "should emit a warning" do
+ expect(Chef::Config).not_to receive(:from_file).with("/etc/chef/default.rb")
+ expect(Chef::Log).to receive(:warn).with("No config file found or specified on command line, using command line options.")
+ @app.configure_chef
end
end
- end
- context "when log_level is not set" do
- it_behaves_like "log_level_is_auto"
- end
-
- context "when log_level is :auto" do
- before do
- Chef::Config[:log_level] = :auto
+ describe "when the config file is set and not found" do
+ before do
+ @app.config[:config_file] = "/etc/chef/notfound"
+ end
+ it "should use the passed in command line options and defaults" do
+ expect(Chef::Config).to receive(:merge!)
+ @app.configure_chef
+ end
end
-
- it_behaves_like "log_level_is_auto"
end
- end
- describe "when configuring environment variables" do
- def configure_proxy_environment_variables_stubs
- allow(@app).to receive(:configure_http_proxy).and_return(true)
- allow(@app).to receive(:configure_https_proxy).and_return(true)
- allow(@app).to receive(:configure_ftp_proxy).and_return(true)
- allow(@app).to receive(:configure_no_proxy).and_return(true)
- end
-
- shared_examples_for "setting ENV['http_proxy']" do
+ describe "when configuring the logger" do
before do
- Chef::Config[:http_proxy] = http_proxy
- end
-
- it "should set ENV['http_proxy']" do
- @app.configure_proxy_environment_variables
- expect(@env['http_proxy']).to eq("#{scheme}://#{address}:#{port}")
+ @app = Chef::Application.new
+ allow(Chef::Log).to receive(:init)
end
- it "should set ENV['HTTP_PROXY']" do
- @app.configure_proxy_environment_variables
- expect(@env['HTTP_PROXY']).to eq("#{scheme}://#{address}:#{port}")
+ it "should initialise the chef logger" do
+ allow(Chef::Log).to receive(:level=)
+ @monologger = double("Monologger")
+ expect(MonoLogger).to receive(:new).with(Chef::Config[:log_location]).and_return(@monologger)
+ expect(Chef::Log).to receive(:init).with(@monologger)
+ @app.configure_logging
end
- describe "when Chef::Config[:http_proxy_user] is set" do
- before do
- Chef::Config[:http_proxy_user] = "username"
- end
-
- it "should set ENV['http_proxy'] with the username" do
- @app.configure_proxy_environment_variables
- expect(@env['http_proxy']).to eq("#{scheme}://username@#{address}:#{port}")
- expect(@env['HTTP_PROXY']).to eq("#{scheme}://username@#{address}:#{port}")
- end
-
- context "when :http_proxy_user contains '@' and/or ':'" do
+ shared_examples_for "log_level_is_auto" do
+ context "when STDOUT is to a tty" do
before do
- Chef::Config[:http_proxy_user] = "my:usern@me"
+ allow(STDOUT).to receive(:tty?).and_return(true)
end
- it "should set ENV['http_proxy'] with the escaped username" do
- @app.configure_proxy_environment_variables
- expect(@env['http_proxy']).to eq("#{scheme}://my%3Ausern%40me@#{address}:#{port}")
- expect(@env['HTTP_PROXY']).to eq("#{scheme}://my%3Ausern%40me@#{address}:#{port}")
+ it "configures the log level to :warn" do
+ @app.configure_logging
+ expect(Chef::Log.level).to eq(:warn)
+ end
+
+ context "when force_logger is configured" do
+ before do
+ Chef::Config[:force_logger] = true
+ end
+
+ it "configures the log level to info" do
+ @app.configure_logging
+ expect(Chef::Log.level).to eq(:info)
+ end
end
end
- describe "when Chef::Config[:http_proxy_pass] is set" do
+ context "when STDOUT is not to a tty" do
before do
- Chef::Config[:http_proxy_pass] = "password"
+ allow(STDOUT).to receive(:tty?).and_return(false)
end
- it "should set ENV['http_proxy'] with the password" do
- @app.configure_proxy_environment_variables
- expect(@env['http_proxy']).to eq("#{scheme}://username:password@#{address}:#{port}")
- expect(@env['HTTP_PROXY']).to eq("#{scheme}://username:password@#{address}:#{port}")
+ it "configures the log level to :info" do
+ @app.configure_logging
+ expect(Chef::Log.level).to eq(:info)
end
- context "when :http_proxy_pass contains '@' and/or ':'" do
+ context "when force_formatter is configured" do
before do
- Chef::Config[:http_proxy_pass] = ":P@ssword101"
+ Chef::Config[:force_formatter] = true
end
-
- it "should set ENV['http_proxy'] with the escaped password" do
- @app.configure_proxy_environment_variables
- expect(@env['http_proxy']).to eq("#{scheme}://username:%3AP%40ssword101@#{address}:#{port}")
- expect(@env['HTTP_PROXY']).to eq("#{scheme}://username:%3AP%40ssword101@#{address}:#{port}")
+ it "sets the log level to :warn" do
+ @app.configure_logging
+ expect(Chef::Log.level).to eq(:warn)
end
end
end
end
- describe "when Chef::Config[:http_proxy_pass] is set (but not Chef::Config[:http_proxy_user])" do
- before do
- Chef::Config[:http_proxy_user] = nil
- Chef::Config[:http_proxy_pass] = "password"
- end
-
- it "should set ENV['http_proxy']" do
- @app.configure_proxy_environment_variables
- expect(@env['http_proxy']).to eq("#{scheme}://#{address}:#{port}")
- expect(@env['HTTP_PROXY']).to eq("#{scheme}://#{address}:#{port}")
- end
- end
- end
-
- describe "when configuring ENV['http_proxy']" do
- before do
- @env = {}
- allow(@app).to receive(:env).and_return(@env)
-
- allow(@app).to receive(:configure_https_proxy).and_return(true)
- allow(@app).to receive(:configure_ftp_proxy).and_return(true)
- allow(@app).to receive(:configure_no_proxy).and_return(true)
+ context "when log_level is not set" do
+ it_behaves_like "log_level_is_auto"
end
- describe "when Chef::Config[:http_proxy] is not set" do
+ context "when log_level is :auto" do
before do
- Chef::Config[:http_proxy] = nil
+ Chef::Config[:log_level] = :auto
end
- it "should not set ENV['http_proxy']" do
- @app.configure_proxy_environment_variables
- expect(@env).to eq({})
- end
+ it_behaves_like "log_level_is_auto"
end
- describe "when Chef::Config[:http_proxy] is set" do
- context "when given an FQDN" do
- let(:scheme) { "http" }
- let(:address) { "proxy.example.org" }
- let(:port) { 8080 }
- let(:http_proxy) { "#{scheme}://#{address}:#{port}" }
-
- it_should_behave_like "setting ENV['http_proxy']"
- end
-
- context "when given an HTTPS URL" do
- let(:scheme) { "https" }
- let(:address) { "proxy.example.org" }
- let(:port) { 8080 }
- let(:http_proxy) { "#{scheme}://#{address}:#{port}" }
-
- it_should_behave_like "setting ENV['http_proxy']"
- end
-
- context "when given an IP" do
- let(:scheme) { "http" }
- let(:address) { "127.0.0.1" }
- let(:port) { 22 }
- let(:http_proxy) { "#{scheme}://#{address}:#{port}" }
-
- it_should_behave_like "setting ENV['http_proxy']"
- end
-
- context "when given an IPv6" do
- let(:scheme) { "http" }
- let(:address) { "[2001:db8::1]" }
- let(:port) { 80 }
- let(:http_proxy) { "#{scheme}://#{address}:#{port}" }
-
- it_should_behave_like "setting ENV['http_proxy']"
- end
-
- context "when given without including http://" do
- let(:scheme) { "http" }
- let(:address) { "proxy.example.org" }
- let(:port) { 8181 }
- let(:http_proxy) { "#{address}:#{port}" }
+ describe "log_location" do
+ shared_examples("sets log_location") do |config_value, expected_class|
+ context "when the configured value is #{config_value.inspect}" do
+ let(:logger_instance) { instance_double(expected_class).as_null_object }
- it_should_behave_like "setting ENV['http_proxy']"
- end
-
- context "when given the full proxy in :http_proxy only" do
- before do
- Chef::Config[:http_proxy] = "http://username:password@proxy.example.org:2222"
- Chef::Config[:http_proxy_user] = nil
- Chef::Config[:http_proxy_pass] = nil
- end
+ before do
+ allow(expected_class).to receive(:new).and_return(logger_instance)
+ Chef::Config[:log_location] = config_value
+ end
- it "should set ENV['http_proxy']" do
- @app.configure_proxy_environment_variables
- expect(@env['http_proxy']).to eq(Chef::Config[:http_proxy])
+ it "it sets log_location to an instance of #{expected_class}" do
+ expect(expected_class).to receive(:new).with no_args
+ @app.configure_logging
+ expect(Chef::Config[:log_location]).to be logger_instance
+ end
end
end
- context "when the config options aren't URI compliant" do
- it "raises Chef::Exceptions::BadProxyURI" do
- Chef::Config[:http_proxy] = "http://proxy.bad_example.org/:8080"
- expect { @app.configure_proxy_environment_variables }.to raise_error(Chef::Exceptions::BadProxyURI)
- end
+ if Chef::Platform.windows?
+ it_behaves_like "sets log_location", :win_evt, Chef::Log::WinEvt
+ it_behaves_like "sets log_location", "win_evt", Chef::Log::WinEvt
+ else
+ it_behaves_like "sets log_location", :syslog, Chef::Log::Syslog
+ it_behaves_like "sets log_location", "syslog", Chef::Log::Syslog
end
end
end
end
+ context "with an invalid log location" do
+
+ it "logs a fatal error and exits" do
+ Chef::Config[:log_location] = "/tmp/non-existing-dir/logfile"
+ expect(Chef::Log).to receive(:fatal).at_least(:once)
+ expect(Process).to receive(:exit)
+ @app.configure_logging
+ end
+ end
+
describe "class method: fatal!" do
before do
allow(STDERR).to receive(:puts).with("FATAL: blah").and_return(true)
@@ -478,29 +345,29 @@ describe Chef::Application do
end
end
- describe 'run_chef_client' do
- context 'with an application' do
+ describe "run_chef_client" do
+ context "with an application" do
let(:app) { Chef::Application.new }
- context 'when called with an invalid argument' do
+ context "when called with an invalid argument" do
before do
allow(app).to receive(:fork_chef_client).and_return(true)
allow(app).to receive(:run_with_graceful_exit_option).and_return(true)
end
- it 'should raise an argument error detailing the problem' do
- specific_recipes_regexp = Regexp.new 'received non-Array like specific_recipes argument'
+ it "should raise an argument error detailing the problem" do
+ specific_recipes_regexp = Regexp.new "received non-Array like specific_recipes argument"
expect { app.run_chef_client(nil) }.to raise_error(ArgumentError, specific_recipes_regexp)
end
end
- context 'when called with an Array-like argument (#size)' do
+ context "when called with an Array-like argument (#size)" do
before do
allow(app).to receive(:fork_chef_client).and_return(true)
allow(app).to receive(:run_with_graceful_exit_option).and_return(true)
end
- it 'should be cool' do
+ it "should be cool" do
expect { app.run_chef_client([]) }.not_to raise_error
end
end
diff --git a/spec/unit/audit/audit_event_proxy_spec.rb b/spec/unit/audit/audit_event_proxy_spec.rb
index 17a5d3d771..820e670f1c 100644
--- a/spec/unit/audit/audit_event_proxy_spec.rb
+++ b/spec/unit/audit/audit_event_proxy_spec.rb
@@ -1,8 +1,8 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
-# Author:: Claire McQuin (<claire@getchef.com>)
+# Author:: Claire McQuin (<claire@chef.io>)
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/audit/audit_event_proxy'
+require "spec_helper"
+require "chef/audit/audit_event_proxy"
describe Chef::Audit::AuditEventProxy do
@@ -34,8 +34,9 @@ describe Chef::Audit::AuditEventProxy do
describe "#example_group_started" do
let(:description) { "poots" }
- let(:group) { double("ExampleGroup", :parent_groups => parents,
- :description => description) }
+ let(:group) do
+ double("ExampleGroup", :parent_groups => parents,
+ :description => description) end
let(:notification) { double("Notification", :group => group) }
context "when notified from a top-level example group" do
@@ -120,44 +121,45 @@ describe Chef::Audit::AuditEventProxy do
let(:examples) { [example] }
- let(:example) { double("Example", :metadata => metadata,
- :description => example_description,
- :full_description => full_description, :exception => nil) }
+ let(:example) do
+ double("Example", :metadata => metadata,
+ :description => example_description,
+ :full_description => full_description, :exception => nil) end
- let(:metadata) {
+ let(:metadata) do
{
:described_class => described_class,
:example_group => example_group,
- :line_number => line
+ :line_number => line,
}
- }
+ end
- let(:example_group) {
+ let(:example_group) do
{
:description => group_description,
- :parent_example_group => parent_group
+ :parent_example_group => parent_group,
}
- }
+ end
- let(:parent_group) {
+ let(:parent_group) do
{
:description => control_group_name,
- :parent_example_group => nil
+ :parent_example_group => nil,
}
- }
+ end
let(:line) { 27 }
- let(:control_data) {
+ let(:control_data) do
{
:name => example_description,
:desc => full_description,
:resource_type => resource_type,
:resource_name => resource_name,
:context => context,
- :line_number => line
+ :line_number => line,
}
- }
+ end
shared_examples "built control" do
@@ -218,12 +220,14 @@ describe Chef::Audit::AuditEventProxy do
let(:control_group_name) { "application ports" }
let(:group_description) { "#{resource_type} #{resource_name}" }
let(:example_description) { "should not be listening" }
- let(:full_description) { [control_group_name, group_description,
- example_description].join(" ") }
+ let(:full_description) do
+ [control_group_name, group_description,
+ example_description].join(" ") end
# Metadata fields
- let(:described_class) { double("Serverspec::Type::Port",
- :class => "Serverspec::Type::Port", :name => resource_name) }
+ let(:described_class) do
+ double("Serverspec::Type::Port",
+ :class => "Serverspec::Type::Port", :name => resource_name) end
# Control data fields
let(:resource_type) { "Port" }
@@ -246,8 +250,9 @@ describe Chef::Audit::AuditEventProxy do
let(:control_group_name) { "application ports" }
let(:group_description) { "port 111" }
let(:example_description) { "is not listening" }
- let(:full_description) { [control_group_name, group_description,
- example_description].join(" ") }
+ let(:full_description) do
+ [control_group_name, group_description,
+ example_description].join(" ") end
# Metadata fields
let(:described_class) { nil }
@@ -276,27 +281,29 @@ describe Chef::Audit::AuditEventProxy do
let(:outer_group_description) { "File \"tmp/audit\"" }
let(:group_description) { "#{resource_type} #{resource_name}" }
let(:example_description) { "is a file" }
- let(:full_description) { [control_group_name, outer_group_description,
- group_description, example_description].join(" ") }
+ let(:full_description) do
+ [control_group_name, outer_group_description,
+ group_description, example_description].join(" ") end
# Metadata parts
- let(:described_class) { double("Serverspec::Type::File",
- :class => "Serverspec::Type::File", :name => resource_name) }
+ let(:described_class) do
+ double("Serverspec::Type::File",
+ :class => "Serverspec::Type::File", :name => resource_name) end
# Example group parts
- let(:parent_group) {
+ let(:parent_group) do
{
:description => outer_group_description,
- :parent_example_group => control_group
+ :parent_example_group => control_group,
}
- }
+ end
- let(:control_group) {
+ let(:control_group) do
{
:description => control_group_name,
- :parent_example_group => nil
+ :parent_example_group => nil,
}
- }
+ end
# Control data parts
let(:resource_type) { "File" }
diff --git a/spec/unit/audit/audit_reporter_spec.rb b/spec/unit/audit/audit_reporter_spec.rb
index 46c2a96b4c..cf916266d8 100644
--- a/spec/unit/audit/audit_reporter_spec.rb
+++ b/spec/unit/audit/audit_reporter_spec.rb
@@ -1,8 +1,8 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
-# Author:: Claire McQuin (<claire@getchef.com>)
+# Author:: Claire McQuin (<claire@chef.io>)
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Audit::AuditReporter do
@@ -28,8 +28,9 @@ describe Chef::Audit::AuditReporter do
let(:run_id) { 0 }
let(:start_time) { Time.new(2014, 12, 3, 9, 31, 05, "-08:00") }
let(:end_time) { Time.new(2014, 12, 3, 9, 36, 14, "-08:00") }
- let(:run_status) { instance_double(Chef::RunStatus, :node => node, :run_id => run_id,
- :start_time => start_time, :end_time => end_time) }
+ let(:run_status) do
+ instance_double(Chef::RunStatus, :node => node, :run_id => run_id,
+ :start_time => start_time, :end_time => end_time) end
describe "#audit_phase_start" do
@@ -57,7 +58,6 @@ describe Chef::Audit::AuditReporter do
before do
allow(reporter).to receive(:auditing_enabled?).and_return(true)
allow(reporter).to receive(:run_status).and_return(run_status)
- allow(rest).to receive(:create_url).and_return(true)
allow(rest).to receive(:post).and_return(true)
allow(reporter).to receive(:audit_data).and_return(audit_data)
allow(reporter).to receive(:run_status).and_return(run_status)
@@ -75,28 +75,25 @@ describe Chef::Audit::AuditReporter do
end
it "posts audit data to server endpoint" do
- endpoint = "api.opscode.us/orgname/controls"
headers = {
- 'X-Ops-Audit-Report-Protocol-Version' => Chef::Audit::AuditReporter::PROTOCOL_VERSION
+ "X-Ops-Audit-Report-Protocol-Version" => Chef::Audit::AuditReporter::PROTOCOL_VERSION,
}
- expect(rest).to receive(:create_url).
- with("controls").
- and_return(endpoint)
expect(rest).to receive(:post).
- with(endpoint, run_data, headers)
+ with("controls", run_data, headers)
reporter.run_completed(node)
end
context "when audit phase failed" do
- let(:audit_error) { double("AuditError", :class => "Chef::Exceptions::AuditError",
- :message => "Audit phase failed with error message: derpderpderp",
- :backtrace => ["/path/recipe.rb:57", "/path/library.rb:106"]) }
+ let(:audit_error) do
+ double("AuditError", :class => "Chef::Exceptions::AuditError",
+ :message => "Audit phase failed with error message: derpderpderp",
+ :backtrace => ["/path/recipe.rb:57", "/path/library.rb:106"]) end
- before do
- reporter.instance_variable_set(:@audit_phase_error, audit_error)
- end
+ before do
+ reporter.instance_variable_set(:@audit_phase_error, audit_error)
+ end
it "reports an error" do
reporter.run_completed(node)
@@ -196,7 +193,7 @@ EOM
expect(error).to receive(:respond_to?).with(:response).and_return(false)
allow(Chef::Log).to receive(:error).and_return(true)
expect(Chef::Log).to receive(:error).with(/Reporting fatals enabled. Aborting run./)
- expect{ reporter.run_completed(node) }.to raise_error(error)
+ expect { reporter.run_completed(node) }.to raise_error(error)
end
end
@@ -238,13 +235,15 @@ EOM
let(:audit_data) { Chef::Audit::AuditData.new(node.name, run_id) }
let(:run_data) { audit_data.to_hash }
- let(:audit_error) { double("AuditError", :class => "Chef::Exceptions::AuditError",
- :message => "Audit phase failed with error message: derpderpderp",
- :backtrace => ["/path/recipe.rb:57", "/path/library.rb:106"]) }
+ let(:audit_error) do
+ double("AuditError", :class => "Chef::Exceptions::AuditError",
+ :message => "Audit phase failed with error message: derpderpderp",
+ :backtrace => ["/path/recipe.rb:57", "/path/library.rb:106"]) end
- let(:run_error) { double("RunError", :class => "Chef::Exceptions::RunError",
- :message => "This error shouldn't be reported.",
- :backtrace => ["fix it", "fix it", "fix it"]) }
+ let(:run_error) do
+ double("RunError", :class => "Chef::Exceptions::RunError",
+ :message => "This error shouldn't be reported.",
+ :backtrace => ["fix it", "fix it", "fix it"]) end
before do
allow(reporter).to receive(:auditing_enabled?).and_return(true)
@@ -255,7 +254,6 @@ EOM
context "when no prior exception is stored" do
it "reports no error" do
- expect(rest).to receive(:create_url)
expect(rest).to receive(:post)
reporter.run_failed(run_error)
expect(run_data).to_not have_key(:error)
@@ -268,7 +266,6 @@ EOM
end
it "reports the prior error" do
- expect(rest).to receive(:create_url)
expect(rest).to receive(:post)
reporter.run_failed(run_error)
expect(run_data).to have_key(:error)
@@ -283,23 +280,27 @@ EOM
shared_context "audit data" do
- let(:control_group_foo) { instance_double(Chef::Audit::ControlGroupData,
- :metadata => double("foo metadata")) }
- let(:control_group_bar) { instance_double(Chef::Audit::ControlGroupData,
- :metadata => double("bar metadata")) }
+ let(:control_group_foo) do
+ instance_double(Chef::Audit::ControlGroupData,
+ :metadata => double("foo metadata")) end
+ let(:control_group_bar) do
+ instance_double(Chef::Audit::ControlGroupData,
+ :metadata => double("bar metadata")) end
- let(:ordered_control_groups) {
+ let(:ordered_control_groups) do
{
"foo" => control_group_foo,
- "bar" => control_group_bar
+ "bar" => control_group_bar,
}
- }
+ end
- let(:audit_data) { instance_double(Chef::Audit::AuditData,
- :add_control_group => true) }
+ let(:audit_data) do
+ instance_double(Chef::Audit::AuditData,
+ :add_control_group => true) end
- let(:run_context) { instance_double(Chef::RunContext,
- :audits => ordered_control_groups) }
+ let(:run_context) do
+ instance_double(Chef::RunContext,
+ :audits => ordered_control_groups) end
before do
allow(reporter).to receive(:ordered_control_groups).and_return(ordered_control_groups)
@@ -347,8 +348,9 @@ EOM
include_context "audit data"
let(:name) { "bat" }
- let(:control_group) { instance_double(Chef::Audit::ControlGroupData,
- :metadata => double("metadata")) }
+ let(:control_group) do
+ instance_double(Chef::Audit::ControlGroupData,
+ :metadata => double("metadata")) end
before do
allow(Chef::Audit::ControlGroupData).to receive(:new).
@@ -373,7 +375,7 @@ EOM
context "when a control group with the same name has been seen" do
it "raises an exception" do
expect(ordered_control_groups).to receive(:has_key?).with(name).and_return(true)
- expect{ reporter.control_group_started(name) }.to raise_error(Chef::Exceptions::AuditControlGroupDuplicate)
+ expect { reporter.control_group_started(name) }.to raise_error(Chef::Exceptions::AuditControlGroupDuplicate)
end
end
end
diff --git a/spec/unit/audit/control_group_data_spec.rb b/spec/unit/audit/control_group_data_spec.rb
index e21ab066fd..ea4ac260f9 100644
--- a/spec/unit/audit/control_group_data_spec.rb
+++ b/spec/unit/audit/control_group_data_spec.rb
@@ -1,8 +1,8 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
-# Author:: Claire McQuin (<claire@getchef.com>)
+# Author:: Claire McQuin (<claire@chef.io>)
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'securerandom'
+require "spec_helper"
+require "securerandom"
describe Chef::Audit::AuditData do
@@ -72,8 +72,8 @@ describe Chef::Audit::AuditData do
describe ":control_groups" do
- let(:control_hash_1) { {:name => "control group 1"} }
- let(:control_hash_2) { {:name => "control group 2"} }
+ let(:control_hash_1) { { :name => "control group 1" } }
+ let(:control_hash_2) { { :name => "control group 2" } }
let(:control_groups) { audit_data_hash[:control_groups] }
@@ -122,10 +122,10 @@ describe Chef::Audit::ControlData do
let(:context) { nil }
let(:line_number) { 27 }
- let(:control_data) { described_class.new(name: name,
- resource_type: resource_type, resource_name: resource_name,
- context: context, line_number: line_number) }
-
+ let(:control_data) do
+ described_class.new(name: name,
+ resource_type: resource_type, resource_name: resource_name,
+ context: context, line_number: line_number) end
describe "#to_hash" do
@@ -172,30 +172,31 @@ describe Chef::Audit::ControlGroupData do
let(:context) { nil }
let(:line_number) { 0 }
- let(:control_data) {
+ let(:control_data) do
{
:name => name,
:resource_type => resource_type,
:resource_name => resource_name,
:context => context,
- :line_number => line_number
+ :line_number => line_number,
}
- }
+ end
end
shared_context "control" do
include_context "control data"
- let(:control) { Chef::Audit::ControlData.new(name: name,
- resource_type: resource_type, resource_name: resource_name,
- context: context, line_number: line_number) }
+ let(:control) do
+ Chef::Audit::ControlData.new(name: name,
+ resource_type: resource_type, resource_name: resource_name,
+ context: context, line_number: line_number) end
before do
allow(Chef::Audit::ControlData).to receive(:new).
with(name: name, resource_type: resource_type,
- resource_name: resource_name, context: context,
- line_number: line_number).
+ resource_name: resource_name, context: context,
+ line_number: line_number).
and_return(control)
end
end
@@ -361,19 +362,19 @@ describe Chef::Audit::ControlGroupData do
context "and it's the first audit" do
include_examples "mixed audit results" do
- let(:audit_results) { ["failure", "success", "success"] }
+ let(:audit_results) { %w{failure success success} }
end
end
context "and it's an audit in the middle" do
include_examples "mixed audit results" do
- let(:audit_results) { ["success", "failure", "success"] }
+ let(:audit_results) { %w{success failure success} }
end
end
context "and it's the last audit" do
include_examples "mixed audit results" do
- let(:audit_results) { ["success", "success", "failure"] }
+ let(:audit_results) { %w{success success failure} }
end
end
end
@@ -433,19 +434,22 @@ describe Chef::Audit::ControlGroupData do
context "with multiple controls added" do
- let(:control_hash_1) { {:line_number => 27} }
- let(:control_hash_2) { {:line_number => 13} }
- let(:control_hash_3) { {:line_number => 35} }
+ let(:control_hash_1) { { :line_number => 27 } }
+ let(:control_hash_2) { { :line_number => 13 } }
+ let(:control_hash_3) { { :line_number => 35 } }
- let(:control_1) { double("control 1",
+ let(:control_1) do
+ double("control 1",
:line_number => control_hash_1[:line_number],
- :to_hash => control_hash_1) }
- let(:control_2) { double("control 2",
+ :to_hash => control_hash_1) end
+ let(:control_2) do
+ double("control 2",
:line_number => control_hash_2[:line_number],
- :to_hash => control_hash_2) }
- let(:control_3) { double("control 3",
+ :to_hash => control_hash_2) end
+ let(:control_3) do
+ double("control 3",
:line_number => control_hash_3[:line_number],
- :to_hash => control_hash_3) }
+ :to_hash => control_hash_3) end
let(:control_list) { [control_1, control_2, control_3] }
let(:ordered_control_hashes) { [control_hash_2, control_hash_1, control_hash_3] }
diff --git a/spec/unit/audit/logger_spec.rb b/spec/unit/audit/logger_spec.rb
index 9dd9ce2cd9..51a32d906e 100644
--- a/spec/unit/audit/logger_spec.rb
+++ b/spec/unit/audit/logger_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Audit::Logger do
@@ -23,19 +23,19 @@ describe Chef::Audit::Logger do
Chef::Audit::Logger.instance_variable_set(:@buffer, nil)
end
- it 'calling puts creates @buffer and adds the message' do
+ it "calling puts creates @buffer and adds the message" do
Chef::Audit::Logger.puts("Output message")
expect(Chef::Audit::Logger.read_buffer).to eq("Output message\n")
end
- it 'calling puts multiple times adds to the message' do
+ it "calling puts multiple times adds to the message" do
Chef::Audit::Logger.puts("Output message")
Chef::Audit::Logger.puts("Output message")
Chef::Audit::Logger.puts("Output message")
expect(Chef::Audit::Logger.read_buffer).to eq("Output message\nOutput message\nOutput message\n")
end
- it 'calling it before @buffer is set returns an empty string' do
+ it "calling it before @buffer is set returns an empty string" do
expect(Chef::Audit::Logger.read_buffer).to eq("")
end
diff --git a/spec/unit/audit/rspec_formatter_spec.rb b/spec/unit/audit/rspec_formatter_spec.rb
index 471473e387..8c266fbb8b 100644
--- a/spec/unit/audit/rspec_formatter_spec.rb
+++ b/spec/unit/audit/rspec_formatter_spec.rb
@@ -1,8 +1,8 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
-# Author:: Claire McQuin (<claire@getchef.com>)
+# Author:: Claire McQuin (<claire@chef.io>)
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/audit/rspec_formatter'
+require "spec_helper"
+require "chef/audit/rspec_formatter"
describe Chef::Audit::RspecFormatter do
let(:formatter) { Chef::Audit::RspecFormatter.new(nil) }
diff --git a/spec/unit/audit/runner_spec.rb b/spec/unit/audit/runner_spec.rb
index 1de024260f..4c03cab1d3 100644
--- a/spec/unit/audit/runner_spec.rb
+++ b/spec/unit/audit/runner_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,13 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'rspec/core/sandbox'
-require 'chef/audit/runner'
-require 'chef/audit/audit_event_proxy'
-require 'chef/audit/rspec_formatter'
-require 'rspec/support/spec/in_sub_process'
-require 'rspec/support/spec/stderr_splitter'
-
+require "spec_helper"
+require "rspec/core/sandbox"
+require "chef/audit/runner"
+require "chef/audit/audit_event_proxy"
+require "chef/audit/rspec_formatter"
+require "rspec/support/spec/in_sub_process"
+require "rspec/support/spec/stderr_splitter"
describe Chef::Audit::Runner do
include RSpec::Support::InSubProcess
@@ -54,7 +53,7 @@ describe Chef::Audit::Runner do
context "during #run" do
describe "#setup" do
- let(:log_location) { File.join(Dir.tmpdir, 'audit_log') }
+ let(:log_location) { File.join(Dir.tmpdir, "audit_log") }
let(:color) { false }
before do
@@ -100,8 +99,8 @@ describe Chef::Audit::Runner do
end
context "audits exist" do
- let(:audits) { {"audit_name" => group} }
- let(:group) {Struct.new(:args, :block).new(["group_name"], nil)}
+ let(:audits) { { "audit_name" => group } }
+ let(:group) { Struct.new(:args, :block).new(["group_name"], nil) }
it "sends the audits to the world" do
runner.send(:register_control_groups)
diff --git a/spec/unit/chef_class_spec.rb b/spec/unit/chef_class_spec.rb
index f1b877520c..21987c01ab 100644
--- a/spec/unit/chef_class_spec.rb
+++ b/spec/unit/chef_class_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Lamont Granquist (<lamont@chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe "Chef class" do
let(:platform) { "debian" }
let(:node) do
node = Chef::Node.new
- node.automatic['platform'] = platform
+ node.automatic["platform"] = platform
node
end
@@ -61,14 +61,14 @@ describe "Chef class" do
end
context "#set_provider_priority_array" do
it "should delegate to the provider_priority_map" do
- expect(provider_priority_map).to receive(:set_priority_array).with(:http_request, ["a", "b"], platform: "debian").and_return("stuff")
- expect(Chef.set_provider_priority_array(:http_request, ["a", "b"], platform: "debian")).to eql("stuff")
+ expect(provider_priority_map).to receive(:set_priority_array).with(:http_request, %w{a b}, platform: "debian").and_return("stuff")
+ expect(Chef.set_provider_priority_array(:http_request, %w{a b}, platform: "debian")).to eql("stuff")
end
end
context "#set_priority_map_for_resource" do
it "should delegate to the resource_priority_map" do
- expect(resource_priority_map).to receive(:set_priority_array).with(:http_request, ["a", "b"], platform: "debian").and_return("stuff")
- expect(Chef.set_resource_priority_array(:http_request, ["a", "b"], platform: "debian")).to eql("stuff")
+ expect(resource_priority_map).to receive(:set_priority_array).with(:http_request, %w{a b}, platform: "debian").and_return("stuff")
+ expect(Chef.set_resource_priority_array(:http_request, %w{a b}, platform: "debian")).to eql("stuff")
end
end
end
@@ -85,8 +85,8 @@ describe "Chef class" do
end
end
- context '#event_handler' do
- it 'adds a new handler' do
+ context "#event_handler" do
+ it "adds a new handler" do
x = 1
Chef.event_handler do
on :converge_start do
@@ -98,7 +98,7 @@ describe "Chef class" do
expect(x).to eq(2)
end
- it 'raise error if unknown event type is passed' do
+ it "raise error if unknown event type is passed" do
expect do
Chef.event_handler do
on :yolo do
diff --git a/spec/unit/chef_fs/config_spec.rb b/spec/unit/chef_fs/config_spec.rb
index c7c47ad8ab..0adcbbfbfb 100644
--- a/spec/unit/chef_fs/config_spec.rb
+++ b/spec/unit/chef_fs/config_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Jess Mink (<jmink@getchef.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Jess Mink (<jmink@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/exceptions'
-require 'lib/chef/chef_fs/config.rb'
+require "spec_helper"
+require "chef/exceptions"
+require "lib/chef/chef_fs/config.rb"
describe Chef::ChefFS::Config do
describe "initialize" do
it "warns when hosted setups use 'everything'" do
base_config = Hash.new()
- base_config[:repo_mode] = 'everything'
- base_config[:chef_server_url] = 'http://foo.com/organizations/fake_org/'
+ base_config[:repo_mode] = "everything"
+ base_config[:chef_server_url] = "http://foo.com/organizations/fake_org/"
ui = double("ui")
expect(ui).to receive(:warn)
@@ -35,8 +35,8 @@ describe Chef::ChefFS::Config do
it "doesn't warn when hosted setups use 'hosted_everything'" do
base_config = Hash.new()
- base_config[:repo_mode] = 'hosted_everything'
- base_config[:chef_server_url] = 'http://foo.com/organizations/fake_org/'
+ base_config[:repo_mode] = "hosted_everything"
+ base_config[:chef_server_url] = "http://foo.com/organizations/fake_org/"
ui = double("ui")
expect(ui).to receive(:warn).exactly(0).times
@@ -46,8 +46,8 @@ describe Chef::ChefFS::Config do
it "doesn't warn when non-hosted setups use 'everything'" do
base_config = Hash.new()
- base_config[:repo_mode] = 'everything'
- base_config[:chef_server_url] = 'http://foo.com/'
+ base_config[:repo_mode] = "everything"
+ base_config[:chef_server_url] = "http://foo.com/"
ui = double("ui")
expect(ui).to receive(:warn).exactly(0).times
@@ -67,11 +67,11 @@ describe Chef::ChefFS::Config do
node_path: "/base_path/nodes",
role_path: "/base_path/roles",
user_path: "/base_path/users",
- policy_path: "/base_path/policies"
+ policy_path: "/base_path/policies",
})
end
- let(:chef_fs_config) { Chef::ChefFS::Config.new(chef_config, Dir.pwd) }
+ let(:chef_fs_config) { Chef::ChefFS::Config.new(chef_config, Dir.pwd) }
subject(:local_fs) { chef_fs_config.local_fs }
@@ -102,9 +102,134 @@ describe Chef::ChefFS::Config do
it "sets the correct user path on the local FS object" do
expect(local_fs.child_paths["users"]).to eq([platform_path("/base_path/users")])
end
+ end
+
+ describe "formats paths", :unix_only do
+
+ let(:single_repo_path) do
+ Mash.new({
+ chef_repo_path: "/base_path",
+ })
+ end
+
+ let(:double_repo_path) do
+ Mash.new({
+ chef_repo_path: %w{ /base_path /second_base_path },
+ })
+ end
+
+ describe "#server_path" do
+ it "returns nil if no paths match" do
+ cfg = Chef::ChefFS::Config.new(single_repo_path, "/my_repo/cookbooks")
+ expect(cfg.server_path("foo")).to be_nil
+ end
+
+ context "with only repo paths" do
+ it "returns / if in the repo path" do
+ cwd = "/base_path/cookbooks"
+ cfg = Chef::ChefFS::Config.new(single_repo_path, cwd)
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("/base_path/cookbooks", cwd).and_return("/base_path/cookbooks")
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("/base_path", cwd).and_return("/base_path/cookbooks")
+ expect(cfg.server_path("/base_path/cookbooks")).to eq("/")
+ end
+
+ it "checks all the repo paths" do
+ cwd = "/second_base_path/cookbooks"
+ cfg = Chef::ChefFS::Config.new(double_repo_path, cwd)
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("/second_base_path/cookbooks", cwd).and_return("/second_base_path/cookbooks")
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("/base_path", cwd).and_return("/base_path/cookbooks")
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("/second_base_path", cwd).and_return("/second_base_path/cookbooks")
+ expect(cfg.server_path("/second_base_path/cookbooks")).to eq("/")
+ end
+ end
+
+ context "with specific object locations" do
+ let(:single_cookbook_path) do
+ Mash.new({
+ cookbook_path: "/base_path/cookbooks",
+ role_path: "/base_path/roles",
+ })
+ end
+
+ let(:cwd) { "/base_path/cookbooks" }
+ let(:cfg) { Chef::ChefFS::Config.new(single_cookbook_path, cwd) }
+
+ before do
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("/base_path/cookbooks", cwd).and_return("/base_path/cookbooks")
+ allow(Chef::ChefFS::PathUtils).to receive(:realest_path).with("/base_path/roles", cwd).and_return("/base_path/roles")
+ end
+
+ it "resolves a relative path" do
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("blah", cwd).and_return("/base_path/cookbooks/blah")
+ expect(cfg.server_path("blah")).to eql("/cookbooks/blah")
+ end
+
+ it "resolves a relative path in a parent directory" do
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("../roles/blah", cwd).and_return("/base_path/roles/blah")
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("/base_path/roles", cwd).and_return("/base_path/roles")
+ expect(cfg.server_path("../roles/blah")).to eql("/roles/blah")
+ end
+
+ it "ignores a relative path that's outside the repository" do
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("../../readme.txt", cwd).and_return("/readme.txt")
+ expect(cfg.server_path("../../readme.txt")).to be_nil
+ end
+
+ it "deals with splat paths" do
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("*/*ab*", cwd).and_return("/base_path/cookbooks/*/*ab*")
+ expect(cfg.server_path("*/*ab*")).to eql("/cookbooks/*/*ab*")
+ end
+
+ it "resolves an absolute path" do
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("/base_path/cookbooks/blah", cwd).and_return("/base_path/cookbooks/blah")
+ expect(cfg.server_path("/base_path/cookbooks/blah")).to eql("/cookbooks/blah")
+ end
+
+ it "deals with an absolute path with splats" do
+ expect(Chef::ChefFS::PathUtils).to receive(:realest_path).with("/*/cookbooks/blah", cwd).and_return("/*/cookbooks/blah")
+ expect(cfg.server_path("/*/cookbooks/blah")).to be_nil
+ end
+ end
+ end
+
+ describe "#format_path" do
+ Entry = Struct.new(:path)
+
+ let(:config) do
+ Mash.new({
+ chef_repo_path: "/base_path",
+ cookbook_path: "/base_path/cookbooks",
+ role_path: "/base_path/roles",
+ })
+ end
+
+ let (:path) { "/roles/foo.json" }
+ let (:entry) { Entry.new(path) }
+
+ it "returns the entry's path if the cwd isn't in the config" do
+ cfg = Chef::ChefFS::Config.new(config, "/my_repo/cookbooks")
+ expect(cfg).to receive(:base_path).and_return(nil)
+ expect(cfg.format_path(entry)).to eq(path)
+ end
+
+ it "returns . if the cwd is the same as the entry's path" do
+ cfg = Chef::ChefFS::Config.new(config, "/base_path/roles/foo.json")
+ expect(cfg).to receive(:base_path).and_return("/roles/foo.json").at_least(:once)
+ expect(cfg.format_path(entry)).to eq(".")
+ end
+
+ it "returns a relative path if the cwd is in the repo" do
+ cfg = Chef::ChefFS::Config.new(config, "/base_path/roles")
+ expect(cfg).to receive(:base_path).and_return("/roles").at_least(:once)
+ expect(cfg.format_path(entry)).to eq("foo.json")
+ end
+
+ it "returns a relative path if the cwd is at the root of repo" do
+ cfg = Chef::ChefFS::Config.new(config, "/base_path")
+ expect(cfg).to receive(:base_path).and_return("/").at_least(:once)
+ expect(cfg.format_path(entry)).to eq("roles/foo.json")
+ end
- it "sets the correct policy path on the local FS object" do
- expect(local_fs.child_paths["policies"]).to eq([platform_path("/base_path/policies")])
end
end
end
diff --git a/spec/unit/chef_fs/data_handler/group_handler_spec.rb b/spec/unit/chef_fs/data_handler/group_handler_spec.rb
index 5f14646602..ac0252162f 100644
--- a/spec/unit/chef_fs/data_handler/group_handler_spec.rb
+++ b/spec/unit/chef_fs/data_handler/group_handler_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Ryan Cragun (<ryan@getchef.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Ryan Cragun (<ryan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'lib/chef/chef_fs/data_handler/group_data_handler'
+require "spec_helper"
+require "lib/chef/chef_fs/data_handler/group_data_handler"
class TestEntry < Mash
attr_accessor :name, :org
@@ -29,34 +29,34 @@ class TestEntry < Mash
end
describe Chef::ChefFS::DataHandler::GroupDataHandler do
- describe '#normalize_for_post' do
+ describe "#normalize_for_post" do
let(:entry) do
- TestEntry.new('workers.json', 'hive')
+ TestEntry.new("workers.json", "hive")
end
let(:group) do
- { 'name' => 'worker_bees',
- 'clients' => %w(honey sting),
- 'users' => %w(fizz buzz),
- 'actors' => %w(honey)
+ { "name" => "worker_bees",
+ "clients" => %w{honey sting},
+ "users" => %w{fizz buzz},
+ "actors" => %w{honey},
}
end
let(:normalized) do
- { 'actors' =>
- { 'users' => %w(fizz buzz),
- 'clients'=> %w(honey sting),
- 'groups'=> []
+ { "actors" =>
+ { "users" => %w{fizz buzz},
+ "clients" => %w{honey sting},
+ "groups" => [],
},
- 'groupname' => 'workers',
- 'name' => 'worker_bees',
- 'orgname' => 'hive'
+ "groupname" => "workers",
+ "name" => "worker_bees",
+ "orgname" => "hive",
}
end
let(:handler) { described_class.new }
- it 'normalizes the users, clients and groups into actors' do
+ it "normalizes the users, clients and groups into actors" do
expect(handler.normalize_for_post(group, entry)).to eq(normalized)
end
end
diff --git a/spec/unit/chef_fs/diff_spec.rb b/spec/unit/chef_fs/diff_spec.rb
index 71605393f3..d946fcb9e7 100644
--- a/spec/unit/chef_fs/diff_spec.rb
+++ b/spec/unit/chef_fs/diff_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,24 +16,24 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/chef_fs/file_pattern'
-require 'chef/chef_fs/command_line'
+require "spec_helper"
+require "chef/chef_fs/file_pattern"
+require "chef/chef_fs/command_line"
# Removes the date stamp from the diff and replaces it with ' DATE'
# example match: "/dev/null\t2012-10-16 16:15:54.000000000 +0000"
# windows match: "--- /dev/null\tTue Oct 16 18:04:34 2012"
def remove_os_differences(diff)
diff = diff.gsub(/([+-]{3}.*)\t.*/, '\1 DATE')
- diff.gsub(/^@@ -\d(,\d)? \+\d(,\d)? @@/, 'CONTEXT_LINE_NUMBERS')
+ diff.gsub(/^@@ -\d(,\d)? \+\d(,\d)? @@/, "CONTEXT_LINE_NUMBERS")
end
-describe 'diff', :uses_diff => true do
+describe "diff", :uses_diff => true do
include FileSystemSupport
- context 'with two filesystems with all types of difference' do
- let(:a) {
- memory_fs('a', {
+ context "with two filesystems with all types of difference" do
+ let(:a) do
+ memory_fs("a", {
:both_dirs => {
:sub_both_dirs => { :subsub => nil },
:sub_both_files => nil,
@@ -44,7 +44,7 @@ describe 'diff', :uses_diff => true do
:sub_a_only_dir => { :subsub => nil },
:sub_a_only_file => nil,
:sub_dir_in_a_file_in_b => {},
- :sub_file_in_a_dir_in_b => nil
+ :sub_file_in_a_dir_in_b => nil,
},
:both_files => nil,
:both_files_different => "a\n",
@@ -56,11 +56,11 @@ describe 'diff', :uses_diff => true do
:a_only_dir => { :subsub => nil },
:a_only_file => nil,
:dir_in_a_file_in_b => {},
- :file_in_a_dir_in_b => nil
+ :file_in_a_dir_in_b => nil,
}, /cannot_be_in_a/)
- }
- let(:b) {
- memory_fs('b', {
+ end
+ let(:b) do
+ memory_fs("b", {
:both_dirs => {
:sub_both_dirs => { :subsub => nil },
:sub_both_files => nil,
@@ -71,7 +71,7 @@ describe 'diff', :uses_diff => true do
:sub_b_only_dir => { :subsub => nil },
:sub_b_only_file => nil,
:sub_dir_in_a_file_in_b => nil,
- :sub_file_in_a_dir_in_b => {}
+ :sub_file_in_a_dir_in_b => {},
},
:both_files => nil,
:both_files_different => "b\n",
@@ -83,12 +83,12 @@ describe 'diff', :uses_diff => true do
:b_only_dir => { :subsub => nil },
:b_only_file => nil,
:dir_in_a_file_in_b => nil,
- :file_in_a_dir_in_b => {}
+ :file_in_a_dir_in_b => {},
}, /cannot_be_in_b/)
- }
- it 'Chef::ChefFS::CommandLine.diff_print(/)' do
+ end
+ it "Chef::ChefFS::CommandLine.diff_print(/)" do
results = []
- Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, nil, nil) do |diff|
+ Chef::ChefFS::CommandLine.diff_print(pattern("/"), a, b, nil, nil) do |diff|
results << remove_os_differences(diff)
end
expect(results).to match_array([
@@ -98,63 +98,63 @@ describe 'diff', :uses_diff => true do
CONTEXT_LINE_NUMBERS
-a
+b
-','diff --knife a/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub
+', 'diff --knife a/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub
new file
--- /dev/null DATE
+++ b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub DATE
CONTEXT_LINE_NUMBERS
+subsub
-','diff --knife a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub
+', 'diff --knife a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub
deleted file
--- a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub DATE
+++ /dev/null DATE
CONTEXT_LINE_NUMBERS
-subsub
-','Only in a/both_dirs: sub_a_only_dir
-','diff --knife a/both_dirs/sub_a_only_file b/both_dirs/sub_a_only_file
+', "Only in a/both_dirs: sub_a_only_dir
+", 'diff --knife a/both_dirs/sub_a_only_file b/both_dirs/sub_a_only_file
deleted file
--- a/both_dirs/sub_a_only_file DATE
+++ /dev/null DATE
CONTEXT_LINE_NUMBERS
-sub_a_only_file
-','File a/both_dirs/sub_dir_in_a_file_in_b is a directory while file b/both_dirs/sub_dir_in_a_file_in_b is a regular file
-','File a/both_dirs/sub_file_in_a_dir_in_b is a regular file while file b/both_dirs/sub_file_in_a_dir_in_b is a directory
-','Only in b/both_dirs: sub_b_only_dir
-','diff --knife a/both_dirs/sub_b_only_file b/both_dirs/sub_b_only_file
+', "File a/both_dirs/sub_dir_in_a_file_in_b is a directory while file b/both_dirs/sub_dir_in_a_file_in_b is a regular file
+", "File a/both_dirs/sub_file_in_a_dir_in_b is a regular file while file b/both_dirs/sub_file_in_a_dir_in_b is a directory
+", "Only in b/both_dirs: sub_b_only_dir
+", 'diff --knife a/both_dirs/sub_b_only_file b/both_dirs/sub_b_only_file
new file
--- /dev/null DATE
+++ b/both_dirs/sub_b_only_file DATE
CONTEXT_LINE_NUMBERS
+sub_b_only_file
-','diff --knife a/both_files_different b/both_files_different
+', 'diff --knife a/both_files_different b/both_files_different
--- a/both_files_different DATE
+++ b/both_files_different DATE
CONTEXT_LINE_NUMBERS
-a
+b
-','diff --knife a/dirs_empty_in_a_filled_in_b/subsub b/dirs_empty_in_a_filled_in_b/subsub
+', 'diff --knife a/dirs_empty_in_a_filled_in_b/subsub b/dirs_empty_in_a_filled_in_b/subsub
new file
--- /dev/null DATE
+++ b/dirs_empty_in_a_filled_in_b/subsub DATE
CONTEXT_LINE_NUMBERS
+subsub
-','diff --knife a/dirs_empty_in_b_filled_in_a/subsub b/dirs_empty_in_b_filled_in_a/subsub
+', 'diff --knife a/dirs_empty_in_b_filled_in_a/subsub b/dirs_empty_in_b_filled_in_a/subsub
deleted file
--- a/dirs_empty_in_b_filled_in_a/subsub DATE
+++ /dev/null DATE
CONTEXT_LINE_NUMBERS
-subsub
-','Only in a: a_only_dir
-','diff --knife a/a_only_file b/a_only_file
+', "Only in a: a_only_dir
+", 'diff --knife a/a_only_file b/a_only_file
deleted file
--- a/a_only_file DATE
+++ /dev/null DATE
CONTEXT_LINE_NUMBERS
-a_only_file
-','File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file
-','File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory
-','Only in b: b_only_dir
-','diff --knife a/b_only_file b/b_only_file
+', "File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file
+", "File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory
+", "Only in b: b_only_dir
+", 'diff --knife a/b_only_file b/b_only_file
new file
--- /dev/null DATE
+++ b/b_only_file DATE
@@ -162,9 +162,9 @@ CONTEXT_LINE_NUMBERS
+b_only_file
' ])
end
- it 'Chef::ChefFS::CommandLine.diff_print(/both_dirs)' do
+ it "Chef::ChefFS::CommandLine.diff_print(/both_dirs)" do
results = []
- Chef::ChefFS::CommandLine.diff_print(pattern('/both_dirs'), a, b, nil, nil) do |diff|
+ Chef::ChefFS::CommandLine.diff_print(pattern("/both_dirs"), a, b, nil, nil) do |diff|
results << remove_os_differences(diff)
end
expect(results).to match_array([
@@ -174,29 +174,29 @@ CONTEXT_LINE_NUMBERS
CONTEXT_LINE_NUMBERS
-a
+b
-','diff --knife a/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub
+', 'diff --knife a/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub
new file
--- /dev/null DATE
+++ b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub DATE
CONTEXT_LINE_NUMBERS
+subsub
-','diff --knife a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub
+', 'diff --knife a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub
deleted file
--- a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub DATE
+++ /dev/null DATE
CONTEXT_LINE_NUMBERS
-subsub
-','Only in a/both_dirs: sub_a_only_dir
-','diff --knife a/both_dirs/sub_a_only_file b/both_dirs/sub_a_only_file
+', "Only in a/both_dirs: sub_a_only_dir
+", 'diff --knife a/both_dirs/sub_a_only_file b/both_dirs/sub_a_only_file
deleted file
--- a/both_dirs/sub_a_only_file DATE
+++ /dev/null DATE
CONTEXT_LINE_NUMBERS
-sub_a_only_file
-','File a/both_dirs/sub_dir_in_a_file_in_b is a directory while file b/both_dirs/sub_dir_in_a_file_in_b is a regular file
-','File a/both_dirs/sub_file_in_a_dir_in_b is a regular file while file b/both_dirs/sub_file_in_a_dir_in_b is a directory
-','Only in b/both_dirs: sub_b_only_dir
-','diff --knife a/both_dirs/sub_b_only_file b/both_dirs/sub_b_only_file
+', "File a/both_dirs/sub_dir_in_a_file_in_b is a directory while file b/both_dirs/sub_dir_in_a_file_in_b is a regular file
+", "File a/both_dirs/sub_file_in_a_dir_in_b is a regular file while file b/both_dirs/sub_file_in_a_dir_in_b is a directory
+", "Only in b/both_dirs: sub_b_only_dir
+", 'diff --knife a/both_dirs/sub_b_only_file b/both_dirs/sub_b_only_file
new file
--- /dev/null DATE
+++ b/both_dirs/sub_b_only_file DATE
@@ -204,33 +204,33 @@ CONTEXT_LINE_NUMBERS
+sub_b_only_file
' ])
end
- it 'Chef::ChefFS::CommandLine.diff_print(/) with depth 1' do
+ it "Chef::ChefFS::CommandLine.diff_print(/) with depth 1" do
results = []
- Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, 1, nil) do |diff|
+ Chef::ChefFS::CommandLine.diff_print(pattern("/"), a, b, 1, nil) do |diff|
results << remove_os_differences(diff)
end
expect(results).to match_array([
-'Common subdirectories: b/both_dirs
-','diff --knife a/both_files_different b/both_files_different
+"Common subdirectories: b/both_dirs
+", 'diff --knife a/both_files_different b/both_files_different
--- a/both_files_different DATE
+++ b/both_files_different DATE
CONTEXT_LINE_NUMBERS
-a
+b
-','Common subdirectories: b/both_dirs_empty
-','Common subdirectories: b/dirs_empty_in_b_filled_in_a
-','Common subdirectories: b/dirs_empty_in_a_filled_in_b
-','Only in a: a_only_dir
-','diff --knife a/a_only_file b/a_only_file
+', "Common subdirectories: b/both_dirs_empty
+", "Common subdirectories: b/dirs_empty_in_b_filled_in_a
+", "Common subdirectories: b/dirs_empty_in_a_filled_in_b
+", "Only in a: a_only_dir
+", 'diff --knife a/a_only_file b/a_only_file
deleted file
--- a/a_only_file DATE
+++ /dev/null DATE
CONTEXT_LINE_NUMBERS
-a_only_file
-','File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file
-','File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory
-','Only in b: b_only_dir
-','diff --knife a/b_only_file b/b_only_file
+', "File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file
+", "File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory
+", "Only in b: b_only_dir
+", 'diff --knife a/b_only_file b/b_only_file
new file
--- /dev/null DATE
+++ b/b_only_file DATE
@@ -238,33 +238,33 @@ CONTEXT_LINE_NUMBERS
+b_only_file
' ])
end
- it 'Chef::ChefFS::CommandLine.diff_print(/*_*) with depth 0' do
+ it "Chef::ChefFS::CommandLine.diff_print(/*_*) with depth 0" do
results = []
- Chef::ChefFS::CommandLine.diff_print(pattern('/*_*'), a, b, 0, nil) do |diff|
+ Chef::ChefFS::CommandLine.diff_print(pattern("/*_*"), a, b, 0, nil) do |diff|
results << remove_os_differences(diff)
end
expect(results).to match_array([
-'Common subdirectories: b/both_dirs
-','diff --knife a/both_files_different b/both_files_different
+"Common subdirectories: b/both_dirs
+", 'diff --knife a/both_files_different b/both_files_different
--- a/both_files_different DATE
+++ b/both_files_different DATE
CONTEXT_LINE_NUMBERS
-a
+b
-','Common subdirectories: b/both_dirs_empty
-','Common subdirectories: b/dirs_empty_in_b_filled_in_a
-','Common subdirectories: b/dirs_empty_in_a_filled_in_b
-','Only in a: a_only_dir
-','diff --knife a/a_only_file b/a_only_file
+', "Common subdirectories: b/both_dirs_empty
+", "Common subdirectories: b/dirs_empty_in_b_filled_in_a
+", "Common subdirectories: b/dirs_empty_in_a_filled_in_b
+", "Only in a: a_only_dir
+", 'diff --knife a/a_only_file b/a_only_file
deleted file
--- a/a_only_file DATE
+++ /dev/null DATE
CONTEXT_LINE_NUMBERS
-a_only_file
-','File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file
-','File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory
-','Only in b: b_only_dir
-','diff --knife a/b_only_file b/b_only_file
+', "File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file
+", "File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory
+", "Only in b: b_only_dir
+", 'diff --knife a/b_only_file b/b_only_file
new file
--- /dev/null DATE
+++ b/b_only_file DATE
@@ -272,9 +272,9 @@ CONTEXT_LINE_NUMBERS
+b_only_file
' ])
end
- it 'Chef::ChefFS::CommandLine.diff_print(/) in name-only mode' do
+ it "Chef::ChefFS::CommandLine.diff_print(/) in name-only mode" do
results = []
- Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, nil, :name_only) do |diff|
+ Chef::ChefFS::CommandLine.diff_print(pattern("/"), a, b, nil, :name_only) do |diff|
results << remove_os_differences(diff)
end
expect(results).to match_array([
@@ -295,12 +295,12 @@ CONTEXT_LINE_NUMBERS
"b/b_only_dir\n",
"b/b_only_file\n",
"b/dir_in_a_file_in_b\n",
- "b/file_in_a_dir_in_b\n"
+ "b/file_in_a_dir_in_b\n",
])
end
- it 'Chef::ChefFS::CommandLine.diff_print(/) in name-status mode' do
+ it "Chef::ChefFS::CommandLine.diff_print(/) in name-status mode" do
results = []
- Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, nil, :name_status) do |diff|
+ Chef::ChefFS::CommandLine.diff_print(pattern("/"), a, b, nil, :name_status) do |diff|
results << remove_os_differences(diff)
end
expect(results).to match_array([
@@ -321,7 +321,7 @@ CONTEXT_LINE_NUMBERS
"A\tb/b_only_dir\n",
"A\tb/b_only_file\n",
"T\tb/dir_in_a_file_in_b\n",
- "T\tb/file_in_a_dir_in_b\n"
+ "T\tb/file_in_a_dir_in_b\n",
])
end
end
diff --git a/spec/unit/chef_fs/file_pattern_spec.rb b/spec/unit/chef_fs/file_pattern_spec.rb
index ed5f314605..c4d076ef90 100644
--- a/spec/unit/chef_fs/file_pattern_spec.rb
+++ b/spec/unit/chef_fs/file_pattern_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/chef_fs/file_pattern'
+require "spec_helper"
+require "chef/chef_fs/file_pattern"
describe Chef::ChefFS::FilePattern do
def p(str)
@@ -26,459 +26,458 @@ describe Chef::ChefFS::FilePattern do
# Different kinds of patterns
context 'with empty pattern ""' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('') }
- it 'match?' do
- expect(pattern.match?('')).to be_truthy
- expect(pattern.match?('/')).to be_falsey
- expect(pattern.match?('a')).to be_falsey
- expect(pattern.match?('a/b')).to be_falsey
+ let(:pattern) { Chef::ChefFS::FilePattern.new("") }
+ it "match?" do
+ expect(pattern.match?("")).to be_truthy
+ expect(pattern.match?("/")).to be_falsey
+ expect(pattern.match?("a")).to be_falsey
+ expect(pattern.match?("a/b")).to be_falsey
end
- it 'exact_path' do
- expect(pattern.exact_path).to eq('')
+ it "exact_path" do
+ expect(pattern.exact_path).to eq("")
end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('')).to be_falsey
- expect(pattern.could_match_children?('a/b')).to be_falsey
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("")).to be_falsey
+ expect(pattern.could_match_children?("a/b")).to be_falsey
end
end
context 'with root pattern "/"' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('/') }
- it 'match?' do
- expect(pattern.match?('/')).to be_truthy
- expect(pattern.match?('')).to be_falsey
- expect(pattern.match?('a')).to be_falsey
- expect(pattern.match?('/a')).to be_falsey
- end
- it 'exact_path' do
- expect(pattern.exact_path).to eq('/')
- end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('')).to be_falsey
- expect(pattern.could_match_children?('/')).to be_falsey
- expect(pattern.could_match_children?('a')).to be_falsey
- expect(pattern.could_match_children?('a/b')).to be_falsey
- expect(pattern.could_match_children?('/a')).to be_falsey
+ let(:pattern) { Chef::ChefFS::FilePattern.new("/") }
+ it "match?" do
+ expect(pattern.match?("/")).to be_truthy
+ expect(pattern.match?("")).to be_falsey
+ expect(pattern.match?("a")).to be_falsey
+ expect(pattern.match?("/a")).to be_falsey
+ end
+ it "exact_path" do
+ expect(pattern.exact_path).to eq("/")
+ end
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("")).to be_falsey
+ expect(pattern.could_match_children?("/")).to be_falsey
+ expect(pattern.could_match_children?("a")).to be_falsey
+ expect(pattern.could_match_children?("a/b")).to be_falsey
+ expect(pattern.could_match_children?("/a")).to be_falsey
end
end
context 'with simple pattern "abc"' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('abc') }
- it 'match?' do
- expect(pattern.match?('abc')).to be_truthy
- expect(pattern.match?('a')).to be_falsey
- expect(pattern.match?('abcd')).to be_falsey
- expect(pattern.match?('/abc')).to be_falsey
- expect(pattern.match?('')).to be_falsey
- expect(pattern.match?('/')).to be_falsey
- end
- it 'exact_path' do
- expect(pattern.exact_path).to eq('abc')
- end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('')).to be_falsey
- expect(pattern.could_match_children?('abc')).to be_falsey
- expect(pattern.could_match_children?('/abc')).to be_falsey
+ let(:pattern) { Chef::ChefFS::FilePattern.new("abc") }
+ it "match?" do
+ expect(pattern.match?("abc")).to be_truthy
+ expect(pattern.match?("a")).to be_falsey
+ expect(pattern.match?("abcd")).to be_falsey
+ expect(pattern.match?("/abc")).to be_falsey
+ expect(pattern.match?("")).to be_falsey
+ expect(pattern.match?("/")).to be_falsey
+ end
+ it "exact_path" do
+ expect(pattern.exact_path).to eq("abc")
+ end
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("")).to be_falsey
+ expect(pattern.could_match_children?("abc")).to be_falsey
+ expect(pattern.could_match_children?("/abc")).to be_falsey
end
end
context 'with simple pattern "/abc"' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('/abc') }
- it 'match?' do
- expect(pattern.match?('/abc')).to be_truthy
- expect(pattern.match?('abc')).to be_falsey
- expect(pattern.match?('a')).to be_falsey
- expect(pattern.match?('abcd')).to be_falsey
- expect(pattern.match?('')).to be_falsey
- expect(pattern.match?('/')).to be_falsey
- end
- it 'exact_path' do
- expect(pattern.exact_path).to eq('/abc')
- end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('abc')).to be_falsey
- expect(pattern.could_match_children?('/abc')).to be_falsey
- expect(pattern.could_match_children?('/')).to be_truthy
- expect(pattern.could_match_children?('')).to be_falsey
- end
- it 'exact_child_name_under' do
- expect(pattern.exact_child_name_under('/')).to eq('abc')
+ let(:pattern) { Chef::ChefFS::FilePattern.new("/abc") }
+ it "match?" do
+ expect(pattern.match?("/abc")).to be_truthy
+ expect(pattern.match?("abc")).to be_falsey
+ expect(pattern.match?("a")).to be_falsey
+ expect(pattern.match?("abcd")).to be_falsey
+ expect(pattern.match?("")).to be_falsey
+ expect(pattern.match?("/")).to be_falsey
+ end
+ it "exact_path" do
+ expect(pattern.exact_path).to eq("/abc")
+ end
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("abc")).to be_falsey
+ expect(pattern.could_match_children?("/abc")).to be_falsey
+ expect(pattern.could_match_children?("/")).to be_truthy
+ expect(pattern.could_match_children?("")).to be_falsey
+ end
+ it "exact_child_name_under" do
+ expect(pattern.exact_child_name_under("/")).to eq("abc")
end
end
context 'with simple pattern "abc/def/ghi"' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('abc/def/ghi') }
- it 'match?' do
- expect(pattern.match?('abc/def/ghi')).to be_truthy
- expect(pattern.match?('/abc/def/ghi')).to be_falsey
- expect(pattern.match?('abc')).to be_falsey
- expect(pattern.match?('abc/def')).to be_falsey
- end
- it 'exact_path' do
- expect(pattern.exact_path).to eq('abc/def/ghi')
- end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('abc')).to be_truthy
- expect(pattern.could_match_children?('xyz')).to be_falsey
- expect(pattern.could_match_children?('/abc')).to be_falsey
- expect(pattern.could_match_children?('abc/def')).to be_truthy
- expect(pattern.could_match_children?('abc/xyz')).to be_falsey
- expect(pattern.could_match_children?('abc/def/ghi')).to be_falsey
- end
- it 'exact_child_name_under' do
- expect(pattern.exact_child_name_under('abc')).to eq('def')
- expect(pattern.exact_child_name_under('abc/def')).to eq('ghi')
+ let(:pattern) { Chef::ChefFS::FilePattern.new("abc/def/ghi") }
+ it "match?" do
+ expect(pattern.match?("abc/def/ghi")).to be_truthy
+ expect(pattern.match?("/abc/def/ghi")).to be_falsey
+ expect(pattern.match?("abc")).to be_falsey
+ expect(pattern.match?("abc/def")).to be_falsey
+ end
+ it "exact_path" do
+ expect(pattern.exact_path).to eq("abc/def/ghi")
+ end
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("abc")).to be_truthy
+ expect(pattern.could_match_children?("xyz")).to be_falsey
+ expect(pattern.could_match_children?("/abc")).to be_falsey
+ expect(pattern.could_match_children?("abc/def")).to be_truthy
+ expect(pattern.could_match_children?("abc/xyz")).to be_falsey
+ expect(pattern.could_match_children?("abc/def/ghi")).to be_falsey
+ end
+ it "exact_child_name_under" do
+ expect(pattern.exact_child_name_under("abc")).to eq("def")
+ expect(pattern.exact_child_name_under("abc/def")).to eq("ghi")
end
end
context 'with simple pattern "/abc/def/ghi"' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/def/ghi') }
- it 'match?' do
- expect(pattern.match?('/abc/def/ghi')).to be_truthy
- expect(pattern.match?('abc/def/ghi')).to be_falsey
- expect(pattern.match?('/abc')).to be_falsey
- expect(pattern.match?('/abc/def')).to be_falsey
- end
- it 'exact_path' do
- expect(pattern.exact_path).to eq('/abc/def/ghi')
- end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('/abc')).to be_truthy
- expect(pattern.could_match_children?('/xyz')).to be_falsey
- expect(pattern.could_match_children?('abc')).to be_falsey
- expect(pattern.could_match_children?('/abc/def')).to be_truthy
- expect(pattern.could_match_children?('/abc/xyz')).to be_falsey
- expect(pattern.could_match_children?('/abc/def/ghi')).to be_falsey
- end
- it 'exact_child_name_under' do
- expect(pattern.exact_child_name_under('/')).to eq('abc')
- expect(pattern.exact_child_name_under('/abc')).to eq('def')
- expect(pattern.exact_child_name_under('/abc/def')).to eq('ghi')
+ let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/def/ghi") }
+ it "match?" do
+ expect(pattern.match?("/abc/def/ghi")).to be_truthy
+ expect(pattern.match?("abc/def/ghi")).to be_falsey
+ expect(pattern.match?("/abc")).to be_falsey
+ expect(pattern.match?("/abc/def")).to be_falsey
+ end
+ it "exact_path" do
+ expect(pattern.exact_path).to eq("/abc/def/ghi")
+ end
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("/abc")).to be_truthy
+ expect(pattern.could_match_children?("/xyz")).to be_falsey
+ expect(pattern.could_match_children?("abc")).to be_falsey
+ expect(pattern.could_match_children?("/abc/def")).to be_truthy
+ expect(pattern.could_match_children?("/abc/xyz")).to be_falsey
+ expect(pattern.could_match_children?("/abc/def/ghi")).to be_falsey
+ end
+ it "exact_child_name_under" do
+ expect(pattern.exact_child_name_under("/")).to eq("abc")
+ expect(pattern.exact_child_name_under("/abc")).to eq("def")
+ expect(pattern.exact_child_name_under("/abc/def")).to eq("ghi")
end
end
context 'with simple pattern "a\*\b"', :skip => (Chef::Platform.windows?) do
let(:pattern) { Chef::ChefFS::FilePattern.new('a\*\b') }
- it 'match?' do
- expect(pattern.match?('a*b')).to be_truthy
- expect(pattern.match?('ab')).to be_falsey
- expect(pattern.match?('acb')).to be_falsey
- expect(pattern.match?('ab')).to be_falsey
+ it "match?" do
+ expect(pattern.match?("a*b")).to be_truthy
+ expect(pattern.match?("ab")).to be_falsey
+ expect(pattern.match?("acb")).to be_falsey
+ expect(pattern.match?("ab")).to be_falsey
end
- it 'exact_path' do
- expect(pattern.exact_path).to eq('a*b')
+ it "exact_path" do
+ expect(pattern.exact_path).to eq("a*b")
end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('a/*b')).to be_falsey
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("a/*b")).to be_falsey
end
end
context 'with star pattern "/abc/*/ghi"' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/*/ghi') }
- it 'match?' do
- expect(pattern.match?('/abc/def/ghi')).to be_truthy
- expect(pattern.match?('/abc/ghi')).to be_falsey
+ let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/*/ghi") }
+ it "match?" do
+ expect(pattern.match?("/abc/def/ghi")).to be_truthy
+ expect(pattern.match?("/abc/ghi")).to be_falsey
end
- it 'exact_path' do
+ it "exact_path" do
expect(pattern.exact_path).to be_nil
end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('/abc')).to be_truthy
- expect(pattern.could_match_children?('/xyz')).to be_falsey
- expect(pattern.could_match_children?('abc')).to be_falsey
- expect(pattern.could_match_children?('/abc/def')).to be_truthy
- expect(pattern.could_match_children?('/abc/xyz')).to be_truthy
- expect(pattern.could_match_children?('/abc/def/ghi')).to be_falsey
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("/abc")).to be_truthy
+ expect(pattern.could_match_children?("/xyz")).to be_falsey
+ expect(pattern.could_match_children?("abc")).to be_falsey
+ expect(pattern.could_match_children?("/abc/def")).to be_truthy
+ expect(pattern.could_match_children?("/abc/xyz")).to be_truthy
+ expect(pattern.could_match_children?("/abc/def/ghi")).to be_falsey
end
- it 'exact_child_name_under' do
- expect(pattern.exact_child_name_under('/')).to eq('abc')
- expect(pattern.exact_child_name_under('/abc')).to eq(nil)
- expect(pattern.exact_child_name_under('/abc/def')).to eq('ghi')
+ it "exact_child_name_under" do
+ expect(pattern.exact_child_name_under("/")).to eq("abc")
+ expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+ expect(pattern.exact_child_name_under("/abc/def")).to eq("ghi")
end
end
context 'with star pattern "/abc/d*f/ghi"' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d*f/ghi') }
- it 'match?' do
- expect(pattern.match?('/abc/def/ghi')).to be_truthy
- expect(pattern.match?('/abc/dxf/ghi')).to be_truthy
- expect(pattern.match?('/abc/df/ghi')).to be_truthy
- expect(pattern.match?('/abc/dxyzf/ghi')).to be_truthy
- expect(pattern.match?('/abc/d/ghi')).to be_falsey
- expect(pattern.match?('/abc/f/ghi')).to be_falsey
- expect(pattern.match?('/abc/ghi')).to be_falsey
- expect(pattern.match?('/abc/xyz/ghi')).to be_falsey
- end
- it 'exact_path' do
+ let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/d*f/ghi") }
+ it "match?" do
+ expect(pattern.match?("/abc/def/ghi")).to be_truthy
+ expect(pattern.match?("/abc/dxf/ghi")).to be_truthy
+ expect(pattern.match?("/abc/df/ghi")).to be_truthy
+ expect(pattern.match?("/abc/dxyzf/ghi")).to be_truthy
+ expect(pattern.match?("/abc/d/ghi")).to be_falsey
+ expect(pattern.match?("/abc/f/ghi")).to be_falsey
+ expect(pattern.match?("/abc/ghi")).to be_falsey
+ expect(pattern.match?("/abc/xyz/ghi")).to be_falsey
+ end
+ it "exact_path" do
expect(pattern.exact_path).to be_nil
end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('/abc')).to be_truthy
- expect(pattern.could_match_children?('/xyz')).to be_falsey
- expect(pattern.could_match_children?('abc')).to be_falsey
- expect(pattern.could_match_children?('/abc/def')).to be_truthy
- expect(pattern.could_match_children?('/abc/xyz')).to be_falsey
- expect(pattern.could_match_children?('/abc/dxyzf')).to be_truthy
- expect(pattern.could_match_children?('/abc/df')).to be_truthy
- expect(pattern.could_match_children?('/abc/d')).to be_falsey
- expect(pattern.could_match_children?('/abc/f')).to be_falsey
- expect(pattern.could_match_children?('/abc/def/ghi')).to be_falsey
- end
- it 'exact_child_name_under' do
- expect(pattern.exact_child_name_under('/')).to eq('abc')
- expect(pattern.exact_child_name_under('/abc')).to eq(nil)
- expect(pattern.exact_child_name_under('/abc/def')).to eq('ghi')
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("/abc")).to be_truthy
+ expect(pattern.could_match_children?("/xyz")).to be_falsey
+ expect(pattern.could_match_children?("abc")).to be_falsey
+ expect(pattern.could_match_children?("/abc/def")).to be_truthy
+ expect(pattern.could_match_children?("/abc/xyz")).to be_falsey
+ expect(pattern.could_match_children?("/abc/dxyzf")).to be_truthy
+ expect(pattern.could_match_children?("/abc/df")).to be_truthy
+ expect(pattern.could_match_children?("/abc/d")).to be_falsey
+ expect(pattern.could_match_children?("/abc/f")).to be_falsey
+ expect(pattern.could_match_children?("/abc/def/ghi")).to be_falsey
+ end
+ it "exact_child_name_under" do
+ expect(pattern.exact_child_name_under("/")).to eq("abc")
+ expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+ expect(pattern.exact_child_name_under("/abc/def")).to eq("ghi")
end
end
context 'with star pattern "/abc/d??f/ghi"' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d??f/ghi') }
- it 'match?' do
- expect(pattern.match?('/abc/deef/ghi')).to be_truthy
- expect(pattern.match?('/abc/deeef/ghi')).to be_falsey
- expect(pattern.match?('/abc/def/ghi')).to be_falsey
- expect(pattern.match?('/abc/df/ghi')).to be_falsey
- expect(pattern.match?('/abc/d/ghi')).to be_falsey
- expect(pattern.match?('/abc/f/ghi')).to be_falsey
- expect(pattern.match?('/abc/ghi')).to be_falsey
- end
- it 'exact_path' do
+ let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/d??f/ghi") }
+ it "match?" do
+ expect(pattern.match?("/abc/deef/ghi")).to be_truthy
+ expect(pattern.match?("/abc/deeef/ghi")).to be_falsey
+ expect(pattern.match?("/abc/def/ghi")).to be_falsey
+ expect(pattern.match?("/abc/df/ghi")).to be_falsey
+ expect(pattern.match?("/abc/d/ghi")).to be_falsey
+ expect(pattern.match?("/abc/f/ghi")).to be_falsey
+ expect(pattern.match?("/abc/ghi")).to be_falsey
+ end
+ it "exact_path" do
expect(pattern.exact_path).to be_nil
end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('/abc')).to be_truthy
- expect(pattern.could_match_children?('/xyz')).to be_falsey
- expect(pattern.could_match_children?('abc')).to be_falsey
- expect(pattern.could_match_children?('/abc/deef')).to be_truthy
- expect(pattern.could_match_children?('/abc/deeef')).to be_falsey
- expect(pattern.could_match_children?('/abc/def')).to be_falsey
- expect(pattern.could_match_children?('/abc/df')).to be_falsey
- expect(pattern.could_match_children?('/abc/d')).to be_falsey
- expect(pattern.could_match_children?('/abc/f')).to be_falsey
- expect(pattern.could_match_children?('/abc/deef/ghi')).to be_falsey
- end
- it 'exact_child_name_under' do
- expect(pattern.exact_child_name_under('/')).to eq('abc')
- expect(pattern.exact_child_name_under('/abc')).to eq(nil)
- expect(pattern.exact_child_name_under('/abc/deef')).to eq('ghi')
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("/abc")).to be_truthy
+ expect(pattern.could_match_children?("/xyz")).to be_falsey
+ expect(pattern.could_match_children?("abc")).to be_falsey
+ expect(pattern.could_match_children?("/abc/deef")).to be_truthy
+ expect(pattern.could_match_children?("/abc/deeef")).to be_falsey
+ expect(pattern.could_match_children?("/abc/def")).to be_falsey
+ expect(pattern.could_match_children?("/abc/df")).to be_falsey
+ expect(pattern.could_match_children?("/abc/d")).to be_falsey
+ expect(pattern.could_match_children?("/abc/f")).to be_falsey
+ expect(pattern.could_match_children?("/abc/deef/ghi")).to be_falsey
+ end
+ it "exact_child_name_under" do
+ expect(pattern.exact_child_name_under("/")).to eq("abc")
+ expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+ expect(pattern.exact_child_name_under("/abc/deef")).to eq("ghi")
end
end
context 'with star pattern "/abc/d[a-z][0-9]f/ghi"', :skip => (Chef::Platform.windows?) do
- let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d[a-z][0-9]f/ghi') }
- it 'match?' do
- expect(pattern.match?('/abc/de1f/ghi')).to be_truthy
- expect(pattern.match?('/abc/deef/ghi')).to be_falsey
- expect(pattern.match?('/abc/d11f/ghi')).to be_falsey
- expect(pattern.match?('/abc/de11f/ghi')).to be_falsey
- expect(pattern.match?('/abc/dee1f/ghi')).to be_falsey
- expect(pattern.match?('/abc/df/ghi')).to be_falsey
- expect(pattern.match?('/abc/d/ghi')).to be_falsey
- expect(pattern.match?('/abc/f/ghi')).to be_falsey
- expect(pattern.match?('/abc/ghi')).to be_falsey
- end
- it 'exact_path' do
+ let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/d[a-z][0-9]f/ghi") }
+ it "match?" do
+ expect(pattern.match?("/abc/de1f/ghi")).to be_truthy
+ expect(pattern.match?("/abc/deef/ghi")).to be_falsey
+ expect(pattern.match?("/abc/d11f/ghi")).to be_falsey
+ expect(pattern.match?("/abc/de11f/ghi")).to be_falsey
+ expect(pattern.match?("/abc/dee1f/ghi")).to be_falsey
+ expect(pattern.match?("/abc/df/ghi")).to be_falsey
+ expect(pattern.match?("/abc/d/ghi")).to be_falsey
+ expect(pattern.match?("/abc/f/ghi")).to be_falsey
+ expect(pattern.match?("/abc/ghi")).to be_falsey
+ end
+ it "exact_path" do
expect(pattern.exact_path).to be_nil
end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('/abc')).to be_truthy
- expect(pattern.could_match_children?('/xyz')).to be_falsey
- expect(pattern.could_match_children?('abc')).to be_falsey
- expect(pattern.could_match_children?('/abc/de1f')).to be_truthy
- expect(pattern.could_match_children?('/abc/deef')).to be_falsey
- expect(pattern.could_match_children?('/abc/d11f')).to be_falsey
- expect(pattern.could_match_children?('/abc/de11f')).to be_falsey
- expect(pattern.could_match_children?('/abc/dee1f')).to be_falsey
- expect(pattern.could_match_children?('/abc/def')).to be_falsey
- expect(pattern.could_match_children?('/abc/df')).to be_falsey
- expect(pattern.could_match_children?('/abc/d')).to be_falsey
- expect(pattern.could_match_children?('/abc/f')).to be_falsey
- expect(pattern.could_match_children?('/abc/de1f/ghi')).to be_falsey
- end
- it 'exact_child_name_under' do
- expect(pattern.exact_child_name_under('/')).to eq('abc')
- expect(pattern.exact_child_name_under('/abc')).to eq(nil)
- expect(pattern.exact_child_name_under('/abc/de1f')).to eq('ghi')
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("/abc")).to be_truthy
+ expect(pattern.could_match_children?("/xyz")).to be_falsey
+ expect(pattern.could_match_children?("abc")).to be_falsey
+ expect(pattern.could_match_children?("/abc/de1f")).to be_truthy
+ expect(pattern.could_match_children?("/abc/deef")).to be_falsey
+ expect(pattern.could_match_children?("/abc/d11f")).to be_falsey
+ expect(pattern.could_match_children?("/abc/de11f")).to be_falsey
+ expect(pattern.could_match_children?("/abc/dee1f")).to be_falsey
+ expect(pattern.could_match_children?("/abc/def")).to be_falsey
+ expect(pattern.could_match_children?("/abc/df")).to be_falsey
+ expect(pattern.could_match_children?("/abc/d")).to be_falsey
+ expect(pattern.could_match_children?("/abc/f")).to be_falsey
+ expect(pattern.could_match_children?("/abc/de1f/ghi")).to be_falsey
+ end
+ it "exact_child_name_under" do
+ expect(pattern.exact_child_name_under("/")).to eq("abc")
+ expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+ expect(pattern.exact_child_name_under("/abc/de1f")).to eq("ghi")
end
end
context 'with star pattern "/abc/**/ghi"' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/**/ghi') }
- it 'match?' do
- expect(pattern.match?('/abc/def/ghi')).to be_truthy
- expect(pattern.match?('/abc/d/e/f/ghi')).to be_truthy
- expect(pattern.match?('/abc/ghi')).to be_falsey
- expect(pattern.match?('/abcdef/d/ghi')).to be_falsey
- expect(pattern.match?('/abc/d/defghi')).to be_falsey
- expect(pattern.match?('/xyz')).to be_falsey
- end
- it 'exact_path' do
+ let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/**/ghi") }
+ it "match?" do
+ expect(pattern.match?("/abc/def/ghi")).to be_truthy
+ expect(pattern.match?("/abc/d/e/f/ghi")).to be_truthy
+ expect(pattern.match?("/abc/ghi")).to be_falsey
+ expect(pattern.match?("/abcdef/d/ghi")).to be_falsey
+ expect(pattern.match?("/abc/d/defghi")).to be_falsey
+ expect(pattern.match?("/xyz")).to be_falsey
+ end
+ it "exact_path" do
expect(pattern.exact_path).to be_nil
end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('/abc')).to be_truthy
- expect(pattern.could_match_children?('/abc/d')).to be_truthy
- expect(pattern.could_match_children?('/abc/d/e')).to be_truthy
- expect(pattern.could_match_children?('/abc/d/e/f')).to be_truthy
- expect(pattern.could_match_children?('/abc/def/ghi')).to be_truthy
- expect(pattern.could_match_children?('abc')).to be_falsey
- expect(pattern.could_match_children?('/xyz')).to be_falsey
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("/abc")).to be_truthy
+ expect(pattern.could_match_children?("/abc/d")).to be_truthy
+ expect(pattern.could_match_children?("/abc/d/e")).to be_truthy
+ expect(pattern.could_match_children?("/abc/d/e/f")).to be_truthy
+ expect(pattern.could_match_children?("/abc/def/ghi")).to be_truthy
+ expect(pattern.could_match_children?("abc")).to be_falsey
+ expect(pattern.could_match_children?("/xyz")).to be_falsey
end
- it 'exact_child_name_under' do
- expect(pattern.exact_child_name_under('/')).to eq('abc')
- expect(pattern.exact_child_name_under('/abc')).to eq(nil)
- expect(pattern.exact_child_name_under('/abc/def')).to eq(nil)
+ it "exact_child_name_under" do
+ expect(pattern.exact_child_name_under("/")).to eq("abc")
+ expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+ expect(pattern.exact_child_name_under("/abc/def")).to eq(nil)
end
end
context 'with star pattern "/abc**/ghi"' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('/abc**/ghi') }
- it 'match?' do
- expect(pattern.match?('/abc/def/ghi')).to be_truthy
- expect(pattern.match?('/abc/d/e/f/ghi')).to be_truthy
- expect(pattern.match?('/abc/ghi')).to be_truthy
- expect(pattern.match?('/abcdef/ghi')).to be_truthy
- expect(pattern.match?('/abc/defghi')).to be_falsey
- expect(pattern.match?('/xyz')).to be_falsey
- end
- it 'exact_path' do
+ let(:pattern) { Chef::ChefFS::FilePattern.new("/abc**/ghi") }
+ it "match?" do
+ expect(pattern.match?("/abc/def/ghi")).to be_truthy
+ expect(pattern.match?("/abc/d/e/f/ghi")).to be_truthy
+ expect(pattern.match?("/abc/ghi")).to be_truthy
+ expect(pattern.match?("/abcdef/ghi")).to be_truthy
+ expect(pattern.match?("/abc/defghi")).to be_falsey
+ expect(pattern.match?("/xyz")).to be_falsey
+ end
+ it "exact_path" do
expect(pattern.exact_path).to be_nil
end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('/abc')).to be_truthy
- expect(pattern.could_match_children?('/abcdef')).to be_truthy
- expect(pattern.could_match_children?('/abc/d/e')).to be_truthy
- expect(pattern.could_match_children?('/abc/d/e/f')).to be_truthy
- expect(pattern.could_match_children?('/abc/def/ghi')).to be_truthy
- expect(pattern.could_match_children?('abc')).to be_falsey
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("/abc")).to be_truthy
+ expect(pattern.could_match_children?("/abcdef")).to be_truthy
+ expect(pattern.could_match_children?("/abc/d/e")).to be_truthy
+ expect(pattern.could_match_children?("/abc/d/e/f")).to be_truthy
+ expect(pattern.could_match_children?("/abc/def/ghi")).to be_truthy
+ expect(pattern.could_match_children?("abc")).to be_falsey
end
- it 'exact_child_name_under' do
- expect(pattern.exact_child_name_under('/')).to eq(nil)
- expect(pattern.exact_child_name_under('/abc')).to eq(nil)
- expect(pattern.exact_child_name_under('/abc/def')).to eq(nil)
+ it "exact_child_name_under" do
+ expect(pattern.exact_child_name_under("/")).to eq(nil)
+ expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+ expect(pattern.exact_child_name_under("/abc/def")).to eq(nil)
end
end
context 'with star pattern "/abc/**ghi"' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/**ghi') }
- it 'match?' do
- expect(pattern.match?('/abc/def/ghi')).to be_truthy
- expect(pattern.match?('/abc/def/ghi/ghi')).to be_truthy
- expect(pattern.match?('/abc/def/ghi/jkl')).to be_falsey
- expect(pattern.match?('/abc/d/e/f/ghi')).to be_truthy
- expect(pattern.match?('/abc/ghi')).to be_truthy
- expect(pattern.match?('/abcdef/ghi')).to be_falsey
- expect(pattern.match?('/abc/defghi')).to be_truthy
- expect(pattern.match?('/xyz')).to be_falsey
- end
- it 'exact_path' do
+ let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/**ghi") }
+ it "match?" do
+ expect(pattern.match?("/abc/def/ghi")).to be_truthy
+ expect(pattern.match?("/abc/def/ghi/ghi")).to be_truthy
+ expect(pattern.match?("/abc/def/ghi/jkl")).to be_falsey
+ expect(pattern.match?("/abc/d/e/f/ghi")).to be_truthy
+ expect(pattern.match?("/abc/ghi")).to be_truthy
+ expect(pattern.match?("/abcdef/ghi")).to be_falsey
+ expect(pattern.match?("/abc/defghi")).to be_truthy
+ expect(pattern.match?("/xyz")).to be_falsey
+ end
+ it "exact_path" do
expect(pattern.exact_path).to be_nil
end
- it 'could_match_children?' do
- expect(pattern.could_match_children?('/abc')).to be_truthy
- expect(pattern.could_match_children?('/abcdef')).to be_falsey
- expect(pattern.could_match_children?('/abc/d/e')).to be_truthy
- expect(pattern.could_match_children?('/abc/d/e/f')).to be_truthy
- expect(pattern.could_match_children?('/abc/def/ghi')).to be_truthy
- expect(pattern.could_match_children?('abc')).to be_falsey
- expect(pattern.could_match_children?('/xyz')).to be_falsey
+ it "could_match_children?" do
+ expect(pattern.could_match_children?("/abc")).to be_truthy
+ expect(pattern.could_match_children?("/abcdef")).to be_falsey
+ expect(pattern.could_match_children?("/abc/d/e")).to be_truthy
+ expect(pattern.could_match_children?("/abc/d/e/f")).to be_truthy
+ expect(pattern.could_match_children?("/abc/def/ghi")).to be_truthy
+ expect(pattern.could_match_children?("abc")).to be_falsey
+ expect(pattern.could_match_children?("/xyz")).to be_falsey
end
- it 'exact_child_name_under' do
- expect(pattern.exact_child_name_under('/')).to eq('abc')
- expect(pattern.exact_child_name_under('/abc')).to eq(nil)
- expect(pattern.exact_child_name_under('/abc/def')).to eq(nil)
+ it "exact_child_name_under" do
+ expect(pattern.exact_child_name_under("/")).to eq("abc")
+ expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+ expect(pattern.exact_child_name_under("/abc/def")).to eq(nil)
end
end
context 'with star pattern "a**b**c"' do
- let(:pattern) { Chef::ChefFS::FilePattern.new('a**b**c') }
- it 'match?' do
- expect(pattern.match?('axybzwc')).to be_truthy
- expect(pattern.match?('abc')).to be_truthy
- expect(pattern.match?('axyzwc')).to be_falsey
- expect(pattern.match?('ac')).to be_falsey
- expect(pattern.match?('a/x/y/b/z/w/c')).to be_truthy
- end
- it 'exact_path' do
+ let(:pattern) { Chef::ChefFS::FilePattern.new("a**b**c") }
+ it "match?" do
+ expect(pattern.match?("axybzwc")).to be_truthy
+ expect(pattern.match?("abc")).to be_truthy
+ expect(pattern.match?("axyzwc")).to be_falsey
+ expect(pattern.match?("ac")).to be_falsey
+ expect(pattern.match?("a/x/y/b/z/w/c")).to be_truthy
+ end
+ it "exact_path" do
expect(pattern.exact_path).to be_nil
end
end
- context 'normalization tests' do
- it 'handles trailing slashes' do
- expect(p('abc/').normalized_pattern).to eq('abc')
- expect(p('abc/').exact_path).to eq('abc')
- expect(p('abc/').match?('abc')).to be_truthy
- expect(p('//').normalized_pattern).to eq('/')
- expect(p('//').exact_path).to eq('/')
- expect(p('//').match?('/')).to be_truthy
- expect(p('/./').normalized_pattern).to eq('/')
- expect(p('/./').exact_path).to eq('/')
- expect(p('/./').match?('/')).to be_truthy
- end
- it 'handles multiple slashes' do
- expect(p('abc//def').normalized_pattern).to eq('abc/def')
- expect(p('abc//def').exact_path).to eq('abc/def')
- expect(p('abc//def').match?('abc/def')).to be_truthy
- expect(p('abc//').normalized_pattern).to eq('abc')
- expect(p('abc//').exact_path).to eq('abc')
- expect(p('abc//').match?('abc')).to be_truthy
- end
- it 'handles dot' do
- expect(p('abc/./def').normalized_pattern).to eq('abc/def')
- expect(p('abc/./def').exact_path).to eq('abc/def')
- expect(p('abc/./def').match?('abc/def')).to be_truthy
- expect(p('./abc/def').normalized_pattern).to eq('abc/def')
- expect(p('./abc/def').exact_path).to eq('abc/def')
- expect(p('./abc/def').match?('abc/def')).to be_truthy
- expect(p('/.').normalized_pattern).to eq('/')
- expect(p('/.').exact_path).to eq('/')
- expect(p('/.').match?('/')).to be_truthy
- end
- it 'handles dotdot' do
- expect(p('abc/../def').normalized_pattern).to eq('def')
- expect(p('abc/../def').exact_path).to eq('def')
- expect(p('abc/../def').match?('def')).to be_truthy
- expect(p('abc/def/../..').normalized_pattern).to eq('')
- expect(p('abc/def/../..').exact_path).to eq('')
- expect(p('abc/def/../..').match?('')).to be_truthy
- expect(p('/*/../def').normalized_pattern).to eq('/def')
- expect(p('/*/../def').exact_path).to eq('/def')
- expect(p('/*/../def').match?('/def')).to be_truthy
- expect(p('/*/*/../def').normalized_pattern).to eq('/*/def')
- expect(p('/*/*/../def').exact_path).to be_nil
- expect(p('/*/*/../def').match?('/abc/def')).to be_truthy
- expect(p('/abc/def/../..').normalized_pattern).to eq('/')
- expect(p('/abc/def/../..').exact_path).to eq('/')
- expect(p('/abc/def/../..').match?('/')).to be_truthy
- expect(p('abc/../../def').normalized_pattern).to eq('../def')
- expect(p('abc/../../def').exact_path).to eq('../def')
- expect(p('abc/../../def').match?('../def')).to be_truthy
- end
- it 'handles dotdot with double star' do
- expect(p('abc**/def/../ghi').exact_path).to be_nil
- expect(p('abc**/def/../ghi').match?('abc/ghi')).to be_truthy
- expect(p('abc**/def/../ghi').match?('abc/x/y/z/ghi')).to be_truthy
- expect(p('abc**/def/../ghi').match?('ghi')).to be_falsey
- end
- it 'raises error on dotdot with overlapping double star' do
- expect { Chef::ChefFS::FilePattern.new('abc/**/../def').exact_path }.to raise_error(ArgumentError)
- expect { Chef::ChefFS::FilePattern.new('abc/**/abc/../../def').exact_path }.to raise_error(ArgumentError)
- end
- it 'handles leading dotdot' do
- expect(p('../abc/def').exact_path).to eq('../abc/def')
- expect(p('../abc/def').match?('../abc/def')).to be_truthy
- expect(p('/../abc/def').exact_path).to eq('/abc/def')
- expect(p('/../abc/def').match?('/abc/def')).to be_truthy
- expect(p('..').exact_path).to eq('..')
- expect(p('..').match?('..')).to be_truthy
- expect(p('/..').exact_path).to eq('/')
- expect(p('/..').match?('/')).to be_truthy
+ context "normalization tests" do
+ it "handles trailing slashes" do
+ expect(p("abc/").normalized_pattern).to eq("abc")
+ expect(p("abc/").exact_path).to eq("abc")
+ expect(p("abc/").match?("abc")).to be_truthy
+ expect(p("//").normalized_pattern).to eq("/")
+ expect(p("//").exact_path).to eq("/")
+ expect(p("//").match?("/")).to be_truthy
+ expect(p("/./").normalized_pattern).to eq("/")
+ expect(p("/./").exact_path).to eq("/")
+ expect(p("/./").match?("/")).to be_truthy
+ end
+ it "handles multiple slashes" do
+ expect(p("abc//def").normalized_pattern).to eq("abc/def")
+ expect(p("abc//def").exact_path).to eq("abc/def")
+ expect(p("abc//def").match?("abc/def")).to be_truthy
+ expect(p("abc//").normalized_pattern).to eq("abc")
+ expect(p("abc//").exact_path).to eq("abc")
+ expect(p("abc//").match?("abc")).to be_truthy
+ end
+ it "handles dot" do
+ expect(p("abc/./def").normalized_pattern).to eq("abc/def")
+ expect(p("abc/./def").exact_path).to eq("abc/def")
+ expect(p("abc/./def").match?("abc/def")).to be_truthy
+ expect(p("./abc/def").normalized_pattern).to eq("abc/def")
+ expect(p("./abc/def").exact_path).to eq("abc/def")
+ expect(p("./abc/def").match?("abc/def")).to be_truthy
+ expect(p("/.").normalized_pattern).to eq("/")
+ expect(p("/.").exact_path).to eq("/")
+ expect(p("/.").match?("/")).to be_truthy
+ end
+ it "handles dotdot" do
+ expect(p("abc/../def").normalized_pattern).to eq("def")
+ expect(p("abc/../def").exact_path).to eq("def")
+ expect(p("abc/../def").match?("def")).to be_truthy
+ expect(p("abc/def/../..").normalized_pattern).to eq("")
+ expect(p("abc/def/../..").exact_path).to eq("")
+ expect(p("abc/def/../..").match?("")).to be_truthy
+ expect(p("/*/../def").normalized_pattern).to eq("/def")
+ expect(p("/*/../def").exact_path).to eq("/def")
+ expect(p("/*/../def").match?("/def")).to be_truthy
+ expect(p("/*/*/../def").normalized_pattern).to eq("/*/def")
+ expect(p("/*/*/../def").exact_path).to be_nil
+ expect(p("/*/*/../def").match?("/abc/def")).to be_truthy
+ expect(p("/abc/def/../..").normalized_pattern).to eq("/")
+ expect(p("/abc/def/../..").exact_path).to eq("/")
+ expect(p("/abc/def/../..").match?("/")).to be_truthy
+ expect(p("abc/../../def").normalized_pattern).to eq("../def")
+ expect(p("abc/../../def").exact_path).to eq("../def")
+ expect(p("abc/../../def").match?("../def")).to be_truthy
+ end
+ it "handles dotdot with double star" do
+ expect(p("abc**/def/../ghi").exact_path).to be_nil
+ expect(p("abc**/def/../ghi").match?("abc/ghi")).to be_truthy
+ expect(p("abc**/def/../ghi").match?("abc/x/y/z/ghi")).to be_truthy
+ expect(p("abc**/def/../ghi").match?("ghi")).to be_falsey
+ end
+ it "raises error on dotdot with overlapping double star" do
+ expect { Chef::ChefFS::FilePattern.new("abc/**/../def").exact_path }.to raise_error(ArgumentError)
+ expect { Chef::ChefFS::FilePattern.new("abc/**/abc/../../def").exact_path }.to raise_error(ArgumentError)
+ end
+ it "handles leading dotdot" do
+ expect(p("../abc/def").exact_path).to eq("../abc/def")
+ expect(p("../abc/def").match?("../abc/def")).to be_truthy
+ expect(p("/../abc/def").exact_path).to eq("/abc/def")
+ expect(p("/../abc/def").match?("/abc/def")).to be_truthy
+ expect(p("..").exact_path).to eq("..")
+ expect(p("..").match?("..")).to be_truthy
+ expect(p("/..").exact_path).to eq("/")
+ expect(p("/..").match?("/")).to be_truthy
end
end
-
# match?
# - single element matches (empty, fixed, ?, *, characters, escapes)
# - nested matches
diff --git a/spec/unit/chef_fs/file_system/cookbook_subdir_spec.rb b/spec/unit/chef_fs/file_system/cookbook_subdir_spec.rb
new file mode 100644
index 0000000000..92ea8d0cea
--- /dev/null
+++ b/spec/unit/chef_fs/file_system/cookbook_subdir_spec.rb
@@ -0,0 +1,34 @@
+#
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/chef_fs/file_system/chef_server/cookbook_subdir"
+
+describe Chef::ChefFS::FileSystem::ChefServer::CookbookSubdir do
+ let(:root) do
+ Chef::ChefFS::FileSystem::BaseFSDir.new("", nil)
+ end
+
+ let(:cookbook_subdir) do
+ Chef::ChefFS::FileSystem::ChefServer::CookbookSubdir.new("test", root, false, true)
+ end
+
+ it "can get child" do
+ cookbook_subdir.child("test")
+ end
+end
diff --git a/spec/unit/chef_fs/file_system/operation_failed_error_spec.rb b/spec/unit/chef_fs/file_system/operation_failed_error_spec.rb
index 142755a4f1..7f3eb6efe2 100644
--- a/spec/unit/chef_fs/file_system/operation_failed_error_spec.rb
+++ b/spec/unit/chef_fs/file_system/operation_failed_error_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,31 +16,31 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/chef_fs/file_system/operation_failed_error'
+require "spec_helper"
+require "chef/chef_fs/file_system/operation_failed_error"
describe Chef::ChefFS::FileSystem::OperationFailedError do
- context 'message' do
+ context "message" do
let(:error_message) { 'HTTP error writing: 400 "Bad Request"' }
- context 'has a cause attribute and HTTP result code is 400' do
- it 'include error cause' do
+ context "has a cause attribute and HTTP result code is 400" do
+ it "include error cause" do
allow_message_expectations_on_nil
response_body = '{"error":["Invalid key test in request body"]}'
allow(@response).to receive(:code).and_return("400")
allow(@response).to receive(:body).and_return(response_body)
exception = Net::HTTPServerException.new("(exception) unauthorized", @response)
- expect {
+ expect do
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, exception), error_message
- }.to raise_error(Chef::ChefFS::FileSystem::OperationFailedError, "#{error_message} cause: #{response_body}")
+ end.to raise_error(Chef::ChefFS::FileSystem::OperationFailedError, "#{error_message} cause: #{response_body}")
end
end
- context 'does not have a cause attribute' do
- it 'does not include error cause' do
- expect {
+ context "does not have a cause attribute" do
+ it "does not include error cause" do
+ expect do
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self), error_message
- }.to raise_error(Chef::ChefFS::FileSystem::OperationFailedError, error_message)
+ end.to raise_error(Chef::ChefFS::FileSystem::OperationFailedError, error_message)
end
end
end
diff --git a/spec/unit/chef_fs/file_system/repository/base_file_spec.rb b/spec/unit/chef_fs/file_system/repository/base_file_spec.rb
new file mode 100644
index 0000000000..625ef32dca
--- /dev/null
+++ b/spec/unit/chef_fs/file_system/repository/base_file_spec.rb
@@ -0,0 +1,126 @@
+#
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/chef_fs/file_system/repository/base_file"
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/base_fs_object"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/chef_fs/file_system/nonexistent_fs_object"
+
+describe Chef::ChefFS::FileSystem::Repository::BaseFile do
+ let(:root) do
+ Chef::ChefFS::FileSystem::BaseFSDir.new("", nil)
+ end
+
+ let(:tmp_dir) { Dir.mktmpdir }
+
+ let(:parent) do
+ Chef::ChefFS::FileSystem::Repository::Directory.new("test", root, tmp_dir)
+ end
+
+ let(:file) do
+ file = described_class.new("test_file.json", parent)
+ file.write_pretty_json = false
+ file
+ end
+
+ let(:content) { '"name": "canteloup"' }
+ let(:file_path) { File.join(tmp_dir, "test_file.json") }
+
+ after do
+ FileUtils.rm_f(file_path)
+ end
+
+ context "#is_json_file?" do
+ it "returns false when the file is not json", pending: "We assume that everything is ruby or JSON" do
+ file = described_class.new("test_file.dpkg", parent)
+ expect(file.is_json_file?).to be_falsey
+ end
+
+ it "returns true when the file is json" do
+ expect(file.is_json_file?).to be_truthy
+ end
+ end
+
+ context "#name_valid?" do
+ it "rejects dotfiles" do
+ file = described_class.new(".test_file.json", parent)
+ expect(file.name_valid?).to be_falsey
+ end
+
+ it "rejects non json files", pending: "We assume that everything is ruby or JSON" do
+ file = described_class.new("test_file.dpkg", parent)
+ expect(file.name_valid?).to be_falsey
+ end
+
+ it "allows ruby files" do
+ file = described_class.new("test_file.rb", parent)
+ expect(file.name_valid?).to be_truthy
+ end
+
+ it "allows correctly named files" do
+ expect(file.name_valid?).to be_truthy
+ end
+ end
+
+ context "#fs_entry_valid?" do
+ it "rejects invalid names" do
+ file = described_class.new("test_file.dpkg", parent)
+ expect(file.fs_entry_valid?).to be_falsey
+ end
+
+ it "rejects missing files" do
+ FileUtils.rm_f(file_path)
+ expect(file.fs_entry_valid?).to be_falsey
+ end
+
+ it "allows present and properly named files" do
+ FileUtils.touch(file_path)
+ expect(file.fs_entry_valid?).to be_truthy
+ end
+ end
+
+ context "#create" do
+ it "doesn't create an existing file" do
+ FileUtils.touch(file_path)
+ expect { file.create('"name": "canteloup"') }.to raise_error(Chef::ChefFS::FileSystem::AlreadyExistsError)
+ end
+
+ it "creates a new file" do
+ expect(file).to receive(:write).with(content)
+ expect { file.create(content) }.to_not raise_error
+ end
+
+ end
+
+ context "#write" do
+ context "minimises a json object" do
+ it "unless pretty json is off" do
+ expect(file).to_not receive(:minimize)
+ file.write(content)
+ end
+
+ it "correctly" do
+ file = described_class.new("test_file.json", parent)
+ file.write_pretty_json = true
+ expect(file).to receive(:minimize).with(content, file).and_return(content)
+ file.write(content)
+ end
+ end
+ end
+end
diff --git a/spec/unit/chef_fs/file_system/repository/directory_spec.rb b/spec/unit/chef_fs/file_system/repository/directory_spec.rb
new file mode 100644
index 0000000000..6e53e52966
--- /dev/null
+++ b/spec/unit/chef_fs/file_system/repository/directory_spec.rb
@@ -0,0 +1,175 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/chef_fs/file_system/repository/directory"
+require "chef/chef_fs/file_system/base_fs_object"
+require "chef/chef_fs/file_system/exceptions"
+require "chef/chef_fs/file_system/nonexistent_fs_object"
+
+CHILD_FILES = %w{ test1.json test2.json skip test3.json skip2 test4 }
+
+class TestDirectory < Chef::ChefFS::FileSystem::Repository::Directory
+ def make_child_entry(name)
+ TestFile.new(name, self)
+ end
+
+ def can_have_child?(name, is_dir)
+ !is_dir && File.extname(name) == ".json"
+ end
+
+ def dir_ls
+ CHILD_FILES
+ end
+end
+
+class TestFile < Chef::ChefFS::FileSystem::BaseFSObject
+ def fs_entry_valid?
+ name.start_with? "test"
+ end
+
+ def name_valid?
+ true
+ end
+end
+
+describe Chef::ChefFS::FileSystem::Repository::Directory do
+ let(:root) do
+ Chef::ChefFS::FileSystem::BaseFSDir.new("", nil)
+ end
+
+ let(:tmp_dir) { Dir.mktmpdir }
+
+ let(:directory) do
+ described_class.new("test", root, tmp_dir)
+ end
+
+ let(:test_directory) do
+ TestDirectory.new("test", root, tmp_dir)
+ end
+
+ let(:file_double) do
+ double(TestFile, create: true, exists?: false)
+ end
+
+ context "#make_child_entry" do
+ it "raises if not implemented" do
+ expect { directory.send(:make_child_entry, "test") }.to raise_error("Not Implemented")
+ end
+ end
+
+ context "#create_child" do
+ it "creates a new TestFile" do
+ expect(TestFile).to receive(:new).with("test_child", test_directory).and_return(file_double)
+ allow(file_double).to receive(:file_path).and_return("#{test_directory}/test_child")
+ expect(file_double).to receive(:write).with("test")
+ test_directory.create_child("test_child", "test")
+ end
+ end
+
+ context "#child" do
+ it "returns a child if it's valid" do
+ expect(test_directory.child("test")).to be_an_instance_of(TestFile)
+ end
+
+ it "returns a non existent object otherwise" do
+ file_double = instance_double(TestFile, :name_valid? => false)
+ expect(TestFile).to receive(:new).with("test_child", test_directory).and_return(file_double)
+ expect(test_directory.child("test_child")).to be_an_instance_of(Chef::ChefFS::FileSystem::NonexistentFSObject)
+ end
+ end
+
+ context "#children" do
+ before do
+ CHILD_FILES.sort.each do |child|
+ expect(TestFile).to receive(:new).with(child, test_directory).and_call_original
+ end
+ end
+
+ it "creates a child for each name" do
+ test_directory.children
+ end
+
+ it "filters invalid names" do
+ expect(test_directory.children.map { |c| c.name }).to eql %w{ test1.json test2.json test3.json }
+ end
+ end
+
+ context "#empty?" do
+ it "is true if there are no children" do
+ expect(test_directory).to receive(:children).and_return([])
+ expect(test_directory.empty?).to be_truthy
+ end
+
+ it "is false if there are children" do
+ expect(test_directory.empty?).to be_falsey
+ end
+ end
+
+ describe "checks entry validity" do
+ it "rejects dotfiles" do
+ dir = described_class.new(".test", root, tmp_dir)
+ expect(dir.name_valid?).to be_falsey
+ end
+
+ it "rejects files" do
+ Tempfile.open("test") do |file|
+ dir = described_class.new("test", root, file.path)
+ expect(dir.name_valid?).to be_truthy
+ expect(dir.fs_entry_valid?).to be_falsey
+ end
+ end
+
+ it "accepts directories" do
+ expect(directory.name_valid?).to be_truthy
+ end
+ end
+
+ describe "creates directories" do
+ it "doesn't create an existing directory" do
+ expect { directory.create }.to raise_error(Chef::ChefFS::FileSystem::AlreadyExistsError)
+ end
+
+ it "creates a new directory" do
+ FileUtils.rmdir(tmp_dir)
+ expect(Dir).to receive(:mkdir).with(tmp_dir)
+ expect { directory.create }.to_not raise_error
+ end
+
+ after do
+ FileUtils.rmdir(tmp_dir)
+ end
+ end
+
+ describe "deletes directories" do
+ it "won't delete a non-existant directory" do
+ FileUtils.rmdir(tmp_dir)
+ expect { directory.delete(true) }.to raise_error(Chef::ChefFS::FileSystem::NotFoundError)
+ end
+
+ it "must delete recursively" do
+ expect { directory.delete(false) }.to raise_error(Chef::ChefFS::FileSystem::MustDeleteRecursivelyError)
+ end
+
+ it "deletes a directory" do
+ expect(FileUtils).to receive(:rm_r).with(tmp_dir)
+ expect { directory.delete(true) }.to_not raise_error
+ end
+ end
+
+end
diff --git a/spec/unit/chef_fs/file_system_spec.rb b/spec/unit/chef_fs/file_system_spec.rb
index 75ca4d4be9..5c74729557 100644
--- a/spec/unit/chef_fs/file_system_spec.rb
+++ b/spec/unit/chef_fs/file_system_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,132 +16,132 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/chef_fs/file_system'
-require 'chef/chef_fs/file_pattern'
+require "spec_helper"
+require "chef/chef_fs/file_system"
+require "chef/chef_fs/file_pattern"
describe Chef::ChefFS::FileSystem do
include FileSystemSupport
- context 'with empty filesystem' do
- let(:fs) { memory_fs('', {}) }
+ context "with empty filesystem" do
+ let(:fs) { memory_fs("", {}) }
- context 'list' do
- it '/' do
- list_should_yield_paths(fs, '/', '/')
+ context "list" do
+ it "/" do
+ list_should_yield_paths(fs, "/", "/")
end
- it '/a' do
- list_should_yield_paths(fs, '/a', '/a')
+ it "/a" do
+ list_should_yield_paths(fs, "/a", "/a")
end
- it '/a/b' do
- list_should_yield_paths(fs, '/a/b', '/a/b')
+ it "/a/b" do
+ list_should_yield_paths(fs, "/a/b", "/a/b")
end
- it '/*' do
- list_should_yield_paths(fs, '/*', '/')
+ it "/*" do
+ list_should_yield_paths(fs, "/*", "/")
end
end
- context 'resolve_path' do
- it '/' do
- expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/').path).to eq('/')
+ context "resolve_path" do
+ it "/" do
+ expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/").path).to eq("/")
end
- it 'nonexistent /a' do
- expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/a').path).to eq('/a')
+ it "nonexistent /a" do
+ expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/a").path).to eq("/a")
end
- it 'nonexistent /a/b' do
- expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/a/b').path).to eq('/a/b')
+ it "nonexistent /a/b" do
+ expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/a/b").path).to eq("/a/b")
end
end
end
- context 'with a populated filesystem' do
- let(:fs) {
- memory_fs('', {
+ context "with a populated filesystem" do
+ let(:fs) do
+ memory_fs("", {
:a => {
:aa => {
- :c => '',
- :zz => ''
+ :c => "",
+ :zz => "",
},
:ab => {
- :c => '',
- }
+ :c => "",
+ },
},
- :x => '',
- :y => {}
+ :x => "",
+ :y => {},
})
- }
- context 'list' do
- it '/**' do
- list_should_yield_paths(fs, '/**', '/', '/a', '/x', '/y', '/a/aa', '/a/aa/c', '/a/aa/zz', '/a/ab', '/a/ab/c')
+ end
+ context "list" do
+ it "/**" do
+ list_should_yield_paths(fs, "/**", "/", "/a", "/x", "/y", "/a/aa", "/a/aa/c", "/a/aa/zz", "/a/ab", "/a/ab/c")
end
- it '/' do
- list_should_yield_paths(fs, '/', '/')
+ it "/" do
+ list_should_yield_paths(fs, "/", "/")
end
- it '/*' do
- list_should_yield_paths(fs, '/*', '/', '/a', '/x', '/y')
+ it "/*" do
+ list_should_yield_paths(fs, "/*", "/", "/a", "/x", "/y")
end
- it '/*/*' do
- list_should_yield_paths(fs, '/*/*', '/a/aa', '/a/ab')
+ it "/*/*" do
+ list_should_yield_paths(fs, "/*/*", "/a/aa", "/a/ab")
end
- it '/*/*/*' do
- list_should_yield_paths(fs, '/*/*/*', '/a/aa/c', '/a/aa/zz', '/a/ab/c')
+ it "/*/*/*" do
+ list_should_yield_paths(fs, "/*/*/*", "/a/aa/c", "/a/aa/zz", "/a/ab/c")
end
- it '/*/*/?' do
- list_should_yield_paths(fs, '/*/*/?', '/a/aa/c', '/a/ab/c')
+ it "/*/*/?" do
+ list_should_yield_paths(fs, "/*/*/?", "/a/aa/c", "/a/ab/c")
end
- it '/a/*/c' do
- list_should_yield_paths(fs, '/a/*/c', '/a/aa/c', '/a/ab/c')
+ it "/a/*/c" do
+ list_should_yield_paths(fs, "/a/*/c", "/a/aa/c", "/a/ab/c")
end
- it '/**b/c' do
- list_should_yield_paths(fs, '/**b/c', '/a/ab/c')
+ it "/**b/c" do
+ list_should_yield_paths(fs, "/**b/c", "/a/ab/c")
end
- it '/a/ab/c' do
+ it "/a/ab/c" do
no_blocking_calls_allowed
- list_should_yield_paths(fs, '/a/ab/c', '/a/ab/c')
+ list_should_yield_paths(fs, "/a/ab/c", "/a/ab/c")
end
- it 'nonexistent /a/ab/blah' do
+ it "nonexistent /a/ab/blah" do
no_blocking_calls_allowed
- list_should_yield_paths(fs, '/a/ab/blah', '/a/ab/blah')
+ list_should_yield_paths(fs, "/a/ab/blah", "/a/ab/blah")
end
- it 'nonexistent /a/ab/blah/bjork' do
+ it "nonexistent /a/ab/blah/bjork" do
no_blocking_calls_allowed
- list_should_yield_paths(fs, '/a/ab/blah/bjork', '/a/ab/blah/bjork')
+ list_should_yield_paths(fs, "/a/ab/blah/bjork", "/a/ab/blah/bjork")
end
end
- context 'resolve_path' do
+ context "resolve_path" do
before(:each) do
no_blocking_calls_allowed
end
- it 'resolves /' do
- expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/').path).to eq('/')
+ it "resolves /" do
+ expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/").path).to eq("/")
end
- it 'resolves /x' do
- expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/x').path).to eq('/x')
+ it "resolves /x" do
+ expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/x").path).to eq("/x")
end
- it 'resolves /a' do
- expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/a').path).to eq('/a')
+ it "resolves /a" do
+ expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/a").path).to eq("/a")
end
- it 'resolves /a/aa' do
- expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/a/aa').path).to eq('/a/aa')
+ it "resolves /a/aa" do
+ expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/a/aa").path).to eq("/a/aa")
end
- it 'resolves /a/aa/zz' do
- expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/a/aa/zz').path).to eq('/a/aa/zz')
+ it "resolves /a/aa/zz" do
+ expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/a/aa/zz").path).to eq("/a/aa/zz")
end
- it 'resolves nonexistent /q/x/w' do
- expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/q/x/w').path).to eq('/q/x/w')
+ it "resolves nonexistent /q/x/w" do
+ expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/q/x/w").path).to eq("/q/x/w")
end
end
- context 'empty?' do
- it 'is not empty /' do
- expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/').empty?).to be false
+ context "empty?" do
+ it "is not empty /" do
+ expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/").empty?).to be false
end
- it 'is empty /y' do
- expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/y').empty?).to be true
+ it "is empty /y" do
+ expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/y").empty?).to be true
end
it 'is not a directory and can\'t be tested /x' do
- expect { Chef::ChefFS::FileSystem.resolve_path(fs, '/x').empty? }.to raise_error(NoMethodError)
+ expect { Chef::ChefFS::FileSystem.resolve_path(fs, "/x").empty? }.to raise_error(NoMethodError)
end
end
end
diff --git a/spec/unit/chef_fs/parallelizer.rb b/spec/unit/chef_fs/parallelizer.rb
index 9cb97963ed..84637f7283 100644
--- a/spec/unit/chef_fs/parallelizer.rb
+++ b/spec/unit/chef_fs/parallelizer.rb
@@ -1,5 +1,5 @@
-require 'spec_helper'
-require 'chef/chef_fs/parallelizer'
+require "spec_helper"
+require "chef/chef_fs/parallelizer"
describe Chef::ChefFS::Parallelizer do
before :each do
@@ -14,7 +14,7 @@ describe Chef::ChefFS::Parallelizer do
parallelizer.kill
end
- context 'With a Parallelizer with 5 threads' do
+ context "With a Parallelizer with 5 threads" do
let :parallelizer do
Chef::ChefFS::Parallelizer.new(5)
end
@@ -25,7 +25,7 @@ describe Chef::ChefFS::Parallelizer do
it "parallel_do creates unordered output as soon as it is available" do
outputs = []
- parallelizer.parallel_do([0.5,0.3,0.1]) do |val|
+ parallelizer.parallel_do([0.5, 0.3, 0.1]) do |val|
sleep val
outputs << val
end
@@ -35,55 +35,55 @@ describe Chef::ChefFS::Parallelizer do
context "With :ordered => false (unordered output)" do
it "An empty input produces an empty output" do
- parallelize([], :ordered => false) do
+ expect(parallelize([], :ordered => false) do
sleep 10
- end.to_a == []
+ end.to_a).to eql([])
expect(elapsed_time).to be < 0.1
end
it "10 sleep(0.2)s complete within 0.5 seconds" do
expect(parallelize(1.upto(10), :ordered => false) do |i|
sleep 0.2
- 'x'
- end.to_a).to eq(%w(x x x x x x x x x x))
+ "x"
+ end.to_a).to eq(%w{x x x x x x x x x x})
expect(elapsed_time).to be < 0.5
end
it "The output comes as soon as it is available" do
- enum = parallelize([0.5,0.3,0.1], :ordered => false) do |val|
+ enum = parallelize([0.5, 0.3, 0.1], :ordered => false) do |val|
sleep val
val
end
expect(enum.map do |value|
- expect(elapsed_time).to be < value+0.1
+ expect(elapsed_time).to be < value + 0.1
value
end).to eq([ 0.1, 0.3, 0.5 ])
end
it "An exception in input is passed through but does NOT stop processing" do
- input = TestEnumerable.new(0.5,0.3,0.1) do
- raise 'hi'
+ input = TestEnumerable.new(0.5, 0.3, 0.1) do
+ raise "hi"
end
enum = parallelize(input, :ordered => false) { |x| sleep(x); x }
results = []
- expect { enum.each { |value| results << value } }.to raise_error 'hi'
+ expect { enum.each { |value| results << value } }.to raise_error "hi"
expect(results).to eq([ 0.1, 0.3, 0.5 ])
expect(elapsed_time).to be < 0.6
end
it "Exceptions in output are raised after all processing is done" do
processed = 0
- enum = parallelize([1,2,'x',3], :ordered => false) do |x|
- if x == 'x'
+ enum = parallelize([1, 2, "x", 3], :ordered => false) do |x|
+ if x == "x"
sleep 0.1
- raise 'hi'
+ raise "hi"
end
sleep 0.2
processed += 1
x
end
results = []
- expect { enum.each { |value| results << value } }.to raise_error 'hi'
+ expect { enum.each { |value| results << value } }.to raise_error "hi"
expect(results.sort).to eq([ 1, 2, 3 ])
expect(elapsed_time).to be < 0.3
expect(processed).to eq(3)
@@ -91,38 +91,38 @@ describe Chef::ChefFS::Parallelizer do
it "Exceptions with :stop_on_exception are raised after all processing is done" do
processed = 0
- parallelized = parallelize([0.3,0.3,'x',0.3,0.3,0.3,0.3,0.3], :ordered => false, :stop_on_exception => true) do |x|
- if x == 'x'
+ parallelized = parallelize([0.3, 0.3, "x", 0.3, 0.3, 0.3, 0.3, 0.3], :ordered => false, :stop_on_exception => true) do |x|
+ if x == "x"
sleep(0.1)
- raise 'hi'
+ raise "hi"
end
sleep(x)
processed += 1
x
end
- expect { parallelized.to_a }.to raise_error 'hi'
+ expect { parallelized.to_a }.to raise_error "hi"
expect(processed).to eq(4)
end
end
context "With :ordered => true (ordered output)" do
it "An empty input produces an empty output" do
- parallelize([]) do
+ expect(parallelize([]) do
sleep 10
- end.to_a == []
+ end.to_a).to eql([])
expect(elapsed_time).to be < 0.1
end
it "10 sleep(0.2)s complete within 0.5 seconds" do
expect(parallelize(1.upto(10), :ordered => true) do |i|
sleep 0.2
- 'x'
- end.to_a).to eq(%w(x x x x x x x x x x))
+ "x"
+ end.to_a).to eq(%w{x x x x x x x x x x})
expect(elapsed_time).to be < 0.5
end
it "Output comes in the order of the input" do
- enum = parallelize([0.5,0.3,0.1]) do |val|
+ enum = parallelize([0.5, 0.3, 0.1]) do |val|
sleep val
val
end.enum_for(:each_with_index)
@@ -133,29 +133,29 @@ describe Chef::ChefFS::Parallelizer do
end
it "Exceptions in input are raised in the correct sequence but do NOT stop processing" do
- input = TestEnumerable.new(0.5,0.3,0.1) do
- raise 'hi'
+ input = TestEnumerable.new(0.5, 0.3, 0.1) do
+ raise "hi"
end
results = []
enum = parallelize(input) { |x| sleep(x); x }
- expect { enum.each { |value| results << value } }.to raise_error 'hi'
+ expect { enum.each { |value| results << value } }.to raise_error "hi"
expect(elapsed_time).to be < 0.6
expect(results).to eq([ 0.5, 0.3, 0.1 ])
end
it "Exceptions in output are raised in the correct sequence and running processes do NOT stop processing" do
processed = 0
- enum = parallelize([1,2,'x',3]) do |x|
- if x == 'x'
+ enum = parallelize([1, 2, "x", 3]) do |x|
+ if x == "x"
sleep(0.1)
- raise 'hi'
+ raise "hi"
end
sleep(0.2)
processed += 1
x
end
results = []
- expect { enum.each { |value| results << value } }.to raise_error 'hi'
+ expect { enum.each { |value| results << value } }.to raise_error "hi"
expect(results).to eq([ 1, 2 ])
expect(elapsed_time).to be < 0.3
expect(processed).to eq(3)
@@ -163,16 +163,16 @@ describe Chef::ChefFS::Parallelizer do
it "Exceptions with :stop_on_exception are raised after all processing is done" do
processed = 0
- parallelized = parallelize([0.3,0.3,'x',0.3,0.3,0.3,0.3,0.3], :ordered => false, :stop_on_exception => true) do |x|
- if x == 'x'
+ parallelized = parallelize([0.3, 0.3, "x", 0.3, 0.3, 0.3, 0.3, 0.3], :ordered => false, :stop_on_exception => true) do |x|
+ if x == "x"
sleep(0.1)
- raise 'hi'
+ raise "hi"
end
sleep(x)
processed += 1
x
end
- expect { parallelized.to_a }.to raise_error 'hi'
+ expect { parallelized.to_a }.to raise_error "hi"
expect(processed).to eq(4)
end
end
@@ -188,7 +188,7 @@ describe Chef::ChefFS::Parallelizer do
end
enum = parallelize(input) { |x| x }
expect(enum.map do |value|
- expect(elapsed_time).to be < (value+1)*0.1
+ expect(elapsed_time).to be < (value + 1) * 0.1
value
end).to eq([ 1, 2, 3 ])
end
@@ -205,18 +205,13 @@ describe Chef::ChefFS::Parallelizer do
started = false
@occupying_job_finished = occupying_job_finished = [ false ]
@thread = Thread.new do
- begin
- parallelizer.parallelize([0], :main_thread_processing => false) do |x|
- started = true
- sleep(0.3)
- occupying_job_finished[0] = true
- end.wait
- ensure
- end
- end
- while !started
- sleep(0.01)
+ parallelizer.parallelize([0], :main_thread_processing => false) do |x|
+ started = true
+ sleep(0.3)
+ occupying_job_finished[0] = true
+ end.wait
end
+ sleep(0.01) until started
end
after :each do
@@ -236,7 +231,7 @@ describe Chef::ChefFS::Parallelizer do
it "parallelize with :main_thread_processing = false waits for the job to finish" do
expect(parallelizer.parallelize([1], :main_thread_processing => false) do |x|
sleep(0.1)
- x+1
+ x + 1
end.to_a).to eq([ 2 ])
expect(elapsed_time).to be > 0.3
end
@@ -270,7 +265,7 @@ describe Chef::ChefFS::Parallelizer do
context "enumerable methods should run efficiently" do
it ".count does not process anything" do
outputs_processed = 0
- input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+ input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
enum = parallelizer.parallelize(input_mapper) do |x|
outputs_processed += 1
sleep(0.05) # Just enough to yield and get other inputs in the queue
@@ -283,7 +278,7 @@ describe Chef::ChefFS::Parallelizer do
it ".count with arguments works normally" do
outputs_processed = 0
- input_mapper = TestEnumerable.new(1,1,1,1,2,2,2,3,3,4)
+ input_mapper = TestEnumerable.new(1, 1, 1, 1, 2, 2, 2, 3, 3, 4)
enum = parallelizer.parallelize(input_mapper) do |x|
outputs_processed += 1
x
@@ -296,40 +291,40 @@ describe Chef::ChefFS::Parallelizer do
it ".first does not enumerate anything other than the first result(s)" do
outputs_processed = 0
- input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+ input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
enum = parallelizer.parallelize(input_mapper) do |x|
outputs_processed += 1
sleep(0.05) # Just enough to yield and get other inputs in the queue
x
end
expect(enum.first).to eq(1)
- expect(enum.first(2)).to eq([1,2])
+ expect(enum.first(2)).to eq([1, 2])
expect(outputs_processed).to eq(3)
expect(input_mapper.num_processed).to eq(3)
end
it ".take does not enumerate anything other than the first result(s)" do
outputs_processed = 0
- input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+ input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
enum = parallelizer.parallelize(input_mapper) do |x|
outputs_processed += 1
sleep(0.05) # Just enough to yield and get other inputs in the queue
x
end
- expect(enum.take(2)).to eq([1,2])
+ expect(enum.take(2)).to eq([1, 2])
expect(outputs_processed).to eq(2)
expect(input_mapper.num_processed).to eq(2)
end
it ".drop does not process anything other than the last result(s)" do
outputs_processed = 0
- input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+ input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
enum = parallelizer.parallelize(input_mapper) do |x|
outputs_processed += 1
sleep(0.05) # Just enough to yield and get other inputs in the queue
x
end
- expect(enum.drop(2)).to eq([3,4,5,6])
+ expect(enum.drop(2)).to eq([3, 4, 5, 6])
expect(outputs_processed).to eq(4)
expect(input_mapper.num_processed).to eq(6)
end
@@ -337,33 +332,33 @@ describe Chef::ChefFS::Parallelizer do
if Enumerable.method_defined?(:lazy)
it ".lazy.take does not enumerate anything other than the first result(s)" do
outputs_processed = 0
- input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+ input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
enum = parallelizer.parallelize(input_mapper) do |x|
outputs_processed += 1
sleep(0.05) # Just enough to yield and get other inputs in the queue
x
end
- expect(enum.lazy.take(2).to_a).to eq([1,2])
+ expect(enum.lazy.take(2).to_a).to eq([1, 2])
expect(outputs_processed).to eq(2)
expect(input_mapper.num_processed).to eq(2)
end
it ".drop does not process anything other than the last result(s)" do
outputs_processed = 0
- input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+ input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
enum = parallelizer.parallelize(input_mapper) do |x|
outputs_processed += 1
sleep(0.05) # Just enough to yield and get other inputs in the queue
x
end
- expect(enum.lazy.drop(2).to_a).to eq([3,4,5,6])
+ expect(enum.lazy.drop(2).to_a).to eq([3, 4, 5, 6])
expect(outputs_processed).to eq(4)
expect(input_mapper.num_processed).to eq(6)
end
it "lazy enumerable is actually lazy" do
outputs_processed = 0
- input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+ input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
enum = parallelizer.parallelize(input_mapper) do |x|
outputs_processed += 1
sleep(0.05) # Just enough to yield and get other inputs in the queue
@@ -381,32 +376,32 @@ describe Chef::ChefFS::Parallelizer do
context "running enumerable multiple times should function correctly" do
it ".map twice on the same parallel enumerable returns the correct results and re-processes the input" do
outputs_processed = 0
- input_mapper = TestEnumerable.new(1,2,3)
+ input_mapper = TestEnumerable.new(1, 2, 3)
enum = parallelizer.parallelize(input_mapper) do |x|
outputs_processed += 1
x
end
- expect(enum.map { |x| x }).to eq([1,2,3])
- expect(enum.map { |x| x }).to eq([1,2,3])
+ expect(enum.map { |x| x }).to eq([1, 2, 3])
+ expect(enum.map { |x| x }).to eq([1, 2, 3])
expect(outputs_processed).to eq(6)
expect(input_mapper.num_processed).to eq(6)
end
it ".first and then .map on the same parallel enumerable returns the correct results and re-processes the input" do
outputs_processed = 0
- input_mapper = TestEnumerable.new(1,2,3)
+ input_mapper = TestEnumerable.new(1, 2, 3)
enum = parallelizer.parallelize(input_mapper) do |x|
outputs_processed += 1
x
end
expect(enum.first).to eq(1)
- expect(enum.map { |x| x }).to eq([1,2,3])
+ expect(enum.map { |x| x }).to eq([1, 2, 3])
expect(outputs_processed).to be >= 4
expect(input_mapper.num_processed).to be >= 4
end
it "two simultaneous enumerations throws an exception" do
- enum = parallelizer.parallelize([1,2,3]) { |x| x }
+ enum = parallelizer.parallelize([1, 2, 3]) { |x| x }
a = enum.enum_for(:each)
a.next
expect do
@@ -424,7 +419,7 @@ describe Chef::ChefFS::Parallelizer do
context "And main_thread_processing on" do
it "succeeds in running" do
- expect(parallelizer.parallelize([0.5]) { |x| x*2 }.to_a).to eq([1])
+ expect(parallelizer.parallelize([0.5]) { |x| x * 2 }.to_a).to eq([1])
end
end
end
@@ -435,16 +430,16 @@ describe Chef::ChefFS::Parallelizer do
end
it "does not have contention issues with large numbers of inputs" do
- expect(parallelizer.parallelize(1.upto(500)) { |x| x+1 }.to_a).to eq(2.upto(501).to_a)
+ expect(parallelizer.parallelize(1.upto(500)) { |x| x + 1 }.to_a).to eq(2.upto(501).to_a)
end
it "does not have contention issues with large numbers of inputs with ordering off" do
- expect(parallelizer.parallelize(1.upto(500), :ordered => false) { |x| x+1 }.to_a.sort).to eq(2.upto(501).to_a)
+ expect(parallelizer.parallelize(1.upto(500), :ordered => false) { |x| x + 1 }.to_a.sort).to eq(2.upto(501).to_a)
end
it "does not have contention issues with large numbers of jobs and inputs with ordering off" do
parallelizers = 0.upto(99).map do
- parallelizer.parallelize(1.upto(500)) { |x| x+1 }
+ parallelizer.parallelize(1.upto(500)) { |x| x + 1 }
end
outputs = []
threads = 0.upto(99).map do |i|
@@ -466,15 +461,15 @@ describe Chef::ChefFS::Parallelizer do
attr_reader :num_processed
- def each(&each_block)
+ def each
@values.each do |value|
@num_processed += 1
- each_block.call(value)
+ yield(value)
end
if @block
@block.call do |value|
@num_processed += 1
- each_block.call(value)
+ yield(value)
end
end
end
diff --git a/spec/unit/chef_fs/path_util_spec.rb b/spec/unit/chef_fs/path_util_spec.rb
index 42eb126dfb..93205a1815 100644
--- a/spec/unit/chef_fs/path_util_spec.rb
+++ b/spec/unit/chef_fs/path_util_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Kartik Null Cating-Subramanian (<ksubramanian@chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,93 +16,93 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/chef_fs/path_utils'
+require "spec_helper"
+require "chef/chef_fs/path_utils"
describe Chef::ChefFS::PathUtils do
- context 'invoking join' do
- it 'joins well-behaved distinct path elements' do
- expect(Chef::ChefFS::PathUtils.join('a', 'b', 'c')).to eq('a/b/c')
+ context "invoking join" do
+ it "joins well-behaved distinct path elements" do
+ expect(Chef::ChefFS::PathUtils.join("a", "b", "c")).to eq("a/b/c")
end
- it 'strips extraneous slashes in the middle of paths' do
- expect(Chef::ChefFS::PathUtils.join('a/', '/b', '/c/')).to eq('a/b/c')
- expect(Chef::ChefFS::PathUtils.join('a/', '/b', '///c/')).to eq('a/b/c')
+ it "strips extraneous slashes in the middle of paths" do
+ expect(Chef::ChefFS::PathUtils.join("a/", "/b", "/c/")).to eq("a/b/c")
+ expect(Chef::ChefFS::PathUtils.join("a/", "/b", "///c/")).to eq("a/b/c")
end
- it 'preserves the whether the first element was absolute or not' do
- expect(Chef::ChefFS::PathUtils.join('/a/', '/b', 'c/')).to eq('/a/b/c')
- expect(Chef::ChefFS::PathUtils.join('///a/', '/b', 'c/')).to eq('/a/b/c')
+ it "preserves the whether the first element was absolute or not" do
+ expect(Chef::ChefFS::PathUtils.join("/a/", "/b", "c/")).to eq("/a/b/c")
+ expect(Chef::ChefFS::PathUtils.join("///a/", "/b", "c/")).to eq("/a/b/c")
end
end
- context 'invoking is_absolute?' do
- it 'confirms that paths starting with / are absolute' do
- expect(Chef::ChefFS::PathUtils.is_absolute?('/foo/bar/baz')).to be true
- expect(Chef::ChefFS::PathUtils.is_absolute?('/foo')).to be true
+ context "invoking is_absolute?" do
+ it "confirms that paths starting with / are absolute" do
+ expect(Chef::ChefFS::PathUtils.is_absolute?("/foo/bar/baz")).to be true
+ expect(Chef::ChefFS::PathUtils.is_absolute?("/foo")).to be true
end
- it 'confirms that paths starting with // are absolute even though that looks like some windows network path' do
- expect(Chef::ChefFS::PathUtils.is_absolute?('//foo/bar/baz')).to be true
+ it "confirms that paths starting with // are absolute even though that looks like some windows network path" do
+ expect(Chef::ChefFS::PathUtils.is_absolute?("//foo/bar/baz")).to be true
end
- it 'confirms that root is indeed absolute' do
- expect(Chef::ChefFS::PathUtils.is_absolute?('/')).to be true
+ it "confirms that root is indeed absolute" do
+ expect(Chef::ChefFS::PathUtils.is_absolute?("/")).to be true
end
- it 'confirms that paths starting without / are relative' do
- expect(Chef::ChefFS::PathUtils.is_absolute?('foo/bar/baz')).to be false
- expect(Chef::ChefFS::PathUtils.is_absolute?('a')).to be false
+ it "confirms that paths starting without / are relative" do
+ expect(Chef::ChefFS::PathUtils.is_absolute?("foo/bar/baz")).to be false
+ expect(Chef::ChefFS::PathUtils.is_absolute?("a")).to be false
end
- it 'returns false for an empty path.' do
- expect(Chef::ChefFS::PathUtils.is_absolute?('')).to be false
+ it "returns false for an empty path." do
+ expect(Chef::ChefFS::PathUtils.is_absolute?("")).to be false
end
end
- context 'invoking realest_path' do
+ context "invoking realest_path" do
let(:good_path) { File.dirname(__FILE__) }
let(:parent_path) { File.dirname(good_path) }
- it 'handles paths with no wildcards or globs' do
+ it "handles paths with no wildcards or globs" do
expect(Chef::ChefFS::PathUtils.realest_path(good_path)).to eq(File.expand_path(good_path))
end
- it 'handles paths with .. and .' do
- expect(Chef::ChefFS::PathUtils.realest_path(good_path+'/../.')).to eq(File.expand_path(parent_path))
+ it "handles paths with .. and ." do
+ expect(Chef::ChefFS::PathUtils.realest_path(good_path + "/../.")).to eq(File.expand_path(parent_path))
end
- it 'handles paths with *' do
- expect(Chef::ChefFS::PathUtils.realest_path(good_path + '/*/foo')).to eq(File.expand_path(good_path + '/*/foo'))
+ it "handles paths with *" do
+ expect(Chef::ChefFS::PathUtils.realest_path(good_path + "/*/foo")).to eq(File.expand_path(good_path + "/*/foo"))
end
- it 'handles directories that do not exist' do
- expect(Chef::ChefFS::PathUtils.realest_path(good_path + '/something/or/other')).to eq(File.expand_path(good_path + '/something/or/other'))
+ it "handles directories that do not exist" do
+ expect(Chef::ChefFS::PathUtils.realest_path(good_path + "/something/or/other")).to eq(File.expand_path(good_path + "/something/or/other"))
end
- it 'handles root correctly' do
+ it "handles root correctly" do
if Chef::Platform.windows?
- expect(Chef::ChefFS::PathUtils.realest_path('C:/')).to eq('C:/')
+ expect(Chef::ChefFS::PathUtils.realest_path("C:/")).to eq("C:/")
else
- expect(Chef::ChefFS::PathUtils.realest_path('/')).to eq('/')
+ expect(Chef::ChefFS::PathUtils.realest_path("/")).to eq("/")
end
end
end
- context 'invoking descendant_path' do
- it 'handles paths with various casing on windows' do
+ context "invoking descendant_path" do
+ it "handles paths with various casing on windows" do
allow(Chef::ChefFS).to receive(:windows?) { true }
- expect(Chef::ChefFS::PathUtils.descendant_path('C:/ab/b/c', 'C:/AB/B')).to eq('c')
- expect(Chef::ChefFS::PathUtils.descendant_path('C:/ab/b/c', 'c:/ab/B')).to eq('c')
+ expect(Chef::ChefFS::PathUtils.descendant_path("C:/ab/b/c", "C:/AB/B")).to eq("c")
+ expect(Chef::ChefFS::PathUtils.descendant_path("C:/ab/b/c", "c:/ab/B")).to eq("c")
end
- it 'returns nil if the path does not have the given ancestor' do
- expect(Chef::ChefFS::PathUtils.descendant_path('/D/E/F', '/A/B/C')).to be_nil
- expect(Chef::ChefFS::PathUtils.descendant_path('/A/B/D', '/A/B/C')).to be_nil
+ it "returns nil if the path does not have the given ancestor" do
+ expect(Chef::ChefFS::PathUtils.descendant_path("/D/E/F", "/A/B/C")).to be_nil
+ expect(Chef::ChefFS::PathUtils.descendant_path("/A/B/D", "/A/B/C")).to be_nil
end
- it 'returns blank if the ancestor equals the path' do
- expect(Chef::ChefFS::PathUtils.descendant_path('/A/B/D', '/A/B/D')).to eq('')
+ it "returns blank if the ancestor equals the path" do
+ expect(Chef::ChefFS::PathUtils.descendant_path("/A/B/D", "/A/B/D")).to eq("")
end
end
end
diff --git a/spec/unit/chef_spec.rb b/spec/unit/chef_spec.rb
index 8a8d6c6c68..bbab793841 100644
--- a/spec/unit/chef_spec.rb
+++ b/spec/unit/chef_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef do
it "should have a version defined" do
diff --git a/spec/unit/client_spec.rb b/spec/unit/client_spec.rb
index 8fbf56844e..ec3f70b9b0 100644
--- a/spec/unit/client_spec.rb
+++ b/spec/unit/client_spec.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright 2008-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,13 +18,13 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'spec/support/shared/context/client'
-require 'spec/support/shared/examples/client'
+require "spec_helper"
+require "spec/support/shared/context/client"
+require "spec/support/shared/examples/client"
-require 'chef/run_context'
-require 'chef/rest'
-require 'rbconfig'
+require "chef/run_context"
+require "chef/server_api"
+require "rbconfig"
class FooError < RuntimeError
end
@@ -38,32 +38,33 @@ describe Chef::Client do
end
it "runs ohai with only the minimum required plugins" do
- expected_filter = %w[fqdn machinename hostname platform platform_version os os_version]
+ expected_filter = %w{fqdn machinename hostname platform platform_version os os_version}
expect(ohai_system).to receive(:all_plugins).with(expected_filter)
client.run_ohai
end
end
describe "authentication protocol selection" do
- after do
- Chef::Config[:authentication_protocol_version] = "1.0"
- end
+ context "when FIPS is disabled" do
+ before do
+ Chef::Config[:fips] = false
+ end
- context "when the node name is <= 90 bytes" do
- it "does not force the authentication protocol to 1.1" do
- Chef::Config[:node_name] = ("f" * 90)
- # ugly that this happens as a side effect of a getter :(
- client.node_name
- expect(Chef::Config[:authentication_protocol_version]).to eq("1.0")
+ it "defaults to 1.1" do
+ expect(Chef::Config[:authentication_protocol_version]).to eq("1.1")
end
end
+ context "when FIPS is enabled" do
+ before do
+ Chef::Config[:fips] = true
+ end
- context "when the node name is > 90 bytes" do
- it "sets the authentication protocol to version 1.1" do
- Chef::Config[:node_name] = ("f" * 91)
- # ugly that this happens as a side effect of a getter :(
- client.node_name
- expect(Chef::Config[:authentication_protocol_version]).to eq("1.1")
+ it "defaults to 1.3" do
+ expect(Chef::Config[:authentication_protocol_version]).to eq("1.3")
+ end
+
+ after do
+ Chef::Config[:fips] = false
end
end
end
@@ -175,21 +176,21 @@ describe Chef::Client do
context "when an override run list is given" do
it "permits spaces in overriding run list" do
- Chef::Client.new(nil, :override_runlist => 'role[a], role[b]')
+ Chef::Client.new(nil, :override_runlist => "role[a], role[b]")
end
describe "calling run" do
include_examples "a successful client run" do
- let(:client_opts) { {:override_runlist => "recipe[override_recipe]"} }
+ let(:client_opts) { { :override_runlist => "recipe[override_recipe]" } }
def stub_for_sync_cookbooks
# --Client#setup_run_context
# ---Client#sync_cookbooks -- downloads the list of cookbooks to sync
#
expect_any_instance_of(Chef::CookbookSynchronizer).to receive(:sync_cookbooks)
- expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
+ expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
expect(http_cookbook_sync).to receive(:post).
- with("environments/_default/cookbook_versions", {:run_list => ["override_recipe"]}).
+ with("environments/_default/cookbook_versions", { :run_list => ["override_recipe"] }).
and_return({})
end
@@ -214,16 +215,16 @@ describe Chef::Client do
include_examples "a successful client run" do
let(:new_runlist) { "recipe[new_run_list_recipe]" }
- let(:client_opts) { {:runlist => new_runlist} }
+ let(:client_opts) { { :runlist => new_runlist } }
def stub_for_sync_cookbooks
# --Client#setup_run_context
# ---Client#sync_cookbooks -- downloads the list of cookbooks to sync
#
expect_any_instance_of(Chef::CookbookSynchronizer).to receive(:sync_cookbooks)
- expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
+ expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
expect(http_cookbook_sync).to receive(:post).
- with("environments/_default/cookbook_versions", {:run_list => ["new_run_list_recipe"]}).
+ with("environments/_default/cookbook_versions", { :run_list => ["new_run_list_recipe"] }).
and_return({})
end
@@ -238,7 +239,7 @@ describe Chef::Client do
describe "when converge completes successfully" do
include_context "a client run"
include_context "converge completed"
- context 'when audit mode is enabled' do
+ context "when audit mode is enabled" do
describe "when audit phase errors" do
include_context "audit phase failed with error"
include_examples "a completed run with audit failure" do
@@ -354,9 +355,9 @@ describe Chef::Client do
# build_node will call Node#expand! with server, which will
# eventually hit the server to expand the included role.
- mock_chef_rest = double("Chef::REST")
- expect(mock_chef_rest).to receive(:get_rest).with("roles/role_containing_cookbook1").and_return(role_containing_cookbook1)
- expect(Chef::REST).to receive(:new).and_return(mock_chef_rest)
+ mock_chef_rest = double("Chef::ServerAPI")
+ expect(mock_chef_rest).to receive(:get).with("roles/role_containing_cookbook1").and_return(role_containing_cookbook1.to_hash)
+ expect(Chef::ServerAPI).to receive(:new).and_return(mock_chef_rest)
# check pre-conditions.
expect(node[:roles]).to be_nil
@@ -387,12 +388,11 @@ describe Chef::Client do
expect(node.chef_environment).to eq("_default")
Chef::Config[:environment] = "A"
- test_env = Chef::Environment.new
- test_env.name("A")
+ test_env = { "name" => "A" }
- mock_chef_rest = double("Chef::REST")
- expect(mock_chef_rest).to receive(:get_rest).with("environments/A").and_return(test_env)
- expect(Chef::REST).to receive(:new).and_return(mock_chef_rest)
+ mock_chef_rest = double("Chef::ServerAPI")
+ expect(mock_chef_rest).to receive(:get).with("environments/A").and_return(test_env)
+ expect(Chef::ServerAPI).to receive(:new).and_return(mock_chef_rest)
allow(client.policy_builder).to receive(:node).and_return(node)
client.policy_builder.select_implementation(node)
allow(client.policy_builder.implementation).to receive(:node).and_return(node)
@@ -462,7 +462,7 @@ describe Chef::Client do
describe "assert_cookbook_path_not_empty" do
before do
- Chef::Config[:solo] = true
+ Chef::Config[:solo_legacy_mode] = true
Chef::Config[:cookbook_path] = ["/path/to/invalid/cookbook_path"]
end
@@ -518,7 +518,7 @@ describe Chef::Client do
allow_any_instance_of(Chef::RunLock).to receive(:save_pid).and_raise(NoMethodError)
end
- context 'when audit mode is enabled' do
+ context "when audit mode is enabled" do
before do
Chef::Config[:audit_mode] = :enabled
end
@@ -531,7 +531,7 @@ describe Chef::Client do
end
end
- context 'when audit mode is disabled' do
+ context "when audit mode is disabled" do
before do
Chef::Config[:audit_mode] = :disabled
end
diff --git a/spec/unit/config_fetcher_spec.rb b/spec/unit/config_fetcher_spec.rb
index 1b4a4903a8..6847ee5fd3 100644
--- a/spec/unit/config_fetcher_spec.rb
+++ b/spec/unit/config_fetcher_spec.rb
@@ -1,13 +1,13 @@
-require 'spec_helper'
-require 'chef/config_fetcher'
+require "spec_helper"
+require "chef/config_fetcher"
describe Chef::ConfigFetcher do
- let(:valid_json) { Chef::JSONCompat.to_json({:a=>"b"}) }
+ let(:valid_json) { Chef::JSONCompat.to_json({ :a => "b" }) }
let(:invalid_json) { %q[{"syntax-error": "missing quote}] }
let(:http) { double("Chef::HTTP::Simple") }
let(:config_location_regex) { Regexp.escape(config_location) }
- let(:invalid_json_error_regex) { %r[Could not parse the provided JSON file \(#{config_location_regex}\)] }
+ let(:invalid_json_error_regex) { %r{Could not parse the provided JSON file \(#{config_location_regex}\)} }
let(:fetcher) { Chef::ConfigFetcher.new(config_location) }
@@ -22,30 +22,43 @@ describe Chef::ConfigFetcher do
expect(fetcher.read_config).to eq(config_content)
end
+ it "gives the expanded path to the config file" do
+ expect(fetcher.expanded_path).to eq(File.expand_path(config_location))
+ end
+
+ context "with a relative path" do
+
+ let(:config_location) { "client.rb" }
+
+ it "gives the expanded path to the config file" do
+ expected = File.join(Dir.pwd, config_location)
+ expect(fetcher.expanded_path).to eq(expected)
+ end
+
+ end
+
context "and consuming JSON" do
let(:config_location) { "/etc/chef/first-boot.json" }
-
it "returns the parsed JSON" do
expect(::File).to receive(:read).
with(config_location).
and_return(valid_json)
- expect(fetcher.fetch_json).to eq({"a" => "b"})
+ expect(fetcher.fetch_json).to eq({ "a" => "b" })
end
context "and the JSON is invalid" do
it "reports the JSON error" do
-
expect(::File).to receive(:read).
with(config_location).
and_return(invalid_json)
expect(Chef::Application).to receive(:fatal!).
- with(invalid_json_error_regex, 2)
+ with(invalid_json_error_regex, Chef::Exceptions::DeprecatedExitCode.new)
fetcher.fetch_json
end
end
@@ -53,45 +66,60 @@ describe Chef::ConfigFetcher do
end
- context "when loading a file over HTTP" do
+ context "with an HTTP URL config location" do
let(:config_location) { "https://example.com/client.rb" }
let(:config_content) { "# The client.rb content" }
- before do
- expect(Chef::HTTP::Simple).to receive(:new).
- with(config_location).
- and_return(http)
+ it "returns the config location unchanged for #expanded_path" do
+ expect(fetcher.expanded_path).to eq(config_location)
end
- it "reads the file over HTTP" do
- expect(http).to receive(:get).
- with("").and_return(config_content)
- expect(fetcher.read_config).to eq(config_content)
- end
+ describe "reading the file" do
- context "and consuming JSON" do
- let(:config_location) { "https://example.com/foo.json" }
+ before do
+ expect(Chef::HTTP::Simple).to receive(:new).
+ with(config_location).
+ and_return(http)
+ end
- it "fetches the file and parses it" do
+ it "reads the file over HTTP" do
expect(http).to receive(:get).
- with("").and_return(valid_json)
- expect(fetcher.fetch_json).to eq({"a" => "b"})
+ with("").and_return(config_content)
+ expect(fetcher.read_config).to eq(config_content)
end
- context "and the JSON is invalid" do
- it "reports the JSON error" do
+ context "and consuming JSON" do
+ let(:config_location) { "https://example.com/foo.json" }
+
+ it "fetches the file and parses it" do
expect(http).to receive(:get).
- with("").and_return(invalid_json)
+ with("").and_return(valid_json)
+ expect(fetcher.fetch_json).to eq({ "a" => "b" })
+ end
- expect(Chef::Application).to receive(:fatal!).
- with(invalid_json_error_regex, 2)
- fetcher.fetch_json
+ context "and the JSON is invalid" do
+ it "reports the JSON error" do
+ expect(http).to receive(:get).
+ with("").and_return(invalid_json)
+
+ expect(Chef::Application).to receive(:fatal!).
+ with(invalid_json_error_regex, Chef::Exceptions::DeprecatedExitCode.new)
+ fetcher.fetch_json
+ end
end
end
end
end
+ context "with a nil config file argument" do
+
+ let(:config_location) { nil }
+
+ it "returns the config location unchanged for #expanded_path" do
+ expect(fetcher.expanded_path).to eq(nil)
+ end
+ end
end
diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb
index 8d155c61ab..68cb589251 100644
--- a/spec/unit/config_spec.rb
+++ b/spec/unit/config_spec.rb
@@ -1,7 +1,7 @@
-require 'spec_helper'
+require "spec_helper"
-require 'chef/config'
+require "chef/config"
RSpec.describe Chef::Config do
diff --git a/spec/unit/cookbook/chefignore_spec.rb b/spec/unit/cookbook/chefignore_spec.rb
index 9f5546de28..95b9295f50 100644
--- a/spec/unit/cookbook/chefignore_spec.rb
+++ b/spec/unit/cookbook/chefignore_spec.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,35 +15,35 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Cookbook::Chefignore do
before do
- @chefignore = Chef::Cookbook::Chefignore.new(File.join(CHEF_SPEC_DATA, 'cookbooks'))
+ @chefignore = Chef::Cookbook::Chefignore.new(File.join(CHEF_SPEC_DATA, "cookbooks"))
end
it "loads the globs in the chefignore file" do
- expect(@chefignore.ignores).to match_array(%w[recipes/ignoreme.rb ignored])
+ expect(@chefignore.ignores).to match_array(%w{recipes/ignoreme.rb ignored})
end
it "removes items from an array that match the ignores" do
- file_list = %w[ recipes/ignoreme.rb recipes/dontignoreme.rb ]
- expect(@chefignore.remove_ignores_from(file_list)).to eq(%w[recipes/dontignoreme.rb])
+ file_list = %w{ recipes/ignoreme.rb recipes/dontignoreme.rb }
+ expect(@chefignore.remove_ignores_from(file_list)).to eq(%w{recipes/dontignoreme.rb})
end
it "determines if a file is ignored" do
- expect(@chefignore.ignored?('ignored')).to be_truthy
- expect(@chefignore.ignored?('recipes/ignoreme.rb')).to be_truthy
- expect(@chefignore.ignored?('recipes/dontignoreme.rb')).to be_falsey
+ expect(@chefignore.ignored?("ignored")).to be_truthy
+ expect(@chefignore.ignored?("recipes/ignoreme.rb")).to be_truthy
+ expect(@chefignore.ignored?("recipes/dontignoreme.rb")).to be_falsey
end
context "when using the single cookbook pattern" do
before do
- @chefignore = Chef::Cookbook::Chefignore.new(File.join(CHEF_SPEC_DATA, 'standalone_cookbook'))
+ @chefignore = Chef::Cookbook::Chefignore.new(File.join(CHEF_SPEC_DATA, "standalone_cookbook"))
end
it "loads the globs in the chefignore file" do
- expect(@chefignore.ignores).to match_array(%w[recipes/ignoreme.rb ignored vendor/bundle/*])
+ expect(@chefignore.ignores).to match_array(%w{recipes/ignoreme.rb ignored vendor/bundle/*})
end
end
end
diff --git a/spec/unit/cookbook/cookbook_version_loader_spec.rb b/spec/unit/cookbook/cookbook_version_loader_spec.rb
index 23ffc21f7f..786e17f35b 100644
--- a/spec/unit/cookbook/cookbook_version_loader_spec.rb
+++ b/spec/unit/cookbook/cookbook_version_loader_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Cookbook::CookbookVersionLoader do
before do
@@ -58,8 +58,8 @@ describe Chef::Cookbook::CookbookVersionLoader do
end
it "loads libraries" do
- expect(loaded_cookbook.library_filenames).to include(full_path('/libraries/openldap.rb'))
- expect(loaded_cookbook.library_filenames).to include(full_path('/libraries/openldap/version.rb'))
+ expect(loaded_cookbook.library_filenames).to include(full_path("/libraries/openldap.rb"))
+ expect(loaded_cookbook.library_filenames).to include(full_path("/libraries/openldap/version.rb"))
end
it "loads static files in the files/ dir" do
@@ -73,6 +73,18 @@ describe Chef::Cookbook::CookbookVersionLoader do
expect(loaded_cookbook.file_filenames).to include(full_path("/files/default/remotedir/.a_dotdir/.a_dotfile_in_a_dotdir"))
end
+ it "loads root files that start with a ." do
+ expect(loaded_cookbook.all_files).to include(full_path(".root_dotfile"))
+ expect(loaded_cookbook.root_filenames).to include(full_path(".root_dotfile"))
+ end
+
+ it "loads all unignored files, even if they don't match a segment type" do
+ expect(loaded_cookbook.all_files).to include(full_path("/spec/spec_helper.rb"))
+
+ # Directories need to be filtered out, though:
+ expect(loaded_cookbook.all_files).to_not include(full_path("/spec"))
+ end
+
it "should load the metadata for the cookbook" do
expect(loaded_cookbook.metadata.name.to_s).to eq("openldap")
expect(loaded_cookbook.metadata).to be_a_kind_of(Chef::Cookbook::Metadata)
@@ -92,6 +104,15 @@ describe Chef::Cookbook::CookbookVersionLoader do
end
+ context "when a cookbook's metadata.rb does not parse but the compiled metadata.json is present" do
+ let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "prefer_metadata_json") }
+
+ it "reads the cookbook" do
+ expect(loaded_cookbook.metadata.name.to_s).to eq("prefer_metadata_json")
+ expect(loaded_cookbook.metadata.version.to_s).to eq("1.2.3")
+ end
+ end
+
context "when the given path is not actually a cookbook" do
let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "cookbooks/NOTHING_HERE_FOLKS") }
@@ -184,4 +205,3 @@ describe Chef::Cookbook::CookbookVersionLoader do
end
end
-
diff --git a/spec/unit/cookbook/file_vendor_spec.rb b/spec/unit/cookbook/file_vendor_spec.rb
index 145541a63f..164fbd8177 100644
--- a/spec/unit/cookbook/file_vendor_spec.rb
+++ b/spec/unit/cookbook/file_vendor_spec.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Cookbook::FileVendor do
@@ -23,7 +23,7 @@ describe Chef::Cookbook::FileVendor do
context "when configured to fetch files over http" do
- let(:http) { double("Chef::REST") }
+ let(:http) { double("Chef::ServerAPI") }
before do
file_vendor_class.fetch_from_remote(http)
@@ -40,7 +40,7 @@ describe Chef::Cookbook::FileVendor do
context "with a manifest from a cookbook version" do
# A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
- let(:manifest) { {:cookbook_name => "bob", :name => "bob-1.2.3"} }
+ let(:manifest) { { :cookbook_name => "bob", :name => "bob-1.2.3" } }
it "creates a RemoteFileVendor for a given manifest" do
file_vendor = file_vendor_class.create_from_manifest(manifest)
@@ -54,7 +54,7 @@ describe Chef::Cookbook::FileVendor do
context "with a manifest from a cookbook artifact" do
# A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
- let(:manifest) { {:name => "bob"} }
+ let(:manifest) { { :name => "bob" } }
it "creates a RemoteFileVendor for a given manifest" do
file_vendor = file_vendor_class.create_from_manifest(manifest)
@@ -68,10 +68,10 @@ describe Chef::Cookbook::FileVendor do
context "when configured to load files from disk" do
- let(:cookbook_path) { %w[/var/chef/cookbooks /var/chef/other_cookbooks] }
+ let(:cookbook_path) { %w{/var/chef/cookbooks /var/chef/other_cookbooks} }
# A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
- let(:manifest) { {:cookbook_name => "bob"} }
+ let(:manifest) { { :cookbook_name => "bob" } }
before do
file_vendor_class.fetch_from_disk(cookbook_path)
@@ -94,5 +94,19 @@ describe Chef::Cookbook::FileVendor do
end
-end
+ context "when vendoring a cookbook with a name mismatch" do
+ let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "cookbooks") }
+
+ # A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
+ let(:manifest) { { :cookbook_name => "name-mismatch" } }
+ before do
+ file_vendor_class.fetch_from_disk(cookbook_path)
+ end
+
+ it "retrieves the file from the correct location based on path to the cookbook that conatins the correct name metadata" do
+ file_vendor = file_vendor_class.create_from_manifest(manifest)
+ file_vendor.get_filename("metadata.rb")
+ end
+ end
+end
diff --git a/spec/unit/cookbook/metadata_spec.rb b/spec/unit/cookbook/metadata_spec.rb
index 1b30286f51..d1117127f1 100644
--- a/spec/unit/cookbook/metadata_spec.rb
+++ b/spec/unit/cookbook/metadata_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2008-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/cookbook/metadata'
+require "spec_helper"
+require "chef/cookbook/metadata"
describe Chef::Cookbook::Metadata do
@@ -30,7 +30,8 @@ describe Chef::Cookbook::Metadata do
:maintainer_email, :license, :platforms, :dependencies,
:recommendations, :suggestions, :conflicting, :providing,
:replacing, :attributes, :groupings, :recipes, :version,
- :source_url, :issues_url, :privacy ]
+ :source_url, :issues_url, :privacy, :ohai_versions, :chef_versions,
+ :gems ]
end
it "does not depend on object identity for equality" do
@@ -142,11 +143,11 @@ describe Chef::Cookbook::Metadata do
end
it "has an empty source_url string" do
- expect(metadata.source_url).to eq('')
+ expect(metadata.source_url).to eq("")
end
it "has an empty issues_url string" do
- expect(metadata.issues_url).to eq('')
+ expect(metadata.issues_url).to eq("")
end
it "is not private" do
@@ -189,7 +190,7 @@ describe Chef::Cookbook::Metadata do
describe "adding a supported platform" do
it "should support adding a supported platform with a single expression" do
metadata.supports("ubuntu", ">= 8.04")
- expect(metadata.platforms["ubuntu"]).to eq('>= 8.04')
+ expect(metadata.platforms["ubuntu"]).to eq(">= 8.04")
end
end
@@ -203,9 +204,9 @@ describe Chef::Cookbook::Metadata do
:version => "0.6.0",
:source_url => "http://example.com",
:issues_url => "http://example.com/issues",
- :privacy => true
+ :privacy => true,
}
- params.sort { |a,b| a.to_s <=> b.to_s }.each do |field, field_value|
+ params.sort_by(&:to_s).each do |field, field_value|
describe field do
it "should be set-able via #{field}" do
expect(metadata.send(field, field_value)).to eql(field_value)
@@ -239,7 +240,7 @@ describe Chef::Cookbook::Metadata do
:provides => [ :providing, "foo::bar", "<= 0.2" ],
:replaces => [ :replacing, "foo::bar", "= 0.2.1" ],
}
- dep_types.sort { |a,b| a.to_s <=> b.to_s }.each do |dep, dep_args|
+ dep_types.sort_by(&:to_s).each do |dep, dep_args|
check_with = dep_args.shift
describe dep do
it "should be set-able via #{dep}" do
@@ -260,7 +261,7 @@ describe Chef::Cookbook::Metadata do
:provides => [ :providing, "foo::bar", "<=0.2", "<= 0.2" ],
:replaces => [ :replacing, "foo::bar", "=0.2.1", "= 0.2.1" ],
}
- dep_types.sort { |a,b| a.to_s <=> b.to_s }.each do |dep, dep_args|
+ dep_types.sort_by(&:to_s).each do |dep, dep_args|
check_with = dep_args.shift
normalized_version = dep_args.pop
describe dep do
@@ -274,7 +275,6 @@ describe Chef::Cookbook::Metadata do
end
end
-
describe "in the obsoleted format" do
dep_types = {
:depends => [ "foo::bar", "> 0.2", "< 1.0" ],
@@ -287,12 +287,11 @@ describe Chef::Cookbook::Metadata do
dep_types.each do |dep, dep_args|
it "for #{dep} raises an informative error instead of vomiting on your shoes" do
- expect {metadata.send(dep, *dep_args)}.to raise_error(Chef::Exceptions::ObsoleteDependencySyntax)
+ expect { metadata.send(dep, *dep_args) }.to raise_error(Chef::Exceptions::ObsoleteDependencySyntax)
end
end
end
-
describe "with obsolete operators" do
dep_types = {
:depends => [ "foo::bar", ">> 0.2"],
@@ -305,51 +304,178 @@ describe Chef::Cookbook::Metadata do
dep_types.each do |dep, dep_args|
it "for #{dep} raises an informative error instead of vomiting on your shoes" do
- expect {metadata.send(dep, *dep_args)}.to raise_error(Chef::Exceptions::InvalidVersionConstraint)
+ expect { metadata.send(dep, *dep_args) }.to raise_error(Chef::Exceptions::InvalidVersionConstraint)
end
end
end
- it "strips out self-dependencies", :chef_lt_13_only do
- metadata.name('foo')
+ it "strips out self-dependencies", chef: "< 13" do
+ metadata.name("foo")
expect(Chef::Log).to receive(:warn).with(
"Ignoring self-dependency in cookbook foo, please remove it (in the future this will be fatal)."
)
- metadata.depends('foo')
+ metadata.depends("foo")
expect(metadata.dependencies).to eql({})
end
- it "errors on self-dependencies", :chef_gte_13_only do
- metadata.name('foo')
- expect { metadata.depends('foo') }.to raise_error
+ it "errors on self-dependencies", chef: ">= 13" do
+ metadata.name("foo")
+ expect { metadata.depends("foo") }.to raise_error
# FIXME: add the error type
end
end
+ describe "chef_version" do
+ def expect_chef_version_works(*args)
+ ret = []
+ args.each do |arg|
+ metadata.send(:chef_version, *arg)
+ ret << Gem::Dependency.new("chef", *arg)
+ end
+ expect(metadata.send(:chef_versions)).to eql(ret)
+ end
+
+ it "should work with a single simple constraint" do
+ expect_chef_version_works(["~> 12"])
+ end
+
+ it "should work with a single complex constraint" do
+ expect_chef_version_works([">= 12.0.1", "< 12.5.1"])
+ end
+
+ it "should work with multiple simple constraints" do
+ expect_chef_version_works(["~> 12.5.1"], ["~> 11.18.10"])
+ end
+
+ it "should work with multiple complex constraints" do
+ expect_chef_version_works([">= 11.14.2", "< 11.18.10"], [">= 12.2.1", "< 12.5.1"])
+ end
+
+ it "should fail validation on a simple pessimistic constraint" do
+ expect_chef_version_works(["~> 999.0"])
+ expect { metadata.validate_chef_version! }.to raise_error(Chef::Exceptions::CookbookChefVersionMismatch)
+ end
+
+ it "should fail validation when that valid chef versions are too big" do
+ expect_chef_version_works([">= 999.0", "< 999.9"])
+ expect { metadata.validate_chef_version! }.to raise_error(Chef::Exceptions::CookbookChefVersionMismatch)
+ end
+
+ it "should fail validation when that valid chef versions are too small" do
+ expect_chef_version_works([">= 0.0.1", "< 0.0.9"])
+ expect { metadata.validate_chef_version! }.to raise_error(Chef::Exceptions::CookbookChefVersionMismatch)
+ end
+
+ it "should fail validation when all ranges fail" do
+ expect_chef_version_works([">= 999.0", "< 999.9"], [">= 0.0.1", "< 0.0.9"])
+ expect { metadata.validate_chef_version! }.to raise_error(Chef::Exceptions::CookbookChefVersionMismatch)
+ end
+
+ it "should pass validation when one constraint passes" do
+ expect_chef_version_works([">= 999.0", "< 999.9"], ["= #{Chef::VERSION}"])
+ expect { metadata.validate_chef_version! }.not_to raise_error
+ end
+ end
+
+ describe "ohai_version" do
+ def expect_ohai_version_works(*args)
+ ret = []
+ args.each do |arg|
+ metadata.send(:ohai_version, *arg)
+ ret << Gem::Dependency.new("ohai", *arg)
+ end
+ expect(metadata.send(:ohai_versions)).to eql(ret)
+ end
+
+ it "should work with a single simple constraint" do
+ expect_ohai_version_works(["~> 12"])
+ end
+
+ it "should work with a single complex constraint" do
+ expect_ohai_version_works([">= 12.0.1", "< 12.5.1"])
+ end
+
+ it "should work with multiple simple constraints" do
+ expect_ohai_version_works(["~> 12.5.1"], ["~> 11.18.10"])
+ end
+
+ it "should work with multiple complex constraints" do
+ expect_ohai_version_works([">= 11.14.2", "< 11.18.10"], [">= 12.2.1", "< 12.5.1"])
+ end
+
+ it "should fail validation on a simple pessimistic constraint" do
+ expect_ohai_version_works(["~> 999.0"])
+ expect { metadata.validate_ohai_version! }.to raise_error(Chef::Exceptions::CookbookOhaiVersionMismatch)
+ end
+
+ it "should fail validation when that valid chef versions are too big" do
+ expect_ohai_version_works([">= 999.0", "< 999.9"])
+ expect { metadata.validate_ohai_version! }.to raise_error(Chef::Exceptions::CookbookOhaiVersionMismatch)
+ end
+
+ it "should fail validation when that valid chef versions are too small" do
+ expect_ohai_version_works([">= 0.0.1", "< 0.0.9"])
+ expect { metadata.validate_ohai_version! }.to raise_error(Chef::Exceptions::CookbookOhaiVersionMismatch)
+ end
+
+ it "should fail validation when all ranges fail" do
+ expect_ohai_version_works([">= 999.0", "< 999.9"], [">= 0.0.1", "< 0.0.9"])
+ expect { metadata.validate_ohai_version! }.to raise_error(Chef::Exceptions::CookbookOhaiVersionMismatch)
+ end
+
+ it "should pass validation when one constraint passes" do
+ expect_ohai_version_works([">= 999.0", "< 999.9"], ["= #{Ohai::VERSION}"])
+ expect { metadata.validate_ohai_version! }.not_to raise_error
+ end
+ end
+
+ describe "gem" do
+ def expect_gem_works(*args)
+ ret = []
+ args.each do |arg|
+ metadata.send(:gem, *arg)
+ ret << arg
+ end
+ expect(metadata.send(:gems)).to eql(ret)
+ end
+
+ it "works on a simple case" do
+ expect_gem_works(["foo", "~> 1.2"])
+ end
+
+ it "works if there's two gems" do
+ expect_gem_works(["foo", "~> 1.2"], ["bar", "~> 2.0"])
+ end
+
+ it "works if there's a more complicated constraint" do
+ expect_gem_works(["foo", "~> 1.2"], ["bar", ">= 2.4", "< 4.0"])
+ end
+ end
+
describe "attribute groupings" do
it "should allow you set a grouping" do
group = {
"title" => "MySQL Tuning",
- "description" => "Setting from the my.cnf file that allow you to tune your mysql server"
+ "description" => "Setting from the my.cnf file that allow you to tune your mysql server",
}
expect(metadata.grouping("/db/mysql/databases/tuning", group)).to eq(group)
end
it "should not accept anything but a string for display_name" do
- expect {
+ expect do
metadata.grouping("db/mysql/databases", :title => "foo")
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.grouping("db/mysql/databases", :title => Hash.new)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should not accept anything but a string for the description" do
- expect {
+ expect do
metadata.grouping("db/mysql/databases", :description => "foo")
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.grouping("db/mysql/databases", :description => Hash.new)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
end
@@ -358,77 +484,77 @@ describe Chef::Cookbook::Metadata do
attrs = {
"display_name" => "MySQL Databases",
"description" => "Description of MySQL",
- "choice" => ['dedicated', 'shared'],
+ "choice" => %w{dedicated shared},
"calculated" => false,
- "type" => 'string',
- "required" => 'recommended',
+ "type" => "string",
+ "required" => "recommended",
"recipes" => [ "mysql::server", "mysql::master" ],
"default" => [ ],
"source_url" => "http://example.com",
"issues_url" => "http://example.com/issues",
- "privacy" => true
+ "privacy" => true,
}
expect(metadata.attribute("/db/mysql/databases", attrs)).to eq(attrs)
end
it "should not accept anything but a string for display_name" do
- expect {
+ expect do
metadata.attribute("db/mysql/databases", :display_name => "foo")
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.attribute("db/mysql/databases", :display_name => Hash.new)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should not accept anything but a string for the description" do
- expect {
+ expect do
metadata.attribute("db/mysql/databases", :description => "foo")
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.attribute("db/mysql/databases", :description => Hash.new)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should not accept anything but a string for the source_url" do
- expect {
+ expect do
metadata.attribute("db/mysql/databases", :source_url => "foo")
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.attribute("db/mysql/databases", :source_url => Hash.new)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should not accept anything but a string for the issues_url" do
- expect {
+ expect do
metadata.attribute("db/mysql/databases", :issues_url => "foo")
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.attribute("db/mysql/databases", :issues_url => Hash.new)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should not accept anything but true or false for the privacy flag" do
- expect {
+ expect do
metadata.attribute("db/mysql/databases", :privacy => true)
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.attribute("db/mysql/databases", :privacy => false)
- }.not_to raise_error
- expect {
- metadata.attribute("db/mysql/databases", :privacy => 'true')
- }.to raise_error(ArgumentError)
+ end.not_to raise_error
+ expect do
+ metadata.attribute("db/mysql/databases", :privacy => "true")
+ end.to raise_error(ArgumentError)
end
it "should not accept anything but an array of strings for choice" do
- expect {
- metadata.attribute("db/mysql/databases", :choice => ['dedicated', 'shared'])
- }.not_to raise_error
- expect {
- metadata.attribute("db/mysql/databases", :choice => [10, 'shared'])
- }.to raise_error(ArgumentError)
- expect {
+ expect do
+ metadata.attribute("db/mysql/databases", :choice => %w{dedicated shared})
+ end.not_to raise_error
+ expect do
+ metadata.attribute("db/mysql/databases", :choice => [10, "shared"])
+ end.to raise_error(ArgumentError)
+ expect do
metadata.attribute("db/mysql/databases", :choice => Hash.new)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should set choice to empty array by default" do
@@ -436,88 +562,88 @@ describe Chef::Cookbook::Metadata do
expect(metadata.attributes["db/mysql/databases"][:choice]).to eq([])
end
- it "should let calculated be true or false" do
- expect {
- metadata.attribute("db/mysql/databases", :calculated => true)
- }.not_to raise_error
- expect {
- metadata.attribute("db/mysql/databases", :calculated => false)
- }.not_to raise_error
- expect {
- metadata.attribute("db/mysql/databases", :calculated => Hash.new)
- }.to raise_error(ArgumentError)
- end
+ it "should let calculated be true or false" do
+ expect do
+ metadata.attribute("db/mysql/databases", :calculated => true)
+ end.not_to raise_error
+ expect do
+ metadata.attribute("db/mysql/databases", :calculated => false)
+ end.not_to raise_error
+ expect do
+ metadata.attribute("db/mysql/databases", :calculated => Hash.new)
+ end.to raise_error(ArgumentError)
+ end
- it "should set calculated to false by default" do
- metadata.attribute("db/mysql/databases", {})
- expect(metadata.attributes["db/mysql/databases"][:calculated]).to eq(false)
- end
+ it "should set calculated to false by default" do
+ metadata.attribute("db/mysql/databases", {})
+ expect(metadata.attributes["db/mysql/databases"][:calculated]).to eq(false)
+ end
it "accepts String for the attribute type" do
- expect {
+ expect do
metadata.attribute("db/mysql/databases", :type => "string")
- }.not_to raise_error
+ end.not_to raise_error
end
it "accepts Array for the attribute type" do
- expect {
+ expect do
metadata.attribute("db/mysql/databases", :type => "array")
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.attribute("db/mysql/databases", :type => Array.new)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "accepts symbol for the attribute type" do
- expect {
+ expect do
metadata.attribute("db/mysql/databases", :type => "symbol")
- }.not_to raise_error
+ end.not_to raise_error
end
- it "should let type be hash (backwards compatibility only)" do
- expect {
+ it "should let type be hash (backwards compatibility only)" do
+ expect do
metadata.attribute("db/mysql/databases", :type => "hash")
- }.not_to raise_error
+ end.not_to raise_error
end
it "should let required be required, recommended or optional" do
- expect {
- metadata.attribute("db/mysql/databases", :required => 'required')
- }.not_to raise_error
- expect {
- metadata.attribute("db/mysql/databases", :required => 'recommended')
- }.not_to raise_error
- expect {
- metadata.attribute("db/mysql/databases", :required => 'optional')
- }.not_to raise_error
+ expect do
+ metadata.attribute("db/mysql/databases", :required => "required")
+ end.not_to raise_error
+ expect do
+ metadata.attribute("db/mysql/databases", :required => "recommended")
+ end.not_to raise_error
+ expect do
+ metadata.attribute("db/mysql/databases", :required => "optional")
+ end.not_to raise_error
end
it "should convert required true to required" do
- expect {
+ expect do
metadata.attribute("db/mysql/databases", :required => true)
- }.not_to raise_error
+ end.not_to raise_error
#attrib = metadata.attributes["db/mysql/databases"][:required].should == "required"
end
it "should convert required false to optional" do
- expect {
+ expect do
metadata.attribute("db/mysql/databases", :required => false)
- }.not_to raise_error
+ end.not_to raise_error
#attrib = metadata.attributes["db/mysql/databases"][:required].should == "optional"
end
it "should set required to 'optional' by default" do
metadata.attribute("db/mysql/databases", {})
- expect(metadata.attributes["db/mysql/databases"][:required]).to eq('optional')
+ expect(metadata.attributes["db/mysql/databases"][:required]).to eq("optional")
end
it "should make sure recipes is an array" do
- expect {
+ expect do
metadata.attribute("db/mysql/databases", :recipes => [])
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.attribute("db/mysql/databases", :required => Hash.new)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should set recipes to an empty array by default" do
@@ -526,119 +652,119 @@ describe Chef::Cookbook::Metadata do
end
it "should allow the default value to be a string, array, hash, boolean or numeric" do
- expect {
+ expect do
metadata.attribute("db/mysql/databases", :default => [])
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.attribute("db/mysql/databases", :default => {})
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.attribute("db/mysql/databases", :default => "alice in chains")
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.attribute("db/mysql/databases", :default => 1337)
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.attribute("db/mysql/databases", :default => true)
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
metadata.attribute("db/mysql/databases", :required => :not_gonna_do_it)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should limit the types allowed in the choice array" do
options = {
:type => "string",
- :choice => [ "test1", "test2" ],
- :default => "test1"
+ :choice => %w{test1 test2},
+ :default => "test1",
}
- expect {
+ expect do
metadata.attribute("test_cookbook/test", options)
- }.not_to raise_error
+ end.not_to raise_error
options = {
:type => "boolean",
:choice => [ true, false ],
- :default => true
+ :default => true,
}
- expect {
+ expect do
metadata.attribute("test_cookbook/test", options)
- }.not_to raise_error
+ end.not_to raise_error
options = {
:type => "numeric",
:choice => [ 1337, 420 ],
- :default => 1337
+ :default => 1337,
}
- expect {
+ expect do
metadata.attribute("test_cookbook/test", options)
- }.not_to raise_error
+ end.not_to raise_error
options = {
:type => "numeric",
:choice => [ true, "false" ],
- :default => false
+ :default => false,
}
- expect {
+ expect do
metadata.attribute("test_cookbook/test", options)
- }.to raise_error
+ end.to raise_error(Chef::Exceptions::ValidationFailed)
end
it "should error if default used with calculated" do
- expect {
+ expect do
attrs = {
:calculated => true,
- :default => [ "I thought you said calculated" ]
+ :default => [ "I thought you said calculated" ],
}
metadata.attribute("db/mysql/databases", attrs)
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
attrs = {
:calculated => true,
- :default => "I thought you said calculated"
+ :default => "I thought you said calculated",
}
metadata.attribute("db/mysql/databases", attrs)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should allow a default that is a choice" do
- expect {
+ expect do
attrs = {
- :choice => [ "a", "b", "c"],
- :default => "b"
+ :choice => %w{a b c},
+ :default => "b",
}
metadata.attribute("db/mysql/databases", attrs)
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
attrs = {
- :choice => [ "a", "b", "c", "d", "e"],
- :default => ["b", "d"]
+ :choice => %w{a b c d e},
+ :default => %w{b d},
}
metadata.attribute("db/mysql/databases", attrs)
- }.not_to raise_error
- end
+ end.not_to raise_error
+ end
it "should error if default is not a choice" do
- expect {
+ expect do
attrs = {
- :choice => [ "a", "b", "c"],
- :default => "d"
+ :choice => %w{a b c},
+ :default => "d",
}
metadata.attribute("db/mysql/databases", attrs)
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
attrs = {
- :choice => [ "a", "b", "c", "d", "e"],
- :default => ["b", "z"]
+ :choice => %w{a b c d e},
+ :default => %w{b z},
}
metadata.attribute("db/mysql/databases", attrs)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
end
describe "recipes" do
let(:cookbook) do
- c = Chef::CookbookVersion.new('test_cookbook')
+ c = Chef::CookbookVersion.new("test_cookbook")
c.recipe_files = [ "default.rb", "enlighten.rb" ]
c
end
@@ -684,9 +810,16 @@ describe Chef::Cookbook::Metadata do
metadata.attribute "bizspark/has_login",
:display_name => "You have nothing"
metadata.version "1.2.3"
+ metadata.gem "foo", "~> 1.2"
+ metadata.gem "bar", ">= 2.2", "< 4.0"
+ metadata.chef_version ">= 11.14.2", "< 11.18.10"
+ metadata.chef_version ">= 12.2.1", "< 12.5.1"
+ metadata.ohai_version ">= 7.1.0", "< 7.5.0"
+ metadata.ohai_version ">= 8.0.1", "< 8.6.0"
end
it "should produce the same output from to_json and Chef::JSONCompat" do
+ # XXX: fairly certain this is testing ruby method dispatch
expect(metadata.to_json).to eq(Chef::JSONCompat.to_json(metadata))
end
@@ -718,18 +851,27 @@ describe Chef::Cookbook::Metadata do
source_url
issues_url
privacy
+ gems
}.each do |t|
it "should include '#{t}'" do
expect(deserialized_metadata[t]).to eq(metadata.send(t.to_sym))
end
end
+
+ %w{
+ ohai_versions
+ chef_versions
+ }.each do |t|
+ it "should include '#{t}'" do
+ expect(deserialized_metadata[t]).to eq(metadata.gem_requirements_to_array(*metadata.send(t.to_sym)))
+ end
+ end
end
describe "deserialize" do
let(:deserialized_metadata) { Chef::Cookbook::Metadata.from_json(Chef::JSONCompat.to_json(metadata)) }
-
it "should deserialize to a Chef::Cookbook::Metadata object" do
expect(deserialized_metadata).to be_a_kind_of(Chef::Cookbook::Metadata)
end
@@ -754,6 +896,9 @@ describe Chef::Cookbook::Metadata do
source_url
issues_url
privacy
+ chef_versions
+ ohai_versions
+ gems
}.each do |t|
it "should match '#{t}'" do
expect(deserialized_metadata.send(t.to_sym)).to eq(metadata.send(t.to_sym))
@@ -771,31 +916,31 @@ describe Chef::Cookbook::Metadata do
:suggestions,
:conflicting,
:replacing].each do |to_check|
- it "should transform deprecated greater than syntax for :#{to_check.to_s}" do
+ it "should transform deprecated greater than syntax for :#{to_check}" do
@hash[to_check.to_s]["foo::bar"] = ">> 0.2"
deserial = Chef::Cookbook::Metadata.from_hash(@hash)
- expect(deserial.send(to_check)["foo::bar"]).to eq('> 0.2')
+ expect(deserial.send(to_check)["foo::bar"]).to eq("> 0.2")
end
- it "should transform deprecated less than syntax for :#{to_check.to_s}" do
+ it "should transform deprecated less than syntax for :#{to_check}" do
@hash[to_check.to_s]["foo::bar"] = "<< 0.2"
deserial = Chef::Cookbook::Metadata.from_hash(@hash)
- expect(deserial.send(to_check)["foo::bar"]).to eq('< 0.2')
+ expect(deserial.send(to_check)["foo::bar"]).to eq("< 0.2")
end
- it "should ignore multiple dependency constraints for :#{to_check.to_s}" do
+ it "should ignore multiple dependency constraints for :#{to_check}" do
@hash[to_check.to_s]["foo::bar"] = [ ">= 1.0", "<= 5.2" ]
deserial = Chef::Cookbook::Metadata.from_hash(@hash)
expect(deserial.send(to_check)["foo::bar"]).to eq([])
end
- it "should accept an empty array of dependency constraints for :#{to_check.to_s}" do
+ it "should accept an empty array of dependency constraints for :#{to_check}" do
@hash[to_check.to_s]["foo::bar"] = []
deserial = Chef::Cookbook::Metadata.from_hash(@hash)
expect(deserial.send(to_check)["foo::bar"]).to eq([])
end
- it "should accept single-element arrays of dependency constraints for :#{to_check.to_s}" do
+ it "should accept single-element arrays of dependency constraints for :#{to_check}" do
@hash[to_check.to_s]["foo::bar"] = [ ">= 2.0" ]
deserial = Chef::Cookbook::Metadata.from_hash(@hash)
expect(deserial.send(to_check)["foo::bar"]).to eq(">= 2.0")
@@ -803,5 +948,24 @@ describe Chef::Cookbook::Metadata do
end
end
+ describe "from_file" do
+ it "ignores unknown metadata fields in metadata.rb files" do
+ expect(Chef::Log).to receive(:debug).with(/ignoring method some_spiffy_new_metadata_field/)
+ Tempfile.open("metadata.rb") do |f|
+ f.write <<-EOF
+ some_spiffy_new_metadata_field "stuff its set to"
+ EOF
+ f.close
+ metadata.from_file(f.path)
+ end
+ end
+ end
+
+ describe "from_json" do
+ it "ignores unknown metadata fields in metdata.json files" do
+ json = %q{{ "some_spiffy_new_metadata_field": "stuff its set to" }}
+ metadata.from_json(json)
+ end
+ end
end
end
diff --git a/spec/unit/cookbook/synchronizer_spec.rb b/spec/unit/cookbook/synchronizer_spec.rb
index 2b040f3c95..82876273e7 100644
--- a/spec/unit/cookbook/synchronizer_spec.rb
+++ b/spec/unit/cookbook/synchronizer_spec.rb
@@ -1,6 +1,6 @@
-require 'spec_helper'
-require 'chef/cookbook/synchronizer'
-require 'chef/cookbook_version'
+require "spec_helper"
+require "chef/cookbook/synchronizer"
+require "chef/cookbook_version"
describe Chef::CookbookCacheCleaner do
describe "when cleaning up unused cookbook components" do
@@ -38,7 +38,6 @@ describe Chef::CookbookCacheCleaner do
unused_template_files.each do |cbf|
expect(file_cache).to receive(:delete).with(cbf)
end
- cookbook_hash = {"valid1"=> {}, "valid2" => {}}
allow(cleaner).to receive(:cache).and_return(file_cache)
cleaner.cleanup_file_cache
end
@@ -51,7 +50,7 @@ describe Chef::CookbookCacheCleaner do
end
it "does not remove anything on chef-solo" do
- Chef::Config[:solo] = true
+ Chef::Config[:solo_legacy_mode] = true
allow(cleaner.cache).to receive(:find).and_return(%w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb})
expect(cleaner.cache).not_to receive(:delete)
cleaner.cleanup_file_cache
@@ -94,7 +93,7 @@ describe Chef::CookbookSynchronizer do
let(:cookbook_a_manifest) do
segments = [ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates, :root_files ]
- cookbook_a_manifest = segments.inject({}) {|h, segment| h[segment.to_s] = []; h}
+ cookbook_a_manifest = segments.inject({}) { |h, segment| h[segment.to_s] = []; h }
cookbook_a_manifest["recipes"] = [ cookbook_a_default_recipe ]
cookbook_a_manifest["attributes"] = [ cookbook_a_default_attrs ]
cookbook_a_manifest["templates"] = [ cookbook_a_template ]
@@ -110,7 +109,7 @@ describe Chef::CookbookSynchronizer do
let(:cookbook_manifest) do
{
- "cookbook_a" => cookbook_a
+ "cookbook_a" => cookbook_a,
}
end
@@ -124,7 +123,7 @@ describe Chef::CookbookSynchronizer do
end
it "lists the cookbook names" do
- expect(synchronizer.cookbook_names).to eq(%w[cookbook_a])
+ expect(synchronizer.cookbook_names).to eq(%w{cookbook_a})
end
it "lists the cookbook manifests" do
@@ -158,15 +157,15 @@ describe Chef::CookbookSynchronizer do
let(:file_cache) { double("Chef::FileCache with files from unused cookbooks") }
let(:cookbook_manifest) do
- {"valid1"=> {}, "valid2" => {}}
+ { "valid1" => {}, "valid2" => {} }
end
it "removes unneeded cookbooks" do
valid_cached_cb_files = %w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb}
obsolete_cb_files = %w{cookbooks/old1/recipes/default.rb cookbooks/old2/recipes/default.rb}
expect(file_cache).to receive(:find).with(File.join(%w{cookbooks ** {*,.*}})).and_return(valid_cached_cb_files + obsolete_cb_files)
- expect(file_cache).to receive(:delete).with('cookbooks/old1/recipes/default.rb')
- expect(file_cache).to receive(:delete).with('cookbooks/old2/recipes/default.rb')
+ expect(file_cache).to receive(:delete).with("cookbooks/old1/recipes/default.rb")
+ expect(file_cache).to receive(:delete).with("cookbooks/old2/recipes/default.rb")
allow(synchronizer).to receive(:cache).and_return(file_cache)
synchronizer.remove_old_cookbooks
end
@@ -176,7 +175,7 @@ describe Chef::CookbookSynchronizer do
let(:file_cache) { double("Chef::FileCache with files from unused cookbooks") }
let(:cookbook_manifest) do
- {"valid1"=> {}, "valid2" => {}}
+ { "valid1" => {}, "valid2" => {} }
end
it "removes only deleted files" do
@@ -187,7 +186,7 @@ describe Chef::CookbookSynchronizer do
expect(synchronizer).to receive(:have_cookbook?).with("valid1").at_least(:once).and_return(true)
# valid2 is a cookbook not in our run_list (we're simulating an override run_list where valid2 needs to be preserved)
expect(synchronizer).to receive(:have_cookbook?).with("valid2").at_least(:once).and_return(false)
- expect(file_cache).to receive(:delete).with('cookbooks/valid1/recipes/deleted.rb')
+ expect(file_cache).to receive(:delete).with("cookbooks/valid1/recipes/deleted.rb")
expect(synchronizer).to receive(:cookbook_segment).with("valid1", "recipes").at_least(:once).and_return([ { "path" => "recipes/default.rb" }])
allow(synchronizer).to receive(:cache).and_return(file_cache)
synchronizer.remove_deleted_files
@@ -224,8 +223,8 @@ describe Chef::CookbookSynchronizer do
and_return(false)
# Fetch and copy default.rb recipe
- expect(server_api).to receive(:get_rest).
- with('http://chef.example.com/abc123', true).
+ expect(server_api).to receive(:streaming_request).
+ with("http://chef.example.com/abc123").
and_return(cookbook_a_default_recipe_tempfile)
expect(file_cache).to receive(:move_to).
with("/tmp/cookbook_a_recipes_default_rb", "cookbooks/cookbook_a/recipes/default.rb")
@@ -234,8 +233,8 @@ describe Chef::CookbookSynchronizer do
and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb")
# Fetch and copy default.rb attribute file
- expect(server_api).to receive(:get_rest).
- with('http://chef.example.com/abc456', true).
+ expect(server_api).to receive(:streaming_request).
+ with("http://chef.example.com/abc456").
and_return(cookbook_a_default_attribute_tempfile)
expect(file_cache).to receive(:move_to).
with("/tmp/cookbook_a_attributes_default_rb", "cookbooks/cookbook_a/attributes/default.rb")
@@ -252,8 +251,8 @@ describe Chef::CookbookSynchronizer do
with("cookbooks/cookbook_a/templates/default/apache2.conf.erb").
and_return(false)
- expect(server_api).to receive(:get_rest).
- with('http://chef.example.com/megaman.conf', true).
+ expect(server_api).to receive(:streaming_request).
+ with("http://chef.example.com/megaman.conf").
and_return(cookbook_a_file_default_tempfile)
expect(file_cache).to receive(:move_to).
with("/tmp/cookbook_a_file_default_tempfile", "cookbooks/cookbook_a/files/default/megaman.conf")
@@ -261,8 +260,8 @@ describe Chef::CookbookSynchronizer do
with("cookbooks/cookbook_a/files/default/megaman.conf", false).
and_return("/file-cache/cookbooks/cookbook_a/default/megaman.conf")
- expect(server_api).to receive(:get_rest).
- with('http://chef.example.com/ffffff', true).
+ expect(server_api).to receive(:streaming_request).
+ with("http://chef.example.com/ffffff").
and_return(cookbook_a_template_default_tempfile)
expect(file_cache).to receive(:move_to).
with("/tmp/cookbook_a_template_default_tempfile", "cookbooks/cookbook_a/templates/default/apache2.conf.erb")
@@ -281,8 +280,8 @@ describe Chef::CookbookSynchronizer do
and_return(true)
# Fetch and copy default.rb recipe
- expect(server_api).to receive(:get_rest).
- with('http://chef.example.com/abc123', true).
+ expect(server_api).to receive(:streaming_request).
+ with("http://chef.example.com/abc123").
and_return(cookbook_a_default_recipe_tempfile)
expect(file_cache).to receive(:move_to).
with("/tmp/cookbook_a_recipes_default_rb", "cookbooks/cookbook_a/recipes/default.rb")
@@ -297,8 +296,8 @@ describe Chef::CookbookSynchronizer do
and_return("fff000")
# Fetch and copy default.rb attribute file
- expect(server_api).to receive(:get_rest).
- with('http://chef.example.com/abc456', true).
+ expect(server_api).to receive(:streaming_request).
+ with("http://chef.example.com/abc456").
and_return(cookbook_a_default_attribute_tempfile)
expect(file_cache).to receive(:move_to).
with("/tmp/cookbook_a_attributes_default_rb", "cookbooks/cookbook_a/attributes/default.rb")
@@ -323,8 +322,8 @@ describe Chef::CookbookSynchronizer do
and_return(true)
# Fetch and copy megaman.conf
- expect(server_api).to receive(:get_rest).
- with('http://chef.example.com/megaman.conf', true).
+ expect(server_api).to receive(:streaming_request).
+ with("http://chef.example.com/megaman.conf").
and_return(cookbook_a_file_default_tempfile)
expect(file_cache).to receive(:move_to).
with("/tmp/cookbook_a_file_default_tempfile", "cookbooks/cookbook_a/files/default/megaman.conf")
@@ -334,8 +333,8 @@ describe Chef::CookbookSynchronizer do
and_return("/file-cache/cookbooks/cookbook_a/default/megaman.conf")
# Fetch and copy apache2.conf template
- expect(server_api).to receive(:get_rest).
- with('http://chef.example.com/ffffff', true).
+ expect(server_api).to receive(:streaming_request).
+ with("http://chef.example.com/ffffff").
and_return(cookbook_a_template_default_tempfile)
expect(file_cache).to receive(:move_to).
with("/tmp/cookbook_a_template_default_tempfile", "cookbooks/cookbook_a/templates/default/apache2.conf.erb")
@@ -415,8 +414,15 @@ describe Chef::CookbookSynchronizer do
and_return("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb")
end
+ describe "#server_api" do
+ it "sets keepalive to true" do
+ expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url], keepalives: true)
+ synchronizer.server_api
+ end
+ end
+
describe "when syncing cookbooks with the server" do
- let(:server_api) { double("Chef::REST (mock)") }
+ let(:server_api) { double("Chef::ServerAPI (mock)") }
let(:file_cache) { double("Chef::FileCache (mock)") }
@@ -442,8 +448,8 @@ describe Chef::CookbookSynchronizer do
it "does not fetch templates or cookbook files" do
# Implicitly tested in previous test; this test is just for behavior specification.
- expect(server_api).not_to receive(:get_rest).
- with('http://chef.example.com/ffffff', true)
+ expect(server_api).not_to receive(:streaming_request).
+ with("http://chef.example.com/ffffff")
synchronizer.sync_cookbooks
end
@@ -502,7 +508,7 @@ describe Chef::CookbookSynchronizer do
it "does not update files" do
expect(file_cache).not_to receive(:move_to)
- expect(server_api).not_to receive(:get_rest)
+ expect(server_api).not_to receive(:streaming_request)
synchronizer.sync_cookbooks
end
end
@@ -512,7 +518,7 @@ describe Chef::CookbookSynchronizer do
it "does not update files" do
expect(file_cache).not_to receive(:move_to)
- expect(server_api).not_to receive(:get_rest)
+ expect(server_api).not_to receive(:streaming_request)
synchronizer.sync_cookbooks
end
end
diff --git a/spec/unit/cookbook/syntax_check_spec.rb b/spec/unit/cookbook/syntax_check_spec.rb
index efdb5b7926..aa6fe49eb9 100644
--- a/spec/unit/cookbook/syntax_check_spec.rb
+++ b/spec/unit/cookbook/syntax_check_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
require "chef/cookbook/syntax_check"
describe Chef::Cookbook::SyntaxCheck do
@@ -24,7 +24,8 @@ describe Chef::Cookbook::SyntaxCheck do
allow(ChefConfig).to receive(:windows?) { false }
end
- let(:cookbook_path) { File.join(CHEF_SPEC_DATA, 'cookbooks', 'openldap') }
+ let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "cookbooks", "openldap") }
+ let(:unsafe_cookbook_path) { 'C:\AGENT-HOME\xml-data\build-dir\76808194-76906499\artifact\cookbooks/java' }
let(:syntax_check) { Chef::Cookbook::SyntaxCheck.new(cookbook_path) }
let(:open_ldap_cookbook_files) do
@@ -38,7 +39,8 @@ describe Chef::Cookbook::SyntaxCheck do
recipes/default.rb
recipes/gigantor.rb
recipes/one.rb
- recipes/return.rb }.map{ |f| File.join(cookbook_path, f) }
+ recipes/return.rb
+ spec/spec_helper.rb }.map { |f| File.join(cookbook_path, f) }
end
before do
@@ -46,12 +48,13 @@ describe Chef::Cookbook::SyntaxCheck do
@original_log_level = Chef::Log.level
Chef::Log.level = :warn # suppress "Syntax OK" messages
- @attr_files = %w{default.rb smokey.rb}.map { |f| File.join(cookbook_path, 'attributes', f) }
- @libr_files = %w{openldap.rb openldap/version.rb}.map { |f| File.join(cookbook_path, 'libraries', f) }
- @defn_files = %w{client.rb server.rb}.map { |f| File.join(cookbook_path, 'definitions', f)}
- @recipes = %w{default.rb gigantor.rb one.rb return.rb}.map { |f| File.join(cookbook_path, 'recipes', f) }
- @ruby_files = @attr_files + @libr_files + @defn_files + @recipes + [File.join(cookbook_path, "metadata.rb")]
- basenames = %w{ helpers_via_partial_test.erb
+ @attr_files = %w{default.rb smokey.rb}.map { |f| File.join(cookbook_path, "attributes", f) }
+ @libr_files = %w{openldap.rb openldap/version.rb}.map { |f| File.join(cookbook_path, "libraries", f) }
+ @defn_files = %w{client.rb server.rb}.map { |f| File.join(cookbook_path, "definitions", f) }
+ @recipes = %w{default.rb gigantor.rb one.rb return.rb}.map { |f| File.join(cookbook_path, "recipes", f) }
+ @spec_files = [ File.join(cookbook_path, "spec", "spec_helper.rb") ]
+ @ruby_files = @attr_files + @libr_files + @defn_files + @recipes + @spec_files + [File.join(cookbook_path, "metadata.rb")]
+ @basenames = %w{ helpers_via_partial_test.erb
helper_test.erb
helpers.erb
openldap_stuff.conf.erb
@@ -62,7 +65,7 @@ describe Chef::Cookbook::SyntaxCheck do
some_windows_line_endings.erb
all_windows_line_endings.erb
no_windows_line_endings.erb }
- @template_files = basenames.map { |f| File.join(cookbook_path, 'templates', 'default', f)}
+ @template_files = @basenames.map { |f| File.join(cookbook_path, "templates", "default", f) }
end
after do
@@ -77,21 +80,26 @@ describe Chef::Cookbook::SyntaxCheck do
end
it "creates a syntax checker given the cookbook name and cookbook_path" do
- syntax_check = Chef::Cookbook::SyntaxCheck.for_cookbook(:openldap, File.join(CHEF_SPEC_DATA, 'cookbooks'))
+ syntax_check = Chef::Cookbook::SyntaxCheck.for_cookbook(:openldap, File.join(CHEF_SPEC_DATA, "cookbooks"))
expect(syntax_check.cookbook_path).to eq(cookbook_path)
expect(syntax_check.ruby_files.sort).to eq(open_ldap_cookbook_files.sort)
end
context "when using a standalone cookbook" do
- let(:cookbook_path) { File.join(CHEF_SPEC_DATA, 'standalone_cookbook') }
+ let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "standalone_cookbook") }
it "creates a syntax checker given the cookbook name and cookbook_path for a standalone cookbook" do
syntax_check = Chef::Cookbook::SyntaxCheck.for_cookbook(:standalone_cookbook, CHEF_SPEC_DATA)
expect(syntax_check.cookbook_path).to eq(cookbook_path)
- expect(syntax_check.ruby_files).to eq([File.join(cookbook_path, 'recipes/default.rb')])
+ expect(syntax_check.ruby_files).to eq([File.join(cookbook_path, "recipes/default.rb")])
end
end
+ it "safely handles a path containing control characters" do
+ syntax_check = Chef::Cookbook::SyntaxCheck.new(unsafe_cookbook_path)
+ expect { syntax_check.remove_uninteresting_ruby_files(@basenames) }.not_to raise_error
+ end
+
describe "when first created" do
it "has the path to the cookbook to syntax check" do
expect(syntax_check.cookbook_path).to eq(cookbook_path)
@@ -128,13 +136,13 @@ describe Chef::Cookbook::SyntaxCheck do
end
it "removes a ruby file from the list of untested files after it is marked as validated" do
- recipe = File.join(cookbook_path, 'recipes', 'default.rb')
+ recipe = File.join(cookbook_path, "recipes", "default.rb")
syntax_check.validated(recipe)
expect(syntax_check.untested_ruby_files).not_to include(recipe)
end
it "removes a template file from the list of untested files after it is marked as validated" do
- template = File.join(cookbook_path, 'templates', 'default', 'test.erb')
+ template = File.join(cookbook_path, "templates", "default", "test.erb")
syntax_check.validated(template)
expect(syntax_check.untested_template_files).not_to include(template)
end
@@ -151,7 +159,7 @@ describe Chef::Cookbook::SyntaxCheck do
describe "and a file has a syntax error" do
before do
- cookbook_path = File.join(CHEF_SPEC_DATA, 'cookbooks', 'borken')
+ cookbook_path = File.join(CHEF_SPEC_DATA, "cookbooks", "borken")
syntax_check.cookbook_path.replace(cookbook_path)
end
@@ -160,9 +168,9 @@ describe Chef::Cookbook::SyntaxCheck do
end
it "does not remove the invalid file from the list of untested files" do
- expect(syntax_check.untested_ruby_files).to include(File.join(cookbook_path, 'recipes', 'default.rb'))
+ expect(syntax_check.untested_ruby_files).to include(File.join(cookbook_path, "recipes", "default.rb"))
syntax_check.validate_ruby_files
- expect(syntax_check.untested_ruby_files).to include(File.join(cookbook_path, 'recipes', 'default.rb'))
+ expect(syntax_check.untested_ruby_files).to include(File.join(cookbook_path, "recipes", "default.rb"))
end
it "indicates that a template file has a syntax error" do
@@ -170,18 +178,18 @@ describe Chef::Cookbook::SyntaxCheck do
end
it "does not remove the invalid template from the list of untested templates" do
- expect(syntax_check.untested_template_files).to include(File.join(cookbook_path, 'templates', 'default', 'borken.erb'))
- expect {syntax_check.validate_templates}.not_to change(syntax_check, :untested_template_files)
+ expect(syntax_check.untested_template_files).to include(File.join(cookbook_path, "templates", "default", "borken.erb"))
+ expect { syntax_check.validate_templates }.not_to change(syntax_check, :untested_template_files)
end
end
describe "and an ignored file has a syntax error" do
before do
- cookbook_path = File.join(CHEF_SPEC_DATA, 'cookbooks', 'ignorken')
+ cookbook_path = File.join(CHEF_SPEC_DATA, "cookbooks", "ignorken")
Chef::Config[:cookbook_path] = File.dirname(cookbook_path)
syntax_check.cookbook_path.replace(cookbook_path)
- @ruby_files = [File.join(cookbook_path, 'metadata.rb'), File.join(cookbook_path, 'recipes/default.rb')]
+ @ruby_files = [File.join(cookbook_path, "metadata.rb"), File.join(cookbook_path, "recipes/default.rb")]
end
it "shows that ignored ruby files do not require a syntax check" do
diff --git a/spec/unit/cookbook_loader_spec.rb b/spec/unit/cookbook_loader_spec.rb
index b1384bffe7..eef5d2afd5 100644
--- a/spec/unit/cookbook_loader_spec.rb
+++ b/spec/unit/cookbook_loader_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::CookbookLoader do
before do
- allow(ChefConfig).to receive(:windows?) {false}
+ allow(ChefConfig).to receive(:windows?) { false }
end
let(:repo_paths) do
[
File.expand_path(File.join(CHEF_SPEC_DATA, "kitchen")),
- File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
+ File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")),
]
end
@@ -45,13 +45,21 @@ describe Chef::CookbookLoader do
once.
and_call_original
end
+ expect(Chef::Log).to receive(:deprecation).with(/The cookbook\(s\): openldap exist in multiple places in your cookbook_path./)
cookbook_loader.load_cookbooks
end
-
context "after loading all cookbooks" do
before(:each) do
+ expect(Chef::Log).to receive(:deprecation).with(/The cookbook\(s\): openldap exist in multiple places in your cookbook_path./)
+ cookbook_loader.load_cookbooks
+ end
+
+ it "should be possible to reload all the cookbooks without triggering deprecation warnings on all of them" do
+ start_merged_cookbooks = cookbook_loader.merged_cookbooks
+ expect(Chef::Log).to receive(:deprecation).with(/The cookbook\(s\): openldap exist in multiple places in your cookbook_path./)
cookbook_loader.load_cookbooks
+ expect(cookbook_loader.merged_cookbooks).to eql(start_merged_cookbooks)
end
describe "[]" do
@@ -86,7 +94,7 @@ describe Chef::CookbookLoader do
seen = Array.new
cookbook_loader.each do |cookbook_name, cookbook|
seen << cookbook_name
- end
+ end
expect(seen[0]).to eq("angrybash")
expect(seen[1]).to eq("apache2")
expect(seen[2]).to eq("borken")
@@ -99,69 +107,68 @@ describe Chef::CookbookLoader do
describe "referencing cookbook files" do
it "should find all the cookbooks in the cookbook path" do
- cookbook_loader.load_cookbooks
expect(cookbook_loader).to have_key(:openldap)
expect(cookbook_loader).to have_key(:apache2)
end
it "should allow you to override an attribute file via cookbook_path" do
- expect(cookbook_loader[:openldap].attribute_filenames.detect { |f|
+ expect(cookbook_loader[:openldap].attribute_filenames.detect do |f|
f =~ /cookbooks\/openldap\/attributes\/default.rb/
- }).not_to eql(nil)
- expect(cookbook_loader[:openldap].attribute_filenames.detect { |f|
+ end).not_to eql(nil)
+ expect(cookbook_loader[:openldap].attribute_filenames.detect do |f|
f =~ /kitchen\/openldap\/attributes\/default.rb/
- }).to eql(nil)
+ end).to eql(nil)
end
it "should load different attribute files from deeper paths" do
- expect(cookbook_loader[:openldap].attribute_filenames.detect { |f|
+ expect(cookbook_loader[:openldap].attribute_filenames.detect do |f|
f =~ /kitchen\/openldap\/attributes\/robinson.rb/
- }).not_to eql(nil)
+ end).not_to eql(nil)
end
it "should allow you to override a definition file via cookbook_path" do
- expect(cookbook_loader[:openldap].definition_filenames.detect { |f|
+ expect(cookbook_loader[:openldap].definition_filenames.detect do |f|
f =~ /cookbooks\/openldap\/definitions\/client.rb/
- }).not_to eql(nil)
- expect(cookbook_loader[:openldap].definition_filenames.detect { |f|
+ end).not_to eql(nil)
+ expect(cookbook_loader[:openldap].definition_filenames.detect do |f|
f =~ /kitchen\/openldap\/definitions\/client.rb/
- }).to eql(nil)
+ end).to eql(nil)
end
it "should load definition files from deeper paths" do
- expect(cookbook_loader[:openldap].definition_filenames.detect { |f|
+ expect(cookbook_loader[:openldap].definition_filenames.detect do |f|
f =~ /kitchen\/openldap\/definitions\/drewbarrymore.rb/
- }).not_to eql(nil)
+ end).not_to eql(nil)
end
it "should allow you to override a recipe file via cookbook_path" do
- expect(cookbook_loader[:openldap].recipe_filenames.detect { |f|
+ expect(cookbook_loader[:openldap].recipe_filenames.detect do |f|
f =~ /cookbooks\/openldap\/recipes\/gigantor.rb/
- }).not_to eql(nil)
- expect(cookbook_loader[:openldap].recipe_filenames.detect { |f|
+ end).not_to eql(nil)
+ expect(cookbook_loader[:openldap].recipe_filenames.detect do |f|
f =~ /kitchen\/openldap\/recipes\/gigantor.rb/
- }).to eql(nil)
+ end).to eql(nil)
end
it "should load recipe files from deeper paths" do
- expect(cookbook_loader[:openldap].recipe_filenames.detect { |f|
+ expect(cookbook_loader[:openldap].recipe_filenames.detect do |f|
f =~ /kitchen\/openldap\/recipes\/woot.rb/
- }).not_to eql(nil)
+ end).not_to eql(nil)
end
it "should allow you to have an 'ignore' file, which skips loading files in later cookbooks" do
- expect(cookbook_loader[:openldap].recipe_filenames.detect { |f|
+ expect(cookbook_loader[:openldap].recipe_filenames.detect do |f|
f =~ /kitchen\/openldap\/recipes\/ignoreme.rb/
- }).to eql(nil)
+ end).to eql(nil)
end
it "should find files that start with a ." do
- expect(cookbook_loader[:openldap].file_filenames.detect { |f|
+ expect(cookbook_loader[:openldap].file_filenames.detect do |f|
f =~ /\.dotfile$/
- }).to match(/\.dotfile$/)
- expect(cookbook_loader[:openldap].file_filenames.detect { |f|
+ end).to match(/\.dotfile$/)
+ expect(cookbook_loader[:openldap].file_filenames.detect do |f|
f =~ /\.ssh\/id_rsa$/
- }).to match(/\.ssh\/id_rsa$/)
+ end).to match(/\.ssh\/id_rsa$/)
end
it "should load the metadata for the cookbook" do
@@ -179,7 +186,7 @@ describe Chef::CookbookLoader do
[
File.join(CHEF_SPEC_DATA, "kitchen"),
File.join(CHEF_SPEC_DATA, "cookbooks"),
- File.join(CHEF_SPEC_DATA, "invalid-metadata-chef-repo")
+ File.join(CHEF_SPEC_DATA, "invalid-metadata-chef-repo"),
]
end
@@ -223,7 +230,7 @@ describe Chef::CookbookLoader do
end
it "should not load the cookbook again when accessed" do
- expect(cookbook_loader).not_to receive('load_cookbook')
+ expect(cookbook_loader).not_to receive("load_cookbook")
cookbook_loader["openldap"]
end
@@ -245,7 +252,7 @@ describe Chef::CookbookLoader do
[
File.join(CHEF_SPEC_DATA, "kitchen"),
File.join(CHEF_SPEC_DATA, "cookbooks"),
- File.join(CHEF_SPEC_DATA, "invalid-metadata-chef-repo")
+ File.join(CHEF_SPEC_DATA, "invalid-metadata-chef-repo"),
]
end
@@ -261,6 +268,7 @@ describe Chef::CookbookLoader do
describe "loading all cookbooks after loading only one cookbook" do
before(:each) do
+ expect(Chef::Log).to receive(:deprecation).with(/The cookbook\(s\): openldap exist in multiple places in your cookbook_path./)
cookbook_loader.load_cookbooks
end
diff --git a/spec/unit/cookbook_manifest_spec.rb b/spec/unit/cookbook_manifest_spec.rb
index f985942e09..acf0ade9f9 100644
--- a/spec/unit/cookbook_manifest_spec.rb
+++ b/spec/unit/cookbook_manifest_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,10 +15,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
-require 'chef/cookbook_manifest'
-require 'chef/digester'
-require 'pathname'
+require "spec_helper"
+require "chef/cookbook_manifest"
+require "chef/digester"
+require "pathname"
describe Chef::CookbookManifest do
@@ -32,7 +32,7 @@ describe Chef::CookbookManifest do
end
end
- let(:cookbook_root) { '/tmp/blah' }
+ let(:cookbook_root) { "/tmp/blah" }
let(:cookbook_version) do
Chef::CookbookVersion.new("tatft", cookbook_root).tap do |c|
@@ -62,7 +62,7 @@ describe Chef::CookbookManifest do
end
it "delegates `root_paths' to cookbook_version" do
- expect(cookbook_manifest.root_paths).to eq(['/tmp/blah'])
+ expect(cookbook_manifest.root_paths).to eq(["/tmp/blah"])
end
it "delegates `metadata' to cookbook_version" do
@@ -101,15 +101,15 @@ describe Chef::CookbookManifest do
"frozen?" => false,
- "recipes" =>[],
- "definitions" =>[],
- "libraries" =>[],
- "attributes" =>[],
- "files" =>[],
- "templates" =>[],
- "resources" =>[],
- "providers" =>[],
- "root_files" =>[],
+ "recipes" => [],
+ "definitions" => [],
+ "libraries" => [],
+ "attributes" => [],
+ "files" => [],
+ "templates" => [],
+ "resources" => [],
+ "providers" => [],
+ "root_files" => [],
}
end
@@ -121,18 +121,18 @@ describe Chef::CookbookManifest do
context "when given a cookbook with files" do
- let(:cookbook_root) { File.join(CHEF_SPEC_DATA, 'cb_version_cookbooks', 'tatft') }
+ let(:cookbook_root) { File.join(CHEF_SPEC_DATA, "cb_version_cookbooks", "tatft") }
- let(:attribute_filenames) { Dir[File.join(cookbook_root, 'attributes', '**', '*.rb')] }
- let(:definition_filenames) { Dir[File.join(cookbook_root, 'definitions', '**', '*.rb')] }
- let(:file_filenames) { Dir[File.join(cookbook_root, 'files', '**', '*.tgz')] }
- let(:recipe_filenames) { Dir[File.join(cookbook_root, 'recipes', '**', '*.rb')] }
- let(:template_filenames) { Dir[File.join(cookbook_root, 'templates', '**', '*.erb')] }
- let(:library_filenames) { Dir[File.join(cookbook_root, 'libraries', '**', '*.rb')] }
- let(:resource_filenames) { Dir[File.join(cookbook_root, 'resources', '**', '*.rb')] }
- let(:provider_filenames) { Dir[File.join(cookbook_root, 'providers', '**', '*.rb')] }
- let(:root_filenames) { Array(File.join(cookbook_root, 'README.rdoc')) }
- let(:metadata_filenames) { Array(File.join(cookbook_root, 'metadata.json')) }
+ let(:attribute_filenames) { Dir[File.join(cookbook_root, "attributes", "**", "*.rb")] }
+ let(:definition_filenames) { Dir[File.join(cookbook_root, "definitions", "**", "*.rb")] }
+ let(:file_filenames) { Dir[File.join(cookbook_root, "files", "**", "*.tgz")] }
+ let(:recipe_filenames) { Dir[File.join(cookbook_root, "recipes", "**", "*.rb")] }
+ let(:template_filenames) { Dir[File.join(cookbook_root, "templates", "**", "*.erb")] }
+ let(:library_filenames) { Dir[File.join(cookbook_root, "libraries", "**", "*.rb")] }
+ let(:resource_filenames) { Dir[File.join(cookbook_root, "resources", "**", "*.rb")] }
+ let(:provider_filenames) { Dir[File.join(cookbook_root, "providers", "**", "*.rb")] }
+ let(:root_filenames) { Array(File.join(cookbook_root, "README.rdoc")) }
+ let(:metadata_filenames) { Array(File.join(cookbook_root, "metadata.json")) }
let(:match_md5) { /[0-9a-f]{32}/ }
@@ -241,4 +241,3 @@ describe Chef::CookbookManifest do
end
end
-
diff --git a/spec/unit/cookbook_site_streaming_uploader_spec.rb b/spec/unit/cookbook_site_streaming_uploader_spec.rb
index 0041a142dc..10963386dd 100644
--- a/spec/unit/cookbook_site_streaming_uploader_spec.rb
+++ b/spec/unit/cookbook_site_streaming_uploader_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Xabier de Zuazo (xabier@onddo.com)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/cookbook_site_streaming_uploader'
+require "chef/cookbook_site_streaming_uploader"
class FakeTempfile
def initialize(basename)
@@ -39,7 +39,7 @@ describe Chef::CookbookSiteStreamingUploader do
describe "create_build_dir" do
before(:each) do
- @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, 'cookbooks'))
+ @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
@loader = Chef::CookbookLoader.new(@cookbook_repo)
@loader.load_cookbooks
allow(File).to receive(:unlink)
@@ -47,7 +47,11 @@ describe Chef::CookbookSiteStreamingUploader do
it "should create the cookbook tmp dir" do
cookbook = @loader[:openldap]
- files_count = Dir.glob(File.join(@cookbook_repo, cookbook.name.to_s, '**', '*'), File::FNM_DOTMATCH).count { |file| File.file?(file) }
+ files_count = Dir.glob(File.join(@cookbook_repo, cookbook.name.to_s, "**", "*"), File::FNM_DOTMATCH).count { |file| File.file?(file) }
+
+ # The fixture cookbook contains a spec/spec_helper.rb file, which is not
+ # a part of any cookbook segment, so it is not uploaded.
+ files_count -= 1
expect(Tempfile).to receive(:new).with("chef-#{cookbook.name}-build").and_return(FakeTempfile.new("chef-#{cookbook.name}-build"))
expect(FileUtils).to receive(:mkdir_p).exactly(files_count + 1).times
@@ -61,25 +65,25 @@ describe Chef::CookbookSiteStreamingUploader do
before(:each) do
@uri = "http://cookbooks.dummy.com/api/v1/cookbooks"
- @secret_filename = File.join(CHEF_SPEC_DATA, 'ssl/private_key.pem')
+ @secret_filename = File.join(CHEF_SPEC_DATA, "ssl/private_key.pem")
@rsa_key = File.read(@secret_filename)
- response = Net::HTTPResponse.new('1.0', '200', 'OK')
+ response = Net::HTTPResponse.new("1.0", "200", "OK")
allow_any_instance_of(Net::HTTP).to receive(:request).and_return(response)
end
it "should send an http request" do
expect_any_instance_of(Net::HTTP).to receive(:request)
- Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename)
+ Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, "bill", @secret_filename)
end
it "should read the private key file" do
expect(File).to receive(:read).with(@secret_filename).and_return(@rsa_key)
- Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename)
+ Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, "bill", @secret_filename)
end
it "should add the authentication signed header" do
expect_any_instance_of(Mixlib::Authentication::SigningObject).to receive(:sign).and_return({})
- Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename)
+ Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, "bill", @secret_filename)
end
it "should be able to send post requests" do
@@ -88,7 +92,7 @@ describe Chef::CookbookSiteStreamingUploader do
expect(Net::HTTP::Post).to receive(:new).once.and_return(post)
expect(Net::HTTP::Put).not_to receive(:new)
expect(Net::HTTP::Get).not_to receive(:new)
- Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename)
+ Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, "bill", @secret_filename)
end
it "should be able to send put requests" do
@@ -97,27 +101,27 @@ describe Chef::CookbookSiteStreamingUploader do
expect(Net::HTTP::Post).not_to receive(:new)
expect(Net::HTTP::Put).to receive(:new).once.and_return(put)
expect(Net::HTTP::Get).not_to receive(:new)
- Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, 'bill', @secret_filename)
+ Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, "bill", @secret_filename)
end
it "should be able to receive files to attach as argument" do
- Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, 'bill', @secret_filename, {
- :myfile => File.new(File.join(CHEF_SPEC_DATA, 'config.rb')), # a dummy file
+ Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, "bill", @secret_filename, {
+ :myfile => File.new(File.join(CHEF_SPEC_DATA, "config.rb")), # a dummy file
})
end
it "should be able to receive strings to attach as argument" do
- Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, 'bill', @secret_filename, {
- :mystring => 'Lorem ipsum',
+ Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, "bill", @secret_filename, {
+ :mystring => "Lorem ipsum",
})
end
it "should be able to receive strings and files as argument at the same time" do
- Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, 'bill', @secret_filename, {
- :myfile1 => File.new(File.join(CHEF_SPEC_DATA, 'config.rb')),
- :mystring1 => 'Lorem ipsum',
- :myfile2 => File.new(File.join(CHEF_SPEC_DATA, 'config.rb')),
- :mystring2 => 'Dummy text',
+ Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, "bill", @secret_filename, {
+ :myfile1 => File.new(File.join(CHEF_SPEC_DATA, "config.rb")),
+ :mystring1 => "Lorem ipsum",
+ :myfile2 => File.new(File.join(CHEF_SPEC_DATA, "config.rb")),
+ :mystring2 => "Dummy text",
})
end
@@ -125,7 +129,7 @@ describe Chef::CookbookSiteStreamingUploader do
describe "StreamPart" do
before(:each) do
- @file = File.new(File.join(CHEF_SPEC_DATA, 'config.rb'))
+ @file = File.new(File.join(CHEF_SPEC_DATA, "config.rb"))
@stream_part = Chef::CookbookSiteStreamingUploader::StreamPart.new(@file, File.size(@file))
end
@@ -147,7 +151,7 @@ describe Chef::CookbookSiteStreamingUploader do
describe "StringPart" do
before(:each) do
- @str = 'What a boring string'
+ @str = "What a boring string"
@string_part = Chef::CookbookSiteStreamingUploader::StringPart.new(@str)
end
@@ -189,7 +193,7 @@ describe Chef::CookbookSiteStreamingUploader do
end
it "should read receiving destination buffer as second argument (CHEF-4456: Ruby 2 compat)" do
- dst_buf = ''
+ dst_buf = ""
@multipart_stream.read(10, dst_buf)
expect(dst_buf).to eql("#{@string1}#{@string2}"[0, 10])
end
diff --git a/spec/unit/cookbook_spec.rb b/spec/unit/cookbook_spec.rb
index f36b031309..33b4a3ccd8 100644
--- a/spec/unit/cookbook_spec.rb
+++ b/spec/unit/cookbook_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::CookbookVersion do
# COOKBOOK_PATH = File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks", "openldap"))
@@ -39,7 +39,7 @@ describe Chef::CookbookVersion do
it "should allow you to set the list of attribute files and create the mapping from short names to paths" do
@cookbook.attribute_filenames = [ "attributes/one.rb", "attributes/two.rb" ]
expect(@cookbook.attribute_filenames).to eq([ "attributes/one.rb", "attributes/two.rb" ])
- expect(@cookbook.attribute_filenames_by_short_filename.keys.sort).to eql(["one", "two"])
+ expect(@cookbook.attribute_filenames_by_short_filename.keys.sort).to eql(%w{one two})
expect(@cookbook.attribute_filenames_by_short_filename["one"]).to eq("attributes/one.rb")
expect(@cookbook.attribute_filenames_by_short_filename["two"]).to eq("attributes/two.rb")
end
@@ -47,7 +47,7 @@ describe Chef::CookbookVersion do
it "should allow you to set the list of recipe files and create the mapping of recipe short name to filename" do
@cookbook.recipe_filenames = [ "recipes/one.rb", "recipes/two.rb" ]
expect(@cookbook.recipe_filenames).to eq([ "recipes/one.rb", "recipes/two.rb" ])
- expect(@cookbook.recipe_filenames_by_name.keys.sort).to eql(["one", "two"])
+ expect(@cookbook.recipe_filenames_by_name.keys.sort).to eql(%w{one two})
expect(@cookbook.recipe_filenames_by_name["one"]).to eq("recipes/one.rb")
expect(@cookbook.recipe_filenames_by_name["two"]).to eq("recipes/two.rb")
end
diff --git a/spec/unit/cookbook_uploader_spec.rb b/spec/unit/cookbook_uploader_spec.rb
index 76727c18e2..c30df71e34 100644
--- a/spec/unit/cookbook_uploader_spec.rb
+++ b/spec/unit/cookbook_uploader_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::CookbookUploader do
- let(:http_client) { double("Chef::REST") }
+ let(:http_client) { double("Chef::ServerAPI") }
let(:cookbook_loader) do
loader = Chef::CookbookLoader.new(File.join(CHEF_SPEC_DATA, "cookbooks"))
@@ -64,8 +64,8 @@ describe Chef::CookbookUploader do
end
it "creates an HTTP client with default configuration when not initialized with one" do
- default_http_client = double("Chef::REST")
- expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(default_http_client)
+ default_http_client = double("Chef::ServerAPI")
+ expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(default_http_client)
uploader = described_class.new(cookbooks_to_upload)
expect(uploader.rest).to eq(default_http_client)
end
@@ -78,7 +78,7 @@ describe Chef::CookbookUploader do
let(:sandbox_response) do
sandbox_checksums = cksums_not_on_remote.inject({}) do |cksum_map, cksum|
- cksum_map[cksum] = { "needs_upload" => true, "url" => url_for(cksum)}
+ cksum_map[cksum] = { "needs_upload" => true, "url" => url_for(cksum) }
cksum_map
end
{ "checksums" => sandbox_checksums, "uri" => sandbox_commit_uri }
@@ -86,7 +86,7 @@ describe Chef::CookbookUploader do
def expect_sandbox_create
expect(http_client).to receive(:post).
- with("sandboxes", {:checksums => checksums_set}).
+ with("sandboxes", { :checksums => checksums_set }).
and_return(sandbox_response)
end
@@ -97,7 +97,7 @@ describe Chef::CookbookUploader do
upload_headers = {
"content-type" => "application/x-binary",
"content-md5" => an_instance_of(String),
- "accept" => "application/json"
+ "accept" => "application/json",
}
expect(http_client).to receive(:put).
@@ -111,7 +111,7 @@ describe Chef::CookbookUploader do
end
def expect_sandbox_commit
- expect(http_client).to receive(:put).with(sandbox_commit_uri, {:is_completed => true})
+ expect(http_client).to receive(:put).with(sandbox_commit_uri, { :is_completed => true })
end
def expect_cookbook_create
@@ -193,7 +193,6 @@ describe Chef::CookbookUploader do
uploader.upload_cookbooks
end
-
end
end
diff --git a/spec/unit/cookbook_version_file_specificity_spec.rb b/spec/unit/cookbook_version_file_specificity_spec.rb
index 73b10899d4..3b5450cb2d 100644
--- a/spec/unit/cookbook_version_file_specificity_spec.rb
+++ b/spec/unit/cookbook_version_file_specificity_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +17,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::CookbookVersion, "file specificity" do
before(:each) do
- @cookbook = Chef::CookbookVersion.new "test-cookbook"
+ @cookbook = Chef::CookbookVersion.new("test-cookbook", "/cookbook-folder")
@cookbook.manifest = {
"files" =>
[
@@ -30,31 +30,31 @@ describe Chef::CookbookVersion, "file specificity" do
:name => "afile.rb",
:path => "files/host-examplehost.example.org/afile.rb",
:checksum => "csum-host",
- :specificity => "host-examplehost.example.org"
+ :specificity => "host-examplehost.example.org",
},
{
:name => "afile.rb",
:path => "files/ubuntu-9.10/afile.rb",
:checksum => "csum-platver-full",
- :specificity => "ubuntu-9.10"
+ :specificity => "ubuntu-9.10",
},
{
:name => "afile.rb",
:path => "files/newubuntu-9/afile.rb",
:checksum => "csum-platver-partial",
- :specificity => "newubuntu-9"
+ :specificity => "newubuntu-9",
},
{
:name => "afile.rb",
:path => "files/ubuntu/afile.rb",
:checksum => "csum-plat",
- :specificity => "ubuntu"
+ :specificity => "ubuntu",
},
{
:name => "afile.rb",
:path => "files/default/afile.rb",
:checksum => "csum-default",
- :specificity => "default"
+ :specificity => "default",
},
# for different/odd platform_versions
@@ -62,25 +62,25 @@ describe Chef::CookbookVersion, "file specificity" do
:name => "bfile.rb",
:path => "files/fakeos-2.0.rc.1/bfile.rb",
:checksum => "csum2-platver-full",
- :specificity => "fakeos-2.0.rc.1"
+ :specificity => "fakeos-2.0.rc.1",
},
{
:name => "bfile.rb",
:path => "files/newfakeos-2.0.rc/bfile.rb",
:checksum => "csum2-platver-partial",
- :specificity => "newfakeos-2.0.rc"
+ :specificity => "newfakeos-2.0.rc",
},
{
:name => "bfile.rb",
:path => "files/fakeos-maple tree/bfile.rb",
:checksum => "csum3-platver-full",
- :specificity => "maple tree"
+ :specificity => "maple tree",
},
{
:name => "bfile.rb",
:path => "files/fakeos-1/bfile.rb",
:checksum => "csum4-platver-full",
- :specificity => "fakeos-1"
+ :specificity => "fakeos-1",
},
# directory adirectory
@@ -88,121 +88,120 @@ describe Chef::CookbookVersion, "file specificity" do
:name => "anotherfile1.rb",
:path => "files/host-examplehost.example.org/adirectory/anotherfile1.rb.host",
:checksum => "csum-host-1",
- :specificity => "host-examplehost.example.org"
+ :specificity => "host-examplehost.example.org",
},
{
:name => "anotherfile2.rb",
:path => "files/host-examplehost.example.org/adirectory/anotherfile2.rb.host",
:checksum => "csum-host-2",
- :specificity => "host-examplehost.example.org"
+ :specificity => "host-examplehost.example.org",
},
{
:name => "anotherfile1.rb",
:path => "files/ubuntu-9.10/adirectory/anotherfile1.rb.platform-full-version",
:checksum => "csum-platver-full-1",
- :specificity => "ubuntu-9.10"
+ :specificity => "ubuntu-9.10",
},
{
:name => "anotherfile2.rb",
:path => "files/ubuntu-9.10/adirectory/anotherfile2.rb.platform-full-version",
:checksum => "csum-platver-full-2",
- :specificity => "ubuntu-9.10"
+ :specificity => "ubuntu-9.10",
},
{
:name => "anotherfile1.rb",
:path => "files/newubuntu-9/adirectory/anotherfile1.rb.platform-partial-version",
:checksum => "csum-platver-partial-1",
- :specificity => "newubuntu-9"
+ :specificity => "newubuntu-9",
},
{
:name => "anotherfile2.rb",
:path => "files/newubuntu-9/adirectory/anotherfile2.rb.platform-partial-version",
:checksum => "csum-platver-partial-2",
- :specificity => "nweubuntu-9"
+ :specificity => "nweubuntu-9",
},
{
:name => "anotherfile1.rb",
:path => "files/ubuntu/adirectory/anotherfile1.rb.platform",
:checksum => "csum-plat-1",
- :specificity => "ubuntu"
+ :specificity => "ubuntu",
},
{
:name => "anotherfile2.rb",
:path => "files/ubuntu/adirectory/anotherfile2.rb.platform",
:checksum => "csum-plat-2",
- :specificity => "ubuntu"
+ :specificity => "ubuntu",
},
{
:name => "anotherfile1.rb",
:path => "files/default/adirectory/anotherfile1.rb.default",
:checksum => "csum-default-1",
- :specificity => "default"
+ :specificity => "default",
},
{
:name => "anotherfile2.rb",
:path => "files/default/adirectory/anotherfile2.rb.default",
:checksum => "csum-default-2",
- :specificity => "default"
+ :specificity => "default",
},
# for different/odd platform_versions
{
:name => "anotherfile1.rb",
:path => "files/fakeos-2.0.rc.1/adirectory/anotherfile1.rb.platform-full-version",
:checksum => "csum2-platver-full-1",
- :specificity => "fakeos-2.0.rc.1"
+ :specificity => "fakeos-2.0.rc.1",
},
{
:name => "anotherfile2.rb",
:path => "files/fakeos-2.0.rc.1/adirectory/anotherfile2.rb.platform-full-version",
:checksum => "csum2-platver-full-2",
- :specificity => "fakeos-2.0.rc.1"
+ :specificity => "fakeos-2.0.rc.1",
},
{
:name => "anotherfile1.rb",
:path => "files/newfakeos-2.0.rc.1/adirectory/anotherfile1.rb.platform-partial-version",
:checksum => "csum2-platver-partial-1",
- :specificity => "newfakeos-2.0.rc"
+ :specificity => "newfakeos-2.0.rc",
},
{
:name => "anotherfile2.rb",
:path => "files/newfakeos-2.0.rc.1/adirectory/anotherfile2.rb.platform-partial-version",
:checksum => "csum2-platver-partial-2",
- :specificity => "newfakeos-2.0.rc"
+ :specificity => "newfakeos-2.0.rc",
},
{
:name => "anotherfile1.rb",
:path => "files/fakeos-maple tree/adirectory/anotherfile1.rb.platform-full-version",
:checksum => "csum3-platver-full-1",
- :specificity => "fakeos-maple tree"
+ :specificity => "fakeos-maple tree",
},
{
:name => "anotherfile2.rb",
:path => "files/fakeos-maple tree/adirectory/anotherfile2.rb.platform-full-version",
:checksum => "csum3-platver-full-2",
- :specificity => "fakeos-maple tree"
+ :specificity => "fakeos-maple tree",
},
{
:name => "anotherfile1.rb",
:path => "files/fakeos-1/adirectory/anotherfile1.rb.platform-full-version",
:checksum => "csum4-platver-full-1",
- :specificity => "fakeos-1"
+ :specificity => "fakeos-1",
},
{
:name => "anotherfile2.rb",
:path => "files/fakeos-1/adirectory/anotherfile2.rb.platform-full-version",
:checksum => "csum4-platver-full-2",
- :specificity => "fakeos-1"
+ :specificity => "fakeos-1",
},
- ]
+ ],
}
end
-
it "should return a manifest record based on priority preference: host" do
node = Chef::Node.new
node.automatic_attrs[:platform] = "ubuntu"
@@ -302,6 +301,29 @@ describe Chef::CookbookVersion, "file specificity" do
expect(manifest_record[:checksum]).to eq("csum4-platver-full")
end
+ it "should raise a FileNotFound exception without match" do
+ node = Chef::Node.new
+
+ expect do
+ @cookbook.preferred_manifest_record(node, :files, "doesn't_exist.rb")
+ end.to raise_error(Chef::Exceptions::FileNotFound)
+ end
+ it "should raise a FileNotFound exception consistently without match" do
+ node = Chef::Node.new
+
+ expect do
+ @cookbook.preferred_manifest_record(node, :files, "doesn't_exist.rb")
+ end.to raise_error(Chef::Exceptions::FileNotFound)
+
+ expect do
+ @cookbook.preferred_manifest_record(node, :files, "doesn't_exist.rb")
+ end.to raise_error(Chef::Exceptions::FileNotFound)
+
+ expect do
+ @cookbook.preferred_manifest_record(node, :files, "doesn't_exist.rb")
+ end.to raise_error(Chef::Exceptions::FileNotFound)
+ end
+
describe "when fetching the contents of a directory by file specificity" do
it "should return a directory of manifest records based on priority preference: host" do
@@ -314,7 +336,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(manifest_records).not_to be_nil
expect(manifest_records.size).to eq(2)
- checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+ checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
expect(checksums.sort).to eq(["csum-host-1", "csum-host-2"])
end
@@ -328,7 +350,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(manifest_records).not_to be_nil
expect(manifest_records.size).to eq(2)
- checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+ checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
expect(checksums.sort).to eq(["csum-platver-full-1", "csum-platver-full-2"])
end
@@ -342,7 +364,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(manifest_records).not_to be_nil
expect(manifest_records.size).to eq(2)
- checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+ checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
expect(checksums.sort).to eq(["csum-platver-partial-1", "csum-platver-partial-2"])
end
@@ -356,7 +378,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(manifest_records).not_to be_nil
expect(manifest_records.size).to eq(2)
- checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+ checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
expect(checksums.sort).to eq(["csum-plat-1", "csum-plat-2"])
end
@@ -370,7 +392,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(manifest_records).not_to be_nil
expect(manifest_records.size).to eq(2)
- checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+ checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
expect(checksums.sort).to eq(["csum-default-1", "csum-default-2"])
end
@@ -384,7 +406,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(manifest_records).not_to be_nil
expect(manifest_records.size).to eq(2)
- checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+ checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
expect(checksums.sort).to eq(["csum2-platver-full-1", "csum2-platver-full-2"])
end
@@ -398,7 +420,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(manifest_records).not_to be_nil
expect(manifest_records.size).to eq(2)
- checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+ checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
expect(checksums.sort).to eq(["csum2-platver-partial-1", "csum2-platver-partial-2"])
end
@@ -412,7 +434,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(manifest_records).not_to be_nil
expect(manifest_records.size).to eq(2)
- checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+ checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
expect(checksums.sort).to eq(["csum3-platver-full-1", "csum3-platver-full-2"])
end
@@ -426,7 +448,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(manifest_records).not_to be_nil
expect(manifest_records.size).to eq(2)
- checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+ checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
expect(checksums.sort).to eq(["csum4-platver-full-1", "csum4-platver-full-2"])
end
end
@@ -444,7 +466,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(filenames).not_to be_nil
expect(filenames.size).to eq(2)
- expect(filenames.sort).to eq(['anotherfile1.rb.host', 'anotherfile2.rb.host'])
+ expect(filenames.sort).to eq(["anotherfile1.rb.host", "anotherfile2.rb.host"])
end
it "should return a list of relative paths based on priority preference: platform & full version" do
@@ -457,7 +479,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(filenames).not_to be_nil
expect(filenames.size).to eq(2)
- expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'])
+ expect(filenames.sort).to eq(["anotherfile1.rb.platform-full-version", "anotherfile2.rb.platform-full-version"])
end
it "should return a list of relative paths based on priority preference: platform & partial version" do
@@ -470,7 +492,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(filenames).not_to be_nil
expect(filenames.size).to eq(2)
- expect(filenames.sort).to eq(['anotherfile1.rb.platform-partial-version', 'anotherfile2.rb.platform-partial-version'])
+ expect(filenames.sort).to eq(["anotherfile1.rb.platform-partial-version", "anotherfile2.rb.platform-partial-version"])
end
it "should return a list of relative paths based on priority preference: platform only" do
@@ -483,7 +505,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(filenames).not_to be_nil
expect(filenames.size).to eq(2)
- expect(filenames.sort).to eq(['anotherfile1.rb.platform', 'anotherfile2.rb.platform'])
+ expect(filenames.sort).to eq(["anotherfile1.rb.platform", "anotherfile2.rb.platform"])
end
it "should return a list of relative paths based on priority preference: default" do
@@ -496,7 +518,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(filenames).not_to be_nil
expect(filenames.size).to eq(2)
- expect(filenames.sort).to eq(['anotherfile1.rb.default', 'anotherfile2.rb.default'])
+ expect(filenames.sort).to eq(["anotherfile1.rb.default", "anotherfile2.rb.default"])
end
it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 1" do
@@ -509,7 +531,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(filenames).not_to be_nil
expect(filenames.size).to eq(2)
- expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'])
+ expect(filenames.sort).to eq(["anotherfile1.rb.platform-full-version", "anotherfile2.rb.platform-full-version"])
end
it "should return a list of relative paths based on priority preference: platform & partial version - platform_version variant 1" do
@@ -522,7 +544,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(filenames).not_to be_nil
expect(filenames.size).to eq(2)
- expect(filenames.sort).to eq(['anotherfile1.rb.platform-partial-version', 'anotherfile2.rb.platform-partial-version'])
+ expect(filenames.sort).to eq(["anotherfile1.rb.platform-partial-version", "anotherfile2.rb.platform-partial-version"])
end
it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 2" do
@@ -535,7 +557,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(filenames).not_to be_nil
expect(filenames.size).to eq(2)
- expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'])
+ expect(filenames.sort).to eq(["anotherfile1.rb.platform-full-version", "anotherfile2.rb.platform-full-version"])
end
it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 3" do
@@ -548,7 +570,7 @@ describe Chef::CookbookVersion, "file specificity" do
expect(filenames).not_to be_nil
expect(filenames.size).to eq(2)
- expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'])
+ expect(filenames.sort).to eq(["anotherfile1.rb.platform-full-version", "anotherfile2.rb.platform-full-version"])
end
end
end
diff --git a/spec/unit/cookbook_version_spec.rb b/spec/unit/cookbook_version_spec.rb
index 2bccddcaec..81ea161bfe 100644
--- a/spec/unit/cookbook_version_spec.rb
+++ b/spec/unit/cookbook_version_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,61 +15,63 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
+require "spec_helper"
describe Chef::CookbookVersion do
describe "when first created" do
- before do
- @cookbook_version = Chef::CookbookVersion.new("tatft", '/tmp/blah')
- end
+ let(:cookbook_version) { Chef::CookbookVersion.new("tatft", "/tmp/blah") }
it "has a name" do
- expect(@cookbook_version.name).to eq('tatft')
+ expect(cookbook_version.name).to eq("tatft")
end
it "has no attribute files" do
- expect(@cookbook_version.attribute_filenames).to be_empty
+ expect(cookbook_version.attribute_filenames).to be_empty
end
it "has no resource definition files" do
- expect(@cookbook_version.definition_filenames).to be_empty
+ expect(cookbook_version.definition_filenames).to be_empty
end
it "has no cookbook files" do
- expect(@cookbook_version.file_filenames).to be_empty
+ expect(cookbook_version.file_filenames).to be_empty
end
it "has no recipe files" do
- expect(@cookbook_version.recipe_filenames).to be_empty
+ expect(cookbook_version.recipe_filenames).to be_empty
end
it "has no library files" do
- expect(@cookbook_version.library_filenames).to be_empty
+ expect(cookbook_version.library_filenames).to be_empty
end
it "has no LWRP resource files" do
- expect(@cookbook_version.resource_filenames).to be_empty
+ expect(cookbook_version.resource_filenames).to be_empty
end
it "has no LWRP provider files" do
- expect(@cookbook_version.provider_filenames).to be_empty
+ expect(cookbook_version.provider_filenames).to be_empty
end
it "has no metadata files" do
- expect(@cookbook_version.metadata_filenames).to be_empty
+ expect(cookbook_version.metadata_filenames).to be_empty
+ end
+
+ it "has an empty set of all_files" do
+ expect(cookbook_version.all_files).to be_empty
end
it "is not frozen" do
- expect(@cookbook_version).not_to be_frozen_version
+ expect(cookbook_version).not_to be_frozen_version
end
it "can be frozen" do
- @cookbook_version.freeze_version
- expect(@cookbook_version).to be_frozen_version
+ cookbook_version.freeze_version
+ expect(cookbook_version).to be_frozen_version
end
it "has empty metadata" do
- expect(@cookbook_version.metadata).to eq(Chef::Cookbook::Metadata.new)
+ expect(cookbook_version.metadata).to eq(Chef::Cookbook::Metadata.new)
end
end
@@ -77,163 +79,178 @@ describe Chef::CookbookVersion do
describe "with a cookbook directory named tatft" do
MD5 = /[0-9a-f]{32}/
- before do
- @cookbook = Hash.new { |hash, key| hash[key] = [] }
-
- @cookbook_root = File.join(CHEF_SPEC_DATA, 'cb_version_cookbooks', 'tatft')
-
- # Dunno if the paths here are representitive of what is set by CookbookLoader...
- @cookbook[:attribute_filenames] = Dir[File.join(@cookbook_root, 'attributes', '**', '*.rb')]
- @cookbook[:definition_filenames] = Dir[File.join(@cookbook_root, 'definitions', '**', '*.rb')]
- @cookbook[:file_filenames] = Dir[File.join(@cookbook_root, 'files', '**', '*.tgz')]
- @cookbook[:recipe_filenames] = Dir[File.join(@cookbook_root, 'recipes', '**', '*.rb')]
- @cookbook[:template_filenames] = Dir[File.join(@cookbook_root, 'templates', '**', '*.erb')]
- @cookbook[:library_filenames] = Dir[File.join(@cookbook_root, 'libraries', '**', '*.rb')]
- @cookbook[:resource_filenames] = Dir[File.join(@cookbook_root, 'resources', '**', '*.rb')]
- @cookbook[:provider_filenames] = Dir[File.join(@cookbook_root, 'providers', '**', '*.rb')]
- @cookbook[:root_filenames] = Array(File.join(@cookbook_root, 'README.rdoc'))
- @cookbook[:metadata_filenames] = Array(File.join(@cookbook_root, 'metadata.json'))
- end
+ let(:cookbook_paths_by_type) do
+ {
+ # Dunno if the paths here are representitive of what is set by CookbookLoader...
+ all_files: Dir[File.join(cookbook_root, "**", "*.rb")],
+ attribute_filenames: Dir[File.join(cookbook_root, "attributes", "**", "*.rb")],
+ definition_filenames: Dir[File.join(cookbook_root, "definitions", "**", "*.rb")],
+ file_filenames: Dir[File.join(cookbook_root, "files", "**", "*.tgz")],
+ recipe_filenames: Dir[File.join(cookbook_root, "recipes", "**", "*.rb")],
+ template_filenames: Dir[File.join(cookbook_root, "templates", "**", "*.erb")],
+ library_filenames: Dir[File.join(cookbook_root, "libraries", "**", "*.rb")],
+ resource_filenames: Dir[File.join(cookbook_root, "resources", "**", "*.rb")],
+ provider_filenames: Dir[File.join(cookbook_root, "providers", "**", "*.rb")],
+ root_filenames: Array(File.join(cookbook_root, "README.rdoc")),
+ metadata_filenames: Array(File.join(cookbook_root, "metadata.json")),
+ }
+ end
+
+ let(:cookbook_root) { File.join(CHEF_SPEC_DATA, "cb_version_cookbooks", "tatft") }
describe "and a cookbook with the same name" do
- before do
+
+ let(:cookbook_version) do
+ Chef::CookbookVersion.new("tatft", cookbook_root).tap do |c|
# Currently the cookbook loader finds all the files then tells CookbookVersion
# where they are.
- @cookbook_version = Chef::CookbookVersion.new('tatft', @cookbook_root)
-
- @cookbook_version.attribute_filenames = @cookbook[:attribute_filenames]
- @cookbook_version.definition_filenames = @cookbook[:definition_filenames]
- @cookbook_version.recipe_filenames = @cookbook[:recipe_filenames]
- @cookbook_version.template_filenames = @cookbook[:template_filenames]
- @cookbook_version.file_filenames = @cookbook[:file_filenames]
- @cookbook_version.library_filenames = @cookbook[:library_filenames]
- @cookbook_version.resource_filenames = @cookbook[:resource_filenames]
- @cookbook_version.provider_filenames = @cookbook[:provider_filenames]
- @cookbook_version.root_filenames = @cookbook[:root_filenames]
- @cookbook_version.metadata_filenames = @cookbook[:metadata_filenames]
-
- # Used to test file-specificity related file lookups
- @node = Chef::Node.new
- @node.set[:platform] = "ubuntu"
- @node.set[:platform_version] = "13.04"
- @node.name("testing")
+ c.attribute_filenames = cookbook_paths_by_type[:attribute_filenames]
+ c.definition_filenames = cookbook_paths_by_type[:definition_filenames]
+ c.recipe_filenames = cookbook_paths_by_type[:recipe_filenames]
+ c.template_filenames = cookbook_paths_by_type[:template_filenames]
+ c.file_filenames = cookbook_paths_by_type[:file_filenames]
+ c.library_filenames = cookbook_paths_by_type[:library_filenames]
+ c.resource_filenames = cookbook_paths_by_type[:resource_filenames]
+ c.provider_filenames = cookbook_paths_by_type[:provider_filenames]
+ c.root_filenames = cookbook_paths_by_type[:root_filenames]
+ c.metadata_filenames = cookbook_paths_by_type[:metadata_filenames]
+ end
+ end
+
+ # Used to test file-specificity related file lookups
+ let(:node) do
+ Chef::Node.new.tap do |n|
+ n.normal[:platform] = "ubuntu"
+ n.normal[:platform_version] = "13.04"
+ n.name("testing")
+ end
end
it "determines whether a template is available for a given node" do
- expect(@cookbook_version).to have_template_for_node(@node, "configuration.erb")
- expect(@cookbook_version).not_to have_template_for_node(@node, "missing.erb")
+ expect(cookbook_version).to have_template_for_node(node, "configuration.erb")
+ expect(cookbook_version).not_to have_template_for_node(node, "missing.erb")
end
it "determines whether a cookbook_file is available for a given node" do
- expect(@cookbook_version).to have_cookbook_file_for_node(@node, "giant_blob.tgz")
- expect(@cookbook_version).not_to have_cookbook_file_for_node(@node, "missing.txt")
+ expect(cookbook_version).to have_cookbook_file_for_node(node, "giant_blob.tgz")
+ expect(cookbook_version).not_to have_cookbook_file_for_node(node, "missing.txt")
end
describe "raises an error when attempting to load a missing cookbook_file and" do
- before do
- node = Chef::Node.new.tap do |n|
+ let(:node) do
+ Chef::Node.new.tap do |n|
n.name("sample.node")
n.automatic_attrs[:fqdn] = "sample.example.com"
n.automatic_attrs[:platform] = "ubuntu"
n.automatic_attrs[:platform_version] = "10.04"
end
- @attempt_to_load_file = lambda { @cookbook_version.preferred_manifest_record(node, :files, "no-such-thing.txt") }
+ end
+
+ def attempt_to_load_file
+ cookbook_version.preferred_manifest_record(node, :files, "no-such-thing.txt")
end
it "describes the cookbook and version" do
useful_explanation = Regexp.new(Regexp.escape("Cookbook 'tatft' (0.0.0) does not contain"))
- expect(@attempt_to_load_file).to raise_error(Chef::Exceptions::FileNotFound, useful_explanation)
+ expect { attempt_to_load_file }.to raise_error(Chef::Exceptions::FileNotFound, useful_explanation)
end
it "lists suggested places to look" do
useful_explanation = Regexp.new(Regexp.escape("files/default/no-such-thing.txt"))
- expect(@attempt_to_load_file).to raise_error(Chef::Exceptions::FileNotFound, useful_explanation)
+ expect { attempt_to_load_file }.to raise_error(Chef::Exceptions::FileNotFound, useful_explanation)
end
end
end
end
- describe 'with a cookbook directory named cookbook2 that has unscoped files' do
- before do
- @cookbook = Hash.new { |hash, key| hash[key] = [] }
-
- @cookbook_root = File.join(CHEF_SPEC_DATA, 'cb_version_cookbooks', 'cookbook2')
-
- # Dunno if the paths here are representitive of what is set by CookbookLoader...
- @cookbook[:attribute_filenames] = Dir[File.join(@cookbook_root, 'attributes', '**', '*.rb')]
- @cookbook[:definition_filenames] = Dir[File.join(@cookbook_root, 'definitions', '**', '*.rb')]
- @cookbook[:file_filenames] = Dir[File.join(@cookbook_root, 'files', '**', '*.*')]
- @cookbook[:recipe_filenames] = Dir[File.join(@cookbook_root, 'recipes', '**', '*.rb')]
- @cookbook[:template_filenames] = Dir[File.join(@cookbook_root, 'templates', '**', '*.*')]
- @cookbook[:library_filenames] = Dir[File.join(@cookbook_root, 'libraries', '**', '*.rb')]
- @cookbook[:resource_filenames] = Dir[File.join(@cookbook_root, 'resources', '**', '*.rb')]
- @cookbook[:provider_filenames] = Dir[File.join(@cookbook_root, 'providers', '**', '*.rb')]
- @cookbook[:root_filenames] = Array(File.join(@cookbook_root, 'README.rdoc'))
- @cookbook[:metadata_filenames] = Array(File.join(@cookbook_root, 'metadata.json'))
-
- @cookbook_version = Chef::CookbookVersion.new('cookbook2', @cookbook_root)
- @cookbook_version.attribute_filenames = @cookbook[:attribute_filenames]
- @cookbook_version.definition_filenames = @cookbook[:definition_filenames]
- @cookbook_version.recipe_filenames = @cookbook[:recipe_filenames]
- @cookbook_version.template_filenames = @cookbook[:template_filenames]
- @cookbook_version.file_filenames = @cookbook[:file_filenames]
- @cookbook_version.library_filenames = @cookbook[:library_filenames]
- @cookbook_version.resource_filenames = @cookbook[:resource_filenames]
- @cookbook_version.provider_filenames = @cookbook[:provider_filenames]
- @cookbook_version.root_filenames = @cookbook[:root_filenames]
- @cookbook_version.metadata_filenames = @cookbook[:metadata_filenames]
+ describe "with a cookbook directory named cookbook2 that has unscoped files" do
+
+ let(:cookbook_paths_by_type) do
+ {
+ # Dunno if the paths here are representitive of what is set by CookbookLoader...
+ all_files: Dir[File.join(cookbook_root, "**", "*.rb")],
+ attribute_filenames: Dir[File.join(cookbook_root, "attributes", "**", "*.rb")],
+ definition_filenames: Dir[File.join(cookbook_root, "definitions", "**", "*.rb")],
+ file_filenames: Dir[File.join(cookbook_root, "files", "**", "*.*")],
+ recipe_filenames: Dir[File.join(cookbook_root, "recipes", "**", "*.rb")],
+ template_filenames: Dir[File.join(cookbook_root, "templates", "**", "*.*")],
+ library_filenames: Dir[File.join(cookbook_root, "libraries", "**", "*.rb")],
+ resource_filenames: Dir[File.join(cookbook_root, "resources", "**", "*.rb")],
+ provider_filenames: Dir[File.join(cookbook_root, "providers", "**", "*.rb")],
+ root_filenames: Array(File.join(cookbook_root, "README.rdoc")),
+ metadata_filenames: Array(File.join(cookbook_root, "metadata.json")),
+ }
+ end
+
+ let(:cookbook_root) { File.join(CHEF_SPEC_DATA, "cb_version_cookbooks", "cookbook2") }
+
+ let(:cookbook_version) do
+ Chef::CookbookVersion.new("cookbook2", cookbook_root).tap do |c|
+ c.attribute_filenames = cookbook_paths_by_type[:attribute_filenames]
+ c.definition_filenames = cookbook_paths_by_type[:definition_filenames]
+ c.recipe_filenames = cookbook_paths_by_type[:recipe_filenames]
+ c.template_filenames = cookbook_paths_by_type[:template_filenames]
+ c.file_filenames = cookbook_paths_by_type[:file_filenames]
+ c.library_filenames = cookbook_paths_by_type[:library_filenames]
+ c.resource_filenames = cookbook_paths_by_type[:resource_filenames]
+ c.provider_filenames = cookbook_paths_by_type[:provider_filenames]
+ c.root_filenames = cookbook_paths_by_type[:root_filenames]
+ c.metadata_filenames = cookbook_paths_by_type[:metadata_filenames]
+ end
+ end
- # Used to test file-specificity related file lookups
- @node = Chef::Node.new
- @node.set[:platform] = "ubuntu"
- @node.set[:platform_version] = "13.04"
- @node.name("testing")
+ # Used to test file-specificity related file lookups
+ let(:node) do
+ Chef::Node.new.tap do |n|
+ n.normal[:platform] = "ubuntu"
+ n.normal[:platform_version] = "13.04"
+ n.name("testing")
+ end
end
it "should see a template" do
- expect(@cookbook_version).to have_template_for_node(@node, "test.erb")
+ expect(cookbook_version).to have_template_for_node(node, "test.erb")
end
it "should see a template using an array lookup" do
- expect(@cookbook_version).to have_template_for_node(@node, ["test.erb"])
+ expect(cookbook_version).to have_template_for_node(node, ["test.erb"])
end
it "should see a template using an array lookup with non-existent elements" do
- expect(@cookbook_version).to have_template_for_node(@node, ["missing.txt", "test.erb"])
+ expect(cookbook_version).to have_template_for_node(node, ["missing.txt", "test.erb"])
end
it "should see a file" do
- expect(@cookbook_version).to have_cookbook_file_for_node(@node, "test.txt")
+ expect(cookbook_version).to have_cookbook_file_for_node(node, "test.txt")
end
it "should see a file using an array lookup" do
- expect(@cookbook_version).to have_cookbook_file_for_node(@node, ["test.txt"])
+ expect(cookbook_version).to have_cookbook_file_for_node(node, ["test.txt"])
end
it "should see a file using an array lookup with non-existent elements" do
- expect(@cookbook_version).to have_cookbook_file_for_node(@node, ["missing.txt", "test.txt"])
+ expect(cookbook_version).to have_cookbook_file_for_node(node, ["missing.txt", "test.txt"])
end
it "should not see a non-existent template" do
- expect(@cookbook_version).not_to have_template_for_node(@node, "missing.erb")
+ expect(cookbook_version).not_to have_template_for_node(node, "missing.erb")
end
it "should not see a non-existent template using an array lookup" do
- expect(@cookbook_version).not_to have_template_for_node(@node, ["missing.erb"])
+ expect(cookbook_version).not_to have_template_for_node(node, ["missing.erb"])
end
it "should not see a non-existent file" do
- expect(@cookbook_version).not_to have_cookbook_file_for_node(@node, "missing.txt")
+ expect(cookbook_version).not_to have_cookbook_file_for_node(node, "missing.txt")
end
it "should not see a non-existent file using an array lookup" do
- expect(@cookbook_version).not_to have_cookbook_file_for_node(@node, ["missing.txt"])
+ expect(cookbook_version).not_to have_cookbook_file_for_node(node, ["missing.txt"])
end
end
-
describe "<=>" do
it "should sort based on the version number" do
@@ -249,11 +266,11 @@ describe Chef::CookbookVersion do
["1.2", "1.3.0"],
["1.2", "1.3"],
["1.2", "2.1.1"],
- ["1.2", "2.1"]
+ ["1.2", "2.1"],
]
examples.each do |smaller, larger|
- sm = Chef::CookbookVersion.new("foo", '/tmp/blah')
- lg = Chef::CookbookVersion.new("foo", '/tmp/blah')
+ sm = Chef::CookbookVersion.new("foo", "/tmp/blah")
+ lg = Chef::CookbookVersion.new("foo", "/tmp/blah")
sm.version = smaller
lg.version = larger
expect(sm).to be < lg
@@ -263,31 +280,30 @@ describe Chef::CookbookVersion do
end
it "should equate versions 1.2 and 1.2.0" do
- a = Chef::CookbookVersion.new("foo", '/tmp/blah')
- b = Chef::CookbookVersion.new("foo", '/tmp/blah')
+ a = Chef::CookbookVersion.new("foo", "/tmp/blah")
+ b = Chef::CookbookVersion.new("foo", "/tmp/blah")
a.version = "1.2"
b.version = "1.2.0"
expect(a).to eq(b)
end
-
it "should not allow you to sort cookbooks with different names" do
- apt = Chef::CookbookVersion.new "apt", '/tmp/blah'
+ apt = Chef::CookbookVersion.new "apt", "/tmp/blah"
apt.version = "1.0"
- god = Chef::CookbookVersion.new "god", '/tmp/blah'
+ god = Chef::CookbookVersion.new "god", "/tmp/blah"
god.version = "2.0"
- expect {apt <=> god}.to raise_error(Chef::Exceptions::CookbookVersionNameMismatch)
+ expect { apt <=> god }.to raise_error(Chef::Exceptions::CookbookVersionNameMismatch)
end
end
describe "when you set a version" do
- before do
- @cbv = Chef::CookbookVersion.new("version validation", '/tmp/blah')
- end
+
+ subject(:cbv) { Chef::CookbookVersion.new("version validation", "/tmp/blah") }
+
it "should accept valid cookbook versions" do
- good_versions = %w(1.2 1.2.3 1000.80.50000 0.300.25)
+ good_versions = %w{1.2 1.2.3 1000.80.50000 0.300.25}
good_versions.each do |v|
- @cbv.version = v
+ cbv.version = v
end
end
@@ -296,7 +312,7 @@ describe Chef::CookbookVersion do
"1 2 3", "1-2-3", "1_2_3", "1.2_3", "1.2-3"]
the_error = Chef::Exceptions::InvalidCookbookVersion
bad_versions.each do |v|
- expect {@cbv.version = v}.to raise_error(the_error)
+ expect { cbv.version = v }.to raise_error(the_error)
end
end
@@ -304,7 +320,7 @@ describe Chef::CookbookVersion do
describe "when deprecation warnings are errors" do
- subject(:cbv) { Chef::CookbookVersion.new("version validation", '/tmp/blah') }
+ subject(:cbv) { Chef::CookbookVersion.new("version validation", "/tmp/blah") }
it "errors on #status and #status=" do
expect { cbv.status = :wat }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
@@ -315,7 +331,7 @@ describe Chef::CookbookVersion do
describe "deprecated features" do
- subject(:cbv) { Chef::CookbookVersion.new("tatft", '/tmp/blah').tap { |c| c.version = "1.2.3" } }
+ subject(:cbv) { Chef::CookbookVersion.new("tatft", "/tmp/blah").tap { |c| c.version = "1.2.3" } }
before do
Chef::Config[:treat_deprecation_warnings_as_errors] = false
@@ -335,9 +351,8 @@ describe Chef::CookbookVersion do
expect(cbv.status).to eq(:ready)
end
-
include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
- let(:jsonable) { Chef::CookbookVersion.new("tatft", '/tmp/blah') }
+ let(:jsonable) { Chef::CookbookVersion.new("tatft", "/tmp/blah") }
end
end
diff --git a/spec/unit/daemon_spec.rb b/spec/unit/daemon_spec.rb
index e020576a23..ae3d626113 100644
--- a/spec/unit/daemon_spec.rb
+++ b/spec/unit/daemon_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@junglist.gen.nz>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,14 +15,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Daemon do
before do
if windows?
mock_struct = #Struct::Passwd.new(nil, nil, 111, 111)
- mock_struct = OpenStruct.new(:uid => 2342, :gid => 2342)
+ mock_struct = OpenStruct.new(:uid => 2342, :gid => 2342)
allow(Etc).to receive(:getpwnam).and_return mock_struct
allow(Etc).to receive(:getgrnam).and_return mock_struct
# mock unimplemented methods
@@ -74,7 +74,7 @@ describe Chef::Daemon do
before do
allow(Chef::Application).to receive(:fatal!).and_return(true)
- Chef::Config[:user] = 'aj'
+ Chef::Config[:user] = "aj"
allow(Dir).to receive(:chdir)
end
@@ -86,7 +86,7 @@ describe Chef::Daemon do
describe "when the user and group options are supplied" do
before do
- Chef::Config[:group] = 'staff'
+ Chef::Config[:group] = "staff"
end
it "should log an appropriate info message" do
diff --git a/spec/unit/data_bag_item_spec.rb b/spec/unit/data_bag_item_spec.rb
index 497817ecf1..e83f0ca0ec 100644
--- a/spec/unit/data_bag_item_spec.rb
+++ b/spec/unit/data_bag_item_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/data_bag_item'
+require "spec_helper"
+require "chef/data_bag_item"
describe Chef::DataBagItem do
let(:data_bag_item) { Chef::DataBagItem.new }
@@ -91,12 +91,12 @@ describe Chef::DataBagItem do
end
describe "object_name" do
- let(:data_bag_item) {
+ let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
data_bag_item.data_bag("dreams")
data_bag_item.raw_data = { "id" => "the_beatdown" }
data_bag_item
- }
+ end
it "should return an object name based on the bag name and the raw_data id" do
expect(data_bag_item.object_name).to eq("data_bag_item_dreams_the_beatdown")
@@ -109,12 +109,30 @@ describe Chef::DataBagItem do
end
end
+ describe "class method name" do
+ let(:data_bag_item) do
+ data_bag_item = Chef::DataBagItem.new
+ data_bag_item.data_bag("dreams")
+ data_bag_item.raw_data = { "id" => "the_beatdown", "name" => "Bruce" }
+ data_bag_item
+ end
+
+ it "should return the object name" do
+ expect(data_bag_item.name).to eq(data_bag_item.object_name)
+ end
+
+ it "should be distinct from raw_data 'name' key" do
+ expect(data_bag_item["name"]).to eq("Bruce")
+ expect(data_bag_item["name"]).not_to eq(data_bag_item.object_name)
+ end
+ end
+
describe "when used like a Hash" do
- let(:data_bag_item) {
+ let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
data_bag_item.raw_data = { "id" => "journey", "trials" => "been through" }
data_bag_item
- }
+ end
it "responds to keys" do
expect(data_bag_item.keys).to include("id")
@@ -138,13 +156,45 @@ describe Chef::DataBagItem do
end
end
+ describe "from_hash" do
+ context "when hash contains raw_data" do
+ let(:data_bag_item) do
+ Chef::DataBagItem.from_hash({ "raw_data" => { "id" => "whoa", "name" => "Bruce", "i_know" => "kung_fu" } })
+ end
+
+ it "should have the id key set" do
+ expect(data_bag_item["id"]).to eq("whoa")
+ end
+
+ it "should have the name key set" do
+ expect(data_bag_item["name"]).to eq("Bruce")
+ end
+ end
+
+ context "when hash does not contain raw_data" do
+ let(:data_bag_item) do
+ Chef::DataBagItem.from_hash({ "id" => "whoa", "name" => "Bruce", "i_know" => "kung_fu" })
+ end
+
+ it "should have the id key set" do
+ expect(data_bag_item["id"]).to eq("whoa")
+ end
+
+ it "should have the name key set" do
+ expect(data_bag_item["name"]).to eq("Bruce")
+ end
+ end
+ end
+
describe "to_hash" do
- let(:data_bag_item) {
+ let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
data_bag_item.data_bag("still_lost")
- data_bag_item.raw_data = { "id" => "whoa", "i_know" => "kung_fu" }
+ data_bag_item.raw_data = { "id" => "whoa", "name" => "Bruce", "i_know" => "kung_fu" }
data_bag_item
- }
+ end
+
+ let!(:original_data_bag_keys) { data_bag_item.keys }
let(:to_hash) { data_bag_item.to_hash }
@@ -154,6 +204,7 @@ describe Chef::DataBagItem do
it "should have the raw_data keys as top level keys" do
expect(to_hash["id"]).to eq("whoa")
+ expect(to_hash["name"]).to eq("Bruce")
expect(to_hash["i_know"]).to eq("kung_fu")
end
@@ -164,18 +215,22 @@ describe Chef::DataBagItem do
it "should have the data_bag set" do
expect(to_hash["data_bag"]).to eq("still_lost")
end
+
+ it "should not mutate the data_bag_item" do
+ data_bag_item.to_hash
+ expect(data_bag_item.keys).to eq(original_data_bag_keys)
+ end
end
describe "when deserializing from JSON" do
- let(:data_bag_item) {
+ let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
- data_bag_item.data_bag('mars_volta')
- data_bag_item.raw_data = { "id" => "octahedron", "snooze" => { "finally" => :world_will } }
+ data_bag_item.data_bag("mars_volta")
+ data_bag_item.raw_data = { "id" => "octahedron", "name" => "Bruce", "snooze" => { "finally" => :world_will } }
data_bag_item
- }
-
- let(:deserial) { Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(data_bag_item)) }
+ end
+ let(:deserial) { Chef::DataBagItem.from_hash(Chef::JSONCompat.parse(Chef::JSONCompat.to_json(data_bag_item))) }
it "should deserialize to a Chef::DataBagItem object" do
expect(deserial).to be_a_kind_of(Chef::DataBagItem)
@@ -189,6 +244,10 @@ describe Chef::DataBagItem do
expect(deserial["id"]).to eq("octahedron")
end
+ it "should have a matching 'name' key" do
+ expect(deserial["name"]).to eq("Bruce")
+ end
+
it "should have a matching 'snooze' key" do
expect(deserial["snooze"]).to eq({ "finally" => "world_will" })
end
@@ -200,12 +259,12 @@ describe Chef::DataBagItem do
describe "when converting to a string" do
it "converts to a string in the form data_bag_item[ID]" do
- data_bag_item['id'] = "heart of darkness"
- expect(data_bag_item.to_s).to eq('data_bag_item[heart of darkness]')
+ data_bag_item["id"] = "heart of darkness"
+ expect(data_bag_item.to_s).to eq("data_bag_item[heart of darkness]")
end
it "inspects as data_bag_item[BAG, ID, RAW_DATA]" do
- raw_data = {"id" => "heart_of_darkness", "author" => "Conrad"}
+ raw_data = { "id" => "heart_of_darkness", "author" => "Conrad" }
data_bag_item.raw_data = raw_data
data_bag_item.data_bag("books")
@@ -214,29 +273,29 @@ describe Chef::DataBagItem do
end
describe "save" do
- let(:server) { instance_double(Chef::REST) }
+ let(:server) { instance_double(Chef::ServerAPI) }
- let(:data_bag_item) {
+ let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
- data_bag_item['id'] = "heart of darkness"
- data_bag_item.raw_data = {"id" => "heart_of_darkness", "author" => "Conrad"}
+ data_bag_item["id"] = "heart of darkness"
+ data_bag_item.raw_data = { "id" => "heart_of_darkness", "author" => "Conrad" }
data_bag_item.data_bag("books")
data_bag_item
- }
+ end
before do
- expect(Chef::REST).to receive(:new).and_return(server)
+ expect(Chef::ServerAPI).to receive(:new).and_return(server)
end
it "should update the item when it already exists" do
- expect(server).to receive(:put_rest).with("data/books/heart_of_darkness", data_bag_item)
+ expect(server).to receive(:put).with("data/books/heart_of_darkness", data_bag_item)
data_bag_item.save
end
it "should create if the item is not found" do
exception = double("404 error", :code => "404")
- expect(server).to receive(:put_rest).and_raise(Net::HTTPServerException.new("foo", exception))
- expect(server).to receive(:post_rest).with("data/books", data_bag_item)
+ expect(server).to receive(:put).and_raise(Net::HTTPServerException.new("foo", exception))
+ expect(server).to receive(:post).with("data/books", data_bag_item)
data_bag_item.save
end
@@ -249,8 +308,8 @@ describe Chef::DataBagItem do
end
it "should not save" do
- expect(server).not_to receive(:put_rest)
- expect(server).not_to receive(:post_rest)
+ expect(server).not_to receive(:put)
+ expect(server).not_to receive(:post)
data_bag_item.data_bag("books")
data_bag_item.save
end
@@ -259,18 +318,18 @@ describe Chef::DataBagItem do
end
describe "destroy" do
- let(:server) { instance_double(Chef::REST) }
+ let(:server) { instance_double(Chef::ServerAPI) }
- let(:data_bag_item) {
+ let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
- data_bag_item.data_bag('a_baggy_bag')
+ data_bag_item.data_bag("a_baggy_bag")
data_bag_item.raw_data = { "id" => "some_id" }
data_bag_item
- }
+ end
it "should set default parameters" do
- expect(Chef::REST).to receive(:new).and_return(server)
- expect(server).to receive(:delete_rest).with("data/a_baggy_bag/data_bag_item_a_baggy_bag_some_id")
+ expect(Chef::ServerAPI).to receive(:new).and_return(server)
+ expect(server).to receive(:delete).with("data/a_baggy_bag/data_bag_item_a_baggy_bag_some_id")
data_bag_item.destroy
end
@@ -278,26 +337,26 @@ describe Chef::DataBagItem do
describe "when loading" do
before do
- data_bag_item.raw_data = {"id" => "charlie", "shell" => "zsh", "ssh_keys" => %w{key1 key2}}
+ data_bag_item.raw_data = { "id" => "charlie", "shell" => "zsh", "ssh_keys" => %w{key1 key2} }
data_bag_item.data_bag("users")
end
describe "from an API call" do
- let(:http_client) { double("Chef::REST") }
+ let(:http_client) { double("Chef::ServerAPI") }
before do
- allow(Chef::REST).to receive(:new).and_return(http_client)
+ allow(Chef::ServerAPI).to receive(:new).and_return(http_client)
end
it "converts raw data to a data bag item" do
- expect(http_client).to receive(:get_rest).with("data/users/charlie").and_return(data_bag_item.to_hash)
+ expect(http_client).to receive(:get).with("data/users/charlie").and_return(data_bag_item.to_hash)
item = Chef::DataBagItem.load(:users, "charlie")
expect(item).to be_a_kind_of(Chef::DataBagItem)
expect(item).to eq(data_bag_item)
end
it "does not convert when a DataBagItem is returned from the API call" do
- expect(http_client).to receive(:get_rest).with("data/users/charlie").and_return(data_bag_item)
+ expect(http_client).to receive(:get).with("data/users/charlie").and_return(data_bag_item)
item = Chef::DataBagItem.load(:users, "charlie")
expect(item).to be_a_kind_of(Chef::DataBagItem)
expect(item).to equal(data_bag_item)
@@ -306,19 +365,24 @@ describe Chef::DataBagItem do
describe "in solo mode" do
before do
- Chef::Config[:solo] = true
+ Chef::Config[:solo_legacy_mode] = true
end
after do
- Chef::Config[:solo] = false
+ Chef::Config[:solo_legacy_mode] = false
end
it "converts the raw data to a data bag item" do
- expect(Chef::DataBag).to receive(:load).with('users').and_return({'charlie' => data_bag_item.to_hash})
- item = Chef::DataBagItem.load('users', 'charlie')
+ expect(Chef::DataBag).to receive(:load).with("users").and_return({ "charlie" => data_bag_item.to_hash })
+ item = Chef::DataBagItem.load("users", "charlie")
expect(item).to be_a_kind_of(Chef::DataBagItem)
expect(item).to eq(data_bag_item)
end
+
+ it "raises an exception for unknown items" do
+ expect(Chef::DataBag).to receive(:load).with("users").and_return({ "charlie" => data_bag_item.to_hash })
+ expect { Chef::DataBagItem.load("users", "wonka") }.to raise_error Chef::Exceptions::InvalidDataBagItemID
+ end
end
end
end
diff --git a/spec/unit/data_bag_spec.rb b/spec/unit/data_bag_spec.rb
index 13b835d120..cadd60936e 100644
--- a/spec/unit/data_bag_spec.rb
+++ b/spec/unit/data_bag_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/data_bag'
+require "spec_helper"
+require "chef/data_bag"
describe Chef::DataBag do
before(:each) do
@@ -58,8 +58,8 @@ describe Chef::DataBag do
describe "deserialize" do
before(:each) do
- @data_bag.name('mars_volta')
- @deserial = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@data_bag))
+ @data_bag.name("mars_volta")
+ @deserial = Chef::DataBag.from_hash(Chef::JSONCompat.parse(Chef::JSONCompat.to_json(@data_bag)))
end
it "should deserialize to a Chef::DataBag object" do
@@ -82,19 +82,19 @@ describe Chef::DataBag do
describe "when saving" do
before do
- @data_bag.name('piggly_wiggly')
- @rest = double("Chef::REST")
- allow(Chef::REST).to receive(:new).and_return(@rest)
+ @data_bag.name("piggly_wiggly")
+ @rest = double("Chef::ServerAPI")
+ allow(Chef::ServerAPI).to receive(:new).and_return(@rest)
end
it "should silently proceed when the data bag already exists" do
exception = double("409 error", :code => "409")
- expect(@rest).to receive(:post_rest).and_raise(Net::HTTPServerException.new("foo", exception))
+ expect(@rest).to receive(:post).and_raise(Net::HTTPServerException.new("foo", exception))
@data_bag.save
end
it "should create the data bag" do
- expect(@rest).to receive(:post_rest).with("data", @data_bag)
+ expect(@rest).to receive(:post).with("data", @data_bag)
@data_bag.save
end
@@ -106,7 +106,7 @@ describe Chef::DataBag do
Chef::Config[:why_run] = false
end
it "should not save" do
- expect(@rest).not_to receive(:post_rest)
+ expect(@rest).not_to receive(:post)
@data_bag.save
end
end
@@ -115,21 +115,21 @@ describe Chef::DataBag do
describe "when loading" do
describe "from an API call" do
before do
- Chef::Config[:chef_server_url] = 'https://myserver.example.com'
- @http_client = double('Chef::REST')
+ Chef::Config[:chef_server_url] = "https://myserver.example.com"
+ @http_client = double("Chef::ServerAPI")
end
it "should get the data bag from the server" do
- expect(Chef::REST).to receive(:new).with('https://myserver.example.com').and_return(@http_client)
- expect(@http_client).to receive(:get_rest).with('data/foo')
- Chef::DataBag.load('foo')
+ expect(Chef::ServerAPI).to receive(:new).with("https://myserver.example.com").and_return(@http_client)
+ expect(@http_client).to receive(:get).with("data/foo")
+ Chef::DataBag.load("foo")
end
it "should return the data bag" do
- allow(Chef::REST).to receive(:new).and_return(@http_client)
- expect(@http_client).to receive(:get_rest).with('data/foo').and_return({'bar' => 'https://myserver.example.com/data/foo/bar'})
- data_bag = Chef::DataBag.load('foo')
- expect(data_bag).to eq({'bar' => 'https://myserver.example.com/data/foo/bar'})
+ allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
+ expect(@http_client).to receive(:get).with("data/foo").and_return({ "bar" => "https://myserver.example.com/data/foo/bar" })
+ data_bag = Chef::DataBag.load("foo")
+ expect(data_bag).to eq({ "bar" => "https://myserver.example.com/data/foo/bar" })
end
end
@@ -138,18 +138,18 @@ describe Chef::DataBag do
end
def dir_glob_stub(path, returns = [])
- expect(Dir).to receive(:glob).with(File.join(path, 'foo/*.json')).and_return(returns)
+ expect(Dir).to receive(:glob).with(File.join(path, "foo/*.json")).and_return(returns)
end
shared_examples_for "data bag in solo mode" do |data_bag_path|
before do
- Chef::Config[:solo] = true
+ Chef::Config[:solo_legacy_mode] = true
Chef::Config[:data_bag_path] = data_bag_path
@paths = Array(data_bag_path)
end
after do
- Chef::Config[:solo] = false
+ Chef::Config[:solo_legacy_mode] = false
end
it "should get the data bag from the data_bag_path" do
@@ -157,7 +157,7 @@ describe Chef::DataBag do
file_dir_stub(path)
dir_glob_stub(path)
end
- Chef::DataBag.load('foo')
+ Chef::DataBag.load("foo")
end
it "should get the data bag from the data_bag_path by symbolic name" do
@@ -172,57 +172,57 @@ describe Chef::DataBag do
@paths.each do |path|
file_dir_stub(path)
if path == @paths.first
- dir_glob_stub(path, [File.join(path, 'foo/bar.json'), File.join(path, 'foo/baz.json')])
+ dir_glob_stub(path, [File.join(path, "foo/bar.json"), File.join(path, "foo/baz.json")])
else
dir_glob_stub(path)
end
end
- expect(IO).to receive(:read).with(File.join(@paths.first, 'foo/bar.json')).and_return('{"id": "bar", "name": "Bob Bar" }')
- expect(IO).to receive(:read).with(File.join(@paths.first, 'foo/baz.json')).and_return('{"id": "baz", "name": "John Baz" }')
- data_bag = Chef::DataBag.load('foo')
- expect(data_bag).to eq({ 'bar' => { 'id' => 'bar', 'name' => 'Bob Bar' }, 'baz' => { 'id' => 'baz', 'name' => 'John Baz' }})
+ expect(IO).to receive(:read).with(File.join(@paths.first, "foo/bar.json")).and_return('{"id": "bar", "name": "Bob Bar" }')
+ expect(IO).to receive(:read).with(File.join(@paths.first, "foo/baz.json")).and_return('{"id": "baz", "name": "John Baz" }')
+ data_bag = Chef::DataBag.load("foo")
+ expect(data_bag).to eq({ "bar" => { "id" => "bar", "name" => "Bob Bar" }, "baz" => { "id" => "baz", "name" => "John Baz" } })
end
it "should raise if data bag has items with similar names but different content" do
@paths.each do |path|
file_dir_stub(path)
item_with_different_content = "{\"id\": \"bar\", \"name\": \"Bob Bar\", \"path\": \"#{path}\"}"
- expect(IO).to receive(:read).with(File.join(path, 'foo/bar.json')).and_return(item_with_different_content)
+ expect(IO).to receive(:read).with(File.join(path, "foo/bar.json")).and_return(item_with_different_content)
if data_bag_path.is_a?(String)
- dir_glob_stub(path, [File.join(path, 'foo/bar.json'), File.join(path, 'foo/baz.json')])
+ dir_glob_stub(path, [File.join(path, "foo/bar.json"), File.join(path, "foo/baz.json")])
item_2_with_different_content = '{"id": "bar", "name": "John Baz"}'
- expect(IO).to receive(:read).with(File.join(path, 'foo/baz.json')).and_return(item_2_with_different_content)
+ expect(IO).to receive(:read).with(File.join(path, "foo/baz.json")).and_return(item_2_with_different_content)
else
- dir_glob_stub(path, [File.join(path, 'foo/bar.json')])
+ dir_glob_stub(path, [File.join(path, "foo/bar.json")])
end
end
- expect { Chef::DataBag.load('foo') }.to raise_error(Chef::Exceptions::DuplicateDataBagItem)
+ expect { Chef::DataBag.load("foo") }.to raise_error(Chef::Exceptions::DuplicateDataBagItem)
end
it "should return data bag if it has items with similar names and the same content" do
@paths.each do |path|
file_dir_stub(path)
- dir_glob_stub(path, [File.join(path, 'foo/bar.json'), File.join(path, 'foo/baz.json')])
+ dir_glob_stub(path, [File.join(path, "foo/bar.json"), File.join(path, "foo/baz.json")])
item_with_same_content = '{"id": "bar", "name": "Bob Bar"}'
- expect(IO).to receive(:read).with(File.join(path, 'foo/bar.json')).and_return(item_with_same_content)
- expect(IO).to receive(:read).with(File.join(path, 'foo/baz.json')).and_return(item_with_same_content)
+ expect(IO).to receive(:read).with(File.join(path, "foo/bar.json")).and_return(item_with_same_content)
+ expect(IO).to receive(:read).with(File.join(path, "foo/baz.json")).and_return(item_with_same_content)
end
- data_bag = Chef::DataBag.load('foo')
- test_data_bag = { 'bar' => { 'id' => 'bar', 'name' => 'Bob Bar'} }
+ data_bag = Chef::DataBag.load("foo")
+ test_data_bag = { "bar" => { "id" => "bar", "name" => "Bob Bar" } }
expect(data_bag).to eq(test_data_bag)
end
it "should merge data bag items if there are no conflicts" do
@paths.each_with_index do |path, index|
file_dir_stub(path)
- dir_glob_stub(path, [File.join(path, 'foo/bar.json'), File.join(path, 'foo/baz.json')])
+ dir_glob_stub(path, [File.join(path, "foo/bar.json"), File.join(path, "foo/baz.json")])
test_item_with_same_content = '{"id": "bar", "name": "Bob Bar"}'
- expect(IO).to receive(:read).with(File.join(path, 'foo/bar.json')).and_return(test_item_with_same_content)
+ expect(IO).to receive(:read).with(File.join(path, "foo/bar.json")).and_return(test_item_with_same_content)
test_uniq_item = "{\"id\": \"baz_#{index}\", \"name\": \"John Baz\", \"path\": \"#{path}\"}"
- expect(IO).to receive(:read).with(File.join(path, 'foo/baz.json')).and_return(test_uniq_item)
+ expect(IO).to receive(:read).with(File.join(path, "foo/baz.json")).and_return(test_uniq_item)
end
- data_bag = Chef::DataBag.load('foo')
- test_data_bag = { 'bar' => { 'id' => 'bar', 'name' => 'Bob Bar'} }
+ data_bag = Chef::DataBag.load("foo")
+ test_data_bag = { "bar" => { "id" => "bar", "name" => "Bob Bar" } }
@paths.each_with_index do |path, index|
test_data_bag["baz_#{index}"] = { "id" => "baz_#{index}", "name" => "John Baz", "path" => path }
end
@@ -232,18 +232,18 @@ describe Chef::DataBag do
it "should return the data bag list" do
@paths.each do |path|
file_dir_stub(path)
- expect(Dir).to receive(:glob).and_return([File.join(path, 'foo'), File.join(path, 'bar')])
+ expect(Dir).to receive(:glob).and_return([File.join(path, "foo"), File.join(path, "bar")])
end
data_bag_list = Chef::DataBag.list
- expect(data_bag_list).to eq({ 'bar' => 'bar', 'foo' => 'foo' })
+ expect(data_bag_list).to eq({ "bar" => "bar", "foo" => "foo" })
end
- it 'should raise an error if the configured data_bag_path is invalid' do
+ it "should raise an error if the configured data_bag_path is invalid" do
file_dir_stub(@paths.first, false)
- expect {
- Chef::DataBag.load('foo')
- }.to raise_error Chef::Exceptions::InvalidDataBagPath, "Data bag path '/var/chef/data_bags' is invalid"
+ expect do
+ Chef::DataBag.load("foo")
+ end.to raise_error Chef::Exceptions::InvalidDataBagPath, "Data bag path '/var/chef/data_bags' is invalid"
end
end
diff --git a/spec/unit/data_collector/messages/helpers_spec.rb b/spec/unit/data_collector/messages/helpers_spec.rb
new file mode 100644
index 0000000000..a241bda699
--- /dev/null
+++ b/spec/unit/data_collector/messages/helpers_spec.rb
@@ -0,0 +1,193 @@
+#
+# Author:: Adam Leff (<adamleff@chef.io)
+#
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/data_collector/messages/helpers"
+
+class TestMessage
+ extend Chef::DataCollector::Messages::Helpers
+end
+
+describe Chef::DataCollector::Messages::Helpers do
+ describe "#organization" do
+ context "when the run is a solo run" do
+ it "returns the data collector organization" do
+ allow(TestMessage).to receive(:solo_run?).and_return(true)
+ expect(TestMessage).to receive(:data_collector_organization).and_return("org1")
+ expect(TestMessage.organization).to eq("org1")
+ end
+ end
+
+ context "when the run is not a solo run" do
+ it "returns the data collector organization" do
+ allow(TestMessage).to receive(:solo_run?).and_return(false)
+ expect(TestMessage).to receive(:chef_server_organization).and_return("org2")
+ expect(TestMessage.organization).to eq("org2")
+ end
+ end
+ end
+
+ describe "#data_collector_organization" do
+ context "when the org is specified in the config" do
+ it "returns the org from the config" do
+ Chef::Config[:data_collector][:organization] = "org1"
+ expect(TestMessage.data_collector_organization).to eq("org1")
+ end
+ end
+
+ context "when the org is not specified in the config" do
+ it "returns the default chef_solo org" do
+ expect(TestMessage.data_collector_organization).to eq("chef_solo")
+ end
+ end
+ end
+
+ describe "#chef_server_organization" do
+ context "when the URL is properly formatted" do
+ it "returns the org from the parsed URL" do
+ Chef::Config[:chef_server_url] = "http://mycompany.com/organizations/myorg"
+ expect(TestMessage.chef_server_organization).to eq("myorg")
+ end
+ end
+
+ context "when the URL is not properly formatted" do
+ it "returns unknown_organization" do
+ Chef::Config[:chef_server_url] = "http://mycompany.com/what/url/is/this"
+ expect(TestMessage.chef_server_organization).to eq("unknown_organization")
+ end
+ end
+
+ context "when the organization in the URL contains hyphens" do
+ it "returns the full org name" do
+ Chef::Config[:chef_server_url] = "http://mycompany.com/organizations/myorg-test"
+ expect(TestMessage.chef_server_organization).to eq("myorg-test")
+ end
+ end
+ end
+
+ describe "#collector_source" do
+ context "when the run is a solo run" do
+ it "returns chef_solo" do
+ allow(TestMessage).to receive(:solo_run?).and_return(true)
+ expect(TestMessage.collector_source).to eq("chef_solo")
+ end
+ end
+
+ context "when the run is not a solo run" do
+ it "returns chef_client" do
+ allow(TestMessage).to receive(:solo_run?).and_return(false)
+ expect(TestMessage.collector_source).to eq("chef_client")
+ end
+ end
+ end
+
+ describe "#solo_run?" do
+ context "when :solo is set in Chef::Config" do
+ it "returns true" do
+ Chef::Config[:solo] = true
+ Chef::Config[:local_mode] = nil
+ expect(TestMessage.solo_run?).to be_truthy
+ end
+ end
+
+ context "when :local_mode is set in Chef::Config" do
+ it "returns true" do
+ Chef::Config[:solo] = nil
+ Chef::Config[:local_mode] = true
+ expect(TestMessage.solo_run?).to be_truthy
+ end
+ end
+
+ context "when neither :solo or :local_mode is set in Chef::Config" do
+ it "returns false" do
+ Chef::Config[:solo] = nil
+ Chef::Config[:local_mode] = nil
+ expect(TestMessage.solo_run?).to be_falsey
+ end
+ end
+ end
+
+ describe "#node_uuid" do
+ context "when the node UUID can be read" do
+ it "returns the read-in node UUID" do
+ allow(TestMessage).to receive(:read_node_uuid).and_return("read_uuid")
+ expect(TestMessage.node_uuid).to eq("read_uuid")
+ end
+ end
+
+ context "when the node UUID cannot be read" do
+ it "generated a new node UUID" do
+ allow(TestMessage).to receive(:read_node_uuid).and_return(nil)
+ allow(TestMessage).to receive(:generate_node_uuid).and_return("generated_uuid")
+ expect(TestMessage.node_uuid).to eq("generated_uuid")
+ end
+ end
+ end
+
+ describe "#generate_node_uuid" do
+ it "generates a new UUID, stores it, and returns it" do
+ expect(SecureRandom).to receive(:uuid).and_return("generated_uuid")
+ expect(TestMessage).to receive(:update_metadata).with("node_uuid", "generated_uuid")
+ expect(TestMessage.generate_node_uuid).to eq("generated_uuid")
+ end
+ end
+
+ describe "#read_node_uuid" do
+ it "reads the node UUID from metadata" do
+ expect(TestMessage).to receive(:metadata).and_return({ "node_uuid" => "read_uuid" })
+ expect(TestMessage.read_node_uuid).to eq("read_uuid")
+ end
+ end
+
+ describe "metadata" do
+ let(:metadata_filename) { "fake_metadata_file.json" }
+
+ before do
+ allow(TestMessage).to receive(:metadata_filename).and_return(metadata_filename)
+ end
+
+ context "when the metadata file exists" do
+ it "returns the contents of the metadata file" do
+ expect(Chef::FileCache).to receive(:load).with(metadata_filename).and_return('{"foo":"bar"}')
+ expect(TestMessage.metadata["foo"]).to eq("bar")
+ end
+ end
+
+ context "when the metadata file does not exist" do
+ it "returns an empty hash" do
+ expect(Chef::FileCache).to receive(:load).with(metadata_filename).and_raise(Chef::Exceptions::FileNotFound)
+ expect(TestMessage.metadata).to eq({})
+ end
+ end
+ end
+
+ describe "#update_metadata" do
+ it "updates the file" do
+ allow(TestMessage).to receive(:metadata_filename).and_return("fake_metadata_file.json")
+ allow(TestMessage).to receive(:metadata).and_return({ "key" => "current_value" })
+ expect(Chef::FileCache).to receive(:store).with(
+ "fake_metadata_file.json",
+ '{"key":"updated_value"}',
+ 0644
+ )
+
+ TestMessage.update_metadata("key", "updated_value")
+ end
+ end
+end
diff --git a/spec/unit/data_collector/messages_spec.rb b/spec/unit/data_collector/messages_spec.rb
new file mode 100644
index 0000000000..5c6ec8736c
--- /dev/null
+++ b/spec/unit/data_collector/messages_spec.rb
@@ -0,0 +1,192 @@
+#
+# Author:: Adam Leff (<adamleff@chef.io)
+#
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "ffi_yajl"
+require "chef/data_collector/messages/helpers"
+
+describe Chef::DataCollector::Messages do
+ describe "#run_start_message" do
+ let(:run_status) { Chef::RunStatus.new(Chef::Node.new, Chef::EventDispatch::Dispatcher.new) }
+ let(:required_fields) do
+ %w{
+ chef_server_fqdn
+ entity_uuid
+ id
+ message_version
+ message_type
+ node_name
+ organization_name
+ run_id
+ source
+ start_time
+ }
+ end
+ let(:optional_fields) { [] }
+
+ before do
+ allow(run_status).to receive(:start_time).and_return(Time.now)
+ end
+
+ it "is not missing any required fields" do
+ missing_fields = required_fields.select do |key|
+ !Chef::DataCollector::Messages.run_start_message(run_status).key?(key)
+ end
+
+ expect(missing_fields).to eq([])
+ end
+
+ it "does not have any extra fields" do
+ extra_fields = Chef::DataCollector::Messages.run_start_message(run_status).keys.select do |key|
+ !required_fields.include?(key) && !optional_fields.include?(key)
+ end
+
+ expect(extra_fields).to eq([])
+ end
+ end
+
+ describe "#run_end_message" do
+ let(:node) { Chef::Node.new }
+ let(:run_status) { Chef::RunStatus.new(node, Chef::EventDispatch::Dispatcher.new) }
+ let(:report1) { double("report1", report_data: { "status" => "updated" }) }
+ let(:report2) { double("report2", report_data: { "status" => "skipped" }) }
+ let(:reporter_data) do
+ {
+ run_status: run_status,
+ resources: [report1, report2],
+ }
+ end
+
+ before do
+ allow(run_status).to receive(:start_time).and_return(Time.now)
+ allow(run_status).to receive(:end_time).and_return(Time.now)
+ end
+
+ it "includes a valid node object in the payload" do
+ message = Chef::DataCollector::Messages.run_end_message(reporter_data)
+ expect(message["node"]).to be_an_instance_of(Chef::Node)
+ end
+
+ it "returns a sane JSON representation of the node object" do
+ node.chef_environment = "my_test_environment"
+ node.run_list.add("recipe[my_test_cookbook::default]")
+ message = FFI_Yajl::Parser.parse(Chef::DataCollector::Messages.run_end_message(reporter_data).to_json)
+
+ expect(message["node"]["chef_environment"]).to eq("my_test_environment")
+ expect(message["node"]["run_list"]).to eq(["recipe[my_test_cookbook::default]"])
+ end
+
+ context "when the run was successful" do
+ let(:required_fields) do
+ %w{
+ chef_server_fqdn
+ entity_uuid
+ id
+ end_time
+ expanded_run_list
+ message_type
+ message_version
+ node
+ node_name
+ organization_name
+ resources
+ run_id
+ run_list
+ source
+ start_time
+ status
+ total_resource_count
+ updated_resource_count
+ deprecations
+ }
+ end
+ let(:optional_fields) { %w{error} }
+
+ before do
+ allow(run_status).to receive(:exception).and_return(nil)
+ end
+
+ it "is not missing any required fields" do
+ missing_fields = required_fields.select do |key|
+ !Chef::DataCollector::Messages.run_end_message(reporter_data).key?(key)
+ end
+ expect(missing_fields).to eq([])
+ end
+
+ it "does not have any extra fields" do
+ extra_fields = Chef::DataCollector::Messages.run_end_message(reporter_data).keys.select do |key|
+ !required_fields.include?(key) && !optional_fields.include?(key)
+ end
+ expect(extra_fields).to eq([])
+ end
+
+ it "only includes updated resources in its count" do
+ message = Chef::DataCollector::Messages.run_end_message(reporter_data)
+ expect(message["total_resource_count"]).to eq(2)
+ expect(message["updated_resource_count"]).to eq(1)
+ end
+ end
+
+ context "when the run was not successful" do
+ let(:required_fields) do
+ %w{
+ chef_server_fqdn
+ entity_uuid
+ id
+ end_time
+ error
+ expanded_run_list
+ message_type
+ message_version
+ node
+ node_name
+ organization_name
+ resources
+ run_id
+ run_list
+ source
+ start_time
+ status
+ total_resource_count
+ updated_resource_count
+ deprecations
+ }
+ end
+ let(:optional_fields) { [] }
+
+ before do
+ allow(run_status).to receive(:exception).and_return(RuntimeError.new("an error happened"))
+ end
+
+ it "is not missing any required fields" do
+ missing_fields = required_fields.select do |key|
+ !Chef::DataCollector::Messages.run_end_message(reporter_data).key?(key)
+ end
+ expect(missing_fields).to eq([])
+ end
+
+ it "does not have any extra fields" do
+ extra_fields = Chef::DataCollector::Messages.run_end_message(reporter_data).keys.select do |key|
+ !required_fields.include?(key) && !optional_fields.include?(key)
+ end
+ expect(extra_fields).to eq([])
+ end
+ end
+ end
+end
diff --git a/spec/unit/data_collector_spec.rb b/spec/unit/data_collector_spec.rb
new file mode 100644
index 0000000000..f3f7ffb30f
--- /dev/null
+++ b/spec/unit/data_collector_spec.rb
@@ -0,0 +1,741 @@
+#
+# Author:: Adam Leff (<adamleff@chef.io)
+# Author:: Ryan Cragun (<ryan@chef.io>)
+#
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/data_collector"
+require "chef/resource_builder"
+
+describe Chef::DataCollector do
+
+ describe ".register_reporter?" do
+ context "when no data collector URL is configured" do
+ it "returns false" do
+ Chef::Config[:data_collector][:server_url] = nil
+ expect(Chef::DataCollector.register_reporter?).to be_falsey
+ end
+ end
+
+ context "when a data collector URL is configured" do
+ before do
+ Chef::Config[:data_collector][:server_url] = "http://data_collector"
+ end
+
+ context "when operating in why_run mode" do
+ it "returns false" do
+ Chef::Config[:why_run] = true
+ expect(Chef::DataCollector.register_reporter?).to be_falsey
+ end
+ end
+
+ context "when not operating in why_run mode" do
+
+ before do
+ Chef::Config[:why_run] = false
+ Chef::Config[:data_collector][:token] = token
+ end
+
+ context "when a token is configured" do
+
+ let(:token) { "supersecrettoken" }
+
+ context "when report is enabled for current mode" do
+ it "returns true" do
+ allow(Chef::DataCollector).to receive(:reporter_enabled_for_current_mode?).and_return(true)
+ expect(Chef::DataCollector.register_reporter?).to be_truthy
+ end
+ end
+
+ context "when report is disabled for current mode" do
+ it "returns false" do
+ allow(Chef::DataCollector).to receive(:reporter_enabled_for_current_mode?).and_return(false)
+ expect(Chef::DataCollector.register_reporter?).to be_falsey
+ end
+ end
+
+ end
+
+ # `Chef::Config[:data_collector][:server_url]` defaults to a URL
+ # relative to the `chef_server_url`, so we use configuration of the
+ # token to infer whether a solo/local mode user intends for data
+ # collection to be enabled.
+ context "when a token is not configured" do
+
+ let(:token) { nil }
+
+ context "when report is enabled for current mode" do
+
+ before do
+ allow(Chef::DataCollector).to receive(:reporter_enabled_for_current_mode?).and_return(true)
+ end
+
+ context "when the current mode is solo" do
+
+ before do
+ Chef::Config[:solo] = true
+ end
+
+ it "returns true" do
+ expect(Chef::DataCollector.register_reporter?).to be(true)
+ end
+
+ end
+
+ context "when the current mode is local mode" do
+
+ before do
+ Chef::Config[:local_mode] = true
+ end
+
+ it "returns false" do
+ expect(Chef::DataCollector.register_reporter?).to be(true)
+ end
+ end
+
+ context "when the current mode is client mode" do
+
+ before do
+ Chef::Config[:local_mode] = false
+ Chef::Config[:solo] = false
+ end
+
+ it "returns true" do
+ expect(Chef::DataCollector.register_reporter?).to be_truthy
+ end
+
+ end
+
+ end
+
+ context "when report is disabled for current mode" do
+ it "returns false" do
+ allow(Chef::DataCollector).to receive(:reporter_enabled_for_current_mode?).and_return(false)
+ expect(Chef::DataCollector.register_reporter?).to be_falsey
+ end
+ end
+
+ end
+
+ end
+ end
+ end
+
+ describe ".reporter_enabled_for_current_mode?" do
+ context "when running in solo mode" do
+ before do
+ Chef::Config[:solo] = true
+ Chef::Config[:local_mode] = false
+ end
+
+ context "when data_collector_mode is :solo" do
+ it "returns true" do
+ Chef::Config[:data_collector][:mode] = :solo
+ expect(Chef::DataCollector.reporter_enabled_for_current_mode?).to eq(true)
+ end
+ end
+
+ context "when data_collector_mode is :client" do
+ it "returns false" do
+ Chef::Config[:data_collector][:mode] = :client
+ expect(Chef::DataCollector.reporter_enabled_for_current_mode?).to eq(false)
+ end
+ end
+
+ context "when data_collector_mode is :both" do
+ it "returns true" do
+ Chef::Config[:data_collector][:mode] = :both
+ expect(Chef::DataCollector.reporter_enabled_for_current_mode?).to eq(true)
+ end
+ end
+ end
+
+ context "when running in local mode" do
+ before do
+ Chef::Config[:solo] = false
+ Chef::Config[:local_mode] = true
+ end
+
+ context "when data_collector_mode is :solo" do
+ it "returns true" do
+ Chef::Config[:data_collector][:mode] = :solo
+ expect(Chef::DataCollector.reporter_enabled_for_current_mode?).to eq(true)
+ end
+ end
+
+ context "when data_collector_mode is :client" do
+ it "returns false" do
+ Chef::Config[:data_collector][:mode] = :client
+ expect(Chef::DataCollector.reporter_enabled_for_current_mode?).to eq(false)
+ end
+ end
+
+ context "when data_collector_mode is :both" do
+ it "returns true" do
+ Chef::Config[:data_collector][:mode] = :both
+ expect(Chef::DataCollector.reporter_enabled_for_current_mode?).to eq(true)
+ end
+ end
+ end
+
+ context "when running in client mode" do
+ before do
+ Chef::Config[:solo] = false
+ Chef::Config[:local_mode] = false
+ end
+
+ context "when data_collector_mode is :solo" do
+ it "returns false" do
+ Chef::Config[:data_collector][:mode] = :solo
+ expect(Chef::DataCollector.reporter_enabled_for_current_mode?).to eq(false)
+ end
+ end
+
+ context "when data_collector_mode is :client" do
+ it "returns true" do
+ Chef::Config[:data_collector][:mode] = :client
+ expect(Chef::DataCollector.reporter_enabled_for_current_mode?).to eq(true)
+ end
+ end
+
+ context "when data_collector_mode is :both" do
+ it "returns true" do
+ Chef::Config[:data_collector][:mode] = :both
+ expect(Chef::DataCollector.reporter_enabled_for_current_mode?).to eq(true)
+ end
+ end
+ end
+ end
+
+end
+
+describe Chef::DataCollector::Reporter do
+ let(:reporter) { described_class.new }
+ let(:run_status) { Chef::RunStatus.new(Chef::Node.new, Chef::EventDispatch::Dispatcher.new) }
+
+ let(:token) { "supersecrettoken" }
+
+ before do
+ Chef::Config[:data_collector][:server_url] = "http://my-data-collector-server.mycompany.com"
+ Chef::Config[:data_collector][:token] = token
+ end
+
+ describe "selecting token or signed header authentication" do
+
+ context "when the token is set in the config" do
+
+ before do
+ Chef::Config[:client_key] = "/no/key/should/exist/at/this/path.pem"
+ end
+
+ it "configures an HTTP client that doesn't do signed header auth" do
+ # Initializing with the wrong kind of HTTP class should cause Chef::Exceptions::PrivateKeyMissing
+ expect { reporter.http }.to_not raise_error
+ end
+
+ end
+
+ context "when no token is set in the config" do
+
+ let(:token) { nil }
+
+ let(:client_key) { File.join(CHEF_SPEC_DATA, "ssl", "private_key.pem") }
+
+ before do
+ Chef::Config[:client_key] = client_key
+ end
+
+ it "configures an HTTP client that does signed header auth" do
+ expect { reporter.http }.to_not raise_error
+ expect(reporter.http.options).to have_key(:signing_key_filename)
+ expect(reporter.http.options[:signing_key_filename]).to eq(client_key)
+ end
+ end
+
+ end
+
+ describe "#run_started" do
+ before do
+ allow(reporter).to receive(:update_run_status)
+ allow(reporter).to receive(:send_to_data_collector)
+ allow(Chef::DataCollector::Messages).to receive(:run_start_message)
+ end
+
+ it "updates the run status" do
+ expect(reporter).to receive(:update_run_status).with(run_status)
+ reporter.run_started(run_status)
+ end
+
+ it "sends the RunStart message output to the Data Collector server" do
+ expect(Chef::DataCollector::Messages)
+ .to receive(:run_start_message)
+ .with(run_status)
+ .and_return(key: "value")
+ expect(reporter).to receive(:send_to_data_collector).with({ key: "value" })
+ reporter.run_started(run_status)
+ end
+ end
+
+ describe "when sending a message at chef run completion" do
+
+ let(:node) { Chef::Node.new }
+
+ let(:run_status) do
+ instance_double("Chef::RunStatus",
+ run_id: "run_id",
+ node: node,
+ start_time: Time.new,
+ end_time: Time.new,
+ exception: exception)
+ end
+
+ before do
+ reporter.send(:update_run_status, run_status)
+ end
+
+ describe "#run_completed" do
+
+ let(:exception) { nil }
+
+ it "sends the run completion" do
+ expect(reporter).to receive(:send_to_data_collector) do |message|
+ expect(message).to be_a(Hash)
+ expect(message["status"]).to eq("success")
+ end
+ reporter.run_completed(node)
+ end
+ end
+
+ describe "#run_failed" do
+
+ let(:exception) { StandardError.new("oops") }
+
+ it "updates the exception and sends the run completion" do
+ expect(reporter).to receive(:send_to_data_collector) do |message|
+ expect(message).to be_a(Hash)
+ expect(message["status"]).to eq("failure")
+ end
+ reporter.run_failed("test_exception")
+ end
+ end
+ end
+
+ describe "#converge_start" do
+ it "stashes the run_context for later use" do
+ reporter.converge_start("test_context")
+ expect(reporter.run_context).to eq("test_context")
+ end
+ end
+
+ describe "#converge_complete" do
+ it "detects and processes any unprocessed resources" do
+ expect(reporter).to receive(:detect_unprocessed_resources)
+ reporter.converge_complete
+ end
+ end
+
+ describe "#converge_failed" do
+ it "detects and processes any unprocessed resources" do
+ expect(reporter).to receive(:detect_unprocessed_resources)
+ reporter.converge_failed("exception")
+ end
+ end
+
+ describe "#resource_current_state_loaded" do
+ let(:new_resource) { double("new_resource") }
+ let(:action) { double("action") }
+ let(:current_resource) { double("current_resource") }
+ let(:resource_report) { double("resource_report") }
+
+ context "when resource is a nested resource" do
+ it "does not update the resource report" do
+ allow(reporter).to receive(:nested_resource?).and_return(true)
+ expect(reporter).not_to receive(:update_current_resource_report)
+ reporter.resource_current_state_loaded(new_resource, action, current_resource)
+ end
+ end
+
+ context "when resource is not a nested resource" do
+ it "initializes the resource report" do
+ allow(reporter).to receive(:nested_resource?).and_return(false)
+ expect(reporter).to receive(:initialize_resource_report_if_needed)
+ .with(new_resource, action, current_resource)
+ reporter.resource_current_state_loaded(new_resource, action, current_resource)
+ end
+ end
+ end
+
+ describe "#resource_up_to_date" do
+ let(:new_resource) { double("new_resource") }
+ let(:action) { double("action") }
+ let(:resource_report) { double("resource_report") }
+
+ before do
+ allow(reporter).to receive(:nested_resource?)
+ allow(reporter).to receive(:current_resource_report).and_return(resource_report)
+ allow(resource_report).to receive(:up_to_date)
+ end
+
+ context "when the resource is a nested resource" do
+ it "does not mark the resource report as up-to-date" do
+ allow(reporter).to receive(:nested_resource?).with(new_resource).and_return(true)
+ expect(resource_report).not_to receive(:up_to_date)
+ reporter.resource_up_to_date(new_resource, action)
+ end
+ end
+
+ context "when the resource is not a nested resource" do
+ it "marks the resource report as up-to-date" do
+ allow(reporter).to receive(:nested_resource?).with(new_resource).and_return(false)
+ expect(resource_report).to receive(:up_to_date)
+ reporter.resource_up_to_date(new_resource, action)
+ end
+ end
+ end
+
+ describe "#resource_skipped" do
+ let(:new_resource) { double("new_resource") }
+ let(:action) { double("action") }
+ let(:conditional) { double("conditional") }
+ let(:resource_report) { double("resource_report") }
+
+ before do
+ allow(reporter).to receive(:nested_resource?)
+ allow(resource_report).to receive(:skipped)
+ end
+
+ context "when the resource is a nested resource" do
+ it "does not mark the resource report as skipped" do
+ allow(reporter).to receive(:nested_resource?).with(new_resource).and_return(true)
+ expect(resource_report).not_to receive(:skipped).with(conditional)
+ reporter.resource_skipped(new_resource, action, conditional)
+ end
+ end
+
+ context "when the resource is not a nested resource" do
+ it "initializes the resource report and marks it as skipped" do
+ allow(reporter).to receive(:nested_resource?).and_return(false)
+ allow(reporter).to receive(:current_resource_report).and_return(resource_report)
+ expect(reporter).to receive(:initialize_resource_report_if_needed).with(new_resource, action)
+ expect(resource_report).to receive(:skipped).with(conditional)
+ reporter.resource_skipped(new_resource, action, conditional)
+ end
+ end
+ end
+
+ describe "#resource_updated" do
+ let(:resource_report) { double("resource_report") }
+
+ before do
+ allow(reporter).to receive(:current_resource_report).and_return(resource_report)
+ allow(resource_report).to receive(:updated)
+ end
+
+ it "marks the resource report as updated" do
+ expect(resource_report).to receive(:updated)
+ reporter.resource_updated("new_resource", "action")
+ end
+ end
+
+ describe "#resource_failed" do
+ let(:new_resource) { double("new_resource") }
+ let(:action) { double("action") }
+ let(:exception) { double("exception") }
+ let(:error_mapper) { double("error_mapper") }
+ let(:resource_report) { double("resource_report") }
+
+ before do
+ allow(reporter).to receive(:update_error_description)
+ allow(reporter).to receive(:current_resource_report).and_return(resource_report)
+ allow(resource_report).to receive(:failed)
+ allow(Chef::Formatters::ErrorMapper).to receive(:resource_failed).and_return(error_mapper)
+ allow(error_mapper).to receive(:for_json)
+ end
+
+ it "updates the error description" do
+ expect(Chef::Formatters::ErrorMapper).to receive(:resource_failed).with(
+ new_resource,
+ action,
+ exception
+ ).and_return(error_mapper)
+ expect(error_mapper).to receive(:for_json).and_return("error_description")
+ expect(reporter).to receive(:update_error_description).with("error_description")
+ reporter.resource_failed(new_resource, action, exception)
+ end
+
+ context "when the resource is not a nested resource" do
+ it "marks the resource report as failed" do
+ allow(reporter).to receive(:nested_resource?).with(new_resource).and_return(false)
+ expect(resource_report).to receive(:failed).with(exception)
+ reporter.resource_failed(new_resource, action, exception)
+ end
+ end
+
+ context "when the resource is a nested resource" do
+ it "does not mark the resource report as failed" do
+ allow(reporter).to receive(:nested_resource?).with(new_resource).and_return(true)
+ expect(resource_report).not_to receive(:failed).with(exception)
+ reporter.resource_failed(new_resource, action, exception)
+ end
+ end
+ end
+
+ describe "#resource_completed" do
+ let(:new_resource) { double("new_resource") }
+ let(:resource_report) { double("resource_report") }
+
+ before do
+ allow(reporter).to receive(:update_current_resource_report)
+ allow(reporter).to receive(:add_resource_report)
+ allow(reporter).to receive(:current_resource_report)
+ allow(resource_report).to receive(:finish)
+ end
+
+ context "when there is no current resource report" do
+ it "does not touch the current resource report" do
+ allow(reporter).to receive(:current_resource_report).and_return(nil)
+ expect(reporter).not_to receive(:update_current_resource_report)
+ reporter.resource_completed(new_resource)
+ end
+ end
+
+ context "when there is a current resource report" do
+ before do
+ allow(reporter).to receive(:current_resource_report).and_return(resource_report)
+ end
+
+ context "when the resource is a nested resource" do
+ it "does not mark the resource as finished" do
+ allow(reporter).to receive(:nested_resource?).with(new_resource).and_return(true)
+ expect(resource_report).not_to receive(:finish)
+ reporter.resource_completed(new_resource)
+ end
+ end
+
+ context "when the resource is not a nested resource" do
+ before do
+ allow(reporter).to receive(:nested_resource?).with(new_resource).and_return(false)
+ end
+
+ it "marks the current resource report as finished" do
+ expect(resource_report).to receive(:finish)
+ reporter.resource_completed(new_resource)
+ end
+
+ it "nils out the current resource report" do
+ expect(reporter).to receive(:clear_current_resource_report)
+ reporter.resource_completed(new_resource)
+ end
+ end
+ end
+ end
+
+ describe "#run_list_expanded" do
+ it "sets the expanded run list" do
+ reporter.run_list_expanded("test_run_list")
+ expect(reporter.expanded_run_list).to eq("test_run_list")
+ end
+ end
+
+ describe "#run_list_expand_failed" do
+ let(:node) { double("node") }
+ let(:error_mapper) { double("error_mapper") }
+ let(:exception) { double("exception") }
+
+ it "updates the error description" do
+ expect(Chef::Formatters::ErrorMapper).to receive(:run_list_expand_failed).with(
+ node,
+ exception
+ ).and_return(error_mapper)
+ expect(error_mapper).to receive(:for_json).and_return("error_description")
+ expect(reporter).to receive(:update_error_description).with("error_description")
+ reporter.run_list_expand_failed(node, exception)
+ end
+ end
+
+ describe "#cookbook_resolution_failed" do
+ let(:error_mapper) { double("error_mapper") }
+ let(:exception) { double("exception") }
+ let(:expanded_run_list) { double("expanded_run_list") }
+
+ it "updates the error description" do
+ expect(Chef::Formatters::ErrorMapper).to receive(:cookbook_resolution_failed).with(
+ expanded_run_list,
+ exception
+ ).and_return(error_mapper)
+ expect(error_mapper).to receive(:for_json).and_return("error_description")
+ expect(reporter).to receive(:update_error_description).with("error_description")
+ reporter.cookbook_resolution_failed(expanded_run_list, exception)
+ end
+
+ end
+
+ describe "#cookbook_sync_failed" do
+ let(:cookbooks) { double("cookbooks") }
+ let(:error_mapper) { double("error_mapper") }
+ let(:exception) { double("exception") }
+
+ it "updates the error description" do
+ expect(Chef::Formatters::ErrorMapper).to receive(:cookbook_sync_failed).with(
+ cookbooks,
+ exception
+ ).and_return(error_mapper)
+ expect(error_mapper).to receive(:for_json).and_return("error_description")
+ expect(reporter).to receive(:update_error_description).with("error_description")
+ reporter.cookbook_sync_failed(cookbooks, exception)
+ end
+ end
+
+ describe "#disable_reporter_on_error" do
+ context "when no exception is raise by the block" do
+ it "does not disable the reporter" do
+ expect(reporter).not_to receive(:disable_data_collector_reporter)
+ reporter.send(:disable_reporter_on_error) { true }
+ end
+
+ it "does not raise an exception" do
+ expect { reporter.send(:disable_reporter_on_error) { true } }.not_to raise_error
+ end
+ end
+
+ context "when an unexpected exception is raised by the block" do
+ it "re-raises the exception" do
+ expect { reporter.send(:disable_reporter_on_error) { raise "bummer" } }.to raise_error(RuntimeError)
+ end
+ end
+
+ [ Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
+ Errno::ECONNREFUSED, EOFError, Net::HTTPBadResponse,
+ Net::HTTPHeaderSyntaxError, Net::ProtocolError, OpenSSL::SSL::SSLError,
+ Errno::EHOSTDOWN ].each do |exception_class|
+ context "when the block raises a #{exception_class} exception" do
+ it "disables the reporter" do
+ expect(reporter).to receive(:disable_data_collector_reporter)
+ reporter.send(:disable_reporter_on_error) { raise exception_class.new("bummer") }
+ end
+
+ context "when raise-on-failure is enabled" do
+ it "logs an error and raises" do
+ Chef::Config[:data_collector][:raise_on_failure] = true
+ expect(Chef::Log).to receive(:error)
+ expect { reporter.send(:disable_reporter_on_error) { raise exception_class.new("bummer") } }.to raise_error(exception_class)
+ end
+ end
+
+ context "when raise-on-failure is disabled" do
+ it "logs an info message and does not raise an exception" do
+ Chef::Config[:data_collector][:raise_on_failure] = false
+ expect(Chef::Log).to receive(:info)
+ expect { reporter.send(:disable_reporter_on_error) { raise exception_class.new("bummer") } }.not_to raise_error
+ end
+ end
+ end
+ end
+ end
+
+ describe "#validate_data_collector_server_url!" do
+ context "when server_url is empty" do
+ it "raises an exception" do
+ Chef::Config[:data_collector][:server_url] = ""
+ expect { reporter.send(:validate_data_collector_server_url!) }.to raise_error(Chef::Exceptions::ConfigurationError)
+ end
+ end
+
+ context "when server_url is not empty" do
+ context "when server_url is an invalid URI" do
+ it "raises an exception" do
+ Chef::Config[:data_collector][:server_url] = "this is not a URI"
+ expect { reporter.send(:validate_data_collector_server_url!) }.to raise_error(Chef::Exceptions::ConfigurationError)
+ end
+ end
+
+ context "when server_url is a valid URI" do
+ context "when server_url is a URI with no host" do
+ it "raises an exception" do
+ Chef::Config[:data_collector][:server_url] = "/file/uri.txt"
+ expect { reporter.send(:validate_data_collector_server_url!) }.to raise_error(Chef::Exceptions::ConfigurationError)
+ end
+
+ end
+
+ context "when server_url is a URI with a valid host" do
+ it "does not an exception" do
+ Chef::Config[:data_collector][:server_url] = "http://www.google.com/data-collector"
+ expect { reporter.send(:validate_data_collector_server_url!) }.not_to raise_error
+ end
+ end
+ end
+ end
+ end
+
+ describe "#detect_unprocessed_resources" do
+ context "when resources do not override core methods" do
+ it "adds resource reports for any resources that have not yet been processed" do
+ resource_a = Chef::Resource::Service.new("processed service")
+ resource_b = Chef::Resource::Service.new("unprocessed service")
+
+ resource_a.action = [ :enable, :start ]
+ resource_b.action = :start
+
+ run_context = Chef::RunContext.new(Chef::Node.new, Chef::CookbookCollection.new, nil)
+ run_context.resource_collection.insert(resource_a)
+ run_context.resource_collection.insert(resource_b)
+
+ allow(reporter).to receive(:run_context).and_return(run_context)
+
+ # process the actions for resource_a, but not resource_b
+ reporter.resource_up_to_date(resource_a, :enable)
+ reporter.resource_completed(resource_a)
+ reporter.resource_up_to_date(resource_a, :start)
+ reporter.resource_completed(resource_a)
+ expect(reporter.all_resource_reports.size).to eq(2)
+
+ # detect unprocessed resources, which should find that resource_b has not yet been processed
+ reporter.send(:detect_unprocessed_resources)
+ expect(reporter.all_resource_reports.size).to eq(3)
+ end
+ end
+
+ context "when a resource overrides a core method, such as #hash" do
+ it "does not raise an exception" do
+ resource_a = Chef::Resource::Service.new("processed service")
+ resource_b = Chef::Resource::Service.new("unprocessed service")
+
+ resource_a.action = :start
+ resource_b.action = :start
+
+ run_context = Chef::RunContext.new(Chef::Node.new, Chef::CookbookCollection.new, nil)
+ run_context.resource_collection.insert(resource_a)
+ run_context.resource_collection.insert(resource_b)
+
+ allow(reporter).to receive(:run_context).and_return(run_context)
+
+ # override the #hash method on resource_a to return a String instead of
+ # a Fixnum. Without the fix in chef/chef#5604, this would raise an
+ # exception when getting added to the Set/Hash.
+ resource_a.define_singleton_method(:hash) { "a string" }
+
+ # process the actions for resource_a, but not resource_b
+ reporter.resource_up_to_date(resource_a, :start)
+ reporter.resource_completed(resource_a)
+
+ expect { reporter.send(:detect_unprocessed_resources) }.not_to raise_error
+ end
+ end
+ end
+end
diff --git a/spec/unit/decorator/lazy_array_spec.rb b/spec/unit/decorator/lazy_array_spec.rb
new file mode 100644
index 0000000000..0c5c2eeee0
--- /dev/null
+++ b/spec/unit/decorator/lazy_array_spec.rb
@@ -0,0 +1,58 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Decorator::LazyArray do
+ def foo
+ @foo ||= 1
+ end
+
+ def bar
+ @bar ||= 2
+ end
+
+ let(:decorator) do
+ Chef::Decorator::LazyArray.new { [ foo, bar ] }
+ end
+
+ it "behaves like an array" do
+ expect(decorator[0]).to eql(1)
+ expect(decorator[1]).to eql(2)
+ end
+
+ it "accessing the array elements is lazy" do
+ expect(decorator[0].class).to eql(Chef::Decorator::Lazy)
+ expect(decorator[1].class).to eql(Chef::Decorator::Lazy)
+ expect(@foo).to be nil
+ expect(@bar).to be nil
+ end
+
+ it "calling a method on the array element runs the proc (and both elements are autovivified)" do
+ expect(decorator[0].nil?).to be false
+ expect(@foo).to equal(1)
+ expect(@bar).to equal(2)
+ end
+
+ it "if we loop over the elements and do nothing then its not lazy" do
+ # we don't know how many elements there are unless we evaluate the proc
+ decorator.each { |i| }
+ expect(@foo).to equal(1)
+ expect(@bar).to equal(2)
+ end
+end
diff --git a/spec/unit/decorator/lazy_spec.rb b/spec/unit/decorator/lazy_spec.rb
new file mode 100644
index 0000000000..46c8955ae8
--- /dev/null
+++ b/spec/unit/decorator/lazy_spec.rb
@@ -0,0 +1,39 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Decorator::Lazy do
+ let(:decorator) do
+ @a = 0
+ Chef::Decorator::Lazy.new { @a += 1 }
+ end
+
+ it "decorates an object" do
+ expect(decorator.even?).to be false
+ end
+
+ it "the proc runs and does work" do
+ expect(decorator).to eql(1)
+ end
+
+ it "creating the decorator does not cause the proc to run" do
+ decorator
+ expect(@a).to eql(0)
+ end
+end
diff --git a/spec/unit/decorator_spec.rb b/spec/unit/decorator_spec.rb
new file mode 100644
index 0000000000..6d73db2cc4
--- /dev/null
+++ b/spec/unit/decorator_spec.rb
@@ -0,0 +1,142 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+def impersonates_a(klass)
+ it "#is_a?(#{klass}) is true" do
+ expect(decorator.is_a?(klass)).to be true
+ end
+
+ it "#is_a?(Chef::Decorator) is true" do
+ expect(decorator.is_a?(Chef::Decorator)).to be true
+ end
+
+ it "#kind_of?(#{klass}) is true" do
+ expect(decorator.kind_of?(klass)).to be true
+ end
+
+ it "#kind_of?(Chef::Decorator) is true" do
+ expect(decorator.kind_of?(Chef::Decorator)).to be true
+ end
+
+ it "#instance_of?(#{klass}) is false" do
+ expect(decorator.instance_of?(klass)).to be false
+ end
+
+ it "#instance_of?(Chef::Decorator) is true" do
+ expect(decorator.instance_of?(Chef::Decorator)).to be true
+ end
+
+ it "#class is Chef::Decorator" do
+ expect(decorator.class).to eql(Chef::Decorator)
+ end
+end
+
+describe Chef::Decorator do
+ let(:obj) {}
+ let(:decorator) { Chef::Decorator.new(obj) }
+
+ context "when the obj is a string" do
+ let(:obj) { "STRING" }
+
+ impersonates_a(String)
+
+ it "#nil? is false" do
+ expect(decorator.nil?).to be false
+ end
+
+ it "!! is true" do
+ expect(!!decorator).to be true
+ end
+
+ it "dup returns a decorator" do
+ expect(decorator.dup.class).to be Chef::Decorator
+ end
+
+ it "dup dup's the underlying thing" do
+ expect(decorator.dup.__getobj__).not_to equal(decorator.__getobj__)
+ end
+ end
+
+ context "when the obj is a nil" do
+ let(:obj) { nil }
+
+ it "#nil? is true" do
+ expect(decorator.nil?).to be true
+ end
+
+ it "!! is false" do
+ expect(!!decorator).to be false
+ end
+
+ impersonates_a(NilClass)
+ end
+
+ context "when the obj is an empty Hash" do
+ let(:obj) { {} }
+
+ impersonates_a(Hash)
+
+ it "formats it correctly through ffi-yajl and not the JSON gem" do
+ # this relies on a quirk of pretty formatting whitespace between yajl and ruby's JSON
+ expect(FFI_Yajl::Encoder.encode(decorator, pretty: true)).to eql("{\n\n}\n")
+ end
+ end
+
+ context "whent he obj is a Hash with elements" do
+ let(:obj) { { foo: "bar", baz: "qux" } }
+
+ impersonates_a(Hash)
+
+ it "dup is shallow on the Hash" do
+ expect(decorator.dup[:baz]).to equal(decorator[:baz])
+ end
+
+ it "deep mutating the dup'd hash mutates the origin" do
+ decorator.dup[:baz] << "qux"
+ expect(decorator[:baz]).to eql("quxqux")
+ end
+ end
+
+ context "memoizing methods" do
+ let(:obj) { {} }
+
+ it "calls method_missing only once" do
+ expect(decorator).to receive(:method_missing).once.and_call_original
+ expect(decorator.keys).to eql([])
+ expect(decorator.keys).to eql([])
+ end
+
+ it "switching a Hash to an Array responds to keys then does not" do
+ expect(decorator.respond_to?(:keys)).to be true
+ expect(decorator.keys).to eql([])
+ decorator.__setobj__([])
+ expect(decorator.respond_to?(:keys)).to be false
+ expect { decorator.keys }.to raise_error(NoMethodError)
+ end
+
+ it "memoization of methods happens on the instances, not the classes" do
+ decorator2 = Chef::Decorator.new([])
+ expect(decorator.respond_to?(:keys)).to be true
+ expect(decorator.keys).to eql([])
+ expect(decorator2.respond_to?(:keys)).to be false
+ expect { decorator2.keys }.to raise_error(NoMethodError)
+ end
+ end
+end
diff --git a/spec/unit/deprecated_spec.rb b/spec/unit/deprecated_spec.rb
new file mode 100644
index 0000000000..9be792ab20
--- /dev/null
+++ b/spec/unit/deprecated_spec.rb
@@ -0,0 +1,59 @@
+#
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/deprecated"
+
+describe Chef::Deprecated do
+ class TestDeprecation < Chef::Deprecated::Base
+ def id; 999; end
+
+ def target; "test.html"; end
+
+ def link; "#{Chef::Deprecated::Base::BASE_URL}test.html"; end
+ end
+
+ context "loading a deprecation class" do
+ it "loads the correct class" do
+ expect(Chef::Deprecated.create(:test_deprecation)).to be_an_instance_of(Chef::Deprecated::TestDeprecation)
+ end
+
+ it "optionally sets a message" do
+ deprecation = Chef::Deprecated.create(:test_deprecation, "A test message")
+ expect(deprecation.message).to eql("A test message")
+ end
+
+ it "optionally sets the location" do
+ deprecation = Chef::Deprecated.create(:test_deprecation, nil, "A test location")
+ expect(deprecation.location).to eql("A test location")
+ end
+ end
+
+ context "formatting deprecation warnings" do
+ let(:base_url) { Chef::Deprecated::Base::BASE_URL }
+ let(:message) { "A test message" }
+ let(:location) { "the location" }
+
+ it "displays the full URL" do
+ expect(Chef::Deprecated::TestDeprecation.new().url).to eql("#{base_url}test.html")
+ end
+
+ it "formats a complete deprecation message" do
+ expect(Chef::Deprecated::TestDeprecation.new(message, location).inspect).to eql("#{message} (CHEF-999)#{location}.\nhttps://docs.chef.io/deprecations_test.html")
+ end
+ end
+end
diff --git a/spec/unit/deprecation_spec.rb b/spec/unit/deprecation_spec.rb
index 674de5ec1d..41c1724e5b 100644
--- a/spec/unit/deprecation_spec.rb
+++ b/spec/unit/deprecation_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/deprecation/warnings'
+require "spec_helper"
+require "chef/deprecation/warnings"
describe Chef::Deprecation do
# Support code for Chef::Deprecation
def self.class_from_string(str)
- str.split('::').inject(Object) do |mod, class_name|
+ str.split("::").inject(Object) do |mod, class_name|
mod.const_get(class_name)
end
end
@@ -59,33 +59,26 @@ describe Chef::Deprecation do
end
end
- context 'when Chef::Config[:treat_deprecation_warnings_as_errors] is off' do
+ context "when Chef::Config[:treat_deprecation_warnings_as_errors] is off" do
before do
Chef::Config[:treat_deprecation_warnings_as_errors] = false
end
- context 'deprecation warning messages' do
- RSpec::Matchers.define_negated_matcher :a_non_empty_array, :be_empty
-
- it 'should be enabled for deprecated methods' do
- expect(Chef::Log).to receive(:warn).with(a_non_empty_array)
- TestClass.new.deprecated_method(10)
- end
-
- it 'should contain stack trace' do
- expect(Chef::Log).to receive(:warn).with(a_string_including(".rb"))
+ context "deprecation warning messages" do
+ it "should be enabled for deprecated methods" do
+ expect(Chef).to receive(:deprecated).with(:internal_api, /Method.*of 'TestClass'/)
TestClass.new.deprecated_method(10)
end
end
- it 'deprecated methods should still be called' do
+ it "deprecated methods should still be called" do
test_instance = TestClass.new
test_instance.deprecated_method(10)
expect(test_instance.get_value).to eq(10)
end
end
- it 'should raise when deprecation warnings are treated as errors' do
+ it "should raise when deprecation warnings are treated as errors" do
# rspec should set this
expect(Chef::Config[:treat_deprecation_warnings_as_errors]).to be true
test_instance = TestClass.new
diff --git a/spec/unit/digester_spec.rb b/spec/unit/digester_spec.rb
index 51bcfbdde5..2684ac8f7d 100644
--- a/spec/unit/digester_spec.rb
+++ b/spec/unit/digester_spec.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Digester do
before(:each) do
@@ -40,11 +40,10 @@ describe Chef::Digester do
it "generates a checksum from a non-file IO object" do
io = StringIO.new("riseofthemachines\nriseofthechefs\n")
- expected_md5 = '0e157ac1e2dd73191b76067fb6b4bceb'
+ expected_md5 = "0e157ac1e2dd73191b76067fb6b4bceb"
expect(@cache.generate_md5_checksum(io)).to eq(expected_md5)
end
end
end
-
diff --git a/spec/unit/dsl/audit_spec.rb b/spec/unit/dsl/audit_spec.rb
index 28b28e0a7c..42e543fdb2 100644
--- a/spec/unit/dsl/audit_spec.rb
+++ b/spec/unit/dsl/audit_spec.rb
@@ -1,6 +1,6 @@
-require 'spec_helper'
-require 'chef/dsl/audit'
+require "spec_helper"
+require "chef/dsl/audit"
class AuditDSLTester < Chef::Recipe
include Chef::DSL::Audit
@@ -17,18 +17,18 @@ describe Chef::DSL::Audit do
let(:cookbook_collection) { {} }
it "raises an error when a block of audits is not provided" do
- expect{ auditor.control_group "name" }.to raise_error(Chef::Exceptions::NoAuditsProvided)
+ expect { auditor.control_group "name" }.to raise_error(Chef::Exceptions::NoAuditsProvided)
end
it "raises an error when no audit name is given" do
- expect{ auditor.control_group do end }.to raise_error(Chef::Exceptions::AuditNameMissing)
+ expect { auditor.control_group {} }.to raise_error(Chef::Exceptions::AuditNameMissing)
end
context "audits already populated" do
- let(:audits) { {"unique" => {} } }
+ let(:audits) { { "unique" => {} } }
it "raises an error if the audit name is a duplicate" do
- expect { auditor.control_group "unique" do end }.to raise_error(Chef::Exceptions::AuditControlGroupDuplicate)
+ expect { auditor.control_group("unique") {} }.to raise_error(Chef::Exceptions::AuditControlGroupDuplicate)
end
end
@@ -36,7 +36,7 @@ describe Chef::DSL::Audit do
let(:auditor) { BadAuditDSLTester.new }
it "fails because it relies on the recipe DSL existing" do
- expect { auditor.control_group "unique" do end }.to raise_error(NoMethodError, /undefined method `cookbook_name'/)
+ expect { auditor.control_group("unique") {} }.to raise_error(NoMethodError, /undefined method `cookbook_name'/)
end
end
diff --git a/spec/unit/dsl/data_query_spec.rb b/spec/unit/dsl/data_query_spec.rb
index b93ae1f1d6..f93f07bc52 100644
--- a/spec/unit/dsl/data_query_spec.rb
+++ b/spec/unit/dsl/data_query_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/dsl/data_query'
+require "spec_helper"
+require "chef/dsl/data_query"
class DataQueryDSLTester
include Chef::DSL::DataQuery
@@ -35,23 +35,23 @@ describe Chef::DSL::DataQuery do
describe "::data_bag" do
it "lists the items in a data bag" do
allow(Chef::DataBag).to receive(:load)
- .with("bag_name")
- .and_return("item_1" => "http://url_for/item_1", "item_2" => "http://url_for/item_2")
- expect( language.data_bag("bag_name").sort ).to eql %w(item_1 item_2)
+ .with("bag_name")
+ .and_return("item_1" => "http://url_for/item_1", "item_2" => "http://url_for/item_2")
+ expect( language.data_bag("bag_name").sort ).to eql %w{item_1 item_2}
end
end
shared_examples_for "a data bag item" do
it "validates the name of the data bag you're trying to load an item from" do
- expect{ language.send(method_name, " %%^& ", "item_name") }.to raise_error(Chef::Exceptions::InvalidDataBagName)
+ expect { language.send(method_name, " %%^& ", "item_name") }.to raise_error(Chef::Exceptions::InvalidDataBagName)
end
it "validates the id of the data bag item you're trying to load" do
- expect{ language.send(method_name, "bag_name", " 987 (*&()") }.to raise_error(Chef::Exceptions::InvalidDataBagItemID)
+ expect { language.send(method_name, "bag_name", " 987 (*&()") }.to raise_error(Chef::Exceptions::InvalidDataBagItemID)
end
it "validates that the id of the data bag item is not nil" do
- expect{ language.send(method_name, "bag_name", nil) }.to raise_error(Chef::Exceptions::InvalidDataBagItemID)
+ expect { language.send(method_name, "bag_name", nil) }.to raise_error(Chef::Exceptions::InvalidDataBagItemID)
end
end
@@ -60,14 +60,15 @@ describe Chef::DSL::DataQuery do
let(:item_name) { "item_name" }
- let(:raw_data) {{
+ let(:raw_data) do
+ {
"id" => item_name,
"greeting" => "hello",
"nested" => {
"a1" => [1, 2, 3],
- "a2" => { "b1" => true }
- }
- }}
+ "a2" => { "b1" => true },
+ },
+ } end
let(:item) do
item = Chef::DataBagItem.new
diff --git a/spec/unit/dsl/declare_resource_spec.rb b/spec/unit/dsl/declare_resource_spec.rb
new file mode 100644
index 0000000000..57a7fd7f18
--- /dev/null
+++ b/spec/unit/dsl/declare_resource_spec.rb
@@ -0,0 +1,365 @@
+#
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::ResourceCollection do
+ let(:run_context) do
+ cookbook_repo = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "data", "cookbooks"))
+ cookbook_loader = Chef::CookbookLoader.new(cookbook_repo)
+ cookbook_loader.load_cookbooks
+ node = Chef::Node.new
+ cookbook_collection = Chef::CookbookCollection.new(cookbook_loader)
+ events = Chef::EventDispatch::Dispatcher.new
+ Chef::RunContext.new(node, cookbook_collection, events)
+ end
+
+ let(:recipe) do
+ Chef::Recipe.new("hjk", "test", run_context)
+ end
+
+ describe "#declare_resource" do
+ before do
+ recipe.declare_resource(:zen_master, "monkey") do
+ something true
+ end
+ end
+
+ it "inserts into the resource collection" do
+ expect(run_context.resource_collection.first.to_s).to eql("zen_master[monkey]")
+ end
+
+ it "sets the property from the block" do
+ expect(run_context.resource_collection.first.something).to be true
+ end
+ end
+
+ describe "#edit_resource!" do
+ it "raises if nothing is found" do
+ expect do
+ recipe.edit_resource!(:zen_master, "monkey") do
+ something true
+ end
+ end.to raise_error(Chef::Exceptions::ResourceNotFound)
+ end
+
+ it "raises if nothing is found and no block is given" do
+ expect do
+ recipe.edit_resource!(:zen_master, "monkey")
+ end.to raise_error(Chef::Exceptions::ResourceNotFound)
+ end
+
+ it "edits the resource if it finds one" do
+ resource = recipe.declare_resource(:zen_master, "monkey") do
+ something false
+ end
+ expect(
+ recipe.edit_resource!(:zen_master, "monkey") do
+ something true
+ end
+ ).to eql(resource)
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
+ expect(run_context.resource_collection.first.something).to be true
+ end
+
+ it "acts like find_resource! if not given a block and the resource exists" do
+ resource = recipe.declare_resource(:zen_master, "monkey") do
+ something false
+ end
+ expect(
+ recipe.edit_resource!(:zen_master, "monkey")
+ ).to eql(resource)
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
+ expect(run_context.resource_collection.first.something).to be false
+ end
+ end
+
+ describe "#edit_resource" do
+ it "inserts a resource if nothing is found" do
+ resource = recipe.edit_resource(:zen_master, "monkey") do
+ something true
+ end
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
+ expect(run_context.resource_collection.first).to eql(resource)
+ expect(run_context.resource_collection.first.something).to be true
+ end
+
+ it "inserts a resource even if not given a block" do
+ resource = recipe.edit_resource(:zen_master, "monkey")
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
+ expect(run_context.resource_collection.first).to eql(resource)
+ end
+
+ it "edits the resource if it finds one" do
+ resource = recipe.declare_resource(:zen_master, "monkey") do
+ something false
+ end
+ expect(
+ recipe.edit_resource(:zen_master, "monkey") do
+ something true
+ end
+ ).to eql(resource)
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
+ expect(run_context.resource_collection.first.something).to be true
+ end
+
+ it "acts like find_resource if not given a block and the resource exists" do
+ resource = recipe.declare_resource(:zen_master, "monkey") do
+ something false
+ end
+ expect(
+ recipe.edit_resource(:zen_master, "monkey")
+ ).to eql(resource)
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
+ expect(run_context.resource_collection.first.something).to be false
+ end
+ end
+
+ describe "#find_resource!" do
+ it "raises if nothing is found" do
+ expect do
+ recipe.find_resource!(:zen_master, "monkey")
+ end.to raise_error(Chef::Exceptions::ResourceNotFound)
+ end
+
+ it "raises if given a block" do
+ resource = recipe.declare_resource(:zen_master, "monkey") do
+ something false
+ end
+ expect do
+ recipe.find_resource!(:zen_master, "monkey") do
+ something false
+ end
+ end.to raise_error(ArgumentError)
+ end
+
+ it "returns the resource if it finds one" do
+ resource = recipe.declare_resource(:zen_master, "monkey") do
+ something false
+ end
+ expect(
+ recipe.find_resource!(:zen_master, "monkey")
+ ).to eql(resource)
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
+ expect(run_context.resource_collection.first.something).to be false
+ end
+ end
+
+ describe "#find_resource without block" do
+ it "returns nil if nothing is found" do
+ expect(recipe.find_resource(:zen_master, "monkey")).to be nil
+ expect(run_context.resource_collection.all_resources.size).to eql(0)
+ end
+
+ it "returns the resource if it finds one" do
+ resource = recipe.declare_resource(:zen_master, "monkey") do
+ something false
+ end
+ expect(
+ recipe.find_resource(:zen_master, "monkey")
+ ).to eql(resource)
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
+ expect(run_context.resource_collection.first.something).to be false
+ end
+ end
+
+ describe "#find_resource with block" do
+ it "inserts a resource if nothing is found" do
+ resource = recipe.find_resource(:zen_master, "monkey") do
+ something true
+ end
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
+ expect(run_context.resource_collection.first).to eql(resource)
+ expect(run_context.resource_collection.first.something).to be true
+ end
+
+ it "returns the resource if it finds one" do
+ resource = recipe.declare_resource(:zen_master, "monkey") do
+ something false
+ end
+ expect(
+ recipe.find_resource(:zen_master, "monkey") do
+ something true
+ end
+ ).to eql(resource)
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
+ expect(run_context.resource_collection.first.something).to be false
+ end
+ end
+
+ describe "#delete_resource" do
+ it "returns nil if nothing is found" do
+ expect(
+ recipe.delete_resource(:zen_master, "monkey")
+ ).to be nil
+ end
+
+ it "deletes and returns the resource if it finds one" do
+ resource = recipe.declare_resource(:zen_master, "monkey") do
+ something false
+ end
+ expect(
+ recipe.delete_resource(:zen_master, "monkey")
+ ).to eql(resource)
+ expect(run_context.resource_collection.all_resources.size).to eql(0)
+ end
+ end
+
+ describe "#delete_resource!" do
+ it "raises if nothing is found" do
+ expect do
+ recipe.delete_resource!(:zen_master, "monkey")
+ end.to raise_error(Chef::Exceptions::ResourceNotFound)
+ end
+
+ it "deletes and returns the resource if it finds one" do
+ resource = recipe.declare_resource(:zen_master, "monkey") do
+ something false
+ end
+ expect(
+ recipe.delete_resource!(:zen_master, "monkey")
+ ).to eql(resource)
+ expect(run_context.resource_collection.all_resources.size).to eql(0)
+ end
+
+ it "removes pending delayed notifications" do
+ recipe.declare_resource(:zen_master, "one")
+ recipe.declare_resource(:zen_master, "two") do
+ notifies :win, "zen_master[one]"
+ end
+ recipe.delete_resource(:zen_master, "two")
+ resource = recipe.declare_resource(:zen_master, "two")
+ expect(resource.delayed_notifications).to eql([])
+ end
+
+ it "removes pending immediate notifications" do
+ recipe.declare_resource(:zen_master, "one")
+ recipe.declare_resource(:zen_master, "two") do
+ notifies :win, "zen_master[one]", :immediate
+ end
+ recipe.delete_resource(:zen_master, "two")
+ resource = recipe.declare_resource(:zen_master, "two")
+ expect(resource.immediate_notifications).to eql([])
+ end
+
+ it "removes pending before notifications" do
+ recipe.declare_resource(:zen_master, "one")
+ recipe.declare_resource(:zen_master, "two") do
+ notifies :win, "zen_master[one]", :before
+ end
+ recipe.delete_resource(:zen_master, "two")
+ resource = recipe.declare_resource(:zen_master, "two")
+ expect(resource.before_notifications).to eql([])
+ end
+ end
+
+ describe "run_context helpers" do
+
+ let(:parent_run_context) do
+ run_context.create_child
+ end
+
+ let(:child_run_context) do
+ parent_run_context.create_child
+ end
+
+ let(:parent_recipe) do
+ Chef::Recipe.new("hjk", "parent", parent_run_context)
+ end
+
+ let(:child_recipe) do
+ Chef::Recipe.new("hjk", "child", child_run_context)
+ end
+
+ before do
+ # wire up our outer run context to the root Chef.run_context
+ allow(Chef).to receive(:run_context).and_return(run_context)
+ end
+
+ it "our tests have correct separation" do
+ child_resource = child_recipe.declare_resource(:zen_master, "child") do
+ something false
+ end
+ parent_resource = parent_recipe.declare_resource(:zen_master, "parent") do
+ something false
+ end
+ root_resource = recipe.declare_resource(:zen_master, "root") do
+ something false
+ end
+ expect(run_context.resource_collection.first).to eql(root_resource)
+ expect(run_context.resource_collection.first.to_s).to eql("zen_master[root]")
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
+ expect(parent_run_context.resource_collection.first).to eql(parent_resource)
+ expect(parent_run_context.resource_collection.first.to_s).to eql("zen_master[parent]")
+ expect(parent_run_context.resource_collection.all_resources.size).to eql(1)
+ expect(child_run_context.resource_collection.first).to eql(child_resource)
+ expect(child_run_context.resource_collection.first.to_s).to eql("zen_master[child]")
+ expect(child_run_context.resource_collection.all_resources.size).to eql(1)
+ end
+
+ it "with_run_context with :parent lets us build resources in the parent run_context from the child" do
+ child_recipe.instance_eval do
+ with_run_context(:parent) do
+ declare_resource(:zen_master, "parent") do
+ something false
+ end
+ end
+ end
+ expect(run_context.resource_collection.all_resources.size).to eql(0)
+ expect(parent_run_context.resource_collection.all_resources.size).to eql(1)
+ expect(parent_run_context.resource_collection.first.to_s).to eql("zen_master[parent]")
+ expect(child_run_context.resource_collection.all_resources.size).to eql(0)
+ end
+
+ it "with_run_context with :root lets us build resources in the root run_context from the child" do
+ child_recipe.instance_eval do
+ with_run_context(:root) do
+ declare_resource(:zen_master, "root") do
+ something false
+ end
+ end
+ end
+ expect(run_context.resource_collection.first.to_s).to eql("zen_master[root]")
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
+ expect(parent_run_context.resource_collection.all_resources.size).to eql(0)
+ expect(child_run_context.resource_collection.all_resources.size).to eql(0)
+ end
+
+ it "with_run_context also takes a RunContext object as an argument" do
+ child_recipe.instance_exec(parent_run_context) do |parent_run_context|
+ with_run_context(parent_run_context) do
+ declare_resource(:zen_master, "parent") do
+ something false
+ end
+ end
+ end
+ expect(run_context.resource_collection.all_resources.size).to eql(0)
+ expect(parent_run_context.resource_collection.all_resources.size).to eql(1)
+ expect(parent_run_context.resource_collection.first.to_s).to eql("zen_master[parent]")
+ expect(child_run_context.resource_collection.all_resources.size).to eql(0)
+ end
+
+ it "with_run_context returns the return value of the block" do
+ child_recipe.instance_eval do
+ ret = with_run_context(:root) do
+ "return value"
+ end
+ raise "failed" unless ret == "return value"
+ end
+ end
+ end
+end
diff --git a/spec/unit/dsl/platform_introspection_spec.rb b/spec/unit/dsl/platform_introspection_spec.rb
index e41560c034..fd1f9b23b5 100644
--- a/spec/unit/dsl/platform_introspection_spec.rb
+++ b/spec/unit/dsl/platform_introspection_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/dsl/platform_introspection'
+require "spec_helper"
+require "chef/dsl/platform_introspection"
class LanguageTester
attr_reader :node
@@ -39,16 +39,16 @@ end
describe Chef::DSL::PlatformIntrospection::PlatformDependentValue do
before do
platform_hash = {
- :openbsd => {:default => 'free, functional, secure'},
- [:redhat, :centos, :fedora, :scientific] => {:default => '"stable"'},
- :ubuntu => {'10.04' => 'using upstart more', :default => 'using init more'},
- :default => 'bork da bork'
+ :openbsd => { :default => "free, functional, secure" },
+ [:redhat, :centos, :fedora, :scientific] => { :default => '"stable"' },
+ :ubuntu => { "10.04" => "using upstart more", :default => "using init more" },
+ :default => "bork da bork",
}
@platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformDependentValue.new(platform_hash)
end
it "returns the default value when the platform doesn't match" do
- expect(@platform_specific_value.value_for_node(:platform => :dos)).to eq('bork da bork')
+ expect(@platform_specific_value.value_for_node(:platform => :dos)).to eq("bork da bork")
end
it "returns a value for a platform set as a group" do
@@ -60,25 +60,25 @@ describe Chef::DSL::PlatformIntrospection::PlatformDependentValue do
end
it "returns a value for a specific platform version" do
- node = {:platform => 'ubuntu', :platform_version => '10.04'}
- expect(@platform_specific_value.value_for_node(node)).to eq('using upstart more')
+ node = { :platform => "ubuntu", :platform_version => "10.04" }
+ expect(@platform_specific_value.value_for_node(node)).to eq("using upstart more")
end
it "returns a platform-default value if the platform version doesn't match an explicit one" do
- node = {:platform => 'ubuntu', :platform_version => '9.10' }
- expect(@platform_specific_value.value_for_node(node)).to eq('using init more')
+ node = { :platform => "ubuntu", :platform_version => "9.10" }
+ expect(@platform_specific_value.value_for_node(node)).to eq("using init more")
end
it "returns nil if there is no default and no platforms match" do
# this matches the behavior in the original implementation.
# whether or not it's correct is another matter.
platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformDependentValue.new({})
- expect(platform_specific_value.value_for_node(:platform => 'foo')).to be_nil
+ expect(platform_specific_value.value_for_node(:platform => "foo")).to be_nil
end
it "raises an argument error if the platform hash is not correctly structured" do
- bad_hash = {:ubuntu => :foo} # should be :ubuntu => {:default => 'foo'}
- expect {Chef::DSL::PlatformIntrospection::PlatformDependentValue.new(bad_hash)}.to raise_error(ArgumentError)
+ bad_hash = { :ubuntu => :foo } # should be :ubuntu => {:default => 'foo'}
+ expect { Chef::DSL::PlatformIntrospection::PlatformDependentValue.new(bad_hash) }.to raise_error(ArgumentError)
end
end
@@ -91,17 +91,16 @@ describe Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue do
[:rhel, "fedora"] => "redhatty value",
"suse" => @array_values,
:gentoo => "gentoo value",
- :default => "default value"
+ :default => "default value",
}
@platform_family_value = Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue.new(@platform_family_hash)
end
it "returns the default value when the platform family doesn't match" do
- expect(@platform_family_value.value_for_node(:platform_family => :os2)).to eq('default value')
+ expect(@platform_family_value.value_for_node(:platform_family => :os2)).to eq("default value")
end
-
it "returns a value for the platform family when it was set as a string but fetched as a symbol" do
expect(@platform_family_value.value_for_node(:platform_family => :debian)).to eq("debian value")
end
@@ -124,7 +123,7 @@ describe Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue do
it "returns nil if there is no default and no platforms match" do
platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue.new({})
- expect(platform_specific_value.value_for_node(:platform_family => 'foo')).to be_nil
+ expect(platform_specific_value.value_for_node(:platform_family => "foo")).to be_nil
end
end
diff --git a/spec/unit/dsl/reboot_pending_spec.rb b/spec/unit/dsl/reboot_pending_spec.rb
index 6705820e17..5cd7c7794f 100644
--- a/spec/unit/dsl/reboot_pending_spec.rb
+++ b/spec/unit/dsl/reboot_pending_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,26 +30,26 @@ describe Chef::DSL::RebootPending do
context "platform is windows" do
before do
- allow(recipe).to receive(:platform?).with('windows').and_return(true)
+ allow(recipe).to receive(:platform?).with("windows").and_return(true)
allow(recipe).to receive(:registry_key_exists?).and_return(false)
allow(recipe).to receive(:registry_value_exists?).and_return(false)
end
-
+
it 'should return true if "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations" exists' do
- allow(recipe).to receive(:registry_value_exists?).with('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => 'PendingFileRenameOperations' }).and_return(true)
+ allow(recipe).to receive(:registry_value_exists?).with('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => "PendingFileRenameOperations" }).and_return(true)
expect(recipe.reboot_pending?).to be_truthy
end
-
+
it 'should return true if "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" exists' do
allow(recipe).to receive(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired').and_return(true)
expect(recipe.reboot_pending?).to be_truthy
end
-
+
it 'should return true if key "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired" exists' do
allow(recipe).to receive(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending').and_return(true)
expect(recipe.reboot_pending?).to be_truthy
end
-
+
context "version is server 2003" do
before do
allow(Chef::Platform).to receive(:windows_server_2003?).and_return(true)
@@ -58,24 +58,24 @@ describe Chef::DSL::RebootPending do
it 'should return true if value "HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile" contains specific data on 2k3' do
allow(recipe).to receive(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').and_return(true)
allow(recipe).to receive(:registry_get_values).with('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').and_return(
- [{:name => "Flags", :type => :dword, :data => 3}])
+ [{ :name => "Flags", :type => :dword, :data => 3 }])
expect(recipe.reboot_pending?).to be_truthy
end
end
end
-
+
context "platform is ubuntu" do
before do
- allow(recipe).to receive(:platform?).with('ubuntu').and_return(true)
+ allow(recipe).to receive(:platform?).with("ubuntu").and_return(true)
end
-
- it 'should return true if /var/run/reboot-required exists' do
- allow(File).to receive(:exists?).with('/var/run/reboot-required').and_return(true)
+
+ it "should return true if /var/run/reboot-required exists" do
+ allow(File).to receive(:exists?).with("/var/run/reboot-required").and_return(true)
expect(recipe.reboot_pending?).to be_truthy
end
-
- it 'should return false if /var/run/reboot-required does not exist' do
- allow(File).to receive(:exists?).with('/var/run/reboot-required').and_return(false)
+
+ it "should return false if /var/run/reboot-required does not exist" do
+ allow(File).to receive(:exists?).with("/var/run/reboot-required").and_return(false)
expect(recipe.reboot_pending?).to be_falsey
end
end
@@ -85,14 +85,14 @@ describe Chef::DSL::RebootPending do
describe "in a recipe" do
it "responds to reboot_pending?" do
# Chef::Recipe.new(cookbook_name, recipe_name, run_context(node, cookbook_collection, events))
- recipe = Chef::Recipe.new(nil,nil,Chef::RunContext.new(Chef::Node.new, {}, nil))
+ recipe = Chef::Recipe.new(nil, nil, Chef::RunContext.new(Chef::Node.new, {}, nil))
expect(recipe).to respond_to(:reboot_pending?)
end
end # describe in a recipe
describe "in a resource" do
it "responds to reboot_pending?" do
- resource = Chef::Resource::new("Crackerjack::Timing", nil)
+ resource = Chef::Resource.new("Crackerjack::Timing", nil)
expect(resource).to respond_to(:reboot_pending?)
end
end # describe in a resource
diff --git a/spec/unit/dsl/recipe_spec.rb b/spec/unit/dsl/recipe_spec.rb
index dfaad0b73e..bc97ecc029 100644
--- a/spec/unit/dsl/recipe_spec.rb
+++ b/spec/unit/dsl/recipe_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,19 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/dsl/recipe'
-
+require "spec_helper"
+require "chef/dsl/recipe"
RecipeDSLExampleClass = Struct.new(:cookbook_name, :recipe_name)
class RecipeDSLExampleClass
include Chef::DSL::Recipe
end
+FullRecipeDSLExampleClass = Struct.new(:cookbook_name, :recipe_name)
+class FullRecipeDSLExampleClass
+ include Chef::DSL::Recipe::FullDSL
+end
+
RecipeDSLBaseAPI = Struct.new(:cookbook_name, :recipe_name)
class RecipeDSLExampleSubclass < RecipeDSLBaseAPI
include Chef::DSL::Recipe
@@ -37,6 +41,14 @@ describe Chef::DSL::Recipe do
let(:cookbook_name) { "example_cb" }
let(:recipe_name) { "example_recipe" }
+ it "tracks when it is included via FullDSL" do
+ expect(Chef::DSL::Recipe::FullDSL.descendants).to include(FullRecipeDSLExampleClass)
+ end
+
+ it "doesn't track what is included via only the recipe DSL" do
+ expect(Chef::DSL::Recipe::FullDSL.descendants).not_to include(RecipeDSLExampleClass)
+ end
+
shared_examples_for "A Recipe DSL Implementation" do
it "responds to cookbook_name" do
@@ -79,4 +91,3 @@ describe Chef::DSL::Recipe do
end
end
-
diff --git a/spec/unit/dsl/regsitry_helper_spec.rb b/spec/unit/dsl/registry_helper_spec.rb
index 6508a12b6f..45c7e73979 100644
--- a/spec/unit/dsl/regsitry_helper_spec.rb
+++ b/spec/unit/dsl/registry_helper_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Prajakta Purohit (<prajakta@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,32 +24,29 @@ describe Chef::Resource::RegistryKey do
before (:all) do
events = Chef::EventDispatch::Dispatcher.new
node = Chef::Node.new
- ohai = Ohai::System.new
- ohai.all_plugins
- node.consume_external_attrs(ohai.data,{})
+ node.consume_external_attrs(OHAI_SYSTEM.data, {})
run_context = Chef::RunContext.new(node, {}, events)
- @resource = Chef::Resource::new("foo", run_context)
+ @resource = Chef::Resource.new("foo", run_context)
end
context "tests registry dsl" do
it "resource can access registry_helper method registry_key_exists" do
- expect(@resource.respond_to?('registry_key_exists?')).to eq(true)
+ expect(@resource.respond_to?("registry_key_exists?")).to eq(true)
end
it "resource can access registry_helper method registry_get_values" do
- expect(@resource.respond_to?('registry_get_values')).to eq(true)
+ expect(@resource.respond_to?("registry_get_values")).to eq(true)
end
it "resource can access registry_helper method registry_has_subkey" do
- expect(@resource.respond_to?('registry_has_subkeys?')).to eq(true)
+ expect(@resource.respond_to?("registry_has_subkeys?")).to eq(true)
end
it "resource can access registry_helper method registry_get_subkeys" do
- expect(@resource.respond_to?('registry_get_subkeys')).to eq(true)
+ expect(@resource.respond_to?("registry_get_subkeys")).to eq(true)
end
it "resource can access registry_helper method registry_value_exists" do
- expect(@resource.respond_to?('registry_value_exists?')).to eq(true)
+ expect(@resource.respond_to?("registry_value_exists?")).to eq(true)
end
it "resource can access registry_helper method data_value_exists" do
- expect(@resource.respond_to?('registry_data_exists?')).to eq(true)
+ expect(@resource.respond_to?("registry_data_exists?")).to eq(true)
end
end
end
-
diff --git a/spec/unit/dsl/resources_spec.rb b/spec/unit/dsl/resources_spec.rb
index 581c835290..dc05f8bcf4 100644
--- a/spec/unit/dsl/resources_spec.rb
+++ b/spec/unit/dsl/resources_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Noah Kantrowitz (<noah@coderanger.net>)
-# Copyright:: Copyright (c) 2015 Noah Kantrowitz
+# Copyright:: Copyright 2015-2016, Noah Kantrowitz
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/dsl/resources'
+require "spec_helper"
+require "chef/dsl/resources"
describe Chef::DSL::Resources do
let(:declared_resources) { [] }
@@ -25,7 +25,7 @@ describe Chef::DSL::Resources do
r = declared_resources
Class.new do
include Chef::DSL::Resources
- define_method(:declare_resource) do |dsl_name, name, _created_at, &_block|
+ define_method(:declare_resource) do |dsl_name, name, _created_at|
r << [dsl_name, name]
end
end
@@ -36,21 +36,21 @@ describe Chef::DSL::Resources do
described_class.remove_resource_dsl(:test_resource)
end
- context 'with a resource added' do
+ context "with a resource added" do
before do
Chef::DSL::Resources.add_resource_dsl(:test_resource)
test_class.new.instance_eval do
- test_resource 'test_name' do
+ test_resource "test_name" do
end
end
end
- it { is_expected.to eq [[:test_resource, 'test_name']]}
+ it { is_expected.to eq [[:test_resource, "test_name"]] }
end
- context 'with no resource added' do
+ context "with no resource added" do
subject do
test_class.new.instance_eval do
- test_resource 'test_name' do
+ test_resource "test_name" do
end
end
end
@@ -58,14 +58,14 @@ describe Chef::DSL::Resources do
it { expect { subject }.to raise_error NoMethodError }
end
- context 'with a resource added and removed' do
+ context "with a resource added and removed" do
before do
Chef::DSL::Resources.add_resource_dsl(:test_resource)
Chef::DSL::Resources.remove_resource_dsl(:test_resource)
end
subject do
test_class.new.instance_eval do
- test_resource 'test_name' do
+ test_resource "test_name" do
end
end
end
@@ -73,13 +73,13 @@ describe Chef::DSL::Resources do
it { expect { subject }.to raise_error NoMethodError }
end
- context 'with a nameless resource' do
+ context "with a nameless resource" do
before do
Chef::DSL::Resources.add_resource_dsl(:test_resource)
test_class.new.instance_eval do
- test_resource { }
+ test_resource {}
end
end
- it { is_expected.to eq [[:test_resource, nil]]}
+ it { is_expected.to eq [[:test_resource, nil]] }
end
end
diff --git a/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb b/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb
index 1e2b2a85e8..7e885f8818 100644
--- a/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb
+++ b/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tyler Ball (<tball@getchef.com>)
-# Copyright:: Copyright (c) 2010-2014 Opscode, Inc.
+# Author:: Tyler Ball (<tball@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/encrypted_data_bag_item/check_encrypted'
+require "spec_helper"
+require "chef/encrypted_data_bag_item/check_encrypted"
class CheckEncryptedTester
include Chef::EncryptedDataBagItem::CheckEncrypted
@@ -32,21 +32,22 @@ describe Chef::EncryptedDataBagItem::CheckEncrypted do
end
it "detects the item is not encrypted when the data only contains an id" do
- expect(tester.encrypted?({id: "foo"})).to eq(false)
+ expect(tester.encrypted?({ id: "foo" })).to eq(false)
end
context "when the item is encrypted" do
let(:default_secret) { "abc123SECRET" }
let(:item_name) { "item_name" }
- let(:raw_data) {{
+ let(:raw_data) do
+ {
"id" => item_name,
"greeting" => "hello",
"nested" => {
"a1" => [1, 2, 3],
- "a2" => { "b1" => true }
- }
- }}
+ "a2" => { "b1" => true },
+ },
+ } end
let(:version) { 1 }
let(:encoded_data) do
@@ -83,7 +84,7 @@ describe Chef::EncryptedDataBagItem::CheckEncrypted do
end
end
- context "when encryption version is 3", :aes_256_gcm_only, :ruby_20_only do
+ context "when encryption version is 3", :aes_256_gcm_only, ruby: "~> 2.0.0" do
include_examples "encryption detected" do
let(:version) { 3 }
let(:encryptor) { Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor }
diff --git a/spec/unit/encrypted_data_bag_item_spec.rb b/spec/unit/encrypted_data_bag_item_spec.rb
index 0a4306727b..a8fb144bf7 100644
--- a/spec/unit/encrypted_data_bag_item_spec.rb
+++ b/spec/unit/encrypted_data_bag_item_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/encrypted_data_bag_item'
+require "spec_helper"
+require "chef/encrypted_data_bag_item"
module Version0Encryptor
def self.encrypt_value(plaintext_data, key)
@@ -32,10 +32,10 @@ module Version0Encryptor
end
end
-describe Chef::EncryptedDataBagItem::Encryptor do
+describe Chef::EncryptedDataBagItem::Encryptor do
subject(:encryptor) { described_class.new(plaintext_data, key) }
- let(:plaintext_data) { {"foo" => "bar"} }
+ let(:plaintext_data) { { "foo" => "bar" } }
let(:key) { "passwd" }
it "encrypts to format version 1 by default" do
@@ -67,7 +67,7 @@ describe Chef::EncryptedDataBagItem::Encryptor do
expect(final_data["encrypted_data"]).to eq encryptor.encrypted_data
expect(final_data["iv"]).to eq Base64.encode64(encryptor.iv)
expect(final_data["version"]).to eq 1
- expect(final_data["cipher"]).to eq"aes-256-cbc"
+ expect(final_data["cipher"]).to eq "aes-256-cbc"
end
end
@@ -97,7 +97,7 @@ describe Chef::EncryptedDataBagItem::Encryptor do
Chef::Config[:data_bag_encrypt_version] = 3
end
- context "on supported platforms", :aes_256_gcm_only, :ruby_20_only do
+ context "on supported platforms", :aes_256_gcm_only, ruby: "~> 2.0.0" do
it "creates a version 3 encryptor" do
expect(encryptor).to be_a_instance_of(Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor)
@@ -112,7 +112,7 @@ describe Chef::EncryptedDataBagItem::Encryptor do
it "includes the auth_tag in the envelope" do
final_data = encryptor.for_encrypted_item
- expect(final_data["auth_tag"]).to eq(Base64::encode64(encryptor.auth_tag))
+ expect(final_data["auth_tag"]).to eq(Base64.encode64(encryptor.auth_tag))
end
it "throws an error if auth tag is read before encrypting the data" do
@@ -149,10 +149,10 @@ end
describe Chef::EncryptedDataBagItem::Decryptor do
subject(:decryptor) { described_class.for(encrypted_value, decryption_key) }
- let(:plaintext_data) { {"foo" => "bar"} }
+ let(:plaintext_data) { { "foo" => "bar" } }
let(:encryption_key) { "passwd" }
let(:decryption_key) { encryption_key }
- let(:json_wrapped_data) { Chef::JSONCompat.to_json({"json_wrapper" => plaintext_data}) }
+ let(:json_wrapped_data) { Chef::JSONCompat.to_json({ "json_wrapper" => plaintext_data }) }
shared_examples "decryption examples" do
it "decrypts the encrypted value" do
@@ -166,7 +166,7 @@ describe Chef::EncryptedDataBagItem::Decryptor do
context "when decrypting a version 3 (JSON+aes-256-gcm+random iv+auth tag) encrypted value" do
- context "on supported platforms", :aes_256_gcm_only, :ruby_20_only do
+ context "on supported platforms", :aes_256_gcm_only, ruby: "~> 2.0.0" do
let(:encrypted_value) do
Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor.new(plaintext_data, encryption_key).for_encrypted_item
@@ -290,7 +290,7 @@ describe Chef::EncryptedDataBagItem::Decryptor do
end
- context "when decrypting a version 0 (YAML+aes-256-cbc+no iv) encrypted value" do
+ context "when decrypting a version 0 (YAML+aes-256-cbc+no iv) encrypted value", :not_supported_under_fips do
let(:encrypted_value) do
Version0Encryptor.encrypt_value(plaintext_data, encryption_key)
end
@@ -320,11 +320,12 @@ end
describe Chef::EncryptedDataBagItem do
subject { described_class }
let(:encrypted_data_bag_item) { subject.new(encoded_data, secret) }
- let(:plaintext_data) {{
+ let(:plaintext_data) do
+ {
"id" => "item_name",
"greeting" => "hello",
- "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true }}
- }}
+ "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true } },
+ } end
let(:secret) { "abc123SECRET" }
let(:encoded_data) { subject.encrypt_data_bag_item(plaintext_data, secret) }
diff --git a/spec/unit/environment_spec.rb b/spec/unit/environment_spec.rb
index 64617e0888..3daae16749 100644
--- a/spec/unit/environment_spec.rb
+++ b/spec/unit/environment_spec.rb
@@ -3,7 +3,7 @@
# Author:: Seth Falcon (<seth@ospcode.com>)
# Author:: John Keiser (<jkeiser@ospcode.com>)
# Author:: Kyle Goodwin (<kgoodwin@primerevenue.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,8 +19,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/environment'
+require "spec_helper"
+require "chef/environment"
describe Chef::Environment do
before(:each) do
@@ -73,12 +73,12 @@ describe Chef::Environment do
describe "default attributes" do
it "should let you set the attributes hash explicitly" do
- expect(@environment.default_attributes({ :one => 'two' })).to eq({ :one => 'two' })
+ expect(@environment.default_attributes({ :one => "two" })).to eq({ :one => "two" })
end
it "should let you return the attributes hash" do
- @environment.default_attributes({ :one => 'two' })
- expect(@environment.default_attributes).to eq({ :one => 'two' })
+ @environment.default_attributes({ :one => "two" })
+ expect(@environment.default_attributes).to eq({ :one => "two" })
end
it "should throw an ArgumentError if we aren't a kind of hash" do
@@ -88,12 +88,12 @@ describe Chef::Environment do
describe "override attributes" do
it "should let you set the attributes hash explicitly" do
- expect(@environment.override_attributes({ :one => 'two' })).to eq({ :one => 'two' })
+ expect(@environment.override_attributes({ :one => "two" })).to eq({ :one => "two" })
end
it "should let you return the attributes hash" do
- @environment.override_attributes({ :one => 'two' })
- expect(@environment.override_attributes).to eq({ :one => 'two' })
+ @environment.override_attributes({ :one => "two" })
+ expect(@environment.override_attributes).to eq({ :one => "two" })
end
it "should throw an ArgumentError if we aren't a kind of hash" do
@@ -106,7 +106,7 @@ describe Chef::Environment do
@cookbook_versions = {
"apt" => "= 1.0.0",
"god" => "= 2.0.0",
- "apache2" => "= 4.2.0"
+ "apache2" => "= 4.2.0",
}
end
@@ -167,7 +167,7 @@ describe Chef::Environment do
before(:each) do
@environment.name("spec")
@environment.description("Where we run the spec tests")
- @environment.cookbook_versions({:apt => "= 1.2.3"})
+ @environment.cookbook_versions({ :apt => "= 1.2.3" })
@hash = @environment.to_hash
end
@@ -190,7 +190,7 @@ describe Chef::Environment do
before(:each) do
@environment.name("spec")
@environment.description("Where we run the spec tests")
- @environment.cookbook_versions({:apt => "= 1.2.3"})
+ @environment.cookbook_versions({ :apt => "= 1.2.3" })
@json = @environment.to_json
end
@@ -221,12 +221,12 @@ describe Chef::Environment do
"cookbook_versions" => {
"apt" => "= 1.2.3",
"god" => ">= 4.2.0",
- "apache2" => "= 2.0.0"
+ "apache2" => "= 2.0.0",
},
"json_class" => "Chef::Environment",
- "chef_type" => "environment"
+ "chef_type" => "environment",
}
- @environment = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@data))
+ @environment = Chef::Environment.from_hash(Chef::JSONCompat.parse(Chef::JSONCompat.to_json(@data)))
end
it "should return a Chef::Environment" do
@@ -245,7 +245,7 @@ describe Chef::Environment do
@cookbook_versions = {
"apt" => "= 1.0.0",
"god" => "= 2.0.0",
- "apache2" => "= 4.2.0"
+ "apache2" => "= 4.2.0",
}
end
@@ -288,17 +288,17 @@ describe Chef::Environment do
describe "in solo mode" do
before do
- Chef::Config[:solo] = true
+ Chef::Config[:solo_legacy_mode] = true
end
after do
- Chef::Config[:solo] = false
+ Chef::Config[:solo_legacy_mode] = false
end
- it "should raise and exception" do
- expect {
+ it "should raise an exception" do
+ expect do
Chef::Environment.validate_cookbook_version("= 1.2.3.4")
- }.to raise_error Chef::Exceptions::IllegalVersionConstraint,
+ end.to raise_error Chef::Exceptions::IllegalVersionConstraint,
"Environment cookbook version constraints not allowed in chef-solo"
end
end
@@ -317,7 +317,7 @@ describe Chef::Environment do
it "validates the name given in the params" do
expect(@environment.update_from_params(:name => "@$%^&*()")).to be_falsey
- expect(@environment.invalid_fields[:name]).to eq(%q|Option name's value @$%^&*() does not match regular expression /^[\-[:alnum:]_]+$/|)
+ expect(@environment.invalid_fields[:name]).to eq(%q{Option name's value @$%^&*() does not match regular expression /^[\-[:alnum:]_]+$/})
end
it "updates the description from parameters[:description]" do
@@ -329,13 +329,13 @@ describe Chef::Environment do
# NOTE: I'm only choosing this (admittedly weird) structure for the hash b/c the better more obvious
# one, i.e, {:cookbook_version_constraints => {COOKBOOK_NAME => CONSTRAINT}} is difficult to implement
# the way merb does params
- params = {:name=>"superbowl", :cookbook_version => {"0" => "apache2 ~> 1.0.0", "1" => "nginx < 2.0.0"}}
+ params = { :name => "superbowl", :cookbook_version => { "0" => "apache2 ~> 1.0.0", "1" => "nginx < 2.0.0" } }
@environment.update_from_params(params)
- expect(@environment.cookbook_versions).to eq({"apache2" => "~> 1.0.0", "nginx" => "< 2.0.0"})
+ expect(@environment.cookbook_versions).to eq({ "apache2" => "~> 1.0.0", "nginx" => "< 2.0.0" })
end
it "validates the cookbook constraints" do
- params = {:cookbook_version => {"0" => "apache2 >>> 1.0.0"}}
+ params = { :cookbook_version => { "0" => "apache2 >>> 1.0.0" } }
expect(@environment.update_from_params(params)).to be_falsey
err_msg = @environment.invalid_fields[:cookbook_version]["0"]
expect(err_msg).to eq("apache2 >>> 1.0.0 is not a valid cookbook constraint")
@@ -353,20 +353,20 @@ describe Chef::Environment do
it "updates default attributes from a JSON string in params[:attributes]" do
@environment.update_from_params(:name => "fuuu", :default_attributes => %q|{"fuuu":"RAGE"}|)
- expect(@environment.default_attributes).to eq({"fuuu" => "RAGE"})
+ expect(@environment.default_attributes).to eq({ "fuuu" => "RAGE" })
end
it "updates override attributes from a JSON string in params[:attributes]" do
@environment.update_from_params(:name => "fuuu", :override_attributes => %q|{"foo":"override"}|)
- expect(@environment.override_attributes).to eq({"foo" => "override"})
+ expect(@environment.override_attributes).to eq({ "foo" => "override" })
end
end
describe "api model" do
before(:each) do
- @rest = double("Chef::REST")
- allow(Chef::REST).to receive(:new).and_return(@rest)
+ @rest = double("Chef::ServerAPI")
+ allow(Chef::ServerAPI).to receive(:new).and_return(@rest)
@query = double("Chef::Search::Query")
allow(Chef::Search::Query).to receive(:new).and_return(@query)
end
@@ -382,7 +382,7 @@ describe Chef::Environment do
end
it "should return a hash of environment names and urls" do
- expect(@rest).to receive(:get_rest).and_return({ "one" => "http://foo" })
+ expect(@rest).to receive(:get).and_return({ "one" => "http://foo" })
r = Chef::Environment.list
expect(r["one"]).to eq("http://foo")
end
@@ -392,77 +392,77 @@ describe Chef::Environment do
describe "when loading" do
describe "in solo mode" do
before do
- Chef::Config[:solo] = true
- Chef::Config[:environment_path] = '/var/chef/environments'
+ Chef::Config[:solo_legacy_mode] = true
+ Chef::Config[:environment_path] = "/var/chef/environments"
end
after do
- Chef::Config[:solo] = false
+ Chef::Config[:solo_legacy_mode] = false
end
it "should get the environment from the environment_path" do
expect(File).to receive(:directory?).with(Chef::Config[:environment_path]).and_return(true)
- expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(false)
- expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).exactly(2).times.and_return(true)
- expect(File).to receive(:readable?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(true)
- role_dsl="name \"foo\"\ndescription \"desc\"\n"
- expect(IO).to receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(role_dsl)
- Chef::Environment.load('foo')
+ expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.json")).and_return(false)
+ expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.rb")).exactly(2).times.and_return(true)
+ expect(File).to receive(:readable?).with(File.join(Chef::Config[:environment_path], "foo.rb")).and_return(true)
+ role_dsl = "name \"foo\"\ndescription \"desc\"\n"
+ expect(IO).to receive(:read).with(File.join(Chef::Config[:environment_path], "foo.rb")).and_return(role_dsl)
+ Chef::Environment.load("foo")
end
it "should return a Chef::Environment object from JSON" do
expect(File).to receive(:directory?).with(Chef::Config[:environment_path]).and_return(true)
- expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(true)
+ expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.json")).and_return(true)
environment_hash = {
"name" => "foo",
"default_attributes" => {
"foo" => {
- "bar" => 1
- }
+ "bar" => 1,
+ },
},
"json_class" => "Chef::Environment",
"description" => "desc",
- "chef_type" => "environment"
+ "chef_type" => "environment",
}
- expect(IO).to receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(Chef::JSONCompat.to_json(environment_hash))
- environment = Chef::Environment.load('foo')
+ expect(IO).to receive(:read).with(File.join(Chef::Config[:environment_path], "foo.json")).and_return(Chef::JSONCompat.to_json(environment_hash))
+ environment = Chef::Environment.load("foo")
expect(environment).to be_a_kind_of(Chef::Environment)
- expect(environment.name).to eq(environment_hash['name'])
- expect(environment.description).to eq(environment_hash['description'])
- expect(environment.default_attributes).to eq(environment_hash['default_attributes'])
+ expect(environment.name).to eq(environment_hash["name"])
+ expect(environment.description).to eq(environment_hash["description"])
+ expect(environment.default_attributes).to eq(environment_hash["default_attributes"])
end
it "should return a Chef::Environment object from Ruby DSL" do
expect(File).to receive(:directory?).with(Chef::Config[:environment_path]).and_return(true)
- expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(false)
- expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).exactly(2).times.and_return(true)
- expect(File).to receive(:readable?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(true)
- role_dsl="name \"foo\"\ndescription \"desc\"\n"
- expect(IO).to receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(role_dsl)
- environment = Chef::Environment.load('foo')
+ expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.json")).and_return(false)
+ expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.rb")).exactly(2).times.and_return(true)
+ expect(File).to receive(:readable?).with(File.join(Chef::Config[:environment_path], "foo.rb")).and_return(true)
+ role_dsl = "name \"foo\"\ndescription \"desc\"\n"
+ expect(IO).to receive(:read).with(File.join(Chef::Config[:environment_path], "foo.rb")).and_return(role_dsl)
+ environment = Chef::Environment.load("foo")
expect(environment).to be_a_kind_of(Chef::Environment)
- expect(environment.name).to eq('foo')
- expect(environment.description).to eq('desc')
+ expect(environment.name).to eq("foo")
+ expect(environment.description).to eq("desc")
end
- it 'should raise an error if the configured environment_path is invalid' do
+ it "should raise an error if the configured environment_path is invalid" do
expect(File).to receive(:directory?).with(Chef::Config[:environment_path]).and_return(false)
- expect {
- Chef::Environment.load('foo')
- }.to raise_error Chef::Exceptions::InvalidEnvironmentPath, "Environment path '/var/chef/environments' is invalid"
+ expect do
+ Chef::Environment.load("foo")
+ end.to raise_error Chef::Exceptions::InvalidEnvironmentPath, "Environment path '/var/chef/environments' is invalid"
end
- it 'should raise an error if the file does not exist' do
+ it "should raise an error if the file does not exist" do
expect(File).to receive(:directory?).with(Chef::Config[:environment_path]).and_return(true)
- expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(false)
- expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(false)
+ expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.json")).and_return(false)
+ expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.rb")).and_return(false)
- expect {
- Chef::Environment.load('foo')
- }.to raise_error Chef::Exceptions::EnvironmentNotFound, "Environment 'foo' could not be loaded from disk"
+ expect do
+ Chef::Environment.load("foo")
+ end.to raise_error Chef::Exceptions::EnvironmentNotFound, "Environment 'foo' could not be loaded from disk"
end
end
end
diff --git a/spec/unit/event_dispatch/dispatcher_spec.rb b/spec/unit/event_dispatch/dispatcher_spec.rb
index 5a06e1d6d1..5061a9845f 100644
--- a/spec/unit/event_dispatch/dispatcher_spec.rb
+++ b/spec/unit/event_dispatch/dispatcher_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Daniel DeLeo (<dan@chef.io>)
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/event_dispatch/dispatcher'
+require "spec_helper"
+require "chef/event_dispatch/dispatcher"
describe Chef::EventDispatch::Dispatcher do
@@ -52,8 +52,8 @@ describe Chef::EventDispatch::Dispatcher do
dispatcher.synchronized_cookbook("apache2", cookbook_version)
exception = StandardError.new("foo")
- expect(event_sink).to receive(:recipe_file_load_failed).with("/path/to/file.rb", exception)
- dispatcher.recipe_file_load_failed("/path/to/file.rb", exception)
+ expect(event_sink).to receive(:recipe_file_load_failed).with("/path/to/file.rb", exception, "myrecipe")
+ dispatcher.recipe_file_load_failed("/path/to/file.rb", exception, "myrecipe")
end
context "when an event sink has fewer arguments for an event" do
@@ -75,7 +75,6 @@ describe Chef::EventDispatch::Dispatcher do
end
end
-
context "when two event sinks have different arguments for an event" do
let(:event_sink_1) do
Class.new(Chef::EventDispatch::Base) do
diff --git a/spec/unit/event_dispatch/dsl_spec.rb b/spec/unit/event_dispatch/dsl_spec.rb
index 0f7adce7a8..979b067fb6 100644
--- a/spec/unit/event_dispatch/dsl_spec.rb
+++ b/spec/unit/event_dispatch/dsl_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Ranjib Dey (<ranjib@linux.com>)
#
-# Copyright:: Copyright (c) 2015 Ranjib Dey
+# Copyright:: Copyright 2015-2016, Ranjib Dey
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/event_dispatch/dsl'
+require "spec_helper"
+require "chef/event_dispatch/dsl"
describe Chef::EventDispatch::DSL do
let(:events) do
@@ -32,25 +32,25 @@ describe Chef::EventDispatch::DSL do
Chef.set_run_context(run_context)
end
- subject{ described_class.new('test') }
+ subject { described_class.new("test") }
- it 'set handler name' do
+ it "set handler name" do
subject.on(:run_started) {}
- expect(events.subscribers.first.name).to eq('test')
+ expect(events.subscribers.first.name).to eq("test")
end
- it 'raise error when invalid event type is supplied' do
+ it "raise error when invalid event type is supplied" do
expect do
subject.on(:foo_bar) {}
end.to raise_error(Chef::Exceptions::InvalidEventType)
end
- it 'register user hooks against valid event type' do
- subject.on(:run_failed) {'testhook'}
- expect(events.subscribers.first.run_failed).to eq('testhook')
+ it "register user hooks against valid event type" do
+ subject.on(:run_failed) { "testhook" }
+ expect(events.subscribers.first.run_failed).to eq("testhook")
end
- it 'preserve state across event hooks' do
+ it "preserve state across event hooks" do
calls = []
Chef.event_handler do
on :resource_updated do
@@ -60,13 +60,13 @@ describe Chef::EventDispatch::DSL do
calls << :started
end
end
- resource = Chef::Resource::RubyBlock.new('foo', run_context)
- resource.block { }
+ resource = Chef::Resource::RubyBlock.new("foo", run_context)
+ resource.block {}
resource.run_action(:run)
expect(calls).to eq([:started, :updated])
end
- it 'preserve instance variables across handler callbacks' do
+ it "preserve instance variables across handler callbacks" do
Chef.event_handler do
on :resource_action_start do
@ivar = [1]
@@ -75,8 +75,8 @@ describe Chef::EventDispatch::DSL do
@ivar << 2
end
end
- resource = Chef::Resource::RubyBlock.new('foo', run_context)
- resource.block { }
+ resource = Chef::Resource::RubyBlock.new("foo", run_context)
+ resource.block {}
resource.run_action(:run)
expect(events.subscribers.first.instance_variable_get(:@ivar)).to eq([1, 2])
end
diff --git a/spec/unit/exceptions_spec.rb b/spec/unit/exceptions_spec.rb
index 85c54aa693..e952a5448a 100644
--- a/spec/unit/exceptions_spec.rb
+++ b/spec/unit/exceptions_spec.rb
@@ -1,9 +1,9 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
+# Author:: Christopher Walters (<cw@chef.io>)
# Author:: Kyle Goodwin (<kgoodwin@primerevenue.com>)
-# Copyright:: Copyright (c) 2010 Thomas Bishop
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Thomas Bishop
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Exceptions do
exception_to_super_class = {
@@ -67,12 +67,14 @@ describe Chef::Exceptions do
Chef::Exceptions::InvalidEnvironmentPath => ArgumentError,
Chef::Exceptions::EnvironmentNotFound => RuntimeError,
Chef::Exceptions::InvalidVersionConstraint => ArgumentError,
- Chef::Exceptions::IllegalVersionConstraint => NotImplementedError
+ Chef::Exceptions::IllegalVersionConstraint => NotImplementedError,
+ Chef::Exceptions::RegKeyValuesTypeMissing => ArgumentError,
+ Chef::Exceptions::RegKeyValuesDataMissing => ArgumentError,
}
exception_to_super_class.each do |exception, expected_super_class|
it "should have an exception class of #{exception} which inherits from #{expected_super_class}" do
- expect{ raise exception }.to raise_error(expected_super_class)
+ expect { raise exception }.to raise_error(expected_super_class)
end
if exception.methods.include?(:to_json)
@@ -95,7 +97,7 @@ describe Chef::Exceptions do
end
context "initialized with nothing" do
- let(:e) { Chef::Exceptions::RunFailedWrappingError.new }
+ let(:e) { Chef::Exceptions::RunFailedWrappingError.new }
let(:num_errors) { 0 }
let(:backtrace) { [] }
@@ -103,7 +105,7 @@ describe Chef::Exceptions do
end
context "initialized with nil" do
- let(:e) { Chef::Exceptions::RunFailedWrappingError.new(nil, nil) }
+ let(:e) { Chef::Exceptions::RunFailedWrappingError.new(nil, nil) }
let(:num_errors) { 0 }
let(:backtrace) { [] }
@@ -111,7 +113,7 @@ describe Chef::Exceptions do
end
context "initialized with 1 error and nil" do
- let(:e) { Chef::Exceptions::RunFailedWrappingError.new(RuntimeError.new("foo"), nil) }
+ let(:e) { Chef::Exceptions::RunFailedWrappingError.new(RuntimeError.new("foo"), nil) }
let(:num_errors) { 1 }
let(:backtrace) { ["1) RuntimeError - foo"] }
@@ -119,7 +121,7 @@ describe Chef::Exceptions do
end
context "initialized with 2 errors" do
- let(:e) { Chef::Exceptions::RunFailedWrappingError.new(RuntimeError.new("foo"), RuntimeError.new("bar")) }
+ let(:e) { Chef::Exceptions::RunFailedWrappingError.new(RuntimeError.new("foo"), RuntimeError.new("bar")) }
let(:num_errors) { 2 }
let(:backtrace) { ["1) RuntimeError - foo", "", "2) RuntimeError - bar"] }
diff --git a/spec/unit/file_access_control_spec.rb b/spec/unit/file_access_control_spec.rb
index 2c68792c63..ee806b5c3a 100644
--- a/spec/unit/file_access_control_spec.rb
+++ b/spec/unit/file_access_control_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::FileAccessControl do
describe "Unix" do
@@ -27,14 +27,14 @@ describe Chef::FileAccessControl do
# platform specific module is mixed in
@node = Chef::Node.new
load File.join(File.dirname(__FILE__), "..", "..", "lib", "chef", "file_access_control.rb")
- @resource = Chef::Resource::File.new('/tmp/a_file.txt')
- @resource.owner('toor')
- @resource.group('wheel')
- @resource.mode('0400')
+ @resource = Chef::Resource::File.new("/tmp/a_file.txt")
+ @resource.owner("toor")
+ @resource.group("wheel")
+ @resource.mode("0400")
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @current_resource = Chef::Resource::File.new('/tmp/different_file.txt')
+ @current_resource = Chef::Resource::File.new("/tmp/different_file.txt")
@provider_requirements = Chef::Provider::ResourceRequirements.new(@resource, @run_context)
@provider = double("File provider", :requirements => @provider_requirements, :manage_symlink_access? => false)
@@ -42,8 +42,8 @@ describe Chef::FileAccessControl do
end
end
- describe 'class methods' do
- it 'responds to #writable?' do
+ describe "class methods" do
+ it "responds to #writable?" do
expect(Chef::FileAccessControl).to respond_to(:writable?)
end
end
@@ -53,7 +53,7 @@ describe Chef::FileAccessControl do
end
it "has a file to manage" do
- expect(@fac.file).to eq('/tmp/different_file.txt')
+ expect(@fac.file).to eq("/tmp/different_file.txt")
end
it "is not modified yet" do
@@ -61,13 +61,13 @@ describe Chef::FileAccessControl do
end
it "determines the uid of the owner specified by the resource" do
- expect(Etc).to receive(:getpwnam).with('toor').and_return(OpenStruct.new(:uid => 2342))
+ expect(Etc).to receive(:getpwnam).with("toor").and_return(OpenStruct.new(:uid => 2342))
expect(@fac.target_uid).to eq(2342)
end
it "raises a Chef::Exceptions::UserIDNotFound error when Etc can't find the user's name" do
- expect(Etc).to receive(:getpwnam).with('toor').and_raise(ArgumentError)
- expect { @fac.target_uid ; @provider_requirements.run(:create) }.to raise_error(Chef::Exceptions::UserIDNotFound, "cannot determine user id for 'toor', does the user exist on this system?")
+ expect(Etc).to receive(:getpwnam).with("toor").and_raise(ArgumentError)
+ expect { @fac.target_uid; @provider_requirements.run(:create) }.to raise_error(Chef::Exceptions::UserIDNotFound, "cannot determine user id for 'toor', does the user exist on this system?")
end
it "does not attempt to resolve the uid if the user is not specified" do
@@ -84,7 +84,7 @@ describe Chef::FileAccessControl do
it "raises an ArgumentError if the resource's owner is set to something wack" do
@resource.instance_variable_set(:@owner, :diaf)
- expect { @fac.target_uid ; @provider_requirements.run(:create) }.to raise_error(ArgumentError)
+ expect { @fac.target_uid; @provider_requirements.run(:create) }.to raise_error(ArgumentError)
end
it "uses the resource's uid for the target uid when the resource's owner is specified by an integer" do
@@ -98,16 +98,16 @@ describe Chef::FileAccessControl do
# complement (i.e., it wraps around the maximum size of C unsigned int) of these
# uids. So we have to get ruby and negative uids to smoke the peace pipe
# with each other.
- @resource.owner('nobody')
- expect(Etc).to receive(:getpwnam).with('nobody').and_return(OpenStruct.new(:uid => (4294967294)))
+ @resource.owner("nobody")
+ expect(Etc).to receive(:getpwnam).with("nobody").and_return(OpenStruct.new(:uid => (4294967294)))
expect(@fac.target_uid).to eq(-2)
end
it "does not wrap uids to their negative complements beyond -9" do
# More: when OSX userIDs are created by ActiveDirectory sync, it tends to use huge numbers
# which had been incorrectly wrapped. It does not look like the OSX IDs go below -2
- @resource.owner('bigdude')
- expect(Etc).to receive(:getpwnam).with('bigdude').and_return(OpenStruct.new(:uid => (4294967286)))
+ @resource.owner("bigdude")
+ expect(Etc).to receive(:getpwnam).with("bigdude").and_return(OpenStruct.new(:uid => (4294967286)))
expect(@fac.target_uid).to eq(4294967286)
end
@@ -133,7 +133,7 @@ describe Chef::FileAccessControl do
it "sets the file's owner as specified in the resource when the current owner is incorrect" do
@resource.owner(2342)
- expect(File).to receive(:chown).with(2342, nil, '/tmp/different_file.txt')
+ expect(File).to receive(:chown).with(2342, nil, "/tmp/different_file.txt")
@fac.set_owner
expect(@fac).to be_modified
end
@@ -153,7 +153,7 @@ describe Chef::FileAccessControl do
end
it "determines the gid of the group specified by the resource" do
- expect(Etc).to receive(:getgrnam).with('wheel').and_return(OpenStruct.new(:gid => 2342))
+ expect(Etc).to receive(:getgrnam).with("wheel").and_return(OpenStruct.new(:gid => 2342))
expect(@fac.target_gid).to eq(2342)
end
@@ -163,18 +163,18 @@ describe Chef::FileAccessControl do
end
it "raises a Chef::Exceptions::GroupIDNotFound error when Etc can't find the user's name" do
- expect(Etc).to receive(:getgrnam).with('wheel').and_raise(ArgumentError)
+ expect(Etc).to receive(:getgrnam).with("wheel").and_raise(ArgumentError)
expect { @fac.target_gid; @provider_requirements.run(:create) }.to raise_error(Chef::Exceptions::GroupIDNotFound, "cannot determine group id for 'wheel', does the group exist on this system?")
end
it "does not attempt to resolve a gid when none is supplied" do
- resource = Chef::Resource::File.new('crab')
+ resource = Chef::Resource::File.new("crab")
fac = Chef::FileAccessControl.new(@current_resource, resource, @provider)
expect(fac.target_gid).to be_nil
end
it "does not want to update the group when no target group is specified" do
- resource = Chef::Resource::File.new('crab')
+ resource = Chef::Resource::File.new("crab")
fac = Chef::FileAccessControl.new(@current_resource, resource, @provider)
expect(fac.should_update_group?).to be_falsey
end
@@ -197,7 +197,7 @@ describe Chef::FileAccessControl do
end
it "includes updating the group in the list of changes" do
- resource = Chef::Resource::File.new('crab')
+ resource = Chef::Resource::File.new("crab")
resource.group(2342)
@current_resource.group(815)
fac = Chef::FileAccessControl.new(@current_resource, resource, @provider)
@@ -208,7 +208,7 @@ describe Chef::FileAccessControl do
@resource.group(2342)
@current_resource.group(815)
- expect(File).to receive(:chown).with(nil, 2342, '/tmp/different_file.txt')
+ expect(File).to receive(:chown).with(nil, 2342, "/tmp/different_file.txt")
@fac.set_group
expect(@fac).to be_modified
end
@@ -230,7 +230,7 @@ describe Chef::FileAccessControl do
end
it "uses the supplied mode as octal when it's a string" do
- @resource.mode('444')
+ @resource.mode("444")
expect(@fac.target_mode).to eq(292) # octal 444 => decimal 292
end
@@ -240,13 +240,13 @@ describe Chef::FileAccessControl do
end
it "does not try to determine the mode when none is given" do
- resource = Chef::Resource::File.new('blahblah')
+ resource = Chef::Resource::File.new("blahblah")
fac = Chef::FileAccessControl.new(@current_resource, resource, @provider)
expect(fac.target_mode).to be_nil
end
it "doesn't want to update the mode when no target mode is given" do
- resource = Chef::Resource::File.new('blahblah')
+ resource = Chef::Resource::File.new("blahblah")
fac = Chef::FileAccessControl.new(@current_resource, resource, @provider)
expect(fac.should_update_mode?).to be_falsey
end
@@ -264,7 +264,7 @@ describe Chef::FileAccessControl do
end
it "includes changing the mode in the list of desired changes" do
- resource = Chef::Resource::File.new('blahblah')
+ resource = Chef::Resource::File.new("blahblah")
resource.mode("0750")
@current_resource.mode("0444")
fac = Chef::FileAccessControl.new(@current_resource, resource, @provider)
@@ -275,7 +275,7 @@ describe Chef::FileAccessControl do
# stat returns modes like 0100644 (octal) => 33188 (decimal)
#@fac.stub(:stat).and_return(OpenStruct.new(:mode => 33188))
@current_resource.mode("0644")
- expect(File).to receive(:chmod).with(256, '/tmp/different_file.txt')
+ expect(File).to receive(:chmod).with(256, "/tmp/different_file.txt")
@fac.set_mode
expect(@fac).to be_modified
end
@@ -298,9 +298,9 @@ describe Chef::FileAccessControl do
@resource.mode(0400)
@resource.owner(0)
@resource.group(0)
- expect(File).to receive(:chmod).with(0400, '/tmp/different_file.txt')
- expect(File).to receive(:chown).with(0, nil, '/tmp/different_file.txt')
- expect(File).to receive(:chown).with(nil, 0, '/tmp/different_file.txt')
+ expect(File).to receive(:chmod).with(0400, "/tmp/different_file.txt")
+ expect(File).to receive(:chown).with(0, nil, "/tmp/different_file.txt")
+ expect(File).to receive(:chown).with(nil, 0, "/tmp/different_file.txt")
@fac.set_all
expect(@fac).to be_modified
end
diff --git a/spec/unit/file_cache_spec.rb b/spec/unit/file_cache_spec.rb
index a24c3d3b97..388b0e746a 100644
--- a/spec/unit/file_cache_spec.rb
+++ b/spec/unit/file_cache_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::FileCache do
before do
@@ -32,11 +32,11 @@ describe Chef::FileCache do
describe "when the relative path to the cache file doesn't exist" do
it "creates intermediate directories as needed" do
Chef::FileCache.store("whiz/bang", "I found a poop")
- expect(File).to exist(File.join(@file_cache_path, 'whiz'))
+ expect(File).to exist(File.join(@file_cache_path, "whiz"))
end
it "creates the cached file at the correct relative path" do
- expect(File).to receive(:open).with(File.join(@file_cache_path, 'whiz', 'bang'), "w",416).and_yield(@io)
+ expect(File).to receive(:open).with(File.join(@file_cache_path, "whiz", "bang"), "w", 416).and_yield(@io)
Chef::FileCache.store("whiz/bang", "borkborkbork")
end
@@ -56,35 +56,35 @@ describe Chef::FileCache do
describe "when loading cached files" do
it "finds and reads the cached file" do
- FileUtils.mkdir_p(File.join(@file_cache_path, 'whiz'))
- File.open(File.join(@file_cache_path, 'whiz', 'bang'), 'w') { |f| f.print("borkborkbork") }
- expect(Chef::FileCache.load('whiz/bang')).to eq('borkborkbork')
+ FileUtils.mkdir_p(File.join(@file_cache_path, "whiz"))
+ File.open(File.join(@file_cache_path, "whiz", "bang"), "w") { |f| f.print("borkborkbork") }
+ expect(Chef::FileCache.load("whiz/bang")).to eq("borkborkbork")
end
it "should raise a Chef::Exceptions::FileNotFound if the file doesn't exist" do
- expect { Chef::FileCache.load('whiz/bang') }.to raise_error(Chef::Exceptions::FileNotFound)
+ expect { Chef::FileCache.load("whiz/bang") }.to raise_error(Chef::Exceptions::FileNotFound)
end
end
describe "when deleting cached files" do
before(:each) do
- FileUtils.mkdir_p(File.join(@file_cache_path, 'whiz'))
- File.open(File.join(@file_cache_path, 'whiz', 'bang'), 'w') { |f| f.print("borkborkbork") }
+ FileUtils.mkdir_p(File.join(@file_cache_path, "whiz"))
+ File.open(File.join(@file_cache_path, "whiz", "bang"), "w") { |f| f.print("borkborkbork") }
end
it "unlinks the file" do
Chef::FileCache.delete("whiz/bang")
- expect(File).not_to exist(File.join(@file_cache_path, 'whiz', 'bang'))
+ expect(File).not_to exist(File.join(@file_cache_path, "whiz", "bang"))
end
end
describe "when listing files in the cache" do
before(:each) do
- FileUtils.mkdir_p(File.join(@file_cache_path, 'whiz'))
- FileUtils.touch(File.join(@file_cache_path, 'whiz', 'bang'))
- FileUtils.mkdir_p(File.join(@file_cache_path, 'snappy'))
- FileUtils.touch(File.join(@file_cache_path, 'snappy', 'patter'))
+ FileUtils.mkdir_p(File.join(@file_cache_path, "whiz"))
+ FileUtils.touch(File.join(@file_cache_path, "whiz", "bang"))
+ FileUtils.mkdir_p(File.join(@file_cache_path, "snappy"))
+ FileUtils.touch(File.join(@file_cache_path, "snappy", "patter"))
end
it "should return the relative paths" do
@@ -92,18 +92,18 @@ describe Chef::FileCache do
end
it "searches for cached files by globbing" do
- expect(Chef::FileCache.find('snappy/**/*')).to eq(%w{snappy/patter})
+ expect(Chef::FileCache.find("snappy/**/*")).to eq(%w{snappy/patter})
end
end
describe "when checking for the existence of a file" do
before do
- FileUtils.mkdir_p(File.join(@file_cache_path, 'whiz'))
+ FileUtils.mkdir_p(File.join(@file_cache_path, "whiz"))
end
it "has a key if the corresponding cache file exists" do
- FileUtils.touch(File.join(@file_cache_path, 'whiz', 'bang'))
+ FileUtils.touch(File.join(@file_cache_path, "whiz", "bang"))
expect(Chef::FileCache).to have_key("whiz/bang")
end
diff --git a/spec/unit/file_content_management/deploy/cp_spec.rb b/spec/unit/file_content_management/deploy/cp_spec.rb
index 5c6583e8a6..cbdb4f1425 100644
--- a/spec/unit/file_content_management/deploy/cp_spec.rb
+++ b/spec/unit/file_content_management/deploy/cp_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::FileContentManagement::Deploy::Cp do
@@ -42,5 +42,3 @@ describe Chef::FileContentManagement::Deploy::Cp do
end
end
-
-
diff --git a/spec/unit/file_content_management/deploy/mv_unix_spec.rb b/spec/unit/file_content_management/deploy/mv_unix_spec.rb
index 4511f91180..569fd898a7 100644
--- a/spec/unit/file_content_management/deploy/mv_unix_spec.rb
+++ b/spec/unit/file_content_management/deploy/mv_unix_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::FileContentManagement::Deploy::MvUnix do
@@ -99,5 +99,3 @@ describe Chef::FileContentManagement::Deploy::MvUnix do
end
end
-
-
diff --git a/spec/unit/file_content_management/deploy/mv_windows_spec.rb b/spec/unit/file_content_management/deploy/mv_windows_spec.rb
index 2d1981befc..30a62c4da9 100644
--- a/spec/unit/file_content_management/deploy/mv_windows_spec.rb
+++ b/spec/unit/file_content_management/deploy/mv_windows_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
unless Chef::Platform.windows?
class Chef
@@ -31,7 +31,7 @@ unless Chef::Platform.windows?
end
end
-require 'chef/file_content_management/deploy/mv_windows'
+require "chef/file_content_management/deploy/mv_windows"
describe Chef::FileContentManagement::Deploy::MvWindows do
@@ -72,7 +72,7 @@ describe Chef::FileContentManagement::Deploy::MvWindows do
end
it "errors out with a WindowsNotAdmin error" do
- expect { content_deployer.deploy(staging_file_path, target_file_path)}.to raise_error(Chef::Exceptions::WindowsNotAdmin)
+ expect { content_deployer.deploy(staging_file_path, target_file_path) }.to raise_error(Chef::Exceptions::WindowsNotAdmin)
end
end
@@ -92,7 +92,6 @@ describe Chef::FileContentManagement::Deploy::MvWindows do
double "security descriptor for target file"
end
-
before do
allow(target_file_security_object).to receive(:security_descriptor).and_return(target_file_security_descriptor)
@@ -130,7 +129,6 @@ describe Chef::FileContentManagement::Deploy::MvWindows do
expect(updated_target_security_object).to receive(:set_sacl).with(nil, false)
end
-
it "fixes up permissions and moves the file into place" do
content_deployer.deploy(staging_file_path, target_file_path)
end
@@ -154,7 +152,6 @@ describe Chef::FileContentManagement::Deploy::MvWindows do
with([]).
and_return(empty_dacl)
-
allow(target_file_security_descriptor).to receive(:sacl_present?).and_return(true)
allow(target_file_security_descriptor).to receive(:sacl_inherits?).and_return(false)
@@ -164,12 +161,10 @@ describe Chef::FileContentManagement::Deploy::MvWindows do
with([]).
and_return(empty_sacl)
-
expect(updated_target_security_object).to receive(:set_dacl).with(empty_dacl, false)
expect(updated_target_security_object).to receive(:set_sacl).with(empty_sacl, false)
end
-
it "fixes up permissions and moves the file into place" do
content_deployer.deploy(staging_file_path, target_file_path)
end
@@ -235,5 +230,3 @@ describe Chef::FileContentManagement::Deploy::MvWindows do
end
end
-
-
diff --git a/spec/unit/file_content_management/tempfile_spec.rb b/spec/unit/file_content_management/tempfile_spec.rb
new file mode 100644
index 0000000000..a04ace5f16
--- /dev/null
+++ b/spec/unit/file_content_management/tempfile_spec.rb
@@ -0,0 +1,115 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright 2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::FileContentManagement::Tempfile do
+
+ def tempfile_object_for_path(path)
+ r = Chef::Resource::File.new("decorative name that should not matter")
+ r.path path
+ Chef::FileContentManagement::Tempfile.new(r)
+ end
+
+ describe "#tempfile_basename" do
+ it "should return a dotfile", :unix_only do
+ subject = tempfile_object_for_path("/foo/bar/new_file")
+ expect(subject.send(:tempfile_basename)).to eql(".chef-new_file")
+ end
+
+ it "should return a file", :windows_only do
+ subject = tempfile_object_for_path("/foo/bar/new_file")
+ expect(subject.send(:tempfile_basename)).to eql("chef-new_file")
+ end
+
+ it "should strip the extension", :unix_only do
+ subject = tempfile_object_for_path("/foo/bar/new_file.html.erb")
+ expect(subject.send(:tempfile_basename)).to eql(".chef-new_file")
+ end
+
+ it "should strip the extension", :windows_only do
+ subject = tempfile_object_for_path("/foo/bar/new_file.html.erb")
+ expect(subject.send(:tempfile_basename)).to eql("chef-new_file")
+ end
+ end
+
+ describe "#tempfile_extension" do
+ it "should preserve the file extension" do
+ subject = tempfile_object_for_path("/foo/bar/new_file.html.erb")
+ expect(subject.send(:tempfile_extension)).to eql(".html.erb")
+ end
+ end
+
+ describe "#tempfile_dirnames" do
+
+ it "should select a temp dir" do
+ subject = tempfile_object_for_path("/foo/bar/new_file")
+ Chef::Config[:file_staging_uses_destdir] = false
+ expect(Dir).to receive(:tmpdir).and_return("/tmp/dir")
+ expect(subject.send(:tempfile_dirnames)).to eql(%w{ /tmp/dir })
+ end
+
+ it "should select the destdir" do
+ subject = tempfile_object_for_path("/foo/bar/new_file")
+ Chef::Config[:file_staging_uses_destdir] = true
+ expect(subject.send(:tempfile_dirnames)).to eql(%w{ /foo/bar })
+ end
+
+ it "should select the destdir and a temp dir" do
+ subject = tempfile_object_for_path("/foo/bar/new_file")
+ Chef::Config[:file_staging_uses_destdir] = :auto
+ expect(Dir).to receive(:tmpdir).and_return("/tmp/dir")
+ expect(subject.send(:tempfile_dirnames)).to eql(%w{ /foo/bar /tmp/dir })
+ end
+ end
+
+ describe "#tempfile_open" do
+ let(:tempfile) { instance_double("Tempfile") }
+ let(:tempname) { windows? ? "chef-new_file" : ".chef-new_file" }
+
+ before do
+ Chef::Config[:file_staging_uses_destdir] = :auto
+ allow(tempfile).to receive(:binmode).and_return(true)
+ end
+
+ it "should create a temporary file" do
+ subject = tempfile_object_for_path("/foo/bar/new_file")
+ expect(subject.send(:tempfile_open)).to be_a(Tempfile)
+ end
+
+ it "should preserve the extension in the tempfile path" do
+ subject = tempfile_object_for_path("/foo/bar/new_file.html.erb")
+ tempfile = subject.send(:tempfile_open)
+ expect(tempfile.path).to match(/chef-new_file.*\.html\.erb$/)
+ end
+
+ it "should pick the destdir preferrentially" do
+ subject = tempfile_object_for_path("/foo/bar/new_file")
+ expect(Tempfile).to receive(:open).with([tempname, ""], "/foo/bar").and_return(tempfile)
+ subject.send(:tempfile_open)
+ end
+
+ it "should use ENV['TMP'] otherwise" do
+ subject = tempfile_object_for_path("/foo/bar/new_file")
+ expect(Dir).to receive(:tmpdir).and_return("/tmp/dir")
+ expect(Tempfile).to receive(:open).with([tempname, ""], "/foo/bar").and_raise(SystemCallError, "foo")
+ expect(Tempfile).to receive(:open).with([tempname, ""], "/tmp/dir").and_return(tempfile)
+ subject.send(:tempfile_open)
+ end
+ end
+end
diff --git a/spec/unit/formatters/base_spec.rb b/spec/unit/formatters/base_spec.rb
index 6a843ea775..30c7757e5a 100644
--- a/spec/unit/formatters/base_spec.rb
+++ b/spec/unit/formatters/base_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Lamont Granquist (<lamont@getchef.com>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
#
-# Copyright:: Copyright (c) 2012 Chef Software, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +17,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Formatters::Base do
- let(:out) { double("out") }
- let(:err) { double("err") }
+ let(:out) { StringIO.new }
+ let(:err) { StringIO.new }
let(:formatter) { Chef::Formatters::Base.new(out, err) }
it "starts with an indentation of zero" do
@@ -43,6 +43,29 @@ describe Chef::Formatters::Base do
formatter.indent_by(-2)
expect(formatter.output.indent).to eql(0)
end
-end
+ it "humanizes EOFError exceptions for #registration_failed" do
+ formatter.registration_failed("foo.example.com", EOFError.new, double("Chef::Config"))
+ expect(out.string).to match(/Received an EOF on transport socket/)
+ end
+
+ it "humanizes EOFError exceptions for #node_load_failed" do
+ formatter.node_load_failed("foo.example.com", EOFError.new, double("Chef::Config"))
+ expect(out.string).to match(/Received an EOF on transport socket/)
+ end
+
+ it "humanizes EOFError exceptions for #run_list_expand_failed" do
+ formatter.run_list_expand_failed(double("Chef::Node"), EOFError.new)
+ expect(out.string).to match(/Received an EOF on transport socket/)
+ end
+
+ it "humanizes EOFError exceptions for #cookbook_resolution_failed" do
+ formatter.run_list_expand_failed(double("Expanded Run List"), EOFError.new)
+ expect(out.string).to match(/Received an EOF on transport socket/)
+ end
+ it "humanizes EOFError exceptions for #cookbook_sync_failed" do
+ formatter.cookbook_sync_failed("foo.example.com", EOFError.new)
+ expect(out.string).to match(/Received an EOF on transport socket/)
+ end
+end
diff --git a/spec/unit/formatters/doc_spec.rb b/spec/unit/formatters/doc_spec.rb
index 7266afc320..b8eccc1bc9 100644
--- a/spec/unit/formatters/doc_spec.rb
+++ b/spec/unit/formatters/doc_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Daniel DeLeo (<dan@chef.io>)
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Formatters::Base do
@@ -28,15 +28,15 @@ describe Chef::Formatters::Base do
it "prints a policyfile's name and revision ID" do
minimal_policyfile = {
- "revision_id"=> "613f803bdd035d574df7fa6da525b38df45a74ca82b38b79655efed8a189e073",
- "name"=> "jenkins",
- "run_list"=> [
+ "revision_id" => "613f803bdd035d574df7fa6da525b38df45a74ca82b38b79655efed8a189e073",
+ "name" => "jenkins",
+ "run_list" => [
"recipe[apt::default]",
"recipe[java::default]",
"recipe[jenkins::master]",
- "recipe[policyfile_demo::default]"
+ "recipe[policyfile_demo::default]",
],
- "cookbook_locks"=> { }
+ "cookbook_locks" => {},
}
formatter.policyfile_loaded(minimal_policyfile)
@@ -75,4 +75,18 @@ describe Chef::Formatters::Base do
expect(formatter.elapsed_time).to eql(36610.0)
expect(formatter.pretty_elapsed_time).to include("10 hours 10 minutes 10 seconds")
end
+
+ it "shows the percentage completion of an action" do
+ res = Chef::Resource::RemoteFile.new("canteloupe")
+ formatter.resource_update_progress(res, 35, 50, 10)
+ expect(out.string).to include(" - Progress: 70%")
+ end
+
+ it "updates the percentage completion of an action" do
+ res = Chef::Resource::RemoteFile.new("canteloupe")
+ formatter.resource_update_progress(res, 70, 100, 10)
+ expect(out.string).to include(" - Progress: 70%")
+ formatter.resource_update_progress(res, 80, 100, 10)
+ expect(out.string).to include(" - Progress: 80%")
+ end
end
diff --git a/spec/unit/formatters/error_description_spec.rb b/spec/unit/formatters/error_description_spec.rb
new file mode 100644
index 0000000000..8b088308fa
--- /dev/null
+++ b/spec/unit/formatters/error_description_spec.rb
@@ -0,0 +1,96 @@
+#
+# Author:: Jordan Running (<jr@chef.io>)
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Formatters::ErrorDescription do
+ let(:title) { "test title" }
+
+ let(:out) { Chef::Formatters::IndentableOutputStream.new(StringIO.new, STDERR) }
+
+ let(:section_heading) { "test heading" }
+ let(:section_text) { "test text" }
+
+ subject { Chef::Formatters::ErrorDescription.new(title) }
+
+ describe "#sections" do
+ context "when no sections have been added" do
+ it "should return an empty array" do
+ expect(subject.sections).to eq []
+ end
+ end
+
+ context "when a section has been added" do
+ before do
+ subject.section(section_heading, section_text)
+ end
+
+ it "should return an array with the added section as a hash" do
+ expect(subject.sections).to eq [ { section_heading => section_text } ]
+ end
+ end
+ end
+
+ describe "#display" do
+ before do
+ stub_const("RUBY_PLATFORM", "ruby-foo-9000")
+ end
+
+ context "when no sections have been added" do
+ it "should output only the title and the Platform section" do
+ subject.display(out)
+ expect(out.out.string).to eq <<-END
+================================================================================
+test title
+================================================================================
+
+Platform:
+---------
+ruby-foo-9000
+
+ END
+ end
+ end
+
+ context "when a section has been added" do
+ before do
+ subject.section(section_heading, section_text)
+ end
+
+ it "should output the expected sections" do
+ subject.display(out)
+ expect(out.out.string).to eq <<-END
+================================================================================
+test title
+================================================================================
+
+test heading
+------------
+test text
+
+Platform:
+---------
+ruby-foo-9000
+
+ END
+ end
+
+ end
+ end
+end
diff --git a/spec/unit/formatters/error_inspectors/api_error_formatting_spec.rb b/spec/unit/formatters/error_inspectors/api_error_formatting_spec.rb
index b8c2de2b8b..0e5104a0db 100644
--- a/spec/unit/formatters/error_inspectors/api_error_formatting_spec.rb
+++ b/spec/unit/formatters/error_inspectors/api_error_formatting_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/formatters/error_inspectors/api_error_formatting'
+require "spec_helper"
+require "chef/formatters/error_inspectors/api_error_formatting"
describe Chef::Formatters::APIErrorFormatting do
let(:class_instance) { (Class.new { include Chef::Formatters::APIErrorFormatting }).new }
@@ -27,37 +27,36 @@ describe Chef::Formatters::APIErrorFormatting do
allow(response).to receive(:body)
end
-
context "when describe_406_error is called" do
context "when response['x-ops-server-api-version'] exists" do
let(:min_version) { "2" }
let(:max_version) { "5" }
let(:request_version) { "30" }
- let(:return_hash) {
+ let(:return_hash) do
{
"min_version" => min_version,
"max_version" => max_version,
- "request_version" => request_version
+ "request_version" => request_version,
}
- }
+ end
before do
# mock out the header
- allow(response).to receive(:[]).with('x-ops-server-api-version').and_return(Chef::JSONCompat.to_json(return_hash))
+ allow(response).to receive(:[]).with("x-ops-server-api-version").and_return(Chef::JSONCompat.to_json(return_hash))
end
it "prints an error about client and server API version incompatibility with a min API version" do
- expect(error_description).to receive(:section).with("Incompatible server API version:",/a min API version of #{min_version}/)
+ expect(error_description).to receive(:section).with("Incompatible server API version:", /a min API version of #{min_version}/)
class_instance.describe_406_error(error_description, response)
end
it "prints an error about client and server API version incompatibility with a max API version" do
- expect(error_description).to receive(:section).with("Incompatible server API version:",/a max API version of #{max_version}/)
+ expect(error_description).to receive(:section).with("Incompatible server API version:", /a max API version of #{max_version}/)
class_instance.describe_406_error(error_description, response)
end
it "prints an error describing the request API version" do
- expect(error_description).to receive(:section).with("Incompatible server API version:",/a request with an API version of #{request_version}/)
+ expect(error_description).to receive(:section).with("Incompatible server API version:", /a request with an API version of #{request_version}/)
class_instance.describe_406_error(error_description, response)
end
end
@@ -65,7 +64,7 @@ describe Chef::Formatters::APIErrorFormatting do
context "when response.body['error'] != 'invalid-x-ops-server-api-version'" do
before do
- allow(response).to receive(:[]).with('x-ops-server-api-version').and_return(nil)
+ allow(response).to receive(:[]).with("x-ops-server-api-version").and_return(nil)
end
it "forwards the error_description to describe_http_error" do
diff --git a/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb
index 3c8d5dfa29..2c1da7345b 100644
--- a/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-BAD_RECIPE=<<-E
+BAD_RECIPE = <<-E
#
# Cookbook Name:: syntax-err
# Recipe:: default
#
-# Copyright 2012, YOUR_COMPANY_NAME
+# Copyright 2012-2016, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
@@ -63,7 +63,7 @@ describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
[
"/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
"/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
- "/home/someuser/.multiruby/gems/chef/lib/chef/client.rb:123:in `run'"
+ "/home/someuser/.multiruby/gems/chef/lib/chef/client.rb:123:in `run'",
]
end
@@ -91,7 +91,7 @@ describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
describe "when explaining an error in the compile phase" do
before do
- recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
+ recipe_lines = BAD_RECIPE.split("\n").map { |l| l << "\n" }
expect(IO).to receive(:readlines).with(path_to_failed_file).and_return(recipe_lines)
inspector.add_explanation(description)
end
@@ -122,7 +122,7 @@ describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
let(:trace) do
[
"/tmp/kitchen/cache/cookbooks/foo/recipes/default.rb:2:in `block in from_file'",
- "/tmp/kitchen/cache/cookbooks/foo/recipes/default.rb:1:in `from_file'"
+ "/tmp/kitchen/cache/cookbooks/foo/recipes/default.rb:1:in `from_file'",
]
end
@@ -148,7 +148,7 @@ describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
"/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `block in foreach_cookbook_load_segment'",
"/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `each'",
"/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `foreach_cookbook_load_segment'",
- "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:137:in `load_libraries'"
+ "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:137:in `load_libraries'",
]
end
@@ -199,7 +199,7 @@ describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
"C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application.rb:70:in `run'",
"C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/bin/chef-client:26:in `<top (required)>'",
"C:/opscode/chef/bin/chef-client:19:in `load'",
- "C:/opscode/chef/bin/chef-client:19:in `<main>'"
+ "C:/opscode/chef/bin/chef-client:19:in `<main>'",
]
end
@@ -209,7 +209,7 @@ describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
before do
allow(Chef::Config).to receive(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ])
- recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
+ recipe_lines = BAD_RECIPE.split("\n").map { |l| l << "\n" }
expect(IO).to receive(:readlines).at_least(1).times.with(full_path_to_failed_file).and_return(recipe_lines)
inspector.add_explanation(description)
end
diff --git a/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb
index 7e4d89f144..07643385b4 100644
--- a/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector do
@@ -32,7 +32,7 @@ describe Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector do
describe "when explaining a 403 error" do
before do
- @response_body = %Q({"error": [{"message": "gtfo"}])
+ @response_body = %q({"error": [{"message": "gtfo"}])
@response = Net::HTTPForbidden.new("1.1", "403", "(response) forbidden")
allow(@response).to receive(:body).and_return(@response_body)
@exception = Net::HTTPServerException.new("(exception) forbidden", @response)
@@ -124,6 +124,3 @@ describe Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector do
end
end
-
-
-
diff --git a/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb
index 775a1838f3..02846af24a 100644
--- a/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Formatters::ErrorInspectors::CookbookSyncErrorInspector do
before do
diff --git a/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb
index d2bbffafee..93aac417fa 100644
--- a/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
# spec_helper loads the shared examples already.
#require 'support/shared/unit/api_error_inspector_spec'
-
describe Chef::Formatters::ErrorInspectors::NodeLoadErrorInspector do
it_behaves_like "an api error inspector"
end
diff --git a/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb
index 4c21dadd82..cea93888eb 100644
--- a/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
# spec_helper loads the shared examples already.
#require 'support/shared/unit/api_error_inspector_spec'
-
describe Chef::Formatters::ErrorInspectors::RegistrationErrorInspector do
it_behaves_like "an api error inspector"
end
diff --git a/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb b/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
index 5594d6e18a..072dcfef28 100644
--- a/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
include Chef::DSL::Recipe
@@ -95,7 +95,7 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
@error = begin
@context.render_template_from_string("foo\nbar\nbaz\n<%= this_is_not_defined %>\nquin\nqunx\ndunno")
- rescue Chef::Mixin::Template::TemplateError => e
+ rescue Chef::Mixin::Template::TemplateError => e
e
end
@@ -108,7 +108,6 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
expect(@stdout.string).to include(@error.source_listing)
end
-
end
describe "recipe_snippet" do
@@ -189,5 +188,4 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
end
-
end
diff --git a/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb
index 1cd97596a7..3e988c584d 100644
--- a/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector do
before do
@@ -39,7 +39,6 @@ describe Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector do
@exception = Chef::Exceptions::MissingRole.new(@run_list_expansion)
-
@inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception)
@inspector.add_explanation(@description)
end
@@ -78,8 +77,8 @@ describe Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector do
@inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception)
allow(@inspector).to receive(:config).and_return(:node_name => "unit-test.example.com",
- :client_key => "/etc/chef/client.pem",
- :chef_server_url => "http://chef.example.com")
+ :client_key => "/etc/chef/client.pem",
+ :chef_server_url => "http://chef.example.com")
@inspector.add_explanation(@description)
end
@@ -90,4 +89,3 @@ describe Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector do
end
end
-
diff --git a/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb b/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb
index acf1b15fd8..746b343e9c 100644
--- a/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb
+++ b/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::GuardInterpreter::ResourceGuardInterpreter do
let(:node) do
@@ -24,7 +24,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
node.default["kernel"] = Hash.new
node.default["kernel"][:machine] = :x86_64.to_s
- node.automatic[:os] = 'windows'
+ node.automatic[:os] = "windows"
node
end
@@ -52,7 +52,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
it "raises an exception if guard_interpreter is set to a resource not derived from Chef::Resource::Script" do
parent_resource.guard_interpreter(:file)
- expect { guard_interpreter }.to raise_error(ArgumentError, 'Specified guard interpreter class Chef::Resource::File must be a kind of Chef::Resource::Execute resource')
+ expect { guard_interpreter }.to raise_error(ArgumentError, "Specified guard interpreter class Chef::Resource::File must be a kind of Chef::Resource::Execute resource")
end
context "when the resource cannot be found for the platform" do
@@ -62,7 +62,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
it "raises an exception" do
parent_resource.guard_interpreter(:foobar)
- expect { guard_interpreter }.to raise_error(ArgumentError, 'Specified guard_interpreter resource foobar unknown for this platform')
+ expect { guard_interpreter }.to raise_error(ArgumentError, "Specified guard_interpreter resource foobar unknown for this platform")
end
end
@@ -105,9 +105,9 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
parent_resource
end
- let(:shell_out) {
+ let(:shell_out) do
instance_double(Mixlib::ShellOut, :live_stream => true, :run_command => true, :error! => nil)
- }
+ end
before do
# TODO for some reason Windows is failing on executing a ruby script
@@ -118,7 +118,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
end
it "merges to :code" do
- expect(command_opts).to receive(:merge).with({:code => "exit 0"}).and_call_original
+ expect(command_opts).to receive(:merge).with({ :code => "exit 0" }).and_call_original
expect(guard_interpreter.evaluate).to eq(true)
end
end
@@ -131,7 +131,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
end
it "merges to :code" do
- expect(command_opts).to receive(:merge).with({:command => "exit 0"}).and_call_original
+ expect(command_opts).to receive(:merge).with({ :command => "exit 0" }).and_call_original
expect(guard_interpreter.evaluate).to eq(true)
end
end
@@ -145,7 +145,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
end
it "merges to :command" do
- expect(command_opts).to receive(:merge).with({:command => "exit 0"}).and_call_original
+ expect(command_opts).to receive(:merge).with({ :command => "exit 0" }).and_call_original
expect(guard_interpreter.evaluate).to eq(true)
end
end
diff --git a/spec/unit/guard_interpreter_spec.rb b/spec/unit/guard_interpreter_spec.rb
index a7fe064948..1bfc831177 100644
--- a/spec/unit/guard_interpreter_spec.rb
+++ b/spec/unit/guard_interpreter_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Steven Danna (steve@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::GuardInterpreter do
describe "#for_resource" do
- let (:resource) { Chef::Resource.new("foo")}
+ let (:resource) { Chef::Resource.new("foo") }
it "returns a DefaultGuardInterpreter if the resource has guard_interpreter set to :default" do
resource.guard_interpreter :default
diff --git a/spec/unit/handler/json_file_spec.rb b/spec/unit/handler/json_file_spec.rb
index f6c14a166e..4be448690a 100644
--- a/spec/unit/handler/json_file_spec.rb
+++ b/spec/unit/handler/json_file_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Handler::JsonFile do
before(:each) do
- @handler = Chef::Handler::JsonFile.new(:the_sun => "will rise", :path => '/tmp/foobarbazqux')
+ @handler = Chef::Handler::JsonFile.new(:the_sun => "will rise", :path => "/tmp/foobarbazqux")
end
it "accepts arbitrary config options" do
@@ -28,8 +28,8 @@ describe Chef::Handler::JsonFile do
end
it "creates the directory where the reports will be saved" do
- expect(FileUtils).to receive(:mkdir_p).with('/tmp/foobarbazqux')
- expect(File).to receive(:chmod).with(00700, '/tmp/foobarbazqux')
+ expect(FileUtils).to receive(:mkdir_p).with("/tmp/foobarbazqux")
+ expect(File).to receive(:chmod).with(00700, "/tmp/foobarbazqux")
@handler.build_report_dir
end
@@ -49,15 +49,14 @@ describe Chef::Handler::JsonFile do
allow(File).to receive(:open).and_yield(@file_mock)
end
-
it "saves run status data to a file as JSON" do
expect(@handler).to receive(:build_report_dir)
@handler.run_report_unsafe(@run_status)
- reported_data = Chef::JSONCompat.from_json(@file_mock.string)
- expect(reported_data['exception']).to eq("Exception: Boy howdy!")
- expect(reported_data['start_time']).to eq(@expected_time.to_s)
- expect(reported_data['end_time']).to eq((@expected_time + 5).to_s)
- expect(reported_data['elapsed_time']).to eq(5)
+ reported_data = Chef::JSONCompat.parse(@file_mock.string)
+ expect(reported_data["exception"]).to eq("Exception: Boy howdy!")
+ expect(reported_data["start_time"]).to eq(@expected_time.to_s)
+ expect(reported_data["end_time"]).to eq((@expected_time + 5).to_s)
+ expect(reported_data["elapsed_time"]).to eq(5)
end
end
diff --git a/spec/unit/handler_spec.rb b/spec/unit/handler_spec.rb
index e7f67405fc..09dd99d1ee 100644
--- a/spec/unit/handler_spec.rb
+++ b/spec/unit/handler_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Handler do
before(:each) do
@@ -36,8 +36,8 @@ describe Chef::Handler do
@exception.set_backtrace(@backtrace)
@run_status.exception = @exception
@run_context = Chef::RunContext.new(@node, {}, @events)
- @all_resources = [Chef::Resource::Cat.new('lolz'), Chef::Resource::ZenMaster.new('tzu')]
- @all_resources.first.updated = true
+ @all_resources = [Chef::Resource::Cat.new("lolz"), Chef::Resource::ZenMaster.new("tzu")]
+ @all_resources.first.updated_by_last_action true
@run_context.resource_collection.all_resources.replace(@all_resources)
@run_status.run_context = @run_context
@start_time = Time.now
@@ -100,7 +100,7 @@ describe Chef::Handler do
$report_ran = true
raise Exception, "I died the deth"
end
- expect {@handler.run_report_safely(@run_status)}.not_to raise_error
+ expect { @handler.run_report_safely(@run_status) }.not_to raise_error
expect($report_ran).to be_truthy
end
it "does not fail if the report handler does not raise an exception" do
@@ -108,7 +108,7 @@ describe Chef::Handler do
def @handler.report
$report_ran = true
end
- expect {@handler.run_report_safely(@run_status)}.not_to raise_error
+ expect { @handler.run_report_safely(@run_status) }.not_to raise_error
expect($report_ran).to be_truthy
end
end
@@ -117,8 +117,8 @@ describe Chef::Handler do
describe "when running a report handler" do
before do
@run_context = Chef::RunContext.new(@node, {}, @events)
- @all_resources = [Chef::Resource::Cat.new('foo'), Chef::Resource::ZenMaster.new('moo')]
- @all_resources.first.updated = true
+ @all_resources = [Chef::Resource::Cat.new("foo"), Chef::Resource::ZenMaster.new("moo")]
+ @all_resources.first.updated_by_last_action true
@run_context.resource_collection.all_resources.replace(@all_resources)
@run_status.run_context = @run_context
@start_time = Time.now
@@ -212,4 +212,91 @@ describe Chef::Handler do
end
end
+ describe "library report handler" do
+ before do
+ # we need to lazily declare this after we have reset Chef::Config in the default rspec before handler
+ class MyTestHandler < Chef::Handler
+ handler_for :report, :exception, :start
+
+ class << self
+ attr_accessor :ran_report
+ end
+
+ def report
+ self.class.ran_report = true
+ end
+ end
+ end
+
+ it "gets added to Chef::Config[:report_handlers]" do
+ expect(Chef::Config[:report_handlers].include?(MyTestHandler)).to be true
+ end
+
+ it "gets added to Chef::Config[:exception_handlers]" do
+ expect(Chef::Config[:exception_handlers].include?(MyTestHandler)).to be true
+ end
+
+ it "gets added to Chef::Config[:start_handlers]" do
+ expect(Chef::Config[:start_handlers].include?(MyTestHandler)).to be true
+ end
+
+ it "runs the report handler" do
+ Chef::Handler.run_report_handlers(@run_status)
+ expect(MyTestHandler.ran_report).to be true
+ end
+
+ it "runs the exception handler" do
+ Chef::Handler.run_exception_handlers(@run_status)
+ expect(MyTestHandler.ran_report).to be true
+ end
+
+ it "runs the start handler" do
+ Chef::Handler.run_start_handlers(@run_status)
+ expect(MyTestHandler.ran_report).to be true
+ end
+ end
+
+ describe "library singleton report handler" do
+ before do
+ # we need to lazily declare this after we have reset Chef::Config in the default rspec before handler
+ class MyTestHandler < Chef::Handler
+ handler_for :report, :exception, :start
+
+ include Singleton
+
+ attr_accessor :ran_report
+
+ def report
+ self.ran_report = true
+ end
+ end
+ end
+
+ it "gets added to Chef::Config[:report_handlers]" do
+ expect(Chef::Config[:report_handlers].include?(MyTestHandler)).to be true
+ end
+
+ it "gets added to Chef::Config[:exception_handlers]" do
+ expect(Chef::Config[:exception_handlers].include?(MyTestHandler)).to be true
+ end
+
+ it "gets added to Chef::Config[:start_handlers]" do
+ expect(Chef::Config[:start_handlers].include?(MyTestHandler)).to be true
+ end
+
+ it "runs the report handler" do
+ Chef::Handler.run_report_handlers(@run_status)
+ expect(MyTestHandler.instance.ran_report).to be true
+ end
+
+ it "runs the exception handler" do
+ Chef::Handler.run_exception_handlers(@run_status)
+ expect(MyTestHandler.instance.ran_report).to be true
+ end
+
+ it "runs the start handler" do
+ Chef::Handler.run_start_handlers(@run_status)
+ expect(MyTestHandler.instance.ran_report).to be true
+ end
+ end
end
diff --git a/spec/unit/http/api_versions_spec.rb b/spec/unit/http/api_versions_spec.rb
new file mode 100644
index 0000000000..79c97a1b69
--- /dev/null
+++ b/spec/unit/http/api_versions_spec.rb
@@ -0,0 +1,69 @@
+#
+# Copyright:: Copyright 2017, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::HTTP::APIVersions do
+ class TestVersionClient < Chef::HTTP
+ use Chef::HTTP::APIVersions
+ end
+
+ before do
+ Chef::ServerAPIVersions.instance.reset!
+ end
+
+ let(:method) { "GET" }
+ let(:url) { "http://dummy.com" }
+ let(:headers) { {} }
+ let(:data) { false }
+
+ let(:request) {}
+ let(:return_value) { "200" }
+
+ # Test Variables
+ let(:response_body) { "Thanks for checking in." }
+ let(:response_headers) do
+ {
+ "x-ops-server-api-version" => { "min_version" => 0, "max_version" => 2 },
+ }
+ end
+
+ let(:response) do
+ m = double("HttpResponse", :body => response_body)
+ allow(m).to receive(:key?).with("x-ops-server-api-version").and_return(true)
+ allow(m).to receive(:[]) do |key|
+ response_headers[key]
+ end
+
+ m
+ end
+
+ let(:middleware) do
+ client = TestVersionClient.new(url)
+ client.middlewares[0]
+ end
+
+ def run_api_version_handler
+ middleware.handle_request(method, url, headers, data)
+ middleware.handle_response(response, request, return_value)
+ end
+
+ it "correctly stores server api versions" do
+ run_api_version_handler
+ expect(Chef::ServerAPIVersions.instance.min_server_version).to eq(0)
+ end
+end
diff --git a/spec/unit/http/authenticator_spec.rb b/spec/unit/http/authenticator_spec.rb
index 48bbdcf76c..7fd2bdc821 100644
--- a/spec/unit/http/authenticator_spec.rb
+++ b/spec/unit/http/authenticator_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/http/authenticator'
+require "spec_helper"
+require "chef/http/authenticator"
describe Chef::HTTP::Authenticator do
let(:class_instance) { Chef::HTTP::Authenticator.new }
@@ -35,15 +35,15 @@ describe Chef::HTTP::Authenticator do
it "merges the default version of X-Ops-Server-API-Version into the headers" do
# headers returned
expect(class_instance.handle_request(method, url, headers, data)[2]).
- to include({'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION})
+ to include({ "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION })
end
context "when api_version is set to something other than the default" do
- let(:class_instance) { Chef::HTTP::Authenticator.new({:api_version => '-10'}) }
+ let(:class_instance) { Chef::HTTP::Authenticator.new({ :api_version => "-10" }) }
it "merges the requested version of X-Ops-Server-API-Version into the headers" do
expect(class_instance.handle_request(method, url, headers, data)[2]).
- to include({'X-Ops-Server-API-Version' => '-10'})
+ to include({ "X-Ops-Server-API-Version" => "-10" })
end
end
end
@@ -70,7 +70,9 @@ describe Chef::HTTP::Authenticator do
it_behaves_like "merging the server API version into the headers"
it "calls authentication_headers with the proper input" do
- expect(class_instance).to receive(:authentication_headers).with(method, url, data).and_return({})
+ expect(class_instance).to receive(:authentication_headers).with(
+ method, url, data,
+ { "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION }).and_return({})
class_instance.handle_request(method, url, headers, data)
end
end
diff --git a/spec/unit/http/basic_client_spec.rb b/spec/unit/http/basic_client_spec.rb
index b7552f54aa..0def00a220 100644
--- a/spec/unit/http/basic_client_spec.rb
+++ b/spec/unit/http/basic_client_spec.rb
@@ -15,8 +15,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/http/basic_client'
+require "spec_helper"
+require "chef/http/basic_client"
describe "HTTP Connection" do
@@ -29,6 +29,26 @@ describe "HTTP Connection" do
end
end
+ describe "#initialize" do
+ it "calls .start when doing keepalives" do
+ basic_client = Chef::HTTP::BasicClient.new(uri, keepalives: true)
+ expect(basic_client).to receive(:configure_ssl)
+ net_http_mock = instance_double(Net::HTTP, proxy_address: nil, "proxy_port=" => nil, "read_timeout=" => nil, "open_timeout=" => nil)
+ expect(net_http_mock).to receive(:start).and_return(net_http_mock)
+ expect(Net::HTTP).to receive(:new).and_return(net_http_mock)
+ expect(basic_client.http_client).to eql(net_http_mock)
+ end
+
+ it "does not call .start when not doing keepalives" do
+ basic_client = Chef::HTTP::BasicClient.new(uri)
+ expect(basic_client).to receive(:configure_ssl)
+ net_http_mock = instance_double(Net::HTTP, proxy_address: nil, "proxy_port=" => nil, "read_timeout=" => nil, "open_timeout=" => nil)
+ expect(net_http_mock).not_to receive(:start)
+ expect(Net::HTTP).to receive(:new).and_return(net_http_mock)
+ expect(basic_client.http_client).to eql(net_http_mock)
+ end
+ end
+
describe "#build_http_client" do
it "should build an http client" do
subject.build_http_client
@@ -40,90 +60,13 @@ describe "HTTP Connection" do
end
describe "#proxy_uri" do
- shared_examples_for "a proxy uri" do
- let(:proxy_host) { "proxy.mycorp.com" }
- let(:proxy_port) { 8080 }
- let(:proxy) { "#{proxy_prefix}#{proxy_host}:#{proxy_port}" }
-
- it "should contain the host" do
- proxy_uri = subject.proxy_uri
- expect(proxy_uri.host).to eq(proxy_host)
- end
-
- it "should contain the port" do
- proxy_uri = subject.proxy_uri
- expect(proxy_uri.port).to eq(proxy_port)
- end
- end
-
- context "when the config setting is normalized (does not contain the scheme)" do
- include_examples "a proxy uri" do
-
- let(:proxy_prefix) { "" }
-
- before do
- Chef::Config["#{uri.scheme}_proxy"] = proxy
- Chef::Config[:no_proxy] = nil
- end
-
- end
- end
-
- context "when the config setting is not normalized (contains the scheme)" do
- include_examples "a proxy uri" do
- let(:proxy_prefix) { "#{uri.scheme}://" }
-
- before do
- Chef::Config["#{uri.scheme}_proxy"] = proxy
- Chef::Config[:no_proxy] = nil
- end
-
- end
- end
-
- context "when the proxy is set by the environment" do
-
- include_examples "a proxy uri" do
-
- let(:env) do
- {
- "https_proxy" => "https://proxy.mycorp.com:8080",
- "https_proxy_user" => "jane_username",
- "https_proxy_pass" => "opensesame"
- }
- end
-
- let(:proxy_uri) { URI.parse(env["https_proxy"]) }
-
- before do
- allow(basic_client).to receive(:env).and_return(env)
- end
-
- it "sets the proxy user" do
- expect(basic_client.http_proxy_user(proxy_uri)).to eq("jane_username")
- end
-
- it "sets the proxy pass" do
- expect(basic_client.http_proxy_pass(proxy_uri)).to eq("opensesame")
- end
- end
-
- end
-
- context "when an empty proxy is set by the environment" do
- let(:env) do
- {
- "https_proxy" => ""
- }
- end
-
- before do
- allow(subject).to receive(:env).and_return(env)
- end
+ subject(:proxy_uri) { basic_client.proxy_uri }
- it "to not fail with URI parse exception" do
- expect { subject.proxy_uri }.to_not raise_error
- end
+ it "uses ChefConfig's proxy_uri method" do
+ expect(ChefConfig::Config).to receive(:proxy_uri).at_least(:once).with(
+ uri.scheme, uri.host, uri.port
+ )
+ proxy_uri
end
end
end
diff --git a/spec/unit/http/http_request_spec.rb b/spec/unit/http/http_request_spec.rb
index 3bba201963..29562de021 100644
--- a/spec/unit/http/http_request_spec.rb
+++ b/spec/unit/http/http_request_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Klaas Jan Wierenga (<k.j.wierenga@gmail.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,40 +16,40 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::HTTP::HTTPRequest do
context "with HTTP url scheme" do
it "should not include port 80 in Host header" do
- request = Chef::HTTP::HTTPRequest.new(:GET, URI('http://dummy.com'), '')
+ request = Chef::HTTP::HTTPRequest.new(:GET, URI("http://dummy.com"), "")
- expect(request.headers['Host']).to eql('dummy.com')
+ expect(request.headers["Host"]).to eql("dummy.com")
end
it "should not include explicit port 80 in Host header" do
- request = Chef::HTTP::HTTPRequest.new(:GET, URI('http://dummy.com:80'), '')
+ request = Chef::HTTP::HTTPRequest.new(:GET, URI("http://dummy.com:80"), "")
- expect(request.headers['Host']).to eql('dummy.com')
+ expect(request.headers["Host"]).to eql("dummy.com")
end
it "should include explicit port 8000 in Host header" do
- request = Chef::HTTP::HTTPRequest.new(:GET, URI('http://dummy.com:8000'), '')
+ request = Chef::HTTP::HTTPRequest.new(:GET, URI("http://dummy.com:8000"), "")
- expect(request.headers['Host']).to eql('dummy.com:8000')
+ expect(request.headers["Host"]).to eql("dummy.com:8000")
end
it "should include explicit 443 port in Host header" do
- request = Chef::HTTP::HTTPRequest.new(:GET, URI('http://dummy.com:443'), '')
+ request = Chef::HTTP::HTTPRequest.new(:GET, URI("http://dummy.com:443"), "")
- expect(request.headers['Host']).to eql('dummy.com:443')
+ expect(request.headers["Host"]).to eql("dummy.com:443")
end
it "should pass on explicit Host header unchanged" do
- request = Chef::HTTP::HTTPRequest.new(:GET, URI('http://dummy.com:8000'), '', { 'Host' => 'yourhost.com:8888' })
+ request = Chef::HTTP::HTTPRequest.new(:GET, URI("http://dummy.com:8000"), "", { "Host" => "yourhost.com:8888" })
- expect(request.headers['Host']).to eql('yourhost.com:8888')
+ expect(request.headers["Host"]).to eql("yourhost.com:8888")
end
end
@@ -57,35 +57,35 @@ describe Chef::HTTP::HTTPRequest do
context "with HTTPS url scheme" do
it "should not include port 443 in Host header" do
- request = Chef::HTTP::HTTPRequest.new(:GET, URI('https://dummy.com'), '')
+ request = Chef::HTTP::HTTPRequest.new(:GET, URI("https://dummy.com"), "")
- expect(request.headers['Host']).to eql('dummy.com')
+ expect(request.headers["Host"]).to eql("dummy.com")
end
it "should include explicit port 80 in Host header" do
- request = Chef::HTTP::HTTPRequest.new(:GET, URI('https://dummy.com:80'), '')
+ request = Chef::HTTP::HTTPRequest.new(:GET, URI("https://dummy.com:80"), "")
- expect(request.headers['Host']).to eql('dummy.com:80')
+ expect(request.headers["Host"]).to eql("dummy.com:80")
end
it "should include explicit port 8000 in Host header" do
- request = Chef::HTTP::HTTPRequest.new(:GET, URI('https://dummy.com:8000'), '')
+ request = Chef::HTTP::HTTPRequest.new(:GET, URI("https://dummy.com:8000"), "")
- expect(request.headers['Host']).to eql('dummy.com:8000')
+ expect(request.headers["Host"]).to eql("dummy.com:8000")
end
it "should not include explicit port 443 in Host header" do
- request = Chef::HTTP::HTTPRequest.new(:GET, URI('https://dummy.com:443'), '')
+ request = Chef::HTTP::HTTPRequest.new(:GET, URI("https://dummy.com:443"), "")
- expect(request.headers['Host']).to eql('dummy.com')
+ expect(request.headers["Host"]).to eql("dummy.com")
end
end
it "should pass on explicit Host header unchanged" do
- request = Chef::HTTP::HTTPRequest.new(:GET, URI('http://dummy.com:8000'), '', { 'Host' => 'myhost.com:80' })
+ request = Chef::HTTP::HTTPRequest.new(:GET, URI("http://dummy.com:8000"), "", { "Host" => "myhost.com:80" })
- expect(request.headers['Host']).to eql('myhost.com:80')
+ expect(request.headers["Host"]).to eql("myhost.com:80")
end
end
diff --git a/spec/unit/http/json_input_spec.rb b/spec/unit/http/json_input_spec.rb
index fbf8f22503..a76c8d1dc7 100644
--- a/spec/unit/http/json_input_spec.rb
+++ b/spec/unit/http/json_input_spec.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/http/json_input'
+require "spec_helper"
+require "chef/http/json_input"
describe Chef::HTTP::JSONInput do
@@ -66,7 +66,7 @@ describe Chef::HTTP::JSONInput do
context "when the request should be serialized" do
let(:http_method) { :put }
- let(:data) { {foo: "bar"} }
+ let(:data) { { foo: "bar" } }
let(:expected_data) { %q[{"foo":"bar"}] }
context "and the request has a ruby object as the body and no explicit content-type" do
@@ -111,7 +111,7 @@ describe Chef::HTTP::JSONInput do
expect(handle_request).to eq([http_method, url, headers, data])
# not normalized
- expect(headers).to eq({"content-type" => "application/x-binary"})
+ expect(headers).to eq({ "content-type" => "application/x-binary" })
end
it "does not serialize the body to json when content type is given in capitalized form" do
@@ -120,7 +120,7 @@ describe Chef::HTTP::JSONInput do
expect(handle_request).to eq([http_method, url, headers, data])
# not normalized
- expect(headers).to eq({"Content-Type" => "application/x-binary"})
+ expect(headers).to eq({ "Content-Type" => "application/x-binary" })
end
end
diff --git a/spec/unit/http/simple_spec.rb b/spec/unit/http/simple_spec.rb
index c8fb52e8b2..0170266bb5 100644
--- a/spec/unit/http/simple_spec.rb
+++ b/spec/unit/http/simple_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::HTTP::Simple do
it "should have content length validation middleware after compressor middleware" do
diff --git a/spec/unit/http/socketless_chef_zero_client_spec.rb b/spec/unit/http/socketless_chef_zero_client_spec.rb
index 963cc9e8c4..637e562799 100644
--- a/spec/unit/http/socketless_chef_zero_client_spec.rb
+++ b/spec/unit/http/socketless_chef_zero_client_spec.rb
@@ -1,6 +1,6 @@
#--
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'chef/http/socketless_chef_zero_client'
+require "chef/http/socketless_chef_zero_client"
describe Chef::HTTP::SocketlessChefZeroClient do
@@ -110,7 +110,7 @@ describe Chef::HTTP::SocketlessChefZeroClient do
end
it "does not fail when calling read_body with a block" do
- expect(net_http_response.read_body {|chunk| chunk }).to eq("bunch o' JSON")
+ expect(net_http_response.read_body { |chunk| chunk }).to eq("bunch o' JSON")
end
end
@@ -149,7 +149,6 @@ describe Chef::HTTP::SocketlessChefZeroClient do
}
end
-
let(:response_code) { 200 }
let(:response_headers) { { "Content-Type" => "Application/JSON" } }
let(:response_body) { [ "bunch o' JSON" ] }
diff --git a/spec/unit/http/ssl_policies_spec.rb b/spec/unit/http/ssl_policies_spec.rb
index 5ebebf39b1..df6dee1198 100644
--- a/spec/unit/http/ssl_policies_spec.rb
+++ b/spec/unit/http/ssl_policies_spec.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010, 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/http/ssl_policies'
+require "spec_helper"
+require "chef/http/ssl_policies"
describe "HTTP SSL Policy" do
@@ -54,7 +54,7 @@ describe "HTTP SSL Policy" do
it "raises a ConfigurationError if :ssl_ca_path is set to a path that doesn't exist" do
Chef::Config[:ssl_ca_path] = "/dev/null/nothing_here"
- expect {http_client}.to raise_error(Chef::Exceptions::ConfigurationError)
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
end
it "should set the CA path if that is set in the configuration" do
@@ -64,12 +64,12 @@ describe "HTTP SSL Policy" do
it "raises a ConfigurationError if :ssl_ca_file is set to a file that does not exist" do
Chef::Config[:ssl_ca_file] = "/dev/null/nothing_here"
- expect {http_client}.to raise_error(Chef::Exceptions::ConfigurationError)
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
end
it "should set the CA file if that is set in the configuration" do
- Chef::Config[:ssl_ca_file] = CHEF_SPEC_DATA + '/ssl/5e707473.0'
- expect(http_client.ca_file).to eq(CHEF_SPEC_DATA + '/ssl/5e707473.0')
+ Chef::Config[:ssl_ca_file] = CHEF_SPEC_DATA + "/ssl/5e707473.0"
+ expect(http_client.ca_file).to eq(CHEF_SPEC_DATA + "/ssl/5e707473.0")
end
end
@@ -85,31 +85,31 @@ describe "HTTP SSL Policy" do
end
describe "when configured with a client certificate" do
- before {@url = URI.parse("https://chef.example.com:4443/")}
+ before { @url = URI.parse("https://chef.example.com:4443/") }
it "raises ConfigurationError if the certificate file doesn't exist" do
Chef::Config[:ssl_client_cert] = "/dev/null/nothing_here"
- Chef::Config[:ssl_client_key] = CHEF_SPEC_DATA + '/ssl/chef-rspec.key'
- expect {http_client}.to raise_error(Chef::Exceptions::ConfigurationError)
+ Chef::Config[:ssl_client_key] = CHEF_SPEC_DATA + "/ssl/chef-rspec.key"
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
end
it "raises ConfigurationError if the certificate file doesn't exist" do
- Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + '/ssl/chef-rspec.cert'
+ Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + "/ssl/chef-rspec.cert"
Chef::Config[:ssl_client_key] = "/dev/null/nothing_here"
- expect {http_client}.to raise_error(Chef::Exceptions::ConfigurationError)
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
end
it "raises a ConfigurationError if one of :ssl_client_cert and :ssl_client_key is set but not both" do
Chef::Config[:ssl_client_cert] = "/dev/null/nothing_here"
Chef::Config[:ssl_client_key] = nil
- expect {http_client}.to raise_error(Chef::Exceptions::ConfigurationError)
+ expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
end
it "configures the HTTP client's cert and private key" do
- Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + '/ssl/chef-rspec.cert'
- Chef::Config[:ssl_client_key] = CHEF_SPEC_DATA + '/ssl/chef-rspec.key'
- expect(http_client.cert.to_s).to eq(OpenSSL::X509::Certificate.new(IO.read(CHEF_SPEC_DATA + '/ssl/chef-rspec.cert')).to_s)
- expect(http_client.key.to_s).to eq(IO.read(CHEF_SPEC_DATA + '/ssl/chef-rspec.key'))
+ Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + "/ssl/chef-rspec.cert"
+ Chef::Config[:ssl_client_key] = CHEF_SPEC_DATA + "/ssl/chef-rspec.key"
+ expect(http_client.cert.to_s).to eq(OpenSSL::X509::Certificate.new(IO.read(CHEF_SPEC_DATA + "/ssl/chef-rspec.cert")).to_s)
+ expect(http_client.key.to_s).to eq(OpenSSL::PKey::RSA.new(IO.read(CHEF_SPEC_DATA + "/ssl/chef-rspec.key")).to_s)
end
end
@@ -167,4 +167,3 @@ describe "HTTP SSL Policy" do
end
end
-
diff --git a/spec/unit/http/validate_content_length_spec.rb b/spec/unit/http/validate_content_length_spec.rb
index 79bd539af3..5067d36d38 100644
--- a/spec/unit/http/validate_content_length_spec.rb
+++ b/spec/unit/http/validate_content_length_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'stringio'
+require "spec_helper"
+require "stringio"
describe Chef::HTTP::ValidateContentLength do
class TestClient < Chef::HTTP
@@ -29,7 +29,7 @@ describe Chef::HTTP::ValidateContentLength do
let(:headers) { {} }
let(:data) { false }
- let(:request) { }
+ let(:request) {}
let(:return_value) { "200" }
# Test Variables
@@ -37,25 +37,25 @@ describe Chef::HTTP::ValidateContentLength do
let(:content_length_value) { 23 }
let(:streaming_length) { 23 }
let(:response_body) { "Thanks for checking in." }
- let(:response_headers) {
+ let(:response_headers) do
{
- "content-length" => content_length_value
+ "content-length" => content_length_value,
}
- }
+ end
- let(:response) {
- m = double('HttpResponse', :body => response_body)
+ let(:response) do
+ m = double("HttpResponse", :body => response_body)
allow(m).to receive(:[]) do |key|
response_headers[key]
end
m
- }
+ end
- let(:middleware) {
+ let(:middleware) do
client = TestClient.new(url)
client.middlewares[0]
- }
+ end
def run_content_length_validation
stream_handler = middleware.stream_response_handler(response)
@@ -105,9 +105,9 @@ describe Chef::HTTP::ValidateContentLength do
end
describe "without Content-Length header" do
- let(:response_headers) { { } }
+ let(:response_headers) { {} }
- [ "direct", "streaming" ].each do |req_type|
+ %w{direct streaming}.each do |req_type|
describe "when running #{req_type} request" do
let(:request_type) { req_type.to_sym }
@@ -119,8 +119,23 @@ describe Chef::HTTP::ValidateContentLength do
end
end
+ describe "with negative Content-Length header" do
+ let(:content_length_value) { "-1" }
+
+ %w{direct streaming}.each do |req_type|
+ describe "when running #{req_type} request" do
+ let(:request_type) { req_type.to_sym }
+
+ it "should skip validation and log for debug" do
+ run_content_length_validation
+ expect(debug_output).to include("HTTP server responded with a negative Content-Length header (-1), cannot identify truncated downloads.")
+ end
+ end
+ end
+ end
+
describe "with correct Content-Length header" do
- [ "direct", "streaming" ].each do |req_type|
+ %w{direct streaming}.each do |req_type|
describe "when running #{req_type} request" do
let(:request_type) { req_type.to_sym }
@@ -134,7 +149,7 @@ describe Chef::HTTP::ValidateContentLength do
describe "with wrong Content-Length header" do
let(:content_length_value) { 25 }
- [ "direct", "streaming" ].each do |req_type|
+ %w{direct streaming}.each do |req_type|
describe "when running #{req_type} request" do
let(:request_type) { req_type.to_sym }
@@ -154,14 +169,14 @@ describe Chef::HTTP::ValidateContentLength do
end
describe "when Transfer-Encoding & Content-Length is set" do
- let(:response_headers) {
+ let(:response_headers) do
{
"content-length" => content_length_value,
- "transfer-encoding" => "chunked"
+ "transfer-encoding" => "chunked",
}
- }
+ end
- [ "direct", "streaming" ].each do |req_type|
+ %w{direct streaming}.each do |req_type|
describe "when running #{req_type} request" do
let(:request_type) { req_type.to_sym }
@@ -180,7 +195,7 @@ describe Chef::HTTP::ValidateContentLength do
end
it "should reset internal counter" do
- expect(middleware.instance_variable_get(:@content_length_counter)).to be_nil
+ expect(middleware.instance_variable_get(:@content_length_counter)).to be_nil
end
it "should validate correctly second time" do
diff --git a/spec/unit/http_spec.rb b/spec/unit/http_spec.rb
index a654d14aa2..d58f07c417 100644
--- a/spec/unit/http_spec.rb
+++ b/spec/unit/http_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Xabier de Zuazo (xabier@onddo.com)
-# Copyright:: Copyright (c) 2014 Onddo Labs, SL.
+# Copyright:: Copyright 2014-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/http'
-require 'chef/http/basic_client'
-require 'chef/http/socketless_chef_zero_client'
+require "chef/http"
+require "chef/http/basic_client"
+require "chef/http/socketless_chef_zero_client"
class Chef::HTTP
public :create_url
@@ -28,6 +28,8 @@ end
describe Chef::HTTP do
+ let(:uri) { "https://chef.example/organizations/default/" }
+
context "when given a chefzero:// URL" do
let(:uri) { URI("chefzero://localhost:1") }
@@ -41,32 +43,58 @@ describe Chef::HTTP do
end
+ describe "#intialize" do
+ it "accepts a keepalive option and passes it to the http_client" do
+ http = Chef::HTTP.new(uri, keepalives: true)
+ expect(Chef::HTTP::BasicClient).to receive(:new).with(uri, ssl_policy: Chef::HTTP::APISSLPolicy, keepalives: true).and_call_original
+ expect(http.http_client).to be_a_kind_of(Chef::HTTP::BasicClient)
+ end
+
+ it "the default is not to use keepalives" do
+ http = Chef::HTTP.new(uri)
+ expect(Chef::HTTP::BasicClient).to receive(:new).with(uri, ssl_policy: Chef::HTTP::APISSLPolicy, keepalives: false).and_call_original
+ expect(http.http_client).to be_a_kind_of(Chef::HTTP::BasicClient)
+ end
+ end
+
describe "create_url" do
- it 'should return a correctly formatted url 1/3 CHEF-5261' do
- http = Chef::HTTP.new('http://www.getchef.com')
- expect(http.create_url('api/endpoint')).to eql(URI.parse('http://www.getchef.com/api/endpoint'))
+ it "should return a correctly formatted url 1/3 CHEF-5261" do
+ http = Chef::HTTP.new("http://www.getchef.com")
+ expect(http.create_url("api/endpoint")).to eql(URI.parse("http://www.getchef.com/api/endpoint"))
end
- it 'should return a correctly formatted url 2/3 CHEF-5261' do
- http = Chef::HTTP.new('http://www.getchef.com/')
- expect(http.create_url('/organization/org/api/endpoint/')).to eql(URI.parse('http://www.getchef.com/organization/org/api/endpoint/'))
+ it "should return a correctly formatted url 2/3 CHEF-5261" do
+ http = Chef::HTTP.new("http://www.getchef.com/")
+ expect(http.create_url("/organization/org/api/endpoint/")).to eql(URI.parse("http://www.getchef.com/organization/org/api/endpoint/"))
end
- it 'should return a correctly formatted url 3/3 CHEF-5261' do
- http = Chef::HTTP.new('http://www.getchef.com/organization/org///')
- expect(http.create_url('///api/endpoint?url=http://foo.bar')).to eql(URI.parse('http://www.getchef.com/organization/org/api/endpoint?url=http://foo.bar'))
+ it "should return a correctly formatted url 3/3 CHEF-5261" do
+ http = Chef::HTTP.new("http://www.getchef.com/organization/org///")
+ expect(http.create_url("///api/endpoint?url=http://foo.bar")).to eql(URI.parse("http://www.getchef.com/organization/org/api/endpoint?url=http://foo.bar"))
end
- # As per: https://github.com/opscode/chef/issues/2500
- it 'should treat scheme part of the URI in a case-insensitive manner' do
+ # As per: https://github.com/chef/chef/issues/2500
+ it "should treat scheme part of the URI in a case-insensitive manner" do
http = Chef::HTTP.allocate # Calling Chef::HTTP::new sets @url, don't want that.
- expect { http.create_url('HTTP://www1.chef.io/') }.not_to raise_error
- expect(http.create_url('HTTP://www2.chef.io/')).to eql(URI.parse('http://www2.chef.io/'))
+ expect { http.create_url("HTTP://www1.chef.io/") }.not_to raise_error
+ expect(http.create_url("HTTP://www2.chef.io/")).to eql(URI.parse("http://www2.chef.io/"))
end
end # create_url
+ describe "#stream_to_tempfile" do
+
+ it "should only close an existing Tempfile" do
+ resp = Net::HTTPOK.new("1.1", 200, "OK")
+ http = Chef::HTTP.new(uri)
+ expect(Tempfile).to receive(:open).and_raise("TestError")
+ expect_any_instance_of(Tempfile).not_to receive(:close!)
+ expect { http.send(:stream_to_tempfile, uri, resp) }.to raise_error("TestError")
+ end
+
+ end
+
describe "head" do
it 'should return nil for a "200 Success" response (CHEF-4762)' do
@@ -89,4 +117,104 @@ describe Chef::HTTP do
end # head
-end \ No newline at end of file
+ describe "retrying connection errors" do
+
+ subject(:http) { Chef::HTTP.new(uri) }
+
+ # http#http_client gets stubbed later, so eager create
+ let!(:low_level_client) { http.http_client(URI(uri)) }
+
+ let(:http_ok_response) do
+ Net::HTTPOK.new("1.1", 200, "OK").tap do |r|
+ allow(r).to receive(:read_body).and_return("")
+ end
+ end
+
+ before do
+ allow(http).to receive(:http_client).with(URI(uri)).and_return(low_level_client)
+ end
+
+ shared_examples_for "retriable_request_errors" do
+
+ before do
+ expect(low_level_client).to receive(:request).exactly(5).times.and_raise(exception)
+ expect(http).to receive(:sleep).exactly(5).times.and_return(1)
+ expect(low_level_client).to receive(:request).and_return([low_level_client, http_ok_response])
+ end
+
+ it "retries the request 5 times" do
+ http.get("/")
+ end
+
+ end
+
+ shared_examples_for "errors_that_are_not_retried" do
+
+ before do
+ expect(low_level_client).to receive(:request).exactly(1).times.and_raise(exception)
+ expect(http).to_not receive(:sleep)
+ end
+
+ it "raises the error without retrying or sleeping" do
+ # We modify the strings to give addtional context, but the exception class should be the same
+ expect { http.get("/") }.to raise_error(exception.class)
+ end
+ end
+
+ context "when ECONNRESET is raised" do
+
+ let(:exception) { Errno::ECONNRESET.new("example error") }
+
+ include_examples "retriable_request_errors"
+
+ end
+
+ context "when SocketError is raised" do
+
+ let(:exception) { SocketError.new("example error") }
+
+ include_examples "retriable_request_errors"
+
+ end
+
+ context "when ETIMEDOUT is raised" do
+
+ let(:exception) { Errno::ETIMEDOUT.new("example error") }
+
+ include_examples "retriable_request_errors"
+
+ end
+
+ context "when ECONNREFUSED is raised" do
+
+ let(:exception) { Errno::ECONNREFUSED.new("example error") }
+
+ include_examples "retriable_request_errors"
+
+ end
+
+ context "when Timeout::Error is raised" do
+
+ let(:exception) { Timeout::Error.new("example error") }
+
+ include_examples "retriable_request_errors"
+
+ end
+
+ context "when OpenSSL::SSL::SSLError is raised" do
+
+ let(:exception) { OpenSSL::SSL::SSLError.new("example error") }
+
+ include_examples "retriable_request_errors"
+
+ end
+
+ context "when OpenSSL::SSL::SSLError is raised for certificate validation failure" do
+
+ let(:exception) { OpenSSL::SSL::SSLError.new("ssl_connect returned=1 errno=0 state=sslv3 read server certificate b: certificate verify failed") }
+
+ include_examples "errors_that_are_not_retried"
+
+ end
+ end
+end
diff --git a/spec/unit/json_compat_spec.rb b/spec/unit/json_compat_spec.rb
index fd6469c146..4da29fe4ec 100644
--- a/spec/unit/json_compat_spec.rb
+++ b/spec/unit/json_compat_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Juanje Ojeda (<juanje.ojeda@gmail.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,21 @@
# limitations under the License.
#
-require File.expand_path('../../spec_helper', __FILE__)
-require 'chef/json_compat'
+require File.expand_path("../../spec_helper", __FILE__)
+require "chef/json_compat"
describe Chef::JSONCompat do
+ before { Chef::Config[:treat_deprecation_warnings_as_errors] = false }
describe "#from_json with JSON containing an existing class" do
let(:json) { '{"json_class": "Chef::Role"}' }
+ it "emits a deprecation warning" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = true
+ expect { Chef::JSONCompat.from_json(json) }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+ /Auto inflation of JSON data is deprecated. Please use Chef::Role#from_hash/
+ end
+
it "returns an instance of the class instead of a Hash" do
expect(Chef::JSONCompat.from_json(json).class).to eq Chef::Role
end
@@ -46,19 +53,19 @@ describe Chef::JSONCompat do
end
describe 'with JSON containing "Chef::Sandbox" as a json_class value' do
- require 'chef/sandbox' # Only needed for this test
+ require "chef/sandbox" # Only needed for this test
let(:json) { '{"json_class": "Chef::Sandbox", "arbitrary": "data"}' }
it "returns a Hash, because Chef::Sandbox is a dummy class" do
- expect(Chef::JSONCompat.from_json(json)).to eq({"json_class" => "Chef::Sandbox", "arbitrary" => "data"})
+ expect(Chef::JSONCompat.from_json(json)).to eq({ "json_class" => "Chef::Sandbox", "arbitrary" => "data" })
end
end
describe "when pretty printing an object that defines #to_json" do
class Foo
def to_json(*a)
- Chef::JSONCompat.to_json({'foo' => 1234, 'bar' => {'baz' => 5678}}, *a)
+ Chef::JSONCompat.to_json({ "foo" => 1234, "bar" => { "baz" => 5678 } }, *a)
end
end
@@ -73,7 +80,7 @@ describe Chef::JSONCompat do
end
describe "with the file with 252 or less nested entries" do
- let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'nested.json')) }
+ let(:json) { IO.read(File.join(CHEF_SPEC_DATA, "nested.json")) }
let(:hash) { Chef::JSONCompat.from_json(json) }
describe "when the 252 json file is loaded" do
@@ -83,9 +90,9 @@ describe Chef::JSONCompat do
it "should has 'test' as a 252 nested value" do
v = 252.times.inject(hash) do |memo, _|
- memo['key']
+ memo["key"]
end
- expect(v).to eq('test')
+ expect(v).to eq("test")
end
end
end
diff --git a/spec/unit/key_spec.rb b/spec/unit/key_spec.rb
index 94ebbf6ae8..4af506d227 100644
--- a/spec/unit/key_spec.rb
+++ b/spec/unit/key_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/key'
+require "chef/key"
describe Chef::Key do
# whether user or client irrelevent to these tests
let(:key) { Chef::Key.new("original_actor", "user") }
let(:public_key_string) do
- <<EOS
+ <<EOS
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvPo+oNPB7uuNkws0fC02
KxSwdyqPLu0fhI1pOweNKAZeEIiEz2PkybathHWy8snSXGNxsITkf3eyvIIKa8OZ
@@ -71,7 +71,6 @@ EOS
end
end
-
describe "when a new Chef::Key object is initialized with invalid input" do
it "should raise an InvalidKeyArgument" do
expect { Chef::Key.new("original_actor", "not_a_user_or_client") }.to raise_error(Chef::Exceptions::InvalidKeyArgument)
@@ -199,7 +198,7 @@ EOS
end
it "should include the actor value under the key relative to the actor_field_name passed" do
- expect(json).to include(%Q("#{new_key.actor_field_name}":"original_actor"))
+ expect(json).to include(%Q{"#{new_key.actor_field_name}":"original_actor"})
end
it "should include the name field when present" do
@@ -213,7 +212,7 @@ EOS
it "should include the public_key field when present" do
new_key.public_key "this_public_key"
- expect(new_key.to_json).to include(%q("public_key":"this_public_key"))
+ expect(new_key.to_json).to include(%q{"public_key":"this_public_key"})
end
it "should not include the public_key if not present" do
@@ -222,7 +221,7 @@ EOS
it "should include the private_key field when present" do
new_key.private_key "this_public_key"
- expect(new_key.to_json).to include(%q("private_key":"this_public_key"))
+ expect(new_key.to_json).to include(%q{"private_key":"this_public_key"})
end
it "should not include the private_key if not present" do
@@ -231,7 +230,7 @@ EOS
it "should include the expiration_date field when present" do
new_key.expiration_date "2020-12-24T21:00:00Z"
- expect(new_key.to_json).to include(%Q("expiration_date":"2020-12-24T21:00:00Z"))
+ expect(new_key.to_json).to include(%q{"expiration_date":"2020-12-24T21:00:00Z"})
end
it "should not include the expiration_date if not present" do
@@ -240,7 +239,7 @@ EOS
it "should include the create_key field when present" do
new_key.create_key true
- expect(new_key.to_json).to include(%q("create_key":true))
+ expect(new_key.to_json).to include(%q{"create_key":true})
end
it "should not include the create_key if not present" do
@@ -306,7 +305,7 @@ EOS
"name" => "key_name",
"public_key" => public_key_string,
"private_key" => "some_private_key",
- "expiration_date" => "infinity"}
+ "expiration_date" => "infinity" }
Chef::Key.from_json(o.to_json)
end
let(:key_with_create_key_field) do
@@ -324,7 +323,7 @@ EOS
"name" => "key_name",
"public_key" => public_key_string,
"private_key" => "some_private_key",
- "expiration_date" => "infinity"}
+ "expiration_date" => "infinity" }
Chef::Key.from_json(o.to_json)
end
let(:key_with_create_key_field) do
@@ -336,13 +335,12 @@ EOS
end
end # when deserializing from JSON
-
describe "API Interactions" do
let(:rest) do
Chef::Config[:chef_server_root] = "http://www.example.com"
Chef::Config[:chef_server_url] = "http://www.example.com/organizations/test_org"
- r = double('rest')
- allow(Chef::REST).to receive(:new).and_return(r)
+ r = double("rest")
+ allow(Chef::ServerAPI).to receive(:new).and_return(r)
r
end
@@ -358,41 +356,40 @@ EOS
describe "list" do
context "when listing keys for a user" do
- let(:response) { [{"uri" => "http://www.example.com/users/keys/foobar", "name"=>"foobar", "expired"=>false}] }
- let(:inflated_response) { {"foobar" => user_key} }
+ let(:response) { [{ "uri" => "http://www.example.com/users/keys/foobar", "name" => "foobar", "expired" => false }] }
+ let(:inflated_response) { { "foobar" => user_key } }
it "lists all keys" do
- expect(rest).to receive(:get_rest).with("users/#{user_key.actor}/keys").and_return(response)
+ expect(rest).to receive(:get).with("users/#{user_key.actor}/keys").and_return(response)
expect(Chef::Key.list_by_user("foobar")).to eq(response)
end
it "inflate all keys" do
allow(Chef::Key).to receive(:load_by_user).with(user_key.actor, "foobar").and_return(user_key)
- expect(rest).to receive(:get_rest).with("users/#{user_key.actor}/keys").and_return(response)
+ expect(rest).to receive(:get).with("users/#{user_key.actor}/keys").and_return(response)
expect(Chef::Key.list_by_user("foobar", true)).to eq(inflated_response)
end
end
context "when listing keys for a client" do
- let(:response) { [{"uri" => "http://www.example.com/users/keys/foobar", "name"=>"foobar", "expired"=>false}] }
- let(:inflated_response) { {"foobar" => client_key} }
+ let(:response) { [{ "uri" => "http://www.example.com/users/keys/foobar", "name" => "foobar", "expired" => false }] }
+ let(:inflated_response) { { "foobar" => client_key } }
it "lists all keys" do
- expect(rest).to receive(:get_rest).with("clients/#{client_key.actor}/keys").and_return(response)
+ expect(rest).to receive(:get).with("clients/#{client_key.actor}/keys").and_return(response)
expect(Chef::Key.list_by_client("foobar")).to eq(response)
end
it "inflate all keys" do
allow(Chef::Key).to receive(:load_by_client).with(client_key.actor, "foobar").and_return(client_key)
- expect(rest).to receive(:get_rest).with("clients/#{user_key.actor}/keys").and_return(response)
+ expect(rest).to receive(:get).with("clients/#{user_key.actor}/keys").and_return(response)
expect(Chef::Key.list_by_client("foobar", true)).to eq(inflated_response)
end
end
end
-
describe "create" do
shared_examples_for "create key" do
context "when a field is missing" do
@@ -408,10 +405,10 @@ EOS
end
it "creates a new key via the API with the fingerprint as the name" do
- expect(rest).to receive(:post_rest).with(url,
- {"name" => "12:3e:33:73:0b:f4:ec:72:dc:f0:4c:51:62:27:08:76:96:24:f4:4a",
- "public_key" => key.public_key,
- "expiration_date" => key.expiration_date}).and_return({})
+ expect(rest).to receive(:post).with(url,
+ { "name" => "12:3e:33:73:0b:f4:ec:72:dc:f0:4c:51:62:27:08:76:96:24:f4:4a",
+ "public_key" => key.public_key,
+ "expiration_date" => key.expiration_date }).and_return({})
key.create
end
end
@@ -426,10 +423,10 @@ EOS
context "when create_key is false" do
it "creates a new key via the API" do
- expect(rest).to receive(:post_rest).with(url,
- {"name" => key.name,
- "public_key" => key.public_key,
- "expiration_date" => key.expiration_date}).and_return({})
+ expect(rest).to receive(:post).with(url,
+ { "name" => key.name,
+ "public_key" => key.public_key,
+ "expiration_date" => key.expiration_date }).and_return({})
key.create
end
end
@@ -443,27 +440,27 @@ EOS
actor_type => "foobar",
"name" => key.name,
"create_key" => true,
- "expiration_date" => key.expiration_date
+ "expiration_date" => key.expiration_date,
}
$expected_input = {
"name" => key.name,
"create_key" => true,
- "expiration_date" => key.expiration_date
+ "expiration_date" => key.expiration_date,
}
end
it "should create a new key via the API" do
- expect(rest).to receive(:post_rest).with(url, $expected_input).and_return({})
+ expect(rest).to receive(:post).with(url, $expected_input).and_return({})
key.create
end
context "when the server returns the private_key via key.create" do
before do
- allow(rest).to receive(:post_rest).with(url, $expected_input).and_return({"private_key" => "this_private_key"})
+ allow(rest).to receive(:post).with(url, $expected_input).and_return({ "private_key" => "this_private_key" })
end
it "key.create returns the original key plus the private_key" do
- expect(key.create.to_hash).to eq($expected_output.merge({"private_key" => "this_private_key"}))
+ expect(key.create.to_hash).to eq($expected_output.merge({ "private_key" => "this_private_key" }))
end
end
end
@@ -512,7 +509,7 @@ EOS
end
it "should update the key via the API" do
- expect(rest).to receive(:put_rest).with(url, key.to_hash).and_return({})
+ expect(rest).to receive(:put).with(url, key.to_hash).and_return({})
key.update
end
end
@@ -523,7 +520,7 @@ EOS
end
it "passes @name in the body and the arg in the PUT URL" do
- expect(rest).to receive(:put_rest).with(update_name_url, key.to_hash).and_return({})
+ expect(rest).to receive(:put).with(update_name_url, key.to_hash).and_return({})
key.update("old_name")
end
end
@@ -532,9 +529,9 @@ EOS
before do
key.name "key_name"
key.create_key true
- allow(rest).to receive(:put_rest).with(url, key.to_hash).and_return({
+ allow(rest).to receive(:put).with(url, key.to_hash).and_return({
"key" => "key_name",
- "public_key" => public_key_string
+ "public_key" => public_key_string,
})
end
@@ -572,7 +569,7 @@ EOS
describe "load" do
shared_examples_for "load" do
it "should load a named key from the API" do
- expect(rest).to receive(:get_rest).with(url).and_return({"user" => "foobar", "name" => "test_key_name", "public_key" => public_key_string, "expiration_date" => "infinity"})
+ expect(rest).to receive(:get).with(url).and_return({ "user" => "foobar", "name" => "test_key_name", "public_key" => public_key_string, "expiration_date" => "infinity" })
key = Chef::Key.send(load_method, "foobar", "test_key_name")
expect(key.actor).to eq("foobar")
expect(key.name).to eq("test_key_name")
@@ -610,7 +607,7 @@ EOS
end
context "when name is not missing" do
it "should delete the key via the API" do
- expect(rest).to receive(:delete_rest).with(url).and_return({})
+ expect(rest).to receive(:delete).with(url).and_return({})
key.destroy
end
end
diff --git a/spec/unit/knife/bootstrap/chef_vault_handler_spec.rb b/spec/unit/knife/bootstrap/chef_vault_handler_spec.rb
index d8f84265b7..d822fe8f98 100644
--- a/spec/unit/knife/bootstrap/chef_vault_handler_spec.rb
+++ b/spec/unit/knife/bootstrap/chef_vault_handler_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Lamont Granquist <lamont@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::Bootstrap::ChefVaultHandler do
@@ -27,12 +27,12 @@ describe Chef::Knife::Bootstrap::ChefVaultHandler do
let(:knife_config) { {} }
- let(:node_name) { "bevell.wat" }
+ let(:client) { Chef::ApiClient.new }
- let(:chef_vault_handler) {
+ let(:chef_vault_handler) do
chef_vault_handler = Chef::Knife::Bootstrap::ChefVaultHandler.new(knife_config: knife_config, ui: ui)
chef_vault_handler
- }
+ end
context "when there's no vault option" do
it "should report its not doing anything" do
@@ -50,67 +50,66 @@ describe Chef::Knife::Bootstrap::ChefVaultHandler do
let(:bootstrap_vault_item) { double("ChefVault::Item") }
before do
- expect(chef_vault_handler).to receive(:wait_for_client).and_return(false)
expect(chef_vault_handler).to receive(:require_chef_vault!).at_least(:once)
- expect(bootstrap_vault_item).to receive(:clients).with("name:#{node_name}").at_least(:once)
+ expect(bootstrap_vault_item).to receive(:clients).with(client).at_least(:once)
expect(bootstrap_vault_item).to receive(:save).at_least(:once)
end
context "from knife_config[:bootstrap_vault_item]" do
it "sets a single item as a scalar" do
- knife_config[:bootstrap_vault_item] = { 'vault' => 'item1' }
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
- chef_vault_handler.run(node_name: node_name)
+ knife_config[:bootstrap_vault_item] = { "vault" => "item1" }
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+ chef_vault_handler.run(client)
end
it "sets a single item as an array" do
- knife_config[:bootstrap_vault_item] = { 'vault' => [ 'item1' ] }
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
- chef_vault_handler.run(node_name: node_name)
+ knife_config[:bootstrap_vault_item] = { "vault" => [ "item1" ] }
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+ chef_vault_handler.run(client)
end
it "sets two items as an array" do
- knife_config[:bootstrap_vault_item] = { 'vault' => [ 'item1', 'item2' ] }
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item2').and_return(bootstrap_vault_item)
- chef_vault_handler.run(node_name: node_name)
+ knife_config[:bootstrap_vault_item] = { "vault" => %w{item1 item2} }
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item2").and_return(bootstrap_vault_item)
+ chef_vault_handler.run(client)
end
it "sets two vaults from different hash keys" do
- knife_config[:bootstrap_vault_item] = { 'vault' => [ 'item1', 'item2' ], 'vault2' => [ 'item3' ] }
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item2').and_return(bootstrap_vault_item)
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault2', 'item3').and_return(bootstrap_vault_item)
- chef_vault_handler.run(node_name: node_name)
+ knife_config[:bootstrap_vault_item] = { "vault" => %w{item1 item2}, "vault2" => [ "item3" ] }
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item2").and_return(bootstrap_vault_item)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault2", "item3").and_return(bootstrap_vault_item)
+ chef_vault_handler.run(client)
end
end
context "from knife_config[:bootstrap_vault_json]" do
it "sets a single item as a scalar" do
knife_config[:bootstrap_vault_json] = '{ "vault": "item1" }'
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
- chef_vault_handler.run(node_name: node_name)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+ chef_vault_handler.run(client)
end
it "sets a single item as an array" do
knife_config[:bootstrap_vault_json] = '{ "vault": [ "item1" ] }'
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
- chef_vault_handler.run(node_name: node_name)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+ chef_vault_handler.run(client)
end
it "sets two items as an array" do
knife_config[:bootstrap_vault_json] = '{ "vault": [ "item1", "item2" ] }'
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item2').and_return(bootstrap_vault_item)
- chef_vault_handler.run(node_name: node_name)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item2").and_return(bootstrap_vault_item)
+ chef_vault_handler.run(client)
end
it "sets two vaults from different hash keys" do
knife_config[:bootstrap_vault_json] = '{ "vault": [ "item1", "item2" ], "vault2": [ "item3" ] }'
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item2').and_return(bootstrap_vault_item)
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault2', 'item3').and_return(bootstrap_vault_item)
- chef_vault_handler.run(node_name: node_name)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item2").and_return(bootstrap_vault_item)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault2", "item3").and_return(bootstrap_vault_item)
+ chef_vault_handler.run(client)
end
end
@@ -124,29 +123,29 @@ describe Chef::Knife::Bootstrap::ChefVaultHandler do
it "sets a single item as a scalar" do
setup_file_contents('{ "vault": "item1" }')
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
- chef_vault_handler.run(node_name: node_name)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+ chef_vault_handler.run(client)
end
it "sets a single item as an array" do
setup_file_contents('{ "vault": [ "item1" ] }')
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
- chef_vault_handler.run(node_name: node_name)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+ chef_vault_handler.run(client)
end
it "sets two items as an array" do
setup_file_contents('{ "vault": [ "item1", "item2" ] }')
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item2').and_return(bootstrap_vault_item)
- chef_vault_handler.run(node_name: node_name)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item2").and_return(bootstrap_vault_item)
+ chef_vault_handler.run(client)
end
it "sets two vaults from different hash keys" do
setup_file_contents('{ "vault": [ "item1", "item2" ], "vault2": [ "item3" ] }')
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item2').and_return(bootstrap_vault_item)
- expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault2', 'item3').and_return(bootstrap_vault_item)
- chef_vault_handler.run(node_name: node_name)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item2").and_return(bootstrap_vault_item)
+ expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault2", "item3").and_return(bootstrap_vault_item)
+ chef_vault_handler.run(client)
end
end
end
diff --git a/spec/unit/knife/bootstrap/client_builder_spec.rb b/spec/unit/knife/bootstrap/client_builder_spec.rb
index e7232fe8d6..97ba0fc48e 100644
--- a/spec/unit/knife/bootstrap/client_builder_spec.rb
+++ b/spec/unit/knife/bootstrap/client_builder_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Lamont Granquist <lamont@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
-
+require "spec_helper"
describe Chef::Knife::Bootstrap::ClientBuilder do
@@ -32,17 +31,17 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
let(:node_name) { "bevell.wat" }
- let(:rest) { double("Chef::REST") }
+ let(:rest) { double("Chef::ServerAPI") }
- let(:client_builder) {
+ let(:client_builder) do
client_builder = Chef::Knife::Bootstrap::ClientBuilder.new(knife_config: knife_config, chef_config: chef_config, ui: ui)
allow(client_builder).to receive(:rest).and_return(rest)
allow(client_builder).to receive(:node_name).and_return(node_name)
client_builder
- }
+ end
context "#sanity_check!" do
- let(:response_404) { OpenStruct.new(:code => '404') }
+ let(:response_404) { OpenStruct.new(:code => "404") }
let(:exception_404) { Net::HTTPServerException.new("404 not found", response_404) }
context "in cases where the prompting fails" do
@@ -53,15 +52,15 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
end
it "exits when the node exists and the user does not want to delete" do
- expect(rest).to receive(:get_rest).with("nodes/#{node_name}")
- expect(ui.stdin).to receive(:readline).and_return('n')
+ expect(rest).to receive(:get).with("nodes/#{node_name}")
+ expect(ui.stdin).to receive(:readline).and_return("n")
expect { client_builder.run }.to raise_error(SystemExit)
end
it "exits when the client exists and the user does not want to delete" do
- expect(rest).to receive(:get_rest).with("nodes/#{node_name}").and_raise(exception_404)
- expect(rest).to receive(:get_rest).with("clients/#{node_name}")
- expect(ui.stdin).to receive(:readline).and_return('n')
+ expect(rest).to receive(:get).with("nodes/#{node_name}").and_raise(exception_404)
+ expect(rest).to receive(:get).with("clients/#{node_name}")
+ expect(ui.stdin).to receive(:readline).and_return("n")
expect { client_builder.run }.to raise_error(SystemExit)
end
end
@@ -74,31 +73,31 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
end
it "when both the client and node do not exist it succeeds" do
- expect(rest).to receive(:get_rest).with("nodes/#{node_name}").and_raise(exception_404)
- expect(rest).to receive(:get_rest).with("clients/#{node_name}").and_raise(exception_404)
+ expect(rest).to receive(:get).with("nodes/#{node_name}").and_raise(exception_404)
+ expect(rest).to receive(:get).with("clients/#{node_name}").and_raise(exception_404)
expect { client_builder.run }.not_to raise_error
end
it "when we are allowed to delete an old node" do
- expect(rest).to receive(:get_rest).with("nodes/#{node_name}")
- expect(ui.stdin).to receive(:readline).and_return('y')
- expect(rest).to receive(:get_rest).with("clients/#{node_name}").and_raise(exception_404)
+ expect(rest).to receive(:get).with("nodes/#{node_name}")
+ expect(ui.stdin).to receive(:readline).and_return("y")
+ expect(rest).to receive(:get).with("clients/#{node_name}").and_raise(exception_404)
expect(rest).to receive(:delete).with("nodes/#{node_name}")
expect { client_builder.run }.not_to raise_error
end
it "when we are allowed to delete an old client" do
- expect(rest).to receive(:get_rest).with("nodes/#{node_name}").and_raise(exception_404)
- expect(rest).to receive(:get_rest).with("clients/#{node_name}")
- expect(ui.stdin).to receive(:readline).and_return('y')
+ expect(rest).to receive(:get).with("nodes/#{node_name}").and_raise(exception_404)
+ expect(rest).to receive(:get).with("clients/#{node_name}")
+ expect(ui.stdin).to receive(:readline).and_return("y")
expect(rest).to receive(:delete).with("clients/#{node_name}")
expect { client_builder.run }.not_to raise_error
end
it "when we are are allowed to delete both an old client and node" do
- expect(rest).to receive(:get_rest).with("nodes/#{node_name}")
- expect(rest).to receive(:get_rest).with("clients/#{node_name}")
- expect(ui.stdin).to receive(:readline).twice.and_return('y')
+ expect(rest).to receive(:get).with("nodes/#{node_name}")
+ expect(rest).to receive(:get).with("clients/#{node_name}")
+ expect(ui.stdin).to receive(:readline).twice.and_return("y")
expect(rest).to receive(:delete).with("nodes/#{node_name}")
expect(rest).to receive(:delete).with("clients/#{node_name}")
expect { client_builder.run }.not_to raise_error
@@ -107,17 +106,20 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
end
context "#create_client!" do
+ let(:client) { Chef::ApiClient.new }
+
before do
# mock out the rest of #run
expect(client_builder).to receive(:sanity_check)
expect(client_builder).to receive(:create_node!)
end
- it "delegates everything to Chef::ApiClient::Registration" do
+ it "delegates everything to Chef::ApiClient::Registration and sets client" do
reg_double = double("Chef::ApiClient::Registration")
expect(Chef::ApiClient::Registration).to receive(:new).with(node_name, client_builder.client_path, http_api: rest).and_return(reg_double)
- expect(reg_double).to receive(:run)
+ expect(reg_double).to receive(:run).and_return(client)
client_builder.run
+ expect(client_builder.client).to eq(client)
end
end
@@ -140,7 +142,7 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
expect(node).to receive(:save)
end
- let(:client_rest) { double("Chef::REST (client)") }
+ let(:client_rest) { double("Chef::ServerAPI (client)") }
let(:node) { double("Chef::Node") }
@@ -158,11 +160,11 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
it "adds tags to the node when given" do
tag_receiver = []
- knife_config[:tags] = %w[foo bar]
+ knife_config[:tags] = %w{foo bar}
allow(node).to receive(:run_list).with([])
allow(node).to receive(:tags).and_return(tag_receiver)
client_builder.run
- expect(tag_receiver).to eq %w[foo bar]
+ expect(tag_receiver).to eq %w{foo bar}
end
it "builds a node when the run_list is a string" do
@@ -178,8 +180,8 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
end
it "builds a node with first_boot_attributes if they're given" do
- knife_config[:first_boot_attributes] = {:baz => :quux}
- expect(node).to receive(:normal_attrs=).with({:baz=>:quux})
+ knife_config[:first_boot_attributes] = { :baz => :quux }
+ expect(node).to receive(:normal_attrs=).with({ :baz => :quux })
expect(node).to receive(:run_list).with([])
client_builder.run
end
diff --git a/spec/unit/knife/bootstrap_spec.rb b/spec/unit/knife/bootstrap_spec.rb
index 342c1878f1..9f944b82d9 100644
--- a/spec/unit/knife/bootstrap_spec.rb
+++ b/spec/unit/knife/bootstrap_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Ian Meyer (<ianmmeyer@gmail.com>)
-# Copyright:: Copyright (c) 2010 Ian Meyer
+# Copyright:: Copyright 2010-2016, Ian Meyer
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
Chef::Knife::Bootstrap.load_deps
-require 'net/ssh'
+require "net/ssh"
describe Chef::Knife::Bootstrap do
before do
@@ -51,7 +51,7 @@ describe Chef::Knife::Bootstrap do
context "with --bootstrap-vault-item" do
let(:bootstrap_cli_options) { [ "--bootstrap-vault-item", "vault1:item1", "--bootstrap-vault-item", "vault1:item2", "--bootstrap-vault-item", "vault2:item1" ] }
it "sets the knife config cli option correctly" do
- expect(knife.config[:bootstrap_vault_item]).to eq({"vault1"=>["item1", "item2"], "vault2"=>["item1"]})
+ expect(knife.config[:bootstrap_vault_item]).to eq({ "vault1" => %w{item1 item2}, "vault2" => ["item1"] })
end
end
@@ -85,7 +85,7 @@ describe Chef::Knife::Bootstrap do
let(:bootstrap_template) { "/opt/blah/not/exists/template.erb" }
it "raises an error" do
- expect { knife.find_template }.to raise_error
+ expect { knife.find_template }.to raise_error(Errno::ENOENT)
end
end
@@ -102,7 +102,7 @@ describe Chef::Knife::Bootstrap do
context "when :bootstrap_template config is set to a template name" do
let(:bootstrap_template) { "example" }
- let(:builtin_template_path) { File.expand_path(File.join(File.dirname(__FILE__), '../../../lib/chef/knife/bootstrap/templates', "example.erb"))}
+ let(:builtin_template_path) { File.expand_path(File.join(File.dirname(__FILE__), "../../../lib/chef/knife/bootstrap/templates", "example.erb")) }
let(:chef_config_dir_template_path) { "/knife/chef/config/bootstrap/example.erb" }
@@ -209,7 +209,7 @@ describe Chef::Knife::Bootstrap do
["-d", "--distro", "-t", "--bootstrap-template", "--template-file"].each do |t|
context "when #{t} option is given in the command line" do
it "sets the knife :bootstrap_template config" do
- knife.parse_options([t,"blahblah"])
+ knife.parse_options([t, "blahblah"])
knife.merge_configs
expect(knife.bootstrap_template).to eq("blahblah")
end
@@ -224,7 +224,7 @@ describe Chef::Knife::Bootstrap do
end
it "should have role[base] in the run_list" do
- knife.parse_options(["-r","role[base]"])
+ knife.parse_options(["-r", "role[base]"])
knife.merge_configs
expect(knife.render_template).to eq('{"run_list":["role[base]"]}')
end
@@ -236,11 +236,11 @@ describe Chef::Knife::Bootstrap do
end
context "with bootstrap_attribute options" do
- let(:jsonfile) {
- file = Tempfile.new (['node', '.json'])
- File.open(file.path, "w") {|f| f.puts '{"foo":{"bar":"baz"}}' }
+ let(:jsonfile) do
+ file = Tempfile.new (["node", ".json"])
+ File.open(file.path, "w") { |f| f.puts '{"foo":{"bar":"baz"}}' }
file
- }
+ end
it "should have foo => {bar => baz} in the first_boot from cli" do
knife.parse_options(["-j", '{"foo":{"bar":"baz"}}'])
@@ -264,7 +264,7 @@ describe Chef::Knife::Bootstrap do
knife.parse_options(["-j", '{"foo":{"bar":"baz"}}'])
knife.parse_options(["--json-attribute-file", jsonfile.path])
knife.merge_configs
- expect{ knife.run }.to raise_error(Chef::Exceptions::BootstrapCommandInputError)
+ expect { knife.run }.to raise_error(Chef::Exceptions::BootstrapCommandInputError)
jsonfile.close
end
end
@@ -297,7 +297,7 @@ describe Chef::Knife::Bootstrap do
k
end
- let(:options){ ["--bootstrap-no-proxy", setting, "-s", "foo"] }
+ let(:options) { ["--bootstrap-no-proxy", setting, "-s", "foo"] }
let(:template_file) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "no_proxy.erb")) }
let(:rendered_template) do
knife.render_template
@@ -339,7 +339,7 @@ describe Chef::Knife::Bootstrap do
let(:options) { ["--node-ssl-verify-mode", "all"] }
it "raises error" do
- expect{ rendered_template }.to raise_error
+ expect { rendered_template }.to raise_error(RuntimeError)
end
end
@@ -385,7 +385,7 @@ describe Chef::Knife::Bootstrap do
end
describe "when transferring trusted certificates" do
- let(:trusted_certs_dir) { Chef::Util::PathHelper.cleanpath(File.join(File.dirname(__FILE__), '../../data/trusted_certs')) }
+ let(:trusted_certs_dir) { Chef::Util::PathHelper.cleanpath(File.join(File.dirname(__FILE__), "../../data/trusted_certs")) }
let(:rendered_template) do
knife.merge_configs
@@ -422,11 +422,98 @@ describe Chef::Knife::Bootstrap do
end
end
+ context "when doing fips things" do
+ let(:template_file) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "no_proxy.erb")) }
+ let(:trusted_certs_dir) { Chef::Util::PathHelper.cleanpath(File.join(File.dirname(__FILE__), "../../data/trusted_certs")) }
+
+ before do
+ Chef::Config[:knife][:bootstrap_template] = template_file
+ end
+
+ let(:rendered_template) do
+ knife.render_template
+ end
+
+ context "when knife is in fips mode" do
+ before do
+ Chef::Config[:fips] = true
+ end
+
+ it "renders 'fips true'" do
+ Chef::Config[:fips] = true
+ expect(rendered_template).to match("fips")
+ end
+ end
+
+ context "when knife is not in fips mode" do
+ before do
+ # This is required because the chef-fips pipeline does
+ # has a default value of true for fips
+ Chef::Config[:fips] = false
+ end
+
+ it "does not render anything about fips" do
+ expect(rendered_template).not_to match("fips")
+ end
+ end
+ end
+
+ describe "when transferring client.d" do
+
+ let(:rendered_template) do
+ knife.merge_configs
+ knife.render_template
+ end
+
+ before do
+ Chef::Config[:client_d_dir] = client_d_dir
+ end
+
+ context "when client_d_dir is nil" do
+ let(:client_d_dir) { nil }
+
+ it "does not create /etc/chef/client.d" do
+ expect(rendered_template).not_to match(%r{mkdir -p /etc/chef/client\.d})
+ end
+ end
+
+ context "when client_d_dir is set" do
+ let(:client_d_dir) do
+ Chef::Util::PathHelper.cleanpath(
+ File.join(File.dirname(__FILE__), "../../data/client.d_00")) end
+
+ it "creates /etc/chef/client.d" do
+ expect(rendered_template).to match("mkdir -p /etc/chef/client\.d")
+ end
+
+ context "a flat directory structure" do
+ it "creates a file 00-foo.rb" do
+ expect(rendered_template).to match("cat > /etc/chef/client.d/00-foo.rb <<'EOP'")
+ expect(rendered_template).to match("d6f9b976-289c-4149-baf7-81e6ffecf228")
+ end
+ it "creates a file bar" do
+ expect(rendered_template).to match("cat > /etc/chef/client.d/bar <<'EOP'")
+ expect(rendered_template).to match("1 / 0")
+ end
+ end
+
+ context "a nested directory structure" do
+ let(:client_d_dir) do
+ Chef::Util::PathHelper.cleanpath(
+ File.join(File.dirname(__FILE__), "../../data/client.d_01")) end
+ it "creates a file foo/bar.rb" do
+ expect(rendered_template).to match("cat > /etc/chef/client.d/foo/bar.rb <<'EOP'")
+ expect(rendered_template).to match("1 / 0")
+ end
+ end
+ end
+ end
+
describe "handling policyfile options" do
context "when only policy_name is given" do
- let(:bootstrap_cli_options) { %w[ --policy-name my-app-server ] }
+ let(:bootstrap_cli_options) { %w{ --policy-name my-app-server } }
it "returns an error stating that policy_name and policy_group must be given together" do
expect { knife.validate_options! }.to raise_error(SystemExit)
@@ -437,7 +524,7 @@ describe Chef::Knife::Bootstrap do
context "when only policy_group is given" do
- let(:bootstrap_cli_options) { %w[ --policy-group staging ] }
+ let(:bootstrap_cli_options) { %w{ --policy-group staging } }
it "returns an error stating that policy_name and policy_group must be given together" do
expect { knife.validate_options! }.to raise_error(SystemExit)
@@ -448,7 +535,7 @@ describe Chef::Knife::Bootstrap do
context "when both policy_name and policy_group are given, but run list is also given" do
- let(:bootstrap_cli_options) { %w[ --policy-name my-app --policy-group staging --run-list cookbook ] }
+ let(:bootstrap_cli_options) { %w{ --policy-name my-app --policy-group staging --run-list cookbook } }
it "returns an error stating that policyfile and run_list are exclusive" do
expect { knife.validate_options! }.to raise_error(SystemExit)
@@ -459,7 +546,7 @@ describe Chef::Knife::Bootstrap do
context "when policy_name and policy_group are given with no conflicting options" do
- let(:bootstrap_cli_options) { %w[ --policy-name my-app --policy-group staging ] }
+ let(:bootstrap_cli_options) { %w{ --policy-name my-app --policy-group staging } }
it "passes options validation" do
expect { knife.validate_options! }.to_not raise_error
@@ -472,6 +559,21 @@ describe Chef::Knife::Bootstrap do
end
+ # https://github.com/chef/chef/issues/4131
+ # Arguably a bug in the plugin: it shouldn't be setting this to nil, but it
+ # worked before, so make it work now.
+ context "when a plugin sets the run list option to nil" do
+
+ before do
+ knife.config[:run_list] = nil
+ end
+
+ it "passes options validation" do
+ expect { knife.validate_options! }.to_not raise_error
+ end
+
+ end
+
end
describe "when configuring the underlying knife ssh command" do
@@ -484,7 +586,7 @@ describe Chef::Knife::Bootstrap do
Chef::Config[:knife][:ssh_user] = nil
Chef::Config[:knife][:ssh_port] = nil
knife.config[:forward_agent] = true
- knife.config[:identity_file] = "~/.ssh/me.rsa"
+ knife.config[:ssh_identity_file] = "~/.ssh/me.rsa"
allow(knife).to receive(:render_template).and_return("")
knife.knife_ssh
end
@@ -494,15 +596,15 @@ describe Chef::Knife::Bootstrap do
end
it "configures the ssh user" do
- expect(knife_ssh.config[:ssh_user]).to eq('rooty')
+ expect(knife_ssh.config[:ssh_user]).to eq("rooty")
end
it "configures the ssh password" do
- expect(knife_ssh.config[:ssh_password]).to eq('open_sesame')
+ expect(knife_ssh.config[:ssh_password]).to eq("open_sesame")
end
it "configures the ssh port" do
- expect(knife_ssh.config[:ssh_port]).to eq('4001')
+ expect(knife_ssh.config[:ssh_port]).to eq("4001")
end
it "configures the ssh agent forwarding" do
@@ -510,7 +612,7 @@ describe Chef::Knife::Bootstrap do
end
it "configures the ssh identity file" do
- expect(knife_ssh.config[:identity_file]).to eq('~/.ssh/me.rsa')
+ expect(knife_ssh.config[:ssh_identity_file]).to eq("~/.ssh/me.rsa")
end
end
@@ -521,9 +623,9 @@ describe Chef::Knife::Bootstrap do
end
it "use_sudo_password contains description and long params for help" do
- expect(knife.options).to have_key(:use_sudo_password) \
- and expect(knife.options[:use_sudo_password][:description].to_s).not_to eq('')\
- and expect(knife.options[:use_sudo_password][:long].to_s).not_to eq('')
+ expect(knife.options).to(have_key(:use_sudo_password)) \
+ && expect(knife.options[:use_sudo_password][:description].to_s).not_to(eq(""))\
+ && expect(knife.options[:use_sudo_password][:long].to_s).not_to(eq(""))
end
it "uses the password from --ssh-password for sudo when --use-sudo-password is set" do
@@ -545,7 +647,7 @@ describe Chef::Knife::Bootstrap do
Chef::Config[:knife][:ssh_user] = "curiosity"
Chef::Config[:knife][:ssh_port] = "2430"
Chef::Config[:knife][:forward_agent] = true
- Chef::Config[:knife][:identity_file] = "~/.ssh/you.rsa"
+ Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/you.rsa"
Chef::Config[:knife][:ssh_gateway] = "towel.blinkenlights.nl"
Chef::Config[:knife][:host_key_verify] = true
allow(knife).to receive(:render_template).and_return("")
@@ -555,11 +657,11 @@ describe Chef::Knife::Bootstrap do
end
it "configures the ssh user" do
- expect(knife_ssh.config[:ssh_user]).to eq('curiosity')
+ expect(knife_ssh.config[:ssh_user]).to eq("curiosity")
end
it "configures the ssh port" do
- expect(knife_ssh.config[:ssh_port]).to eq('2430')
+ expect(knife_ssh.config[:ssh_port]).to eq("2430")
end
it "configures the ssh agent forwarding" do
@@ -567,11 +669,11 @@ describe Chef::Knife::Bootstrap do
end
it "configures the ssh identity file" do
- expect(knife_ssh.config[:identity_file]).to eq('~/.ssh/you.rsa')
+ expect(knife_ssh.config[:ssh_identity_file]).to eq("~/.ssh/you.rsa")
end
it "configures the ssh gateway" do
- expect(knife_ssh.config[:ssh_gateway]).to eq('towel.blinkenlights.nl')
+ expect(knife_ssh.config[:ssh_gateway]).to eq("towel.blinkenlights.nl")
end
it "configures the host key verify mode" do
@@ -582,21 +684,21 @@ describe Chef::Knife::Bootstrap do
describe "when falling back to password auth when host key auth fails" do
let(:knife_ssh_with_password_auth) do
knife.name_args = ["foo.example.com"]
- knife.config[:ssh_user] = "rooty"
- knife.config[:identity_file] = "~/.ssh/me.rsa"
+ knife.config[:ssh_user] = "rooty"
+ knife.config[:ssh_identity_file] = "~/.ssh/me.rsa"
allow(knife).to receive(:render_template).and_return("")
k = knife.knife_ssh
- allow(k).to receive(:get_password).and_return('typed_in_password')
+ allow(k).to receive(:get_password).and_return("typed_in_password")
allow(knife).to receive(:knife_ssh).and_return(k)
knife.knife_ssh_with_password_auth
end
it "prompts the user for a password " do
- expect(knife_ssh_with_password_auth.config[:ssh_password]).to eq('typed_in_password')
+ expect(knife_ssh_with_password_auth.config[:ssh_password]).to eq("typed_in_password")
end
it "configures knife not to use the identity file that didn't work previously" do
- expect(knife_ssh_with_password_auth.config[:identity_file]).to be_nil
+ expect(knife_ssh_with_password_auth.config[:ssh_identity_file]).to be_nil
end
end
end
@@ -611,13 +713,14 @@ describe Chef::Knife::Bootstrap do
let(:knife_ssh) do
knife.name_args = ["foo.example.com"]
knife.config[:chef_node_name] = "foo.example.com"
- knife.config[:ssh_user] = "rooty"
- knife.config[:identity_file] = "~/.ssh/me.rsa"
+ knife.config[:ssh_user] = "rooty"
+ knife.config[:ssh_identity_file] = "~/.ssh/me.rsa"
allow(knife).to receive(:render_template).and_return("")
knife_ssh = knife.knife_ssh
allow(knife).to receive(:knife_ssh).and_return(knife_ssh)
knife_ssh
end
+ let(:client) { Chef::ApiClient.new }
context "when running with a configured and present validation key" do
before do
@@ -625,7 +728,6 @@ describe Chef::Knife::Bootstrap do
allow(File).to receive(:exist?).with(File.expand_path(Chef::Config[:validation_key])).and_return(true)
end
-
it "configures the underlying ssh command and then runs it" do
expect(knife_ssh).to receive(:run)
knife.run
@@ -651,7 +753,8 @@ describe Chef::Knife::Bootstrap do
knife.config[:bootstrap_vault_file] = "/not/our/responsibility/to/check/if/this/exists"
expect(knife_ssh).to receive(:run)
expect(knife.client_builder).to receive(:run)
- expect(knife.chef_vault_handler).to receive(:run).with(node_name: knife.config[:chef_node_name])
+ expect(knife.client_builder).to receive(:client).and_return(client)
+ expect(knife.chef_vault_handler).to receive(:run).with(client)
knife.run
end
@@ -659,7 +762,8 @@ describe Chef::Knife::Bootstrap do
knife.config[:bootstrap_vault_json] = '{ "vault" => "item" }'
expect(knife_ssh).to receive(:run)
expect(knife.client_builder).to receive(:run)
- expect(knife.chef_vault_handler).to receive(:run).with(node_name: knife.config[:chef_node_name])
+ expect(knife.client_builder).to receive(:client).and_return(client)
+ expect(knife.chef_vault_handler).to receive(:run).with(client)
knife.run
end
@@ -667,7 +771,7 @@ describe Chef::Knife::Bootstrap do
expect(File).to receive(:exist?).with(File.expand_path(Chef::Config[:validation_key])).and_return(true)
expect(knife_ssh).to receive(:run)
expect(knife.client_builder).not_to receive(:run)
- expect(knife.chef_vault_handler).not_to receive(:run).with(node_name: knife.config[:chef_node_name])
+ expect(knife.chef_vault_handler).not_to receive(:run)
knife.run
end
@@ -687,7 +791,8 @@ describe Chef::Knife::Bootstrap do
it "creates the client (and possibly adds chef-vault items)" do
expect(knife_ssh).to receive(:run)
expect(knife.client_builder).to receive(:run)
- expect(knife.chef_vault_handler).to receive(:run).with(node_name: knife.config[:chef_node_name])
+ expect(knife.client_builder).to receive(:client).and_return(client)
+ expect(knife.chef_vault_handler).to receive(:run).with(client)
knife.run
end
@@ -716,5 +821,4 @@ describe Chef::Knife::Bootstrap do
describe "specifying ssl verification" do
end
-
end
diff --git a/spec/unit/knife/client_bulk_delete_spec.rb b/spec/unit/knife/client_bulk_delete_spec.rb
index 1a6317ac00..994f4d33a4 100644
--- a/spec/unit/knife/client_bulk_delete_spec.rb
+++ b/spec/unit/knife/client_bulk_delete_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::ClientBulkDelete do
let(:stdout_io) { StringIO.new }
- let(:stdout) {stdout_io.string}
+ let(:stdout) { stdout_io.string }
let(:stderr_io) { StringIO.new }
let(:stderr) { stderr_io.string }
- let(:knife) {
+ let(:knife) do
k = Chef::Knife::ClientBulkDelete.new
k.name_args = name_args
k.config = option_args
@@ -33,7 +33,7 @@ describe Chef::Knife::ClientBulkDelete do
allow(k.ui).to receive(:confirm).and_return(knife_confirm)
allow(k.ui).to receive(:confirm_without_exit).and_return(knife_confirm)
k
- }
+ end
let(:name_args) { [ "." ] }
let(:option_args) { {} }
@@ -41,7 +41,7 @@ describe Chef::Knife::ClientBulkDelete do
let(:knife_confirm) { true }
let(:nonvalidator_client_names) { %w{tim dan stephen} }
- let(:nonvalidator_clients) {
+ let(:nonvalidator_clients) do
clients = Hash.new
nonvalidator_client_names.each do |client_name|
@@ -52,10 +52,10 @@ describe Chef::Knife::ClientBulkDelete do
end
clients
- }
+ end
let(:validator_client_names) { %w{myorg-validator} }
- let(:validator_clients) {
+ let(:validator_clients) do
clients = Hash.new
validator_client_names.each do |validator_client_name|
@@ -67,12 +67,12 @@ describe Chef::Knife::ClientBulkDelete do
end
clients
- }
+ end
- let(:client_names) { nonvalidator_client_names + validator_client_names}
- let(:clients) {
+ let(:client_names) { nonvalidator_client_names + validator_client_names }
+ let(:clients) do
nonvalidator_clients.merge(validator_clients)
- }
+ end
before(:each) do
allow(Chef::ApiClientV1).to receive(:list).and_return(clients)
@@ -108,8 +108,8 @@ describe Chef::Knife::ClientBulkDelete do
describe "without --delete-validators" do
it "should mention that validator clients wont be deleted" do
knife.run
- expect(stdout).to include("Following clients are validators and will not be deleted.")
- info = stdout.index "Following clients are validators and will not be deleted."
+ expect(stdout).to include("The following clients are validators and will not be deleted:")
+ info = stdout.index "The following clients are validators and will not be deleted:"
val = stdout.index "myorg-validator"
expect(val > info).to be_truthy
end
@@ -128,7 +128,7 @@ describe Chef::Knife::ClientBulkDelete do
end
describe "with --delete-validators" do
- let(:option_args) { {:delete_validators => true} }
+ let(:option_args) { { :delete_validators => true } }
it "should mention that validator clients will be deleted" do
knife.run
diff --git a/spec/unit/knife/client_create_spec.rb b/spec/unit/knife/client_create_spec.rb
index a1dcc564e2..17d18d084e 100644
--- a/spec/unit/knife/client_create_spec.rb
+++ b/spec/unit/knife/client_create_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
Chef::Knife::ClientCreate.load_deps
@@ -24,12 +24,11 @@ describe Chef::Knife::ClientCreate do
let(:stderr) { StringIO.new }
let(:stdout) { StringIO.new }
-
let(:default_client_hash) do
{
"name" => "adam",
"validator" => false,
- "admin" => false
+ "admin" => false,
}
end
@@ -41,7 +40,7 @@ describe Chef::Knife::ClientCreate do
k = Chef::Knife::ClientCreate.new
k.name_args = []
allow(k).to receive(:client).and_return(client)
- allow(k).to receive(:edit_data).with(client).and_return(client)
+ allow(k).to receive(:edit_hash).with(client).and_return(client)
allow(k.ui).to receive(:stderr).and_return(stderr)
allow(k.ui).to receive(:stdout).and_return(stdout)
k
@@ -53,7 +52,7 @@ describe Chef::Knife::ClientCreate do
end
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
end
describe "run" do
@@ -61,13 +60,13 @@ describe Chef::Knife::ClientCreate do
# from spec/support/shared/unit/knife_shared.rb
it_should_behave_like "mandatory field missing" do
let(:name_args) { [] }
- let(:fieldname) { 'client name' }
+ let(:fieldname) { "client name" }
end
end
context "when clientname is passed" do
before do
- knife.name_args = ['adam']
+ knife.name_args = ["adam"]
end
context "when public_key and prevent_keygen are passed" do
@@ -119,7 +118,7 @@ describe Chef::Knife::ClientCreate do
end
it "should allow you to edit the data" do
- expect(knife).to receive(:edit_data).with(client).and_return(client)
+ expect(knife).to receive(:edit_hash).with(client).and_return(client)
knife.run
end
@@ -131,7 +130,7 @@ describe Chef::Knife::ClientCreate do
it "should write the private key to a file" do
knife.config[:file] = "/tmp/monkeypants"
filehandle = double("Filehandle")
- expect(filehandle).to receive(:print).with('woot')
+ expect(filehandle).to receive(:print).with("woot")
expect(File).to receive(:open).with("/tmp/monkeypants", "w").and_yield(filehandle)
knife.run
end
@@ -150,14 +149,14 @@ describe Chef::Knife::ClientCreate do
describe "with -p or --public-key" do
before do
- knife.config[:public_key] = 'some_key'
- allow(File).to receive(:read).and_return('some_key')
+ knife.config[:public_key] = "some_key"
+ allow(File).to receive(:read).and_return("some_key")
allow(File).to receive(:expand_path)
end
it "sets the public key" do
knife.run
- expect(client.public_key).to eq('some_key')
+ expect(client.public_key).to eq("some_key")
end
end
diff --git a/spec/unit/knife/client_delete_spec.rb b/spec/unit/knife/client_delete_spec.rb
index 619009979b..f20b25f5e6 100644
--- a/spec/unit/knife/client_delete_spec.rb
+++ b/spec/unit/knife/client_delete_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,25 +16,41 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::ClientDelete do
before(:each) do
@knife = Chef::Knife::ClientDelete.new
# defaults
@knife.config = {
- :delete_validators => false
+ :delete_validators => false,
}
- @knife.name_args = [ 'adam' ]
+ @knife.name_args = [ "adam" ]
end
- describe 'run' do
- it 'should delete the client' do
- expect(@knife).to receive(:delete_object).with(Chef::ApiClientV1, 'adam', 'client')
+ describe "run" do
+ it "should delete the client" do
+ expect(@knife).to receive(:delete_object).with(Chef::ApiClientV1, "adam", "client")
@knife.run
end
- it 'should print usage and exit when a client name is not provided' do
+ context "receives multiple clients" do
+ let(:clients) { %w{ "adam", "ben", "charlie" } }
+
+ before(:each) do
+ @knife.name_args = clients
+ end
+
+ it "deletes all clients" do
+ clients.each do |client|
+ expect(@knife).to receive(:delete_object).with(Chef::ApiClientV1, client, "client")
+ end
+
+ @knife.run
+ end
+ end
+
+ it "should print usage and exit when a client name is not provided" do
@knife.name_args = []
expect(@knife).to receive(:show_usage)
expect(@knife.ui).to receive(:fatal)
@@ -42,7 +58,7 @@ describe Chef::Knife::ClientDelete do
end
end
- describe 'with a validator' do
+ describe "with a validator" do
before(:each) do
allow(Chef::Knife::UI).to receive(:confirm).and_return(true)
allow(@knife).to receive(:confirm).and_return(true)
@@ -50,7 +66,7 @@ describe Chef::Knife::ClientDelete do
expect(Chef::ApiClientV1).to receive(:load).and_return(@client)
end
- it 'should delete non-validator client if --delete-validators is not set' do
+ it "should delete non-validator client if --delete-validators is not set" do
@knife.config[:delete_validators] = false
expect(@client).to receive(:destroy).and_return(@client)
expect(@knife).to receive(:msg)
@@ -58,7 +74,7 @@ describe Chef::Knife::ClientDelete do
@knife.run
end
- it 'should delete non-validator client if --delete-validators is set' do
+ it "should delete non-validator client if --delete-validators is set" do
@knife.config[:delete_validators] = true
expect(@client).to receive(:destroy).and_return(@client)
expect(@knife).to receive(:msg)
@@ -66,13 +82,13 @@ describe Chef::Knife::ClientDelete do
@knife.run
end
- it 'should not delete validator client if --delete-validators is not set' do
+ it "should not delete validator client if --delete-validators is not set" do
@client.validator(true)
expect(@knife.ui).to receive(:fatal)
- expect { @knife.run}.to raise_error(SystemExit)
+ expect { @knife.run }.to raise_error(SystemExit)
end
- it 'should delete validator client if --delete-validators is set' do
+ it "should delete validator client if --delete-validators is set" do
@knife.config[:delete_validators] = true
expect(@client).to receive(:destroy).and_return(@client)
expect(@knife).to receive(:msg)
diff --git a/spec/unit/knife/client_edit_spec.rb b/spec/unit/knife/client_edit_spec.rb
index ad56d9212d..e7c9030883 100644
--- a/spec/unit/knife/client_edit_spec.rb
+++ b/spec/unit/knife/client_edit_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,34 +16,34 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/api_client_v1'
+require "spec_helper"
+require "chef/api_client_v1"
describe Chef::Knife::ClientEdit do
before(:each) do
@knife = Chef::Knife::ClientEdit.new
- @knife.name_args = [ 'adam' ]
+ @knife.name_args = [ "adam" ]
@knife.config[:disable_editing] = true
end
- describe 'run' do
- let(:data) {
+ describe "run" do
+ let(:data) do
{
"name" => "adam",
"validator" => false,
"admin" => false,
"chef_type" => "client",
- "create_key" => true
+ "create_key" => true,
}
- }
+ end
- it 'should edit the client' do
- allow(Chef::ApiClientV1).to receive(:load).with('adam').and_return(data)
- expect(@knife).to receive(:edit_data).with(data).and_return(data)
+ it "should edit the client" do
+ allow(Chef::ApiClientV1).to receive(:load).with("adam").and_return(data)
+ expect(@knife).to receive(:edit_hash).with(data).and_return(data)
@knife.run
end
- it 'should print usage and exit when a client name is not provided' do
+ it "should print usage and exit when a client name is not provided" do
@knife.name_args = []
expect(@knife).to receive(:show_usage)
expect(@knife.ui).to receive(:fatal)
diff --git a/spec/unit/knife/client_list_spec.rb b/spec/unit/knife/client_list_spec.rb
index ce0fa4f5e8..d1b379a787 100644
--- a/spec/unit/knife/client_list_spec.rb
+++ b/spec/unit/knife/client_list_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::ClientList do
before(:each) do
@knife = Chef::Knife::ClientList.new
- @knife.name_args = [ 'adam' ]
+ @knife.name_args = [ "adam" ]
end
- describe 'run' do
- it 'should list the clients' do
+ describe "run" do
+ it "should list the clients" do
expect(Chef::ApiClientV1).to receive(:list)
expect(@knife).to receive(:format_list_for_display)
@knife.run
diff --git a/spec/unit/knife/client_reregister_spec.rb b/spec/unit/knife/client_reregister_spec.rb
index 7e763242e4..6776cafa0a 100644
--- a/spec/unit/knife/client_reregister_spec.rb
+++ b/spec/unit/knife/client_reregister_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::ClientReregister do
before(:each) do
@knife = Chef::Knife::ClientReregister.new
- @knife.name_args = [ 'adam' ]
- @client_mock = double('client_mock', :private_key => "foo_key")
+ @knife.name_args = [ "adam" ]
+ @client_mock = double("client_mock", :private_key => "foo_key")
@stdout = StringIO.new
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
end
@@ -32,28 +32,28 @@ describe Chef::Knife::ClientReregister do
@knife.name_args = []
end
- it 'should print usage and exit when a client name is not provided' do
+ it "should print usage and exit when a client name is not provided" do
expect(@knife).to receive(:show_usage)
expect(@knife.ui).to receive(:fatal)
expect { @knife.run }.to raise_error(SystemExit)
end
end
- context 'when not configured for file output' do
- it 'reregisters the client and prints the key' do
- expect(Chef::ApiClientV1).to receive(:reregister).with('adam').and_return(@client_mock)
+ context "when not configured for file output" do
+ it "reregisters the client and prints the key" do
+ expect(Chef::ApiClientV1).to receive(:reregister).with("adam").and_return(@client_mock)
@knife.run
expect(@stdout.string).to match( /foo_key/ )
end
end
- context 'when configured for file output' do
- it 'should write the private key to a file' do
- expect(Chef::ApiClientV1).to receive(:reregister).with('adam').and_return(@client_mock)
+ context "when configured for file output" do
+ it "should write the private key to a file" do
+ expect(Chef::ApiClientV1).to receive(:reregister).with("adam").and_return(@client_mock)
- @knife.config[:file] = '/tmp/monkeypants'
+ @knife.config[:file] = "/tmp/monkeypants"
filehandle = StringIO.new
- expect(File).to receive(:open).with('/tmp/monkeypants', 'w').and_yield(filehandle)
+ expect(File).to receive(:open).with("/tmp/monkeypants", "w").and_yield(filehandle)
@knife.run
expect(filehandle.string).to eq("foo_key")
end
diff --git a/spec/unit/knife/client_show_spec.rb b/spec/unit/knife/client_show_spec.rb
index 73a876cee0..47b4b6ccb0 100644
--- a/spec/unit/knife/client_show_spec.rb
+++ b/spec/unit/knife/client_show_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,33 +16,33 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::ClientShow do
before(:each) do
@knife = Chef::Knife::ClientShow.new
- @knife.name_args = [ 'adam' ]
- @client_mock = double('client_mock')
+ @knife.name_args = [ "adam" ]
+ @client_mock = double("client_mock")
end
- describe 'run' do
- it 'should list the client' do
- expect(Chef::ApiClientV1).to receive(:load).with('adam').and_return(@client_mock)
+ describe "run" do
+ it "should list the client" do
+ expect(Chef::ApiClientV1).to receive(:load).with("adam").and_return(@client_mock)
expect(@knife).to receive(:format_for_display).with(@client_mock)
@knife.run
end
- it 'should pretty print json' do
- @knife.config[:format] = 'json'
+ it "should pretty print json" do
+ @knife.config[:format] = "json"
@stdout = StringIO.new
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
- fake_client_contents = {"foo"=>"bar", "baz"=>"qux"}
- expect(Chef::ApiClientV1).to receive(:load).with('adam').and_return(fake_client_contents)
+ fake_client_contents = { "foo" => "bar", "baz" => "qux" }
+ expect(Chef::ApiClientV1).to receive(:load).with("adam").and_return(fake_client_contents)
@knife.run
expect(@stdout.string).to eql("{\n \"foo\": \"bar\",\n \"baz\": \"qux\"\n}\n")
end
- it 'should print usage and exit when a client name is not provided' do
+ it "should print usage and exit when a client name is not provided" do
@knife.name_args = []
expect(@knife).to receive(:show_usage)
expect(@knife.ui).to receive(:fatal)
diff --git a/spec/unit/knife/configure_client_spec.rb b/spec/unit/knife/configure_client_spec.rb
index 363743f8cc..3ecb89f827 100644
--- a/spec/unit/knife/configure_client_spec.rb
+++ b/spec/unit/knife/configure_client_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,46 +16,46 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::ConfigureClient do
before do
@knife = Chef::Knife::ConfigureClient.new
- Chef::Config[:chef_server_url] = 'https://chef.example.com'
- Chef::Config[:validation_client_name] = 'chef-validator'
- Chef::Config[:validation_key] = '/etc/chef/validation.pem'
+ Chef::Config[:chef_server_url] = "https://chef.example.com"
+ Chef::Config[:validation_client_name] = "chef-validator"
+ Chef::Config[:validation_key] = "/etc/chef/validation.pem"
@stderr = StringIO.new
allow(@knife.ui).to receive(:stderr).and_return(@stderr)
end
- describe 'run' do
- it 'should print usage and exit when a directory is not provided' do
+ describe "run" do
+ it "should print usage and exit when a directory is not provided" do
expect(@knife).to receive(:show_usage)
expect(@knife.ui).to receive(:fatal).with(/must provide the directory/)
- expect {
+ expect do
@knife.run
- }.to raise_error SystemExit
+ end.to raise_error SystemExit
end
- describe 'when specifing a directory' do
+ describe "when specifing a directory" do
before do
- @knife.name_args = ['/home/bob/.chef']
+ @knife.name_args = ["/home/bob/.chef"]
@client_file = StringIO.new
@validation_file = StringIO.new
- expect(File).to receive(:open).with('/home/bob/.chef/client.rb', 'w').
- and_yield(@client_file)
- expect(File).to receive(:open).with('/home/bob/.chef/validation.pem', 'w').
- and_yield(@validation_file)
- expect(IO).to receive(:read).and_return('foo_bar_baz')
+ expect(File).to receive(:open).with("/home/bob/.chef/client.rb", "w").
+ and_yield(@client_file)
+ expect(File).to receive(:open).with("/home/bob/.chef/validation.pem", "w").
+ and_yield(@validation_file)
+ expect(IO).to receive(:read).and_return("foo_bar_baz")
end
- it 'should recursively create the directory' do
- expect(FileUtils).to receive(:mkdir_p).with('/home/bob/.chef')
+ it "should recursively create the directory" do
+ expect(FileUtils).to receive(:mkdir_p).with("/home/bob/.chef")
@knife.run
end
- it 'should write out the config file' do
+ it "should write out the config file" do
allow(FileUtils).to receive(:mkdir_p)
@knife.run
expect(@client_file.string).to match /log_level\s+\:info/
@@ -64,13 +64,13 @@ describe Chef::Knife::ConfigureClient do
expect(@client_file.string).to match /validation_client_name\s+'chef-validator'/
end
- it 'should write out the validation.pem file' do
+ it "should write out the validation.pem file" do
allow(FileUtils).to receive(:mkdir_p)
@knife.run
expect(@validation_file.string).to match /foo_bar_baz/
end
- it 'should print information on what is being configured' do
+ it "should print information on what is being configured" do
allow(FileUtils).to receive(:mkdir_p)
@knife.run
expect(@stderr.string).to match /creating client configuration/i
@@ -81,4 +81,3 @@ describe Chef::Knife::ConfigureClient do
end
end
-
diff --git a/spec/unit/knife/configure_spec.rb b/spec/unit/knife/configure_spec.rb
index e3ea1f052c..b7802d3890 100644
--- a/spec/unit/knife/configure_spec.rb
+++ b/spec/unit/knife/configure_spec.rb
@@ -1,17 +1,17 @@
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::Configure do
before do
Chef::Log.logger = Logger.new(StringIO.new)
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::Configure.new
- @rest_client = double("null rest client", :post_rest => { :result => :true })
+ @rest_client = double("null rest client", :post => { :result => :true })
allow(@knife).to receive(:rest).and_return(@rest_client)
@out = StringIO.new
allow(@knife.ui).to receive(:stdout).and_return(@out)
- @knife.config[:config_file] = '/home/you/.chef/knife.rb'
+ @knife.config[:config_file] = "/home/you/.chef/knife.rb"
@in = StringIO.new("\n" * 7)
allow(@knife.ui).to receive(:stdin).and_return(@in)
@@ -22,7 +22,6 @@ describe Chef::Knife::Configure do
allow(Ohai::System).to receive(:new).and_return(ohai)
end
-
let(:fqdn) { "foo.example.org" }
let(:ohai) do
@@ -39,8 +38,7 @@ describe Chef::Knife::Configure do
let(:default_validator_key) { "/etc/chef-server/chef-validator.pem" }
let(:default_validator_key_win32) { File.expand_path(default_validator_key) }
- let(:default_server_url) { "https://#{fqdn}:443" }
-
+ let(:default_server_url) { "https://#{fqdn}/organizations/myorg" }
it "asks the user for the URL of the chef server" do
@knife.ask_user_for_config
@@ -58,11 +56,11 @@ describe Chef::Knife::Configure do
it "should not ask the user for the clientname they want for the new client if -i and --node_name are specified" do
@knife.config[:initial] = true
- @knife.config[:node_name] = 'testnode'
+ @knife.config[:node_name] = "testnode"
allow(Etc).to receive(:getlogin).and_return("a-new-user")
@knife.ask_user_for_config
expect(@out.string).not_to match(Regexp.escape("Please enter a name for the new user"))
- expect(@knife.new_client_name).to eq('testnode')
+ expect(@knife.new_client_name).to eq("testnode")
end
it "asks the user for the existing API username or clientname if -i is not specified" do
@@ -76,21 +74,21 @@ describe Chef::Knife::Configure do
@knife.config[:initial] = true
@knife.ask_user_for_config
expect(@out.string).to match(Regexp.escape("Please enter the existing admin name: [admin]"))
- expect(@knife.admin_client_name).to eq('admin')
+ expect(@knife.admin_client_name).to eq("admin")
end
it "should not ask the user for the existing admin client's name if -i and --admin-client_name are specified" do
@knife.config[:initial] = true
- @knife.config[:admin_client_name] = 'my-webui'
+ @knife.config[:admin_client_name] = "my-webui"
@knife.ask_user_for_config
expect(@out.string).not_to match(Regexp.escape("Please enter the existing admin:"))
- expect(@knife.admin_client_name).to eq('my-webui')
+ expect(@knife.admin_client_name).to eq("my-webui")
end
it "should not ask the user for the existing admin client's name if -i is not specified" do
@knife.ask_user_for_config
expect(@out.string).not_to match(Regexp.escape("Please enter the existing admin: [admin]"))
- expect(@knife.admin_client_name).not_to eq('admin')
+ expect(@knife.admin_client_name).not_to eq("admin")
end
it "asks the user for the location of the existing admin key if -i is specified" do
@@ -106,13 +104,13 @@ describe Chef::Knife::Configure do
it "should not ask the user for the location of the existing admin key if -i and --admin_client_key are specified" do
@knife.config[:initial] = true
- @knife.config[:admin_client_key] = '/home/you/.chef/my-webui.pem'
+ @knife.config[:admin_client_key] = "/home/you/.chef/my-webui.pem"
@knife.ask_user_for_config
expect(@out.string).not_to match(Regexp.escape("Please enter the location of the existing admin client's private key:"))
if windows?
expect(@knife.admin_client_key).to match %r{^[A-Za-z]:/home/you/\.chef/my-webui\.pem$}
else
- expect(@knife.admin_client_key).to eq('/home/you/.chef/my-webui.pem')
+ expect(@knife.admin_client_key).to eq("/home/you/.chef/my-webui.pem")
end
end
@@ -129,20 +127,20 @@ describe Chef::Knife::Configure do
it "asks the user for the location of a chef repo" do
@knife.ask_user_for_config
expect(@out.string).to match(Regexp.escape("Please enter the path to a chef repository (or leave blank):"))
- expect(@knife.chef_repo).to eq('')
+ expect(@knife.chef_repo).to eq("")
end
it "asks the users for the name of the validation client" do
@knife.ask_user_for_config
expect(@out.string).to match(Regexp.escape("Please enter the validation clientname: [chef-validator]"))
- expect(@knife.validation_client_name).to eq('chef-validator')
+ expect(@knife.validation_client_name).to eq("chef-validator")
end
it "should not ask the users for the name of the validation client if --validation_client_name is specified" do
- @knife.config[:validation_client_name] = 'my-validator'
+ @knife.config[:validation_client_name] = "my-validator"
@knife.ask_user_for_config
expect(@out.string).not_to match(Regexp.escape("Please enter the validation clientname:"))
- expect(@knife.validation_client_name).to eq('my-validator')
+ expect(@knife.validation_client_name).to eq("my-validator")
end
it "asks the users for the location of the validation key" do
@@ -156,45 +154,45 @@ describe Chef::Knife::Configure do
end
it "should not ask the users for the location of the validation key if --validation_key is specified" do
- @knife.config[:validation_key] = '/home/you/.chef/my-validation.pem'
+ @knife.config[:validation_key] = "/home/you/.chef/my-validation.pem"
@knife.ask_user_for_config
expect(@out.string).not_to match(Regexp.escape("Please enter the location of the validation key:"))
if windows?
expect(@knife.validation_key).to match %r{^[A-Za-z]:/home/you/\.chef/my-validation\.pem$}
else
- expect(@knife.validation_key).to eq('/home/you/.chef/my-validation.pem')
+ expect(@knife.validation_key).to eq("/home/you/.chef/my-validation.pem")
end
end
it "should not ask the user for anything if -i and all other properties are specified" do
@knife.config[:initial] = true
- @knife.config[:chef_server_url] = 'http://localhost:5000'
- @knife.config[:node_name] = 'testnode'
- @knife.config[:admin_client_name] = 'my-webui'
- @knife.config[:admin_client_key] = '/home/you/.chef/my-webui.pem'
- @knife.config[:validation_client_name] = 'my-validator'
- @knife.config[:validation_key] = '/home/you/.chef/my-validation.pem'
- @knife.config[:repository] = ''
- @knife.config[:client_key] = '/home/you/a-new-user.pem'
- allow(Etc).to receive(:getlogin).and_return('a-new-user')
+ @knife.config[:chef_server_url] = "http://localhost:5000"
+ @knife.config[:node_name] = "testnode"
+ @knife.config[:admin_client_name] = "my-webui"
+ @knife.config[:admin_client_key] = "/home/you/.chef/my-webui.pem"
+ @knife.config[:validation_client_name] = "my-validator"
+ @knife.config[:validation_key] = "/home/you/.chef/my-validation.pem"
+ @knife.config[:repository] = ""
+ @knife.config[:client_key] = "/home/you/a-new-user.pem"
+ allow(Etc).to receive(:getlogin).and_return("a-new-user")
@knife.ask_user_for_config
expect(@out.string).to match(/\s*/)
- expect(@knife.new_client_name).to eq('testnode')
- expect(@knife.chef_server).to eq('http://localhost:5000')
- expect(@knife.admin_client_name).to eq('my-webui')
+ expect(@knife.new_client_name).to eq("testnode")
+ expect(@knife.chef_server).to eq("http://localhost:5000")
+ expect(@knife.admin_client_name).to eq("my-webui")
if windows?
expect(@knife.admin_client_key).to match %r{^[A-Za-z]:/home/you/\.chef/my-webui\.pem$}
expect(@knife.validation_key).to match %r{^[A-Za-z]:/home/you/\.chef/my-validation\.pem$}
expect(@knife.new_client_key).to match %r{^[A-Za-z]:/home/you/a-new-user\.pem$}
else
- expect(@knife.admin_client_key).to eq('/home/you/.chef/my-webui.pem')
- expect(@knife.validation_key).to eq('/home/you/.chef/my-validation.pem')
- expect(@knife.new_client_key).to eq('/home/you/a-new-user.pem')
+ expect(@knife.admin_client_key).to eq("/home/you/.chef/my-webui.pem")
+ expect(@knife.validation_key).to eq("/home/you/.chef/my-validation.pem")
+ expect(@knife.new_client_key).to eq("/home/you/a-new-user.pem")
end
- expect(@knife.validation_client_name).to eq('my-validator')
- expect(@knife.chef_repo).to eq('')
+ expect(@knife.validation_client_name).to eq("my-validator")
+ expect(@knife.chef_repo).to eq("")
end
it "writes the new data to a config file" do
@@ -205,7 +203,7 @@ describe Chef::Knife::Configure do
expect(FileUtils).to receive(:mkdir_p).with("/home/you/.chef")
config_file = StringIO.new
expect(::File).to receive(:open).with("/home/you/.chef/knife.rb", "w").and_yield config_file
- @knife.config[:repository] = '/home/you/chef-repo'
+ @knife.config[:repository] = "/home/you/chef-repo"
@knife.run
expect(config_file.string).to match(/^node_name[\s]+'#{Etc.getlogin}'$/)
expect(config_file.string).to match(%r{^client_key[\s]+'/home/you/.chef/#{Etc.getlogin}.pem'$})
@@ -220,7 +218,7 @@ describe Chef::Knife::Configure do
expect(File).to receive(:expand_path).with("/home/you/.chef/a-new-user.pem").and_return("/home/you/.chef/a-new-user.pem")
expect(File).to receive(:expand_path).with(default_validator_key).and_return(default_validator_key)
expect(File).to receive(:expand_path).with(default_admin_key).and_return(default_admin_key)
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
user_command = Chef::Knife::UserCreate.new
expect(user_command).to receive(:run)
diff --git a/spec/unit/knife/cookbook_bulk_delete_spec.rb b/spec/unit/knife/cookbook_bulk_delete_spec.rb
index 98cd06bbbc..62b8c9fe51 100644
--- a/spec/unit/knife/cookbook_bulk_delete_spec.rb
+++ b/spec/unit/knife/cookbook_bulk_delete_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::CookbookBulkDelete do
before(:each) do
Chef::Log.logger = Logger.new(StringIO.new)
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::CookbookBulkDelete.new
- @knife.config = {:print_after => nil}
+ @knife.config = { :print_after => nil }
@knife.name_args = ["."]
@stdout = StringIO.new
@stderr = StringIO.new
@@ -36,24 +36,22 @@ describe Chef::Knife::CookbookBulkDelete do
cookbook = Chef::CookbookVersion.new(cookbook_name)
@cookbooks[cookbook_name] = cookbook
end
- @rest = double("Chef::REST")
- allow(@rest).to receive(:get_rest).and_return(@cookbooks)
- allow(@rest).to receive(:delete_rest).and_return(true)
+ @rest = double("Chef::ServerAPI")
+ allow(@rest).to receive(:get).and_return(@cookbooks)
+ allow(@rest).to receive(:delete).and_return(true)
allow(@knife).to receive(:rest).and_return(@rest)
allow(Chef::CookbookVersion).to receive(:list).and_return(@cookbooks)
end
-
-
describe "when there are several cookbooks on the server" do
before do
- @cheezburger = {'cheezburger' => {"url" => "file:///dev/null", "versions" => [{"url" => "file:///dev/null-cheez", "version" => "1.0.0"}]}}
- allow(@rest).to receive(:get_rest).with('cookbooks/cheezburger').and_return(@cheezburger)
- @pizza = {'pizza' => {"url" => "file:///dev/null", "versions" => [{"url" => "file:///dev/null-pizza", "version" => "2.0.0"}]}}
- allow(@rest).to receive(:get_rest).with('cookbooks/pizza').and_return(@pizza)
- @lasagna = {'lasagna' => {"url" => "file:///dev/null", "versions" => [{"url" => "file:///dev/null-lasagna", "version" => "3.0.0"}]}}
- allow(@rest).to receive(:get_rest).with('cookbooks/lasagna').and_return(@lasagna)
+ @cheezburger = { "cheezburger" => { "url" => "file:///dev/null", "versions" => [{ "url" => "file:///dev/null-cheez", "version" => "1.0.0" }] } }
+ allow(@rest).to receive(:get).with("cookbooks/cheezburger").and_return(@cheezburger)
+ @pizza = { "pizza" => { "url" => "file:///dev/null", "versions" => [{ "url" => "file:///dev/null-pizza", "version" => "2.0.0" }] } }
+ allow(@rest).to receive(:get).with("cookbooks/pizza").and_return(@pizza)
+ @lasagna = { "lasagna" => { "url" => "file:///dev/null", "versions" => [{ "url" => "file:///dev/null-lasagna", "version" => "3.0.0" }] } }
+ allow(@rest).to receive(:get).with("cookbooks/lasagna").and_return(@lasagna)
end
it "should print the cookbooks you are about to delete" do
@@ -68,15 +66,15 @@ describe Chef::Knife::CookbookBulkDelete do
end
it "should delete each cookbook" do
- {"cheezburger" => "1.0.0", "pizza" => "2.0.0", "lasagna" => '3.0.0'}.each do |cookbook_name, version|
- expect(@rest).to receive(:delete_rest).with("cookbooks/#{cookbook_name}/#{version}")
+ { "cheezburger" => "1.0.0", "pizza" => "2.0.0", "lasagna" => "3.0.0" }.each do |cookbook_name, version|
+ expect(@rest).to receive(:delete).with("cookbooks/#{cookbook_name}/#{version}")
end
@knife.run
end
it "should only delete cookbooks that match the regex" do
@knife.name_args = ["cheezburger"]
- expect(@rest).to receive(:delete_rest).with('cookbooks/cheezburger/1.0.0')
+ expect(@rest).to receive(:delete).with("cookbooks/cheezburger/1.0.0")
@knife.run
end
end
diff --git a/spec/unit/knife/cookbook_create_spec.rb b/spec/unit/knife/cookbook_create_spec.rb
index 3354432d39..f860a8bce8 100644
--- a/spec/unit/knife/cookbook_create_spec.rb
+++ b/spec/unit/knife/cookbook_create_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,13 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
describe Chef::Knife::CookbookCreate do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
@knife = Chef::Knife::CookbookCreate.new
@knife.config = {}
@knife.name_args = ["foobar"]
@@ -34,7 +35,7 @@ describe Chef::Knife::CookbookCreate do
# Fixes CHEF-2579
it "should expand the path of the cookbook directory" do
expect(File).to receive(:expand_path).with("~/tmp/monkeypants")
- @knife.config = {:cookbook_path => "~/tmp/monkeypants"}
+ @knife.config = { :cookbook_path => "~/tmp/monkeypants" }
allow(@knife).to receive(:create_cookbook)
allow(@knife).to receive(:create_readme)
allow(@knife).to receive(:create_changelog)
@@ -44,7 +45,7 @@ describe Chef::Knife::CookbookCreate do
it "should create a new cookbook with default values to copyright name, email, readme format and license if those are not supplied" do
@dir = Dir.tmpdir
- @knife.config = {:cookbook_path => @dir}
+ @knife.config = { :cookbook_path => @dir }
expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "YOUR_COMPANY_NAME", "none")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -56,13 +57,13 @@ describe Chef::Knife::CookbookCreate do
@dir = Dir.tmpdir
@knife.config = {
:cookbook_path => @dir,
- :cookbook_copyright => "Opscode, Inc"
+ :cookbook_copyright => "Chef Software, Inc.",
}
- @knife.name_args=["foobar"]
- expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none")
+ @knife.name_args = ["foobar"]
+ expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "none")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
- expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "YOUR_EMAIL", "none", "md")
+ expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "YOUR_EMAIL", "none", "md")
@knife.run
end
@@ -70,14 +71,14 @@ describe Chef::Knife::CookbookCreate do
@dir = Dir.tmpdir
@knife.config = {
:cookbook_path => @dir,
- :cookbook_copyright => "Opscode, Inc",
- :cookbook_email => "nuo@opscode.com"
+ :cookbook_copyright => "Chef Software, Inc.",
+ :cookbook_email => "test@chef.io",
}
- @knife.name_args=["foobar"]
- expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none")
+ @knife.name_args = ["foobar"]
+ expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "none")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
- expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "none", "md")
+ expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "test@chef.io", "none", "md")
@knife.run
end
@@ -85,15 +86,15 @@ describe Chef::Knife::CookbookCreate do
@dir = Dir.tmpdir
@knife.config = {
:cookbook_path => @dir,
- :cookbook_copyright => "Opscode, Inc",
- :cookbook_email => "nuo@opscode.com",
- :cookbook_license => "apachev2"
+ :cookbook_copyright => "Chef Software, Inc.",
+ :cookbook_email => "test@chef.io",
+ :cookbook_license => "apachev2",
}
- @knife.name_args=["foobar"]
- expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "apachev2")
+ @knife.name_args = ["foobar"]
+ expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "apachev2")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
- expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "apachev2", "md")
+ expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "test@chef.io", "apachev2", "md")
@knife.run
end
@@ -101,15 +102,15 @@ describe Chef::Knife::CookbookCreate do
@dir = Dir.tmpdir
@knife.config = {
:cookbook_path => @dir,
- :cookbook_copyright => "Opscode, Inc",
- :cookbook_email => "nuo@opscode.com",
- :cookbook_license => false
+ :cookbook_copyright => "Chef Software, Inc.",
+ :cookbook_email => "test@chef.io",
+ :cookbook_license => false,
}
- @knife.name_args=["foobar"]
- expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none")
+ @knife.name_args = ["foobar"]
+ expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "none")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
- expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "none", "md")
+ expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "test@chef.io", "none", "md")
@knife.run
end
@@ -117,15 +118,15 @@ describe Chef::Knife::CookbookCreate do
@dir = Dir.tmpdir
@knife.config = {
:cookbook_path => @dir,
- :cookbook_copyright => "Opscode, Inc",
- :cookbook_email => "nuo@opscode.com",
- :cookbook_license => "false"
+ :cookbook_copyright => "Chef Software, Inc.",
+ :cookbook_email => "test@chef.io",
+ :cookbook_license => "false",
}
- @knife.name_args=["foobar"]
- expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none")
+ @knife.name_args = ["foobar"]
+ expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "none")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
- expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "none", "md")
+ expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "test@chef.io", "none", "md")
@knife.run
end
@@ -133,15 +134,15 @@ describe Chef::Knife::CookbookCreate do
@dir = Dir.tmpdir
@knife.config = {
:cookbook_path => @dir,
- :cookbook_copyright => "Opscode, Inc",
- :cookbook_email => "nuo@opscode.com",
- :cookbook_license => "gplv2"
+ :cookbook_copyright => "Chef Software, Inc.",
+ :cookbook_email => "test@chef.io",
+ :cookbook_license => "gplv2",
}
- @knife.name_args=["foobar"]
- expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "gplv2")
+ @knife.name_args = ["foobar"]
+ expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "gplv2")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
- expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "gplv2", "md")
+ expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "test@chef.io", "gplv2", "md")
@knife.run
end
@@ -149,15 +150,15 @@ describe Chef::Knife::CookbookCreate do
@dir = Dir.tmpdir
@knife.config = {
:cookbook_path => @dir,
- :cookbook_copyright => "Opscode, Inc",
- :cookbook_email => "nuo@opscode.com",
- :cookbook_license => "gplv3"
+ :cookbook_copyright => "Chef Software, Inc.",
+ :cookbook_email => "test@chef.io",
+ :cookbook_license => "gplv3",
}
- @knife.name_args=["foobar"]
- expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "gplv3")
+ @knife.name_args = ["foobar"]
+ expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "gplv3")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
- expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "gplv3", "md")
+ expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "test@chef.io", "gplv3", "md")
@knife.run
end
@@ -165,15 +166,15 @@ describe Chef::Knife::CookbookCreate do
@dir = Dir.tmpdir
@knife.config = {
:cookbook_path => @dir,
- :cookbook_copyright => "Opscode, Inc",
- :cookbook_email => "nuo@opscode.com",
- :cookbook_license => "mit"
+ :cookbook_copyright => "Chef Software, Inc.",
+ :cookbook_email => "test@chef.io",
+ :cookbook_license => "mit",
}
- @knife.name_args=["foobar"]
- expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit")
+ @knife.name_args = ["foobar"]
+ expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "mit")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
- expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "md")
+ expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "test@chef.io", "mit", "md")
@knife.run
end
@@ -181,33 +182,33 @@ describe Chef::Knife::CookbookCreate do
@dir = Dir.tmpdir
@knife.config = {
:cookbook_path => @dir,
- :cookbook_copyright => "Opscode, Inc",
- :cookbook_email => "nuo@opscode.com",
+ :cookbook_copyright => "Chef Software, Inc.",
+ :cookbook_email => "test@chef.io",
:cookbook_license => "mit",
- :readme_format => "rdoc"
+ :readme_format => "rdoc",
}
- @knife.name_args=["foobar"]
- expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit")
+ @knife.name_args = ["foobar"]
+ expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "mit")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "rdoc")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
- expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "rdoc")
+ expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "test@chef.io", "mit", "rdoc")
@knife.run
end
- it "should allow specifying the mkd readme format" do
+ it "should allow specifying the md readme format" do
@dir = Dir.tmpdir
@knife.config = {
:cookbook_path => @dir,
- :cookbook_copyright => "Opscode, Inc",
- :cookbook_email => "nuo@opscode.com",
+ :cookbook_copyright => "Chef Software, Inc.",
+ :cookbook_email => "test@chef.io",
:cookbook_license => "mit",
- :readme_format => "mkd"
+ :readme_format => "mkd",
}
- @knife.name_args=["foobar"]
- expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit")
+ @knife.name_args = ["foobar"]
+ expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "mit")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "mkd")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
- expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "mkd")
+ expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "test@chef.io", "mit", "mkd")
@knife.run
end
@@ -215,16 +216,16 @@ describe Chef::Knife::CookbookCreate do
@dir = Dir.tmpdir
@knife.config = {
:cookbook_path => @dir,
- :cookbook_copyright => "Opscode, Inc",
- :cookbook_email => "nuo@opscode.com",
+ :cookbook_copyright => "Chef Software, Inc.",
+ :cookbook_email => "test@chef.io",
:cookbook_license => "mit",
- :readme_format => "txt"
+ :readme_format => "txt",
}
- @knife.name_args=["foobar"]
- expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit")
+ @knife.name_args = ["foobar"]
+ expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "mit")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "txt")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
- expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "txt")
+ expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "test@chef.io", "mit", "txt")
@knife.run
end
@@ -232,16 +233,16 @@ describe Chef::Knife::CookbookCreate do
@dir = Dir.tmpdir
@knife.config = {
:cookbook_path => @dir,
- :cookbook_copyright => "Opscode, Inc",
- :cookbook_email => "nuo@opscode.com",
+ :cookbook_copyright => "Chef Software, Inc.",
+ :cookbook_email => "test@chef.io",
:cookbook_license => "mit",
- :readme_format => "foo"
+ :readme_format => "foo",
}
- @knife.name_args=["foobar"]
- expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit")
+ @knife.name_args = ["foobar"]
+ expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "mit")
expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "foo")
expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
- expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "foo")
+ expect(@knife).to receive(:create_metadata).with(@dir, @knife.name_args.first, "Chef Software, Inc.", "test@chef.io", "mit", "foo")
@knife.run
end
@@ -252,7 +253,7 @@ describe Chef::Knife::CookbookCreate do
it "should throw an argument error" do
@dir = Dir.tmpdir
- expect{@knife.run}.to raise_error(ArgumentError)
+ expect { @knife.run }.to raise_error(ArgumentError)
end
end
diff --git a/spec/unit/knife/cookbook_delete_spec.rb b/spec/unit/knife/cookbook_delete_spec.rb
index 4e75a689e3..9bf4c81a73 100644
--- a/spec/unit/knife/cookbook_delete_spec.rb
+++ b/spec/unit/knife/cookbook_delete_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,54 +16,54 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::CookbookDelete do
before(:each) do
@knife = Chef::Knife::CookbookDelete.new
- @knife.name_args = ['foobar']
- @knife.cookbook_name = 'foobar'
+ @knife.name_args = ["foobar"]
+ @knife.cookbook_name = "foobar"
@stdout = StringIO.new
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
@stderr = StringIO.new
allow(@knife.ui).to receive(:stderr).and_return(@stderr)
end
- describe 'run' do
- it 'should print usage and exit when a cookbook name is not provided' do
+ describe "run" do
+ it "should print usage and exit when a cookbook name is not provided" do
@knife.name_args = []
expect(@knife).to receive(:show_usage)
expect(@knife.ui).to receive(:fatal)
expect { @knife.run }.to raise_error(SystemExit)
end
- describe 'when specifying a cookbook name' do
- it 'should delete the cookbook without a specific version' do
+ describe "when specifying a cookbook name" do
+ it "should delete the cookbook without a specific version" do
expect(@knife).to receive(:delete_without_explicit_version)
@knife.run
end
- describe 'and a version' do
- it 'should delete the specific version of the cookbook' do
- @knife.name_args << '1.0.0'
+ describe "and a version" do
+ it "should delete the specific version of the cookbook" do
+ @knife.name_args << "1.0.0"
expect(@knife).to receive(:delete_explicit_version)
@knife.run
end
end
- describe 'with -a or --all' do
- it 'should delete all versions of the cookbook' do
+ describe "with -a or --all" do
+ it "should delete all versions of the cookbook" do
@knife.config[:all] = true
expect(@knife).to receive(:delete_all_versions)
@knife.run
end
end
- describe 'with -p or --purge' do
- it 'should prompt to purge the files' do
+ describe "with -p or --purge" do
+ it "should prompt to purge the files" do
@knife.config[:purge] = true
expect(@knife).to receive(:confirm).
- with(/.+Are you sure you want to purge files.+/)
+ with(/.+Are you sure you want to purge files.+/)
expect(@knife).to receive(:delete_without_explicit_version)
@knife.run
end
@@ -71,30 +71,30 @@ describe Chef::Knife::CookbookDelete do
end
end
- describe 'delete_explicit_version' do
- it 'should delete the specific cookbook version' do
- @knife.cookbook_name = 'foobar'
- @knife.version = '1.0.0'
+ describe "delete_explicit_version" do
+ it "should delete the specific cookbook version" do
+ @knife.cookbook_name = "foobar"
+ @knife.version = "1.0.0"
expect(@knife).to receive(:delete_object).with(Chef::CookbookVersion,
- 'foobar version 1.0.0',
- 'cookbook').and_yield()
- expect(@knife).to receive(:delete_request).with('cookbooks/foobar/1.0.0')
+ "foobar version 1.0.0",
+ "cookbook").and_yield()
+ expect(@knife).to receive(:delete_request).with("cookbooks/foobar/1.0.0")
@knife.delete_explicit_version
end
end
- describe 'delete_all_versions' do
- it 'should prompt to delete all versions of the cookbook' do
- @knife.cookbook_name = 'foobar'
- expect(@knife).to receive(:confirm).with('Do you really want to delete all versions of foobar')
+ describe "delete_all_versions" do
+ it "should prompt to delete all versions of the cookbook" do
+ @knife.cookbook_name = "foobar"
+ expect(@knife).to receive(:confirm).with("Do you really want to delete all versions of foobar")
expect(@knife).to receive(:delete_all_without_confirmation)
@knife.delete_all_versions
end
end
- describe 'delete_all_without_confirmation' do
- it 'should delete all versions without confirmation' do
- versions = ['1.0.0', '1.1.0']
+ describe "delete_all_without_confirmation" do
+ it "should delete all versions without confirmation" do
+ versions = ["1.0.0", "1.1.0"]
expect(@knife).to receive(:available_versions).and_return(versions)
versions.each do |v|
expect(@knife).to receive(:delete_version_without_confirmation).with(v)
@@ -103,132 +103,132 @@ describe Chef::Knife::CookbookDelete do
end
end
- describe 'delete_without_explicit_version' do
- it 'should exit if there are no available versions' do
+ describe "delete_without_explicit_version" do
+ it "should exit if there are no available versions" do
expect(@knife).to receive(:available_versions).and_return(nil)
expect { @knife.delete_without_explicit_version }.to raise_error(SystemExit)
end
- it 'should delete the version if only one is found' do
- expect(@knife).to receive(:available_versions).at_least(:once).and_return(['1.0.0'])
+ it "should delete the version if only one is found" do
+ expect(@knife).to receive(:available_versions).at_least(:once).and_return(["1.0.0"])
expect(@knife).to receive(:delete_explicit_version)
@knife.delete_without_explicit_version
end
- it 'should ask which version(s) to delete if multiple are found' do
- expect(@knife).to receive(:available_versions).at_least(:once).and_return(['1.0.0', '1.1.0'])
- expect(@knife).to receive(:ask_which_versions_to_delete).and_return(['1.0.0', '1.1.0'])
- expect(@knife).to receive(:delete_versions_without_confirmation).with(['1.0.0', '1.1.0'])
+ it "should ask which version(s) to delete if multiple are found" do
+ expect(@knife).to receive(:available_versions).at_least(:once).and_return(["1.0.0", "1.1.0"])
+ expect(@knife).to receive(:ask_which_versions_to_delete).and_return(["1.0.0", "1.1.0"])
+ expect(@knife).to receive(:delete_versions_without_confirmation).with(["1.0.0", "1.1.0"])
@knife.delete_without_explicit_version
end
end
- describe 'available_versions' do
+ describe "available_versions" do
before(:each) do
- @rest_mock = double('rest')
+ @rest_mock = double("rest")
expect(@knife).to receive(:rest).and_return(@rest_mock)
- @cookbook_data = { 'foobar' => { 'versions' => [{'version' => '1.0.0'},
- {'version' => '1.1.0'},
- {'version' => '2.0.0'} ]}
+ @cookbook_data = { "foobar" => { "versions" => [{ "version" => "1.0.0" },
+ { "version" => "1.1.0" },
+ { "version" => "2.0.0" } ] },
}
end
- it 'should return the list of versions of the cookbook' do
- expect(@rest_mock).to receive(:get_rest).with('cookbooks/foobar').and_return(@cookbook_data)
- expect(@knife.available_versions).to eq(['1.0.0', '1.1.0', '2.0.0'])
+ it "should return the list of versions of the cookbook" do
+ expect(@rest_mock).to receive(:get).with("cookbooks/foobar").and_return(@cookbook_data)
+ expect(@knife.available_versions).to eq(["1.0.0", "1.1.0", "2.0.0"])
end
- it 'should raise if an error other than HTTP 404 is returned' do
- exception = Net::HTTPServerException.new('500 Internal Server Error', '500')
- expect(@rest_mock).to receive(:get_rest).and_raise(exception)
+ it "should raise if an error other than HTTP 404 is returned" do
+ exception = Net::HTTPServerException.new("500 Internal Server Error", "500")
+ expect(@rest_mock).to receive(:get).and_raise(exception)
expect { @knife.available_versions }.to raise_error Net::HTTPServerException
end
describe "if the cookbook can't be found" do
before(:each) do
- expect(@rest_mock).to receive(:get_rest).
- and_raise(Net::HTTPServerException.new('404 Not Found', '404'))
+ expect(@rest_mock).to receive(:get).
+ and_raise(Net::HTTPServerException.new("404 Not Found", "404"))
end
- it 'should print an error' do
+ it "should print an error" do
@knife.available_versions
expect(@stderr.string).to match /error.+cannot find a cookbook named foobar/i
end
- it 'should return nil' do
+ it "should return nil" do
expect(@knife.available_versions).to eq(nil)
end
end
end
- describe 'ask_which_version_to_delete' do
+ describe "ask_which_version_to_delete" do
before(:each) do
- allow(@knife).to receive(:available_versions).and_return(['1.0.0', '1.1.0', '2.0.0'])
+ allow(@knife).to receive(:available_versions).and_return(["1.0.0", "1.1.0", "2.0.0"])
end
- it 'should prompt the user to select a version' do
+ it "should prompt the user to select a version" do
prompt = /Which version\(s\) do you want to delete\?.+1\. foobar 1\.0\.0.+2\. foobar 1\.1\.0.+3\. foobar 2\.0\.0.+4\. All versions.+/m
- expect(@knife).to receive(:ask_question).with(prompt).and_return('1')
+ expect(@knife).to receive(:ask_question).with(prompt).and_return("1")
@knife.ask_which_versions_to_delete
end
it "should print an error and exit if a version wasn't specified" do
- expect(@knife).to receive(:ask_question).and_return('')
+ expect(@knife).to receive(:ask_question).and_return("")
expect(@knife.ui).to receive(:error).with(/no versions specified/i)
expect { @knife.ask_which_versions_to_delete }.to raise_error(SystemExit)
end
- it 'should print an error if an invalid choice was selected' do
- expect(@knife).to receive(:ask_question).and_return('100')
+ it "should print an error if an invalid choice was selected" do
+ expect(@knife).to receive(:ask_question).and_return("100")
expect(@knife.ui).to receive(:error).with(/100 is not a valid choice/i)
@knife.ask_which_versions_to_delete
end
- it 'should return the selected versions' do
- expect(@knife).to receive(:ask_question).and_return('1, 3')
- expect(@knife.ask_which_versions_to_delete).to eq(['1.0.0', '2.0.0'])
+ it "should return the selected versions" do
+ expect(@knife).to receive(:ask_question).and_return("1, 3")
+ expect(@knife.ask_which_versions_to_delete).to eq(["1.0.0", "2.0.0"])
end
it "should return all of the versions if 'all' was selected" do
- expect(@knife).to receive(:ask_question).and_return('4')
+ expect(@knife).to receive(:ask_question).and_return("4")
expect(@knife.ask_which_versions_to_delete).to eq([:all])
end
end
- describe 'delete_version_without_confirmation' do
- it 'should delete the cookbook version' do
- expect(@knife).to receive(:delete_request).with('cookbooks/foobar/1.0.0')
- @knife.delete_version_without_confirmation('1.0.0')
+ describe "delete_version_without_confirmation" do
+ it "should delete the cookbook version" do
+ expect(@knife).to receive(:delete_request).with("cookbooks/foobar/1.0.0")
+ @knife.delete_version_without_confirmation("1.0.0")
end
- it 'should output that the cookbook was deleted' do
+ it "should output that the cookbook was deleted" do
allow(@knife).to receive(:delete_request)
- @knife.delete_version_without_confirmation('1.0.0')
+ @knife.delete_version_without_confirmation("1.0.0")
expect(@stderr.string).to match /deleted cookbook\[foobar\]\[1.0.0\]/im
end
- describe 'with --print-after' do
- it 'should display the cookbook data' do
- object = ''
+ describe "with --print-after" do
+ it "should display the cookbook data" do
+ object = ""
@knife.config[:print_after] = true
allow(@knife).to receive(:delete_request).and_return(object)
expect(@knife).to receive(:format_for_display).with(object)
- @knife.delete_version_without_confirmation('1.0.0')
+ @knife.delete_version_without_confirmation("1.0.0")
end
end
end
- describe 'delete_versions_without_confirmation' do
- it 'should delete each version without confirmation' do
- versions = ['1.0.0', '1.1.0']
+ describe "delete_versions_without_confirmation" do
+ it "should delete each version without confirmation" do
+ versions = ["1.0.0", "1.1.0"]
versions.each do |v|
expect(@knife).to receive(:delete_version_without_confirmation).with(v)
end
@knife.delete_versions_without_confirmation(versions)
end
- describe 'with -a or --all' do
- it 'should delete all versions without confirmation' do
+ describe "with -a or --all" do
+ it "should delete all versions without confirmation" do
versions = [:all]
expect(@knife).to receive(:delete_all_without_confirmation)
@knife.delete_versions_without_confirmation(versions)
diff --git a/spec/unit/knife/cookbook_download_spec.rb b/spec/unit/knife/cookbook_download_spec.rb
index 7ca1adfcb5..38a4974774 100644
--- a/spec/unit/knife/cookbook_download_spec.rb
+++ b/spec/unit/knife/cookbook_download_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::CookbookDownload do
before(:each) do
@@ -25,66 +25,66 @@ describe Chef::Knife::CookbookDownload do
allow(@knife.ui).to receive(:stderr).and_return(@stderr)
end
- describe 'run' do
- it 'should print usage and exit when a cookbook name is not provided' do
+ describe "run" do
+ it "should print usage and exit when a cookbook name is not provided" do
@knife.name_args = []
expect(@knife).to receive(:show_usage)
expect(@knife.ui).to receive(:fatal).with(/must specify a cookbook name/)
expect { @knife.run }.to raise_error(SystemExit)
end
- it 'should exit with a fatal error when there is no cookbook on the server' do
- @knife.name_args = ['foobar', nil]
+ it "should exit with a fatal error when there is no cookbook on the server" do
+ @knife.name_args = ["foobar", nil]
expect(@knife).to receive(:determine_version).and_return(nil)
- expect(@knife.ui).to receive(:fatal).with('No such cookbook found')
+ expect(@knife.ui).to receive(:fatal).with("No such cookbook found")
expect { @knife.run }.to raise_error(SystemExit)
end
- describe 'with a cookbook name' do
+ describe "with a cookbook name" do
before(:each) do
- @knife.name_args = ['foobar']
- @knife.config[:download_directory] = '/var/tmp/chef'
- @rest_mock = double('rest')
+ @knife.name_args = ["foobar"]
+ @knife.config[:download_directory] = "/var/tmp/chef"
+ @rest_mock = double("rest")
allow(@knife).to receive(:rest).and_return(@rest_mock)
@manifest_data = {
:recipes => [
- {'path' => 'recipes/foo.rb',
- 'url' => 'http://example.org/files/foo.rb'},
- {'path' => 'recipes/bar.rb',
- 'url' => 'http://example.org/files/bar.rb'}
+ { "path" => "recipes/foo.rb",
+ "url" => "http://example.org/files/foo.rb" },
+ { "path" => "recipes/bar.rb",
+ "url" => "http://example.org/files/bar.rb" },
],
:templates => [
- {'path' => 'templates/default/foo.erb',
- 'url' => 'http://example.org/files/foo.erb'},
- {'path' => 'templates/default/bar.erb',
- 'url' => 'http://example.org/files/bar.erb'}
+ { "path" => "templates/default/foo.erb",
+ "url" => "http://example.org/files/foo.erb" },
+ { "path" => "templates/default/bar.erb",
+ "url" => "http://example.org/files/bar.erb" },
],
:attributes => [
- {'path' => 'attributes/default.rb',
- 'url' => 'http://example.org/files/default.rb'}
- ]
+ { "path" => "attributes/default.rb",
+ "url" => "http://example.org/files/default.rb" },
+ ],
}
- @cookbook_mock = double('cookbook')
- allow(@cookbook_mock).to receive(:version).and_return('1.0.0')
+ @cookbook_mock = double("cookbook")
+ allow(@cookbook_mock).to receive(:version).and_return("1.0.0")
allow(@cookbook_mock).to receive(:manifest).and_return(@manifest_data)
- expect(@rest_mock).to receive(:get_rest).with('cookbooks/foobar/1.0.0').
- and_return(@cookbook_mock)
+ expect(Chef::CookbookVersion).to receive(:load).with("foobar", "1.0.0").
+ and_return(@cookbook_mock)
end
- it 'should determine which version if one was not explicitly specified'do
+ it "should determine which version if one was not explicitly specified" do
allow(@cookbook_mock).to receive(:manifest).and_return({})
- expect(@knife).to receive(:determine_version).and_return('1.0.0')
- expect(File).to receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(false)
+ expect(@knife).to receive(:determine_version).and_return("1.0.0")
+ expect(File).to receive(:exists?).with("/var/tmp/chef/foobar-1.0.0").and_return(false)
allow(Chef::CookbookVersion).to receive(:COOKBOOK_SEGEMENTS).and_return([])
@knife.run
end
- describe 'and a version' do
+ describe "and a version" do
before(:each) do
- @knife.name_args << '1.0.0'
- @files = @manifest_data.values.map { |v| v.map { |i| i['path'] } }.flatten.uniq
+ @knife.name_args << "1.0.0"
+ @files = @manifest_data.values.map { |v| v.map { |i| i["path"] } }.flatten.uniq
@files_mocks = {}
@files.map { |f| File.basename(f) }.flatten.uniq.each do |f|
@files_mocks[f] = double("#{f}_mock")
@@ -92,46 +92,45 @@ describe Chef::Knife::CookbookDownload do
end
end
- it 'should print an error and exit if the cookbook download directory already exists' do
- expect(File).to receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(true)
+ it "should print an error and exit if the cookbook download directory already exists" do
+ expect(File).to receive(:exists?).with("/var/tmp/chef/foobar-1.0.0").and_return(true)
expect(@knife.ui).to receive(:fatal).with(/\/var\/tmp\/chef\/foobar-1\.0\.0 exists/i)
expect { @knife.run }.to raise_error(SystemExit)
end
- describe 'when downloading the cookbook' do
+ describe "when downloading the cookbook" do
before(:each) do
@files.map { |f| File.dirname(f) }.flatten.uniq.each do |dir|
expect(FileUtils).to receive(:mkdir_p).with("/var/tmp/chef/foobar-1.0.0/#{dir}").
- at_least(:once)
+ at_least(:once)
end
@files_mocks.each_pair do |file, mock|
- expect(@rest_mock).to receive(:get_rest).with("http://example.org/files/#{file}", true).
- and_return(mock)
+ expect(@rest_mock).to receive(:streaming_request).with("http://example.org/files/#{file}").
+ and_return(mock)
end
- expect(@rest_mock).to receive(:sign_on_redirect=).with(false).at_least(:once)
@files.each do |f|
expect(FileUtils).to receive(:mv).
- with("/var/tmp/#{File.basename(f)}", "/var/tmp/chef/foobar-1.0.0/#{f}")
+ with("/var/tmp/#{File.basename(f)}", "/var/tmp/chef/foobar-1.0.0/#{f}")
end
end
it "should download the cookbook when the cookbook download directory doesn't exist" do
- expect(File).to receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(false)
+ expect(File).to receive(:exists?).with("/var/tmp/chef/foobar-1.0.0").and_return(false)
@knife.run
- ['attributes', 'recipes', 'templates'].each do |segment|
+ %w{attributes recipes templates}.each do |segment|
expect(@stderr.string).to match /downloading #{segment}/im
end
expect(@stderr.string).to match /downloading foobar cookbook version 1\.0\.0/im
expect(@stderr.string).to match /cookbook downloaded to \/var\/tmp\/chef\/foobar-1\.0\.0/im
end
- describe 'with -f or --force' do
- it 'should remove the existing the cookbook download directory if it exists' do
+ describe "with -f or --force" do
+ it "should remove the existing the cookbook download directory if it exists" do
@knife.config[:force] = true
- expect(File).to receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(true)
- expect(FileUtils).to receive(:rm_rf).with('/var/tmp/chef/foobar-1.0.0')
+ expect(File).to receive(:exists?).with("/var/tmp/chef/foobar-1.0.0").and_return(true)
+ expect(FileUtils).to receive(:rm_rf).with("/var/tmp/chef/foobar-1.0.0")
@knife.run
end
end
@@ -142,94 +141,94 @@ describe Chef::Knife::CookbookDownload do
end
- describe 'determine_version' do
+ describe "determine_version" do
- it 'should return nil if there are no versions' do
+ it "should return nil if there are no versions" do
expect(@knife).to receive(:available_versions).and_return(nil)
expect(@knife.determine_version).to eq(nil)
expect(@knife.version).to eq(nil)
end
- it 'should return and set the version if there is only one version' do
- expect(@knife).to receive(:available_versions).at_least(:once).and_return(['1.0.0'])
- expect(@knife.determine_version).to eq('1.0.0')
- expect(@knife.version).to eq('1.0.0')
+ it "should return and set the version if there is only one version" do
+ expect(@knife).to receive(:available_versions).at_least(:once).and_return(["1.0.0"])
+ expect(@knife.determine_version).to eq("1.0.0")
+ expect(@knife.version).to eq("1.0.0")
end
- it 'should ask which version to download and return it if there is more than one' do
- expect(@knife).to receive(:available_versions).at_least(:once).and_return(['1.0.0', '2.0.0'])
- expect(@knife).to receive(:ask_which_version).and_return('1.0.0')
- expect(@knife.determine_version).to eq('1.0.0')
+ it "should ask which version to download and return it if there is more than one" do
+ expect(@knife).to receive(:available_versions).at_least(:once).and_return(["1.0.0", "2.0.0"])
+ expect(@knife).to receive(:ask_which_version).and_return("1.0.0")
+ expect(@knife.determine_version).to eq("1.0.0")
end
- describe 'with -N or --latest' do
- it 'should return and set the version to the latest version' do
+ describe "with -N or --latest" do
+ it "should return and set the version to the latest version" do
@knife.config[:latest] = true
expect(@knife).to receive(:available_versions).at_least(:once).
- and_return(['1.0.0', '1.1.0', '2.0.0'])
+ and_return(["1.0.0", "1.1.0", "2.0.0"])
@knife.determine_version
- expect(@knife.version.to_s).to eq('2.0.0')
+ expect(@knife.version.to_s).to eq("2.0.0")
end
end
end
- describe 'available_versions' do
+ describe "available_versions" do
before(:each) do
- @knife.cookbook_name = 'foobar'
+ @knife.cookbook_name = "foobar"
end
- it 'should return nil if there are no versions' do
+ it "should return nil if there are no versions" do
expect(Chef::CookbookVersion).to receive(:available_versions).
- with('foobar').
- and_return(nil)
+ with("foobar").
+ and_return(nil)
expect(@knife.available_versions).to eq(nil)
end
- it 'should return the available versions' do
+ it "should return the available versions" do
expect(Chef::CookbookVersion).to receive(:available_versions).
- with('foobar').
- and_return(['1.1.0', '2.0.0', '1.0.0'])
- expect(@knife.available_versions).to eq([Chef::Version.new('1.0.0'),
- Chef::Version.new('1.1.0'),
- Chef::Version.new('2.0.0')])
+ with("foobar").
+ and_return(["1.1.0", "2.0.0", "1.0.0"])
+ expect(@knife.available_versions).to eq([Chef::Version.new("1.0.0"),
+ Chef::Version.new("1.1.0"),
+ Chef::Version.new("2.0.0")])
end
- it 'should avoid multiple API calls to the server' do
+ it "should avoid multiple API calls to the server" do
expect(Chef::CookbookVersion).to receive(:available_versions).
- once.
- with('foobar').
- and_return(['1.1.0', '2.0.0', '1.0.0'])
+ once.
+ with("foobar").
+ and_return(["1.1.0", "2.0.0", "1.0.0"])
@knife.available_versions
@knife.available_versions
end
end
- describe 'ask_which_version' do
+ describe "ask_which_version" do
before(:each) do
- @knife.cookbook_name = 'foobar'
- allow(@knife).to receive(:available_versions).and_return(['1.0.0', '1.1.0', '2.0.0'])
+ @knife.cookbook_name = "foobar"
+ allow(@knife).to receive(:available_versions).and_return(["1.0.0", "1.1.0", "2.0.0"])
end
- it 'should prompt the user to select a version' do
+ it "should prompt the user to select a version" do
prompt = /Which version do you want to download\?.+1\. foobar 1\.0\.0.+2\. foobar 1\.1\.0.+3\. foobar 2\.0\.0.+/m
- expect(@knife).to receive(:ask_question).with(prompt).and_return('1')
+ expect(@knife).to receive(:ask_question).with(prompt).and_return("1")
@knife.ask_which_version
end
it "should set the version to the user's selection" do
- expect(@knife).to receive(:ask_question).and_return('1')
+ expect(@knife).to receive(:ask_question).and_return("1")
@knife.ask_which_version
- expect(@knife.version).to eq('1.0.0')
+ expect(@knife.version).to eq("1.0.0")
end
it "should print an error and exit if a version wasn't specified" do
- expect(@knife).to receive(:ask_question).and_return('')
+ expect(@knife).to receive(:ask_question).and_return("")
expect(@knife.ui).to receive(:error).with(/is not a valid value/i)
expect { @knife.ask_which_version }.to raise_error(SystemExit)
end
- it 'should print an error if an invalid choice was selected' do
- expect(@knife).to receive(:ask_question).and_return('100')
+ it "should print an error if an invalid choice was selected" do
+ expect(@knife).to receive(:ask_question).and_return("100")
expect(@knife.ui).to receive(:error).with(/'100' is not a valid value/i)
expect { @knife.ask_which_version }.to raise_error(SystemExit)
end
diff --git a/spec/unit/knife/cookbook_list_spec.rb b/spec/unit/knife/cookbook_list_spec.rb
index 559f700bb4..fce6bc9593 100644
--- a/spec/unit/knife/cookbook_list_spec.rb
+++ b/spec/unit/knife/cookbook_list_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,47 +16,47 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::CookbookList do
before do
@knife = Chef::Knife::CookbookList.new
- @rest_mock = double('rest')
+ @rest_mock = double("rest")
allow(@knife).to receive(:rest).and_return(@rest_mock)
- @cookbook_names = ['apache2', 'mysql']
- @base_url = 'https://server.example.com/cookbooks'
+ @cookbook_names = %w{apache2 mysql}
+ @base_url = "https://server.example.com/cookbooks"
@cookbook_data = {}
@cookbook_names.each do |item|
- @cookbook_data[item] = {'url' => "#{@base_url}/#{item}",
- 'versions' => [{'version' => '1.0.1',
- 'url' => "#{@base_url}/#{item}/1.0.1"}]}
+ @cookbook_data[item] = { "url" => "#{@base_url}/#{item}",
+ "versions" => [{ "version" => "1.0.1",
+ "url" => "#{@base_url}/#{item}/1.0.1" }] }
end
@stdout = StringIO.new
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
end
- describe 'run' do
- it 'should display the latest version of the cookbooks' do
- expect(@rest_mock).to receive(:get_rest).with('/cookbooks?num_versions=1').
- and_return(@cookbook_data)
+ describe "run" do
+ it "should display the latest version of the cookbooks" do
+ expect(@rest_mock).to receive(:get).with("/cookbooks?num_versions=1").
+ and_return(@cookbook_data)
@knife.run
@cookbook_names.each do |item|
expect(@stdout.string).to match /#{item}\s+1\.0\.1/
end
end
- it 'should query cookbooks for the configured environment' do
- @knife.config[:environment] = 'production'
- expect(@rest_mock).to receive(:get_rest).
- with('/environments/production/cookbooks?num_versions=1').
- and_return(@cookbook_data)
+ it "should query cookbooks for the configured environment" do
+ @knife.config[:environment] = "production"
+ expect(@rest_mock).to receive(:get).
+ with("/environments/production/cookbooks?num_versions=1").
+ and_return(@cookbook_data)
@knife.run
end
- describe 'with -w or --with-uri' do
- it 'should display the cookbook uris' do
+ describe "with -w or --with-uri" do
+ it "should display the cookbook uris" do
@knife.config[:with_uri] = true
- allow(@rest_mock).to receive(:get_rest).and_return(@cookbook_data)
+ allow(@rest_mock).to receive(:get).and_return(@cookbook_data)
@knife.run
@cookbook_names.each do |item|
pattern = /#{Regexp.escape(@cookbook_data[item]['versions'].first['url'])}/
@@ -65,18 +65,18 @@ describe Chef::Knife::CookbookList do
end
end
- describe 'with -a or --all' do
+ describe "with -a or --all" do
before do
@cookbook_names.each do |item|
- @cookbook_data[item]['versions'] << {'version' => '1.0.0',
- 'url' => "#{@base_url}/#{item}/1.0.0"}
+ @cookbook_data[item]["versions"] << { "version" => "1.0.0",
+ "url" => "#{@base_url}/#{item}/1.0.0" }
end
end
- it 'should display all versions of the cookbooks' do
+ it "should display all versions of the cookbooks" do
@knife.config[:all_versions] = true
- expect(@rest_mock).to receive(:get_rest).with('/cookbooks?num_versions=all').
- and_return(@cookbook_data)
+ expect(@rest_mock).to receive(:get).with("/cookbooks?num_versions=all").
+ and_return(@cookbook_data)
@knife.run
@cookbook_names.each do |item|
expect(@stdout.string).to match /#{item}\s+1\.0\.1\s+1\.0\.0/
diff --git a/spec/unit/knife/cookbook_metadata_from_file_spec.rb b/spec/unit/knife/cookbook_metadata_from_file_spec.rb
index 456e378ca2..274eb5e167 100644
--- a/spec/unit/knife/cookbook_metadata_from_file_spec.rb
+++ b/spec/unit/knife/cookbook_metadata_from_file_spec.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Matthew Kent (<mkent@magoazul.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,11 +18,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::CookbookMetadataFromFile do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@src = File.expand_path(File.join(CHEF_SPEC_DATA, "metadata", "quick_start", "metadata.rb"))
@tgt = File.expand_path(File.join(CHEF_SPEC_DATA, "metadata", "quick_start", "metadata.json"))
@knife = Chef::Knife::CookbookMetadataFromFile.new
diff --git a/spec/unit/knife/cookbook_metadata_spec.rb b/spec/unit/knife/cookbook_metadata_spec.rb
index 861d85f1f7..c19fc5ae2d 100644
--- a/spec/unit/knife/cookbook_metadata_spec.rb
+++ b/spec/unit/knife/cookbook_metadata_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,164 +16,167 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::CookbookMetadata do
+ let(:knife) do
+ knife = Chef::Knife::CookbookMetadata.new
+ knife.name_args = ["foobar"]
+ knife
+ end
+
+ let(:cookbook_dir) { Dir.mktmpdir }
+
+ let(:stdout) { StringIO.new }
+
+ let(:stderr) { StringIO.new }
+
before(:each) do
- @knife = Chef::Knife::CookbookMetadata.new
- @knife.name_args = ['foobar']
- @cookbook_dir = Dir.mktmpdir
- @json_data = '{ "version": "1.0.0" }'
- @stdout = StringIO.new
- @stderr = StringIO.new
- allow(@knife.ui).to receive(:stdout).and_return(@stdout)
- allow(@knife.ui).to receive(:stderr).and_return(@stderr)
+ allow(knife.ui).to receive(:stdout).and_return(stdout)
+ allow(knife.ui).to receive(:stderr).and_return(stderr)
+ end
+
+ def create_metadata_rb(**kwargs)
+ name = kwargs[:name]
+ Dir.mkdir("#{cookbook_dir}/#{name}")
+ File.open("#{cookbook_dir}/#{name}/metadata.rb", "w+") do |f|
+ kwargs.each do |key, value|
+ if value.is_a?(Array)
+ f.puts "#{key} #{value.map { |v| "\"#{v}\"" }.join(", ")}"
+ else
+ f.puts "#{key} \"#{value}\""
+ end
+ end
+ end
+ end
+
+ def create_metadata_json(**kwargs)
+ name = kwargs[:name]
+ Dir.mkdir("#{cookbook_dir}/#{name}")
+ File.open("#{cookbook_dir}/#{name}/metadata.json", "w+") do |f|
+ f.write(FFI_Yajl::Encoder.encode(kwargs))
+ end
+ end
+
+ def create_invalid_json
+ Dir.mkdir("#{cookbook_dir}/foobar")
+ File.open("#{cookbook_dir}/foobar/metadata.json", "w+") do |f|
+ f.write <<-EOH
+ { "version": "1.0.0", {ImInvalid}}
+ EOH
+ end
end
- describe 'run' do
- it 'should print an error and exit if a cookbook name was not provided' do
- @knife.name_args = []
- expect(@knife.ui).to receive(:error).with(/you must specify the cookbook.+use the --all/i)
- expect { @knife.run }.to raise_error(SystemExit)
+ describe "run" do
+ it "should print an error and exit if a cookbook name was not provided" do
+ knife.name_args = []
+ expect(knife.ui).to receive(:error).with(/you must specify the cookbook.+use the --all/i)
+ expect { knife.run }.to raise_error(SystemExit)
end
- it 'should print an error and exit if an empty cookbook name was provided' do
- @knife.name_args = ['']
- expect(@knife.ui).to receive(:error).with(/you must specify the cookbook.+use the --all/i)
- expect { @knife.run }.to raise_error(SystemExit)
+ it "should print an error and exit if an empty cookbook name was provided" do
+ knife.name_args = [""]
+ expect(knife.ui).to receive(:error).with(/you must specify the cookbook.+use the --all/i)
+ expect { knife.run }.to raise_error(SystemExit)
end
- it 'should generate the metadata for the cookbook' do
- expect(@knife).to receive(:generate_metadata).with('foobar')
- @knife.run
+ it "should generate the metadata for the cookbook" do
+ expect(knife).to receive(:generate_metadata).with("foobar")
+ knife.run
end
- describe 'with -a or --all' do
+ describe "with -a or --all" do
before(:each) do
- @knife.config[:all] = true
- @foo = Chef::CookbookVersion.new('foo', '/tmp/blah')
- @foo.version = '1.0.0'
- @bar = Chef::CookbookVersion.new('bar', '/tmp/blah')
- @bar.version = '2.0.0'
- @cookbook_loader = {
- "foo" => @foo,
- "bar" => @bar
- }
- expect(@cookbook_loader).to receive(:load_cookbooks).and_return(@cookbook_loader)
- expect(@knife).to receive(:generate_metadata).with('foo')
- expect(@knife).to receive(:generate_metadata).with('bar')
+ Chef::Config[:cookbook_path] = cookbook_dir
+ knife.config[:all] = true
+ create_metadata_rb(name: "foo", version: "1.0.0")
+ create_metadata_rb(name: "bar", version: "2.0.0")
+ expect(knife).to receive(:generate_metadata).with("foo").and_call_original
+ expect(knife).to receive(:generate_metadata).with("bar").and_call_original
end
- it 'should generate the metadata for each cookbook' do
- Chef::Config[:cookbook_path] = @cookbook_dir
- expect(Chef::CookbookLoader).to receive(:new).with(@cookbook_dir).and_return(@cookbook_loader)
- @knife.run
+ it "should generate the metadata for each cookbook" do
+ expect(Chef::CookbookLoader).to receive(:new).with(cookbook_dir).and_call_original
+ knife.run
+ expect(stderr.string).to match /generating metadata for foo from #{cookbook_dir}\/foo\/metadata\.rb/im
+ expect(stderr.string).to match /generating metadata for bar from #{cookbook_dir}\/bar\/metadata\.rb/im
end
- describe 'and with -o or --cookbook-path' do
- it 'should look in the provided path and generate cookbook metadata' do
- @knife.config[:cookbook_path] = '/opt/chef/cookbooks'
- expect(Chef::CookbookLoader).to receive(:new).with('/opt/chef/cookbooks').and_return(@cookbook_loader)
- @knife.run
- end
+ it "with -o or --cookbook_path should look in the provided path and generate cookbook metadata" do
+ Chef::Config[:cookbook_path] = "/dev/null"
+ knife.config[:cookbook_path] = cookbook_dir
+ expect(Chef::CookbookLoader).to receive(:new).with(cookbook_dir).and_call_original
+ knife.run
+ expect(stderr.string).to match /generating metadata for foo from #{cookbook_dir}\/foo\/metadata\.rb/im
+ expect(stderr.string).to match /generating metadata for bar from #{cookbook_dir}\/bar\/metadata\.rb/im
end
end
end
- describe 'generate_metadata' do
+ describe "generate_metadata" do
before(:each) do
- @knife.config[:cookbook_path] = @cookbook_dir
- allow(File).to receive(:expand_path).with("#{@cookbook_dir}/foobar/metadata.rb").
- and_return("#{@cookbook_dir}/foobar/metadata.rb")
+ Chef::Config[:cookbook_path] = cookbook_dir
end
- it 'should generate the metadata from metadata.rb if it exists' do
- expect(File).to receive(:exists?).with("#{@cookbook_dir}/foobar/metadata.rb").
- and_return(true)
- expect(@knife).to receive(:generate_metadata_from_file).with('foobar', "#{@cookbook_dir}/foobar/metadata.rb")
- @knife.run
+ it "should generate the metadata from metadata.rb if it exists" do
+ create_metadata_rb(name: "foobar", version: "1.0.0")
+ expect(knife).to receive(:generate_metadata_from_file).with("foobar", "#{cookbook_dir}/foobar/metadata.rb").and_call_original
+ knife.run
+ expect(File.exist?("#{cookbook_dir}/foobar/metadata.json")).to be true
+ json = FFI_Yajl::Parser.parse(IO.read("#{cookbook_dir}/foobar/metadata.json"))
+ expect(json["name"]).to eql("foobar")
+ expect(json["version"]).to eql("1.0.0")
end
- it 'should validate the metadata json if metadata.rb does not exist' do
- expect(File).to receive(:exists?).with("#{@cookbook_dir}/foobar/metadata.rb").
- and_return(false)
- expect(@knife).to receive(:validate_metadata_json).with(@cookbook_dir, 'foobar')
- @knife.run
+ it "should validate the metadata json if metadata.rb does not exist" do
+ create_metadata_json(name: "foobar", version: "1.0.0")
+ expect(knife).to receive(:validate_metadata_json).with(cookbook_dir, "foobar").and_call_original
+ knife.run
end
end
- describe 'generate_metadata_from_file' do
+ describe "validation errors" do
before(:each) do
- @metadata_mock = double('metadata')
- @json_file_mock = double('json_file')
- end
-
- it 'should generate the metatdata json from metatdata.rb' do
- allow(Chef::Cookbook::Metadata).to receive(:new).and_return(@metadata_mock)
- expect(@metadata_mock).to receive(:name).with('foobar')
- expect(@metadata_mock).to receive(:from_file).with("#{@cookbook_dir}/foobar/metadata.rb")
- expect(File).to receive(:open).with("#{@cookbook_dir}/foobar/metadata.json", 'w').
- and_yield(@json_file_mock)
- expect(@json_file_mock).to receive(:write).with(@json_data)
- expect(Chef::JSONCompat).to receive(:to_json_pretty).with(@metadata_mock).
- and_return(@json_data)
- @knife.generate_metadata_from_file('foobar', "#{@cookbook_dir}/foobar/metadata.rb")
- expect(@stderr.string).to match /generating metadata for foobar from #{@cookbook_dir}\/foobar\/metadata\.rb/im
- end
-
- { Chef::Exceptions::ObsoleteDependencySyntax => 'obsolote dependency',
- Chef::Exceptions::InvalidVersionConstraint => 'invalid version constraint'
- }.each_pair do |klass, description|
- it "should print an error and exit when an #{description} syntax exception is encountered" do
- exception = klass.new("#{description} blah")
- allow(Chef::Cookbook::Metadata).to receive(:new).and_raise(exception)
- expect {
- @knife.generate_metadata_from_file('foobar', "#{@cookbook_dir}/foobar/metadata.rb")
- }.to raise_error(SystemExit)
- expect(@stderr.string).to match /error: the cookbook 'foobar' contains invalid or obsolete metadata syntax/im
- expect(@stderr.string).to match /in #{@cookbook_dir}\/foobar\/metadata\.rb/im
- expect(@stderr.string).to match /#{description} blah/im
- end
+ Chef::Config[:cookbook_path] = cookbook_dir
end
- end
- describe 'validate_metadata_json' do
- it 'should validate the metadata json' do
- expect(File).to receive(:exist?).with("#{@cookbook_dir}/foobar/metadata.json").
- and_return(true)
- expect(IO).to receive(:read).with("#{@cookbook_dir}/foobar/metadata.json").
- and_return(@json_data)
- expect(Chef::Cookbook::Metadata).to receive(:validate_json).with(@json_data)
- @knife.validate_metadata_json(@cookbook_dir, 'foobar')
+ it "should fail for obsolete operators in metadata.rb" do
+ create_metadata_rb(name: "foobar", version: "1.0.0", depends: [ "foo:bar", ">> 0.2" ])
+ expect(Chef::Cookbook::Metadata).not_to receive(:validate_json)
+ expect { knife.run }.to raise_error(SystemExit)
+ expect(stderr.string).to match /error: the cookbook 'foobar' contains invalid or obsolete metadata syntax/im
end
- it 'should not try to validate the metadata json if the file does not exist' do
- expect(File).to receive(:exist?).with("#{@cookbook_dir}/foobar/metadata.json").
- and_return(false)
- expect(IO).not_to receive(:read)
+ it "should fail for obsolete format in metadata.rb (sadly)" do
+ create_metadata_rb(name: "foobar", version: "1.0.0", depends: [ "foo:bar", "> 0.2", "< 1.0" ])
expect(Chef::Cookbook::Metadata).not_to receive(:validate_json)
- @knife.validate_metadata_json(@cookbook_dir, 'foobar')
- end
-
- { Chef::Exceptions::ObsoleteDependencySyntax => 'obsolote dependency',
- Chef::Exceptions::InvalidVersionConstraint => 'invalid version constraint'
- }.each_pair do |klass, description|
- it "should print an error and exit when an #{description} syntax exception is encountered" do
- expect(File).to receive(:exist?).with("#{@cookbook_dir}/foobar/metadata.json").
- and_return(true)
- expect(IO).to receive(:read).with("#{@cookbook_dir}/foobar/metadata.json").
- and_return(@json_data)
- exception = klass.new("#{description} blah")
- allow(Chef::Cookbook::Metadata).to receive(:validate_json).and_raise(exception)
- expect {
- @knife.validate_metadata_json(@cookbook_dir, 'foobar')
- }.to raise_error(SystemExit)
- expect(@stderr.string).to match /error: the cookbook 'foobar' contains invalid or obsolete metadata syntax/im
- expect(@stderr.string).to match /in #{@cookbook_dir}\/foobar\/metadata\.json/im
- expect(@stderr.string).to match /#{description} blah/im
- end
+ expect { knife.run }.to raise_error(SystemExit)
+ expect(stderr.string).to match /error: the cookbook 'foobar' contains invalid or obsolete metadata syntax/im
+ end
+
+ it "should fail for obsolete operators in metadata.json" do
+ create_metadata_json(name: "foobar", version: "1.0.0", dependencies: { "foo:bar" => ">> 0.2" })
+ expect { knife.run }.to raise_error(SystemExit)
+ expect(stderr.string).to match /error: the cookbook 'foobar' contains invalid or obsolete metadata syntax/im
end
- end
+ it "should not fail for unknown field in metadata.rb" do
+ create_metadata_rb(name: "sounders", version: "2.0.0", beats: "toronto")
+ expect(Chef::Cookbook::Metadata).not_to receive(:validate_json)
+ expect { knife.run }.not_to raise_error
+ expect(stderr.string).to eql("")
+ end
+
+ it "should not fail for unknown field in metadata.json" do
+ create_metadata_json(name: "sounders", version: "2.0.0", beats: "toronto")
+ expect { knife.run }.not_to raise_error
+ expect(stderr.string).to eql("")
+ end
+
+ it "should fail on unparsable json" do
+ create_invalid_json
+ expect { knife.run }.to raise_error(Chef::Exceptions::JSON::ParseError)
+ end
+ end
end
diff --git a/spec/unit/knife/cookbook_show_spec.rb b/spec/unit/knife/cookbook_show_spec.rb
index bf480e3678..749e50c647 100644
--- a/spec/unit/knife/cookbook_show_spec.rb
+++ b/spec/unit/knife/cookbook_show_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, eersion 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,207 +17,205 @@
#
# rename to cookbook not coookbook
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::CookbookShow do
- before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
- @knife = Chef::Knife::CookbookShow.new
- @knife.config = { }
- @knife.name_args = [ "cookbook_name" ]
- @rest = double(Chef::REST)
- allow(@knife).to receive(:rest).and_return(@rest)
- allow(@knife).to receive(:pretty_print).and_return(true)
- allow(@knife).to receive(:output).and_return(true)
+ before do
+ Chef::Config[:node_name] = "webmonkey.example.com"
+ allow(knife).to receive(:rest).and_return(rest)
+ allow(knife).to receive(:pretty_print).and_return(true)
+ allow(knife).to receive(:output).and_return(true)
+ allow(Chef::CookbookVersion).to receive(:load).and_return(cb)
+ end
+
+ let (:knife) do
+ knife = Chef::Knife::CookbookShow.new
+ knife.config = {}
+ knife.name_args = [ "cookbook_name" ]
+ knife
+ end
+
+ let (:cb) do
+ cb = Chef::CookbookVersion.new("cookbook_name")
+ cb.manifest = manifest
+ cb
+ end
+
+ let (:rest) { double(Chef::ServerAPI) }
+
+ let (:content) { "Example recipe text" }
+
+ let (:manifest) do
+ {
+ "recipes" => [
+ {
+ :name => "default.rb",
+ :path => "recipes/default.rb",
+ :checksum => "1234",
+ :url => "http://example.org/files/default.rb",
+ },
+ ],
+ }
end
describe "run" do
describe "with 0 arguments: help" do
- it 'should should print usage and exit when given no arguments' do
- @knife.name_args = []
- expect(@knife).to receive(:show_usage)
- expect(@knife.ui).to receive(:fatal)
- expect { @knife.run }.to raise_error(SystemExit)
+ it "should should print usage and exit when given no arguments" do
+ knife.name_args = []
+ expect(knife).to receive(:show_usage)
+ expect(knife.ui).to receive(:fatal)
+ expect { knife.run }.to raise_error(SystemExit)
end
end
describe "with 1 argument: versions" do
- before(:each) do
- @response = {
+ let (:response) do
+ {
"cookbook_name" => {
"url" => "http://url/cookbooks/cookbook_name",
"versions" => [
{ "version" => "0.10.0", "url" => "http://url/cookbooks/cookbook_name/0.10.0" },
{ "version" => "0.9.0", "url" => "http://url/cookbookx/cookbook_name/0.9.0" },
- { "version" => "0.8.0", "url" => "http://url/cookbooks/cookbook_name/0.8.0" }
- ]
- }
+ { "version" => "0.8.0", "url" => "http://url/cookbooks/cookbook_name/0.8.0" },
+ ],
+ },
}
end
it "should show the raw cookbook data" do
- expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name").and_return(@response)
- expect(@knife).to receive(:format_cookbook_list_for_display).with(@response)
- @knife.run
+ expect(rest).to receive(:get).with("cookbooks/cookbook_name").and_return(response)
+ expect(knife).to receive(:format_cookbook_list_for_display).with(response)
+ knife.run
end
it "should respect the user-supplied environment" do
- @knife.config[:environment] = "foo"
- expect(@rest).to receive(:get_rest).with("environments/foo/cookbooks/cookbook_name").and_return(@response)
- expect(@knife).to receive(:format_cookbook_list_for_display).with(@response)
- @knife.run
+ knife.config[:environment] = "foo"
+ expect(rest).to receive(:get).with("environments/foo/cookbooks/cookbook_name").and_return(response)
+ expect(knife).to receive(:format_cookbook_list_for_display).with(response)
+ knife.run
end
end
describe "with 2 arguments: name and version" do
- before(:each) do
- @knife.name_args << "0.1.0"
- @response = { "0.1.0" => { "recipes" => {"default.rb" => ""} } }
+ before do
+ knife.name_args << "0.1.0"
end
it "should show the specific part of a cookbook" do
- expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@response)
- expect(@knife).to receive(:output).with(@response)
- @knife.run
+ expect(Chef::CookbookVersion).to receive(:load).with("cookbook_name", "0.1.0").and_return(cb)
+ expect(knife).to receive(:output).with(cb)
+ knife.run
end
end
describe "with 3 arguments: name, version, and segment" do
before(:each) do
- @knife.name_args = [ "cookbook_name", "0.1.0", "recipes" ]
- @cookbook_response = Chef::CookbookVersion.new("cookbook_name")
- @manifest = {
- "recipes" => [
- {
- :name => "default.rb",
- :path => "recipes/default.rb",
- :checksum => "1234",
- :url => "http://example.org/files/default.rb"
- }
- ]
- }
- @cookbook_response.manifest = @manifest
- @response = {"name"=>"default.rb", "url"=>"http://example.org/files/default.rb", "checksum"=>"1234", "path"=>"recipes/default.rb"}
+ knife.name_args = [ "cookbook_name", "0.1.0", "recipes" ]
end
it "should print the json of the part" do
- expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
- expect(@knife).to receive(:output).with(@cookbook_response.manifest["recipes"])
- @knife.run
+ expect(Chef::CookbookVersion).to receive(:load).with("cookbook_name", "0.1.0").and_return(cb)
+ expect(knife).to receive(:output).with(cb.manifest["recipes"])
+ knife.run
end
end
describe "with 4 arguments: name, version, segment and filename" do
before(:each) do
- @knife.name_args = [ "cookbook_name", "0.1.0", "recipes", "default.rb" ]
- @cookbook_response = Chef::CookbookVersion.new("cookbook_name")
- @cookbook_response.manifest = {
- "recipes" => [
- {
- :name => "default.rb",
- :path => "recipes/default.rb",
- :checksum => "1234",
- :url => "http://example.org/files/default.rb"
- }
- ]
- }
- @response = "Example recipe text"
+ knife.name_args = [ "cookbook_name", "0.1.0", "recipes", "default.rb" ]
end
it "should print the raw result of the request (likely a file!)" do
- expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
- expect(@rest).to receive(:get_rest).with("http://example.org/files/default.rb", true).and_return(StringIO.new(@response))
- expect(@knife).to receive(:pretty_print).with(@response)
- @knife.run
+ expect(Chef::CookbookVersion).to receive(:load).with("cookbook_name", "0.1.0").and_return(cb)
+ expect(rest).to receive(:streaming_request).with("http://example.org/files/default.rb").and_return(StringIO.new(content))
+ expect(knife).to receive(:pretty_print).with(content)
+ knife.run
end
end
describe "with 4 arguments: name, version, segment and filename -- with specificity" do
before(:each) do
- @knife.name_args = [ "cookbook_name", "0.1.0", "files", "afile.rb" ]
- @cookbook_response = Chef::CookbookVersion.new("cookbook_name")
- @cookbook_response.manifest = {
+ knife.name_args = [ "cookbook_name", "0.1.0", "files", "afile.rb" ]
+ cb.manifest = {
"files" => [
{
:name => "afile.rb",
:path => "files/host-examplehost.example.org/afile.rb",
:checksum => "1111",
:specificity => "host-examplehost.example.org",
- :url => "http://example.org/files/1111"
+ :url => "http://example.org/files/1111",
},
{
:name => "afile.rb",
:path => "files/ubuntu-9.10/afile.rb",
:checksum => "2222",
:specificity => "ubuntu-9.10",
- :url => "http://example.org/files/2222"
+ :url => "http://example.org/files/2222",
},
{
:name => "afile.rb",
:path => "files/ubuntu/afile.rb",
:checksum => "3333",
:specificity => "ubuntu",
- :url => "http://example.org/files/3333"
+ :url => "http://example.org/files/3333",
},
{
:name => "afile.rb",
:path => "files/default/afile.rb",
:checksum => "4444",
:specificity => "default",
- :url => "http://example.org/files/4444"
+ :url => "http://example.org/files/4444",
},
- ]
+ ],
}
- @response = "Example recipe text"
end
describe "with --fqdn" do
it "should pass the fqdn" do
- @knife.config[:platform] = "example_platform"
- @knife.config[:platform_version] = "1.0"
- @knife.config[:fqdn] = "examplehost.example.org"
- expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
- expect(@rest).to receive(:get_rest).with("http://example.org/files/1111", true).and_return(StringIO.new(@response))
- expect(@knife).to receive(:pretty_print).with(@response)
- @knife.run
+ knife.config[:platform] = "example_platform"
+ knife.config[:platform_version] = "1.0"
+ knife.config[:fqdn] = "examplehost.example.org"
+ expect(Chef::CookbookVersion).to receive(:load).with("cookbook_name", "0.1.0").and_return(cb)
+ expect(rest).to receive(:streaming_request).with("http://example.org/files/1111").and_return(StringIO.new(content))
+ expect(knife).to receive(:pretty_print).with(content)
+ knife.run
end
end
describe "and --platform" do
it "should pass the platform" do
- @knife.config[:platform] = "ubuntu"
- @knife.config[:platform_version] = "1.0"
- @knife.config[:fqdn] = "differenthost.example.org"
- expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
- expect(@rest).to receive(:get_rest).with("http://example.org/files/3333", true).and_return(StringIO.new(@response))
- expect(@knife).to receive(:pretty_print).with(@response)
- @knife.run
+ knife.config[:platform] = "ubuntu"
+ knife.config[:platform_version] = "1.0"
+ knife.config[:fqdn] = "differenthost.example.org"
+ expect(Chef::CookbookVersion).to receive(:load).with("cookbook_name", "0.1.0").and_return(cb)
+ expect(rest).to receive(:streaming_request).with("http://example.org/files/3333").and_return(StringIO.new(content))
+ expect(knife).to receive(:pretty_print).with(content)
+ knife.run
end
end
describe "and --platform-version" do
it "should pass the platform" do
- @knife.config[:platform] = "ubuntu"
- @knife.config[:platform_version] = "9.10"
- @knife.config[:fqdn] = "differenthost.example.org"
- expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
- expect(@rest).to receive(:get_rest).with("http://example.org/files/2222", true).and_return(StringIO.new(@response))
- expect(@knife).to receive(:pretty_print).with(@response)
- @knife.run
+ knife.config[:platform] = "ubuntu"
+ knife.config[:platform_version] = "9.10"
+ knife.config[:fqdn] = "differenthost.example.org"
+ expect(Chef::CookbookVersion).to receive(:load).with("cookbook_name", "0.1.0").and_return(cb)
+ expect(rest).to receive(:streaming_request).with("http://example.org/files/2222").and_return(StringIO.new(content))
+ expect(knife).to receive(:pretty_print).with(content)
+ knife.run
end
end
describe "with none of the arguments, it should use the default" do
it "should pass them all" do
- expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
- expect(@rest).to receive(:get_rest).with("http://example.org/files/4444", true).and_return(StringIO.new(@response))
- expect(@knife).to receive(:pretty_print).with(@response)
- @knife.run
+ expect(Chef::CookbookVersion).to receive(:load).with("cookbook_name", "0.1.0").and_return(cb)
+ expect(rest).to receive(:streaming_request).with("http://example.org/files/4444").and_return(StringIO.new(content))
+ expect(knife).to receive(:pretty_print).with(content)
+ knife.run
end
end
end
end
end
-
diff --git a/spec/unit/knife/cookbook_site_download_spec.rb b/spec/unit/knife/cookbook_site_download_spec.rb
index fdf4c2197b..0ab6a8a9b4 100644
--- a/spec/unit/knife/cookbook_site_download_spec.rb
+++ b/spec/unit/knife/cookbook_site_download_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2012 Thomas Bishop
+# Copyright:: Copyright 2012-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,73 +16,72 @@
# limitations under the License.
#
-require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
+require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
describe Chef::Knife::CookbookSiteDownload do
- describe 'run' do
+ describe "run" do
before do
@knife = Chef::Knife::CookbookSiteDownload.new
- @knife.name_args = ['apache2']
- @noauth_rest = double('no auth rest')
+ @knife.name_args = ["apache2"]
+ @noauth_rest = double("no auth rest")
@stderr = StringIO.new
- @cookbook_api_url = 'https://supermarket.chef.io/api/v1/cookbooks'
- @version = '1.0.2'
- @version_us = @version.gsub '.', '_'
- @current_data = { 'deprecated' => false,
- 'latest_version' => "#{@cookbook_api_url}/apache2/versions/#{@version_us}",
- 'replacement' => 'other_apache2' }
+ @cookbook_api_url = "https://supermarket.chef.io/api/v1/cookbooks"
+ @version = "1.0.2"
+ @version_us = @version.tr ".", "_"
+ @current_data = { "deprecated" => false,
+ "latest_version" => "#{@cookbook_api_url}/apache2/versions/#{@version_us}",
+ "replacement" => "other_apache2" }
allow(@knife.ui).to receive(:stderr).and_return(@stderr)
allow(@knife).to receive(:noauth_rest).and_return(@noauth_rest)
- expect(@noauth_rest).to receive(:get_rest).
- with("#{@cookbook_api_url}/apache2").
- and_return(@current_data)
+ expect(@noauth_rest).to receive(:get).
+ with("#{@cookbook_api_url}/apache2").
+ and_return(@current_data)
+ @knife.configure_chef
end
- context 'when the cookbook is deprecated and not forced' do
+ context "when the cookbook is deprecated and not forced" do
before do
- @current_data['deprecated'] = true
+ @current_data["deprecated"] = true
end
- it 'should warn with info about the replacement' do
+ it "should warn with info about the replacement" do
expect(@knife.ui).to receive(:warn).
- with(/.+deprecated.+replaced by other_apache2.+/i)
+ with(/.+deprecated.+replaced by other_apache2.+/i)
expect(@knife.ui).to receive(:warn).
- with(/use --force.+download.+/i)
+ with(/use --force.+download.+/i)
@knife.run
end
end
- context 'when' do
+ context "when" do
before do
- @cookbook_data = { 'version' => @version,
- 'file' => "http://example.com/apache2_#{@version_us}.tgz" }
- @temp_file = double( :path => "/tmp/apache2_#{@version_us}.tgz" )
+ @cookbook_data = { "version" => @version,
+ "file" => "http://example.com/apache2_#{@version_us}.tgz" }
+ @temp_file = double( :path => "/tmp/apache2_#{@version_us}.tgz" )
@file = File.join(Dir.pwd, "apache2-#{@version}.tar.gz")
-
- expect(@noauth_rest).to receive(:sign_on_redirect=).with(false)
end
- context 'downloading the latest version' do
+ context "downloading the latest version" do
before do
- expect(@noauth_rest).to receive(:get_rest).
- with(@current_data['latest_version']).
- and_return(@cookbook_data)
- expect(@noauth_rest).to receive(:get_rest).
- with(@cookbook_data['file'], true).
- and_return(@temp_file)
+ expect(@noauth_rest).to receive(:get).
+ with(@current_data["latest_version"]).
+ and_return(@cookbook_data)
+ expect(@noauth_rest).to receive(:streaming_request).
+ with(@cookbook_data["file"]).
+ and_return(@temp_file)
end
- context 'and it is deprecated and with --force' do
+ context "and it is deprecated and with --force" do
before do
- @current_data['deprecated'] = true
+ @current_data["deprecated"] = true
@knife.config[:force] = true
end
- it 'should download the latest version' do
+ it "should download the latest version" do
expect(@knife.ui).to receive(:warn).
- with(/.+deprecated.+replaced by other_apache2.+/i)
+ with(/.+deprecated.+replaced by other_apache2.+/i)
expect(FileUtils).to receive(:cp).with(@temp_file.path, @file)
@knife.run
expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
@@ -91,52 +90,52 @@ describe Chef::Knife::CookbookSiteDownload do
end
- it 'should download the latest version' do
+ it "should download the latest version" do
expect(FileUtils).to receive(:cp).with(@temp_file.path, @file)
@knife.run
expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
expect(@stderr.string).to match /cookbook save.+#{Regexp.escape(@file)}/i
end
- context 'with -f or --file' do
+ context "with -f or --file" do
before do
- @file = '/opt/chef/cookbooks/apache2.tar.gz'
+ @file = "/opt/chef/cookbooks/apache2.tar.gz"
@knife.config[:file] = @file
expect(FileUtils).to receive(:cp).with(@temp_file.path, @file)
end
- it 'should download the cookbook to the desired file' do
+ it "should download the cookbook to the desired file" do
@knife.run
expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
expect(@stderr.string).to match /cookbook save.+#{Regexp.escape(@file)}/i
end
end
- it 'should provide an accessor to the version' do
+ it "should provide an accessor to the version" do
allow(FileUtils).to receive(:cp).and_return(true)
expect(@knife.version).to eq(@version)
@knife.run
end
end
- context 'downloading a cookbook of a specific version' do
+ context "downloading a cookbook of a specific version" do
before do
- @version = '1.0.1'
- @version_us = @version.gsub '.', '_'
- @cookbook_data = { 'version' => @version,
- 'file' => "http://example.com/apache2_#{@version_us}.tgz" }
+ @version = "1.0.1"
+ @version_us = @version.tr ".", "_"
+ @cookbook_data = { "version" => @version,
+ "file" => "http://example.com/apache2_#{@version_us}.tgz" }
@temp_file = double(:path => "/tmp/apache2_#{@version_us}.tgz")
@file = File.join(Dir.pwd, "apache2-#{@version}.tar.gz")
@knife.name_args << @version
end
- it 'should download the desired version' do
- expect(@noauth_rest).to receive(:get_rest).
- with("#{@cookbook_api_url}/apache2/versions/#{@version_us}").
- and_return(@cookbook_data)
- expect(@noauth_rest).to receive(:get_rest).
- with(@cookbook_data['file'], true).
- and_return(@temp_file)
+ it "should download the desired version" do
+ expect(@noauth_rest).to receive(:get).
+ with("#{@cookbook_api_url}/apache2/versions/#{@version_us}").
+ and_return(@cookbook_data)
+ expect(@noauth_rest).to receive(:streaming_request).
+ with(@cookbook_data["file"]).
+ and_return(@temp_file)
expect(FileUtils).to receive(:cp).with(@temp_file.path, @file)
@knife.run
expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
diff --git a/spec/unit/knife/cookbook_site_install_spec.rb b/spec/unit/knife/cookbook_site_install_spec.rb
index 07b268bb64..d93af10761 100644
--- a/spec/unit/knife/cookbook_site_install_spec.rb
+++ b/spec/unit/knife/cookbook_site_install_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,17 +23,21 @@ describe Chef::Knife::CookbookSiteInstall do
let(:stdout) { StringIO.new }
let(:stderr) { StringIO.new }
let(:downloader) { Hash.new }
- let(:repo) { double(:sanity_check => true, :reset_to_default_state => true,
- :prepare_to_import => true, :finalize_updates_to => true,
- :merge_updates_from => true) }
- let(:install_path) { if Chef::Platform.windows?
- 'C:/tmp/chef'
- else
- '/var/tmp/chef'
- end }
+ let(:archive) { double(Mixlib::Archive, extract: true) }
+ let(:repo) do
+ double(:sanity_check => true, :reset_to_default_state => true,
+ :prepare_to_import => true, :finalize_updates_to => true,
+ :merge_updates_from => true) end
+ let(:install_path) do
+ if Chef::Platform.windows?
+ "C:/tmp/chef"
+ else
+ "/var/tmp/chef"
+ end
+ end
before(:each) do
- require 'chef/knife/core/cookbook_scm_repo'
+ require "chef/knife/core/cookbook_scm_repo"
allow(knife.ui).to receive(:stdout).and_return(stdout)
knife.config = {}
@@ -46,6 +50,7 @@ describe Chef::Knife::CookbookSiteInstall do
allow(File).to receive(:unlink)
allow(File).to receive(:rmtree)
allow(knife).to receive(:shell_out!).and_return(true)
+ allow(Mixlib::Archive).to receive(:new).and_return(archive)
# CookbookSiteDownload Stup
allow(knife).to receive(:download_cookbook_to).and_return(downloader)
@@ -69,7 +74,7 @@ describe Chef::Knife::CookbookSiteInstall do
end
it "raises an error if more than two arguments are given" do
- knife.name_args = ["foo", "bar", "baz"]
+ knife.name_args = %w{foo bar baz}
expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.")
expect { knife.run }.to raise_error(SystemExit)
end
diff --git a/spec/unit/knife/cookbook_site_share_spec.rb b/spec/unit/knife/cookbook_site_share_spec.rb
index a7caca9744..823eff8b04 100644
--- a/spec/unit/knife/cookbook_site_share_spec.rb
+++ b/spec/unit/knife/cookbook_site_share_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/cookbook_uploader'
-require 'chef/cookbook_site_streaming_uploader'
+require "chef/cookbook_uploader"
+require "chef/cookbook_site_streaming_uploader"
describe Chef::Knife::CookbookSiteShare do
@@ -27,19 +27,19 @@ describe Chef::Knife::CookbookSiteShare do
@knife = Chef::Knife::CookbookSiteShare.new
# Merge default settings in.
@knife.merge_configs
- @knife.name_args = ['cookbook_name', 'AwesomeSausage']
+ @knife.name_args = %w{cookbook_name AwesomeSausage}
- @cookbook = Chef::CookbookVersion.new('cookbook_name')
+ @cookbook = Chef::CookbookVersion.new("cookbook_name")
- @cookbook_loader = double('Chef::CookbookLoader')
+ @cookbook_loader = double("Chef::CookbookLoader")
allow(@cookbook_loader).to receive(:cookbook_exists?).and_return(true)
allow(@cookbook_loader).to receive(:[]).and_return(@cookbook)
allow(Chef::CookbookLoader).to receive(:new).and_return(@cookbook_loader)
- @noauth_rest = double(Chef::REST)
+ @noauth_rest = double(Chef::ServerAPI)
allow(@knife).to receive(:noauth_rest).and_return(@noauth_rest)
- @cookbook_uploader = Chef::CookbookUploader.new('herpderp', :rest => "norest")
+ @cookbook_uploader = Chef::CookbookUploader.new("herpderp", :rest => "norest")
allow(Chef::CookbookUploader).to receive(:new).and_return(@cookbook_uploader)
allow(@cookbook_uploader).to receive(:validate_cookbooks).and_return(true)
allow(Chef::CookbookSiteStreamingUploader).to receive(:create_build_dir).and_return(Dir.mktmpdir)
@@ -49,55 +49,55 @@ describe Chef::Knife::CookbookSiteShare do
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
end
- describe 'run' do
+ describe "run" do
before(:each) do
allow(@knife).to receive(:do_upload).and_return(true)
@category_response = {
"name" => "cookbook_name",
- "category" => "Testing Category"
+ "category" => "Testing Category",
}
@bad_category_response = {
"error_code" => "NOT_FOUND",
"error_messages" => [
- "Resource does not exist."
- ]
+ "Resource does not exist.",
+ ],
}
end
- it 'should set true to config[:dry_run] as default' do
+ it "should set true to config[:dry_run] as default" do
expect(@knife.config[:dry_run]).to be_falsey
end
- it 'should should print usage and exit when given no arguments' do
+ it "should should print usage and exit when given no arguments" do
@knife.name_args = []
expect(@knife).to receive(:show_usage)
expect(@knife.ui).to receive(:fatal)
expect { @knife.run }.to raise_error(SystemExit)
end
- it 'should not fail when given only 1 argument and can determine category' do
- @knife.name_args = ['cookbook_name']
- expect(@noauth_rest).to receive(:get_rest).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name").and_return(@category_response)
+ it "should not fail when given only 1 argument and can determine category" do
+ @knife.name_args = ["cookbook_name"]
+ expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name").and_return(@category_response)
expect(@knife).to receive(:do_upload)
@knife.run
end
- it 'should print error and exit when given only 1 argument and cannot determine category' do
- @knife.name_args = ['cookbook_name']
- expect(@noauth_rest).to receive(:get_rest).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name").and_return(@bad_category_response)
- expect(@knife.ui).to receive(:fatal)
- expect { @knife.run }.to raise_error(SystemExit)
+ it "should use a default category when given only 1 argument and cannot determine category" do
+ @knife.name_args = ["cookbook_name"]
+ expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name") { raise Net::HTTPServerException.new("404 Not Found", OpenStruct.new(code: "404")) }
+ expect(@knife).to receive(:do_upload)
+ expect { @knife.run }.to_not raise_error
end
- it 'should print error and exit when given only 1 argument and Chef::REST throws an exception' do
- @knife.name_args = ['cookbook_name']
- expect(@noauth_rest).to receive(:get_rest).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name") { raise Errno::ECONNREFUSED, "Connection refused" }
+ it "should print error and exit when given only 1 argument and Chef::ServerAPI throws an exception" do
+ @knife.name_args = ["cookbook_name"]
+ expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name") { raise Errno::ECONNREFUSED, "Connection refused" }
expect(@knife.ui).to receive(:fatal)
expect { @knife.run }.to raise_error(SystemExit)
end
- it 'should check if the cookbook exists' do
+ it "should check if the cookbook exists" do
expect(@cookbook_loader).to receive(:cookbook_exists?)
@knife.run
end
@@ -108,15 +108,15 @@ describe Chef::Knife::CookbookSiteShare do
expect { @knife.run }.to raise_error(SystemExit)
end
- if File.exists?('/usr/bin/gnutar') || File.exists?('/bin/gnutar')
- it 'should use gnutar to make a tarball of the cookbook' do
+ if File.exists?("/usr/bin/gnutar") || File.exists?("/bin/gnutar")
+ it "should use gnutar to make a tarball of the cookbook" do
expect(@knife).to receive(:shell_out!) do |args|
expect(args.to_s).to match(/gnutar -czf/)
end
@knife.run
end
else
- it 'should make a tarball of the cookbook' do
+ it "should make a tarball of the cookbook" do
expect(@knife).to receive(:shell_out!) do |args|
expect(args.to_s).to match(/tar -czf/)
end
@@ -124,13 +124,13 @@ describe Chef::Knife::CookbookSiteShare do
end
end
- it 'should exit and log to error when the tarball creation fails' do
+ it "should exit and log to error when the tarball creation fails" do
allow(@knife).to receive(:shell_out!).and_raise(Chef::Exceptions::Exec)
expect(@knife.ui).to receive(:error)
expect { @knife.run }.to raise_error(SystemExit)
end
- it 'should upload the cookbook and clean up the tarball' do
+ it "should upload the cookbook and clean up the tarball" do
expect(@knife).to receive(:do_upload)
expect(FileUtils).to receive(:rm_rf)
@knife.run
@@ -140,13 +140,13 @@ describe Chef::Knife::CookbookSiteShare do
before do
allow(Chef::CookbookSiteStreamingUploader).to receive(:create_build_dir).and_return("/var/tmp/dummy")
@knife.config = { :dry_run => true }
- allow(@knife).to receive_message_chain(:shell_out!, :stdout).and_return('file')
+ allow(@knife).to receive_message_chain(:shell_out!, :stdout).and_return("file")
end
it "should list files in the tarball" do
allow(@knife).to receive(:tar_cmd).and_return("footar")
- expect(@knife).to receive(:shell_out!).with("footar -czf #{@cookbook.name}.tgz #{@cookbook.name}", {:cwd => "/var/tmp/dummy"})
- expect(@knife).to receive(:shell_out!).with("footar -tzf #{@cookbook.name}.tgz", {:cwd => "/var/tmp/dummy"})
+ expect(@knife).to receive(:shell_out!).with("footar -czf #{@cookbook.name}.tgz #{@cookbook.name}", { :cwd => "/var/tmp/dummy" })
+ expect(@knife).to receive(:shell_out!).with("footar -tzf #{@cookbook.name}.tgz", { :cwd => "/var/tmp/dummy" })
@knife.run
end
@@ -158,10 +158,10 @@ describe Chef::Knife::CookbookSiteShare do
end
end
- describe 'do_upload' do
+ describe "do_upload" do
before(:each) do
- @upload_response = double('Net::HTTPResponse')
+ @upload_response = double("Net::HTTPResponse")
allow(Chef::CookbookSiteStreamingUploader).to receive(:post).and_return(@upload_response)
@stdout = StringIO.new
@@ -172,35 +172,35 @@ describe Chef::Knife::CookbookSiteShare do
end
it 'should post the cookbook to "https://supermarket.chef.io"' do
- response_text = Chef::JSONCompat.to_json({:uri => 'https://supermarket.chef.io/cookbooks/cookbook_name'})
+ response_text = Chef::JSONCompat.to_json({ :uri => "https://supermarket.chef.io/cookbooks/cookbook_name" })
allow(@upload_response).to receive(:body).and_return(response_text)
allow(@upload_response).to receive(:code).and_return(201)
expect(Chef::CookbookSiteStreamingUploader).to receive(:post).with(/supermarket\.chef\.io/, anything(), anything(), anything())
@knife.run
end
- it 'should alert the user when a version already exists' do
- response_text = Chef::JSONCompat.to_json({:error_messages => ['Version already exists']})
+ it "should alert the user when a version already exists" do
+ response_text = Chef::JSONCompat.to_json({ :error_messages => ["Version already exists"] })
allow(@upload_response).to receive(:body).and_return(response_text)
allow(@upload_response).to receive(:code).and_return(409)
expect { @knife.run }.to raise_error(SystemExit)
expect(@stderr.string).to match(/ERROR(.+)cookbook already exists/)
end
- it 'should pass any errors on to the user' do
- response_text = Chef::JSONCompat.to_json({:error_messages => ["You're holding it wrong"]})
+ it "should pass any errors on to the user" do
+ response_text = Chef::JSONCompat.to_json({ :error_messages => ["You're holding it wrong"] })
allow(@upload_response).to receive(:body).and_return(response_text)
allow(@upload_response).to receive(:code).and_return(403)
expect { @knife.run }.to raise_error(SystemExit)
expect(@stderr.string).to match("ERROR(.*)You're holding it wrong")
end
- it 'should print the body if no errors are exposed on failure' do
- response_text = Chef::JSONCompat.to_json({:system_error => "Your call was dropped", :reason => "There's a map for that"})
+ it "should print the body if no errors are exposed on failure" do
+ response_text = Chef::JSONCompat.to_json({ :system_error => "Your call was dropped", :reason => "There's a map for that" })
allow(@upload_response).to receive(:body).and_return(response_text)
allow(@upload_response).to receive(:code).and_return(500)
- expect(@knife.ui).to receive(:error).with(/#{Regexp.escape(response_text)}/)#.ordered
- expect(@knife.ui).to receive(:error).with(/Unknown error/)#.ordered
+ expect(@knife.ui).to receive(:error).with(/#{Regexp.escape(response_text)}/) #.ordered
+ expect(@knife.ui).to receive(:error).with(/Unknown error/) #.ordered
expect { @knife.run }.to raise_error(SystemExit)
end
diff --git a/spec/unit/knife/cookbook_site_unshare_spec.rb b/spec/unit/knife/cookbook_site_unshare_spec.rb
index ec46a8705c..8e4358226d 100644
--- a/spec/unit/knife/cookbook_site_unshare_spec.rb
+++ b/spec/unit/knife/cookbook_site_unshare_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,26 +17,26 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::CookbookSiteUnshare do
before(:each) do
@knife = Chef::Knife::CookbookSiteUnshare.new
- @knife.name_args = ['cookbook_name']
+ @knife.name_args = ["cookbook_name"]
allow(@knife).to receive(:confirm).and_return(true)
- @rest = double('Chef::REST')
- allow(@rest).to receive(:delete_rest).and_return(true)
+ @rest = double("Chef::ServerAPI")
+ allow(@rest).to receive(:delete).and_return(true)
allow(@knife).to receive(:rest).and_return(@rest)
@stdout = StringIO.new
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
end
- describe 'run' do
+ describe "run" do
- describe 'with no cookbook argument' do
- it 'should print the usage and exit' do
+ describe "with no cookbook argument" do
+ it "should print the usage and exit" do
@knife.name_args = []
expect(@knife.ui).to receive(:fatal)
expect(@knife).to receive(:show_usage)
@@ -44,30 +44,30 @@ describe Chef::Knife::CookbookSiteUnshare do
end
end
- it 'should confirm you want to unshare the cookbook' do
+ it "should confirm you want to unshare the cookbook" do
expect(@knife).to receive(:confirm)
@knife.run
end
- it 'should send a delete request to the cookbook site' do
- expect(@rest).to receive(:delete_rest)
+ it "should send a delete request to the cookbook site" do
+ expect(@rest).to receive(:delete)
@knife.run
end
- it 'should log an error and exit when forbidden' do
- exception = double('403 "Forbidden"', :code => '403')
- allow(@rest).to receive(:delete_rest).and_raise(Net::HTTPServerException.new('403 "Forbidden"', exception))
+ it "should log an error and exit when forbidden" do
+ exception = double('403 "Forbidden"', :code => "403")
+ allow(@rest).to receive(:delete).and_raise(Net::HTTPServerException.new('403 "Forbidden"', exception))
expect(@knife.ui).to receive(:error)
expect { @knife.run }.to raise_error(SystemExit)
end
- it 'should re-raise any non-forbidden errors on delete_rest' do
- exception = double('500 "Application Error"', :code => '500')
- allow(@rest).to receive(:delete_rest).and_raise(Net::HTTPServerException.new('500 "Application Error"', exception))
+ it "should re-raise any non-forbidden errors on delete" do
+ exception = double('500 "Application Error"', :code => "500")
+ allow(@rest).to receive(:delete).and_raise(Net::HTTPServerException.new('500 "Application Error"', exception))
expect { @knife.run }.to raise_error(Net::HTTPServerException)
end
- it 'should log a success message' do
+ it "should log a success message" do
expect(@knife.ui).to receive(:info)
@knife.run
end
diff --git a/spec/unit/knife/cookbook_test_spec.rb b/spec/unit/knife/cookbook_test_spec.rb
index ce74bcaa5d..f8b212e271 100644
--- a/spec/unit/knife/cookbook_test_spec.rb
+++ b/spec/unit/knife/cookbook_test_spec.rb
@@ -1,8 +1,8 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)$
+# Author:: Stephen Delano (<stephen@chef.io>)$
# Author:: Matthew Kent (<mkent@magoazul.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.$
-# Copyright:: Copyright (c) 2010 Matthew Kent
+# Copyright:: Copyright 2010-2016, Chef Software Inc.$
+# Copyright:: Copyright 2010-2016, Matthew Kent
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,14 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
Chef::Knife::CookbookTest.load_deps
describe Chef::Knife::CookbookTest do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::CookbookTest.new
- @knife.config[:cookbook_path] = File.join(CHEF_SPEC_DATA,'cookbooks')
+ @knife.config[:cookbook_path] = File.join(CHEF_SPEC_DATA, "cookbooks")
allow(@knife.cookbook_loader).to receive(:cookbook_exists?).and_return(true)
@cookbooks = []
%w{tats central_market jimmy_johns pho}.each do |cookbook_name|
@@ -45,7 +45,7 @@ describe Chef::Knife::CookbookTest do
it "should test multiple cookbooks when provided" do
allow(@knife).to receive(:test_cookbook).and_return(true)
- @knife.name_args = ["tats", "jimmy_johns"]
+ @knife.name_args = %w{tats jimmy_johns}
expect(@knife).to receive(:test_cookbook).with("tats")
expect(@knife).to receive(:test_cookbook).with("jimmy_johns")
expect(@knife).not_to receive(:test_cookbook).with("central_market")
@@ -56,7 +56,7 @@ describe Chef::Knife::CookbookTest do
it "should test both ruby and templates" do
@knife.name_args = ["example"]
expect(@knife.config[:cookbook_path]).not_to be_empty
- Array(@knife.config[:cookbook_path]).reverse.each do |path|
+ Array(@knife.config[:cookbook_path]).reverse_each do |path|
expect(@knife).to receive(:test_ruby).with(an_instance_of(Chef::Cookbook::SyntaxCheck))
expect(@knife).to receive(:test_templates).with(an_instance_of(Chef::Cookbook::SyntaxCheck))
end
diff --git a/spec/unit/knife/cookbook_upload_spec.rb b/spec/unit/knife/cookbook_upload_spec.rb
index fb94886cad..9e07497c57 100644
--- a/spec/unit/knife/cookbook_upload_spec.rb
+++ b/spec/unit/knife/cookbook_upload_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Matthew Kent (<mkent@magoazul.com>)
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,20 +19,20 @@
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
-require 'chef/cookbook_uploader'
-require 'timeout'
+require "chef/cookbook_uploader"
+require "timeout"
describe Chef::Knife::CookbookUpload do
- let(:cookbook) { Chef::CookbookVersion.new('test_cookbook', '/tmp/blah.txt') }
+ let(:cookbook) { Chef::CookbookVersion.new("test_cookbook", "/tmp/blah.txt") }
let(:cookbooks_by_name) do
- {cookbook.name => cookbook}
+ { cookbook.name => cookbook }
end
let(:cookbook_loader) do
cookbook_loader = cookbooks_by_name.dup
allow(cookbook_loader).to receive(:merged_cookbooks).and_return([])
- allow(cookbook_loader).to receive(:load_cookbooks).and_return(cookbook_loader)
+ allow(cookbook_loader).to receive(:load_cookbooks_without_shadow_warning).and_return(cookbook_loader)
cookbook_loader
end
@@ -40,7 +40,7 @@ describe Chef::Knife::CookbookUpload do
let(:output) { StringIO.new }
- let(:name_args) { ['test_cookbook'] }
+ let(:name_args) { ["test_cookbook"] }
let(:knife) do
k = Chef::Knife::CookbookUpload.new
@@ -54,49 +54,49 @@ describe Chef::Knife::CookbookUpload do
allow(Chef::CookbookLoader).to receive(:new).and_return(cookbook_loader)
end
- describe 'with --concurrency' do
- it 'should upload cookbooks with predefined concurrency' do
+ describe "with --concurrency" do
+ it "should upload cookbooks with predefined concurrency" do
allow(Chef::CookbookVersion).to receive(:list_all_versions).and_return({})
knife.config[:concurrency] = 3
- test_cookbook = Chef::CookbookVersion.new('test_cookbook', '/tmp/blah')
+ test_cookbook = Chef::CookbookVersion.new("test_cookbook", "/tmp/blah")
allow(cookbook_loader).to receive(:each).and_yield("test_cookbook", test_cookbook)
allow(cookbook_loader).to receive(:cookbook_names).and_return(["test_cookbook"])
expect(Chef::CookbookUploader).to receive(:new).
- with( kind_of(Array), { :force => nil, :concurrency => 3}).
- and_return(double("Chef::CookbookUploader", :upload_cookbooks=> true))
+ with( kind_of(Array), { :force => nil, :concurrency => 3 }).
+ and_return(double("Chef::CookbookUploader", :upload_cookbooks => true))
knife.run
end
end
- describe 'run' do
+ describe "run" do
before(:each) do
allow(Chef::CookbookUploader).to receive_messages(:new => cookbook_uploader)
allow(Chef::CookbookVersion).to receive(:list_all_versions).and_return({})
end
- it 'should print usage and exit when a cookbook name is not provided' do
+ it "should print usage and exit when a cookbook name is not provided" do
knife.name_args = []
expect(knife).to receive(:show_usage)
expect(knife.ui).to receive(:fatal)
expect { knife.run }.to raise_error(SystemExit)
end
- describe 'when specifying a cookbook name' do
- it 'should upload the cookbook' do
+ describe "when specifying a cookbook name" do
+ it "should upload the cookbook" do
expect(knife).to receive(:upload).once
knife.run
end
- it 'should report on success' do
+ it "should report on success" do
expect(knife).to receive(:upload).once
expect(knife.ui).to receive(:info).with(/Uploaded 1 cookbook/)
knife.run
end
end
- describe 'when specifying the same cookbook name twice' do
- it 'should upload the cookbook only once' do
- knife.name_args = ['test_cookbook', 'test_cookbook']
+ describe "when specifying the same cookbook name twice" do
+ it "should upload the cookbook only once" do
+ knife.name_args = %w{test_cookbook test_cookbook}
expect(knife).to receive(:upload).once
knife.run
end
@@ -105,14 +105,14 @@ describe Chef::Knife::CookbookUpload do
context "when uploading a cookbook that uses deprecated overlays" do
before do
- allow(cookbook_loader).to receive(:merged_cookbooks).and_return(['test_cookbook'])
+ allow(cookbook_loader).to receive(:merged_cookbooks).and_return(["test_cookbook"])
allow(cookbook_loader).to receive(:merged_cookbook_paths).
- and_return({'test_cookbook' => %w{/path/one/test_cookbook /path/two/test_cookbook}})
+ and_return({ "test_cookbook" => %w{/path/one/test_cookbook /path/two/test_cookbook} })
end
it "emits a warning" do
knife.run
- expected_message=<<-E
+ expected_message = <<-E
WARNING: The cookbooks: test_cookbook exist in multiple places in your cookbook_path.
A composite version of these cookbooks has been compiled for uploading.
@@ -127,24 +127,25 @@ E
end
end
- describe 'when specifying a cookbook name among many' do
- let(:name_args) { ['test_cookbook1'] }
+ describe "when specifying a cookbook name among many" do
+ let(:name_args) { ["test_cookbook1"] }
let(:cookbooks_by_name) do
{
- 'test_cookbook1' => Chef::CookbookVersion.new('test_cookbook1', '/tmp/blah'),
- 'test_cookbook2' => Chef::CookbookVersion.new('test_cookbook2', '/tmp/blah'),
- 'test_cookbook3' => Chef::CookbookVersion.new('test_cookbook3', '/tmp/blah')
+ "test_cookbook1" => Chef::CookbookVersion.new("test_cookbook1", "/tmp/blah"),
+ "test_cookbook2" => Chef::CookbookVersion.new("test_cookbook2", "/tmp/blah"),
+ "test_cookbook3" => Chef::CookbookVersion.new("test_cookbook3", "/tmp/blah"),
}
end
it "should read only one cookbook" do
- expect(cookbook_loader).to receive(:[]).once.with('test_cookbook1').and_call_original
+ expect(cookbook_loader).to receive(:[]).once.with("test_cookbook1").and_call_original
knife.run
end
it "should not read all cookbooks" do
expect(cookbook_loader).not_to receive(:load_cookbooks)
+ expect(cookbook_loader).not_to receive(:load_cookbooks_without_shadow_warning)
knife.run
end
@@ -155,7 +156,7 @@ E
end
# This is testing too much. We should break it up.
- describe 'when specifying a cookbook name with dependencies' do
+ describe "when specifying a cookbook name with dependencies" do
let(:name_args) { ["test_cookbook2"] }
let(:cookbooks_by_name) do
@@ -164,16 +165,16 @@ E
"test_cookbook3" => test_cookbook3 }
end
- let(:test_cookbook1) { Chef::CookbookVersion.new('test_cookbook1', '/tmp/blah') }
+ let(:test_cookbook1) { Chef::CookbookVersion.new("test_cookbook1", "/tmp/blah") }
let(:test_cookbook2) do
- c = Chef::CookbookVersion.new('test_cookbook2')
+ c = Chef::CookbookVersion.new("test_cookbook2")
c.metadata.depends("test_cookbook3")
c
end
let(:test_cookbook3) do
- c = Chef::CookbookVersion.new('test_cookbook3')
+ c = Chef::CookbookVersion.new("test_cookbook3")
c.metadata.depends("test_cookbook1")
c.metadata.depends("test_cookbook2")
c
@@ -181,56 +182,57 @@ E
it "should upload all dependencies once" do
knife.config[:depends] = true
- allow(knife).to receive(:cookbook_names).and_return(["test_cookbook1", "test_cookbook2", "test_cookbook3"])
+ allow(knife).to receive(:cookbook_names).and_return(%w{test_cookbook1 test_cookbook2 test_cookbook3})
expect(knife).to receive(:upload).exactly(3).times
expect do
- Timeout::timeout(5) do
+ Timeout.timeout(5) do
knife.run
end
end.not_to raise_error
end
end
- describe 'when specifying a cookbook name with missing dependencies' do
- let(:cookbook_dependency) { Chef::CookbookVersion.new('dependency', '/tmp/blah') }
+ describe "when specifying a cookbook name with missing dependencies" do
+ let(:cookbook_dependency) { Chef::CookbookVersion.new("dependency", "/tmp/blah") }
before(:each) do
cookbook.metadata.depends("dependency")
- allow(cookbook_loader).to receive(:[]) do |ckbk|
+ allow(cookbook_loader).to receive(:[]) do |ckbk|
{ "test_cookbook" => cookbook,
- "dependency" => cookbook_dependency}[ckbk]
+ "dependency" => cookbook_dependency }[ckbk]
end
- allow(knife).to receive(:cookbook_names).and_return(["cookbook_dependency", "test_cookbook"])
+ allow(knife).to receive(:cookbook_names).and_return(%w{cookbook_dependency test_cookbook})
@stdout, @stderr, @stdin = StringIO.new, StringIO.new, StringIO.new
knife.ui = Chef::Knife::UI.new(@stdout, @stderr, @stdin, {})
end
- it 'should exit and not upload the cookbook' do
- expect(cookbook_loader).to receive(:[]).once.with('test_cookbook')
+ it "should exit and not upload the cookbook" do
+ expect(cookbook_loader).to receive(:[]).once.with("test_cookbook")
expect(cookbook_loader).not_to receive(:load_cookbooks)
+ expect(cookbook_loader).not_to receive(:load_cookbooks_without_shadow_warning)
expect(cookbook_uploader).not_to receive(:upload_cookbooks)
- expect {knife.run}.to raise_error(SystemExit)
+ expect { knife.run }.to raise_error(SystemExit)
end
- it 'should output a message for a single missing dependency' do
- expect {knife.run}.to raise_error(SystemExit)
- expect(@stderr.string).to include('Cookbook test_cookbook depends on cookbooks which are not currently')
- expect(@stderr.string).to include('being uploaded and cannot be found on the server.')
+ it "should output a message for a single missing dependency" do
+ expect { knife.run }.to raise_error(SystemExit)
+ expect(@stderr.string).to include("Cookbook test_cookbook depends on cookbooks which are not currently")
+ expect(@stderr.string).to include("being uploaded and cannot be found on the server.")
expect(@stderr.string).to include("The missing cookbook(s) are: 'dependency' version '>= 0.0.0'")
end
- it 'should output a message for a multiple missing dependencies which are concatenated' do
- cookbook_dependency2 = Chef::CookbookVersion.new('dependency2')
+ it "should output a message for a multiple missing dependencies which are concatenated" do
+ cookbook_dependency2 = Chef::CookbookVersion.new("dependency2")
cookbook.metadata.depends("dependency2")
- allow(cookbook_loader).to receive(:[]) do |ckbk|
+ allow(cookbook_loader).to receive(:[]) do |ckbk|
{ "test_cookbook" => cookbook,
"dependency" => cookbook_dependency,
- "dependency2" => cookbook_dependency2}[ckbk]
+ "dependency2" => cookbook_dependency2 }[ckbk]
end
- allow(knife).to receive(:cookbook_names).and_return(["dependency", "dependency2", "test_cookbook"])
- expect {knife.run}.to raise_error(SystemExit)
- expect(@stderr.string).to include('Cookbook test_cookbook depends on cookbooks which are not currently')
- expect(@stderr.string).to include('being uploaded and cannot be found on the server.')
+ allow(knife).to receive(:cookbook_names).and_return(%w{dependency dependency2 test_cookbook})
+ expect { knife.run }.to raise_error(SystemExit)
+ expect(@stderr.string).to include("Cookbook test_cookbook depends on cookbooks which are not currently")
+ expect(@stderr.string).to include("being uploaded and cannot be found on the server.")
expect(@stderr.string).to include("The missing cookbook(s) are:")
expect(@stderr.string).to include("'dependency' version '>= 0.0.0'")
expect(@stderr.string).to include("'dependency2' version '>= 0.0.0'")
@@ -243,31 +245,31 @@ E
knife.run
end
- describe 'with -a or --all' do
+ describe "with -a or --all" do
before(:each) do
knife.config[:all] = true
end
- context 'when cookbooks exist in the cookbook path' do
+ context "when cookbooks exist in the cookbook path" do
before(:each) do
- @test_cookbook1 = Chef::CookbookVersion.new('test_cookbook1', '/tmp/blah')
- @test_cookbook2 = Chef::CookbookVersion.new('test_cookbook2', '/tmp/blah')
+ @test_cookbook1 = Chef::CookbookVersion.new("test_cookbook1", "/tmp/blah")
+ @test_cookbook2 = Chef::CookbookVersion.new("test_cookbook2", "/tmp/blah")
allow(cookbook_loader).to receive(:each).and_yield("test_cookbook1", @test_cookbook1).and_yield("test_cookbook2", @test_cookbook2)
- allow(cookbook_loader).to receive(:cookbook_names).and_return(["test_cookbook1", "test_cookbook2"])
+ allow(cookbook_loader).to receive(:cookbook_names).and_return(%w{test_cookbook1 test_cookbook2})
end
- it 'should upload all cookbooks' do
+ it "should upload all cookbooks" do
expect(knife).to receive(:upload).once
knife.run
end
- it 'should report on success' do
+ it "should report on success" do
expect(knife).to receive(:upload).once
expect(knife.ui).to receive(:info).with(/Uploaded all cookbooks/)
knife.run
end
- it 'should update the version constraints for an environment' do
+ it "should update the version constraints for an environment" do
allow(knife).to receive(:assert_environment_valid!).and_return(true)
knife.config[:environment] = "production"
expect(knife).to receive(:update_version_constraints).once
@@ -275,28 +277,28 @@ E
end
end
- context 'when no cookbooks exist in the cookbook path' do
+ context "when no cookbooks exist in the cookbook path" do
before(:each) do
allow(cookbook_loader).to receive(:each)
end
- it 'should not upload any cookbooks' do
+ it "should not upload any cookbooks" do
expect(knife).to_not receive(:upload)
knife.run
end
- context 'when cookbook path is an array' do
- it 'should warn users that no cookbooks exist' do
- knife.config[:cookbook_path] = ['/chef-repo/cookbooks', '/home/user/cookbooks']
+ context "when cookbook path is an array" do
+ it "should warn users that no cookbooks exist" do
+ knife.config[:cookbook_path] = ["/chef-repo/cookbooks", "/home/user/cookbooks"]
expect(knife.ui).to receive(:warn).with(
/Could not find any cookbooks in your cookbook path: #{knife.config[:cookbook_path].join(', ')}\. Use --cookbook-path to specify the desired path\./)
knife.run
end
end
- context 'when cookbook path is a string' do
- it 'should warn users that no cookbooks exist' do
- knife.config[:cookbook_path] = '/chef-repo/cookbooks'
+ context "when cookbook path is a string" do
+ it "should warn users that no cookbooks exist" do
+ knife.config[:cookbook_path] = "/chef-repo/cookbooks"
expect(knife.ui).to receive(:warn).with(
/Could not find any cookbooks in your cookbook path: #{knife.config[:cookbook_path]}\. Use --cookbook-path to specify the desired path\./)
knife.run
@@ -305,8 +307,8 @@ E
end
end
- describe 'when a frozen cookbook exists on the server' do
- it 'should fail to replace it' do
+ describe "when a frozen cookbook exists on the server" do
+ it "should fail to replace it" do
exception = Chef::Exceptions::CookbookFrozen.new
expect(cookbook_uploader).to receive(:upload_cookbooks).
and_raise(exception)
@@ -315,7 +317,7 @@ E
expect { knife.run }.to raise_error(SystemExit)
end
- it 'should not update the version constraints for an environment' do
+ it "should not update the version constraints for an environment" do
allow(knife).to receive(:assert_environment_valid!).and_return(true)
knife.config[:environment] = "production"
allow(knife).to receive(:upload).and_raise(Chef::Exceptions::CookbookFrozen)
diff --git a/spec/unit/knife/core/bootstrap_context_spec.rb b/spec/unit/knife/core/bootstrap_context_spec.rb
index 4d69d6300a..3a32155063 100644
--- a/spec/unit/knife/core/bootstrap_context_spec.rb
+++ b/spec/unit/knife/core/bootstrap_context_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,25 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/knife/core/bootstrap_context'
+require "spec_helper"
+require "chef/knife/core/bootstrap_context"
describe Chef::Knife::Core::BootstrapContext do
- let(:config) { {:foo => :bar} }
- let(:run_list) { Chef::RunList.new('recipe[tmux]', 'role[base]') }
+ before do
+ # This is required because the chef-fips pipeline does
+ # has a default value of true for fips
+ Chef::Config[:fips] = false
+ end
+
+ let(:config) { { :foo => :bar, :color => true } }
+ let(:run_list) { Chef::RunList.new("recipe[tmux]", "role[base]") }
let(:chef_config) do
{
- :validation_key => File.join(CHEF_SPEC_DATA, 'ssl', 'private_key.pem'),
- :chef_server_url => 'http://chef.example.com:4444',
- :validation_client_name => 'chef-validator-testing'
+ :config_log_level => "info",
+ :config_log_location => "/tmp/log",
+ :validation_key => File.join(CHEF_SPEC_DATA, "ssl", "private_key.pem"),
+ :chef_server_url => "http://chef.example.com:4444",
+ :validation_client_name => "chef-validator-testing",
}
end
@@ -35,7 +43,7 @@ describe Chef::Knife::Core::BootstrapContext do
subject(:bootstrap_context) { described_class.new(config, run_list, chef_config, secret) }
it "initializes with Chef 11 parameters" do
- expect{described_class.new(config, run_list, chef_config)}.not_to raise_error
+ expect { described_class.new(config, run_list, chef_config) }.not_to raise_error
end
it "runs chef with the first-boot.json with no environment specified" do
@@ -43,77 +51,81 @@ describe Chef::Knife::Core::BootstrapContext do
end
describe "when in verbosity mode" do
- let(:config) { {:verbosity => 2} }
+ let(:config) { { :verbosity => 2, :color => true } }
it "adds '-l debug' when verbosity is >= 2" do
expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json -l debug"
end
end
+ describe "when no color value has been set in config" do
+ let(:config) { { :color => false } }
+ it "adds '--no-color' when color is false" do
+ expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json --no-color"
+ end
+ end
+
it "reads the validation key" do
- expect(bootstrap_context.validation_key).to eq IO.read(File.join(CHEF_SPEC_DATA, 'ssl', 'private_key.pem'))
+ expect(bootstrap_context.validation_key).to eq IO.read(File.join(CHEF_SPEC_DATA, "ssl", "private_key.pem"))
end
it "generates the config file data" do
- expected=<<-EXPECTED
-log_location STDOUT
+ expected = <<-EXPECTED
chef_server_url "http://chef.example.com:4444"
validation_client_name "chef-validator-testing"
+log_level :info
+log_location "/tmp/log"
# Using default node name (fqdn)
EXPECTED
expect(bootstrap_context.config_content).to eq expected
end
- it "does not set a default log_level" do
- expect(bootstrap_context.config_content).not_to match(/log_level/)
- end
-
describe "alternate chef-client path" do
- let(:chef_config){ {:chef_client_path => '/usr/local/bin/chef-client'} }
+ let(:chef_config) { { :chef_client_path => "/usr/local/bin/chef-client" } }
it "runs chef-client from another path when specified" do
expect(bootstrap_context.start_chef).to eq "/usr/local/bin/chef-client -j /etc/chef/first-boot.json"
end
end
describe "validation key path that contains a ~" do
- let(:chef_config){ {:validation_key => '~/my.key'} }
+ let(:chef_config) { { :validation_key => "~/my.key" } }
it "reads the validation key when it contains a ~" do
- expect(File).to receive(:exist?).with(File.expand_path("my.key", ENV['HOME'])).and_return(true)
- expect(IO).to receive(:read).with(File.expand_path("my.key", ENV['HOME']))
+ expect(File).to receive(:exist?).with(File.expand_path("my.key", ENV["HOME"])).and_return(true)
+ expect(IO).to receive(:read).with(File.expand_path("my.key", ENV["HOME"]))
bootstrap_context.validation_key
end
end
describe "when an explicit node name is given" do
- let(:config){ {:chef_node_name => 'foobar.example.com' }}
+ let(:config) { { :chef_node_name => "foobar.example.com" } }
it "sets the node name in the client.rb" do
expect(bootstrap_context.config_content).to match(/node_name "foobar\.example\.com"/)
end
end
describe "when bootstrapping into a specific environment" do
- let(:config){ {:environment => "prodtastic"} }
+ let(:config) { { :environment => "prodtastic", :color => true } }
it "starts chef in the configured environment" do
- expect(bootstrap_context.start_chef).to eq('chef-client -j /etc/chef/first-boot.json -E prodtastic')
+ expect(bootstrap_context.start_chef).to eq("chef-client -j /etc/chef/first-boot.json -E prodtastic")
end
end
describe "when tags are given" do
- let(:config) { {:tags => [ "unicorn" ] } }
+ let(:config) { { :tags => [ "unicorn" ] } }
it "adds the attributes to first_boot" do
- expect(Chef::JSONCompat.to_json(bootstrap_context.first_boot)).to eq(Chef::JSONCompat.to_json({:run_list => run_list, :tags => ["unicorn"]}))
+ expect(Chef::JSONCompat.to_json(bootstrap_context.first_boot)).to eq(Chef::JSONCompat.to_json({ :run_list => run_list, :tags => ["unicorn"] }))
end
end
describe "when JSON attributes are given" do
- let(:config) { {:first_boot_attributes => {:baz => :quux}} }
+ let(:config) { { :first_boot_attributes => { :baz => :quux } } }
it "adds the attributes to first_boot" do
- expect(Chef::JSONCompat.to_json(bootstrap_context.first_boot)).to eq(Chef::JSONCompat.to_json({:baz => :quux, :run_list => run_list}))
+ expect(Chef::JSONCompat.to_json(bootstrap_context.first_boot)).to eq(Chef::JSONCompat.to_json({ :baz => :quux, :run_list => run_list }))
end
end
describe "when JSON attributes are NOT given" do
it "sets first_boot equal to run_list" do
- expect(Chef::JSONCompat.to_json(bootstrap_context.first_boot)).to eq(Chef::JSONCompat.to_json({:run_list => run_list}))
+ expect(Chef::JSONCompat.to_json(bootstrap_context.first_boot)).to eq(Chef::JSONCompat.to_json({ :run_list => run_list }))
end
end
@@ -147,7 +159,7 @@ EXPECTED
describe "when a bootstrap_version is specified" do
let(:chef_config) do
{
- :knife => {:bootstrap_version => "11.12.4" }
+ :knife => { :bootstrap_version => "11.12.4" },
}
end
@@ -159,7 +171,7 @@ EXPECTED
describe "when a pre-release bootstrap_version is specified" do
let(:chef_config) do
{
- :knife => {:bootstrap_version => "11.12.4.rc.0" }
+ :knife => { :bootstrap_version => "11.12.4.rc.0" },
}
end
@@ -183,7 +195,7 @@ EXPECTED
describe "when configured in config" do
let(:chef_config) do
{
- :knife => {:ssl_verify_mode => :verify_peer}
+ :knife => { :ssl_verify_mode => :verify_peer },
}
end
@@ -192,7 +204,7 @@ EXPECTED
end
describe "when configured via CLI" do
- let(:config) {{:node_ssl_verify_mode => "none"}}
+ let(:config) { { :node_ssl_verify_mode => "none" } }
it "uses CLI value" do
expect(bootstrap_context.config_content).to include("ssl_verify_mode :verify_none")
@@ -201,6 +213,23 @@ EXPECTED
end
end
+ describe "fips mode" do
+ before do
+ Chef::Config[:fips] = true
+ end
+
+ it "adds the chef version check" do
+ expect(bootstrap_context.config_content).to include <<-CONFIG.gsub(/^ {8}/, "")
+ fips true
+ require "chef/version"
+ chef_version = ::Chef::VERSION.split(".")
+ unless chef_version[0].to_i > 12 || (chef_version[0].to_i == 12 && chef_version[1].to_i >= 8)
+ raise "FIPS Mode requested but not supported by this client"
+ end
+ CONFIG
+ end
+ end
+
describe "verify_api_cert" do
it "isn't set in the config_content by default" do
expect(bootstrap_context.config_content).not_to include("verify_api_cert")
@@ -209,7 +238,7 @@ EXPECTED
describe "when configured in config" do
let(:chef_config) do
{
- :knife => {:verify_api_cert => :false}
+ :knife => { :verify_api_cert => :false },
}
end
@@ -218,7 +247,7 @@ EXPECTED
end
describe "when configured via CLI" do
- let(:config) {{:node_verify_api_cert => true}}
+ let(:config) { { :node_verify_api_cert => true } }
it "uses CLI value" do
expect(bootstrap_context.config_content).to include("verify_api_cert true")
@@ -233,7 +262,7 @@ EXPECTED
end
describe "when configured via cli" do
- let(:config) {{:prerelease => true}}
+ let(:config) { { :prerelease => true } }
it "uses CLI value" do
expect(bootstrap_context.latest_current_chef_version_string).to eq("-p")
@@ -241,4 +270,55 @@ EXPECTED
end
end
+ describe "#config_log_location" do
+ context "when config_log_location is nil" do
+ let(:chef_config) { { :config_log_location => nil } }
+ it "sets the default config_log_location in the client.rb" do
+ expect(bootstrap_context.get_log_location).to eq "STDOUT"
+ end
+ end
+
+ context "when config_log_location is empty" do
+ let(:chef_config) { { :config_log_location => "" } }
+ it "sets the default config_log_location in the client.rb" do
+ expect(bootstrap_context.get_log_location).to eq "STDOUT"
+ end
+ end
+
+ context "when config_log_location is :win_evt" do
+ let(:chef_config) { { :config_log_location => :win_evt } }
+ it "raise error when config_log_location is :win_evt " do
+ expect { bootstrap_context.get_log_location }.to raise_error("The value :win_evt is not supported for config_log_location on Linux Platforms \n")
+ end
+ end
+
+ context "when config_log_location is :syslog" do
+ let(:chef_config) { { :config_log_location => :syslog } }
+ it "sets the config_log_location value as :syslog in the client.rb" do
+ expect(bootstrap_context.get_log_location).to eq ":syslog"
+ end
+ end
+
+ context "When config_log_location is STDOUT" do
+ let(:chef_config) { { :config_log_location => STDOUT } }
+ it "Sets the config_log_location value as STDOUT in the client.rb" do
+ expect(bootstrap_context.get_log_location).to eq "STDOUT"
+ end
+ end
+
+ context "when config_log_location is STDERR" do
+ let(:chef_config) { { :config_log_location => STDERR } }
+ it "sets the config_log_location value as STDERR in the client.rb" do
+ expect(bootstrap_context.get_log_location).to eq "STDERR"
+ end
+ end
+
+ context "when config_log_location is a path" do
+ let(:chef_config) { { :config_log_location => "/tmp/ChefLogFile" } }
+ it "sets the config_log_location path in the client.rb" do
+ expect(bootstrap_context.get_log_location).to eq "\"/tmp/ChefLogFile\""
+ end
+ end
+
+ end
end
diff --git a/spec/unit/knife/core/cookbook_scm_repo_spec.rb b/spec/unit/knife/core/cookbook_scm_repo_spec.rb
index 2d66df31c1..137bdddafb 100644
--- a/spec/unit/knife/core/cookbook_scm_repo_spec.rb
+++ b/spec/unit/knife/core/cookbook_scm_repo_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/knife/core/cookbook_scm_repo'
+require "spec_helper"
+require "chef/knife/core/cookbook_scm_repo"
describe Chef::Knife::CookbookSCMRepo do
before do
- @repo_path = File.join(CHEF_SPEC_DATA, 'cookbooks')
+ @repo_path = File.join(CHEF_SPEC_DATA, "cookbooks")
@stdout, @stderr, @stdin = StringIO.new, StringIO.new, StringIO.new
@ui = Chef::Knife::UI.new(@stdout, @stderr, @stdin, {})
- @cookbook_repo = Chef::Knife::CookbookSCMRepo.new(@repo_path, @ui, :default_branch => 'master')
+ @cookbook_repo = Chef::Knife::CookbookSCMRepo.new(@repo_path, @ui, :default_branch => "master")
@branch_list = Mixlib::ShellOut.new
@branch_list.stdout.replace(<<-BRANCHES)
@@ -43,13 +43,13 @@ BRANCHES
end
it "has a default branch" do
- expect(@cookbook_repo.default_branch).to eq('master')
+ expect(@cookbook_repo.default_branch).to eq("master")
end
describe "when sanity checking the repo" do
it "exits when the directory does not exist" do
expect(::File).to receive(:directory?).with(@repo_path).and_return(false)
- expect {@cookbook_repo.sanity_check}.to raise_error(SystemExit)
+ expect { @cookbook_repo.sanity_check }.to raise_error(SystemExit)
end
describe "and the repo dir exists" do
@@ -59,18 +59,18 @@ BRANCHES
it "exits when there is no git repo" do
allow(::File).to receive(:directory?).with(/.*\.git/).and_return(false)
- expect {@cookbook_repo.sanity_check}.to raise_error(SystemExit)
+ expect { @cookbook_repo.sanity_check }.to raise_error(SystemExit)
end
describe "and the repo is a git repo" do
before do
- allow(::File).to receive(:directory?).with(File.join(@repo_path, '.git')).and_return(true)
+ allow(::File).to receive(:directory?).with(File.join(@repo_path, ".git")).and_return(true)
end
it "exits when the default branch doesn't exist" do
- @nobranches = Mixlib::ShellOut.new.tap {|s|s.stdout.replace "\n"}
- expect(@cookbook_repo).to receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@nobranches)
- expect {@cookbook_repo.sanity_check}.to raise_error(SystemExit)
+ @nobranches = Mixlib::ShellOut.new.tap { |s| s.stdout.replace "\n" }
+ expect(@cookbook_repo).to receive(:shell_out!).with("git branch --no-color", :cwd => @repo_path).and_return(@nobranches)
+ expect { @cookbook_repo.sanity_check }.to raise_error(SystemExit)
end
describe "and the default branch exists" do
@@ -85,14 +85,14 @@ BRANCHES
@dirty_status.stdout.replace(<<-DIRTY)
M chef/lib/chef/knife/cookbook_site_vendor.rb
DIRTY
- expect(@cookbook_repo).to receive(:shell_out!).with('git status --porcelain', :cwd => @repo_path).and_return(@dirty_status)
- expect {@cookbook_repo.sanity_check}.to raise_error(SystemExit)
+ expect(@cookbook_repo).to receive(:shell_out!).with("git status --porcelain", :cwd => @repo_path).and_return(@dirty_status)
+ expect { @cookbook_repo.sanity_check }.to raise_error(SystemExit)
end
describe "and the repo is clean" do
before do
- @clean_status = Mixlib::ShellOut.new.tap {|s| s.stdout.replace("\n")}
- allow(@cookbook_repo).to receive(:shell_out!).with('git status --porcelain', :cwd => @repo_path).and_return(@clean_status)
+ @clean_status = Mixlib::ShellOut.new.tap { |s| s.stdout.replace("\n") }
+ allow(@cookbook_repo).to receive(:shell_out!).with("git status --porcelain", :cwd => @repo_path).and_return(@clean_status)
end
it "passes the sanity check" do
@@ -106,35 +106,35 @@ DIRTY
end
it "resets to default state by checking out the default branch" do
- expect(@cookbook_repo).to receive(:shell_out!).with('git checkout master', :cwd => @repo_path)
+ expect(@cookbook_repo).to receive(:shell_out!).with("git checkout master", :cwd => @repo_path)
@cookbook_repo.reset_to_default_state
end
it "determines if a the pristine copy branch exists" do
- expect(@cookbook_repo).to receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list)
+ expect(@cookbook_repo).to receive(:shell_out!).with("git branch --no-color", :cwd => @repo_path).and_return(@branch_list)
expect(@cookbook_repo.branch_exists?("chef-vendor-apache2")).to be_truthy
- expect(@cookbook_repo).to receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list)
+ expect(@cookbook_repo).to receive(:shell_out!).with("git branch --no-color", :cwd => @repo_path).and_return(@branch_list)
expect(@cookbook_repo.branch_exists?("chef-vendor-nginx")).to be_falsey
end
it "determines if a the branch not exists correctly without substring search" do
- expect(@cookbook_repo).to receive(:shell_out!).twice.with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list)
+ expect(@cookbook_repo).to receive(:shell_out!).twice.with("git branch --no-color", :cwd => @repo_path).and_return(@branch_list)
expect(@cookbook_repo).not_to be_branch_exists("chef-vendor-absent")
expect(@cookbook_repo).to be_branch_exists("chef-vendor-absent-new")
end
describe "when the pristine copy branch does not exist" do
it "prepares for import by creating the pristine copy branch" do
- expect(@cookbook_repo).to receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list)
- expect(@cookbook_repo).to receive(:shell_out!).with('git checkout -b chef-vendor-nginx', :cwd => @repo_path)
+ expect(@cookbook_repo).to receive(:shell_out!).with("git branch --no-color", :cwd => @repo_path).and_return(@branch_list)
+ expect(@cookbook_repo).to receive(:shell_out!).with("git checkout -b chef-vendor-nginx", :cwd => @repo_path)
@cookbook_repo.prepare_to_import("nginx")
end
end
describe "when the pristine copy branch does exist" do
it "prepares for import by checking out the pristine copy branch" do
- expect(@cookbook_repo).to receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list)
- expect(@cookbook_repo).to receive(:shell_out!).with('git checkout chef-vendor-apache2', :cwd => @repo_path)
+ expect(@cookbook_repo).to receive(:shell_out!).with("git branch --no-color", :cwd => @repo_path).and_return(@branch_list)
+ expect(@cookbook_repo).to receive(:shell_out!).with("git checkout chef-vendor-apache2", :cwd => @repo_path)
@cookbook_repo.prepare_to_import("apache2")
end
end
@@ -143,15 +143,15 @@ DIRTY
before do
@updates = Mixlib::ShellOut.new
@updates.stdout.replace("\n")
- allow(@cookbook_repo).to receive(:shell_out!).with('git status --porcelain -- apache2', :cwd => @repo_path).and_return(@updates)
+ allow(@cookbook_repo).to receive(:shell_out!).with("git status --porcelain -- apache2", :cwd => @repo_path).and_return(@updates)
end
it "shows no changes in the pristine copy" do
- expect(@cookbook_repo.updated?('apache2')).to be_falsey
+ expect(@cookbook_repo.updated?("apache2")).to be_falsey
end
it "does nothing to finalize the updates" do
- expect(@cookbook_repo.finalize_updates_to('apache2', '1.2.3')).to be_falsey
+ expect(@cookbook_repo.finalize_updates_to("apache2", "1.2.3")).to be_falsey
end
end
@@ -159,11 +159,11 @@ DIRTY
before do
@updates = Mixlib::ShellOut.new
@updates.stdout.replace(" M cookbooks/apache2/recipes/default.rb\n")
- allow(@cookbook_repo).to receive(:shell_out!).with('git status --porcelain -- apache2', :cwd => @repo_path).and_return(@updates)
+ allow(@cookbook_repo).to receive(:shell_out!).with("git status --porcelain -- apache2", :cwd => @repo_path).and_return(@updates)
end
it "shows changes in the pristine copy" do
- expect(@cookbook_repo.updated?('apache2')).to be_truthy
+ expect(@cookbook_repo.updated?("apache2")).to be_truthy
end
it "commits the changes to the repo and tags the commit" do
@@ -176,11 +176,11 @@ DIRTY
describe "when a custom default branch is specified" do
before do
- @cookbook_repo = Chef::Knife::CookbookSCMRepo.new(@repo_path, @ui, :default_branch => 'develop')
+ @cookbook_repo = Chef::Knife::CookbookSCMRepo.new(@repo_path, @ui, :default_branch => "develop")
end
it "resets to default state by checking out the default branch" do
- expect(@cookbook_repo).to receive(:shell_out!).with('git checkout develop', :cwd => @repo_path)
+ expect(@cookbook_repo).to receive(:shell_out!).with("git checkout develop", :cwd => @repo_path)
@cookbook_repo.reset_to_default_state
end
end
diff --git a/spec/unit/knife/core/custom_manifest_loader_spec.rb b/spec/unit/knife/core/custom_manifest_loader_spec.rb
index 1edbedd3c8..814ac8a027 100644
--- a/spec/unit/knife/core/custom_manifest_loader_spec.rb
+++ b/spec/unit/knife/core/custom_manifest_loader_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::SubcommandLoader::CustomManifestLoader do
let(:ec2_server_create_plugin) { "/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_server_create.rb" }
@@ -23,14 +23,14 @@ describe Chef::Knife::SubcommandLoader::CustomManifestLoader do
{ "plugins" => {
"knife-ec2" => {
"paths" => [
- ec2_server_create_plugin
- ]
- }
- }
+ ec2_server_create_plugin,
+ ],
+ },
+ },
}
end
let(:loader) do
- Chef::Knife::SubcommandLoader::CustomManifestLoader.new(File.join(CHEF_SPEC_DATA, 'knife-site-subcommands'),
+ Chef::Knife::SubcommandLoader::CustomManifestLoader.new(File.join(CHEF_SPEC_DATA, "knife-site-subcommands"),
manifest_content)
end
diff --git a/spec/unit/knife/core/gem_glob_loader_spec.rb b/spec/unit/knife/core/gem_glob_loader_spec.rb
index 465eea2656..2f9e04769e 100644
--- a/spec/unit/knife/core/gem_glob_loader_spec.rb
+++ b/spec/unit/knife/core/gem_glob_loader_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,17 +15,17 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::SubcommandLoader::GemGlobLoader do
- let(:loader) { Chef::Knife::SubcommandLoader::GemGlobLoader.new(File.join(CHEF_SPEC_DATA, 'knife-site-subcommands')) }
- let(:home) { File.join(CHEF_SPEC_DATA, 'knife-home') }
- let(:plugin_dir) { File.join(home, '.chef', 'plugins', 'knife') }
+ let(:loader) { Chef::Knife::SubcommandLoader::GemGlobLoader.new(File.join(CHEF_SPEC_DATA, "knife-site-subcommands")) }
+ let(:home) { File.join(CHEF_SPEC_DATA, "knife-home") }
+ let(:plugin_dir) { File.join(home, ".chef", "plugins", "knife") }
- before do
- allow(ChefConfig).to receive(:windows?) { false }
- Chef::Util::PathHelper.class_variable_set(:@@home_dir, home)
- end
+ before do
+ allow(ChefConfig).to receive(:windows?) { false }
+ Chef::Util::PathHelper.class_variable_set(:@@home_dir, home)
+ end
after do
Chef::Util::PathHelper.class_variable_set(:@@home_dir, nil)
@@ -39,15 +39,15 @@ describe Chef::Knife::SubcommandLoader::GemGlobLoader do
end
it "finds files installed via rubygems" do
- expect(loader.find_subcommands_via_rubygems).to include('chef/knife/node_create')
- loader.find_subcommands_via_rubygems.each {|rel_path, abs_path| expect(abs_path).to match(%r[chef/knife/.+])}
+ expect(loader.find_subcommands_via_rubygems).to include("chef/knife/node_create")
+ loader.find_subcommands_via_rubygems.each { |rel_path, abs_path| expect(abs_path).to match(%r{chef/knife/.+}) }
end
it "finds files from latest version of installed gems" do
- gems = [ double('knife-ec2-0.5.12') ]
+ gems = [ double("knife-ec2-0.5.12") ]
gem_files = [
- '/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_base.rb',
- '/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_otherstuff.rb'
+ "/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_base.rb",
+ "/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_otherstuff.rb",
]
expect($LOAD_PATH).to receive(:map).and_return([])
if Gem::Specification.respond_to? :latest_specs
@@ -55,30 +55,30 @@ describe Chef::Knife::SubcommandLoader::GemGlobLoader do
expect(gems[0]).to receive(:matches_for_glob).with(/chef\/knife\/\*\.rb\{(.*),\.rb,(.*)\}/).and_return(gem_files)
else
expect(Gem.source_index).to receive(:latest_specs).with(true).and_return(gems)
- expect(gems[0]).to receive(:require_paths).twice.and_return(['lib'])
- expect(gems[0]).to receive(:full_gem_path).and_return('/usr/lib/ruby/gems/knife-ec2-0.5.12')
- expect(Dir).to receive(:[]).with('/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/*.rb').and_return(gem_files)
+ expect(gems[0]).to receive(:require_paths).twice.and_return(["lib"])
+ expect(gems[0]).to receive(:full_gem_path).and_return("/usr/lib/ruby/gems/knife-ec2-0.5.12")
+ expect(Dir).to receive(:[]).with("/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/*.rb").and_return(gem_files)
end
expect(loader).to receive(:find_subcommands_via_dirglob).and_return({})
expect(loader.subcommand_files.select { |file| file =~ /knife-ec2/ }.sort).to eq(gem_files)
end
it "finds files using a dirglob when rubygems is not available" do
- expect(loader.find_subcommands_via_dirglob).to include('chef/knife/node_create')
- loader.find_subcommands_via_dirglob.each {|rel_path, abs_path| expect(abs_path).to match(%r[chef/knife/.+])}
+ expect(loader.find_subcommands_via_dirglob).to include("chef/knife/node_create")
+ loader.find_subcommands_via_dirglob.each { |rel_path, abs_path| expect(abs_path).to match(%r{chef/knife/.+}) }
end
it "finds user-specific subcommands in the user's ~/.chef directory" do
- expected_command = File.join(home, '.chef', 'plugins', 'knife', 'example_home_subcommand.rb')
+ expected_command = File.join(home, ".chef", "plugins", "knife", "example_home_subcommand.rb")
expect(loader.site_subcommands).to include(expected_command)
end
it "finds repo specific subcommands by searching for a .chef directory" do
- expected_command = File.join(CHEF_SPEC_DATA, 'knife-site-subcommands', 'plugins', 'knife', 'example_subcommand.rb')
+ expected_command = File.join(CHEF_SPEC_DATA, "knife-site-subcommands", "plugins", "knife", "example_subcommand.rb")
expect(loader.site_subcommands).to include(expected_command)
end
- # https://github.com/opscode/chef-dk/issues/227
+ # https://github.com/chef/chef-dk/issues/227
#
# `knife` in ChefDK isn't from a gem install, it's directly run from a clone
# of the source, but there can be one or more versions of chef also installed
@@ -135,7 +135,7 @@ describe Chef::Knife::SubcommandLoader::GemGlobLoader do
# `SubcommandLoader::MATCHES_CHEF_GEM` should make it clear why we want
# to test these two cases.
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-bar-1.0.0/lib/chef/knife/chef-bar.rb",
- "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/bar-chef-1.0.0/lib/chef/knife/bar-chef.rb"
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/bar-chef-1.0.0/lib/chef/knife/bar-chef.rb",
]
end
@@ -153,7 +153,7 @@ describe Chef::Knife::SubcommandLoader::GemGlobLoader do
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-foo-#{Chef::VERSION}/lib/chef/knife/chef-foo.rb",
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/foo-chef-#{Chef::VERSION}/lib/chef/knife/foo-chef.rb",
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-bar-1.0.0/lib/chef/knife/chef-bar.rb",
- "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/bar-chef-1.0.0/lib/chef/knife/bar-chef.rb"
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/bar-chef-1.0.0/lib/chef/knife/bar-chef.rb",
]
end
@@ -178,7 +178,6 @@ describe Chef::Knife::SubcommandLoader::GemGlobLoader do
allow(ENV).to receive(:[]).with("HOME").and_return(env_home)
end
-
it "searches rubygems for plugins" do
if Gem::Specification.respond_to?(:latest_specs)
expect(Gem::Specification).to receive(:latest_specs).and_call_original
diff --git a/spec/unit/knife/core/hashed_command_loader_spec.rb b/spec/unit/knife/core/hashed_command_loader_spec.rb
index 00e7ba377b..53bd81f4f7 100644
--- a/spec/unit/knife/core/hashed_command_loader_spec.rb
+++ b/spec/unit/knife/core/hashed_command_loader_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,43 +15,60 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::SubcommandLoader::HashedCommandLoader do
before do
allow(ChefConfig).to receive(:windows?) { false }
end
- let(:plugin_manifest) {
+ let(:plugin_manifest) do
{
"_autogenerated_command_paths" => {
"plugins_paths" => {
"cool_a" => ["/file/for/plugin/a"],
- "cooler_b" => ["/file/for/plugin/b"]
+ "cooler_b" => ["/file/for/plugin/b"],
},
"plugins_by_category" => {
"cool" => [
- "cool_a"
+ "cool_a",
],
"cooler" => [
- "cooler_b"
- ]
- }
- }
+ "cooler_b",
+ ],
+ },
+ },
}
- }
+ end
- let(:loader) { Chef::Knife::SubcommandLoader::HashedCommandLoader.new(
- File.join(CHEF_SPEC_DATA, 'knife-site-subcommands'),
- plugin_manifest)}
+ let(:loader) do
+ Chef::Knife::SubcommandLoader::HashedCommandLoader.new(
+ File.join(CHEF_SPEC_DATA, "knife-site-subcommands"),
+ plugin_manifest) end
describe "#list_commands" do
+ before do
+ allow(File).to receive(:exists?).and_return(true)
+ end
+
it "lists all commands by category when no argument is given" do
- expect(loader.list_commands).to eq({"cool" => ["cool_a"], "cooler" => ["cooler_b"]})
+ expect(loader.list_commands).to eq({ "cool" => ["cool_a"], "cooler" => ["cooler_b"] })
end
it "lists only commands in the given category when a category is given" do
- expect(loader.list_commands("cool")).to eq({"cool" => ["cool_a"]})
+ expect(loader.list_commands("cool")).to eq({ "cool" => ["cool_a"] })
+ end
+
+ context "when the plugin path is invalid" do
+ before do
+ expect(File).to receive(:exists?).with("/file/for/plugin/b").and_return(false)
+ end
+
+ it "lists all commands by category when no argument is given" do
+ expect(Chef::Log).to receive(:error).with(/There are files specified in the manifest that are missing/)
+ expect(Chef::Log).to receive(:error).with("Missing files:\n\t/file/for/plugin/b")
+ expect(loader.list_commands).to eq({})
+ end
end
end
@@ -83,7 +100,7 @@ describe Chef::Knife::SubcommandLoader::HashedCommandLoader do
end
it "finds the right subcommand even when _'s are elided" do
- expect(loader.subcommand_for_args(["cooler", "b"])).to eq("cooler_b")
+ expect(loader.subcommand_for_args(%w{cooler b})).to eq("cooler_b")
end
it "returns nil if the the subcommand isn't in our manifest" do
diff --git a/spec/unit/knife/core/node_editor_spec.rb b/spec/unit/knife/core/node_editor_spec.rb
new file mode 100644
index 0000000000..ce169a77dd
--- /dev/null
+++ b/spec/unit/knife/core/node_editor_spec.rb
@@ -0,0 +1,211 @@
+#
+# Author:: Jordan Running (<jr@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/knife/core/node_editor"
+
+describe Chef::Knife::NodeEditor do
+ let(:node_data) do
+ { "name" => "test_node",
+ "chef_environment" => "production",
+ "automatic" => { "foo" => "bar" },
+ "default" => { "alpha" => { "bravo" => "charlie", "delta" => "echo" } },
+ "normal" => { "alpha" => { "bravo" => "hotel" }, "tags" => [] },
+ "override" => { "alpha" => { "bravo" => "foxtrot", "delta" => "golf" } },
+ "policy_name" => nil,
+ "policy_group" => nil,
+ "run_list" => %w{role[comedy] role[drama] recipe[mystery]},
+ }
+ end
+
+ let(:node) { Chef::Node.from_hash(node_data) }
+
+ let(:ui) { double "ui" }
+ let(:base_config) { { editor: "cat" } }
+ let(:config) { base_config.merge(all_attributes: false) }
+
+ subject { described_class.new(node, ui, config) }
+
+ describe "#view" do
+ it "returns a Hash with only the name, chef_environment, normal, " +
+ "policy_name, policy_group, and run_list properties" do
+ expected = node_data.select do |key,|
+ %w{ name chef_environment normal
+ policy_name policy_group run_list }.include?(key)
+ end
+
+ expect(subject.view).to eq(expected)
+ end
+
+ context "when config[:all_attributes] == true" do
+ let(:config) { base_config.merge(all_attributes: true) }
+
+ it 'returns a Hash with all of the node\'s properties' do
+ expect(subject.view).to eq(node_data)
+ end
+ end
+ end
+
+ describe "#apply_updates" do
+ context "when the node name is changed" do
+ before(:each) do
+ allow(ui).to receive(:warn)
+ allow(ui).to receive(:confirm).and_return(true)
+ end
+
+ it "emits a warning and prompts for confirmation" do
+ data = subject.view.merge("name" => "foo_new_name_node")
+ updated_node = subject.apply_updates(data)
+
+ expect(ui).to have_received(:warn)
+ .with "Changing the name of a node results in a new node being " +
+ "created, test_node will not be modified or removed."
+
+ expect(ui).to have_received(:confirm)
+ .with("Proceed with creation of new node")
+
+ expect(updated_node).to be_a(Chef::Node)
+ end
+ end
+
+ context "when config[:all_attributes] == false" do
+ let(:config) { base_config.merge(all_attributes: false) }
+
+ let(:updated_data) do
+ subject.view.merge(
+ "normal" => { "alpha" => { "bravo" => "hotel2" }, "tags" => [ "xyz" ] },
+ "policy_name" => "mypolicy",
+ "policy_group" => "prod",
+ "run_list" => %w{role[drama] recipe[mystery]}
+ )
+ end
+
+ it "returns a node with run_list and normal_attrs changed" do
+ updated_node = subject.apply_updates(updated_data)
+ expect(updated_node).to be_a(Chef::Node)
+
+ # Expected to have been changed
+ expect(updated_node.chef_environment).to eql(updated_data["chef_environment"])
+ expect(updated_node.normal_attrs).to eql(updated_data["normal"])
+ expect(updated_node.policy_name).to eql(updated_data["policy_name"])
+ expect(updated_node.policy_group).to eql(updated_data["policy_group"])
+ expect(updated_node.run_list.map(&:to_s)).to eql(updated_data["run_list"])
+
+ # Expected not to have changed
+ expect(updated_node.default_attrs).to eql(node.default_attrs)
+ expect(updated_node.override_attrs).to eql(node.override_attrs)
+ expect(updated_node.automatic_attrs).to eql(node.automatic_attrs)
+ end
+ end
+
+ context "when config[:all_attributes] == true" do
+ let(:config) { base_config.merge(all_attributes: true) }
+
+ let(:updated_data) do
+ subject.view.merge(
+ "default" => { "alpha" => { "bravo" => "charlie2", "delta" => "echo2" } },
+ "normal" => { "alpha" => { "bravo" => "hotel2" }, "tags" => [ "xyz" ] },
+ "override" => { "alpha" => { "bravo" => "foxtrot2", "delta" => "golf2" } },
+ "policy_name" => "mypolicy",
+ "policy_group" => "prod",
+ "run_list" => %w{role[drama] recipe[mystery]}
+ )
+ end
+
+ it "returns a node with all editable properties changed" do
+ updated_node = subject.apply_updates(updated_data)
+ expect(updated_node).to be_a(Chef::Node)
+
+ expect(updated_node.chef_environment).to eql(updated_data["chef_environment"])
+ expect(updated_node.automatic_attrs).to eql(updated_data["automatic"])
+ expect(updated_node.normal_attrs).to eql(updated_data["normal"])
+ expect(updated_node.default_attrs).to eql(updated_data["default"])
+ expect(updated_node.override_attrs).to eql(updated_data["override"])
+ expect(updated_node.policy_name).to eql(updated_data["policy_name"])
+ expect(updated_node.policy_group).to eql(updated_data["policy_group"])
+ expect(updated_node.run_list.map(&:to_s)).to eql(updated_data["run_list"])
+ end
+ end
+ end
+
+ describe "#updated?" do
+ context "before the node has been edited" do
+ it "returns false" do
+ expect(subject.updated?).to be false
+ end
+ end
+
+ context "after the node has been edited" do
+ context "and changes were made" do
+ let(:updated_data) do
+ subject.view.merge(
+ "default" => { "alpha" => { "bravo" => "charlie2", "delta" => "echo2" } },
+ "normal" => { "alpha" => { "bravo" => "hotel2" }, "tags" => [ "xyz" ] },
+ "override" => { "alpha" => { "bravo" => "foxtrot2", "delta" => "golf2" } },
+ "policy_name" => "mypolicy",
+ "policy_group" => "prod",
+ "run_list" => %w{role[drama] recipe[mystery]}
+ )
+ end
+
+ context "and changes affect only editable properties" do
+ before(:each) do
+ allow(ui).to receive(:edit_hash)
+ .with(subject.view)
+ .and_return(updated_data)
+
+ subject.edit_node
+ end
+
+ it "returns an array of the changed property names" do
+ expect(subject.updated?).to eql %w{ normal policy_name policy_group run_list }
+ end
+ end
+
+ context "and the changes include non-editable properties" do
+ before(:each) do
+ data = updated_data.merge("bad_property" => "bad_value")
+
+ allow(ui).to receive(:edit_hash)
+ .with(subject.view)
+ .and_return(data)
+
+ subject.edit_node
+ end
+
+ it 'returns an array of property names that doesn\'t include ' +
+ "the non-editable properties" do
+ expect(subject.updated?).to eql %w{ normal policy_name policy_group run_list }
+ end
+ end
+ end
+
+ context "and changes were not made" do
+ before(:each) do
+ allow(ui).to receive(:edit_hash)
+ .with(subject.view)
+ .and_return(subject.view.dup)
+
+ subject.edit_node
+ end
+
+ it { is_expected.not_to be_updated }
+ end
+ end
+ end
+end
diff --git a/spec/unit/knife/core/object_loader_spec.rb b/spec/unit/knife/core/object_loader_spec.rb
index 67fa858029..9cabf2ba63 100644
--- a/spec/unit/knife/core/object_loader_spec.rb
+++ b/spec/unit/knife/core/object_loader_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
# Author:: Juanje Ojeda (<juanje.ojeda@gmail.com>)
-# Copyright:: Copyright (c) 2011-2012 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/knife/core/object_loader'
+require "spec_helper"
+require "chef/knife/core/object_loader"
describe Chef::Knife::Core::ObjectLoader do
before(:each) do
@knife = Chef::Knife.new
@stdout = StringIO.new
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
- Dir.chdir(File.join(CHEF_SPEC_DATA, 'object_loader'))
+ Dir.chdir(File.join(CHEF_SPEC_DATA, "object_loader"))
end
shared_examples_for "Chef object" do |chef_class|
@@ -34,14 +34,14 @@ describe Chef::Knife::Core::ObjectLoader do
end
it "should has a attribute 'name'" do
- expect(@object.name).to eql('test')
+ expect(@object.name).to eql("test")
end
end
{
- 'nodes' => Chef::Node,
- 'roles' => Chef::Role,
- 'environments' => Chef::Environment
+ "nodes" => Chef::Node,
+ "roles" => Chef::Role,
+ "environments" => Chef::Environment,
}.each do |repo_location, chef_class|
describe "when the file is a #{chef_class}" do
@@ -51,7 +51,7 @@ describe Chef::Knife::Core::ObjectLoader do
describe "when the file is a Ruby" do
before do
- @object = @loader.load_from(repo_location, 'test.rb')
+ @object = @loader.load_from(repo_location, "test.rb")
end
it_behaves_like "Chef object", chef_class
@@ -61,7 +61,7 @@ describe Chef::Knife::Core::ObjectLoader do
describe "when the file is a JSON" do
describe "and it has defined 'json_class'" do
before do
- @object = @loader.load_from(repo_location, 'test_json_class.json')
+ @object = @loader.load_from(repo_location, "test_json_class.json")
end
it_behaves_like "Chef object", chef_class
@@ -69,7 +69,7 @@ describe Chef::Knife::Core::ObjectLoader do
describe "and it has not defined 'json_class'" do
before do
- @object = @loader.load_from(repo_location, 'test.json')
+ @object = @loader.load_from(repo_location, "test.json")
end
it_behaves_like "Chef object", chef_class
diff --git a/spec/unit/knife/core/subcommand_loader_spec.rb b/spec/unit/knife/core/subcommand_loader_spec.rb
index 2386465c75..b235102a0b 100644
--- a/spec/unit/knife/core/subcommand_loader_spec.rb
+++ b/spec/unit/knife/core/subcommand_loader_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,12 +15,12 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::SubcommandLoader do
- let(:loader) { Chef::Knife::SubcommandLoader.new(File.join(CHEF_SPEC_DATA, 'knife-site-subcommands')) }
- let(:home) { File.join(CHEF_SPEC_DATA, 'knife-home') }
- let(:plugin_dir) { File.join(home, '.chef', 'plugins', 'knife') }
+ let(:loader) { Chef::Knife::SubcommandLoader.new(File.join(CHEF_SPEC_DATA, "knife-site-subcommands")) }
+ let(:home) { File.join(CHEF_SPEC_DATA, "knife-home") }
+ let(:plugin_dir) { File.join(home, ".chef", "plugins", "knife") }
before do
allow(ChefConfig).to receive(:windows?) { false }
@@ -31,29 +31,29 @@ describe Chef::Knife::SubcommandLoader do
Chef::Util::PathHelper.class_variable_set(:@@home_dir, nil)
end
- let(:config_dir) { File.join(CHEF_SPEC_DATA, 'knife-site-subcommands') }
+ let(:config_dir) { File.join(CHEF_SPEC_DATA, "knife-site-subcommands") }
describe "#for_config" do
context "when ~/.chef/plugin_manifest.json exists" do
before do
- allow(File).to receive(:exist?).with(File.join(home, '.chef', 'plugin_manifest.json')).and_return(true)
+ allow(File).to receive(:exist?).with(File.join(home, ".chef", "plugin_manifest.json")).and_return(true)
end
it "creates a HashedCommandLoader with the manifest has _autogenerated_command_paths" do
- allow(File).to receive(:read).with(File.join(home, '.chef', 'plugin_manifest.json')).and_return("{ \"_autogenerated_command_paths\": {}}")
+ allow(File).to receive(:read).with(File.join(home, ".chef", "plugin_manifest.json")).and_return("{ \"_autogenerated_command_paths\": {}}")
expect(Chef::Knife::SubcommandLoader.for_config(config_dir)).to be_a Chef::Knife::SubcommandLoader::HashedCommandLoader
end
it "creates a CustomManifestLoader with then manifest has a key other than _autogenerated_command_paths" do
Chef::Config[:treat_deprecation_warnings_as_errors] = false
- allow(File).to receive(:read).with(File.join(home, '.chef', 'plugin_manifest.json')).and_return("{ \"plugins\": {}}")
+ allow(File).to receive(:read).with(File.join(home, ".chef", "plugin_manifest.json")).and_return("{ \"plugins\": {}}")
expect(Chef::Knife::SubcommandLoader.for_config(config_dir)).to be_a Chef::Knife::SubcommandLoader::CustomManifestLoader
end
end
context "when ~/.chef/plugin_manifest.json does not exist" do
before do
- allow(File).to receive(:exist?).with(File.join(home, '.chef', 'plugin_manifest.json')).and_return(false)
+ allow(File).to receive(:exist?).with(File.join(home, ".chef", "plugin_manifest.json")).and_return(false)
end
it "creates a GemGlobLoader" do
@@ -61,4 +61,10 @@ describe Chef::Knife::SubcommandLoader do
end
end
end
+
+ describe "#gem_glob_loader" do
+ it "always creates a GemGlobLoader" do
+ expect(Chef::Knife::SubcommandLoader.gem_glob_loader(config_dir)).to be_a Chef::Knife::SubcommandLoader::GemGlobLoader
+ end
+ end
end
diff --git a/spec/unit/knife/core/ui_spec.rb b/spec/unit/knife/core/ui_spec.rb
index ab420518a3..38c72161e5 100644
--- a/spec/unit/knife/core/ui_spec.rb
+++ b/spec/unit/knife/core/ui_spec.rb
@@ -1,9 +1,9 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011, 2012 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::UI do
before do
@@ -28,15 +28,17 @@ describe Chef::Knife::UI do
:verbosity => 0,
:yes => nil,
:format => "summary",
+ :field_separator => ".",
}
@ui = Chef::Knife::UI.new(@out, @err, @in, @config)
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
end
describe "edit" do
- ruby_for_json = { 'foo' => 'bar' }
+ ruby_for_json = { "foo" => "bar" }
json_from_ruby = "{\n \"foo\": \"bar\"\n}"
json_from_editor = "{\n \"bar\": \"foo\"\n}"
- ruby_from_editor = { 'bar' => 'foo' }
+ ruby_from_editor = { "bar" => "foo" }
my_editor = "veeeye"
temp_path = "/tmp/bar/baz"
@@ -46,7 +48,7 @@ describe Chef::Knife::UI do
context "when editing is disabled" do
before do
@ui.config[:disable_editing] = true
- stub_const("Tempfile", double) # Tempfiles should never be invoked
+ stub_const("Tempfile", double) # Tempfiles should never be invoked
end
context "when parse_output is false" do
it "returns pretty json string" do
@@ -58,6 +60,12 @@ describe Chef::Knife::UI do
it "returns a ruby object" do
expect(subject).to eql(ruby_for_json)
end
+
+ it "gives a deprecation error" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = true
+ expect { subject }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+ /Auto inflation of JSON data is deprecated./
+ end
end
end
@@ -66,12 +74,12 @@ describe Chef::Knife::UI do
before do
@ui.config[:disable_editing] = false
@ui.config[:editor] = my_editor
- @mock = double('Tempfile')
+ @mock = double("Tempfile")
expect(@mock).to receive(:sync=).with(true)
expect(@mock).to receive(:puts).with(json_from_ruby)
expect(@mock).to receive(:close)
expect(@mock).to receive(:path).at_least(:once).and_return(temp_path)
- expect(Tempfile).to receive(:open).with([ 'knife-edit-', '.json' ]).and_yield(@mock)
+ expect(Tempfile).to receive(:open).with([ "knife-edit-", ".json" ]).and_yield(@mock)
end
context "and the editor works" do
before do
@@ -97,7 +105,7 @@ describe Chef::Knife::UI do
expect(IO).not_to receive(:read)
end
it "throws an exception" do
- expect{ subject }.to raise_error(RuntimeError)
+ expect { subject }.to raise_error(RuntimeError)
end
end
context "when running the editor fails with false" do
@@ -106,7 +114,7 @@ describe Chef::Knife::UI do
expect(IO).not_to receive(:read)
end
it "throws an exception" do
- expect{ subject }.to raise_error(RuntimeError)
+ expect { subject }.to raise_error(RuntimeError)
end
end
end
@@ -114,8 +122,8 @@ describe Chef::Knife::UI do
before do
@ui.config[:disable_editing] = false
@ui.config[:editor] = my_editor
- @tempfile = Tempfile.new([ 'knife-edit-', '.json' ])
- expect(Tempfile).to receive(:open).with([ 'knife-edit-', '.json' ]).and_yield(@tempfile)
+ @tempfile = Tempfile.new([ "knife-edit-", ".json" ])
+ expect(Tempfile).to receive(:open).with([ "knife-edit-", ".json" ]).and_yield(@tempfile)
end
context "and the editor works" do
@@ -166,20 +174,20 @@ describe Chef::Knife::UI do
it "should throw Errno::EIO exceptions" do
allow(@out).to receive(:puts).and_raise(Errno::EIO)
allow(@err).to receive(:puts).and_raise(Errno::EIO)
- expect {@ui.send(method, "hi")}.to raise_error(Errno::EIO)
+ expect { @ui.send(method, "hi") }.to raise_error(Errno::EIO)
end
it "should ignore Errno::EPIPE exceptions (CHEF-3516)" do
allow(@out).to receive(:puts).and_raise(Errno::EPIPE)
allow(@err).to receive(:puts).and_raise(Errno::EPIPE)
- expect {@ui.send(method, "hi")}.to raise_error(SystemExit)
+ expect { @ui.send(method, "hi") }.to raise_error(SystemExit)
end
it "should throw Errno::EPIPE exceptions with -VV (CHEF-3516)" do
@config[:verbosity] = 2
allow(@out).to receive(:puts).and_raise(Errno::EPIPE)
allow(@err).to receive(:puts).and_raise(Errno::EPIPE)
- expect {@ui.send(method, "hi")}.to raise_error(Errno::EPIPE)
+ expect { @ui.send(method, "hi") }.to raise_error(Errno::EPIPE)
end
end
@@ -192,7 +200,7 @@ describe Chef::Knife::UI do
end
it "formats hashes appropriately" do
- @ui.output({'hi' => 'a', 'lo' => 'b' })
+ @ui.output({ "hi" => "a", "lo" => "b" })
expect(@out.string).to eq <<EOM
hi: a
lo: b
@@ -205,7 +213,7 @@ EOM
end
it "formats arrays appropriately" do
- @ui.output([ 'a', 'b' ])
+ @ui.output(%w{a b})
expect(@out.string).to eq <<EOM
a
b
@@ -218,17 +226,17 @@ EOM
end
it "formats single-member arrays appropriately" do
- @ui.output([ 'a' ])
+ @ui.output([ "a" ])
expect(@out.string).to eq("a\n")
end
it "formats nested single-member arrays appropriately" do
- @ui.output([ [ 'a' ] ])
+ @ui.output([ [ "a" ] ])
expect(@out.string).to eq("a\n")
end
it "formats nested arrays appropriately" do
- @ui.output([ [ 'a', 'b' ], [ 'c', 'd' ]])
+ @ui.output([ %w{a b}, %w{c d}])
expect(@out.string).to eq <<EOM
a
b
@@ -239,7 +247,7 @@ EOM
end
it "formats nested arrays with single- and empty subarrays appropriately" do
- @ui.output([ [ 'a', 'b' ], [ 'c' ], [], [ 'd', 'e' ]])
+ @ui.output([ %w{a b}, [ "c" ], [], %w{d e}])
expect(@out.string).to eq <<EOM
a
b
@@ -253,7 +261,7 @@ EOM
end
it "formats arrays of hashes with extra lines in between for readability" do
- @ui.output([ { 'a' => 'b', 'c' => 'd' }, { 'x' => 'y' }, { 'm' => 'n', 'o' => 'p' }])
+ @ui.output([ { "a" => "b", "c" => "d" }, { "x" => "y" }, { "m" => "n", "o" => "p" }])
expect(@out.string).to eq <<EOM
a: b
c: d
@@ -266,7 +274,7 @@ EOM
end
it "formats hashes with empty array members appropriately" do
- @ui.output({ 'a' => [], 'b' => 'c' })
+ @ui.output({ "a" => [], "b" => "c" })
expect(@out.string).to eq <<EOM
a:
b: c
@@ -274,7 +282,7 @@ EOM
end
it "formats hashes with single-member array values appropriately" do
- @ui.output({ 'a' => [ 'foo' ], 'b' => 'c' })
+ @ui.output({ "a" => [ "foo" ], "b" => "c" })
expect(@out.string).to eq <<EOM
a: foo
b: c
@@ -282,7 +290,7 @@ EOM
end
it "formats hashes with array members appropriately" do
- @ui.output({ 'a' => [ 'foo', 'bar' ], 'b' => 'c' })
+ @ui.output({ "a" => %w{foo bar}, "b" => "c" })
expect(@out.string).to eq <<EOM
a:
foo
@@ -292,7 +300,7 @@ EOM
end
it "formats hashes with single-member nested array values appropriately" do
- @ui.output({ 'a' => [ [ 'foo' ] ], 'b' => 'c' })
+ @ui.output({ "a" => [ [ "foo" ] ], "b" => "c" })
expect(@out.string).to eq <<EOM
a:
foo
@@ -301,14 +309,14 @@ EOM
end
it "formats hashes with nested array values appropriately" do
- @ui.output({ 'a' => [ [ 'foo', 'bar' ], [ 'baz', 'bjork' ] ], 'b' => 'c' })
+ @ui.output({ "a" => [ %w{foo bar}, %w{baz bjork} ], "b" => "c" })
# XXX: using a HEREDOC at this point results in a line with required spaces which auto-whitespace removal settings
# on editors will remove and will break this test.
expect(@out.string).to eq("a:\n foo\n bar\n \n baz\n bjork\nb: c\n")
end
it "formats hashes with hash values appropriately" do
- @ui.output({ 'a' => { 'aa' => 'bb', 'cc' => 'dd' }, 'b' => 'c' })
+ @ui.output({ "a" => { "aa" => "bb", "cc" => "dd" }, "b" => "c" })
expect(@out.string).to eq <<EOM
a:
aa: bb
@@ -318,7 +326,7 @@ EOM
end
it "formats hashes with empty hash values appropriately" do
- @ui.output({ 'a' => { }, 'b' => 'c' })
+ @ui.output({ "a" => {}, "b" => "c" })
expect(@out.string).to eq <<EOM
a:
b: c
@@ -352,36 +360,66 @@ EOM
end
it "should return multiple attributes" do
- input = { "gi" => "go", "hi" => "ho", "id" => "sample-data-bag-item" }
- @ui.config[:attribute] = ["gi", "hi"]
- expect(@ui.format_for_display(input)).to eq({ "sample-data-bag-item" => { "gi" => "go", "hi"=> "ho" } })
+ input = { "gi" => "go", "hi" => "ho", "id" => "sample-data-bag-item" }
+ @ui.config[:attribute] = %w{gi hi}
+ expect(@ui.format_for_display(input)).to eq({ "sample-data-bag-item" => { "gi" => "go", "hi" => "ho" } })
end
it "should handle attributes named the same as methods" do
- input = { "keys" => "values", "hi" => "ho", "id" => "sample-data-bag-item" }
+ input = { "keys" => "values", "hi" => "ho", "id" => "sample-data-bag-item" }
@ui.config[:attribute] = "keys"
expect(@ui.format_for_display(input)).to eq({ "sample-data-bag-item" => { "keys" => "values" } })
end
it "should handle nested attributes named the same as methods" do
- input = { "keys" => {"keys" => "values"}, "hi" => "ho", "id" => "sample-data-bag-item" }
+ input = { "keys" => { "keys" => "values" }, "hi" => "ho", "id" => "sample-data-bag-item" }
@ui.config[:attribute] = "keys.keys"
expect(@ui.format_for_display(input)).to eq({ "sample-data-bag-item" => { "keys.keys" => "values" } })
end
it "should return the name attribute" do
- allow_any_instance_of(Chef::Node).to receive(:name).and_return("chef.localdomain")
input = Chef::Node.new
+ input.name("chef.localdomain")
@ui.config[:attribute] = "name"
- expect(@ui.format_for_display(input)).to eq( {"chef.localdomain"=>{"name"=>"chef.localdomain"} })
+ expect(@ui.format_for_display(input)).to eq( { "chef.localdomain" => { "name" => "chef.localdomain" } })
+ end
+
+ it "should return a 'class' attribute and not the node.class" do
+ input = Chef::Node.new
+ input.default["class"] = "classy!"
+ @ui.config[:attribute] = "class"
+ expect(@ui.format_for_display(input)).to eq( { nil => { "class" => "classy!" } } )
+ end
+
+ it "should return the chef_environment attribute" do
+ input = Chef::Node.new
+ input.chef_environment = "production-partner-load-integration-preview-testing"
+ @ui.config[:attribute] = "chef_environment"
+ expect(@ui.format_for_display(input)).to eq( { nil => { "chef_environment" => "production-partner-load-integration-preview-testing" } } )
+ end
+
+ it "works with arrays" do
+ input = Chef::Node.new
+ input.default["array"] = %w{zero one two}
+ @ui.config[:attribute] = "array.1"
+ expect(@ui.format_for_display(input)).to eq( { nil => { "array.1" => "one" } } )
end
it "returns nil when given an attribute path that isn't a name or attribute" do
- input = { "keys" => {"keys" => "values"}, "hi" => "ho", "id" => "sample-data-bag-item" }
+ input = { "keys" => { "keys" => "values" }, "hi" => "ho", "id" => "sample-data-bag-item" }
non_existing_path = "nope.nada.nothingtoseehere"
@ui.config[:attribute] = non_existing_path
expect(@ui.format_for_display(input)).to eq({ "sample-data-bag-item" => { non_existing_path => nil } })
end
+
+ describe "when --field-separator is passed" do
+ it "honors that separator" do
+ input = { "keys" => { "with spaces" => { "open" => { "doors" => { "with many.dots" => "when asked" } } } } }
+ @ui.config[:field_separator] = ";"
+ @ui.config[:attribute] = "keys;with spaces;open;doors;with many.dots"
+ expect(@ui.format_for_display(input)).to eq({ nil => { "keys;with spaces;open;doors;with many.dots" => "when asked" } })
+ end
+ end
end
describe "with --run-list passed" do
@@ -405,9 +443,9 @@ EOM
"versions" => [
{ "version" => "3.0.0", "url" => "http://url/cookbooks/3.0.0" },
{ "version" => "2.0.0", "url" => "http://url/cookbooks/2.0.0" },
- { "version" => "1.0.0", "url" => "http://url/cookbooks/1.0.0" }
- ]
- }
+ { "version" => "1.0.0", "url" => "http://url/cookbooks/1.0.0" },
+ ],
+ },
}
end
@@ -420,10 +458,10 @@ EOM
describe "with --with-uri" do
it "should return the URIs" do
response = {
- "cookbook_name"=>{
+ "cookbook_name" => {
"1.0.0" => "http://url/cookbooks/1.0.0",
"2.0.0" => "http://url/cookbooks/2.0.0",
- "3.0.0" => "http://url/cookbooks/3.0.0"}
+ "3.0.0" => "http://url/cookbooks/3.0.0" },
}
@ui.config[:with_uri] = true
expect(@ui.format_cookbook_list_for_display(@item)).to eq(response)
@@ -432,7 +470,7 @@ EOM
context "when running on Windows" do
before(:each) do
- stdout = double('StringIO', :tty? => true)
+ stdout = double("StringIO", :tty? => true)
allow(@ui).to receive(:stdout).and_return(stdout)
allow(ChefConfig).to receive(:windows?) { true }
Chef::Config.reset
@@ -460,11 +498,11 @@ EOM
end
describe "confirm" do
- let(:stdout) {StringIO.new}
- let(:output) {stdout.string}
+ let(:stdout) { StringIO.new }
+ let(:output) { stdout.string }
let(:question) { "monkeys rule" }
- let(:answer) { 'y' }
+ let(:answer) { "y" }
let(:default_choice) { nil }
let(:append_instructions) { true }
@@ -493,9 +531,9 @@ EOM
shared_examples_for "confirm with negative answer" do
it "confirm should exit 3" do
- expect {
+ expect do
run_confirm
- }.to raise_error(SystemExit) { |e| expect(e.status).to eq(3) }
+ end.to raise_error(SystemExit) { |e| expect(e.status).to eq(3) }
end
it "confirm_without_exit should return false" do
@@ -545,7 +583,7 @@ EOM
end
end
- ["Y", "y"].each do |answer|
+ %w{Y y}.each do |answer|
describe "with answer #{answer}" do
let(:answer) { answer }
@@ -553,7 +591,7 @@ EOM
end
end
- ["N", "n"].each do |answer|
+ %w{N n}.each do |answer|
describe "with answer #{answer}" do
let(:answer) { answer }
@@ -583,7 +621,7 @@ EOM
out = StringIO.new
allow(@ui).to receive(:stdout).and_return(out)
allow(@ui).to receive(:stdin).and_return(StringIO.new(" \n"))
- expect(@ui.ask_question("your chef server URL? ", :default => 'http://localhost:4000')).to eq("http://localhost:4000")
+ expect(@ui.ask_question("your chef server URL? ", :default => "http://localhost:4000")).to eq("http://localhost:4000")
expect(out.string).to eq("your chef server URL? [http://localhost:4000] ")
end
end
diff --git a/spec/unit/knife/data_bag_create_spec.rb b/spec/unit/knife/data_bag_create_spec.rb
index c31c88577d..b852c30401 100644
--- a/spec/unit/knife/data_bag_create_spec.rb
+++ b/spec/unit/knife/data_bag_create_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2009-2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tempfile'
+require "spec_helper"
+require "tempfile"
describe Chef::Knife::DataBagCreate do
let(:knife) do
@@ -28,7 +28,7 @@ describe Chef::Knife::DataBagCreate do
k
end
- let(:rest) { double("Chef::REST") }
+ let(:rest) { double("Chef::ServerAPI") }
let(:stdout) { StringIO.new }
let(:bag_name) { "sudoing_admins" }
@@ -36,7 +36,7 @@ describe Chef::Knife::DataBagCreate do
let(:secret) { "abc123SECRET" }
- let(:raw_hash) {{ "login_name" => "alphaomega", "id" => item_name }}
+ let(:raw_hash) { { "login_name" => "alphaomega", "id" => item_name } }
let(:config) { {} }
@@ -47,9 +47,9 @@ describe Chef::Knife::DataBagCreate do
end
it "tries to create a data bag with an invalid name when given one argument" do
- knife.name_args = ['invalid&char']
+ knife.name_args = ["invalid&char"]
expect(Chef::DataBag).to receive(:validate_name!).with(knife.name_args[0]).and_raise(Chef::Exceptions::InvalidDataBagName)
- expect {knife.run}.to exit_with_code(1)
+ expect { knife.run }.to exit_with_code(1)
end
context "when given one argument" do
@@ -58,7 +58,7 @@ describe Chef::Knife::DataBagCreate do
end
it "creates a data bag" do
- expect(rest).to receive(:post_rest).with("data", {"name" => bag_name})
+ expect(rest).to receive(:post).with("data", { "name" => bag_name })
expect(knife.ui).to receive(:info).with("Created data_bag[#{bag_name}]")
knife.run
@@ -75,8 +75,8 @@ describe Chef::Knife::DataBagCreate do
it "creates a data bag item" do
expect(knife).to receive(:create_object).and_yield(raw_hash)
expect(knife).to receive(:encryption_secret_provided?).and_return(false)
- expect(rest).to receive(:post_rest).with("data", {'name' => bag_name}).ordered
- expect(rest).to receive(:post_rest).with("data/#{bag_name}", item).ordered
+ expect(rest).to receive(:post).with("data", { "name" => bag_name }).ordered
+ expect(rest).to receive(:post).with("data/#{bag_name}", item).ordered
knife.run
end
@@ -99,8 +99,8 @@ describe Chef::Knife::DataBagCreate do
.to receive(:encrypt_data_bag_item)
.with(raw_hash, secret)
.and_return(encoded_data)
- expect(rest).to receive(:post_rest).with("data", {"name" => bag_name}).ordered
- expect(rest).to receive(:post_rest).with("data/#{bag_name}", item).ordered
+ expect(rest).to receive(:post).with("data", { "name" => bag_name }).ordered
+ expect(rest).to receive(:post).with("data/#{bag_name}", item).ordered
knife.run
end
diff --git a/spec/unit/knife/data_bag_edit_spec.rb b/spec/unit/knife/data_bag_edit_spec.rb
index 6f19b5e63e..635dc63489 100644
--- a/spec/unit/knife/data_bag_edit_spec.rb
+++ b/spec/unit/knife/data_bag_edit_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2010 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tempfile'
+require "spec_helper"
+require "tempfile"
describe Chef::Knife::DataBagEdit do
before do
@@ -33,11 +33,11 @@ describe Chef::Knife::DataBagEdit do
k
end
- let(:raw_hash) { {"login_name" => "alphaomega", "id" => "item_name"} }
- let(:db) { Chef::DataBagItem.from_hash(raw_hash)}
- let(:raw_edited_hash) { {"login_name" => "rho", "id" => "item_name", "new_key" => "new_value"} }
+ let(:raw_hash) { { "login_name" => "alphaomega", "id" => "item_name" } }
+ let(:db) { Chef::DataBagItem.from_hash(raw_hash) }
+ let(:raw_edited_hash) { { "login_name" => "rho", "id" => "item_name", "new_key" => "new_value" } }
- let(:rest) { double("Chef::REST") }
+ let(:rest) { double("Chef::ServerAPI") }
let(:stdout) { StringIO.new }
let(:bag_name) { "sudoing_admins" }
@@ -55,8 +55,8 @@ describe Chef::Knife::DataBagEdit do
it "correctly edits then uploads the data bag" do
expect(Chef::DataBagItem).to receive(:load).with(bag_name, item_name).and_return(db)
expect(knife).to receive(:encrypted?).with(db.raw_data).and_return(is_encrypted?)
- expect(knife).to receive(:edit_data).with(data_to_edit).and_return(raw_edited_hash)
- expect(rest).to receive(:put_rest).with("data/#{bag_name}/#{item_name}", transmitted_hash).ordered
+ expect(knife).to receive(:edit_hash).with(data_to_edit).and_return(raw_edited_hash)
+ expect(rest).to receive(:put).with("data/#{bag_name}/#{item_name}", transmitted_hash).ordered
knife.run
end
@@ -65,7 +65,7 @@ describe Chef::Knife::DataBagEdit do
it "requires data bag and item arguments" do
knife.name_args = []
expect(stdout).to receive(:puts).twice.with(anything)
- expect {knife.run}.to exit_with_code(1)
+ expect { knife.run }.to exit_with_code(1)
expect(stdout.string).to eq("")
end
@@ -74,7 +74,7 @@ describe Chef::Knife::DataBagEdit do
end
context "when config[:print_after] is set" do
- let(:config) { {:print_after => true} }
+ let(:config) { { :print_after => true } }
before do
expect(knife.ui).to receive(:output).with(raw_edited_hash)
end
@@ -121,7 +121,7 @@ describe Chef::Knife::DataBagEdit do
expect(knife).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(false)
expect(knife.ui).to receive(:fatal).with("You cannot edit an encrypted data bag without providing the secret.")
- expect {knife.run}.to exit_with_code(1)
+ expect { knife.run }.to exit_with_code(1)
end
end
diff --git a/spec/unit/knife/data_bag_from_file_spec.rb b/spec/unit/knife/data_bag_from_file_spec.rb
index 8b6502145c..3bea392ae2 100644
--- a/spec/unit/knife/data_bag_from_file_spec.rb
+++ b/spec/unit/knife/data_bag_from_file_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/data_bag_item'
-require 'chef/encrypted_data_bag_item'
-require 'tempfile'
+require "chef/data_bag_item"
+require "chef/encrypted_data_bag_item"
+require "tempfile"
Chef::Knife::DataBagFromFile.load_deps
@@ -52,7 +52,7 @@ describe Chef::Knife::DataBagFromFile do
k
end
- let(:tmp_dir) { Dir.mktmpdir }
+ let(:tmp_dir) { make_canonical_temp_directory }
let(:db_folder) { File.join(tmp_dir, data_bags_path, bag_name) }
let(:db_file) { Tempfile.new(["data_bag_from_file_test", ".json"], db_folder) }
let(:db_file2) { Tempfile.new(["data_bag_from_file_test2", ".json"], db_folder) }
@@ -72,14 +72,15 @@ describe Chef::Knife::DataBagFromFile do
let(:loader) { double("Knife::Core::ObjectLoader") }
let(:data_bags_path) { "data_bags" }
- let(:plain_data) { {
+ let(:plain_data) do
+ {
"id" => "item_name",
"greeting" => "hello",
- "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true }}
- } }
+ "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true } },
+ } end
let(:enc_data) { Chef::EncryptedDataBagItem.encrypt_data_bag_item(plain_data, secret) }
- let(:rest) { double("Chef::REST") }
+ let(:rest) { double("Chef::ServerAPI") }
let(:stdout) { StringIO.new }
let(:bag_name) { "sudoing_admins" }
@@ -164,7 +165,7 @@ describe Chef::Knife::DataBagFromFile do
describe "command line parsing" do
it "prints help if given no arguments" do
knife.name_args = [bag_name]
- expect {knife.run}.to exit_with_code(1)
+ expect { knife.run }.to exit_with_code(1)
expect(stdout.string).to start_with("knife data bag from file BAG FILE|FOLDER [FILE|FOLDER..] (options)")
end
end
diff --git a/spec/unit/knife/data_bag_secret_options_spec.rb b/spec/unit/knife/data_bag_secret_options_spec.rb
index 0a2d8ca4bf..2f4d8c8a88 100644
--- a/spec/unit/knife/data_bag_secret_options_spec.rb
+++ b/spec/unit/knife/data_bag_secret_options_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tyler Ball (<tball@opscode.com>)
-# Copyright:: Copyright (c) 2009-2014 Opscode, Inc.
+# Author:: Tyler Ball (<tball@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/knife'
-require 'chef/config'
-require 'tempfile'
+require "spec_helper"
+require "chef/knife"
+require "chef/config"
+require "tempfile"
class ExampleDataBagCommand < Chef::Knife
include Chef::Knife::DataBagSecretOptions
diff --git a/spec/unit/knife/data_bag_show_spec.rb b/spec/unit/knife/data_bag_show_spec.rb
index 1125d99c2a..ece7f5bf78 100644
--- a/spec/unit/knife/data_bag_show_spec.rb
+++ b/spec/unit/knife/data_bag_show_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2008-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,12 +17,12 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/data_bag_item'
-require 'chef/encrypted_data_bag_item'
-require 'chef/json_compat'
-require 'tempfile'
+require "chef/data_bag_item"
+require "chef/encrypted_data_bag_item"
+require "chef/json_compat"
+require "tempfile"
describe Chef::Knife::DataBagShow do
@@ -39,16 +39,17 @@ describe Chef::Knife::DataBagShow do
k
end
- let(:rest) { double("Chef::REST") }
+ let(:rest) { double("Chef::ServerAPI") }
let(:stdout) { StringIO.new }
let(:bag_name) { "sudoing_admins" }
let(:item_name) { "ME" }
- let(:data_bag_contents) { { "id" => "id", "baz"=>"http://localhost:4000/data/bag_o_data/baz",
- "qux"=>"http://localhost:4000/data/bag_o_data/qux"} }
- let(:enc_hash) {Chef::EncryptedDataBagItem.encrypt_data_bag_item(data_bag_contents, secret)}
- let(:data_bag) {Chef::DataBagItem.from_hash(data_bag_contents)}
+ let(:data_bag_contents) do
+ { "id" => "id", "baz" => "http://localhost:4000/data/bag_o_data/baz",
+ "qux" => "http://localhost:4000/data/bag_o_data/qux" } end
+ let(:enc_hash) { Chef::EncryptedDataBagItem.encrypt_data_bag_item(data_bag_contents, secret) }
+ let(:data_bag) { Chef::DataBagItem.from_hash(data_bag_contents) }
let(:data_bag_with_encoded_hash) { Chef::DataBagItem.from_hash(enc_hash) }
let(:enc_data_bag) { Chef::EncryptedDataBagItem.new(enc_hash, secret) }
@@ -56,7 +57,7 @@ describe Chef::Knife::DataBagShow do
#
# let(:raw_hash) {{ "login_name" => "alphaomega", "id" => item_name }}
#
- let(:config) { {format: "json"} }
+ let(:config) { { format: "json" } }
context "Data bag to show is encrypted" do
before do
@@ -70,9 +71,9 @@ describe Chef::Knife::DataBagShow do
expect(knife.ui).to receive(:info).with("Encrypted data bag detected, decrypting with provided secret.")
expect(Chef::EncryptedDataBagItem).to receive(:load).with(bag_name, item_name, secret).and_return(enc_data_bag)
- expected = %q|baz: http://localhost:4000/data/bag_o_data/baz
+ expected = %q{baz: http://localhost:4000/data/bag_o_data/baz
id: id
-qux: http://localhost:4000/data/bag_o_data/qux|
+qux: http://localhost:4000/data/bag_o_data/qux}
knife.run
expect(stdout.string.strip).to eq(expected)
end
@@ -80,7 +81,7 @@ qux: http://localhost:4000/data/bag_o_data/qux|
it "displays the encrypted data bag when the secret is not provided" do
expect(knife).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(false)
expect(Chef::DataBagItem).to receive(:load).with(bag_name, item_name).and_return(data_bag_with_encoded_hash)
- expect(knife.ui).to receive(:warn).with("Encrypted data bag detected, but no secret provided for decoding. Displaying encrypted data.")
+ expect(knife.ui).to receive(:warn).with("Encrypted data bag detected, but no secret provided for decoding. Displaying encrypted data.")
knife.run
expect(stdout.string.strip).to include("baz", "qux", "cipher")
@@ -95,11 +96,11 @@ qux: http://localhost:4000/data/bag_o_data/qux|
it "displays the data bag" do
expect(Chef::DataBagItem).to receive(:load).with(bag_name, item_name).and_return(data_bag)
- expect(knife.ui).to receive(:info).with("Unencrypted data bag detected, ignoring any provided secret options.")
+ expect(knife.ui).to receive(:warn).with("Unencrypted data bag detected, ignoring any provided secret options.")
- expected = %q|baz: http://localhost:4000/data/bag_o_data/baz
+ expected = %q{baz: http://localhost:4000/data/bag_o_data/baz
id: id
-qux: http://localhost:4000/data/bag_o_data/qux|
+qux: http://localhost:4000/data/bag_o_data/qux}
knife.run
expect(stdout.string.strip).to eq(expected)
end
@@ -116,7 +117,7 @@ qux: http://localhost:4000/data/bag_o_data/qux|
it "raises an error when no @name_args are provided" do
knife.name_args = []
- expect {knife.run}.to exit_with_code(1)
+ expect { knife.run }.to exit_with_code(1)
expect(stdout.string).to start_with("knife data bag show BAG [ITEM] (options)")
end
diff --git a/spec/unit/knife/environment_compare_spec.rb b/spec/unit/knife/environment_compare_spec.rb
index 6d4d3ead52..e408532884 100644
--- a/spec/unit/knife/environment_compare_spec.rb
+++ b/spec/unit/knife/environment_compare_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Sander Botman (<sbotman@schubergphilis.com>)
-# Copyright:: Copyright (c) 2013 Sander Botman.
+# Copyright:: Copyright 2013-2016, Sander Botman.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,66 +16,66 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::EnvironmentCompare do
before(:each) do
@knife = Chef::Knife::EnvironmentCompare.new
-
+
@environments = {
"cita" => "http://localhost:4000/environments/cita",
- "citm" => "http://localhost:4000/environments/citm"
+ "citm" => "http://localhost:4000/environments/citm",
}
allow(@knife).to receive(:environment_list).and_return(@environments)
@constraints = {
"cita" => { "foo" => "= 1.0.1", "bar" => "= 0.0.4" },
- "citm" => { "foo" => "= 1.0.1", "bar" => "= 0.0.2" }
+ "citm" => { "foo" => "= 1.0.1", "bar" => "= 0.0.2" },
}
-
+
allow(@knife).to receive(:constraint_list).and_return(@constraints)
- @cookbooks = { "foo"=>"= 1.0.1", "bar"=>"= 0.0.1" }
+ @cookbooks = { "foo" => "= 1.0.1", "bar" => "= 0.0.1" }
allow(@knife).to receive(:cookbook_list).and_return(@cookbooks)
- @rest_double = double('rest')
+ @rest_double = double("rest")
allow(@knife).to receive(:rest).and_return(@rest_double)
- @cookbook_names = ['apache2', 'mysql', 'foo', 'bar', 'dummy', 'chef_handler']
- @base_url = 'https://server.example.com/cookbooks'
+ @cookbook_names = %w{apache2 mysql foo bar dummy chef_handler}
+ @base_url = "https://server.example.com/cookbooks"
@cookbook_data = {}
@cookbook_names.each do |item|
- @cookbook_data[item] = {'url' => "#{@base_url}/#{item}",
- 'versions' => [{'version' => '1.0.1',
- 'url' => "#{@base_url}/#{item}/1.0.1"}]}
- end
+ @cookbook_data[item] = { "url" => "#{@base_url}/#{item}",
+ "versions" => [{ "version" => "1.0.1",
+ "url" => "#{@base_url}/#{item}/1.0.1" }] }
+ end
- allow(@rest_double).to receive(:get_rest).with("/cookbooks?num_versions=1").and_return(@cookbook_data)
+ allow(@rest_double).to receive(:get).with("/cookbooks?num_versions=1").and_return(@cookbook_data)
@stdout = StringIO.new
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
end
- describe 'run' do
- it 'should display only cookbooks with version constraints' do
- @knife.config[:format] = 'summary'
+ describe "run" do
+ it "should display only cookbooks with version constraints" do
+ @knife.config[:format] = "summary"
@knife.run
@environments.each do |item, url|
- expect(@stdout.string).to match /#{item}/ and expect(@stdout.string.lines.count).to be 4
+ expect(@stdout.string).to(match /#{item}/) && expect(@stdout.string.lines.count).to(be 4)
end
end
-
- it 'should display 4 number of lines' do
- @knife.config[:format] = 'summary'
+
+ it "should display 4 number of lines" do
+ @knife.config[:format] = "summary"
@knife.run
expect(@stdout.string.lines.count).to be 4
end
end
- describe 'with -m or --mismatch' do
- it 'should display only cookbooks that have mismatching version constraints' do
- @knife.config[:format] = 'summary'
+ describe "with -m or --mismatch" do
+ it "should display only cookbooks that have mismatching version constraints" do
+ @knife.config[:format] = "summary"
@knife.config[:mismatch] = true
@knife.run
@constraints.each do |item, ver|
@@ -83,17 +83,17 @@ describe Chef::Knife::EnvironmentCompare do
end
end
- it 'should display 3 number of lines' do
- @knife.config[:format] = 'summary'
+ it "should display 3 number of lines" do
+ @knife.config[:format] = "summary"
@knife.config[:mismatch] = true
@knife.run
expect(@stdout.string.lines.count).to be 3
end
end
-
- describe 'with -a or --all' do
- it 'should display all cookbooks' do
- @knife.config[:format] = 'summary'
+
+ describe "with -a or --all" do
+ it "should display all cookbooks" do
+ @knife.config[:format] = "summary"
@knife.config[:all] = true
@knife.run
@constraints.each do |item, ver|
@@ -101,8 +101,8 @@ describe Chef::Knife::EnvironmentCompare do
end
end
- it 'should display 8 number of lines' do
- @knife.config[:format] = 'summary'
+ it "should display 8 number of lines" do
+ @knife.config[:format] = "summary"
@knife.config[:all] = true
@knife.run
expect(@stdout.string.lines.count).to be 8
diff --git a/spec/unit/knife/environment_create_spec.rb b/spec/unit/knife/environment_create_spec.rb
index 04e45048ef..a80626657c 100644
--- a/spec/unit/knife/environment_create_spec.rb
+++ b/spec/unit/knife/environment_create_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Stephen Delano (<stephen@ospcode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::EnvironmentCreate do
before(:each) do
@@ -50,7 +50,7 @@ describe Chef::Knife::EnvironmentCreate do
end
it "should prompt you to edit the data" do
- expect(@knife).to receive(:edit_data).with(@environment)
+ expect(@knife).to receive(:edit_data).with(@environment, object_class: Chef::Environment)
@knife.run
end
diff --git a/spec/unit/knife/environment_delete_spec.rb b/spec/unit/knife/environment_delete_spec.rb
index 95df6e15fe..307a6196c0 100644
--- a/spec/unit/knife/environment_delete_spec.rb
+++ b/spec/unit/knife/environment_delete_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Stephen Delano (<stephen@ospcode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::EnvironmentDelete do
before(:each) do
diff --git a/spec/unit/knife/environment_edit_spec.rb b/spec/unit/knife/environment_edit_spec.rb
index 61c2663a41..1f2ff27ce8 100644
--- a/spec/unit/knife/environment_edit_spec.rb
+++ b/spec/unit/knife/environment_edit_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Stephen Delano (<stephen@ospcode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::EnvironmentEdit do
before(:each) do
@@ -40,7 +40,7 @@ describe Chef::Knife::EnvironmentEdit do
end
it "should let you edit the environment" do
- expect(@knife.ui).to receive(:edit_data).with(@environment)
+ expect(@knife.ui).to receive(:edit_data).with(@environment, object_class: Chef::Environment)
@knife.run
end
@@ -48,7 +48,7 @@ describe Chef::Knife::EnvironmentEdit do
pansy = Chef::Environment.new
@environment.name("new_environment_name")
- expect(@knife.ui).to receive(:edit_data).with(@environment).and_return(pansy)
+ expect(@knife.ui).to receive(:edit_data).with(@environment, object_class: Chef::Environment).and_return(pansy)
expect(pansy).to receive(:save)
@knife.run
end
diff --git a/spec/unit/knife/environment_from_file_spec.rb b/spec/unit/knife/environment_from_file_spec.rb
index 11ad23c919..4505da3637 100644
--- a/spec/unit/knife/environment_from_file_spec.rb
+++ b/spec/unit/knife/environment_from_file_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Stephen Delano (<stephen@ospcode.com>)
# Author:: Seth Falcon (<seth@ospcode.com>)
-# Copyright:: Copyright 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
Chef::Knife::EnvironmentFromFile.load_deps
@@ -32,14 +32,14 @@ describe Chef::Knife::EnvironmentFromFile do
@environment = Chef::Environment.new
@environment.name("spec")
@environment.description("runs the unit tests")
- @environment.cookbook_versions({"apt" => "= 1.2.3"})
+ @environment.cookbook_versions({ "apt" => "= 1.2.3" })
allow(@environment).to receive(:save).and_return true
allow(@knife.loader).to receive(:load_from).and_return @environment
end
describe "run" do
it "loads the environment data from a file and saves it" do
- expect(@knife.loader).to receive(:load_from).with('environments', 'spec.rb').and_return(@environment)
+ expect(@knife.loader).to receive(:load_from).with("environments", "spec.rb").and_return(@environment)
expect(@environment).to receive(:save)
@knife.run
end
@@ -61,7 +61,7 @@ describe Chef::Knife::EnvironmentFromFile do
allow(File).to receive(:expand_path).with("./environments/").and_return("/tmp/environments")
allow(Dir).to receive(:glob).with("/tmp/environments/*.{json,rb}").and_return(["spec.rb", "apple.rb"])
@knife.name_args = []
- allow(@knife).to receive(:config).and_return({:all => true})
+ allow(@knife).to receive(:config).and_return({ :all => true })
expect(@environment).to receive(:save).twice
@knife.run
end
diff --git a/spec/unit/knife/environment_list_spec.rb b/spec/unit/knife/environment_list_spec.rb
index 6488a073b6..636b32273e 100644
--- a/spec/unit/knife/environment_list_spec.rb
+++ b/spec/unit/knife/environment_list_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Stephen Delano (<stephen@ospcode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::EnvironmentList do
before(:each) do
@@ -28,7 +28,7 @@ describe Chef::Knife::EnvironmentList do
@environments = {
"production" => "http://localhost:4000/environments/production",
"development" => "http://localhost:4000/environments/development",
- "testing" => "http://localhost:4000/environments/testing"
+ "testing" => "http://localhost:4000/environments/testing",
}
allow(Chef::Environment).to receive(:list).and_return @environments
end
@@ -39,7 +39,7 @@ describe Chef::Knife::EnvironmentList do
end
it "should print the environment names in a sorted list" do
- names = @environments.keys.sort { |a,b| a <=> b }
+ names = @environments.keys.sort { |a, b| a <=> b }
expect(@knife).to receive(:output).with(names)
@knife.run
end
diff --git a/spec/unit/knife/environment_show_spec.rb b/spec/unit/knife/environment_show_spec.rb
index caac958f8e..bd4148e451 100644
--- a/spec/unit/knife/environment_show_spec.rb
+++ b/spec/unit/knife/environment_show_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Stephen Delano (<stephen@ospcode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::EnvironmentShow do
before(:each) do
diff --git a/spec/unit/knife/index_rebuild_spec.rb b/spec/unit/knife/index_rebuild_spec.rb
index 6c3b60bd88..97a3a69155 100644
--- a/spec/unit/knife/index_rebuild_spec.rb
+++ b/spec/unit/knife/index_rebuild_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::IndexRebuild do
- let(:knife){Chef::Knife::IndexRebuild.new}
- let(:rest_client){double(Chef::REST)}
+ let(:knife) { Chef::Knife::IndexRebuild.new }
+ let(:rest_client) { double(Chef::ServerAPI) }
let(:stub_rest!) do
expect(knife).to receive(:rest).and_return(rest_client)
@@ -45,18 +45,18 @@ describe Chef::Knife::IndexRebuild do
before(:each) do
stub_rest!
- allow(rest_client).to receive(:get_rest).and_raise(http_server_exception)
+ allow(rest_client).to receive(:get).and_raise(http_server_exception)
end
context "against a Chef 11 server" do
- let(:api_header_value){"flavor=osc;version=11.0.0;erchef=1.2.3"}
+ let(:api_header_value) { "flavor=osc;version=11.0.0;erchef=1.2.3" }
it "retrieves API information" do
- expect(knife.grab_api_info).to eq({"flavor" => "osc", "version" => "11.0.0", "erchef" => "1.2.3"})
+ expect(knife.grab_api_info).to eq({ "flavor" => "osc", "version" => "11.0.0", "erchef" => "1.2.3" })
end
end # Chef 11
context "against a Chef 10 server" do
- let(:api_header_value){nil}
+ let(:api_header_value) { nil }
it "finds no API information" do
expect(knife.grab_api_info).to eq({})
end
@@ -66,11 +66,11 @@ describe Chef::Knife::IndexRebuild do
context "#unsupported_version?" do
context "with Chef 11 API metadata" do
it "is unsupported" do
- expect(knife.unsupported_version?({"version" => "11.0.0", "flavor" => "osc", "erchef" => "1.2.3"})).to be_truthy
+ expect(knife.unsupported_version?({ "version" => "11.0.0", "flavor" => "osc", "erchef" => "1.2.3" })).to be_truthy
end
it "only truly relies on the version being non-nil" do
- expect(knife.unsupported_version?({"version" => "1", "flavor" => "osc", "erchef" => "1.2.3"})).to be_truthy
+ expect(knife.unsupported_version?({ "version" => "1", "flavor" => "osc", "erchef" => "1.2.3" })).to be_truthy
end
end
@@ -91,9 +91,9 @@ describe Chef::Knife::IndexRebuild do
context "against a Chef 11 server" do
let(:api_info) do
- {"flavor" => "osc",
+ { "flavor" => "osc",
"version" => "11.0.0",
- "erchef" => "1.2.3"
+ "erchef" => "1.2.3",
}
end
let(:server_specific_stubs!) do
@@ -107,10 +107,10 @@ describe Chef::Knife::IndexRebuild do
end
context "against a Chef 10 server" do
- let(:api_info){ {} }
+ let(:api_info) { {} }
let(:server_specific_stubs!) do
stub_rest!
- expect(rest_client).to receive(:post_rest).with("/search/reindex", {}).and_return("representative output")
+ expect(rest_client).to receive(:post).with("/search/reindex", {}).and_return("representative output")
expect(knife).not_to receive(:unsupported_server_message)
expect(knife).to receive(:deprecated_server_message)
expect(knife).to receive(:nag)
@@ -123,6 +123,3 @@ describe Chef::Knife::IndexRebuild do
end
end
-
-
-
diff --git a/spec/unit/knife/key_create_spec.rb b/spec/unit/knife/key_create_spec.rb
index 5998e10274..5b00c6ea31 100644
--- a/spec/unit/knife/key_create_spec.rb
+++ b/spec/unit/knife/key_create_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/knife/user_key_create'
-require 'chef/knife/client_key_create'
-require 'chef/knife/key_create'
-require 'chef/key'
+require "spec_helper"
+require "chef/knife/user_key_create"
+require "chef/knife/client_key_create"
+require "chef/knife/key_create"
+require "chef/key"
describe "key create commands that inherit knife" do
shared_examples_for "a key create command" do
@@ -73,7 +73,7 @@ describe "key create commands that inherit knife" do
end
describe Chef::Knife::KeyCreate do
- let(:public_key) {
+ let(:public_key) do
"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvPo+oNPB7uuNkws0fC02
KxSwdyqPLu0fhI1pOweNKAZeEIiEz2PkybathHWy8snSXGNxsITkf3eyvIIKa8OZ
@@ -83,28 +83,28 @@ IjSmiN/ihHtlhV/VSnBJ5PzT/lRknlrJ4kACoz7Pq9jv+aAx5ft/xE9yDa2DYs0q
Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
0wIDAQAB
-----END PUBLIC KEY-----"
- }
+ end
let(:config) { Hash.new }
let(:actor) { "charmander" }
let(:ui) { instance_double("Chef::Knife::UI") }
shared_examples_for "key create run command" do
- let(:key_create_object) {
+ let(:key_create_object) do
described_class.new(actor, actor_field_name, ui, config)
- }
+ end
context "when public_key and key_name weren't passed" do
it "raises a Chef::Exceptions::KeyCommandInputError with the proper error message" do
- expect{ key_create_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_create_object.public_key_or_key_name_error_msg)
+ expect { key_create_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_create_object.public_key_or_key_name_error_msg)
end
end
context "when the command is run" do
- let(:expected_hash) {
+ let(:expected_hash) do
{
- actor_field_name => "charmander"
+ actor_field_name => "charmander",
}
- }
+ end
before do
allow(File).to receive(:read).and_return(public_key)
@@ -112,7 +112,7 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
allow(key_create_object).to receive(:output_private_key_to_file)
allow(key_create_object).to receive(:display_private_key)
- allow(key_create_object).to receive(:edit_data).and_return(expected_hash)
+ allow(key_create_object).to receive(:edit_hash).and_return(expected_hash)
allow(key_create_object).to receive(:create_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
allow(key_create_object).to receive(:display_info)
end
@@ -120,14 +120,14 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
context "when a valid hash is passed" do
let(:key_name) { "charmander-key" }
let(:valid_expiration_date) { "2020-12-24T21:00:00Z" }
- let(:expected_hash) {
+ let(:expected_hash) do
{
actor_field_name => "charmander",
"public_key" => public_key,
"expiration_date" => valid_expiration_date,
- "key_name" => key_name
+ "key_name" => key_name,
}
- }
+ end
before do
key_create_object.config[:public_key] = "public_key_path"
key_create_object.config[:expiration_Date] = valid_expiration_date,
@@ -141,12 +141,12 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
end
context "when public_key is passed" do
- let(:expected_hash) {
+ let(:expected_hash) do
{
actor_field_name => "charmander",
- "public_key" => public_key
+ "public_key" => public_key,
}
- }
+ end
before do
key_create_object.config[:public_key] = "public_key_path"
end
@@ -158,13 +158,13 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
end # when public_key is passed
context "when public_key isn't passed and key_name is" do
- let(:expected_hash) {
+ let(:expected_hash) do
{
actor_field_name => "charmander",
"name" => "charmander-key",
- "create_key" => true
+ "create_key" => true,
}
- }
+ end
before do
key_create_object.config[:key_name] = "charmander-key"
end
@@ -176,13 +176,13 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
end
context "when the server returns a private key" do
- let(:expected_hash) {
+ let(:expected_hash) do
{
actor_field_name => "charmander",
"public_key" => public_key,
- "private_key" => "super_private"
+ "private_key" => "super_private",
}
- }
+ end
before do
key_create_object.config[:public_key] = "public_key_path"
@@ -221,4 +221,3 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
end
end
end
-
diff --git a/spec/unit/knife/key_delete_spec.rb b/spec/unit/knife/key_delete_spec.rb
index 1d4b9f825f..0176f3c71e 100644
--- a/spec/unit/knife/key_delete_spec.rb
+++ b/spec/unit/knife/key_delete_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/knife/user_key_delete'
-require 'chef/knife/client_key_delete'
-require 'chef/knife/key_delete'
-require 'chef/key'
+require "spec_helper"
+require "chef/knife/user_key_delete"
+require "chef/knife/client_key_delete"
+require "chef/knife/key_delete"
+require "chef/key"
describe "key delete commands that inherit knife" do
shared_examples_for "a key delete command" do
@@ -45,8 +45,8 @@ describe "key delete commands that inherit knife" do
context "when the service object is called" do
it "creates a new instance of Chef::Knife::KeyDelete with the correct args" do
expect(Chef::Knife::KeyDelete).to receive(:new).
- with("charmander-key", "charmander", command.actor_field_name, command.ui).
- and_return(service_object)
+ with("charmander-key", "charmander", command.actor_field_name, command.ui).
+ and_return(service_object)
command.service_object
end
end # when the service object is called
@@ -80,9 +80,9 @@ describe Chef::Knife::KeyDelete do
let(:ui) { instance_double("Chef::Knife::UI") }
shared_examples_for "key delete run command" do
- let(:key_delete_object) {
+ let(:key_delete_object) do
described_class.new(keyname, actor, actor_field_name, ui)
- }
+ end
before do
allow_any_instance_of(Chef::Key).to receive(:destroy)
@@ -117,7 +117,6 @@ describe Chef::Knife::KeyDelete do
end
end # when the command is run
-
end # key delete run command
context "when actor_field_name is 'user'" do
@@ -132,4 +131,3 @@ describe Chef::Knife::KeyDelete do
end
end
end
-
diff --git a/spec/unit/knife/key_edit_spec.rb b/spec/unit/knife/key_edit_spec.rb
index 538b91de2d..244d8bdcc7 100644
--- a/spec/unit/knife/key_edit_spec.rb
+++ b/spec/unit/knife/key_edit_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/knife/user_key_edit'
-require 'chef/knife/client_key_edit'
-require 'chef/knife/key_edit'
-require 'chef/key'
+require "spec_helper"
+require "chef/knife/user_key_edit"
+require "chef/knife/client_key_edit"
+require "chef/knife/key_edit"
+require "chef/key"
describe "key edit commands that inherit knife" do
shared_examples_for "a key edit command" do
@@ -45,8 +45,8 @@ describe "key edit commands that inherit knife" do
context "when the service object is called" do
it "creates a new instance of Chef::Knife::KeyEdit with the correct args" do
expect(Chef::Knife::KeyEdit).to receive(:new).
- with("charmander-key", "charmander", command.actor_field_name, command.ui, command.config).
- and_return(service_object)
+ with("charmander-key", "charmander", command.actor_field_name, command.ui, command.config).
+ and_return(service_object)
command.service_object
end
end # when the service object is called
@@ -75,7 +75,7 @@ describe "key edit commands that inherit knife" do
end
describe Chef::Knife::KeyEdit do
- let(:public_key) {
+ let(:public_key) do
"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvPo+oNPB7uuNkws0fC02
KxSwdyqPLu0fhI1pOweNKAZeEIiEz2PkybathHWy8snSXGNxsITkf3eyvIIKa8OZ
@@ -85,23 +85,23 @@ IjSmiN/ihHtlhV/VSnBJ5PzT/lRknlrJ4kACoz7Pq9jv+aAx5ft/xE9yDa2DYs0q
Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
0wIDAQAB
-----END PUBLIC KEY-----"
- }
+ end
let(:config) { Hash.new }
let(:actor) { "charmander" }
let(:keyname) { "charmander-key" }
let(:ui) { instance_double("Chef::Knife::UI") }
shared_examples_for "key edit run command" do
- let(:key_edit_object) {
+ let(:key_edit_object) do
described_class.new(keyname, actor, actor_field_name, ui, config)
- }
+ end
context "when the command is run" do
- let(:expected_hash) {
+ let(:expected_hash) do
{
- actor_field_name => "charmander"
+ actor_field_name => "charmander",
}
- }
+ end
let(:new_keyname) { "charizard-key" }
before do
@@ -110,11 +110,10 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
allow(key_edit_object).to receive(:output_private_key_to_file)
allow(key_edit_object).to receive(:display_private_key)
- allow(key_edit_object).to receive(:edit_data).and_return(expected_hash)
+ allow(key_edit_object).to receive(:edit_hash).and_return(expected_hash)
allow(key_edit_object).to receive(:display_info)
end
-
context "when public_key and create_key are passed" do
before do
key_edit_object.config[:public_key] = "public_key_path"
@@ -122,17 +121,17 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
end
it "raises a Chef::Exceptions::KeyCommandInputError with the proper error message" do
- expect{ key_edit_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_edit_object.public_key_and_create_key_error_msg)
+ expect { key_edit_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_edit_object.public_key_and_create_key_error_msg)
end
end
context "when key_name is passed" do
- let(:expected_hash) {
+ let(:expected_hash) do
{
actor_field_name => "charmander",
- "name" => new_keyname
+ "name" => new_keyname,
}
- }
+ end
before do
key_edit_object.config[:key_name] = new_keyname
allow_any_instance_of(Chef::Key).to receive(:update)
@@ -156,14 +155,14 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
end
context "when public_key, key_name, and expiration_date are passed" do
- let(:expected_hash) {
+ let(:expected_hash) do
{
actor_field_name => "charmander",
"public_key" => public_key,
"name" => new_keyname,
- "expiration_date" => "infinity"
+ "expiration_date" => "infinity",
}
- }
+ end
before do
key_edit_object.config[:public_key] = "this-public-key"
key_edit_object.config[:key_name] = new_keyname
@@ -178,12 +177,12 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
end
context "when create_key is passed" do
- let(:expected_hash) {
+ let(:expected_hash) do
{
actor_field_name => "charmander",
- "create_key" => true
+ "create_key" => true,
}
- }
+ end
before do
key_edit_object.config[:create_key] = true
@@ -197,12 +196,12 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
end
context "when public_key is passed" do
- let(:expected_hash) {
+ let(:expected_hash) do
{
actor_field_name => "charmander",
- "public_key" => public_key
+ "public_key" => public_key,
}
- }
+ end
before do
allow(key_edit_object).to receive(:update_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
key_edit_object.config[:public_key] = "public_key_path"
@@ -215,13 +214,13 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
end # when public_key is passed
context "when the server returns a private key" do
- let(:expected_hash) {
+ let(:expected_hash) do
{
actor_field_name => "charmander",
"public_key" => public_key,
- "private_key" => "super_private"
+ "private_key" => "super_private",
}
- }
+ end
before do
allow(key_edit_object).to receive(:update_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
@@ -249,8 +248,6 @@ Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
end # when the command is run
-
-
end # key edit run command
context "when actor_field_name is 'user'" do
diff --git a/spec/unit/knife/key_helper.rb b/spec/unit/knife/key_helper.rb
index 36ababc09a..af81812b93 100644
--- a/spec/unit/knife/key_helper.rb
+++ b/spec/unit/knife/key_helper.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
shared_examples_for "a knife key command" do
let(:stderr) { StringIO.new }
diff --git a/spec/unit/knife/key_list_spec.rb b/spec/unit/knife/key_list_spec.rb
index aabe02ac02..82fd1e4a09 100644
--- a/spec/unit/knife/key_list_spec.rb
+++ b/spec/unit/knife/key_list_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/knife/user_key_list'
-require 'chef/knife/client_key_list'
-require 'chef/knife/key_list'
-require 'chef/key'
+require "spec_helper"
+require "chef/knife/user_key_list"
+require "chef/knife/client_key_list"
+require "chef/knife/key_list"
+require "chef/key"
describe "key list commands that inherit knife" do
shared_examples_for "a key list command" do
@@ -78,9 +78,9 @@ describe Chef::Knife::KeyList do
let(:ui) { instance_double("Chef::Knife::UI") }
shared_examples_for "key list run command" do
- let(:key_list_object) {
+ let(:key_list_object) do
described_class.new(actor, list_method, ui, config)
- }
+ end
before do
allow(Chef::Key).to receive(list_method).and_return(http_response)
@@ -98,7 +98,7 @@ describe Chef::Knife::KeyList do
end
it "raises a Chef::Exceptions::KeyCommandInputError with the proper error message" do
- expect{ key_list_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_list_object.expired_and_non_expired_msg)
+ expect { key_list_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_list_object.expired_and_non_expired_msg)
end
end
@@ -191,26 +191,26 @@ describe Chef::Knife::KeyList do
context "when list_method is :list_by_user" do
it_should_behave_like "key list run command" do
let(:list_method) { :list_by_user }
- let(:http_response) {
+ let(:http_response) do
[
- {"uri"=>"https://api.opscode.piab/users/charmander/keys/non-expired1", "name"=>"non-expired1", "expired"=>false},
- {"uri"=>"https://api.opscode.piab/users/charmander/keys/non-expired2", "name"=>"non-expired2", "expired"=>false},
- {"uri"=>"https://api.opscode.piab/users/mary/keys/out-of-date", "name"=>"out-of-date", "expired"=>true}
+ { "uri" => "https://api.opscode.piab/users/charmander/keys/non-expired1", "name" => "non-expired1", "expired" => false },
+ { "uri" => "https://api.opscode.piab/users/charmander/keys/non-expired2", "name" => "non-expired2", "expired" => false },
+ { "uri" => "https://api.opscode.piab/users/mary/keys/out-of-date", "name" => "out-of-date", "expired" => true },
]
- }
+ end
end
end
context "when list_method is :list_by_client" do
it_should_behave_like "key list run command" do
let(:list_method) { :list_by_client }
- let(:http_response) {
+ let(:http_response) do
[
- {"uri"=>"https://api.opscode.piab/organizations/pokemon/clients/charmander/keys/non-expired1", "name"=>"non-expired1", "expired"=>false},
- {"uri"=>"https://api.opscode.piab/organizations/pokemon/clients/charmander/keys/non-expired2", "name"=>"non-expired2", "expired"=>false},
- {"uri"=>"https://api.opscode.piab/organizations/pokemon/clients/mary/keys/out-of-date", "name"=>"out-of-date", "expired"=>true}
+ { "uri" => "https://api.opscode.piab/organizations/pokemon/clients/charmander/keys/non-expired1", "name" => "non-expired1", "expired" => false },
+ { "uri" => "https://api.opscode.piab/organizations/pokemon/clients/charmander/keys/non-expired2", "name" => "non-expired2", "expired" => false },
+ { "uri" => "https://api.opscode.piab/organizations/pokemon/clients/mary/keys/out-of-date", "name" => "out-of-date", "expired" => true },
]
- }
+ end
end
end
end
diff --git a/spec/unit/knife/key_show_spec.rb b/spec/unit/knife/key_show_spec.rb
index 5a0d839e4f..139d4f91a2 100644
--- a/spec/unit/knife/key_show_spec.rb
+++ b/spec/unit/knife/key_show_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/knife/user_key_show'
-require 'chef/knife/client_key_show'
-require 'chef/knife/key_show'
-require 'chef/key'
+require "spec_helper"
+require "chef/knife/user_key_show"
+require "chef/knife/client_key_show"
+require "chef/knife/key_show"
+require "chef/key"
describe "key show commands that inherit knife" do
shared_examples_for "a key show command" do
@@ -45,8 +45,8 @@ describe "key show commands that inherit knife" do
context "when the service object is called" do
it "creates a new instance of Chef::Knife::KeyShow with the correct args" do
expect(Chef::Knife::KeyShow).to receive(:new).
- with("charmander-key", "charmander", command.load_method, command.ui).
- and_return(service_object)
+ with("charmander-key", "charmander", command.load_method, command.ui).
+ and_return(service_object)
command.service_object
end
end # when the service object is called
@@ -78,19 +78,19 @@ describe Chef::Knife::KeyShow do
let(:actor) { "charmander" }
let(:keyname) { "charmander" }
let(:ui) { instance_double("Chef::Knife::UI") }
- let(:expected_hash) {
+ let(:expected_hash) do
{
actor_field_name => "charmander",
"name" => "charmander-key",
"public_key" => "some-public-key",
- "expiration_date" => "infinity"
+ "expiration_date" => "infinity",
}
- }
+ end
shared_examples_for "key show run command" do
- let(:key_show_object) {
+ let(:key_show_object) do
described_class.new(keyname, actor, load_method, ui)
- }
+ end
before do
allow(key_show_object).to receive(:display_output)
@@ -113,14 +113,14 @@ describe Chef::Knife::KeyShow do
context "when load_method is :load_by_user" do
it_should_behave_like "key show run command" do
let(:load_method) { :load_by_user }
- let(:actor_field_name) { 'user' }
+ let(:actor_field_name) { "user" }
end
end
context "when load_method is :load_by_client" do
it_should_behave_like "key show run command" do
let(:load_method) { :load_by_client }
- let(:actor_field_name) { 'user' }
+ let(:actor_field_name) { "user" }
end
end
end
diff --git a/spec/unit/knife/knife_help.rb b/spec/unit/knife/knife_help.rb
index 293bae17f4..0369951511 100644
--- a/spec/unit/knife/knife_help.rb
+++ b/spec/unit/knife/knife_help.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::Help do
before(:each) do
diff --git a/spec/unit/knife/node_bulk_delete_spec.rb b/spec/unit/knife/node_bulk_delete_spec.rb
index 57a8d0bf64..2a3563e563 100644
--- a/spec/unit/knife/node_bulk_delete_spec.rb
+++ b/spec/unit/knife/node_bulk_delete_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::NodeBulkDelete do
before(:each) do
Chef::Log.logger = Logger.new(StringIO.new)
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::NodeBulkDelete.new
@knife.name_args = ["."]
@stdout = StringIO.new
@@ -37,14 +37,14 @@ describe Chef::Knife::NodeBulkDelete do
describe "when creating the list of nodes" do
it "fetches the node list" do
expected = @nodes.inject({}) do |inflatedish, (name, uri)|
- inflatedish[name] = Chef::Node.new.tap {|n| n.name(name)}
+ inflatedish[name] = Chef::Node.new.tap { |n| n.name(name) }
inflatedish
end
expect(Chef::Node).to receive(:list).and_return(@nodes)
# I hate not having == defined for anything :(
actual = @knife.all_nodes
expect(actual.keys).to match_array(expected.keys)
- expect(actual.values.map {|n| n.name }).to match_array(%w[adam brent jacob])
+ expect(actual.values.map { |n| n.name }).to match_array(%w{adam brent jacob})
end
end
@@ -78,10 +78,10 @@ describe Chef::Knife::NodeBulkDelete do
end
it "should only delete nodes that match the regex" do
- @knife.name_args = ['adam']
- expect(@inflatedish_list['adam']).to receive(:destroy)
- expect(@inflatedish_list['brent']).not_to receive(:destroy)
- expect(@inflatedish_list['jacob']).not_to receive(:destroy)
+ @knife.name_args = ["adam"]
+ expect(@inflatedish_list["adam"]).to receive(:destroy)
+ expect(@inflatedish_list["brent"]).not_to receive(:destroy)
+ expect(@inflatedish_list["jacob"]).not_to receive(:destroy)
@knife.run
end
@@ -92,6 +92,3 @@ describe Chef::Knife::NodeBulkDelete do
end
end
-
-
-
diff --git a/spec/unit/knife/node_delete_spec.rb b/spec/unit/knife/node_delete_spec.rb
index 0941d850e5..1a6b277dbb 100644
--- a/spec/unit/knife/node_delete_spec.rb
+++ b/spec/unit/knife/node_delete_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,26 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::NodeDelete do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::NodeDelete.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
- @knife.name_args = [ "adam" ]
+ @knife.name_args = %w{ adam ben }
allow(@knife).to receive(:output).and_return(true)
allow(@knife).to receive(:confirm).and_return(true)
- @node = Chef::Node.new()
- allow(@node).to receive(:destroy).and_return(true)
- allow(Chef::Node).to receive(:load).and_return(@node)
+
+ @adam_node = Chef::Node.new()
+ @ben_node = Chef::Node.new()
+ allow(@ben_node).to receive(:destroy).and_return(true)
+ allow(@adam_node).to receive(:destroy).and_return(true)
+ allow(Chef::Node).to receive(:load).with("adam").and_return(@adam_node)
+ allow(Chef::Node).to receive(:load).with("ben").and_return(@ben_node)
+
@stdout = StringIO.new
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
end
@@ -41,13 +46,15 @@ describe Chef::Knife::NodeDelete do
@knife.run
end
- it "should load the node" do
- expect(Chef::Node).to receive(:load).with("adam").and_return(@node)
+ it "should load the nodes" do
+ expect(Chef::Node).to receive(:load).with("adam").and_return(@adam_node)
+ expect(Chef::Node).to receive(:load).with("ben").and_return(@ben_node)
@knife.run
end
- it "should delete the node" do
- expect(@node).to receive(:destroy).and_return(@node)
+ it "should delete the nodes" do
+ expect(@adam_node).to receive(:destroy).and_return(@adam_node)
+ expect(@ben_node).to receive(:destroy).and_return(@ben_node)
@knife.run
end
@@ -59,8 +66,10 @@ describe Chef::Knife::NodeDelete do
describe "with -p or --print-after" do
it "should pretty print the node, formatted for display" do
@knife.config[:print_after] = true
- expect(@knife).to receive(:format_for_display).with(@node).and_return("poop")
- expect(@knife).to receive(:output).with("poop")
+ expect(@knife).to receive(:format_for_display).with(@adam_node).and_return("adam")
+ expect(@knife).to receive(:format_for_display).with(@ben_node).and_return("ben")
+ expect(@knife).to receive(:output).with("adam")
+ expect(@knife).to receive(:output).with("ben")
@knife.run
end
end
diff --git a/spec/unit/knife/node_edit_spec.rb b/spec/unit/knife/node_edit_spec.rb
index 58e2da2a1c..dedb5c949d 100644
--- a/spec/unit/knife/node_edit_spec.rb
+++ b/spec/unit/knife/node_edit_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
Chef::Knife::NodeEdit.load_deps
describe Chef::Knife::NodeEdit do
@@ -27,12 +27,12 @@ describe Chef::Knife::NodeEdit do
end
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::NodeEdit.new
@knife.config = {
- :editor => 'cat',
+ :editor => "cat",
:attribute => nil,
- :print_after => nil
+ :print_after => nil,
}
@knife.name_args = [ "adam" ]
@node = Chef::Node.new()
@@ -46,10 +46,10 @@ describe Chef::Knife::NodeEdit do
describe "after loading the node" do
before do
allow(@knife).to receive(:node).and_return(@node)
- @node.automatic_attrs = {:go => :away}
- @node.default_attrs = {:hide => :me}
- @node.override_attrs = {:dont => :show}
- @node.normal_attrs = {:do_show => :these}
+ @node.automatic_attrs = { :go => :away }
+ @node.default_attrs = { :hide => :me }
+ @node.override_attrs = { :dont => :show }
+ @node.normal_attrs = { :do_show => :these }
@node.chef_environment("prod")
@node.run_list("recipe[foo]")
end
@@ -59,7 +59,7 @@ describe Chef::Knife::NodeEdit do
expect(actual).not_to have_key("automatic")
expect(actual).not_to have_key("override")
expect(actual).not_to have_key("default")
- expect(actual["normal"]).to eq({"do_show" => "these"})
+ expect(actual["normal"]).to eq({ "do_show" => "these" })
expect(actual["run_list"]).to eq(["recipe[foo]"])
expect(actual["chef_environment"]).to eq("prod")
end
@@ -68,10 +68,10 @@ describe Chef::Knife::NodeEdit do
@knife.config[:all_attributes] = true
actual = deserialized_json_view
- expect(actual["automatic"]).to eq({"go" => "away"})
- expect(actual["override"]).to eq({"dont" => "show"})
- expect(actual["default"]).to eq({"hide" => "me"})
- expect(actual["normal"]).to eq({"do_show" => "these"})
+ expect(actual["automatic"]).to eq({ "go" => "away" })
+ expect(actual["override"]).to eq({ "dont" => "show" })
+ expect(actual["default"]).to eq({ "hide" => "me" })
+ expect(actual["normal"]).to eq({ "do_show" => "these" })
expect(actual["run_list"]).to eq(["recipe[foo]"])
expect(actual["chef_environment"]).to eq("prod")
end
@@ -101,15 +101,14 @@ describe Chef::Knife::NodeEdit do
it "raises an exception when editing is disabled" do
@knife.config[:disable_editing] = true
- expect{ subject }.to raise_error(SystemExit)
+ expect { subject }.to raise_error(SystemExit)
end
it "raises an exception when the editor is not set" do
@knife.config[:editor] = nil
- expect{ subject }.to raise_error(SystemExit)
+ expect { subject }.to raise_error(SystemExit)
end
end
end
-
diff --git a/spec/unit/knife/node_environment_set_spec.rb b/spec/unit/knife/node_environment_set_spec.rb
index 10267915d7..7ceafdad78 100644
--- a/spec/unit/knife/node_environment_set_spec.rb
+++ b/spec/unit/knife/node_environment_set_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Jimmy McCrory (<jimmy.mccrory@gmail.com>)
-# Copyright:: Copyright (c) 2014 Jimmy McCrory
+# Copyright:: Copyright 2014-2016, Jimmy McCrory
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::NodeEnvironmentSet do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::NodeEnvironmentSet.new
- @knife.name_args = [ "adam", "bar" ]
+ @knife.name_args = %w{adam bar}
allow(@knife).to receive(:output).and_return(true)
@node = Chef::Node.new()
@node.name("knifetest-node")
@@ -39,7 +39,7 @@ describe Chef::Knife::NodeEnvironmentSet do
it "should update the environment" do
@knife.run
- expect(@node.chef_environment).to eq('bar')
+ expect(@node.chef_environment).to eq("bar")
end
it "should save the node" do
@@ -52,29 +52,5 @@ describe Chef::Knife::NodeEnvironmentSet do
@knife.run
end
- describe "with no environment" do
- # Set up outputs for inspection later
- before(:each) do
- @stdout = StringIO.new
- @stderr = StringIO.new
-
- allow(@knife.ui).to receive(:stdout).and_return(@stdout)
- allow(@knife.ui).to receive(:stderr).and_return(@stderr)
- end
-
- it "should exit" do
- @knife.name_args = [ "adam" ]
- expect { @knife.run }.to raise_error SystemExit
- end
-
- it "should show the user the usage and an error" do
- @knife.name_args = [ "adam" ]
-
- begin ; @knife.run ; rescue SystemExit ; end
-
- expect(@stdout.string).to eq "USAGE: knife node environment set NODE ENVIRONMENT\n"
- expect(@stderr.string).to eq "FATAL: You must specify a node name and an environment.\n"
- end
- end
end
end
diff --git a/spec/unit/knife/node_from_file_spec.rb b/spec/unit/knife/node_from_file_spec.rb
index 623904753e..61c63c150e 100644
--- a/spec/unit/knife/node_from_file_spec.rb
+++ b/spec/unit/knife/node_from_file_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
Chef::Knife::NodeFromFile.load_deps
describe Chef::Knife::NodeFromFile do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::NodeFromFile.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
@knife.name_args = [ "adam.rb" ]
allow(@knife).to receive(:output).and_return(true)
@@ -39,7 +39,7 @@ describe Chef::Knife::NodeFromFile do
describe "run" do
it "should load from a file" do
- expect(@knife.loader).to receive(:load_from).with('nodes', 'adam.rb').and_return(@node)
+ expect(@knife.loader).to receive(:load_from).with("nodes", "adam.rb").and_return(@node)
@knife.run
end
diff --git a/spec/unit/knife/node_list_spec.rb b/spec/unit/knife/node_list_spec.rb
index 71edea78f7..b94101ef7a 100644
--- a/spec/unit/knife/node_list_spec.rb
+++ b/spec/unit/knife/node_list_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,17 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::NodeList do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
Chef::Config[:environment] = nil # reset this value each time, as it is not reloaded
@knife = Chef::Knife::NodeList.new
allow(@knife).to receive(:output).and_return(true)
@list = {
"foo" => "http://example.com/foo",
- "bar" => "http://example.com/foo"
+ "bar" => "http://example.com/foo",
}
allow(Chef::Node).to receive(:list).and_return(@list)
allow(Chef::Node).to receive(:list_by_environment).and_return(@list)
@@ -40,7 +40,7 @@ describe Chef::Knife::NodeList do
it "should pretty print the list" do
expect(Chef::Node).to receive(:list).and_return(@list)
- expect(@knife).to receive(:output).with([ "bar", "foo" ])
+ expect(@knife).to receive(:output).with(%w{bar foo})
@knife.run
end
@@ -60,4 +60,3 @@ describe Chef::Knife::NodeList do
end
end
end
-
diff --git a/spec/unit/knife/node_run_list_add_spec.rb b/spec/unit/knife/node_run_list_add_spec.rb
index 92fbfd23fe..e11bf78029 100644
--- a/spec/unit/knife/node_run_list_add_spec.rb
+++ b/spec/unit/knife/node_run_list_add_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::NodeRunListAdd do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::NodeRunListAdd.new
@knife.config = {
- :after => nil
+ :after => nil,
}
@knife.name_args = [ "adam", "role[monkey]" ]
allow(@knife).to receive(:output).and_return(true)
@@ -40,7 +40,7 @@ describe Chef::Knife::NodeRunListAdd do
it "should add to the run list" do
@knife.run
- expect(@node.run_list[0]).to eq('role[monkey]')
+ expect(@node.run_list[0]).to eq("role[monkey]")
end
it "should save the node" do
@@ -143,6 +143,3 @@ describe Chef::Knife::NodeRunListAdd do
end
end
end
-
-
-
diff --git a/spec/unit/knife/node_run_list_remove_spec.rb b/spec/unit/knife/node_run_list_remove_spec.rb
index a279a59635..4f753d7991 100644
--- a/spec/unit/knife/node_run_list_remove_spec.rb
+++ b/spec/unit/knife/node_run_list_remove_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::NodeRunListRemove do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::NodeRunListRemove.new
@knife.config[:print_after] = nil
@knife.name_args = [ "adam", "role[monkey]" ]
@@ -43,7 +43,7 @@ describe Chef::Knife::NodeRunListRemove do
it "should remove the item from the run list" do
@knife.run
- expect(@node.run_list[0]).not_to eq('role[monkey]')
+ expect(@node.run_list[0]).not_to eq("role[monkey]")
end
it "should save the node" do
@@ -53,50 +53,50 @@ describe Chef::Knife::NodeRunListRemove do
it "should print the run list" do
@knife.config[:print_after] = true
- expect(@knife.ui).to receive(:output).with({ "knifetest-node" => { 'run_list' => [] } })
+ expect(@knife.ui).to receive(:output).with({ "knifetest-node" => { "run_list" => [] } })
@knife.run
end
describe "run with a list of roles and recipes" do
it "should remove the items from the run list" do
- @node.run_list << 'role[monkey]'
- @node.run_list << 'recipe[duck::type]'
- @knife.name_args = [ 'adam', 'role[monkey],recipe[duck::type]' ]
+ @node.run_list << "role[monkey]"
+ @node.run_list << "recipe[duck::type]"
+ @knife.name_args = [ "adam", "role[monkey],recipe[duck::type]" ]
@knife.run
- expect(@node.run_list).not_to include('role[monkey]')
- expect(@node.run_list).not_to include('recipe[duck::type]')
+ expect(@node.run_list).not_to include("role[monkey]")
+ expect(@node.run_list).not_to include("recipe[duck::type]")
end
it "should remove the items from the run list when name args contains whitespace" do
- @node.run_list << 'role[monkey]'
- @node.run_list << 'recipe[duck::type]'
- @knife.name_args = [ 'adam', 'role[monkey], recipe[duck::type]' ]
+ @node.run_list << "role[monkey]"
+ @node.run_list << "recipe[duck::type]"
+ @knife.name_args = [ "adam", "role[monkey], recipe[duck::type]" ]
@knife.run
- expect(@node.run_list).not_to include('role[monkey]')
- expect(@node.run_list).not_to include('recipe[duck::type]')
+ expect(@node.run_list).not_to include("role[monkey]")
+ expect(@node.run_list).not_to include("recipe[duck::type]")
end
it "should remove the items from the run list when name args contains multiple run lists" do
- @node.run_list << 'role[blah]'
- @node.run_list << 'recipe[duck::type]'
- @knife.name_args = [ 'adam', 'role[monkey], recipe[duck::type]', 'role[blah]' ]
+ @node.run_list << "role[blah]"
+ @node.run_list << "recipe[duck::type]"
+ @knife.name_args = [ "adam", "role[monkey], recipe[duck::type]", "role[blah]" ]
@knife.run
- expect(@node.run_list).not_to include('role[monkey]')
- expect(@node.run_list).not_to include('recipe[duck::type]')
+ expect(@node.run_list).not_to include("role[monkey]")
+ expect(@node.run_list).not_to include("recipe[duck::type]")
end
it "should warn when the thing to remove is not in the runlist" do
- @node.run_list << 'role[blah]'
- @node.run_list << 'recipe[duck::type]'
- @knife.name_args = [ 'adam', 'role[blork]' ]
+ @node.run_list << "role[blah]"
+ @node.run_list << "recipe[duck::type]"
+ @knife.name_args = [ "adam", "role[blork]" ]
expect(@knife.ui).to receive(:warn).with("role[blork] is not in the run list")
@knife.run
end
it "should warn even more when the thing to remove is not in the runlist and unqualified" do
- @node.run_list << 'role[blah]'
- @node.run_list << 'recipe[duck::type]'
- @knife.name_args = [ 'adam', 'blork' ]
+ @node.run_list << "role[blah]"
+ @node.run_list << "recipe[duck::type]"
+ @knife.name_args = %w{adam blork}
expect(@knife.ui).to receive(:warn).with("blork is not in the run list")
expect(@knife.ui).to receive(:warn).with(/did you forget recipe\[\] or role\[\]/)
@knife.run
diff --git a/spec/unit/knife/node_run_list_set_spec.rb b/spec/unit/knife/node_run_list_set_spec.rb
index 68daaafd70..bd55edb997 100644
--- a/spec/unit/knife/node_run_list_set_spec.rb
+++ b/spec/unit/knife/node_run_list_set_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Mike Fiedler (<miketheman@gmail.com>)
-# Copyright:: Copyright (c) 2013 Mike Fiedler
+# Copyright:: Copyright 2013-2016, Mike Fiedler
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::NodeRunListSet do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::NodeRunListSet.new
@knife.config = {}
@knife.name_args = [ "adam", "role[monkey]" ]
@@ -38,7 +38,7 @@ describe Chef::Knife::NodeRunListSet do
it "should set the run list" do
@knife.run
- expect(@node.run_list[0]).to eq('role[monkey]')
+ expect(@node.run_list[0]).to eq("role[monkey]")
end
it "should save the node" do
@@ -111,30 +111,5 @@ describe Chef::Knife::NodeRunListSet do
end
end
- describe "with no role or recipe" do
- # Set up outputs for inspection later
- before(:each) do
- @stdout = StringIO.new
- @stderr = StringIO.new
-
- allow(@knife.ui).to receive(:stdout).and_return(@stdout)
- allow(@knife.ui).to receive(:stderr).and_return(@stderr)
- end
-
- it "should exit" do
- @knife.name_args = [ "adam" ]
- expect { @knife.run }.to raise_error SystemExit
- end
-
- it "should show the user" do
- @knife.name_args = [ "adam" ]
-
- begin ; @knife.run ; rescue SystemExit ; end
-
- expect(@stdout.string).to eq "USAGE: knife node run_list set NODE ENTRIES (options)\n"
- expect(@stderr.string).to eq "FATAL: You must supply both a node name and a run list.\n"
- end
- end
-
end
end
diff --git a/spec/unit/knife/node_show_spec.rb b/spec/unit/knife/node_show_spec.rb
index 4806354b60..2f684b27f4 100644
--- a/spec/unit/knife/node_show_spec.rb
+++ b/spec/unit/knife/node_show_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::NodeShow do
let(:node) do
node = Chef::Node.new()
node.name("adam")
- node.run_list = ['role[base]']
+ node.run_list = ["role[base]"]
node
end
@@ -34,7 +34,7 @@ describe Chef::Knife::NodeShow do
end
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
end
describe "run" do
@@ -54,10 +54,10 @@ describe Chef::Knife::NodeShow do
end
it "should pretty print json" do
- knife.config[:format] = 'json'
+ knife.config[:format] = "json"
stdout = StringIO.new
allow(knife.ui).to receive(:stdout).and_return(stdout)
- expect(Chef::Node).to receive(:load).with('adam').and_return(node)
+ expect(Chef::Node).to receive(:load).with("adam").and_return(node)
knife.run
expect(stdout.string).to eql("{\n \"name\": \"adam\",\n \"chef_environment\": \"_default\",\n \"run_list\": [\n\n]\n,\n \"normal\": {\n\n }\n}\n")
end
diff --git a/spec/unit/knife/osc_user_create_spec.rb b/spec/unit/knife/osc_user_create_spec.rb
index e4ed78fe2b..0413d46f78 100644
--- a/spec/unit/knife/osc_user_create_spec.rb
+++ b/spec/unit/knife/osc_user_create_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
Chef::Knife::OscUserCreate.load_deps
@@ -34,17 +34,17 @@ describe Chef::Knife::OscUserCreate do
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
allow(@knife.ui).to receive(:stderr).and_return(@stderr)
- @knife.name_args = [ 'a_user' ]
+ @knife.name_args = [ "a_user" ]
@knife.config[:user_password] = "foobar"
@user = Chef::User.new
@user.name "a_user"
@user_with_private_key = Chef::User.new
@user_with_private_key.name "a_user"
- @user_with_private_key.private_key 'private_key'
+ @user_with_private_key.private_key "private_key"
allow(@user).to receive(:create).and_return(@user_with_private_key)
allow(Chef::User).to receive(:new).and_return(@user)
allow(Chef::User).to receive(:from_hash).and_return(@user)
- allow(@knife).to receive(:edit_data).and_return(@user.to_hash)
+ allow(@knife).to receive(:edit_hash).and_return(@user.to_hash)
end
it "creates a new user" do
@@ -61,7 +61,7 @@ describe Chef::Knife::OscUserCreate do
end
it "exits with an error if password is blank" do
- @knife.config[:user_password] = ''
+ @knife.config[:user_password] = ""
expect { @knife.run }.to raise_error SystemExit
expect(@stderr.string).to match /You must specify a non-blank password/
end
@@ -79,14 +79,14 @@ describe Chef::Knife::OscUserCreate do
end
it "allows you to edit the data" do
- expect(@knife).to receive(:edit_data).with(@user)
+ expect(@knife).to receive(:edit_hash).with(@user)
@knife.run
end
it "writes the private key to a file when --file is specified" do
@knife.config[:file] = "/tmp/a_file"
filehandle = double("filehandle")
- expect(filehandle).to receive(:print).with('private_key')
+ expect(filehandle).to receive(:print).with("private_key")
expect(File).to receive(:open).with("/tmp/a_file", "w").and_yield(filehandle)
@knife.run
end
diff --git a/spec/unit/knife/osc_user_delete_spec.rb b/spec/unit/knife/osc_user_delete_spec.rb
index 4a3ec4228f..6e90988156 100644
--- a/spec/unit/knife/osc_user_delete_spec.rb
+++ b/spec/unit/knife/osc_user_delete_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
# DEPRECATION NOTE
# This code only remains to support users still operating with
@@ -27,15 +27,15 @@ describe Chef::Knife::OscUserDelete do
before(:each) do
Chef::Knife::OscUserDelete.load_deps
@knife = Chef::Knife::OscUserDelete.new
- @knife.name_args = [ 'my_user' ]
+ @knife.name_args = [ "my_user" ]
end
- it 'deletes the user' do
- expect(@knife).to receive(:delete_object).with(Chef::User, 'my_user')
+ it "deletes the user" do
+ expect(@knife).to receive(:delete_object).with(Chef::User, "my_user")
@knife.run
end
- it 'prints usage and exits when a user name is not provided' do
+ it "prints usage and exits when a user name is not provided" do
@knife.name_args = []
expect(@knife).to receive(:show_usage)
expect(@knife.ui).to receive(:fatal)
diff --git a/spec/unit/knife/osc_user_edit_spec.rb b/spec/unit/knife/osc_user_edit_spec.rb
index 279f2e30ef..59fb152b5b 100644
--- a/spec/unit/knife/osc_user_edit_spec.rb
+++ b/spec/unit/knife/osc_user_edit_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
# DEPRECATION NOTE
# This code only remains to support users still operating with
@@ -32,18 +32,18 @@ describe Chef::Knife::OscUserEdit do
@knife = Chef::Knife::OscUserEdit.new
allow(@knife.ui).to receive(:stderr).and_return(@stderr)
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
- @knife.name_args = [ 'my_user' ]
+ @knife.name_args = [ "my_user" ]
@knife.config[:disable_editing] = true
end
- it 'loads and edits the user' do
+ it "loads and edits the user" do
data = { :name => "my_user" }
allow(Chef::User).to receive(:load).with("my_user").and_return(data)
- expect(@knife).to receive(:edit_data).with(data).and_return(data)
+ expect(@knife).to receive(:edit_hash).with(data).and_return(data)
@knife.run
end
- it 'prints usage and exits when a user name is not provided' do
+ it "prints usage and exits when a user name is not provided" do
@knife.name_args = []
expect(@knife).to receive(:show_usage)
expect(@knife.ui).to receive(:fatal)
diff --git a/spec/unit/knife/osc_user_list_spec.rb b/spec/unit/knife/osc_user_list_spec.rb
index f496a414b8..10682eb96f 100644
--- a/spec/unit/knife/osc_user_list_spec.rb
+++ b/spec/unit/knife/osc_user_list_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Steven Danna
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
# DEPRECATION NOTE
# This code only remains to support users still operating with
@@ -29,7 +29,7 @@ describe Chef::Knife::OscUserList do
@knife = Chef::Knife::OscUserList.new
end
- it 'lists the users' do
+ it "lists the users" do
expect(Chef::User).to receive(:list)
expect(@knife).to receive(:format_list_for_display)
@knife.run
diff --git a/spec/unit/knife/osc_user_reregister_spec.rb b/spec/unit/knife/osc_user_reregister_spec.rb
index 989eb180f1..ae6b4be9a8 100644
--- a/spec/unit/knife/osc_user_reregister_spec.rb
+++ b/spec/unit/knife/osc_user_reregister_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
# DEPRECATION NOTE
# This code only remains to support users still operating with
@@ -27,31 +27,31 @@ describe Chef::Knife::OscUserReregister do
before(:each) do
Chef::Knife::OscUserReregister.load_deps
@knife = Chef::Knife::OscUserReregister.new
- @knife.name_args = [ 'a_user' ]
- @user_mock = double('user_mock', :private_key => "private_key")
+ @knife.name_args = [ "a_user" ]
+ @user_mock = double("user_mock", :private_key => "private_key")
allow(Chef::User).to receive(:load).and_return(@user_mock)
@stdout = StringIO.new
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
end
- it 'prints usage and exits when a user name is not provided' do
+ it "prints usage and exits when a user name is not provided" do
@knife.name_args = []
expect(@knife).to receive(:show_usage)
expect(@knife.ui).to receive(:fatal)
expect { @knife.run }.to raise_error(SystemExit)
end
- it 'reregisters the user and prints the key' do
+ it "reregisters the user and prints the key" do
expect(@user_mock).to receive(:reregister).and_return(@user_mock)
@knife.run
expect(@stdout.string).to match( /private_key/ )
end
- it 'writes the private key to a file when --file is specified' do
+ it "writes the private key to a file when --file is specified" do
expect(@user_mock).to receive(:reregister).and_return(@user_mock)
- @knife.config[:file] = '/tmp/a_file'
+ @knife.config[:file] = "/tmp/a_file"
filehandle = StringIO.new
- expect(File).to receive(:open).with('/tmp/a_file', 'w').and_yield(filehandle)
+ expect(File).to receive(:open).with("/tmp/a_file", "w").and_yield(filehandle)
@knife.run
expect(filehandle.string).to eq("private_key")
end
diff --git a/spec/unit/knife/osc_user_show_spec.rb b/spec/unit/knife/osc_user_show_spec.rb
index 18d2086099..d6efbef870 100644
--- a/spec/unit/knife/osc_user_show_spec.rb
+++ b/spec/unit/knife/osc_user_show_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
# DEPRECATION NOTE
# This code only remains to support users still operating with
@@ -27,17 +27,17 @@ describe Chef::Knife::OscUserShow do
before(:each) do
Chef::Knife::OscUserShow.load_deps
@knife = Chef::Knife::OscUserShow.new
- @knife.name_args = [ 'my_user' ]
- @user_mock = double('user_mock')
+ @knife.name_args = [ "my_user" ]
+ @user_mock = double("user_mock")
end
- it 'loads and displays the user' do
- expect(Chef::User).to receive(:load).with('my_user').and_return(@user_mock)
+ it "loads and displays the user" do
+ expect(Chef::User).to receive(:load).with("my_user").and_return(@user_mock)
expect(@knife).to receive(:format_for_display).with(@user_mock)
@knife.run
end
- it 'prints usage and exits when a user name is not provided' do
+ it "prints usage and exits when a user name is not provided" do
@knife.name_args = []
expect(@knife).to receive(:show_usage)
expect(@knife.ui).to receive(:fatal)
diff --git a/spec/unit/knife/raw_spec.rb b/spec/unit/knife/raw_spec.rb
index ab929abd39..9202998fb9 100644
--- a/spec/unit/knife/raw_spec.rb
+++ b/spec/unit/knife/raw_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,11 +15,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::Raw do
let(:rest) do
- r = double('Chef::Knife::Raw::RawInputServerAPI')
+ r = double("Chef::Knife::Raw::RawInputServerAPI")
allow(Chef::Knife::Raw::RawInputServerAPI).to receive(:new).and_return(r)
r
end
@@ -35,8 +35,8 @@ describe Chef::Knife::Raw do
it "should set the x-ops-request-source header when --proxy-auth is set" do
knife.config[:proxy_auth] = true
expect(rest).to receive(:request).with(:GET, "/nodes",
- { 'Content-Type' => 'application/json',
- 'x-ops-request-source' => 'web'}, false)
+ { "Content-Type" => "application/json",
+ "x-ops-request-source" => "web" }, false)
knife.run
end
end
diff --git a/spec/unit/knife/role_bulk_delete_spec.rb b/spec/unit/knife/role_bulk_delete_spec.rb
index 5b79e52a04..e9054c1d00 100644
--- a/spec/unit/knife/role_bulk_delete_spec.rb
+++ b/spec/unit/knife/role_bulk_delete_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleBulkDelete do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::RoleBulkDelete.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
@knife.name_args = ["."]
@stdout = StringIO.new
diff --git a/spec/unit/knife/role_create_spec.rb b/spec/unit/knife/role_create_spec.rb
index fb748c51f6..9466d9642c 100644
--- a/spec/unit/knife/role_create_spec.rb
+++ b/spec/unit/knife/role_create_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleCreate do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::RoleCreate.new
@knife.config = {
- :description => nil
+ :description => nil,
}
@knife.name_args = [ "adam" ]
allow(@knife).to receive(:output).and_return(true)
@@ -52,7 +52,7 @@ describe Chef::Knife::RoleCreate do
end
it "should allow you to edit the data" do
- expect(@knife).to receive(:edit_data).with(@role)
+ expect(@knife).to receive(:edit_data).with(@role, object_class: Chef::Role)
@knife.run
end
diff --git a/spec/unit/knife/role_delete_spec.rb b/spec/unit/knife/role_delete_spec.rb
index b1a0d90410..f095e5ba2d 100644
--- a/spec/unit/knife/role_delete_spec.rb
+++ b/spec/unit/knife/role_delete_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleDelete do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::RoleDelete.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
@knife.name_args = [ "adam" ]
allow(@knife).to receive(:output).and_return(true)
diff --git a/spec/unit/knife/role_edit_spec.rb b/spec/unit/knife/role_edit_spec.rb
index 0975c6458d..5e03b7aef3 100644
--- a/spec/unit/knife/role_edit_spec.rb
+++ b/spec/unit/knife/role_edit_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleEdit do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::RoleEdit.new
@knife.config[:print_after] = nil
@knife.name_args = [ "adam" ]
@@ -39,7 +39,7 @@ describe Chef::Knife::RoleEdit do
end
it "should edit the role data" do
- expect(@knife.ui).to receive(:edit_data).with(@role)
+ expect(@knife.ui).to receive(:edit_data).with(@role, object_class: Chef::Role)
@knife.run
end
@@ -47,7 +47,7 @@ describe Chef::Knife::RoleEdit do
pansy = Chef::Role.new
@role.name("new_role_name")
- expect(@knife.ui).to receive(:edit_data).with(@role).and_return(pansy)
+ expect(@knife.ui).to receive(:edit_data).with(@role, object_class: Chef::Role).and_return(pansy)
expect(pansy).to receive(:save)
@knife.run
end
@@ -55,7 +55,7 @@ describe Chef::Knife::RoleEdit do
it "should not save the unedited role data" do
pansy = Chef::Role.new
- expect(@knife.ui).to receive(:edit_data).with(@role).and_return(pansy)
+ expect(@knife.ui).to receive(:edit_data).with(@role, object_class: Chef::Role).and_return(pansy)
expect(pansy).not_to receive(:save)
@knife.run
@@ -75,5 +75,3 @@ describe Chef::Knife::RoleEdit do
end
end
end
-
-
diff --git a/spec/unit/knife/role_env_run_list_add_spec.rb b/spec/unit/knife/role_env_run_list_add_spec.rb
index f286d5fd0d..4738101f90 100644
--- a/spec/unit/knife/role_env_run_list_add_spec.rb
+++ b/spec/unit/knife/role_env_run_list_add_spec.rb
@@ -1,15 +1,15 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Will Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleEnvRunListAdd do
before(:each) do
@@ -25,11 +25,11 @@ describe Chef::Knife::RoleEnvRunListAdd do
# Chef::Config[:env_name] = "QA"
@knife = Chef::Knife::RoleEnvRunListAdd.new
@knife.config = {
- :after => nil
+ :after => nil,
}
@knife.name_args = [ "will", "QA", "role[monkey]" ]
allow(@knife).to receive(:output).and_return(true)
- @role = Chef::Role.new()
+ @role = Chef::Role.new()
allow(@role).to receive(:save).and_return(true)
allow(Chef::Role).to receive(:load).and_return(@role)
end
@@ -48,7 +48,7 @@ describe Chef::Knife::RoleEnvRunListAdd do
it "should have a QA environment" do
@knife.run
- expect(@role.active_run_list_for('QA')).to eq('QA')
+ expect(@role.active_run_list_for("QA")).to eq("QA")
end
it "should load the role named will" do
@@ -58,7 +58,7 @@ describe Chef::Knife::RoleEnvRunListAdd do
it "should be able to add an environment specific run list" do
@knife.run
- expect(@role.run_list_for('QA')[0]).to eq('role[monkey]')
+ expect(@role.run_list_for("QA")[0]).to eq("role[monkey]")
end
it "should save the role" do
@@ -180,7 +180,7 @@ describe Chef::Knife::RoleEnvRunListAdd do
expect(@role.run_list[1]).to be_nil
end
end
-
+
describe "with more than one command" do
it "should be able to the environment run list by running multiple knife commands" do
@knife.name_args = [ "will", "QA", "role[blue]," ]
diff --git a/spec/unit/knife/role_env_run_list_clear_spec.rb b/spec/unit/knife/role_env_run_list_clear_spec.rb
index 525376c358..c9c24858c0 100644
--- a/spec/unit/knife/role_env_run_list_clear_spec.rb
+++ b/spec/unit/knife/role_env_run_list_clear_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Will Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,20 +17,20 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleEnvRunListClear do
before(:each) do
- Chef::Config[:role_name] = "will"
- Chef::Config[:env_name] = "QA"
+ Chef::Config[:role_name] = "will"
+ Chef::Config[:env_name] = "QA"
@setup = Chef::Knife::RoleEnvRunListAdd.new
@setup.name_args = [ "will", "QA", "role[monkey]", "role[person]" ]
@knife = Chef::Knife::RoleEnvRunListClear.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
- @knife.name_args = [ "will", "QA" ]
+ @knife.name_args = %w{will QA}
allow(@knife).to receive(:output).and_return(true)
@role = Chef::Role.new()
@@ -42,11 +42,8 @@ describe Chef::Knife::RoleEnvRunListClear do
end
-
-
describe "run" do
-
# it "should display all the things" do
# @knife.run
# @role.to_json.should == 'show all the things'
@@ -57,44 +54,41 @@ describe Chef::Knife::RoleEnvRunListClear do
@knife.run
end
- it "should remove the item from the run list" do
- @setup.run
- @knife.run
- expect(@role.run_list_for('QA')[0]).to be_nil
- expect(@role.run_list[0]).to be_nil
- end
+ it "should remove the item from the run list" do
+ @setup.run
+ @knife.run
+ expect(@role.run_list_for("QA")[0]).to be_nil
+ expect(@role.run_list[0]).to be_nil
+ end
- it "should save the node" do
- expect(@role).to receive(:save).and_return(true)
- @knife.run
- end
+ it "should save the node" do
+ expect(@role).to receive(:save).and_return(true)
+ @knife.run
+ end
- it "should print the run list" do
- expect(@knife).to receive(:output).and_return(true)
- @knife.config[:print_after] = true
- @setup.run
- @knife.run
- end
+ it "should print the run list" do
+ expect(@knife).to receive(:output).and_return(true)
+ @knife.config[:print_after] = true
+ @setup.run
+ @knife.run
+ end
- describe "should clear an environmental run list of roles and recipes" do
- it "should remove the items from the run list" do
- @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
- @setup.run
- @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
- @setup.run
- @knife.name_args = [ 'will', 'QA' ]
- @knife.run
- expect(@role.run_list_for('QA')[0]).to be_nil
- expect(@role.run_list_for('PRD')[0]).to eq('recipe[orange::chicken]')
- expect(@role.run_list_for('PRD')[1]).to eq('role[monkey]')
- expect(@role.run_list_for('PRD')[2]).to eq('recipe[duck::type]')
- expect(@role.run_list_for('PRD')[3]).to eq('role[person]')
- expect(@role.run_list_for('PRD')[4]).to eq('role[bird]')
- expect(@role.run_list_for('PRD')[5]).to eq('role[town]')
- end
- end
+ describe "should clear an environmental run list of roles and recipes" do
+ it "should remove the items from the run list" do
+ @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+ @setup.run
+ @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+ @setup.run
+ @knife.name_args = %w{will QA}
+ @knife.run
+ expect(@role.run_list_for("QA")[0]).to be_nil
+ expect(@role.run_list_for("PRD")[0]).to eq("recipe[orange::chicken]")
+ expect(@role.run_list_for("PRD")[1]).to eq("role[monkey]")
+ expect(@role.run_list_for("PRD")[2]).to eq("recipe[duck::type]")
+ expect(@role.run_list_for("PRD")[3]).to eq("role[person]")
+ expect(@role.run_list_for("PRD")[4]).to eq("role[bird]")
+ expect(@role.run_list_for("PRD")[5]).to eq("role[town]")
+ end
+ end
end
end
-
-
-
diff --git a/spec/unit/knife/role_env_run_list_remove_spec.rb b/spec/unit/knife/role_env_run_list_remove_spec.rb
index a15d0af691..8a077f1de3 100644
--- a/spec/unit/knife/role_env_run_list_remove_spec.rb
+++ b/spec/unit/knife/role_env_run_list_remove_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Will Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,18 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleEnvRunListRemove do
before(:each) do
- Chef::Config[:role_name] = "will"
- Chef::Config[:env_name] = "QA"
+ Chef::Config[:role_name] = "will"
+ Chef::Config[:env_name] = "QA"
@setup = Chef::Knife::RoleEnvRunListAdd.new
@setup.name_args = [ "will", "QA", "role[monkey]", "role[person]" ]
@knife = Chef::Knife::RoleEnvRunListRemove.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
@knife.name_args = [ "will", "QA", "role[monkey]" ]
allow(@knife).to receive(:output).and_return(true)
@@ -42,11 +42,8 @@ describe Chef::Knife::RoleEnvRunListRemove do
end
-
-
describe "run" do
-
# it "should display all the things" do
# @knife.run
# @role.to_json.should == 'show all the things'
@@ -57,52 +54,49 @@ describe Chef::Knife::RoleEnvRunListRemove do
@knife.run
end
- it "should remove the item from the run list" do
- @setup.run
- @knife.run
- expect(@role.run_list_for('QA')[0]).not_to eq('role[monkey]')
- expect(@role.run_list_for('QA')[0]).to eq('role[person]')
- expect(@role.run_list[0]).to be_nil
- end
+ it "should remove the item from the run list" do
+ @setup.run
+ @knife.run
+ expect(@role.run_list_for("QA")[0]).not_to eq("role[monkey]")
+ expect(@role.run_list_for("QA")[0]).to eq("role[person]")
+ expect(@role.run_list[0]).to be_nil
+ end
- it "should save the node" do
- expect(@role).to receive(:save).and_return(true)
- @knife.run
- end
+ it "should save the node" do
+ expect(@role).to receive(:save).and_return(true)
+ @knife.run
+ end
- it "should print the run list" do
- expect(@knife).to receive(:output).and_return(true)
- @knife.config[:print_after] = true
- @setup.run
- @knife.run
- end
+ it "should print the run list" do
+ expect(@knife).to receive(:output).and_return(true)
+ @knife.config[:print_after] = true
+ @setup.run
+ @knife.run
+ end
- describe "run with a list of roles and recipes" do
- it "should remove the items from the run list" do
- @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
- @setup.run
- @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
- @setup.run
- @knife.name_args = [ 'will', 'QA', 'role[monkey]' ]
- @knife.run
- @knife.name_args = [ 'will', 'QA', 'recipe[duck::type]' ]
- @knife.run
- expect(@role.run_list_for('QA')).not_to include('role[monkey]')
- expect(@role.run_list_for('QA')).not_to include('recipe[duck::type]')
- expect(@role.run_list_for('QA')[0]).to eq('recipe[orange::chicken]')
- expect(@role.run_list_for('QA')[1]).to eq('role[person]')
- expect(@role.run_list_for('QA')[2]).to eq('role[bird]')
- expect(@role.run_list_for('QA')[3]).to eq('role[town]')
- expect(@role.run_list_for('PRD')[0]).to eq('recipe[orange::chicken]')
- expect(@role.run_list_for('PRD')[1]).to eq('role[monkey]')
- expect(@role.run_list_for('PRD')[2]).to eq('recipe[duck::type]')
- expect(@role.run_list_for('PRD')[3]).to eq('role[person]')
- expect(@role.run_list_for('PRD')[4]).to eq('role[bird]')
- expect(@role.run_list_for('PRD')[5]).to eq('role[town]')
- end
- end
+ describe "run with a list of roles and recipes" do
+ it "should remove the items from the run list" do
+ @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+ @setup.run
+ @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+ @setup.run
+ @knife.name_args = [ "will", "QA", "role[monkey]" ]
+ @knife.run
+ @knife.name_args = [ "will", "QA", "recipe[duck::type]" ]
+ @knife.run
+ expect(@role.run_list_for("QA")).not_to include("role[monkey]")
+ expect(@role.run_list_for("QA")).not_to include("recipe[duck::type]")
+ expect(@role.run_list_for("QA")[0]).to eq("recipe[orange::chicken]")
+ expect(@role.run_list_for("QA")[1]).to eq("role[person]")
+ expect(@role.run_list_for("QA")[2]).to eq("role[bird]")
+ expect(@role.run_list_for("QA")[3]).to eq("role[town]")
+ expect(@role.run_list_for("PRD")[0]).to eq("recipe[orange::chicken]")
+ expect(@role.run_list_for("PRD")[1]).to eq("role[monkey]")
+ expect(@role.run_list_for("PRD")[2]).to eq("recipe[duck::type]")
+ expect(@role.run_list_for("PRD")[3]).to eq("role[person]")
+ expect(@role.run_list_for("PRD")[4]).to eq("role[bird]")
+ expect(@role.run_list_for("PRD")[5]).to eq("role[town]")
+ end
+ end
end
end
-
-
-
diff --git a/spec/unit/knife/role_env_run_list_replace_spec.rb b/spec/unit/knife/role_env_run_list_replace_spec.rb
index ea48601b8d..08dcdd90e2 100644
--- a/spec/unit/knife/role_env_run_list_replace_spec.rb
+++ b/spec/unit/knife/role_env_run_list_replace_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Will Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,18 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleEnvRunListReplace do
before(:each) do
- Chef::Config[:role_name] = "will"
- Chef::Config[:env_name] = "QA"
+ Chef::Config[:role_name] = "will"
+ Chef::Config[:env_name] = "QA"
@setup = Chef::Knife::RoleEnvRunListAdd.new
@setup.name_args = [ "will", "QA", "role[monkey]", "role[dude]", "role[fixer]" ]
@knife = Chef::Knife::RoleEnvRunListReplace.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
@knife.name_args = [ "will", "QA", "role[dude]", "role[person]" ]
allow(@knife).to receive(:output).and_return(true)
@@ -42,11 +42,8 @@ describe Chef::Knife::RoleEnvRunListReplace do
end
-
-
describe "run" do
-
# it "should display all the things" do
# @knife.run
# @role.to_json.should == 'show all the things'
@@ -57,52 +54,52 @@ describe Chef::Knife::RoleEnvRunListReplace do
@knife.run
end
- it "should remove the item from the run list" do
- @setup.run
- @knife.run
- expect(@role.run_list_for('QA')[1]).not_to eq('role[dude]')
- expect(@role.run_list_for('QA')[1]).to eq('role[person]')
- expect(@role.run_list[0]).to be_nil
- end
+ it "should remove the item from the run list" do
+ @setup.run
+ @knife.run
+ expect(@role.run_list_for("QA")[1]).not_to eq("role[dude]")
+ expect(@role.run_list_for("QA")[1]).to eq("role[person]")
+ expect(@role.run_list[0]).to be_nil
+ end
- it "should save the node" do
- expect(@role).to receive(:save).and_return(true)
- @knife.run
- end
+ it "should save the node" do
+ expect(@role).to receive(:save).and_return(true)
+ @knife.run
+ end
- it "should print the run list" do
- expect(@knife).to receive(:output).and_return(true)
- @knife.config[:print_after] = true
- @setup.run
- @knife.run
- end
+ it "should print the run list" do
+ expect(@knife).to receive(:output).and_return(true)
+ @knife.config[:print_after] = true
+ @setup.run
+ @knife.run
+ end
- describe "run with a list of roles and recipes" do
- it "should replace the items from the run list" do
- @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
- @setup.run
- @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
- @setup.run
- @knife.name_args = [ 'will', 'QA', 'role[monkey]', 'role[gibbon]' ]
- @knife.run
- @knife.name_args = [ 'will', 'QA', 'recipe[duck::type]', 'recipe[duck::mallard]' ]
- @knife.run
- expect(@role.run_list_for('QA')).not_to include('role[monkey]')
- expect(@role.run_list_for('QA')).not_to include('recipe[duck::type]')
- expect(@role.run_list_for('QA')[0]).to eq('recipe[orange::chicken]')
- expect(@role.run_list_for('QA')[1]).to eq('role[gibbon]')
- expect(@role.run_list_for('QA')[2]).to eq('recipe[duck::mallard]')
- expect(@role.run_list_for('QA')[3]).to eq('role[person]')
- expect(@role.run_list_for('QA')[4]).to eq('role[bird]')
- expect(@role.run_list_for('QA')[5]).to eq('role[town]')
- expect(@role.run_list_for('PRD')[0]).to eq('recipe[orange::chicken]')
- expect(@role.run_list_for('PRD')[1]).to eq('role[monkey]')
- expect(@role.run_list_for('PRD')[2]).to eq('recipe[duck::type]')
- expect(@role.run_list_for('PRD')[3]).to eq('role[person]')
- expect(@role.run_list_for('PRD')[4]).to eq('role[bird]')
- expect(@role.run_list_for('PRD')[5]).to eq('role[town]')
- expect(@role.run_list[0]).to be_nil
- end
- end
+ describe "run with a list of roles and recipes" do
+ it "should replace the items from the run list" do
+ @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+ @setup.run
+ @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+ @setup.run
+ @knife.name_args = [ "will", "QA", "role[monkey]", "role[gibbon]" ]
+ @knife.run
+ @knife.name_args = [ "will", "QA", "recipe[duck::type]", "recipe[duck::mallard]" ]
+ @knife.run
+ expect(@role.run_list_for("QA")).not_to include("role[monkey]")
+ expect(@role.run_list_for("QA")).not_to include("recipe[duck::type]")
+ expect(@role.run_list_for("QA")[0]).to eq("recipe[orange::chicken]")
+ expect(@role.run_list_for("QA")[1]).to eq("role[gibbon]")
+ expect(@role.run_list_for("QA")[2]).to eq("recipe[duck::mallard]")
+ expect(@role.run_list_for("QA")[3]).to eq("role[person]")
+ expect(@role.run_list_for("QA")[4]).to eq("role[bird]")
+ expect(@role.run_list_for("QA")[5]).to eq("role[town]")
+ expect(@role.run_list_for("PRD")[0]).to eq("recipe[orange::chicken]")
+ expect(@role.run_list_for("PRD")[1]).to eq("role[monkey]")
+ expect(@role.run_list_for("PRD")[2]).to eq("recipe[duck::type]")
+ expect(@role.run_list_for("PRD")[3]).to eq("role[person]")
+ expect(@role.run_list_for("PRD")[4]).to eq("role[bird]")
+ expect(@role.run_list_for("PRD")[5]).to eq("role[town]")
+ expect(@role.run_list[0]).to be_nil
+ end
+ end
end
end
diff --git a/spec/unit/knife/role_env_run_list_set_spec.rb b/spec/unit/knife/role_env_run_list_set_spec.rb
index f3abb86fcf..aed1c9fe1e 100644
--- a/spec/unit/knife/role_env_run_list_set_spec.rb
+++ b/spec/unit/knife/role_env_run_list_set_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Will Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,18 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleEnvRunListSet do
before(:each) do
- Chef::Config[:role_name] = "will"
- Chef::Config[:env_name] = "QA"
+ Chef::Config[:role_name] = "will"
+ Chef::Config[:env_name] = "QA"
@setup = Chef::Knife::RoleEnvRunListAdd.new
@setup.name_args = [ "will", "QA", "role[monkey]", "role[person]", "role[bucket]" ]
@knife = Chef::Knife::RoleEnvRunListSet.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
@knife.name_args = [ "will", "QA", "role[owen]", "role[mauntel]" ]
allow(@knife).to receive(:output).and_return(true)
@@ -42,11 +42,8 @@ describe Chef::Knife::RoleEnvRunListSet do
end
-
-
describe "run" do
-
# it "should display all the things" do
# @knife.run
# @role.to_json.should == 'show all the things'
@@ -60,9 +57,9 @@ describe Chef::Knife::RoleEnvRunListSet do
it "should replace all the items in the runlist with what is specified" do
@setup.run
@knife.run
- expect(@role.run_list_for('QA')[0]).to eq("role[owen]")
- expect(@role.run_list_for('QA')[1]).to eq("role[mauntel]")
- expect(@role.run_list_for('QA')[2]).to be_nil
+ expect(@role.run_list_for("QA")[0]).to eq("role[owen]")
+ expect(@role.run_list_for("QA")[1]).to eq("role[mauntel]")
+ expect(@role.run_list_for("QA")[2]).to be_nil
expect(@role.run_list[0]).to be_nil
end
@@ -86,15 +83,15 @@ describe Chef::Knife::RoleEnvRunListSet do
@setup.run
@knife.name_args = [ "will", "QA", "role[coke]", "role[pepsi]" ]
@knife.run
- expect(@role.run_list_for('QA')[0]).to eq("role[coke]")
- expect(@role.run_list_for('QA')[1]).to eq("role[pepsi]")
- expect(@role.run_list_for('QA')[2]).to be_nil
- expect(@role.run_list_for('PRD')[0]).to eq('recipe[orange::chicken]')
- expect(@role.run_list_for('PRD')[1]).to eq('role[monkey]')
- expect(@role.run_list_for('PRD')[2]).to eq('recipe[duck::type]')
- expect(@role.run_list_for('PRD')[3]).to eq('role[person]')
- expect(@role.run_list_for('PRD')[4]).to eq('role[bird]')
- expect(@role.run_list_for('PRD')[5]).to eq('role[town]')
+ expect(@role.run_list_for("QA")[0]).to eq("role[coke]")
+ expect(@role.run_list_for("QA")[1]).to eq("role[pepsi]")
+ expect(@role.run_list_for("QA")[2]).to be_nil
+ expect(@role.run_list_for("PRD")[0]).to eq("recipe[orange::chicken]")
+ expect(@role.run_list_for("PRD")[1]).to eq("role[monkey]")
+ expect(@role.run_list_for("PRD")[2]).to eq("recipe[duck::type]")
+ expect(@role.run_list_for("PRD")[3]).to eq("role[person]")
+ expect(@role.run_list_for("PRD")[4]).to eq("role[bird]")
+ expect(@role.run_list_for("PRD")[5]).to eq("role[town]")
expect(@role.run_list[0]).to be_nil
end
end
diff --git a/spec/unit/knife/role_from_file_spec.rb b/spec/unit/knife/role_from_file_spec.rb
index 9379f08de3..104894df17 100644
--- a/spec/unit/knife/role_from_file_spec.rb
+++ b/spec/unit/knife/role_from_file_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
Chef::Knife::RoleFromFile.load_deps
describe Chef::Knife::RoleFromFile do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::RoleFromFile.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
@knife.name_args = [ "adam.rb" ]
allow(@knife).to receive(:output).and_return(true)
@@ -39,7 +39,7 @@ describe Chef::Knife::RoleFromFile do
describe "run" do
it "should load from a file" do
- expect(@knife.loader).to receive(:load_from).with('roles', 'adam.rb').and_return(@role)
+ expect(@knife.loader).to receive(:load_from).with("roles", "adam.rb").and_return(@role)
@knife.run
end
@@ -60,8 +60,8 @@ describe Chef::Knife::RoleFromFile do
describe "run with multiple arguments" do
it "should load each file" do
@knife.name_args = [ "adam.rb", "caleb.rb" ]
- expect(@knife.loader).to receive(:load_from).with('roles', 'adam.rb').and_return(@role)
- expect(@knife.loader).to receive(:load_from).with('roles', 'caleb.rb').and_return(@role)
+ expect(@knife.loader).to receive(:load_from).with("roles", "adam.rb").and_return(@role)
+ expect(@knife.loader).to receive(:load_from).with("roles", "caleb.rb").and_return(@role)
@knife.run
end
end
diff --git a/spec/unit/knife/role_list_spec.rb b/spec/unit/knife/role_list_spec.rb
index 808a04d204..30743fdc02 100644
--- a/spec/unit/knife/role_list_spec.rb
+++ b/spec/unit/knife/role_list_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleList do
before(:each) do
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
@knife = Chef::Knife::RoleList.new
allow(@knife).to receive(:output).and_return(true)
@list = {
"foo" => "http://example.com/foo",
- "bar" => "http://example.com/foo"
+ "bar" => "http://example.com/foo",
}
allow(Chef::Role).to receive(:list).and_return(@list)
end
@@ -38,7 +38,7 @@ describe Chef::Knife::RoleList do
it "should pretty print the list" do
expect(Chef::Role).to receive(:list).and_return(@list)
- expect(@knife).to receive(:output).with([ "bar", "foo" ])
+ expect(@knife).to receive(:output).with(%w{bar foo})
@knife.run
end
@@ -52,5 +52,3 @@ describe Chef::Knife::RoleList do
end
end
end
-
-
diff --git a/spec/unit/knife/role_run_list_add_spec.rb b/spec/unit/knife/role_run_list_add_spec.rb
index d61c114912..fe7318c040 100644
--- a/spec/unit/knife/role_run_list_add_spec.rb
+++ b/spec/unit/knife/role_run_list_add_spec.rb
@@ -1,15 +1,15 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Will Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleRunListAdd do
before(:each) do
@@ -25,11 +25,11 @@ describe Chef::Knife::RoleRunListAdd do
# Chef::Config[:env_name] = "QA"
@knife = Chef::Knife::RoleRunListAdd.new
@knife.config = {
- :after => nil
+ :after => nil,
}
@knife.name_args = [ "will", "role[monkey]" ]
allow(@knife).to receive(:output).and_return(true)
- @role = Chef::Role.new()
+ @role = Chef::Role.new()
allow(@role).to receive(:save).and_return(true)
allow(Chef::Role).to receive(:load).and_return(@role)
end
@@ -162,7 +162,7 @@ describe Chef::Knife::RoleRunListAdd do
expect(@role.run_list[2]).to be_nil
end
end
-
+
describe "with more than one command" do
it "should be able to the environment run list by running multiple knife commands" do
@knife.name_args = [ "will", "role[blue]," ]
diff --git a/spec/unit/knife/role_run_list_clear_spec.rb b/spec/unit/knife/role_run_list_clear_spec.rb
index e5a6e18673..4ed1f312b0 100644
--- a/spec/unit/knife/role_run_list_clear_spec.rb
+++ b/spec/unit/knife/role_run_list_clear_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Will Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,17 +17,17 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleRunListClear do
before(:each) do
- Chef::Config[:role_name] = "will"
+ Chef::Config[:role_name] = "will"
@setup = Chef::Knife::RoleRunListAdd.new
@setup.name_args = [ "will", "role[monkey]", "role[person]" ]
@knife = Chef::Knife::RoleRunListClear.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
@knife.name_args = [ "will" ]
allow(@knife).to receive(:output).and_return(true)
@@ -41,11 +41,8 @@ describe Chef::Knife::RoleRunListClear do
end
-
-
describe "run" do
-
# it "should display all the things" do
# @knife.run
# @role.to_json.should == 'show all the things'
@@ -56,35 +53,32 @@ describe Chef::Knife::RoleRunListClear do
@knife.run
end
- it "should remove the item from the run list" do
- @setup.run
- @knife.run
- expect(@role.run_list[0]).to be_nil
- end
+ it "should remove the item from the run list" do
+ @setup.run
+ @knife.run
+ expect(@role.run_list[0]).to be_nil
+ end
- it "should save the node" do
- expect(@role).to receive(:save).and_return(true)
- @knife.run
- end
+ it "should save the node" do
+ expect(@role).to receive(:save).and_return(true)
+ @knife.run
+ end
- it "should print the run list" do
- expect(@knife).to receive(:output).and_return(true)
- @knife.config[:print_after] = true
- @setup.run
- @knife.run
- end
+ it "should print the run list" do
+ expect(@knife).to receive(:output).and_return(true)
+ @knife.config[:print_after] = true
+ @setup.run
+ @knife.run
+ end
- describe "should clear an environmental run list of roles and recipes" do
- it "should remove the items from the run list" do
- @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
- @setup.run
- @knife.name_args = [ 'will' ]
- @knife.run
- expect(@role.run_list[0]).to be_nil
- end
- end
+ describe "should clear an environmental run list of roles and recipes" do
+ it "should remove the items from the run list" do
+ @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+ @setup.run
+ @knife.name_args = [ "will" ]
+ @knife.run
+ expect(@role.run_list[0]).to be_nil
+ end
+ end
end
end
-
-
-
diff --git a/spec/unit/knife/role_run_list_remove_spec.rb b/spec/unit/knife/role_run_list_remove_spec.rb
index 0f4adf253b..087bc2c6ee 100644
--- a/spec/unit/knife/role_run_list_remove_spec.rb
+++ b/spec/unit/knife/role_run_list_remove_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Will Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,17 +17,17 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleRunListRemove do
before(:each) do
- Chef::Config[:role_name] = "will"
+ Chef::Config[:role_name] = "will"
@setup = Chef::Knife::RoleRunListAdd.new
@setup.name_args = [ "will", "role[monkey]", "role[person]" ]
@knife = Chef::Knife::RoleRunListRemove.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
@knife.name_args = [ "will", "role[monkey]" ]
allow(@knife).to receive(:output).and_return(true)
@@ -41,11 +41,8 @@ describe Chef::Knife::RoleRunListRemove do
end
-
-
describe "run" do
-
# it "should display all the things" do
# @knife.run
# @role.to_json.should == 'show all the things'
@@ -56,43 +53,40 @@ describe Chef::Knife::RoleRunListRemove do
@knife.run
end
- it "should remove the item from the run list" do
- @setup.run
- @knife.run
- expect(@role.run_list[0]).to eq('role[person]')
- expect(@role.run_list[1]).to be_nil
- end
+ it "should remove the item from the run list" do
+ @setup.run
+ @knife.run
+ expect(@role.run_list[0]).to eq("role[person]")
+ expect(@role.run_list[1]).to be_nil
+ end
- it "should save the node" do
- expect(@role).to receive(:save).and_return(true)
- @knife.run
- end
+ it "should save the node" do
+ expect(@role).to receive(:save).and_return(true)
+ @knife.run
+ end
- it "should print the run list" do
- expect(@knife).to receive(:output).and_return(true)
- @knife.config[:print_after] = true
- @setup.run
- @knife.run
- end
+ it "should print the run list" do
+ expect(@knife).to receive(:output).and_return(true)
+ @knife.config[:print_after] = true
+ @setup.run
+ @knife.run
+ end
- describe "run with a list of roles and recipes" do
- it "should remove the items from the run list" do
- @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
- @setup.run
- @knife.name_args = [ 'will', 'role[monkey]' ]
- @knife.run
- @knife.name_args = [ 'will', 'recipe[duck::type]' ]
- @knife.run
- expect(@role.run_list).not_to include('role[monkey]')
- expect(@role.run_list).not_to include('recipe[duck::type]')
- expect(@role.run_list[0]).to eq('recipe[orange::chicken]')
- expect(@role.run_list[1]).to eq('role[person]')
- expect(@role.run_list[2]).to eq('role[bird]')
- expect(@role.run_list[3]).to eq('role[town]')
- end
- end
+ describe "run with a list of roles and recipes" do
+ it "should remove the items from the run list" do
+ @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+ @setup.run
+ @knife.name_args = [ "will", "role[monkey]" ]
+ @knife.run
+ @knife.name_args = [ "will", "recipe[duck::type]" ]
+ @knife.run
+ expect(@role.run_list).not_to include("role[monkey]")
+ expect(@role.run_list).not_to include("recipe[duck::type]")
+ expect(@role.run_list[0]).to eq("recipe[orange::chicken]")
+ expect(@role.run_list[1]).to eq("role[person]")
+ expect(@role.run_list[2]).to eq("role[bird]")
+ expect(@role.run_list[3]).to eq("role[town]")
+ end
+ end
end
end
-
-
-
diff --git a/spec/unit/knife/role_run_list_replace_spec.rb b/spec/unit/knife/role_run_list_replace_spec.rb
index 2ff38f573c..2bc060ae2d 100644
--- a/spec/unit/knife/role_run_list_replace_spec.rb
+++ b/spec/unit/knife/role_run_list_replace_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Will Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,17 +17,17 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleRunListReplace do
before(:each) do
- Chef::Config[:role_name] = "will"
+ Chef::Config[:role_name] = "will"
@setup = Chef::Knife::RoleRunListAdd.new
@setup.name_args = [ "will", "role[monkey]", "role[dude]", "role[fixer]" ]
@knife = Chef::Knife::RoleRunListReplace.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
@knife.name_args = [ "will", "role[dude]", "role[person]" ]
allow(@knife).to receive(:output).and_return(true)
@@ -41,11 +41,8 @@ describe Chef::Knife::RoleRunListReplace do
end
-
-
describe "run" do
-
# it "should display all the things" do
# @knife.run
# @role.to_json.should == 'show all the things'
@@ -56,46 +53,46 @@ describe Chef::Knife::RoleRunListReplace do
@knife.run
end
- it "should remove the item from the run list" do
- @setup.run
- @knife.run
- expect(@role.run_list[0]).to eq('role[monkey]')
- expect(@role.run_list[1]).not_to eq('role[dude]')
- expect(@role.run_list[1]).to eq('role[person]')
- expect(@role.run_list[2]).to eq('role[fixer]')
- expect(@role.run_list[3]).to be_nil
- end
+ it "should remove the item from the run list" do
+ @setup.run
+ @knife.run
+ expect(@role.run_list[0]).to eq("role[monkey]")
+ expect(@role.run_list[1]).not_to eq("role[dude]")
+ expect(@role.run_list[1]).to eq("role[person]")
+ expect(@role.run_list[2]).to eq("role[fixer]")
+ expect(@role.run_list[3]).to be_nil
+ end
- it "should save the node" do
- expect(@role).to receive(:save).and_return(true)
- @knife.run
- end
+ it "should save the node" do
+ expect(@role).to receive(:save).and_return(true)
+ @knife.run
+ end
- it "should print the run list" do
- expect(@knife).to receive(:output).and_return(true)
- @knife.config[:print_after] = true
- @setup.run
- @knife.run
- end
+ it "should print the run list" do
+ expect(@knife).to receive(:output).and_return(true)
+ @knife.config[:print_after] = true
+ @setup.run
+ @knife.run
+ end
- describe "run with a list of roles and recipes" do
- it "should replace the items from the run list" do
- @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
- @setup.run
- @knife.name_args = [ 'will', 'role[monkey]', 'role[gibbon]' ]
- @knife.run
- @knife.name_args = [ 'will', 'recipe[duck::type]', 'recipe[duck::mallard]' ]
- @knife.run
- expect(@role.run_list).not_to include('role[monkey]')
- expect(@role.run_list).not_to include('recipe[duck::type]')
- expect(@role.run_list[0]).to eq('recipe[orange::chicken]')
- expect(@role.run_list[1]).to eq('role[gibbon]')
- expect(@role.run_list[2]).to eq('recipe[duck::mallard]')
- expect(@role.run_list[3]).to eq('role[person]')
- expect(@role.run_list[4]).to eq('role[bird]')
- expect(@role.run_list[5]).to eq('role[town]')
- expect(@role.run_list[6]).to be_nil
- end
- end
+ describe "run with a list of roles and recipes" do
+ it "should replace the items from the run list" do
+ @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+ @setup.run
+ @knife.name_args = [ "will", "role[monkey]", "role[gibbon]" ]
+ @knife.run
+ @knife.name_args = [ "will", "recipe[duck::type]", "recipe[duck::mallard]" ]
+ @knife.run
+ expect(@role.run_list).not_to include("role[monkey]")
+ expect(@role.run_list).not_to include("recipe[duck::type]")
+ expect(@role.run_list[0]).to eq("recipe[orange::chicken]")
+ expect(@role.run_list[1]).to eq("role[gibbon]")
+ expect(@role.run_list[2]).to eq("recipe[duck::mallard]")
+ expect(@role.run_list[3]).to eq("role[person]")
+ expect(@role.run_list[4]).to eq("role[bird]")
+ expect(@role.run_list[5]).to eq("role[town]")
+ expect(@role.run_list[6]).to be_nil
+ end
+ end
end
end
diff --git a/spec/unit/knife/role_run_list_set_spec.rb b/spec/unit/knife/role_run_list_set_spec.rb
index 1350741f10..27b4d9fea1 100644
--- a/spec/unit/knife/role_run_list_set_spec.rb
+++ b/spec/unit/knife/role_run_list_set_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Will Albenzi (<walbenzi@gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,17 +17,17 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleRunListSet do
before(:each) do
- Chef::Config[:role_name] = "will"
+ Chef::Config[:role_name] = "will"
@setup = Chef::Knife::RoleRunListAdd.new
@setup.name_args = [ "will", "role[monkey]", "role[person]", "role[bucket]" ]
@knife = Chef::Knife::RoleRunListSet.new
@knife.config = {
- :print_after => nil
+ :print_after => nil,
}
@knife.name_args = [ "will", "role[owen]", "role[mauntel]" ]
allow(@knife).to receive(:output).and_return(true)
@@ -41,11 +41,8 @@ describe Chef::Knife::RoleRunListSet do
end
-
-
describe "run" do
-
# it "should display all the things" do
# @knife.run
# @role.to_json.should == 'show all the things'
@@ -59,8 +56,8 @@ describe Chef::Knife::RoleRunListSet do
it "should replace all the items in the runlist with what is specified" do
@setup.run
@knife.run
- expect(@role.run_list[0]).to eq("role[owen]")
- expect(@role.run_list[1]).to eq("role[mauntel]")
+ expect(@role.run_list[0]).to eq("role[owen]")
+ expect(@role.run_list[1]).to eq("role[mauntel]")
expect(@role.run_list[2]).to be_nil
end
diff --git a/spec/unit/knife/role_show_spec.rb b/spec/unit/knife/role_show_spec.rb
index b086136186..fe48e2f940 100644
--- a/spec/unit/knife/role_show_spec.rb
+++ b/spec/unit/knife/role_show_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@getchef.com>)
-# Copyright:: Copyright (c) 2014 Lamont Granquist
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2014-2016, Lamont Granquist
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::RoleShow do
- let(:role) { 'base' }
+ let(:role) { "base" }
let(:knife) do
knife = Chef::Knife::RoleShow.new
@@ -27,29 +27,29 @@ describe Chef::Knife::RoleShow do
knife
end
- let(:role_mock) { double('role_mock') }
+ let(:role_mock) { double("role_mock") }
- describe 'run' do
- it 'should list the role' do
- expect(Chef::Role).to receive(:load).with('base').and_return(role_mock)
+ describe "run" do
+ it "should list the role" do
+ expect(Chef::Role).to receive(:load).with("base").and_return(role_mock)
expect(knife).to receive(:format_for_display).with(role_mock)
knife.run
end
- it 'should pretty print json' do
- knife.config[:format] = 'json'
+ it "should pretty print json" do
+ knife.config[:format] = "json"
stdout = StringIO.new
allow(knife.ui).to receive(:stdout).and_return(stdout)
- fake_role_contents = {"foo"=>"bar", "baz"=>"qux"}
- expect(Chef::Role).to receive(:load).with('base').and_return(fake_role_contents)
+ fake_role_contents = { "foo" => "bar", "baz" => "qux" }
+ expect(Chef::Role).to receive(:load).with("base").and_return(fake_role_contents)
knife.run
expect(stdout.string).to eql("{\n \"foo\": \"bar\",\n \"baz\": \"qux\"\n}\n")
end
context "without a role name" do
- let(:role) { }
+ let(:role) {}
- it 'should print usage and exit when a role name is not provided' do
+ it "should print usage and exit when a role name is not provided" do
expect(knife).to receive(:show_usage)
expect(knife.ui).to receive(:fatal)
expect { knife.run }.to raise_error(SystemExit)
diff --git a/spec/unit/knife/ssh_spec.rb b/spec/unit/knife/ssh_spec.rb
index 723280bead..6141a8a6df 100644
--- a/spec/unit/knife/ssh_spec.rb
+++ b/spec/unit/knife/ssh_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Bryan McLellan <btm@opscode.com>
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Bryan McLellan <btm@chef.io>
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,62 +16,61 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'net/ssh'
-require 'net/ssh/multi'
+require "spec_helper"
+require "net/ssh"
+require "net/ssh/multi"
describe Chef::Knife::Ssh do
- before(:each) do
- Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem"
- end
+ let(:query_result) { double("chef search results") }
before do
+ Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem"
@knife = Chef::Knife::Ssh.new
@knife.merge_configs
- @node_foo = Chef::Node.new
- @node_foo.automatic_attrs[:fqdn] = "foo.example.org"
- @node_foo.automatic_attrs[:ipaddress] = "10.0.0.1"
+ @node_foo = {}
+ @node_foo["fqdn"] = "foo.example.org"
+ @node_foo["ipaddress"] = "10.0.0.1"
+ @node_foo["cloud"] = {}
+
+ @node_bar = {}
+ @node_bar["fqdn"] = "bar.example.org"
+ @node_bar["ipaddress"] = "10.0.0.2"
+ @node_bar["cloud"] = {}
- @node_bar = Chef::Node.new
- @node_bar.automatic_attrs[:fqdn] = "bar.example.org"
- @node_bar.automatic_attrs[:ipaddress] = "10.0.0.2"
end
describe "#configure_session" do
context "manual is set to false (default)" do
before do
@knife.config[:manual] = false
- @query = Chef::Search::Query.new
- end
-
- def configure_query(node_array)
- allow(@query).to receive(:search).and_return([node_array])
- allow(Chef::Search::Query).to receive(:new).and_return(@query)
+ allow(query_result).to receive(:search).with(any_args).and_yield(@node_foo).and_yield(@node_bar)
+ allow(Chef::Search::Query).to receive(:new).and_return(query_result)
end
def self.should_return_specified_attributes
it "returns an array of the attributes specified on the command line OR config file, if only one is set" do
+ @node_bar["config"] = "10.0.0.2"
+ @node_foo["config"] = "10.0.0.1"
@knife.config[:attribute] = "ipaddress"
Chef::Config[:knife][:ssh_attribute] = "ipaddress" # this value will be in the config file
- configure_query([@node_foo, @node_bar])
- expect(@knife).to receive(:session_from_list).with([['10.0.0.1', nil], ['10.0.0.2', nil]])
+ expect(@knife).to receive(:session_from_list).with([["10.0.0.1", nil], ["10.0.0.2", nil]])
@knife.configure_session
end
it "returns an array of the attributes specified on the command line even when a config value is set" do
+ @node_bar["config"] = "10.0.0.2"
+ @node_foo["config"] = "10.0.0.1"
Chef::Config[:knife][:ssh_attribute] = "config_file" # this value will be in the config file
@knife.config[:attribute] = "ipaddress" # this is the value of the command line via #configure_attribute
- configure_query([@node_foo, @node_bar])
- expect(@knife).to receive(:session_from_list).with([['10.0.0.1', nil], ['10.0.0.2', nil]])
+ expect(@knife).to receive(:session_from_list).with([["10.0.0.1", nil], ["10.0.0.2", nil]])
@knife.configure_session
end
end
it "searchs for and returns an array of fqdns" do
- configure_query([@node_foo, @node_bar])
expect(@knife).to receive(:session_from_list).with([
- ['foo.example.org', nil],
- ['bar.example.org', nil]
+ ["foo.example.org", nil],
+ ["bar.example.org", nil],
])
@knife.configure_session
end
@@ -80,14 +79,13 @@ describe Chef::Knife::Ssh do
context "when cloud hostnames are available" do
before do
- @node_foo.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-1.compute-1.amazonaws.com"
- @node_bar.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-2.compute-1.amazonaws.com"
+ @node_foo["cloud"]["public_hostname"] = "ec2-10-0-0-1.compute-1.amazonaws.com"
+ @node_bar["cloud"]["public_hostname"] = "ec2-10-0-0-2.compute-1.amazonaws.com"
end
it "returns an array of cloud public hostnames" do
- configure_query([@node_foo, @node_bar])
expect(@knife).to receive(:session_from_list).with([
- ['ec2-10-0-0-1.compute-1.amazonaws.com', nil],
- ['ec2-10-0-0-2.compute-1.amazonaws.com', nil]
+ ["ec2-10-0-0-1.compute-1.amazonaws.com", nil],
+ ["ec2-10-0-0-2.compute-1.amazonaws.com", nil],
])
@knife.configure_session
end
@@ -97,15 +95,14 @@ describe Chef::Knife::Ssh do
context "when cloud hostnames are available but empty" do
before do
- @node_foo.automatic_attrs[:cloud][:public_hostname] = ''
- @node_bar.automatic_attrs[:cloud][:public_hostname] = ''
+ @node_foo["cloud"]["public_hostname"] = ""
+ @node_bar["cloud"]["public_hostname"] = ""
end
it "returns an array of fqdns" do
- configure_query([@node_foo, @node_bar])
expect(@knife).to receive(:session_from_list).with([
- ['foo.example.org', nil],
- ['bar.example.org', nil]
+ ["foo.example.org", nil],
+ ["bar.example.org", nil],
])
@knife.configure_session
end
@@ -114,18 +111,16 @@ describe Chef::Knife::Ssh do
end
it "should raise an error if no host are found" do
- configure_query([ ])
- expect(@knife.ui).to receive(:fatal)
- expect(@knife).to receive(:exit).with(10)
- @knife.configure_session
+ allow(query_result).to receive(:search).with(any_args)
+ expect(@knife.ui).to receive(:fatal)
+ expect(@knife).to receive(:exit).with(10)
+ @knife.configure_session
end
context "when there are some hosts found but they do not have an attribute to connect with" do
before do
- allow(@query).to receive(:search).and_return([[@node_foo, @node_bar]])
- @node_foo.automatic_attrs[:fqdn] = nil
- @node_bar.automatic_attrs[:fqdn] = nil
- allow(Chef::Search::Query).to receive(:new).and_return(@query)
+ @node_foo["fqdn"] = nil
+ @node_bar["fqdn"] = nil
end
it "should raise a specific error (CHEF-3402)" do
@@ -143,7 +138,7 @@ describe Chef::Knife::Ssh do
it "returns an array of provided values" do
@knife.instance_variable_set(:@name_args, ["foo.example.org bar.example.org"])
- expect(@knife).to receive(:session_from_list).with(['foo.example.org', 'bar.example.org'])
+ expect(@knife).to receive(:session_from_list).with(["foo.example.org", "bar.example.org"])
@knife.configure_session
end
end
@@ -158,63 +153,84 @@ describe Chef::Knife::Ssh do
before do
Chef::Config[:knife][:ssh_attribute] = nil
@knife.config[:attribute] = nil
- @node_foo.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-1.compute-1.amazonaws.com"
- @node_bar.automatic_attrs[:cloud][:public_hostname] = ''
+ @node_foo["cloud"]["public_hostname"] = "ec2-10-0-0-1.compute-1.amazonaws.com"
+ @node_bar["cloud"]["public_hostname"] = ""
end
it "should return fqdn by default" do
- expect(@knife.get_ssh_attribute(Chef::Node.new)).to eq("fqdn")
+ expect(@knife.get_ssh_attribute({ "fqdn" => "fqdn" })).to eq("fqdn")
end
it "should return cloud.public_hostname attribute if available" do
- expect(@knife.get_ssh_attribute(@node_foo)).to eq("cloud.public_hostname")
+ expect(@knife.get_ssh_attribute(@node_foo)).to eq("ec2-10-0-0-1.compute-1.amazonaws.com")
end
- it "should favor to attribute_from_cli over config file and cloud" do
+ it "should favor to attribute_from_cli over config file and cloud" do
@knife.config[:attribute] = "command_line"
Chef::Config[:knife][:ssh_attribute] = "config_file"
+ @node_foo["config"] = "command_line"
+ @node_foo["knife_config"] = "config_file"
expect( @knife.get_ssh_attribute(@node_foo)).to eq("command_line")
end
- it "should favor config file over cloud and default" do
+ it "should favor config file over cloud and default" do
Chef::Config[:knife][:ssh_attribute] = "config_file"
+ @node_foo["knife_config"] = "config_file"
expect( @knife.get_ssh_attribute(@node_foo)).to eq("config_file")
end
it "should return fqdn if cloud.hostname is empty" do
- expect( @knife.get_ssh_attribute(@node_bar)).to eq("fqdn")
+ expect( @knife.get_ssh_attribute(@node_bar)).to eq("bar.example.org")
end
end
describe "#session_from_list" do
before :each do
@knife.instance_variable_set(:@longest, 0)
- ssh_config = {:timeout => 50, :user => "locutus", :port => 23 }
- allow(Net::SSH).to receive(:configuration_for).with('the.b.org').and_return(ssh_config)
+ ssh_config = { :timeout => 50, :user => "locutus", :port => 23 }
+ allow(Net::SSH).to receive(:configuration_for).with("the.b.org", true).and_return(ssh_config)
end
it "uses the port from an ssh config file" do
- @knife.session_from_list([['the.b.org', nil]])
+ @knife.session_from_list([["the.b.org", nil]])
expect(@knife.session.servers[0].port).to eq(23)
end
it "uses the port from a cloud attr" do
- @knife.session_from_list([['the.b.org', 123]])
+ @knife.session_from_list([["the.b.org", 123]])
expect(@knife.session.servers[0].port).to eq(123)
end
+ it "defaults to a timeout of 120 seconds" do
+ @knife.session_from_list([["the.b.org", nil]])
+ expect(@knife.session.servers[0].options[:timeout]).to eq(120)
+ end
+
+ it "uses the timeout from Chef Config" do
+ Chef::Config[:knife][:ssh_timeout] = 5
+ @knife.config[:ssh_timeout] = nil
+ @knife.session_from_list([["the.b.org", nil]])
+ expect(@knife.session.servers[0].options[:timeout]).to eq(5)
+ end
+
+ it "uses the timeout from knife config" do
+ @knife.config[:ssh_timeout] = 6
+ @knife.session_from_list([["the.b.org", nil]])
+ expect(@knife.session.servers[0].options[:timeout]).to eq(6)
+ end
+
it "uses the user from an ssh config file" do
- @knife.session_from_list([['the.b.org', 123]])
+ @knife.session_from_list([["the.b.org", 123]])
expect(@knife.session.servers[0].user).to eq("locutus")
end
end
describe "#ssh_command" do
let(:execution_channel) { double(:execution_channel, :on_data => nil) }
- let(:session_channel) { double(:session_channel, :request_pty => nil)}
+ let(:session_channel) { double(:session_channel, :request_pty => nil) }
let(:execution_channel2) { double(:execution_channel, :on_data => nil) }
- let(:session_channel2) { double(:session_channel, :request_pty => nil)}
+ let(:session_channel2) { double(:session_channel, :request_pty => nil) }
let(:session) { double(:session, :loop => nil) }
@@ -276,10 +292,10 @@ describe Chef::Knife::Ssh do
describe "#run" do
before do
@query = Chef::Search::Query.new
- expect(@query).to receive(:search).and_return([[@node_foo]])
+ expect(@query).to receive(:search).and_yield(@node_foo)
allow(Chef::Search::Query).to receive(:new).and_return(@query)
allow(@knife).to receive(:ssh_command).and_return(exit_code)
- @knife.name_args = ['*:*', 'false']
+ @knife.name_args = ["*:*", "false"]
end
context "with an error" do
@@ -309,14 +325,14 @@ describe Chef::Knife::Ssh do
context "when setting ssh_password_ng from knife ssh" do
# in this case ssh_password_ng exists, but ssh_password does not
- it "should prompt for a password when ssh_passsword_ng is nil" do
+ it "should prompt for a password when ssh_passsword_ng is nil" do
@knife.config[:ssh_password_ng] = nil
expect(@knife).to receive(:get_password).and_return("mysekretpassw0rd")
@knife.configure_password
expect(@knife.config[:ssh_password]).to eq("mysekretpassw0rd")
end
- it "should set ssh_password to false if ssh_password_ng is false" do
+ it "should set ssh_password to false if ssh_password_ng is false" do
@knife.config[:ssh_password_ng] = false
expect(@knife).not_to receive(:get_password)
@knife.configure_password
@@ -360,14 +376,14 @@ describe Chef::Knife::Ssh do
end
context "when setting ssh_password_ng from knife ssh" do
# in this case ssh_password_ng exists, but ssh_password does not
- it "should prompt for a password when ssh_passsword_ng is nil" do
+ it "should prompt for a password when ssh_passsword_ng is nil" do
@knife.config[:ssh_password_ng] = nil
expect(@knife).to receive(:get_password).and_return("mysekretpassw0rd")
@knife.configure_password
expect(@knife.config[:ssh_password]).to eq("mysekretpassw0rd")
end
- it "should set ssh_password to the configured knife.rb value if ssh_password_ng is false" do
+ it "should set ssh_password to the configured knife.rb value if ssh_password_ng is false" do
@knife.config[:ssh_password_ng] = false
expect(@knife).not_to receive(:get_password)
@knife.configure_password
diff --git a/spec/unit/knife/ssl_check_spec.rb b/spec/unit/knife/ssl_check_spec.rb
index fd46c47d99..8aa18c3abc 100644
--- a/spec/unit/knife/ssl_check_spec.rb
+++ b/spec/unit/knife/ssl_check_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
#
require "spec_helper"
-require 'stringio'
+require "stringio"
describe Chef::Knife::SslCheck do
@@ -67,10 +67,10 @@ describe Chef::Knife::SslCheck do
it "prints an error and exits" do
expect { ssl_check.run }.to raise_error(SystemExit)
- expected_stdout=<<-E
+ expected_stdout = <<-E
USAGE: knife ssl check [URL] (options)
E
- expected_stderr=<<-E
+ expected_stderr = <<-E
ERROR: Given URI: `foo.test' is invalid
E
expect(stdout_io.string).to eq(expected_stdout)
@@ -83,10 +83,10 @@ E
it "prints an error and exits" do
expect { ssl_check.run }.to raise_error(SystemExit)
- expected_stdout=<<-E
+ expected_stdout = <<-E
USAGE: knife ssl check [URL] (options)
E
- expected_stderr=<<-E
+ expected_stderr = <<-E
ERROR: Given URI: `#{name_args[0]}' is invalid
E
expect(stdout_io.string).to eq(expected_stdout)
@@ -114,6 +114,22 @@ E
allow(ssl_check).to receive(:verify_cert_host).and_return(true)
end
+ context "when the trusted certificates directory is not glob escaped", :windows_only do
+ let(:trusted_certs_dir) { File.join(CHEF_SPEC_DATA.tr("/", "\\"), "trusted_certs") }
+
+ before do
+ allow(ssl_check).to receive(:trusted_certificates).and_call_original
+ allow(store).to receive(:verify).with(certificate).and_return(true)
+ end
+
+ it "escpaes the trusted certificates directory" do
+ expect(Dir).to receive(:glob)
+ .with("#{ChefConfig::PathHelper.escape_glob_dir(trusted_certs_dir)}/*.{crt,pem}")
+ .and_return([trusted_cert_file])
+ ssl_check.run
+ end
+ end
+
context "when the trusted certificates have valid X509 properties" do
before do
allow(store).to receive(:verify).with(certificate).and_return(true)
@@ -145,7 +161,7 @@ E
let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket) }
before do
- expect(TCPSocket).to receive(:new).with("foo.example.com", 8443).and_return(tcp_socket)
+ expect(ssl_check).to receive(:proxified_socket).with("foo.example.com", 8443).and_return(tcp_socket)
expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, ssl_check.verify_peer_ssl_context).and_return(ssl_socket)
end
@@ -181,9 +197,9 @@ E
let(:self_signed_crt) { OpenSSL::X509::Certificate.new(File.read(self_signed_crt_path)) }
before do
- trap(:INT, "DEFAULT")
+ @old_signal = trap(:INT, "DEFAULT")
- expect(TCPSocket).to receive(:new).
+ expect(ssl_check).to receive(:proxified_socket).
with("foo.example.com", 8443).
and_return(tcp_socket_for_debug)
expect(OpenSSL::SSL::SSLSocket).to receive(:new).
@@ -191,6 +207,10 @@ E
and_return(ssl_socket_for_debug)
end
+ after do
+ trap(:INT, @old_signal)
+ end
+
context "when the certificate's CN does not match the hostname" do
before do
expect(ssl_check).to receive(:verify_X509).and_return(true) # X509 valid certs
diff --git a/spec/unit/knife/ssl_fetch_spec.rb b/spec/unit/knife/ssl_fetch_spec.rb
index cd0e423459..bc49c40241 100644
--- a/spec/unit/knife/ssl_fetch_spec.rb
+++ b/spec/unit/knife/ssl_fetch_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/knife/ssl_fetch'
+require "spec_helper"
+require "chef/knife/ssl_fetch"
describe Chef::Knife::SslFetch do
@@ -68,10 +68,10 @@ describe Chef::Knife::SslFetch do
it "prints an error and exits" do
expect { ssl_fetch.run }.to raise_error(SystemExit)
- expected_stdout=<<-E
+ expected_stdout = <<-E
USAGE: knife ssl fetch [URL] (options)
E
- expected_stderr=<<-E
+ expected_stderr = <<-E
ERROR: Given URI: `foo.test' is invalid
E
expect(stdout_io.string).to eq(expected_stdout)
@@ -84,10 +84,10 @@ E
it "prints an error and exits" do
expect { ssl_fetch.run }.to raise_error(SystemExit)
- expected_stdout=<<-E
+ expected_stdout = <<-E
USAGE: knife ssl fetch [URL] (options)
E
- expected_stderr=<<-E
+ expected_stderr = <<-E
ERROR: Given URI: `#{name_args[0]}' is invalid
E
expect(stdout_io.string).to eq(expected_stdout)
@@ -108,6 +108,24 @@ E
end
+ describe "#cn_of" do
+ let(:certificate) { double("Certificate", subject: subject) }
+
+ describe "when the certificate has a common name" do
+ let(:subject) { [["CN", "common name"]] }
+ it "returns the common name" do
+ expect(ssl_fetch.cn_of(certificate)).to eq("common name")
+ end
+ end
+
+ describe "when the certificate does not have a common name" do
+ let(:subject) { [] }
+ it "returns nil" do
+ expect(ssl_fetch.cn_of(certificate)).to eq(nil)
+ end
+ end
+ end
+
describe "fetching the remote cert chain" do
let(:name_args) { %w{https://foo.example.com:8443} }
@@ -139,7 +157,7 @@ E
context "when the TLS connection is successful" do
before do
- expect(TCPSocket).to receive(:new).with("foo.example.com", 8443).and_return(tcp_socket)
+ expect(ssl_fetch).to receive(:proxified_socket).with("foo.example.com", 8443).and_return(tcp_socket)
expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, ssl_fetch.noverify_peer_ssl_context).and_return(ssl_socket)
expect(ssl_socket).to receive(:connect)
expect(ssl_socket).to receive(:peer_cert_chain).and_return([self_signed_crt])
@@ -161,7 +179,7 @@ E
let(:unknown_protocol_error) { OpenSSL::SSL::SSLError.new("SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: unknown protocol") }
before do
- expect(TCPSocket).to receive(:new).with("foo.example.com", 80).and_return(tcp_socket)
+ expect(ssl_fetch).to receive(:proxified_socket).with("foo.example.com", 80).and_return(tcp_socket)
expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, ssl_fetch.noverify_peer_ssl_context).and_return(ssl_socket)
expect(ssl_socket).to receive(:connect).and_raise(unknown_protocol_error)
@@ -180,5 +198,25 @@ ERROR_TEXT
end
+ describe "when the certificate does not have a CN" do
+ let(:self_signed_crt_path) { File.join(CHEF_SPEC_DATA, "trusted_certs", "example_no_cn.crt") }
+ let(:self_signed_crt) { OpenSSL::X509::Certificate.new(File.read(self_signed_crt_path)) }
+
+ before do
+ expect(ssl_fetch).to receive(:proxified_socket).with("foo.example.com", 8443).and_return(tcp_socket)
+ expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, ssl_fetch.noverify_peer_ssl_context).and_return(ssl_socket)
+ expect(ssl_socket).to receive(:connect)
+ expect(ssl_socket).to receive(:peer_cert_chain).and_return([self_signed_crt])
+ expect(Time).to receive(:new).and_return(1)
+ end
+
+ it "fetches the certificate and writes it to a file in the trusted_certs_dir" do
+ run
+ stored_cert_path = File.join(trusted_certs_dir, "foo.example.com_1.crt")
+ expect(File).to exist(stored_cert_path)
+ expect(File.read(stored_cert_path)).to eq(File.read(self_signed_crt_path))
+ end
+ end
+
end
end
diff --git a/spec/unit/knife/status_spec.rb b/spec/unit/knife/status_spec.rb
index 11728a6f9b..c87ea3ad17 100644
--- a/spec/unit/knife/status_spec.rb
+++ b/spec/unit/knife/status_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Sahil Muthoo (<sahil.muthoo@gmail.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::Status do
before(:each) do
@@ -34,10 +34,11 @@ describe Chef::Knife::Status do
end
describe "run" do
- let(:opts) {{filter_result:
+ let(:opts) do
+ { filter_result:
{ name: ["name"], ipaddress: ["ipaddress"], ohai_time: ["ohai_time"],
- ec2: ["ec2"], run_list: ["run_list"], platform: ["platform"],
- platform_version: ["platform_version"], chef_environment: ["chef_environment"]}}}
+ ec2: ["ec2"], run_list: ["run_list"], platform: ["platform"],
+ platform_version: ["platform_version"], chef_environment: ["chef_environment"] } } end
it "should default to searching for everything" do
expect(@query).to receive(:search).with(:node, "*:*", opts)
diff --git a/spec/unit/knife/tag_create_spec.rb b/spec/unit/knife/tag_create_spec.rb
index 586ec118bd..6a3ced3f5b 100644
--- a/spec/unit/knife/tag_create_spec.rb
+++ b/spec/unit/knife/tag_create_spec.rb
@@ -1,4 +1,4 @@
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::TagCreate do
before(:each) do
diff --git a/spec/unit/knife/tag_delete_spec.rb b/spec/unit/knife/tag_delete_spec.rb
index e7fa108947..5c932706af 100644
--- a/spec/unit/knife/tag_delete_spec.rb
+++ b/spec/unit/knife/tag_delete_spec.rb
@@ -1,4 +1,4 @@
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::TagDelete do
before(:each) do
@@ -16,7 +16,7 @@ describe Chef::Knife::TagDelete do
describe "run" do
it "can delete tags on a node" do
- expect(@node.tags).to eq(["sadtag", "happytag"])
+ expect(@node.tags).to eq(%w{sadtag happytag})
@knife.run
expect(@node.tags).to eq(["happytag"])
expect(@stderr.string).to match /deleted.+sadtag/i
diff --git a/spec/unit/knife/tag_list_spec.rb b/spec/unit/knife/tag_list_spec.rb
index 9c71d22f06..dceec9a5ea 100644
--- a/spec/unit/knife/tag_list_spec.rb
+++ b/spec/unit/knife/tag_list_spec.rb
@@ -1,4 +1,4 @@
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::TagList do
before(:each) do
@@ -14,7 +14,7 @@ describe Chef::Knife::TagList do
describe "run" do
it "can list tags on a node" do
- expected = %w(sadtag happytag)
+ expected = %w{sadtag happytag}
expect(@node.tags).to eq(expected)
expect(@knife).to receive(:output).with(expected)
@knife.run
diff --git a/spec/unit/knife/user_create_spec.rb b/spec/unit/knife/user_create_spec.rb
index fa5c8324b4..07d72fd05a 100644
--- a/spec/unit/knife/user_create_spec.rb
+++ b/spec/unit/knife/user_create_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Steven Danna (<steve@chef.io>)
# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2012, 2015 Chef Software, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,20 +17,20 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
Chef::Knife::UserCreate.load_deps
describe Chef::Knife::UserCreate do
let(:knife) { Chef::Knife::UserCreate.new }
- let(:stderr) {
+ let(:stderr) do
StringIO.new
- }
+ end
- let(:stdout) {
+ let(:stdout) do
StringIO.new
- }
+ end
before(:each) do
allow(knife.ui).to receive(:stdout).and_return(stdout)
@@ -41,18 +41,18 @@ describe Chef::Knife::UserCreate do
# delete this once OSC11 support is gone
context "when only one name_arg is passed" do
before do
- knife.name_args = ['some_user']
+ knife.name_args = ["some_user"]
allow(knife).to receive(:run_osc_11_user_create).and_raise(SystemExit)
end
it "displays the osc warning" do
expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
- expect{ knife.run }.to raise_error(SystemExit)
+ expect { knife.run }.to raise_error(SystemExit)
end
it "calls knife osc_user create" do
expect(knife).to receive(:run_osc_11_user_create)
- expect{ knife.run }.to raise_error(SystemExit)
+ expect { knife.run }.to raise_error(SystemExit)
end
end
@@ -61,7 +61,7 @@ describe Chef::Knife::UserCreate do
# from spec/support/shared/unit/knife_shared.rb
it_should_behave_like "mandatory field missing" do
let(:name_args) { [] }
- let(:fieldname) { 'username' }
+ let(:fieldname) { "username" }
end
end
@@ -79,39 +79,39 @@ describe Chef::Knife::UserCreate do
context "when FIRST_NAME isn't specified" do
# from spec/support/shared/unit/knife_shared.rb
it_should_behave_like "mandatory field missing" do
- let(:name_args) { ['some_user', 'some_display_name'] }
- let(:fieldname) { 'first name' }
+ let(:name_args) { %w{some_user some_display_name} }
+ let(:fieldname) { "first name" }
end
end
context "when LAST_NAME isn't specified" do
# from spec/support/shared/unit/knife_shared.rb
it_should_behave_like "mandatory field missing" do
- let(:name_args) { ['some_user', 'some_display_name', 'some_first_name'] }
- let(:fieldname) { 'last name' }
+ let(:name_args) { %w{some_user some_display_name some_first_name} }
+ let(:fieldname) { "last name" }
end
end
context "when EMAIL isn't specified" do
# from spec/support/shared/unit/knife_shared.rb
it_should_behave_like "mandatory field missing" do
- let(:name_args) { ['some_user', 'some_display_name', 'some_first_name', 'some_last_name'] }
- let(:fieldname) { 'email' }
+ let(:name_args) { %w{some_user some_display_name some_first_name some_last_name} }
+ let(:fieldname) { "email" }
end
end
context "when PASSWORD isn't specified" do
# from spec/support/shared/unit/knife_shared.rb
it_should_behave_like "mandatory field missing" do
- let(:name_args) { ['some_user', 'some_display_name', 'some_first_name', 'some_last_name', 'some_email'] }
- let(:fieldname) { 'password' }
+ let(:name_args) { %w{some_user some_display_name some_first_name some_last_name some_email} }
+ let(:fieldname) { "password" }
end
end
context "when all mandatory fields are validly specified" do
before do
- knife.name_args = ['some_user', 'some_display_name', 'some_first_name', 'some_last_name', 'some_email', 'some_password']
- allow(knife).to receive(:edit_data).and_return(knife.user.to_hash)
+ knife.name_args = %w{some_user some_display_name some_first_name some_last_name some_email some_password}
+ allow(knife).to receive(:edit_hash).and_return(knife.user.to_hash)
allow(knife).to receive(:create_user_from_hash).and_return(knife.user)
end
@@ -122,12 +122,12 @@ describe Chef::Knife::UserCreate do
it "sets all the mandatory fields" do
knife.run
- expect(knife.user.username).to eq('some_user')
- expect(knife.user.display_name).to eq('some_display_name')
- expect(knife.user.first_name).to eq('some_first_name')
- expect(knife.user.last_name).to eq('some_last_name')
- expect(knife.user.email).to eq('some_email')
- expect(knife.user.password).to eq('some_password')
+ expect(knife.user.username).to eq("some_user")
+ expect(knife.user.display_name).to eq("some_display_name")
+ expect(knife.user.first_name).to eq("some_first_name")
+ expect(knife.user.last_name).to eq("some_last_name")
+ expect(knife.user.email).to eq("some_email")
+ expect(knife.user.password).to eq("some_password")
end
context "when user_key and prevent_keygen are passed" do
@@ -166,14 +166,14 @@ describe Chef::Knife::UserCreate do
context "when --user-key is passed" do
before do
- knife.config[:user_key] = 'some_key'
- allow(File).to receive(:read).and_return('some_key')
+ knife.config[:user_key] = "some_key"
+ allow(File).to receive(:read).and_return("some_key")
allow(File).to receive(:expand_path)
end
it "sets user.public_key" do
knife.run
- expect(knife.user.public_key).to eq('some_key')
+ expect(knife.user.public_key).to eq("some_key")
end
end
@@ -186,25 +186,25 @@ describe Chef::Knife::UserCreate do
context "when a private_key is returned" do
before do
- allow(knife).to receive(:create_user_from_hash).and_return(Chef::UserV1.from_hash(knife.user.to_hash.merge({"private_key" => "some_private_key"})))
+ allow(knife).to receive(:create_user_from_hash).and_return(Chef::UserV1.from_hash(knife.user.to_hash.merge({ "private_key" => "some_private_key" })))
end
context "when --file is passed" do
before do
- knife.config[:file] = '/some/path'
+ knife.config[:file] = "/some/path"
end
it "creates a new file of the path passed" do
- filehandle = double('filehandle')
- expect(filehandle).to receive(:print).with('some_private_key')
- expect(File).to receive(:open).with('/some/path', 'w').and_yield(filehandle)
+ filehandle = double("filehandle")
+ expect(filehandle).to receive(:print).with("some_private_key")
+ expect(File).to receive(:open).with("/some/path", "w").and_yield(filehandle)
knife.run
end
end
context "when --file is not passed" do
it "prints the private key to stdout" do
- expect(knife.ui).to receive(:msg).with('some_private_key')
+ expect(knife.ui).to receive(:msg).with("some_private_key")
knife.run
end
end
diff --git a/spec/unit/knife/user_delete_spec.rb b/spec/unit/knife/user_delete_spec.rb
index a24160624a..0f71b39a41 100644
--- a/spec/unit/knife/user_delete_spec.rb
+++ b/spec/unit/knife/user_delete_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,18 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::UserDelete do
let(:knife) { Chef::Knife::UserDelete.new }
- let(:user) { double('user_object') }
+ let(:user) { double("user_object") }
let(:stdout) { StringIO.new }
before(:each) do
Chef::Knife::UserDelete.load_deps
- knife.name_args = [ 'my_user' ]
+ knife.name_args = [ "my_user" ]
allow(Chef::UserV1).to receive(:load).and_return(user)
- allow(user).to receive(:username).and_return('my_user')
+ allow(user).to receive(:username).and_return("my_user")
allow(knife.ui).to receive(:stderr).and_return(stdout)
allow(knife.ui).to receive(:stdout).and_return(stdout)
end
@@ -41,22 +41,22 @@ describe Chef::Knife::UserDelete do
it "displays the osc warning" do
expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
- expect{ knife.run }.to raise_error(SystemExit)
+ expect { knife.run }.to raise_error(SystemExit)
end
it "forwards the command to knife osc_user edit" do
expect(knife).to receive(:run_osc_11_user_delete)
- expect{ knife.run }.to raise_error(SystemExit)
+ expect { knife.run }.to raise_error(SystemExit)
end
end
- it 'deletes the user' do
+ it "deletes the user" do
#expect(knife).to receive(:delete_object).with(Chef::UserV1, 'my_user')
- expect(knife).to receive(:delete_object).with('my_user')
+ expect(knife).to receive(:delete_object).with("my_user")
knife.run
end
- it 'prints usage and exits when a user name is not provided' do
+ it "prints usage and exits when a user name is not provided" do
knife.name_args = []
expect(knife).to receive(:show_usage)
expect(knife.ui).to receive(:fatal)
diff --git a/spec/unit/knife/user_edit_spec.rb b/spec/unit/knife/user_edit_spec.rb
index a21d982d29..18ade54068 100644
--- a/spec/unit/knife/user_edit_spec.rb
+++ b/spec/unit/knife/user_edit_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::UserEdit do
let(:knife) { Chef::Knife::UserEdit.new }
@@ -28,7 +28,7 @@ describe Chef::Knife::UserEdit do
Chef::Knife::UserEdit.load_deps
allow(knife.ui).to receive(:stderr).and_return(@stderr)
allow(knife.ui).to receive(:stdout).and_return(@stdout)
- knife.name_args = [ 'my_user' ]
+ knife.name_args = [ "my_user" ]
knife.config[:disable_editing] = true
end
@@ -36,28 +36,28 @@ describe Chef::Knife::UserEdit do
context "when the username field is not supported by the server" do
before do
allow(knife).to receive(:run_osc_11_user_edit).and_raise(SystemExit)
- allow(Chef::UserV1).to receive(:load).and_return({"username" => nil})
+ allow(Chef::UserV1).to receive(:load).and_return({ "username" => nil })
end
it "displays the osc warning" do
expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
- expect{ knife.run }.to raise_error(SystemExit)
+ expect { knife.run }.to raise_error(SystemExit)
end
it "forwards the command to knife osc_user edit" do
expect(knife).to receive(:run_osc_11_user_edit)
- expect{ knife.run }.to raise_error(SystemExit)
+ expect { knife.run }.to raise_error(SystemExit)
end
end
- it 'loads and edits the user' do
+ it "loads and edits the user" do
data = { "username" => "my_user" }
allow(Chef::UserV1).to receive(:load).with("my_user").and_return(data)
- expect(knife).to receive(:edit_data).with(data).and_return(data)
+ expect(knife).to receive(:edit_hash).with(data).and_return(data)
knife.run
end
- it 'prints usage and exits when a user name is not provided' do
+ it "prints usage and exits when a user name is not provided" do
knife.name_args = []
expect(knife).to receive(:show_usage)
expect(knife.ui).to receive(:fatal)
diff --git a/spec/unit/knife/user_list_spec.rb b/spec/unit/knife/user_list_spec.rb
index fa2bac426e..bb135dbe03 100644
--- a/spec/unit/knife/user_list_spec.rb
+++ b/spec/unit/knife/user_list_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Steven Danna
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::UserList do
let(:knife) { Chef::Knife::UserList.new }
@@ -28,7 +28,7 @@ describe Chef::Knife::UserList do
allow(knife.ui).to receive(:stdout).and_return(stdout)
end
- it 'lists the users' do
+ it "lists the users" do
expect(Chef::UserV1).to receive(:list)
expect(knife).to receive(:format_list_for_display)
knife.run
diff --git a/spec/unit/knife/user_reregister_spec.rb b/spec/unit/knife/user_reregister_spec.rb
index 89aa6726cd..d650ff9fb8 100644
--- a/spec/unit/knife/user_reregister_spec.rb
+++ b/spec/unit/knife/user_reregister_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,20 +16,20 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::UserReregister do
let(:knife) { Chef::Knife::UserReregister.new }
- let(:user_mock) { double('user_mock', :private_key => "private_key") }
+ let(:user_mock) { double("user_mock", :private_key => "private_key") }
let(:stdout) { StringIO.new }
before do
Chef::Knife::UserReregister.load_deps
- knife.name_args = [ 'a_user' ]
+ knife.name_args = [ "a_user" ]
allow(Chef::UserV1).to receive(:load).and_return(user_mock)
allow(knife.ui).to receive(:stdout).and_return(stdout)
allow(knife.ui).to receive(:stderr).and_return(stdout)
- allow(user_mock).to receive(:username).and_return('a_user')
+ allow(user_mock).to receive(:username).and_return("a_user")
end
# delete this once OSC11 support is gone
@@ -41,33 +41,33 @@ describe Chef::Knife::UserReregister do
it "displays the osc warning" do
expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
- expect{ knife.run }.to raise_error(SystemExit)
+ expect { knife.run }.to raise_error(SystemExit)
end
it "forwards the command to knife osc_user edit" do
expect(knife).to receive(:run_osc_11_user_reregister)
- expect{ knife.run }.to raise_error(SystemExit)
+ expect { knife.run }.to raise_error(SystemExit)
end
end
- it 'prints usage and exits when a user name is not provided' do
+ it "prints usage and exits when a user name is not provided" do
knife.name_args = []
expect(knife).to receive(:show_usage)
expect(knife.ui).to receive(:fatal)
expect { knife.run }.to raise_error(SystemExit)
end
- it 'reregisters the user and prints the key' do
+ it "reregisters the user and prints the key" do
expect(user_mock).to receive(:reregister).and_return(user_mock)
knife.run
expect(stdout.string).to match( /private_key/ )
end
- it 'writes the private key to a file when --file is specified' do
+ it "writes the private key to a file when --file is specified" do
expect(user_mock).to receive(:reregister).and_return(user_mock)
- knife.config[:file] = '/tmp/a_file'
+ knife.config[:file] = "/tmp/a_file"
filehandle = StringIO.new
- expect(File).to receive(:open).with('/tmp/a_file', 'w').and_yield(filehandle)
+ expect(File).to receive(:open).with("/tmp/a_file", "w").and_yield(filehandle)
knife.run
expect(filehandle.string).to eq("private_key")
end
diff --git a/spec/unit/knife/user_show_spec.rb b/spec/unit/knife/user_show_spec.rb
index 7c39e428c0..3a38161b34 100644
--- a/spec/unit/knife/user_show_spec.rb
+++ b/spec/unit/knife/user_show_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Author:: Steven Danna (<steve@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,17 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Knife::UserShow do
let(:knife) { Chef::Knife::UserShow.new }
- let(:user_mock) { double('user_mock') }
+ let(:user_mock) { double("user_mock") }
let(:stdout) { StringIO.new }
before do
Chef::Knife::UserShow.load_deps
- knife.name_args = [ 'my_user' ]
- allow(user_mock).to receive(:username).and_return('my_user')
+ knife.name_args = [ "my_user" ]
+ allow(user_mock).to receive(:username).and_return("my_user")
allow(knife.ui).to receive(:stderr).and_return(stdout)
allow(knife.ui).to receive(:stdout).and_return(stdout)
end
@@ -35,28 +35,28 @@ describe Chef::Knife::UserShow do
context "when the username field is not supported by the server" do
before do
allow(knife).to receive(:run_osc_11_user_show).and_raise(SystemExit)
- allow(Chef::UserV1).to receive(:load).with('my_user').and_return(user_mock)
+ allow(Chef::UserV1).to receive(:load).with("my_user").and_return(user_mock)
allow(user_mock).to receive(:username).and_return(nil)
end
it "displays the osc warning" do
expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
- expect{ knife.run }.to raise_error(SystemExit)
+ expect { knife.run }.to raise_error(SystemExit)
end
it "forwards the command to knife osc_user edit" do
expect(knife).to receive(:run_osc_11_user_show)
- expect{ knife.run }.to raise_error(SystemExit)
+ expect { knife.run }.to raise_error(SystemExit)
end
end
- it 'loads and displays the user' do
- expect(Chef::UserV1).to receive(:load).with('my_user').and_return(user_mock)
+ it "loads and displays the user" do
+ expect(Chef::UserV1).to receive(:load).with("my_user").and_return(user_mock)
expect(knife).to receive(:format_for_display).with(user_mock)
knife.run
end
- it 'prints usage and exits when a user name is not provided' do
+ it "prints usage and exits when a user name is not provided" do
knife.name_args = []
expect(knife).to receive(:show_usage)
expect(knife.ui).to receive(:fatal)
diff --git a/spec/unit/knife_spec.rb b/spec/unit/knife_spec.rb
index 022256f370..9569526b2a 100644
--- a/spec/unit/knife_spec.rb
+++ b/spec/unit/knife_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,8 +21,9 @@
module KnifeSpecs
end
-require 'spec_helper'
-require 'uri'
+require "spec_helper"
+require "uri"
+require "chef/knife/core/gem_glob_loader"
describe Chef::Knife do
@@ -33,13 +34,16 @@ describe Chef::Knife do
let(:config_location) { File.expand_path("~/.chef/config.rb") }
let(:config_loader) do
- instance_double("WorkstationConfigLoader", load: nil, no_config_found?: false, config_location: config_location)
+ instance_double("WorkstationConfigLoader",
+ load: nil, no_config_found?: false,
+ config_location: config_location,
+ :chef_config_dir => "/etc/chef")
end
before(:each) do
Chef::Log.logger = Logger.new(StringIO.new)
- Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:node_name] = "webmonkey.example.com"
allow(Chef::WorkstationConfigLoader).to receive(:new).and_return(config_loader)
allow(config_loader).to receive(:explicit_config_file=)
@@ -60,6 +64,12 @@ describe Chef::Knife do
Chef::Knife.reset_config_loader!
end
+ it "does not reset Chef::Config[:verbosity to nil if config[:verbosity] is nil" do
+ Chef::Config[:verbosity] = 2
+ Chef::Knife.new
+ expect(Chef::Config[:verbosity]).to eq(2)
+ end
+
describe "after loading a subcommand" do
before do
Chef::Knife.reset_subcommands!
@@ -72,28 +82,28 @@ describe Chef::Knife do
KnifeSpecs.send(:remove_const, :TestExplicitCategory)
end
- Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_name_mapping.rb'))
- Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_explicit_category.rb'))
+ Kernel.load(File.join(CHEF_SPEC_DATA, "knife_subcommand", "test_name_mapping.rb"))
+ Kernel.load(File.join(CHEF_SPEC_DATA, "knife_subcommand", "test_explicit_category.rb"))
end
it "has a category based on its name" do
- expect(KnifeSpecs::TestNameMapping.subcommand_category).to eq('test')
+ expect(KnifeSpecs::TestNameMapping.subcommand_category).to eq("test")
end
it "has an explicitly defined category if set" do
- expect(KnifeSpecs::TestExplicitCategory.subcommand_category).to eq('cookbook site')
+ expect(KnifeSpecs::TestExplicitCategory.subcommand_category).to eq("cookbook site")
end
it "can reference the subcommand by its snake cased name" do
- expect(Chef::Knife.subcommands['test_name_mapping']).to equal(KnifeSpecs::TestNameMapping)
+ expect(Chef::Knife.subcommands["test_name_mapping"]).to equal(KnifeSpecs::TestNameMapping)
end
it "lists subcommands by category" do
- expect(Chef::Knife.subcommands_by_category['test']).to include('test_name_mapping')
+ expect(Chef::Knife.subcommands_by_category["test"]).to include("test_name_mapping")
end
it "lists subcommands by category when the subcommands have explicit categories" do
- expect(Chef::Knife.subcommands_by_category['cookbook site']).to include('test_explicit_category')
+ expect(Chef::Knife.subcommands_by_category["cookbook site"]).to include("test_explicit_category")
end
it "has empty dependency_loader list by default" do
@@ -117,12 +127,20 @@ describe Chef::Knife do
expect(Chef::Knife.subcommands["super_awesome_command"]).to eq(SuperAwesomeCommand)
end
+ it "records the location of ChefFS-based commands correctly" do
+ class AwesomeCheffsCommand < Chef::ChefFS::Knife
+ end
+
+ Chef::Knife.load_commands
+ expect(Chef::Knife.subcommand_files["awesome_cheffs_command"]).to eq([__FILE__])
+ end
+
it "guesses a category from a given ARGV" do
Chef::Knife.subcommands_by_category["cookbook"] << :cookbook
Chef::Knife.subcommands_by_category["cookbook site"] << :cookbook_site
- expect(Chef::Knife.guess_category(%w{cookbook foo bar baz})).to eq('cookbook')
- expect(Chef::Knife.guess_category(%w{cookbook site foo bar baz})).to eq('cookbook site')
- expect(Chef::Knife.guess_category(%w{cookbook site --help})).to eq('cookbook site')
+ expect(Chef::Knife.guess_category(%w{cookbook foo bar baz})).to eq("cookbook")
+ expect(Chef::Knife.guess_category(%w{cookbook site foo bar baz})).to eq("cookbook site")
+ expect(Chef::Knife.guess_category(%w{cookbook site --help})).to eq("cookbook site")
end
it "finds a subcommand class based on ARGV" do
@@ -131,18 +149,25 @@ describe Chef::Knife do
expect(Chef::Knife.subcommand_class_from(%w{cookbook site vendor --help foo bar baz})).to eq(:CookbookSiteVendor)
end
+ it "special case sets the subcommand_loader to GemGlobLoader when running rehash" do
+ Chef::Knife.subcommands["rehash"] = :Rehash
+ expect(Chef::Knife.subcommand_class_from(%w{rehash })).to eq(:Rehash)
+ expect(Chef::Knife.subcommand_loader).to be_a(Chef::Knife::SubcommandLoader::GemGlobLoader)
+ end
+
end
describe "the headers include X-Remote-Request-Id" do
- let(:headers) {{"Accept"=>"application/json",
- "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
- 'X-Chef-Version' => Chef::VERSION,
- "Host"=>"api.opscode.piab",
- "X-REMOTE-REQUEST-ID"=>request_id,
- 'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION}}
+ let(:headers) do
+ { "Accept" => "application/json",
+ "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
+ "X-Chef-Version" => Chef::VERSION,
+ "Host" => "api.opscode.piab",
+ "X-REMOTE-REQUEST-ID" => request_id,
+ } end
- let(:request_id) {"1234"}
+ let(:request_id) { "1234" }
let(:request_mock) { {} }
@@ -178,13 +203,13 @@ describe Chef::Knife do
if KnifeSpecs.const_defined?(:TestYourself)
KnifeSpecs.send :remove_const, :TestYourself
end
- Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_yourself.rb'))
+ Kernel.load(File.join(CHEF_SPEC_DATA, "knife_subcommand", "test_yourself.rb"))
Chef::Knife.subcommands.each { |name, klass| Chef::Knife.subcommands.delete(name) unless klass.kind_of?(Class) }
end
it "confirms that the headers include X-Remote-Request-Id" do
expect(Net::HTTP::Get).to receive(:new).with("/monkey", headers).and_return(request_mock)
- rest.get_rest("monkey")
+ rest.get("monkey")
end
end
@@ -193,16 +218,16 @@ describe Chef::Knife do
if KnifeSpecs.const_defined?(:TestYourself)
KnifeSpecs.send :remove_const, :TestYourself
end
- Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_yourself.rb'))
+ Kernel.load(File.join(CHEF_SPEC_DATA, "knife_subcommand", "test_yourself.rb"))
Chef::Knife.subcommands.each { |name, klass| Chef::Knife.subcommands.delete(name) unless klass.kind_of?(Class) }
end
it "merges the global knife CLI options" do
extra_opts = {}
- extra_opts[:editor] = {:long=>"--editor EDITOR",
- :description=>"Set the editor to use for interactive commands",
- :short=>"-e EDITOR",
- :default=>"/usr/bin/vim"}
+ extra_opts[:editor] = { :long => "--editor EDITOR",
+ :description => "Set the editor to use for interactive commands",
+ :short => "-e EDITOR",
+ :default => "/usr/bin/vim" }
# there is special hackery to return the subcommand instance going on here.
command = Chef::Knife.run(%w{test yourself}, extra_opts)
@@ -235,7 +260,7 @@ describe Chef::Knife do
allow(Chef::Knife.ui).to receive(:stderr).and_return(stderr)
allow(Chef::Knife.ui).to receive(:stdout).and_return(stdout)
expect(Chef::Knife.ui).to receive(:fatal)
- expect {Chef::Knife.run(%w{fuuu uuuu fuuuu})}.to raise_error(SystemExit) { |e| expect(e.status).not_to eq(0) }
+ expect { Chef::Knife.run(%w{fuuu uuuu fuuuu}) }.to raise_error(SystemExit) { |e| expect(e.status).not_to eq(0) }
end
it "loads lazy dependencies" do
@@ -294,11 +319,11 @@ describe Chef::Knife do
end
it "merges `listen` config to Chef::Config" do
- Chef::Knife.run(%w[test yourself --no-listen], Chef::Application::Knife.options)
+ Chef::Knife.run(%w{test yourself --no-listen}, Chef::Application::Knife.options)
expect(Chef::Config[:listen]).to be(false)
end
- context "verbosity is greater than zero" do
+ context "verbosity is one" do
let(:fake_config) { "/does/not/exist/knife.rb" }
before do
@@ -316,7 +341,45 @@ describe Chef::Knife do
knife.configure_chef
end
end
+
+ it "does not humanize the exception if Chef::Config[:verbosity] is two" do
+ Chef::Config[:verbosity] = 2
+ allow(knife).to receive(:run).and_raise(Exception)
+ expect(knife).not_to receive(:humanize_exception)
+ expect { knife.run_with_pretty_exceptions }.to raise_error(Exception)
+ end
end
+
+ describe "setting arbitrary configuration with --config-option" do
+
+ let(:stdout) { StringIO.new }
+
+ let(:stderr) { StringIO.new }
+
+ let(:stdin) { StringIO.new }
+
+ let(:ui) { Chef::Knife::UI.new(stdout, stderr, stdin, disable_editing: true) }
+
+ let(:subcommand) do
+ KnifeSpecs::TestYourself.options = Chef::Application::Knife.options.merge(KnifeSpecs::TestYourself.options)
+ KnifeSpecs::TestYourself.new(%w{--config-option badly_formatted_arg}).tap do |cmd|
+ cmd.ui = ui
+ end
+ end
+
+ it "sets arbitrary configuration via --config-option" do
+ Chef::Knife.run(%w{test yourself --config-option arbitrary_config_thing=hello}, Chef::Application::Knife.options)
+ expect(Chef::Config[:arbitrary_config_thing]).to eq("hello")
+ end
+
+ it "handles errors in arbitrary configuration" do
+ expect(subcommand).to receive(:exit).with(1)
+ subcommand.configure_chef
+ expect(stderr.string).to include("ERROR: Unparsable config option \"badly_formatted_arg\"")
+ expect(stdout.string).to include(subcommand.opt_parser.to_s)
+ end
+ end
+
end
describe "when first created" do
@@ -325,12 +388,12 @@ describe Chef::Knife do
before do
unless KnifeSpecs.const_defined?(:TestYourself)
- Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_yourself.rb'))
+ Kernel.load(File.join(CHEF_SPEC_DATA, "knife_subcommand", "test_yourself.rb"))
end
end
it "it parses the options passed to it" do
- expect(knife.config[:scro]).to eq('scrogramming')
+ expect(knife.config[:scro]).to eq("scrogramming")
end
it "extracts its command specific args from the full arg list" do
@@ -372,8 +435,8 @@ describe Chef::Knife do
allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("403 Forbidden", response))
allow(knife).to receive(:username).and_return("sadpanda")
knife.run_with_pretty_exceptions
- expect(stderr.string).to match(%r[ERROR: You authenticated successfully to http.+ as sadpanda but you are not authorized for this action])
- expect(stderr.string).to match(%r[Response: y u no administrator])
+ expect(stderr.string).to match(%r{ERROR: You authenticated successfully to http.+ as sadpanda but you are not authorized for this action})
+ expect(stderr.string).to match(%r{Response: y u no administrator})
end
it "formats 400s nicely" do
@@ -382,8 +445,8 @@ describe Chef::Knife do
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "y u search wrong"))
allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("400 Bad Request", response))
knife.run_with_pretty_exceptions
- expect(stderr.string).to match(%r[ERROR: The data in your request was invalid])
- expect(stderr.string).to match(%r[Response: y u search wrong])
+ expect(stderr.string).to match(%r{ERROR: The data in your request was invalid})
+ expect(stderr.string).to match(%r{Response: y u search wrong})
end
it "formats 404s nicely" do
@@ -392,8 +455,8 @@ describe Chef::Knife do
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "nothing to see here"))
allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("404 Not Found", response))
knife.run_with_pretty_exceptions
- expect(stderr.string).to match(%r[ERROR: The object you are looking for could not be found])
- expect(stderr.string).to match(%r[Response: nothing to see here])
+ expect(stderr.string).to match(%r{ERROR: The object you are looking for could not be found})
+ expect(stderr.string).to match(%r{Response: nothing to see here})
end
it "formats 406s (non-supported API version error) nicely" do
@@ -407,9 +470,9 @@ describe Chef::Knife do
allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("406 Not Acceptable", response))
knife.run_with_pretty_exceptions
- expect(stderr.string).to include('The request that Knife sent was using API version 10000000')
- expect(stderr.string).to include('The Chef server you sent the request to supports a min API verson of 0 and a max API version of 1')
- expect(stderr.string).to include('Please either update your Chef client or server to be a compatible set')
+ expect(stderr.string).to include("The request that Knife sent was using API version 10000000")
+ expect(stderr.string).to include("The Chef server you sent the request to supports a min API verson of 0 and a max API version of 1")
+ expect(stderr.string).to include("Please either update your Chef client or server to be a compatible set")
end
it "formats 500s nicely" do
@@ -418,8 +481,8 @@ describe Chef::Knife do
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "sad trombone"))
allow(knife).to receive(:run).and_raise(Net::HTTPFatalError.new("500 Internal Server Error", response))
knife.run_with_pretty_exceptions
- expect(stderr.string).to match(%r[ERROR: internal server error])
- expect(stderr.string).to match(%r[Response: sad trombone])
+ expect(stderr.string).to match(%r{ERROR: internal server error})
+ expect(stderr.string).to match(%r{Response: sad trombone})
end
it "formats 502s nicely" do
@@ -428,8 +491,8 @@ describe Chef::Knife do
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "sadder trombone"))
allow(knife).to receive(:run).and_raise(Net::HTTPFatalError.new("502 Bad Gateway", response))
knife.run_with_pretty_exceptions
- expect(stderr.string).to match(%r[ERROR: bad gateway])
- expect(stderr.string).to match(%r[Response: sadder trombone])
+ expect(stderr.string).to match(%r{ERROR: bad gateway})
+ expect(stderr.string).to match(%r{Response: sadder trombone})
end
it "formats 503s nicely" do
@@ -438,8 +501,8 @@ describe Chef::Knife do
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "saddest trombone"))
allow(knife).to receive(:run).and_raise(Net::HTTPFatalError.new("503 Service Unavailable", response))
knife.run_with_pretty_exceptions
- expect(stderr.string).to match(%r[ERROR: Service temporarily unavailable])
- expect(stderr.string).to match(%r[Response: saddest trombone])
+ expect(stderr.string).to match(%r{ERROR: Service temporarily unavailable})
+ expect(stderr.string).to match(%r{Response: saddest trombone})
end
it "formats other HTTP errors nicely" do
@@ -448,34 +511,34 @@ describe Chef::Knife do
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "nobugfixtillyoubuy"))
allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("402 Payment Required", response))
knife.run_with_pretty_exceptions
- expect(stderr.string).to match(%r[ERROR: Payment Required])
- expect(stderr.string).to match(%r[Response: nobugfixtillyoubuy])
+ expect(stderr.string).to match(%r{ERROR: Payment Required})
+ expect(stderr.string).to match(%r{Response: nobugfixtillyoubuy})
end
it "formats NameError and NoMethodError nicely" do
allow(knife).to receive(:run).and_raise(NameError.new("Undefined constant FUUU"))
knife.run_with_pretty_exceptions
- expect(stderr.string).to match(%r[ERROR: knife encountered an unexpected error])
- expect(stderr.string).to match(%r[This may be a bug in the 'knife' knife command or plugin])
- expect(stderr.string).to match(%r[Exception: NameError: Undefined constant FUUU])
+ expect(stderr.string).to match(%r{ERROR: knife encountered an unexpected error})
+ expect(stderr.string).to match(%r{This may be a bug in the 'knife' knife command or plugin})
+ expect(stderr.string).to match(%r{Exception: NameError: Undefined constant FUUU})
end
it "formats missing private key errors nicely" do
- allow(knife).to receive(:run).and_raise(Chef::Exceptions::PrivateKeyMissing.new('key not there'))
+ allow(knife).to receive(:run).and_raise(Chef::Exceptions::PrivateKeyMissing.new("key not there"))
allow(knife).to receive(:api_key).and_return("/home/root/.chef/no-key-here.pem")
knife.run_with_pretty_exceptions
- expect(stderr.string).to match(%r[ERROR: Your private key could not be loaded from /home/root/.chef/no-key-here.pem])
- expect(stderr.string).to match(%r[Check your configuration file and ensure that your private key is readable])
+ expect(stderr.string).to match(%r{ERROR: Your private key could not be loaded from /home/root/.chef/no-key-here.pem})
+ expect(stderr.string).to match(%r{Check your configuration file and ensure that your private key is readable})
end
it "formats connection refused errors nicely" do
- allow(knife).to receive(:run).and_raise(Errno::ECONNREFUSED.new('y u no shut up'))
+ allow(knife).to receive(:run).and_raise(Errno::ECONNREFUSED.new("y u no shut up"))
knife.run_with_pretty_exceptions
# Errno::ECONNREFUSED message differs by platform
# *nix = Errno::ECONNREFUSED: Connection refused
# win32: Errno::ECONNREFUSED: No connection could be made because the target machine actively refused it.
- expect(stderr.string).to match(%r[ERROR: Network Error: .* - y u no shut up])
- expect(stderr.string).to match(%r[Check your knife configuration and network settings])
+ expect(stderr.string).to match(%r{ERROR: Network Error: .* - y u no shut up})
+ expect(stderr.string).to match(%r{Check your knife configuration and network settings})
end
it "formats SSL errors nicely and suggests to use `knife ssl check` and `knife ssl fetch`" do
@@ -484,7 +547,7 @@ describe Chef::Knife do
knife.run_with_pretty_exceptions
- expected_message=<<-MSG
+ expected_message = <<-MSG
ERROR: Could not establish a secure connection to the server.
Use `knife ssl check` to troubleshoot your SSL configuration.
If your Chef Server uses a self-signed certificate, you can use
diff --git a/spec/unit/lib_backcompat_spec.rb b/spec/unit/lib_backcompat_spec.rb
new file mode 100644
index 0000000000..c7dfee5bcd
--- /dev/null
+++ b/spec/unit/lib_backcompat_spec.rb
@@ -0,0 +1,34 @@
+#
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe "lib-backcompat" do
+ it "require 'chef/chef_fs/file_system/chef_server_root_dir' yields the proper class" do
+ require "chef/chef_fs/file_system/chef_server_root_dir"
+ expect(Chef::ChefFS::FileSystem::ChefServerRootDir).to eq(Chef::ChefFS::FileSystem::ChefServer::ChefServerRootDir)
+ end
+ it "require 'chef/chef_fs/file_system/chef_repository_file_system_root_dir' yields the proper class" do
+ require "chef/chef_fs/file_system/chef_repository_file_system_root_dir"
+ expect(Chef::ChefFS::FileSystem::ChefRepositoryFileSystemRootDir).to eq(Chef::ChefFS::FileSystem::Repository::ChefRepositoryFileSystemRootDir)
+ end
+ it "require 'chef/chef_fs/file_system/acl_entry' yields the proper class" do
+ require "chef/chef_fs/file_system/acl_entry"
+ expect(Chef::ChefFS::FileSystem::AclEntry).to eq(Chef::ChefFS::FileSystem::ChefServer::AclEntry)
+ end
+end
diff --git a/spec/unit/log/syslog_spec.rb b/spec/unit/log/syslog_spec.rb
index 3db90e50c6..ebf1418576 100644
--- a/spec/unit/log/syslog_spec.rb
+++ b/spec/unit/log/syslog_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: SAWANOBORI Yukihiko (<sawanoboriyu@higanworks.com>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef'
+require "spec_helper"
+require "chef"
describe "Chef::Log::Syslog", :unix_only => true do
let(:syslog) { Chef::Log::Syslog.new }
diff --git a/spec/unit/log/winevt_spec.rb b/spec/unit/log/winevt_spec.rb
index 867ef55900..d5d452159b 100644
--- a/spec/unit/log/winevt_spec.rb
+++ b/spec/unit/log/winevt_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Jay Mundrawala (jdm@chef.io)
# Author:: SAWANOBORI Yukihiko (<sawanoboriyu@higanworks.com>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Log::WinEvt do
- let(:evtlog) { instance_double("Win32::EventLog")}
+ let(:evtlog) { instance_double("Win32::EventLog") }
let(:winevt) { Chef::Log::WinEvt.new(evtlog) }
let(:app) { Chef::Application.new }
diff --git a/spec/unit/log_spec.rb b/spec/unit/log_spec.rb
index 7be40f77e6..929a24a95b 100644
--- a/spec/unit/log_spec.rb
+++ b/spec/unit/log_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'tempfile'
-require 'logger'
-require 'spec_helper'
+require "tempfile"
+require "logger"
+require "spec_helper"
describe Chef::Log do
end
diff --git a/spec/unit/lwrp_spec.rb b/spec/unit/lwrp_spec.rb
index 7f6d315bbb..9700b8ef2b 100644
--- a/spec/unit/lwrp_spec.rb
+++ b/spec/unit/lwrp_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tmpdir'
-require 'fileutils'
-require 'chef/mixin/convert_to_class_name'
+require "spec_helper"
+require "tmpdir"
+require "fileutils"
+require "chef/mixin/convert_to_class_name"
module LwrpConstScopingConflict
end
@@ -28,13 +28,13 @@ describe "LWRP" do
include Chef::Mixin::ConvertToClassName
before do
- @original_VERBOSE = $VERBOSE
+ @original_verbose = $VERBOSE
$VERBOSE = nil
Chef::Resource::LWRPBase.class_eval { @loaded_lwrps = {} }
end
after do
- $VERBOSE = @original_VERBOSE
+ $VERBOSE = @original_verbose
end
def get_lwrp(name)
@@ -57,21 +57,21 @@ describe "LWRP" do
end
it "should not skip loading a resource when there's a top level symbol of the same name" do
- Object.const_set('LwrpFoo', Class.new)
+ Object.const_set("LwrpFoo", Class.new)
file = File.expand_path( "lwrp/resources/foo.rb", CHEF_SPEC_DATA)
expect(Chef::Log).not_to receive(:info).with(/Skipping/)
expect(Chef::Log).not_to receive(:debug).with(/anymore/)
Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
- Object.send(:remove_const, 'LwrpFoo')
+ Object.send(:remove_const, "LwrpFoo")
end
it "should not skip loading a provider when there's a top level symbol of the same name" do
- Object.const_set('LwrpBuckPasser', Class.new)
+ Object.const_set("LwrpBuckPasser", Class.new)
file = File.expand_path( "lwrp/providers/buck_passer.rb", CHEF_SPEC_DATA)
expect(Chef::Log).not_to receive(:info).with(/Skipping/)
expect(Chef::Log).not_to receive(:debug).with(/anymore/)
Chef::Provider::LWRPBase.build_from_file("lwrp", file, nil)
- Object.send(:remove_const, 'LwrpBuckPasser')
+ Object.send(:remove_const, "LwrpBuckPasser")
end
# @todo: we need a before block to manually remove_const all of the LWRPs that we
@@ -84,7 +84,7 @@ describe "LWRP" do
end
Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file|
- expect(Chef::Log).to receive(:info).with(/Skipping/)
+ expect(Chef::Log).to receive(:debug).with(/Skipping/)
Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
end
end
@@ -95,7 +95,7 @@ describe "LWRP" do
end
Dir[File.expand_path( "lwrp/providers/*", CHEF_SPEC_DATA)].each do |file|
- expect(Chef::Log).to receive(:info).with(/Skipping/)
+ expect(Chef::Log).to receive(:debug).with(/Skipping/)
Chef::Provider::LWRPBase.build_from_file("lwrp", file, nil)
end
end
@@ -202,7 +202,7 @@ describe "LWRP" do
end
it "should create a method for each attribute" do
- expect(get_lwrp(:lwrp_foo).new("blah").methods.map{ |m| m.to_sym}).to include(:monkey)
+ expect(get_lwrp(:lwrp_foo).new("blah").methods.map { |m| m.to_sym }).to include(:monkey)
end
it "should build attribute methods that respect validation rules" do
@@ -232,9 +232,9 @@ describe "LWRP" do
end
it "allows to user to user the resource_name" do
- expect {
+ expect do
klass.resource_name(:foo)
- }.to_not raise_error
+ end.to_not raise_error
end
it "returns the set value for the resource" do
@@ -246,19 +246,19 @@ describe "LWRP" do
let(:klass) do
Class.new(Chef::Resource::LWRPBase) do
self.resource_name = :sample_resource
- attribute :food, :default => lazy { 'BACON!'*3 }
- attribute :drink, :default => lazy { |r| "Drink after #{r.food}!"}
+ attribute :food, :default => lazy { "BACON!" * 3 }
+ attribute :drink, :default => lazy { |r| "Drink after #{r.food}!" }
end
end
- let(:instance) { klass.new('kitchen') }
+ let(:instance) { klass.new("kitchen") }
it "evaluates the default value when requested" do
- expect(instance.food).to eq('BACON!BACON!BACON!')
+ expect(instance.food).to eq("BACON!BACON!BACON!")
end
it "evaluates yields self to the block" do
- expect(instance.drink).to eq('Drink after BACON!BACON!BACON!!')
+ expect(instance.drink).to eq("Drink after BACON!BACON!BACON!!")
end
end
end
@@ -325,7 +325,7 @@ describe "LWRP" do
end
def raise_if_deprecated!
- if Chef::VERSION.split('.').first.to_i > 12
+ if Chef::VERSION.split(".").first.to_i > 12
raise "This test should be removed and the associated code should be removed!"
end
end
@@ -344,7 +344,7 @@ describe "LWRP" do
end
end
let(:resource) do
- resource_class.new('blah')
+ resource_class.new("blah")
end
it "actions includes those actions" do
expect(resource_class.actions).to eq [ :nothing, :eat, :sleep ]
@@ -364,7 +364,7 @@ describe "LWRP" do
end
end
let(:resource) do
- resource_class.new('blah')
+ resource_class.new("blah")
end
it "actions includes those actions" do
expect(resource_class.actions).to eq [ :nothing, :eat, :sleep ]
@@ -383,7 +383,7 @@ describe "LWRP" do
let(:node) do
Chef::Node.new.tap do |n|
n.automatic[:platform] = :ubuntu
- n.automatic[:platform_version] = '8.10'
+ n.automatic[:platform_version] = "8.10"
end
end
@@ -413,8 +413,7 @@ describe "LWRP" do
resource = get_lwrp(:lwrp_foo).new("morpheus", run_context)
resource.monkey("bob")
resource.provider(get_lwrp_provider(:lwrp_monkey_name_printer))
-
- provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs)
+ provider = resource.provider_for_action(:twiddle_thumbs)
provider.action_twiddle_thumbs
end
@@ -483,8 +482,8 @@ describe "LWRP" do
Chef::Runner.new(run_context).converge
expect(run_context.resource_collection[0]).to eql(injector)
- expect(run_context.resource_collection[1].name).to eql('prepared_thumbs')
- expect(run_context.resource_collection[2].name).to eql('twiddled_thumbs')
+ expect(run_context.resource_collection[1].name).to eql("prepared_thumbs")
+ expect(run_context.resource_collection[2].name).to eql("twiddled_thumbs")
expect(run_context.resource_collection[3]).to eql(dummy)
end
@@ -507,12 +506,12 @@ describe "LWRP" do
Chef::Runner.new(run_context).converge
expect(run_context.resource_collection[0]).to eql(injector)
- expect(run_context.resource_collection[1].name).to eql('prepared_thumbs')
- expect(run_context.resource_collection[2].name).to eql('twiddled_thumbs')
+ expect(run_context.resource_collection[1].name).to eql("prepared_thumbs")
+ expect(run_context.resource_collection[2].name).to eql("twiddled_thumbs")
expect(run_context.resource_collection[3]).to eql(dummy)
expect(run_context.resource_collection[4]).to eql(injector2)
- expect(run_context.resource_collection[5].name).to eql('prepared_eyes')
- expect(run_context.resource_collection[6].name).to eql('dried_paint_watched')
+ expect(run_context.resource_collection[5].name).to eql("prepared_eyes")
+ expect(run_context.resource_collection[6].name).to eql("dried_paint_watched")
end
it "should properly handle a new_resource reference" do
@@ -520,7 +519,7 @@ describe "LWRP" do
resource.monkey("bob")
resource.provider(get_lwrp_provider(:lwrp_monkey_name_printer))
- provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs)
+ provider = resource.provider_for_action(:twiddle_thumbs)
provider.action_twiddle_thumbs
expect(provider.monkey_name).to eq("my monkey's name is 'bob'")
@@ -531,11 +530,11 @@ describe "LWRP" do
resource.monkey("bob")
resource.provider(get_lwrp_provider(:lwrp_embedded_resource_accesses_providers_scope))
- provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs)
+ provider = resource.provider_for_action(:twiddle_thumbs)
#provider = @runner.build_provider(resource)
provider.action_twiddle_thumbs
- expect(provider.enclosed_resource.monkey).to eq('bob, the monkey')
+ expect(provider.enclosed_resource.monkey).to eq("bob, the monkey")
end
describe "when using inline compilation" do
@@ -603,7 +602,7 @@ describe "LWRP" do
end
it "get_lwrp(:lwrp_once).new is a Chef::Resource::LwrpOnce" do
- lwrp = get_lwrp(:lwrp_once).new('hi')
+ lwrp = get_lwrp(:lwrp_once).new("hi")
expect(lwrp.kind_of?(Chef::Resource::LwrpOnce)).to be_truthy
expect(lwrp.is_a?(Chef::Resource::LwrpOnce)).to be_truthy
expect(get_lwrp(:lwrp_once) === lwrp).to be_truthy
@@ -611,7 +610,7 @@ describe "LWRP" do
end
it "Chef::Resource::LwrpOnce.new is a get_lwrp(:lwrp_once)" do
- lwrp = Chef::Resource::LwrpOnce.new('hi')
+ lwrp = Chef::Resource::LwrpOnce.new("hi")
expect(lwrp.kind_of?(get_lwrp(:lwrp_once))).to be_truthy
expect(lwrp.is_a?(get_lwrp(:lwrp_once))).to be_truthy
expect(get_lwrp(:lwrp_once) === lwrp).to be_truthy
@@ -639,35 +638,35 @@ describe "LWRP" do
end
it "subclass.new is a subclass" do
- lwrp = subclass.new('hi')
+ lwrp = subclass.new("hi")
expect(lwrp.kind_of?(subclass)).to be_truthy
expect(lwrp.is_a?(subclass)).to be_truthy
expect(subclass === lwrp).to be_truthy
expect(lwrp.class === subclass)
end
it "subclass.new is a Chef::Resource::LwrpOnce" do
- lwrp = subclass.new('hi')
+ lwrp = subclass.new("hi")
expect(lwrp.kind_of?(Chef::Resource::LwrpOnce)).to be_truthy
expect(lwrp.is_a?(Chef::Resource::LwrpOnce)).to be_truthy
expect(Chef::Resource::LwrpOnce === lwrp).to be_truthy
expect(lwrp.class === Chef::Resource::LwrpOnce)
end
it "subclass.new is a get_lwrp(:lwrp_once)" do
- lwrp = subclass.new('hi')
+ lwrp = subclass.new("hi")
expect(lwrp.kind_of?(get_lwrp(:lwrp_once))).to be_truthy
expect(lwrp.is_a?(get_lwrp(:lwrp_once))).to be_truthy
expect(get_lwrp(:lwrp_once) === lwrp).to be_truthy
expect(lwrp.class === get_lwrp(:lwrp_once))
end
it "Chef::Resource::LwrpOnce.new is *not* a subclass" do
- lwrp = Chef::Resource::LwrpOnce.new('hi')
+ lwrp = Chef::Resource::LwrpOnce.new("hi")
expect(lwrp.kind_of?(subclass)).to be_falsey
expect(lwrp.is_a?(subclass)).to be_falsey
expect(subclass === lwrp.class).to be_falsey
expect(subclass === Chef::Resource::LwrpOnce).to be_falsey
end
it "get_lwrp(:lwrp_once).new is *not* a subclass" do
- lwrp = get_lwrp(:lwrp_once).new('hi')
+ lwrp = get_lwrp(:lwrp_once).new("hi")
expect(lwrp.kind_of?(subclass)).to be_falsey
expect(lwrp.is_a?(subclass)).to be_falsey
expect(subclass === lwrp.class).to be_falsey
@@ -681,35 +680,35 @@ describe "LWRP" do
end
it "subclass.new is a subclass" do
- lwrp = subclass.new('hi')
+ lwrp = subclass.new("hi")
expect(lwrp.kind_of?(subclass)).to be_truthy
expect(lwrp.is_a?(subclass)).to be_truthy
expect(subclass === lwrp).to be_truthy
expect(lwrp.class === subclass)
end
it "subclass.new is a Chef::Resource::LwrpOnce" do
- lwrp = subclass.new('hi')
+ lwrp = subclass.new("hi")
expect(lwrp.kind_of?(Chef::Resource::LwrpOnce)).to be_truthy
expect(lwrp.is_a?(Chef::Resource::LwrpOnce)).to be_truthy
expect(Chef::Resource::LwrpOnce === lwrp).to be_truthy
expect(lwrp.class === Chef::Resource::LwrpOnce)
end
it "subclass.new is a get_lwrp(:lwrp_once)" do
- lwrp = subclass.new('hi')
+ lwrp = subclass.new("hi")
expect(lwrp.kind_of?(get_lwrp(:lwrp_once))).to be_truthy
expect(lwrp.is_a?(get_lwrp(:lwrp_once))).to be_truthy
expect(get_lwrp(:lwrp_once) === lwrp).to be_truthy
expect(lwrp.class === get_lwrp(:lwrp_once))
end
it "Chef::Resource::LwrpOnce.new is *not* a subclass" do
- lwrp = Chef::Resource::LwrpOnce.new('hi')
+ lwrp = Chef::Resource::LwrpOnce.new("hi")
expect(lwrp.kind_of?(subclass)).to be_falsey
expect(lwrp.is_a?(subclass)).to be_falsey
expect(subclass === lwrp.class).to be_falsey
expect(subclass === Chef::Resource::LwrpOnce).to be_falsey
end
it "get_lwrp(:lwrp_once).new is *not* a subclass" do
- lwrp = get_lwrp(:lwrp_once).new('hi')
+ lwrp = get_lwrp(:lwrp_once).new("hi")
expect(lwrp.kind_of?(subclass)).to be_falsey
expect(lwrp.is_a?(subclass)).to be_falsey
expect(subclass === lwrp.class).to be_falsey
@@ -717,6 +716,62 @@ describe "LWRP" do
end
end
end
-end
+ describe "extending the DSL mixin" do
+ module MyAwesomeDSLExensionClass
+ def my_awesome_dsl_extension(argument)
+ argument
+ end
+ end
+
+ class MyAwesomeResource < Chef::Resource::LWRPBase
+ provides :my_awesome_resource
+ resource_name :my_awesome_resource
+ default_action :create
+ end
+
+ class MyAwesomeProvider < Chef::Provider::LWRPBase
+ use_inline_resources
+
+ provides :my_awesome_resource
+
+ action :create do
+ my_awesome_dsl_extension("foo")
+ end
+ end
+
+ let(:recipe) do
+ cookbook_repo = File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks"))
+ cookbook_loader = Chef::CookbookLoader.new(cookbook_repo)
+ cookbook_loader.load_cookbooks
+ cookbook_collection = Chef::CookbookCollection.new(cookbook_loader)
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, cookbook_collection, events)
+ Chef::Recipe.new("hjk", "test", run_context)
+ end
+
+ it "lets you extend the recipe DSL" do
+ expect(Chef::Recipe).to receive(:include).with(MyAwesomeDSLExensionClass)
+ expect(Chef::Resource::ActionClass).to receive(:include).with(MyAwesomeDSLExensionClass)
+ Chef::DSL::Recipe.send(:include, MyAwesomeDSLExensionClass)
+ end
+
+ it "lets you call your DSL from a recipe" do
+ Chef::DSL::Recipe.send(:include, MyAwesomeDSLExensionClass)
+ expect(recipe.my_awesome_dsl_extension("foo")).to eql("foo")
+ end
+ it "lets you call your DSL from a provider" do
+ Chef::DSL::Recipe.send(:include, MyAwesomeDSLExensionClass)
+
+ resource = MyAwesomeResource.new("name", run_context)
+ run_context.resource_collection << resource
+
+ runner = Chef::Runner.new(run_context)
+ expect_any_instance_of(MyAwesomeProvider).to receive(:my_awesome_dsl_extension).and_call_original
+ runner.converge
+ end
+ end
+
+end
diff --git a/spec/unit/mash_spec.rb b/spec/unit/mash_spec.rb
index b8f4c2d5aa..e58f6b85a1 100644
--- a/spec/unit/mash_spec.rb
+++ b/spec/unit/mash_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Matthew Kent (<mkent@magoazul.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mash'
+require "spec_helper"
+require "chef/mash"
describe Mash do
it "should duplicate a simple key/value mash to a new mash" do
- data = {:x=>"one", :y=>"two", :z=>"three"}
+ data = { :x => "one", :y => "two", :z => "three" }
@orig = Mash.new(data)
@copy = @orig.dup
expect(@copy.to_hash).to eq(Mash.new(data).to_hash)
@@ -30,21 +30,21 @@ describe Mash do
end
it "should duplicate a mash with an array to a new mash" do
- data = {:x=>"one", :y=>"two", :z=>[1,2,3]}
+ data = { :x => "one", :y => "two", :z => [1, 2, 3] }
@orig = Mash.new(data)
@copy = @orig.dup
expect(@copy.to_hash).to eq(Mash.new(data).to_hash)
@copy[:z] << 4
- expect(@orig[:z]).to eq([1,2,3])
+ expect(@orig[:z]).to eq([1, 2, 3])
end
it "should duplicate a nested mash to a new mash" do
- data = {:x=>"one", :y=>"two", :z=>Mash.new({:a=>[1,2,3]})}
+ data = { :x => "one", :y => "two", :z => Mash.new({ :a => [1, 2, 3] }) }
@orig = Mash.new(data)
@copy = @orig.dup
expect(@copy.to_hash).to eq(Mash.new(data).to_hash)
@copy[:z][:a] << 4
- expect(@orig[:z][:a]).to eq([1,2,3])
+ expect(@orig[:z][:a]).to eq([1, 2, 3])
end
# add more!
diff --git a/spec/unit/mixin/api_version_request_handling_spec.rb b/spec/unit/mixin/api_version_request_handling_spec.rb
index cc5340e424..191dee643b 100644
--- a/spec/unit/mixin/api_version_request_handling_spec.rb
+++ b/spec/unit/mixin/api_version_request_handling_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Cloke (tyler@chef.io)
-# Copyright:: Copyright 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,17 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Mixin::ApiVersionRequestHandling do
let(:dummy_class) { Class.new { include Chef::Mixin::ApiVersionRequestHandling } }
let(:object) { dummy_class.new }
describe ".server_client_api_version_intersection" do
- let(:default_supported_client_versions) { [0,1,2] }
-
+ let(:default_supported_client_versions) { [0, 1, 2] }
context "when the response code is not 406" do
- let(:response) { OpenStruct.new(:code => '405') }
+ let(:response) { OpenStruct.new(:code => "405") }
let(:exception) { Net::HTTPServerException.new("405 Something Else", response) }
it "returns nil" do
@@ -38,7 +37,7 @@ describe Chef::Mixin::ApiVersionRequestHandling do
end # when the response code is not 406
context "when the response code is 406" do
- let(:response) { OpenStruct.new(:code => '406') }
+ let(:response) { OpenStruct.new(:code => "406") }
let(:exception) { Net::HTTPServerException.new("406 Not Acceptable", response) }
context "when x-ops-server-api-version header does not exist" do
@@ -51,15 +50,15 @@ describe Chef::Mixin::ApiVersionRequestHandling do
context "when x-ops-server-api-version header exists" do
let(:min_server_version) { 2 }
let(:max_server_version) { 4 }
- let(:return_hash) {
+ let(:return_hash) do
{
"min_version" => min_server_version,
- "max_version" => max_server_version
+ "max_version" => max_server_version,
}
- }
+ end
before(:each) do
- allow(response).to receive(:[]).with('x-ops-server-api-version').and_return(Chef::JSONCompat.to_json(return_hash))
+ allow(response).to receive(:[]).with("x-ops-server-api-version").and_return(Chef::JSONCompat.to_json(return_hash))
end
context "when there is no intersection between client and server versions" do
@@ -78,13 +77,13 @@ describe Chef::Mixin::ApiVersionRequestHandling do
context "when all the versions are higher than the max" do
it_should_behave_like "no intersection between client and server versions" do
- let(:supported_client_versions) { [5,6,7] }
+ let(:supported_client_versions) { [5, 6, 7] }
end
end
context "when all the versions are lower than the min" do
it_should_behave_like "no intersection between client and server versions" do
- let(:supported_client_versions) { [0,1] }
+ let(:supported_client_versions) { [0, 1] }
end
end
@@ -92,16 +91,16 @@ describe Chef::Mixin::ApiVersionRequestHandling do
context "when there is an intersection between client and server versions" do
context "when multiple versions intersect" do
- let(:supported_client_versions) { [1,2,3,4,5] }
+ let(:supported_client_versions) { [1, 2, 3, 4, 5] }
it "includes all of the intersection" do
expect(object.server_client_api_version_intersection(exception, supported_client_versions)).
- to eq([2,3,4])
+ to eq([2, 3, 4])
end
end # when multiple versions intersect
context "when only the min client version intersects" do
- let(:supported_client_versions) { [0,1,2] }
+ let(:supported_client_versions) { [0, 1, 2] }
it "includes the intersection" do
expect(object.server_client_api_version_intersection(exception, supported_client_versions)).
@@ -110,7 +109,7 @@ describe Chef::Mixin::ApiVersionRequestHandling do
end # when only the min client version intersects
context "when only the max client version intersects" do
- let(:supported_client_versions) { [4,5,6] }
+ let(:supported_client_versions) { [4, 5, 6] }
it "includes the intersection" do
expect(object.server_client_api_version_intersection(exception, supported_client_versions)).
diff --git a/spec/unit/mixin/checksum_spec.rb b/spec/unit/mixin/checksum_spec.rb
index 864b15f2bc..801c8820d2 100644
--- a/spec/unit/mixin/checksum_spec.rb
+++ b/spec/unit/mixin/checksum_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/checksum'
-require 'stringio'
+require "spec_helper"
+require "chef/mixin/checksum"
+require "stringio"
class Chef::CMCCheck
include Chef::Mixin::Checksum
@@ -37,5 +37,18 @@ describe Chef::Mixin::Checksum do
expect(@checksum_user.checksum(@file)).to eq("09ee9c8cc70501763563bcf9c218d71b2fbf4186bf8e1e0da07f0f42c80a3394")
end
-end
+ describe "short_cksum" do
+ context "nil provided for checksum" do
+ it "returns none" do
+ expect(@checksum_user.short_cksum(nil)).to eq("none")
+ end
+ end
+
+ context "non-nil provided for checksum" do
+ it "returns the short checksum" do
+ expect(@checksum_user.short_cksum("u7ghbxikk3i9blsimmy2y2ionmxx")).to eq("u7ghbx")
+ end
+ end
+ end
+end
diff --git a/spec/unit/mixin/command_spec.rb b/spec/unit/mixin/command_spec.rb
index 050b261256..e9f0dacad6 100644
--- a/spec/unit/mixin/command_spec.rb
+++ b/spec/unit/mixin/command_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Hongli Lai (hongli@phusion.nl)
-# Copyright:: Copyright (c) 2009 Phusion
+# Copyright:: Copyright 2009-2016, Phusion
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Mixin::Command, :volatile do
@@ -43,28 +43,30 @@ describe Chef::Mixin::Command, :volatile do
end
it "should respect locale when specified explicitly" do
- popen4("echo $LC_ALL", :environment => {"LC_ALL" => "es"}) do |pid, stdin, stdout, stderr|
+ popen4("echo $LC_ALL", :environment => { "LC_ALL" => "es" }) do |pid, stdin, stdout, stderr|
expect(stdout.read.strip).to eq("es")
end
end
it "should end when the child process reads from STDIN and a block is given" do
- expect {Timeout.timeout(10) do
+ expect do
+ Timeout.timeout(10) do
popen4("ruby -e 'while gets; end'", :waitlast => true) do |pid, stdin, stdout, stderr|
(1..5).each { |i| stdin.puts "#{i}" }
end
end
- }.not_to raise_error
+ end.not_to raise_error
end
describe "when a process detaches but doesn't close STDOUT and STDERR [CHEF-584]" do
it "returns immediately after the first child process exits" do
- expect {Timeout.timeout(10) do
- evil_forker="exit if fork; 10.times { sleep 1}"
- popen4("ruby -e '#{evil_forker}'") do |pid,stdin,stdout,stderr|
- end
- end}.not_to raise_error
+ expect do
+ Timeout.timeout(10) do
+ evil_forker = "exit if fork; 10.times { sleep 1}"
+ popen4("ruby -e '#{evil_forker}'") do |pid, stdin, stdout, stderr|
+ end
+ end end.not_to raise_error
end
end
@@ -92,10 +94,11 @@ describe Chef::Mixin::Command, :volatile do
# btm
# Serdar - During Solaris tests, we've seen that processes
# are taking a long time to exit. Bumping timeout now to 10.
- expect {Timeout.timeout(10) do
- evil_forker="exit if fork; 10.times { sleep 1}"
- run_command(:command => "ruby -e '#{evil_forker}'")
- end}.not_to raise_error
+ expect do
+ Timeout.timeout(10) do
+ evil_forker = "exit if fork; 10.times { sleep 1}"
+ run_command(:command => "ruby -e '#{evil_forker}'")
+ end end.not_to raise_error
end
end
diff --git a/spec/unit/mixin/convert_to_class_name_spec.rb b/spec/unit/mixin/convert_to_class_name_spec.rb
index 4cf6728d64..27c9ac651a 100644
--- a/spec/unit/mixin/convert_to_class_name_spec.rb
+++ b/spec/unit/mixin/convert_to_class_name_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
class ConvertToClassTestHarness
include Chef::Mixin::ConvertToClassName
diff --git a/spec/unit/mixin/deep_merge_spec.rb b/spec/unit/mixin/deep_merge_spec.rb
index d107323f32..2122008616 100644
--- a/spec/unit/mixin/deep_merge_spec.rb
+++ b/spec/unit/mixin/deep_merge_spec.rb
@@ -1,8 +1,8 @@
#
# Author:: Matthew Kent (<mkent@magoazul.com>)
# Author:: Steve Midgley (http://www.misuse.org/science)
-# Copyright:: Copyright (c) 2010 Matthew Kent
-# Copyright:: Copyright (c) 2008 Steve Midgley
+# Copyright:: Copyright 2010-2016, Matthew Kent
+# Copyright:: Copyright 2008-2016, Steve Midgley
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,26 +22,26 @@
# available under the MIT license from
# http://trac.misuse.org/science/wiki/DeepMerge
-require 'spec_helper'
+require "spec_helper"
# Test coverage from the original author converted to rspec
describe Chef::Mixin::DeepMerge, "deep_merge!" do
before do
@dm = Chef::Mixin::DeepMerge
- @field_ko_prefix = '!merge'
+ @field_ko_prefix = "!merge"
end
# deep_merge core tests - moving from basic to more complex
it "tests merging an hash w/array into blank hash" do
- hash_src = {'id' => '2'}
+ hash_src = { "id" => "2" }
hash_dst = {}
@dm.deep_merge!(hash_src.dup, hash_dst)
expect(hash_dst).to eq(hash_src)
end
it "tests merging an hash w/array into blank hash" do
- hash_src = {'region' => {'id' => ['227', '2']}}
+ hash_src = { "region" => { "id" => %w{227 2} } }
hash_dst = {}
@dm.deep_merge!(hash_src, hash_dst)
expect(hash_dst).to eq(hash_src)
@@ -49,192 +49,192 @@ describe Chef::Mixin::DeepMerge, "deep_merge!" do
it "tests merge from empty hash" do
hash_src = {}
- hash_dst = {"property" => ["2","4"]}
+ hash_dst = { "property" => %w{2 4} }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => ["2","4"]})
+ expect(hash_dst).to eq({ "property" => %w{2 4} })
end
it "tests merge to empty hash" do
- hash_src = {"property" => ["2","4"]}
+ hash_src = { "property" => %w{2 4} }
hash_dst = {}
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => ["2","4"]})
+ expect(hash_dst).to eq({ "property" => %w{2 4} })
end
it "tests simple string overwrite" do
- hash_src = {"name" => "value"}
- hash_dst = {"name" => "value1"}
+ hash_src = { "name" => "value" }
+ hash_dst = { "name" => "value1" }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"name" => "value"})
+ expect(hash_dst).to eq({ "name" => "value" })
end
it "tests simple string overwrite of empty hash" do
- hash_src = {"name" => "value"}
+ hash_src = { "name" => "value" }
hash_dst = {}
@dm.deep_merge!(hash_src, hash_dst)
expect(hash_dst).to eq(hash_src)
end
it "tests hashes holding array" do
- hash_src = {"property" => ["1","3"]}
- hash_dst = {"property" => ["2","4"]}
+ hash_src = { "property" => %w{1 3} }
+ hash_dst = { "property" => %w{2 4} }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => ["2","4","1","3"]})
+ expect(hash_dst).to eq({ "property" => %w{2 4 1 3} })
end
it "tests hashes holding hashes holding arrays (array with duplicate elements is merged with dest then src" do
- hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
- hash_dst = {"property" => {"bedroom_count" => ["3", "2"], "bathroom_count" => ["2"]}}
+ hash_src = { "property" => { "bedroom_count" => %w{1 2}, "bathroom_count" => ["1", "4+"] } }
+ hash_dst = { "property" => { "bedroom_count" => %w{3 2}, "bathroom_count" => ["2"] } }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => {"bedroom_count" => ["3","2","1"], "bathroom_count" => ["2", "1", "4+"]}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => %w{3 2 1}, "bathroom_count" => ["2", "1", "4+"] } })
end
it "tests hash holding hash holding array v string (string is overwritten by array)" do
- hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
- hash_dst = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["2"]}}
+ hash_src = { "property" => { "bedroom_count" => %w{1 2}, "bathroom_count" => ["1", "4+"] } }
+ hash_dst = { "property" => { "bedroom_count" => "3", "bathroom_count" => ["2"] } }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2","1","4+"]}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => %w{1 2}, "bathroom_count" => ["2", "1", "4+"] } })
end
it "tests hash holding hash holding string v array (array is overwritten by string)" do
- hash_src = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["1", "4+"]}}
- hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
+ hash_src = { "property" => { "bedroom_count" => "3", "bathroom_count" => ["1", "4+"] } }
+ hash_dst = { "property" => { "bedroom_count" => %w{1 2}, "bathroom_count" => ["2"] } }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => {"bedroom_count" => "3", "bathroom_count" => ["2","1","4+"]}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => "3", "bathroom_count" => ["2", "1", "4+"] } })
end
it "tests hash holding hash holding hash v array (array is overwritten by hash)" do
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}}
- hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
+ hash_src = { "property" => { "bedroom_count" => { "king_bed" => 3, "queen_bed" => 1 }, "bathroom_count" => ["1", "4+"] } }
+ hash_dst = { "property" => { "bedroom_count" => %w{1 2}, "bathroom_count" => ["2"] } }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["2","1","4+"]}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => 3, "queen_bed" => 1 }, "bathroom_count" => ["2", "1", "4+"] } })
end
it "tests 3 hash layers holding integers (integers are overwritten by source)" do
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}}
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => 2, "queen_bed" => 4}, "bathroom_count" => ["2"]}}
+ hash_src = { "property" => { "bedroom_count" => { "king_bed" => 3, "queen_bed" => 1 }, "bathroom_count" => ["1", "4+"] } }
+ hash_dst = { "property" => { "bedroom_count" => { "king_bed" => 2, "queen_bed" => 4 }, "bathroom_count" => ["2"] } }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["2","1","4+"]}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => 3, "queen_bed" => 1 }, "bathroom_count" => ["2", "1", "4+"] } })
end
it "tests 3 hash layers holding arrays of int (arrays are merged)" do
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => ["1", "4+"]}}
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+ hash_src = { "property" => { "bedroom_count" => { "king_bed" => [3], "queen_bed" => [1] }, "bathroom_count" => ["1", "4+"] } }
+ hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => ["2","1","4+"]}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => [2, 3], "queen_bed" => [4, 1] }, "bathroom_count" => ["2", "1", "4+"] } })
end
it "tests 1 hash overwriting 3 hash layers holding arrays of int" do
- hash_src = {"property" => "1"}
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+ hash_src = { "property" => "1" }
+ hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => "1"})
+ expect(hash_dst).to eq({ "property" => "1" })
end
it "tests 3 hash layers holding arrays of int (arrays are merged) but second hash's array is overwritten" do
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}}
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+ hash_src = { "property" => { "bedroom_count" => { "king_bed" => [3], "queen_bed" => [1] }, "bathroom_count" => "1" } }
+ hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => "1"}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => [2, 3], "queen_bed" => [4, 1] }, "bathroom_count" => "1" } })
end
it "tests 3 hash layers holding arrays of int, but one holds int. This one overwrites, but the rest merge" do
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [1]}, "bathroom_count" => ["1"]}}
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+ hash_src = { "property" => { "bedroom_count" => { "king_bed" => 3, "queen_bed" => [1] }, "bathroom_count" => ["1"] } }
+ hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [4,1]}, "bathroom_count" => ["2","1"]}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => 3, "queen_bed" => [4, 1] }, "bathroom_count" => %w{2 1} } })
end
it "tests 3 hash layers holding arrays of int, but source is incomplete." do
- hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3]}, "bathroom_count" => ["1"]}}
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+ hash_src = { "property" => { "bedroom_count" => { "king_bed" => [3] }, "bathroom_count" => ["1"] } }
+ hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => [2, 3], "queen_bed" => [4] }, "bathroom_count" => %w{2 1} } })
end
it "tests 3 hash layers holding arrays of int, but source is shorter and has new 2nd level ints." do
- hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+ hash_src = { "property" => { "bedroom_count" => { 2 => 3, "king_bed" => [3] }, "bathroom_count" => ["1"] } }
+ hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => {"bedroom_count" => {2=>3, "king_bed" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => { 2 => 3, "king_bed" => [2, 3], "queen_bed" => [4] }, "bathroom_count" => %w{2 1} } })
end
it "tests 3 hash layers holding arrays of int, but source is empty" do
hash_src = {}
- hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+ hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } })
end
it "tests 3 hash layers holding arrays of int, but dest is empty" do
- hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
+ hash_src = { "property" => { "bedroom_count" => { 2 => 3, "king_bed" => [3] }, "bathroom_count" => ["1"] } }
hash_dst = {}
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => { 2 => 3, "king_bed" => [3] }, "bathroom_count" => ["1"] } })
end
it "tests hash holding arrays of arrays" do
- hash_src = {["1", "2", "3"] => ["1", "2"]}
- hash_dst = {["4", "5"] => ["3"]}
+ hash_src = { %w{1 2 3} => %w{1 2} }
+ hash_dst = { %w{4 5} => ["3"] }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({["1","2","3"] => ["1", "2"], ["4", "5"] => ["3"]})
+ expect(hash_dst).to eq({ %w{1 2 3} => %w{1 2}, %w{4 5} => ["3"] })
end
it "tests merging of hash with blank hash, and make sure that source array split does not function when turned off" do
- hash_src = {'property' => {'bedroom_count' => ["1","2,3"]}}
+ hash_src = { "property" => { "bedroom_count" => ["1", "2,3"] } }
hash_dst = {}
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({'property' => {'bedroom_count' => ["1","2,3"]}})
+ expect(hash_dst).to eq({ "property" => { "bedroom_count" => ["1", "2,3"] } })
end
it "tests merging into a blank hash" do
- hash_src = {"action"=>"browse", "controller"=>"results"}
+ hash_src = { "action" => "browse", "controller" => "results" }
hash_dst = {}
@dm.deep_merge!(hash_src, hash_dst)
expect(hash_dst).to eq(hash_src)
end
it "tests are unmerged hashes passed unmodified w/out :unpack_arrays?" do
- hash_src = {"amenity"=>{"id"=>["26,27"]}}
+ hash_src = { "amenity" => { "id" => ["26,27"] } }
hash_dst = {}
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"amenity"=>{"id"=>["26,27"]}})
+ expect(hash_dst).to eq({ "amenity" => { "id" => ["26,27"] } })
end
it "tests hash of array of hashes" do
- hash_src = {"item" => [{"1" => "3"}, {"2" => "4"}]}
- hash_dst = {"item" => [{"3" => "5"}]}
+ hash_src = { "item" => [{ "1" => "3" }, { "2" => "4" }] }
+ hash_dst = { "item" => [{ "3" => "5" }] }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"item" => [{"3" => "5"}, {"1" => "3"}, {"2" => "4"}]})
+ expect(hash_dst).to eq({ "item" => [{ "3" => "5" }, { "1" => "3" }, { "2" => "4" }] })
end
# Additions since import
it "should overwrite true with false when merging boolean values" do
- hash_src = {"valid" => false}
- hash_dst = {"valid" => true}
+ hash_src = { "valid" => false }
+ hash_dst = { "valid" => true }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"valid" => false})
+ expect(hash_dst).to eq({ "valid" => false })
end
it "should overwrite false with true when merging boolean values" do
- hash_src = {"valid" => true}
- hash_dst = {"valid" => false}
+ hash_src = { "valid" => true }
+ hash_dst = { "valid" => false }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"valid" => true})
+ expect(hash_dst).to eq({ "valid" => true })
end
it "should overwrite a string with an empty string when merging string values" do
- hash_src = {"item" => " "}
- hash_dst = {"item" => "orange"}
+ hash_src = { "item" => " " }
+ hash_dst = { "item" => "orange" }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"item" => " "})
+ expect(hash_dst).to eq({ "item" => " " })
end
it "should overwrite an empty string with a string when merging string values" do
- hash_src = {"item" => "orange"}
- hash_dst = {"item" => " "}
+ hash_src = { "item" => "orange" }
+ hash_dst = { "item" => " " }
@dm.deep_merge!(hash_src, hash_dst)
- expect(hash_dst).to eq({"item" => "orange"})
+ expect(hash_dst).to eq({ "item" => "orange" })
end
end # deep_merge!
@@ -247,41 +247,41 @@ describe Chef::Mixin::DeepMerge do
describe "merge" do
it "should merge a hash into an empty hash" do
hash_dst = {}
- hash_src = {'id' => '2'}
+ hash_src = { "id" => "2" }
expect(@dm.merge(hash_dst, hash_src)).to eq(hash_src)
end
it "should merge a nested hash into an empty hash" do
hash_dst = {}
- hash_src = {'region' => {'id' => ['227', '2']}}
+ hash_src = { "region" => { "id" => %w{227 2} } }
expect(@dm.merge(hash_dst, hash_src)).to eq(hash_src)
end
it "should overwrite as string value when merging hashes" do
- hash_dst = {"name" => "value1"}
- hash_src = {"name" => "value"}
- expect(@dm.merge(hash_dst, hash_src)).to eq({"name" => "value"})
+ hash_dst = { "name" => "value1" }
+ hash_src = { "name" => "value" }
+ expect(@dm.merge(hash_dst, hash_src)).to eq({ "name" => "value" })
end
it "should merge arrays within hashes" do
- hash_dst = {"property" => ["2","4"]}
- hash_src = {"property" => ["1","3"]}
- expect(@dm.merge(hash_dst, hash_src)).to eq({"property" => ["2","4","1","3"]})
+ hash_dst = { "property" => %w{2 4} }
+ hash_src = { "property" => %w{1 3} }
+ expect(@dm.merge(hash_dst, hash_src)).to eq({ "property" => %w{2 4 1 3} })
end
it "should merge deeply nested hashes" do
- hash_dst = {"property" => {"values" => {"are" => "falling", "can" => "change"}}}
- hash_src = {"property" => {"values" => {"are" => "stable", "may" => "rise"}}}
- expect(@dm.merge(hash_dst, hash_src)).to eq({"property" => {"values" => {"are" => "stable", "can" => "change", "may" => "rise"}}})
+ hash_dst = { "property" => { "values" => { "are" => "falling", "can" => "change" } } }
+ hash_src = { "property" => { "values" => { "are" => "stable", "may" => "rise" } } }
+ expect(@dm.merge(hash_dst, hash_src)).to eq({ "property" => { "values" => { "are" => "stable", "can" => "change", "may" => "rise" } } })
end
it "should not modify the source or destination during the merge" do
- hash_dst = {"property" => ["1","2","3"]}
- hash_src = {"property" => ["4","5","6"]}
+ hash_dst = { "property" => %w{1 2 3} }
+ hash_src = { "property" => %w{4 5 6} }
ret = @dm.merge(hash_dst, hash_src)
- expect(hash_dst).to eq({"property" => ["1","2","3"]})
- expect(hash_src).to eq({"property" => ["4","5","6"]})
- expect(ret).to eq({"property" => ["1","2","3","4","5","6"]})
+ expect(hash_dst).to eq({ "property" => %w{1 2 3} })
+ expect(hash_src).to eq({ "property" => %w{4 5 6} })
+ expect(ret).to eq({ "property" => %w{1 2 3 4 5 6} })
end
it "should not error merging un-dupable objects" do
@@ -292,8 +292,8 @@ describe Chef::Mixin::DeepMerge do
describe "hash-only merging" do
it "merges Hashes like normal deep merge" do
- merge_ee_hash = {"top_level_a" => {"1_deep_a" => "1-a-merge-ee", "1_deep_b" => "1-deep-b-merge-ee"}, "top_level_b" => "top-level-b-merge-ee"}
- merge_with_hash = {"top_level_a" => {"1_deep_b" => "1-deep-b-merged-onto", "1_deep_c" => "1-deep-c-merged-onto"}, "top_level_b" => "top-level-b-merged-onto" }
+ merge_ee_hash = { "top_level_a" => { "1_deep_a" => "1-a-merge-ee", "1_deep_b" => "1-deep-b-merge-ee" }, "top_level_b" => "top-level-b-merge-ee" }
+ merge_with_hash = { "top_level_a" => { "1_deep_b" => "1-deep-b-merged-onto", "1_deep_c" => "1-deep-c-merged-onto" }, "top_level_b" => "top-level-b-merged-onto" }
merged_result = @dm.hash_only_merge(merge_ee_hash, merge_with_hash)
@@ -304,38 +304,38 @@ describe Chef::Mixin::DeepMerge do
end
it "replaces arrays rather than merging them" do
- merge_ee_hash = {"top_level_a" => {"1_deep_a" => "1-a-merge-ee", "1_deep_b" => %w[A A A]}, "top_level_b" => "top-level-b-merge-ee"}
- merge_with_hash = {"top_level_a" => {"1_deep_b" => %w[B B B], "1_deep_c" => "1-deep-c-merged-onto"}, "top_level_b" => "top-level-b-merged-onto" }
+ merge_ee_hash = { "top_level_a" => { "1_deep_a" => "1-a-merge-ee", "1_deep_b" => %w{A A A} }, "top_level_b" => "top-level-b-merge-ee" }
+ merge_with_hash = { "top_level_a" => { "1_deep_b" => %w{B B B}, "1_deep_c" => "1-deep-c-merged-onto" }, "top_level_b" => "top-level-b-merged-onto" }
merged_result = @dm.hash_only_merge(merge_ee_hash, merge_with_hash)
expect(merged_result["top_level_b"]).to eq("top-level-b-merged-onto")
expect(merged_result["top_level_a"]["1_deep_a"]).to eq("1-a-merge-ee")
- expect(merged_result["top_level_a"]["1_deep_b"]).to eq(%w[B B B])
+ expect(merged_result["top_level_a"]["1_deep_b"]).to eq(%w{B B B})
end
it "replaces non-hash items with hashes when there's a conflict" do
- merge_ee_hash = {"top_level_a" => "top-level-a-mergee", "top_level_b" => "top-level-b-merge-ee"}
- merge_with_hash = {"top_level_a" => {"1_deep_b" => %w[B B B], "1_deep_c" => "1-deep-c-merged-onto"}, "top_level_b" => "top-level-b-merged-onto" }
+ merge_ee_hash = { "top_level_a" => "top-level-a-mergee", "top_level_b" => "top-level-b-merge-ee" }
+ merge_with_hash = { "top_level_a" => { "1_deep_b" => %w{B B B}, "1_deep_c" => "1-deep-c-merged-onto" }, "top_level_b" => "top-level-b-merged-onto" }
merged_result = @dm.hash_only_merge(merge_ee_hash, merge_with_hash)
expect(merged_result["top_level_a"]).to be_a(Hash)
expect(merged_result["top_level_a"]["1_deep_a"]).to be_nil
- expect(merged_result["top_level_a"]["1_deep_b"]).to eq(%w[B B B])
+ expect(merged_result["top_level_a"]["1_deep_b"]).to eq(%w{B B B})
end
it "does not mutate deeply-nested original hashes by default" do
- merge_ee_hash = {"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_a" => "foo" }}}}
- merge_with_hash = {"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_b" => "bar" }}}}
+ merge_ee_hash = { "top_level_a" => { "1_deep_a" => { "2_deep_a" => { "3_deep_a" => "foo" } } } }
+ merge_with_hash = { "top_level_a" => { "1_deep_a" => { "2_deep_a" => { "3_deep_b" => "bar" } } } }
@dm.hash_only_merge(merge_ee_hash, merge_with_hash)
- expect(merge_ee_hash).to eq({"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_a" => "foo" }}}})
- expect(merge_with_hash).to eq({"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_b" => "bar" }}}})
+ expect(merge_ee_hash).to eq({ "top_level_a" => { "1_deep_a" => { "2_deep_a" => { "3_deep_a" => "foo" } } } })
+ expect(merge_with_hash).to eq({ "top_level_a" => { "1_deep_a" => { "2_deep_a" => { "3_deep_b" => "bar" } } } })
end
it "does not error merging un-dupable items" do
- merge_ee_hash = {"top_level_a" => 1, "top_level_b" => false}
- merge_with_hash = {"top_level_a" => 2, "top_level_b" => true }
+ merge_ee_hash = { "top_level_a" => 1, "top_level_b" => false }
+ merge_with_hash = { "top_level_a" => 2, "top_level_b" => true }
@dm.hash_only_merge(merge_ee_hash, merge_with_hash)
end
end
diff --git a/spec/unit/mixin/deprecation_spec.rb b/spec/unit/mixin/deprecation_spec.rb
index 6d9f39af9f..8707c6476e 100644
--- a/spec/unit/mixin/deprecation_spec.rb
+++ b/spec/unit/mixin/deprecation_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/deprecation'
+require "spec_helper"
+require "chef/mixin/deprecation"
describe Chef::Mixin do
describe "deprecating constants (Class/Module)" do
@@ -36,7 +36,7 @@ describe Chef::Mixin do
end
it "warns when accessing the deprecated constant" do
- Chef::Mixin::DeprecatedClass
+ Chef::Mixin::DeprecatedClass # rubocop:disable Lint/Void
expect(@log_io.string).to include("This is a test deprecation")
end
end
@@ -46,7 +46,7 @@ describe Chef::Mixin::Deprecation::DeprecatedInstanceVariable do
before do
Chef::Log.logger = Logger.new(StringIO.new)
- @deprecated_ivar = Chef::Mixin::Deprecation::DeprecatedInstanceVariable.new('value', 'an_ivar')
+ @deprecated_ivar = Chef::Mixin::Deprecation::DeprecatedInstanceVariable.new("value", "an_ivar")
end
it "forward method calls to the target object" do
diff --git a/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb b/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb
index 408926293e..248de0ba95 100644
--- a/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb
+++ b/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Mark Mzyk (<mmzyk@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Mark Mzyk (<mmzyk@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'etc'
-require 'ostruct'
+require "spec_helper"
+require "etc"
+require "ostruct"
describe Chef::Mixin::EnforceOwnershipAndPermissions do
@@ -52,8 +52,8 @@ describe Chef::Mixin::EnforceOwnershipAndPermissions do
allow_any_instance_of(Chef::FileAccessControl).to receive(:describe_changes)
passwd_struct = OpenStruct.new(:name => "root", :passwd => "x",
- :uid => 0, :gid => 0, :dir => '/root',
- :shell => '/bin/bash')
+ :uid => 0, :gid => 0, :dir => "/root",
+ :shell => "/bin/bash")
group_struct = OpenStruct.new(:name => "root", :passwd => "x", :gid => 0)
allow(Etc).to receive(:getpwuid).and_return(passwd_struct)
@@ -76,8 +76,8 @@ describe Chef::Mixin::EnforceOwnershipAndPermissions do
allow_any_instance_of(Chef::FileAccessControl).to receive(:describe_changes)
passwd_struct = OpenStruct.new(:name => "root", :passwd => "x",
- :uid => 0, :gid => 0, :dir => '/root',
- :shell => '/bin/bash')
+ :uid => 0, :gid => 0, :dir => "/root",
+ :shell => "/bin/bash")
group_struct = OpenStruct.new(:name => "root", :passwd => "x", :gid => 0)
allow(Etc).to receive(:getpwuid).and_return(passwd_struct)
diff --git a/spec/unit/mixin/homebrew_user_spec.rb b/spec/unit/mixin/homebrew_user_spec.rb
index 57b89720dc..c9a6e6e909 100644
--- a/spec/unit/mixin/homebrew_user_spec.rb
+++ b/spec/unit/mixin/homebrew_user_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Joshua Timberman (<joshua@getchef.com>)
+# Author:: Joshua Timberman (<joshua@chef.io>)
#
-# Copyright 2014, Chef Software, Inc <legal@getchef.com>
+# Copyright 2014-2016, Chef Software, Inc <legal@chef.io>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,8 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
-require 'chef/mixin/homebrew_user'
+require "spec_helper"
+require "chef/mixin/homebrew_user"
class ExampleHomebrewUser
include Chef::Mixin::HomebrewUser
@@ -24,22 +24,22 @@ end
describe Chef::Mixin::HomebrewUser do
before(:each) do
- node.default['homebrew']['owner'] = nil
+ node.default["homebrew"]["owner"] = nil
end
let(:homebrew_user) { ExampleHomebrewUser.new }
let(:node) { Chef::Node.new }
- describe 'when the homebrew user is provided' do
+ describe "when the homebrew user is provided" do
let(:uid) { 1001 }
let(:user) { "foo" }
- it 'returns the homebrew user without looking at the file when uid is provided' do
+ it "returns the homebrew user without looking at the file when uid is provided" do
expect(File).to receive(:exist?).exactly(0).times
expect(homebrew_user.find_homebrew_uid(uid)).to eq(uid)
end
- it 'returns the homebrew user without looking at the file when name is provided' do
+ it "returns the homebrew user without looking at the file when name is provided" do
expect(File).to receive(:exist?).exactly(0).times
allow(Etc).to receive_message_chain(:getpwnam, :uid).and_return(uid)
expect(homebrew_user.find_homebrew_uid(user)).to eq(uid)
@@ -50,12 +50,12 @@ describe Chef::Mixin::HomebrewUser do
shared_examples "successfully find executable" do
let(:user) { nil }
let(:brew_owner) { 2001 }
- let(:default_brew_path) { '/usr/local/bin/brew' }
- let(:stat_double) {
+ let(:default_brew_path) { "/usr/local/bin/brew" }
+ let(:stat_double) do
d = double()
expect(d).to receive(:uid).and_return(brew_owner)
d
- }
+ end
context "debug statement prints owner name" do
@@ -63,13 +63,13 @@ describe Chef::Mixin::HomebrewUser do
expect(Etc).to receive(:getpwuid).with(brew_owner).and_return(OpenStruct.new(:name => "name"))
end
- it 'returns the owner of the brew executable when it is at a default location' do
+ it "returns the owner of the brew executable when it is at a default location" do
expect(File).to receive(:exist?).with(default_brew_path).and_return(true)
expect(File).to receive(:stat).with(default_brew_path).and_return(stat_double)
expect(homebrew_user.find_homebrew_uid(user)).to eq(brew_owner)
end
- it 'returns the owner of the brew executable when it is not at a default location' do
+ it "returns the owner of the brew executable when it is not at a default location" do
expect(File).to receive(:exist?).with(default_brew_path).and_return(false)
allow(homebrew_user).to receive_message_chain(:shell_out, :stdout, :strip).and_return("/foo")
expect(File).to receive(:stat).with("/foo").and_return(stat_double)
@@ -79,9 +79,9 @@ describe Chef::Mixin::HomebrewUser do
end
end
- describe 'when the homebrew user is not provided' do
+ describe "when the homebrew user is not provided" do
- it 'raises an error if no executable is found' do
+ it "raises an error if no executable is found" do
expect(File).to receive(:exist?).with(default_brew_path).and_return(false)
allow(homebrew_user).to receive_message_chain(:shell_out, :stdout, :strip).and_return("")
expect { homebrew_user.find_homebrew_uid(user) }.to raise_error(Chef::Exceptions::CannotDetermineHomebrewOwner)
diff --git a/spec/unit/mixin/lazy_module_include.rb b/spec/unit/mixin/lazy_module_include.rb
new file mode 100644
index 0000000000..542ae853ae
--- /dev/null
+++ b/spec/unit/mixin/lazy_module_include.rb
@@ -0,0 +1,71 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+module TestA
+ extend Chef::Mixin::LazyModuleInclude
+end
+
+module TestB
+ include TestA
+ extend Chef::Mixin::LazyModuleInclude
+end
+
+class TestC
+ include TestB
+end
+
+module Monkey
+ def monkey
+ "monkey"
+ end
+end
+
+module Klowns
+ def klowns
+ "klowns"
+ end
+end
+
+TestA.send(:include, Monkey)
+
+TestB.send(:include, Klowns)
+
+describe Chef::Mixin::LazyModuleInclude do
+
+ it "tracks descendant classes of TestA" do
+ expect(TestA.descendants).to include(TestB)
+ expect(TestA.descendants).to include(TestC)
+ end
+
+ it "tracks descendent classes of TestB" do
+ expect(TestB.descendants).to eql([TestC])
+ end
+
+ it "including into A mixins in methods into B and C" do
+ expect(TestA.instance_methods).to include(:monkey)
+ expect(TestB.instance_methods).to include(:monkey)
+ expect(TestC.instance_methods).to include(:monkey)
+ end
+
+ it "including into B only mixins in methods into C" do
+ expect(TestA.instance_methods).not_to include(:klowns)
+ expect(TestB.instance_methods).to include(:klowns)
+ expect(TestC.instance_methods).to include(:klowns)
+ end
+end
diff --git a/spec/unit/mixin/params_validate_spec.rb b/spec/unit/mixin/params_validate_spec.rb
index 3724bbf583..0cafb925c8 100644
--- a/spec/unit/mixin/params_validate_spec.rb
+++ b/spec/unit/mixin/params_validate_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,25 +16,25 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
class TinyClass
include Chef::Mixin::ParamsValidate
attr_reader :name
- def music(is_good=true)
+ def music(is_good = true)
is_good
end
end
describe Chef::Mixin::ParamsValidate do
before(:each) do
- @vo = TinyClass.new()
+ @vo = TinyClass.new()
end
it "should allow a hash and a hash as arguments to validate" do
- expect { @vo.validate({:one => "two"}, {}) }.not_to raise_error
+ expect { @vo.validate({ :one => "two" }, {}) }.not_to raise_error
end
it "should raise an argument error if validate is called incorrectly" do
@@ -42,195 +42,195 @@ describe Chef::Mixin::ParamsValidate do
end
it "should require validation map keys to be symbols or strings" do
- expect { @vo.validate({:one => "two"}, { :one => true }) }.not_to raise_error
- expect { @vo.validate({:one => "two"}, { "one" => true }) }.not_to raise_error
- expect { @vo.validate({:one => "two"}, { Hash.new => true }) }.to raise_error(ArgumentError)
+ expect { @vo.validate({ :one => "two" }, { :one => true }) }.not_to raise_error
+ expect { @vo.validate({ :one => "two" }, { "one" => true }) }.not_to raise_error
+ expect { @vo.validate({ :one => "two" }, { Hash.new => true }) }.to raise_error(ArgumentError)
end
it "should allow options to be required with true" do
- expect { @vo.validate({:one => "two"}, { :one => true }) }.not_to raise_error
+ expect { @vo.validate({ :one => "two" }, { :one => true }) }.not_to raise_error
end
it "should allow options to be optional with false" do
- expect { @vo.validate({}, {:one => false})}.not_to raise_error
+ expect { @vo.validate({}, { :one => false }) }.not_to raise_error
end
it "should allow you to check what kind_of? thing an argument is with kind_of" do
- expect {
+ expect do
@vo.validate(
- {:one => "string"},
+ { :one => "string" },
{
:one => {
- :kind_of => String
- }
+ :kind_of => String,
+ },
}
)
- }.not_to raise_error
+ end.not_to raise_error
- expect {
+ expect do
@vo.validate(
- {:one => "string"},
+ { :one => "string" },
{
:one => {
- :kind_of => Array
- }
+ :kind_of => Array,
+ },
}
)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should allow you to specify an argument is required with required" do
- expect {
+ expect do
@vo.validate(
- {:one => "string"},
+ { :one => "string" },
{
:one => {
- :required => true
- }
+ :required => true,
+ },
}
)
- }.not_to raise_error
+ end.not_to raise_error
- expect {
+ expect do
@vo.validate(
- {:two => "string"},
+ { :two => "string" },
{
:one => {
- :required => true
- }
+ :required => true,
+ },
}
)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
- expect {
+ expect do
@vo.validate(
- {:two => "string"},
+ { :two => "string" },
{
:one => {
- :required => false
- }
+ :required => false,
+ },
}
)
- }.not_to raise_error
+ end.not_to raise_error
end
it "should allow you to specify whether an object has a method with respond_to" do
- expect {
+ expect do
@vo.validate(
- {:one => @vo},
+ { :one => @vo },
{
:one => {
- :respond_to => "validate"
- }
+ :respond_to => "validate",
+ },
}
)
- }.not_to raise_error
+ end.not_to raise_error
- expect {
+ expect do
@vo.validate(
- {:one => @vo},
+ { :one => @vo },
{
:one => {
- :respond_to => "monkey"
- }
+ :respond_to => "monkey",
+ },
}
)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should allow you to specify whether an object has all the given methods with respond_to and an array" do
- expect {
+ expect do
@vo.validate(
- {:one => @vo},
+ { :one => @vo },
{
:one => {
- :respond_to => ["validate", "music"]
- }
+ :respond_to => %w{validate music},
+ },
}
)
- }.not_to raise_error
+ end.not_to raise_error
- expect {
+ expect do
@vo.validate(
- {:one => @vo},
+ { :one => @vo },
{
:one => {
- :respond_to => ["monkey", "validate"]
- }
+ :respond_to => %w{monkey validate},
+ },
}
)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should let you set a default value with default => value" do
arguments = Hash.new
@vo.validate(arguments, {
:one => {
- :default => "is the loneliest number"
- }
+ :default => "is the loneliest number",
+ },
})
expect(arguments[:one]).to eq("is the loneliest number")
end
it "should let you check regular expressions" do
- expect {
+ expect do
@vo.validate(
{ :one => "is good" },
{
:one => {
- :regex => /^is good$/
- }
+ :regex => /^is good$/,
+ },
}
)
- }.not_to raise_error
+ end.not_to raise_error
- expect {
+ expect do
@vo.validate(
{ :one => "is good" },
{
:one => {
- :regex => /^is bad$/
- }
+ :regex => /^is bad$/,
+ },
}
)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should let you specify your own callbacks" do
- expect {
+ expect do
@vo.validate(
{ :one => "is good" },
{
:one => {
:callbacks => {
- "should be equal to is good" => lambda { |a|
+ "should be equal to is good" => lambda do |a|
a == "is good"
- },
- }
- }
+ end,
+ },
+ },
}
)
- }.not_to raise_error
+ end.not_to raise_error
- expect {
+ expect do
@vo.validate(
{ :one => "is bad" },
{
:one => {
:callbacks => {
- "should be equal to 'is good'" => lambda { |a|
+ "should be equal to 'is good'" => lambda do |a|
a == "is good"
- },
- }
- }
+ end,
+ },
+ },
}
)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should let you combine checks" do
args = { :one => "is good", :two => "is bad" }
- expect {
+ expect do
@vo.validate(
args,
{
@@ -239,22 +239,22 @@ describe Chef::Mixin::ParamsValidate do
:respond_to => [ :to_s, :upcase ],
:regex => /^is good/,
:callbacks => {
- "should be your friend" => lambda { |a|
+ "should be your friend" => lambda do |a|
a == "is good"
- }
+ end,
},
- :required => true
+ :required => true,
},
:two => {
:kind_of => String,
- :required => false
+ :required => false,
},
- :three => { :default => "neato mosquito" }
+ :three => { :default => "neato mosquito" },
}
)
- }.not_to raise_error
+ end.not_to raise_error
expect(args[:three]).to eq("neato mosquito")
- expect {
+ expect do
@vo.validate(
args,
{
@@ -263,81 +263,82 @@ describe Chef::Mixin::ParamsValidate do
:respond_to => [ :to_s, :upcase ],
:regex => /^is good/,
:callbacks => {
- "should be your friend" => lambda { |a|
+ "should be your friend" => lambda do |a|
a == "is good"
- }
+ end,
},
- :required => true
+ :required => true,
},
:two => {
:kind_of => Hash,
- :required => false
+ :required => false,
},
- :three => { :default => "neato mosquito" }
+ :three => { :default => "neato mosquito" },
}
)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should raise an ArgumentError if the validation map has an unknown check" do
- expect { @vo.validate(
+ expect do
+ @vo.validate(
{ :one => "two" },
{
:one => {
- :busted => "check"
- }
+ :busted => "check",
+ },
}
)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should accept keys that are strings in the options" do
- expect {
- @vo.validate({ "one" => "two" }, { :one => { :regex => /^two$/ }})
- }.not_to raise_error
+ expect do
+ @vo.validate({ "one" => "two" }, { :one => { :regex => /^two$/ } })
+ end.not_to raise_error
end
it "should allow an array to kind_of" do
- expect {
+ expect do
@vo.validate(
- {:one => "string"},
+ { :one => "string" },
{
:one => {
- :kind_of => [ String, Array ]
- }
+ :kind_of => [ String, Array ],
+ },
}
)
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
@vo.validate(
- {:one => ["string"]},
+ { :one => ["string"] },
{
:one => {
- :kind_of => [ String, Array ]
- }
+ :kind_of => [ String, Array ],
+ },
}
)
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
@vo.validate(
- {:one => Hash.new},
+ { :one => Hash.new },
{
:one => {
- :kind_of => [ String, Array ]
- }
+ :kind_of => [ String, Array ],
+ },
}
)
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "asserts that a value returns false from a predicate method" do
expect do
- @vo.validate({:not_blank => "should pass"},
- {:not_blank => {:cannot_be => [ :nil, :empty ]}})
+ @vo.validate({ :not_blank => "should pass" },
+ { :not_blank => { :cannot_be => [ :nil, :empty ] } })
end.not_to raise_error
expect do
- @vo.validate({:not_blank => ""},
- {:not_blank => {:cannot_be => [ :nil, :empty ]}})
+ @vo.validate({ :not_blank => "" },
+ { :not_blank => { :cannot_be => [ :nil, :empty ] } })
end.to raise_error(Chef::Exceptions::ValidationFailed)
end
@@ -354,53 +355,53 @@ describe Chef::Mixin::ParamsValidate do
end
it "should raise an ArgumentError when argument is nil and required is true" do
- expect {
+ expect do
@vo.set_or_return(:test, nil, { :required => true })
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should not raise an error when argument is nil and required is false" do
- expect {
+ expect do
@vo.set_or_return(:test, nil, { :required => false })
- }.not_to raise_error
+ end.not_to raise_error
end
it "should set and return @name, then return @name for foo when argument is nil" do
value = "meow"
- expect(@vo.set_or_return(:name, value, { }).object_id).to eq(value.object_id)
+ expect(@vo.set_or_return(:name, value, {}).object_id).to eq(value.object_id)
expect(@vo.set_or_return(:foo, nil, { :name_attribute => true }).object_id).to eq(value.object_id)
end
it "should allow DelayedEvaluator instance to be set for value regardless of restriction" do
- value = Chef::DelayedEvaluator.new{ 'test' }
- @vo.set_or_return(:test, value, {:kind_of => Numeric})
+ value = Chef::DelayedEvaluator.new { "test" }
+ @vo.set_or_return(:test, value, { :kind_of => Numeric })
end
it "should raise an error when delayed evaluated attribute is not valid" do
- value = Chef::DelayedEvaluator.new{ 'test' }
- @vo.set_or_return(:test, value, {:kind_of => Numeric})
+ value = Chef::DelayedEvaluator.new { "test" }
+ @vo.set_or_return(:test, value, { :kind_of => Numeric })
expect do
- @vo.set_or_return(:test, nil, {:kind_of => Numeric})
+ @vo.set_or_return(:test, nil, { :kind_of => Numeric })
end.to raise_error(Chef::Exceptions::ValidationFailed)
end
it "should create DelayedEvaluator instance when #lazy is used" do
- @vo.set_or_return(:delayed, @vo.lazy{ 'test' }, {})
+ @vo.set_or_return(:delayed, @vo.lazy { "test" }, {})
expect(@vo.instance_variable_get(:@delayed)).to be_a(Chef::DelayedEvaluator)
end
it "should execute block on each call when DelayedEvaluator" do
- value = 'fubar'
- @vo.set_or_return(:test, @vo.lazy{ value }, {})
- expect(@vo.set_or_return(:test, nil, {})).to eq('fubar')
- value = 'foobar'
- expect(@vo.set_or_return(:test, nil, {})).to eq('foobar')
- value = 'fauxbar'
- expect(@vo.set_or_return(:test, nil, {})).to eq('fauxbar')
+ value = "fubar"
+ @vo.set_or_return(:test, @vo.lazy { value }, {})
+ expect(@vo.set_or_return(:test, nil, {})).to eq("fubar")
+ value = "foobar"
+ expect(@vo.set_or_return(:test, nil, {})).to eq("foobar")
+ value = "fauxbar"
+ expect(@vo.set_or_return(:test, nil, {})).to eq("fauxbar")
end
it "should not evaluate non DelayedEvaluator instances" do
- value = lambda{ 'test' }
+ value = lambda { "test" }
@vo.set_or_return(:test, value, {})
expect(@vo.set_or_return(:test, nil, {}).object_id).to eq(value.object_id)
expect(@vo.set_or_return(:test, nil, {})).to be_a(Proc)
diff --git a/spec/unit/mixin/path_sanity_spec.rb b/spec/unit/mixin/path_sanity_spec.rb
index 3a924b9538..675b5722be 100644
--- a/spec/unit/mixin/path_sanity_spec.rb
+++ b/spec/unit/mixin/path_sanity_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
class PathSanityTestHarness
include Chef::Mixin::PathSanity
@@ -31,43 +31,49 @@ describe Chef::Mixin::PathSanity do
describe "when enforcing path sanity" do
before do
Chef::Config[:enforce_path_sanity] = true
- @ruby_bindir = '/some/ruby/bin'
- @gem_bindir = '/some/gem/bin'
+ @ruby_bindir = "/some/ruby/bin"
+ @gem_bindir = "/some/gem/bin"
allow(Gem).to receive(:bindir).and_return(@gem_bindir)
- allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return(@ruby_bindir)
+ allow(RbConfig::CONFIG).to receive(:[]).with("bindir").and_return(@ruby_bindir)
allow(ChefConfig).to receive(:windows?).and_return(false)
end
it "adds all useful PATHs even if environment is an empty hash" do
- env={}
+ env = {}
@sanity.enforce_path_sanity(env)
expect(env["PATH"]).to eq("#{@ruby_bindir}:#{@gem_bindir}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
end
it "adds all useful PATHs that are not yet in PATH to PATH" do
- env = {"PATH" => ""}
+ env = { "PATH" => "" }
@sanity.enforce_path_sanity(env)
expect(env["PATH"]).to eq("#{@ruby_bindir}:#{@gem_bindir}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
end
it "does not re-add paths that already exist in PATH" do
- env = {"PATH" => "/usr/bin:/sbin:/bin"}
+ env = { "PATH" => "/usr/bin:/sbin:/bin" }
@sanity.enforce_path_sanity(env)
expect(env["PATH"]).to eq("/usr/bin:/sbin:/bin:#{@ruby_bindir}:#{@gem_bindir}:/usr/local/sbin:/usr/local/bin:/usr/sbin")
end
+ it "creates path with utf-8 encoding" do
+ env = { "PATH" => "/usr/bin:/sbin:/bin:/b#{0x81.chr}t".force_encoding("ISO-8859-1") }
+ @sanity.enforce_path_sanity(env)
+ expect(env["PATH"].encoding.to_s).to eq("UTF-8")
+ end
+
it "adds the current executing Ruby's bindir and Gem bindir to the PATH" do
- env = {"PATH" => ""}
+ env = { "PATH" => "" }
@sanity.enforce_path_sanity(env)
expect(env["PATH"]).to eq("#{@ruby_bindir}:#{@gem_bindir}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
end
it "does not create entries for Ruby/Gem bindirs if they exist in SANE_PATH or PATH" do
- ruby_bindir = '/usr/bin'
- gem_bindir = '/yo/gabba/gabba'
+ ruby_bindir = "/usr/bin"
+ gem_bindir = "/yo/gabba/gabba"
allow(Gem).to receive(:bindir).and_return(gem_bindir)
- allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return(ruby_bindir)
- env = {"PATH" => gem_bindir}
+ allow(RbConfig::CONFIG).to receive(:[]).with("bindir").and_return(ruby_bindir)
+ env = { "PATH" => gem_bindir }
@sanity.enforce_path_sanity(env)
expect(env["PATH"]).to eq("/yo/gabba/gabba:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
end
@@ -76,9 +82,9 @@ describe Chef::Mixin::PathSanity do
ruby_bindir = 'C:\ruby\bin'
gem_bindir = 'C:\gems\bin'
allow(Gem).to receive(:bindir).and_return(gem_bindir)
- allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return(ruby_bindir)
+ allow(RbConfig::CONFIG).to receive(:[]).with("bindir").and_return(ruby_bindir)
allow(ChefConfig).to receive(:windows?).and_return(true)
- env = {"PATH" => 'C:\Windows\system32;C:\mr\softie'}
+ env = { "PATH" => 'C:\Windows\system32;C:\mr\softie' }
@sanity.enforce_path_sanity(env)
expect(env["PATH"]).to eq("C:\\Windows\\system32;C:\\mr\\softie;#{ruby_bindir};#{gem_bindir}")
end
diff --git a/spec/unit/mixin/powershell_out_spec.rb b/spec/unit/mixin/powershell_out_spec.rb
index 0fede582fa..4ecdcb8325 100644
--- a/spec/unit/mixin/powershell_out_spec.rb
+++ b/spec/unit/mixin/powershell_out_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,16 +15,16 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/powershell_out'
+require "spec_helper"
+require "chef/mixin/powershell_out"
-describe Chef::Mixin::PowershellOut do
+describe Chef::Mixin::PowershellOut, :windows_only do
let(:shell_out_class) { Class.new { include Chef::Mixin::PowershellOut } }
subject(:object) { shell_out_class.new }
- let(:architecture) { "something" }
- let(:flags) {
- "-NoLogo -NonInteractive -NoProfile -ExecutionPolicy Unrestricted -InputFormat None"
- }
+ let(:architecture) { "something" }
+ let(:flags) do
+ "-NoLogo -NonInteractive -NoProfile -ExecutionPolicy Unrestricted -InputFormat None"
+ end
describe "#powershell_out" do
it "runs a command and returns the shell_out object" do
@@ -44,6 +44,18 @@ describe Chef::Mixin::PowershellOut do
).and_return(ret)
expect(object.powershell_out("Get-Process", timeout: 600)).to eql(ret)
end
+
+ context "when double quote is passed in the powershell command" do
+ it "passes if double quote is appended with single escape" do
+ result = object.powershell_out("Write-Verbose \"Some String\" -Verbose")
+ expect(result.stderr).to be == ""
+ expect(result.stdout).to be == "VERBOSE: Some String\n"
+ end
+
+ it "suppresses error if double quote is passed with double escape characters" do
+ expect { object.powershell_out("Write-Verbose \\\"Some String\\\" -Verbose") }.not_to raise_error
+ end
+ end
end
describe "#powershell_out!" do
@@ -66,5 +78,17 @@ describe Chef::Mixin::PowershellOut do
expect(mixlib_shellout).to receive(:error!)
expect(object.powershell_out!("Get-Process", timeout: 600)).to eql(mixlib_shellout)
end
+
+ context "when double quote is passed in the powershell command" do
+ it "passes if double quote is appended with single escape" do
+ result = object.powershell_out!("Write-Verbose \"Some String\" -Verbose")
+ expect(result.stderr).to be == ""
+ expect(result.stdout).to be == "VERBOSE: Some String\n"
+ end
+
+ it "raises error if double quote is passed with double escape characters" do
+ expect { object.powershell_out!("Write-Verbose \\\"Some String\\\" -Verbose") }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
+ end
+ end
end
end
diff --git a/spec/unit/mixin/powershell_type_coercions_spec.rb b/spec/unit/mixin/powershell_type_coercions_spec.rb
index 988c3926c1..6f52abccfb 100644
--- a/spec/unit/mixin/powershell_type_coercions_spec.rb
+++ b/spec/unit/mixin/powershell_type_coercions_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/powershell_type_coercions'
-require 'base64'
+require "spec_helper"
+require "chef/mixin/powershell_type_coercions"
+require "base64"
class Chef::PSTypeTester
include Chef::Mixin::PowershellTypeCoercions
@@ -27,46 +27,57 @@ end
describe Chef::Mixin::PowershellTypeCoercions do
let (:test_class) { Chef::PSTypeTester.new }
- describe '#translate_type' do
- it 'should single quote a string' do
- expect(test_class.translate_type('foo')).to eq("'foo'")
+ describe "#translate_type" do
+ it "single quotes a string" do
+ expect(test_class.translate_type("foo")).to eq("'foo'")
end
- ["'", '"', '#', '`'].each do |c|
- it "should base64 encode a string that contains #{c}" do
+ ["'", '"', "#", "`"].each do |c|
+ it "base64 encodes a string that contains #{c}" do
expect(test_class.translate_type("#{c}")).to match(Base64.strict_encode64(c))
end
end
- it 'should not quote an integer' do
- expect(test_class.translate_type(123)).to eq('123')
+ it "does not quote an integer" do
+ expect(test_class.translate_type(123)).to eq("123")
end
- it 'should not quote a floating point number' do
- expect(test_class.translate_type(123.4)).to eq('123.4')
+ it "does not quote a floating point number" do
+ expect(test_class.translate_type(123.4)).to eq("123.4")
end
- it 'should return $false when an instance of FalseClass is provided' do
- expect(test_class.translate_type(false)).to eq('$false')
+ it "translates $false when an instance of FalseClass is provided" do
+ expect(test_class.translate_type(false)).to eq("$false")
end
- it 'should return $true when an instance of TrueClass is provided' do
- expect(test_class.translate_type(true)).to eq('$true')
+ it "translates $true when an instance of TrueClass is provided" do
+ expect(test_class.translate_type(true)).to eq("$true")
end
- it 'should translate all members of a hash and wrap them in @{} separated by ;' do
- expect(test_class.translate_type({"a" => 1, "b" => 1.2, "c" => false, "d" => true
+ it "translates all members of a hash and wrap them in @{} separated by ;" do
+ expect(test_class.translate_type({ "a" => 1, "b" => 1.2, "c" => false, "d" => true
})).to eq("@{a=1;b=1.2;c=$false;d=$true}")
end
- it 'should translat all members of an array and them by a ,' do
- expect(test_class.translate_type([true, false])).to eq('@($true,$false)')
+ it "translates all members of an array and them by a ," do
+ expect(test_class.translate_type([true, false])).to eq("@($true,$false)")
end
- it 'should fall back :to_psobject if we have not defined at explicit rule' do
+ it "translates a Chef::Node::ImmutableMash like a hash" do
+ test_mash = Chef::Node::ImmutableMash.new({ "a" => 1, "b" => 1.2,
+ "c" => false, "d" => true })
+ expect(test_class.translate_type(test_mash)).to eq("@{a=1;b=1.2;c=$false;d=$true}")
+ end
+
+ it "translates a Chef::Node::ImmutableArray like an array" do
+ test_array = Chef::Node::ImmutableArray.new([true, false])
+ expect(test_class.translate_type(test_array)).to eq("@($true,$false)")
+ end
+
+ it "falls back :to_psobject if we have not defined at explicit rule" do
ps_obj = double("PSObject")
- expect(ps_obj).to receive(:to_psobject).and_return('$true')
- expect(test_class.translate_type(ps_obj)).to eq('($true)')
+ expect(ps_obj).to receive(:to_psobject).and_return("$true")
+ expect(test_class.translate_type(ps_obj)).to eq("($true)")
end
end
end
diff --git a/spec/unit/mixin/properties_spec.rb b/spec/unit/mixin/properties_spec.rb
index 18178619e4..1af0bc7abd 100644
--- a/spec/unit/mixin/properties_spec.rb
+++ b/spec/unit/mixin/properties_spec.rb
@@ -1,5 +1,5 @@
-require 'support/shared/integration/integration_helper'
-require 'chef/mixin/properties'
+require "support/shared/integration/integration_helper"
+require "chef/mixin/properties"
module ChefMixinPropertiesSpec
describe "Chef::Resource.property" do
@@ -8,46 +8,46 @@ module ChefMixinPropertiesSpec
context "with a base class A with properties a, ab, and ac" do
class A
include Chef::Mixin::Properties
- property :a, 'a', default: 'a'
- property :ab, ['a', 'b'], default: 'a'
- property :ac, ['a', 'c'], default: 'a'
+ property :a, "a", default: "a"
+ property :ab, %w{a b}, default: "a"
+ property :ac, %w{a c}, default: "a"
end
context "and a module B with properties b, ab and bc" do
module B
include Chef::Mixin::Properties
- property :b, 'b', default: 'b'
- property :ab, default: 'b'
- property :bc, ['b', 'c'], default: 'c'
+ property :b, "b", default: "b"
+ property :ab, default: "b"
+ property :bc, %w{b c}, default: "c"
end
context "and a derived class C < A with properties c, ac and bc" do
class C < A
include B
- property :c, 'c', default: 'c'
- property :ac, default: 'c'
- property :bc, default: 'c'
+ property :c, "c", default: "c"
+ property :ac, default: "c"
+ property :bc, default: "c"
end
it "A.properties has a, ab, and ac with types 'a', ['a', 'b'], and ['b', 'c']" do
expect(A.properties.keys).to eq [ :a, :ab, :ac ]
- expect(A.properties[:a].validation_options[:is]).to eq 'a'
- expect(A.properties[:ab].validation_options[:is]).to eq [ 'a', 'b' ]
- expect(A.properties[:ac].validation_options[:is]).to eq [ 'a', 'c' ]
+ expect(A.properties[:a].validation_options[:is]).to eq "a"
+ expect(A.properties[:ab].validation_options[:is]).to eq %w{a b}
+ expect(A.properties[:ac].validation_options[:is]).to eq %w{a c}
end
it "B.properties has b, ab, and bc with types 'b', nil and ['b', 'c']" do
expect(B.properties.keys).to eq [ :b, :ab, :bc ]
- expect(B.properties[:b].validation_options[:is]).to eq 'b'
+ expect(B.properties[:b].validation_options[:is]).to eq "b"
expect(B.properties[:ab].validation_options[:is]).to be_nil
- expect(B.properties[:bc].validation_options[:is]).to eq [ 'b', 'c' ]
+ expect(B.properties[:bc].validation_options[:is]).to eq %w{b c}
end
it "C.properties has a, b, c, ac and bc with merged types" do
expect(C.properties.keys).to eq [ :a, :ab, :ac, :b, :bc, :c ]
- expect(C.properties[:a].validation_options[:is]).to eq 'a'
- expect(C.properties[:b].validation_options[:is]).to eq 'b'
- expect(C.properties[:c].validation_options[:is]).to eq 'c'
- expect(C.properties[:ac].validation_options[:is]).to eq [ 'a', 'c' ]
- expect(C.properties[:bc].validation_options[:is]).to eq [ 'b', 'c' ]
+ expect(C.properties[:a].validation_options[:is]).to eq "a"
+ expect(C.properties[:b].validation_options[:is]).to eq "b"
+ expect(C.properties[:c].validation_options[:is]).to eq "c"
+ expect(C.properties[:ac].validation_options[:is]).to eq %w{a c}
+ expect(C.properties[:bc].validation_options[:is]).to eq %w{b c}
end
it "C.properties has ab with a non-merged type (from B)" do
expect(C.properties[:ab].validation_options[:is]).to be_nil
@@ -57,12 +57,12 @@ module ChefMixinPropertiesSpec
let(:c) { C.new }
it "all properties can be retrieved and merged properties default to ab->b, ac->c, bc->c" do
- expect(c.a).to eq('a')
- expect(c.b).to eq('b')
- expect(c.c).to eq('c')
- expect(c.ab).to eq('b')
- expect(c.ac).to eq('c')
- expect(c.bc).to eq('c')
+ expect(c.a).to eq("a")
+ expect(c.b).to eq("b")
+ expect(c.c).to eq("c")
+ expect(c.ab).to eq("b")
+ expect(c.ac).to eq("c")
+ expect(c.bc).to eq("c")
end
end
end
diff --git a/spec/unit/mixin/proxified_socket_spec.rb b/spec/unit/mixin/proxified_socket_spec.rb
new file mode 100644
index 0000000000..d3ba54f618
--- /dev/null
+++ b/spec/unit/mixin/proxified_socket_spec.rb
@@ -0,0 +1,97 @@
+#
+# Author:: Tyler Ball (<tball@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/mixin/proxified_socket"
+require "proxifier/proxy"
+
+class TestProxifiedSocket
+ include Chef::Mixin::ProxifiedSocket
+end
+
+describe Chef::Mixin::ProxifiedSocket do
+
+ before(:all) do
+ @original_env = ENV.to_hash
+ end
+
+ after(:all) do
+ ENV.clear
+ ENV.update(@original_env)
+ end
+
+ let(:host) { "host" }
+ let(:port) { 7979 }
+ let(:test_instance) { TestProxifiedSocket.new }
+ let(:socket_double) { instance_double(TCPSocket) }
+ let(:proxifier_double) { instance_double(Proxifier::Proxy) }
+ let(:http_uri) { "http://somehost:1" }
+ let(:https_uri) { "https://somehost:1" }
+ let(:no_proxy_spec) { nil }
+
+ shared_examples "proxified socket" do
+ it "wraps the Socket in a Proxifier::Proxy" do
+ expect(Proxifier).to receive(:Proxy).with(proxy_uri).and_return(proxifier_double)
+ expect(proxifier_double).to receive(:open).with(host, port).and_return(socket_double)
+ expect(test_instance.proxified_socket(host, port)).to eq(socket_double)
+ end
+ end
+
+ context "when no proxy is set" do
+ it "returns a plain TCPSocket" do
+ ENV["http_proxy"] = nil
+ ENV["https_proxy"] = nil
+ expect(TCPSocket).to receive(:new).with(host, port).and_return(socket_double)
+ expect(test_instance.proxified_socket(host, port)).to eq(socket_double)
+ end
+ end
+
+ context "when https_proxy is set" do
+ before do
+ # I'm purposefully setting both of these because we prefer the https
+ # variable
+ ENV["https_proxy"] = https_uri
+ ENV["http_proxy"] = http_uri
+ end
+
+ let(:proxy_uri) { https_uri }
+ include_examples "proxified socket"
+
+ context "when no_proxy is set" do
+ # This is testing that no_proxy is also provided to Proxified
+ # when it is set
+ before do
+ ENV["no_proxy"] = no_proxy_spec
+ end
+
+ let(:no_proxy_spec) { "somehost1,somehost2" }
+ include_examples "proxified socket"
+ end
+ end
+
+ context "when http_proxy is set" do
+ before do
+ ENV["https_proxy"] = nil
+ ENV["http_proxy"] = http_uri
+ end
+
+ let(:proxy_uri) { http_uri }
+ include_examples "proxified socket"
+ end
+
+end
diff --git a/spec/unit/mixin/securable_spec.rb b/spec/unit/mixin/securable_spec.rb
index 714d6dedae..6f50ce853f 100644
--- a/spec/unit/mixin/securable_spec.rb
+++ b/spec/unit/mixin/securable_spec.rb
@@ -1,7 +1,7 @@
# encoding: UTF-8
#
-# Author:: Mark Mzyk (<mmzyk@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Mark Mzyk (<mmzyk@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Mixin::Securable do
@@ -59,32 +59,32 @@ describe Chef::Mixin::Securable do
end
it "should accept group/owner names that are a single character or digit" do
- expect { @securable.group 'v' }.not_to raise_error
- expect { @securable.group '1' }.not_to raise_error
- expect { @securable.owner 'v' }.not_to raise_error
- expect { @securable.owner '1' }.not_to raise_error
+ expect { @securable.group "v" }.not_to raise_error
+ expect { @securable.group "1" }.not_to raise_error
+ expect { @securable.owner "v" }.not_to raise_error
+ expect { @securable.owner "1" }.not_to raise_error
end
it "should not accept group/owner names starting with '-', '+', or '~'" do
- expect { @securable.group '-test' }.to raise_error(ArgumentError)
- expect { @securable.group '+test' }.to raise_error(ArgumentError)
- expect { @securable.group '~test' }.to raise_error(ArgumentError)
- expect { @securable.group 'te-st' }.not_to raise_error
- expect { @securable.group 'te+st' }.not_to raise_error
- expect { @securable.group 'te~st' }.not_to raise_error
- expect { @securable.owner '-test' }.to raise_error(ArgumentError)
- expect { @securable.owner '+test' }.to raise_error(ArgumentError)
- expect { @securable.owner '~test' }.to raise_error(ArgumentError)
- expect { @securable.owner 'te-st' }.not_to raise_error
- expect { @securable.owner 'te+st' }.not_to raise_error
- expect { @securable.owner 'te~st' }.not_to raise_error
+ expect { @securable.group "-test" }.to raise_error(ArgumentError)
+ expect { @securable.group "+test" }.to raise_error(ArgumentError)
+ expect { @securable.group "~test" }.to raise_error(ArgumentError)
+ expect { @securable.group "te-st" }.not_to raise_error
+ expect { @securable.group "te+st" }.not_to raise_error
+ expect { @securable.group "te~st" }.not_to raise_error
+ expect { @securable.owner "-test" }.to raise_error(ArgumentError)
+ expect { @securable.owner "+test" }.to raise_error(ArgumentError)
+ expect { @securable.owner "~test" }.to raise_error(ArgumentError)
+ expect { @securable.owner "te-st" }.not_to raise_error
+ expect { @securable.owner "te+st" }.not_to raise_error
+ expect { @securable.owner "te~st" }.not_to raise_error
end
it "should not accept group/owner names containing ':', ',' or non-space whitespace" do
- expect { @securable.group ':test' }.to raise_error(ArgumentError)
- expect { @securable.group 'te:st' }.to raise_error(ArgumentError)
- expect { @securable.group ',test' }.to raise_error(ArgumentError)
- expect { @securable.group 'te,st' }.to raise_error(ArgumentError)
+ expect { @securable.group ":test" }.to raise_error(ArgumentError)
+ expect { @securable.group "te:st" }.to raise_error(ArgumentError)
+ expect { @securable.group ",test" }.to raise_error(ArgumentError)
+ expect { @securable.group "te,st" }.to raise_error(ArgumentError)
expect { @securable.group "\ttest" }.to raise_error(ArgumentError)
expect { @securable.group "te\tst" }.to raise_error(ArgumentError)
expect { @securable.group "\rtest" }.to raise_error(ArgumentError)
@@ -93,10 +93,10 @@ describe Chef::Mixin::Securable do
expect { @securable.group "te\fst" }.to raise_error(ArgumentError)
expect { @securable.group "\0test" }.to raise_error(ArgumentError)
expect { @securable.group "te\0st" }.to raise_error(ArgumentError)
- expect { @securable.owner ':test' }.to raise_error(ArgumentError)
- expect { @securable.owner 'te:st' }.to raise_error(ArgumentError)
- expect { @securable.owner ',test' }.to raise_error(ArgumentError)
- expect { @securable.owner 'te,st' }.to raise_error(ArgumentError)
+ expect { @securable.owner ":test" }.to raise_error(ArgumentError)
+ expect { @securable.owner "te:st" }.to raise_error(ArgumentError)
+ expect { @securable.owner ",test" }.to raise_error(ArgumentError)
+ expect { @securable.owner "te,st" }.to raise_error(ArgumentError)
expect { @securable.owner "\ttest" }.to raise_error(ArgumentError)
expect { @securable.owner "te\tst" }.to raise_error(ArgumentError)
expect { @securable.owner "\rtest" }.to raise_error(ArgumentError)
@@ -124,10 +124,10 @@ describe Chef::Mixin::Securable do
end
it "should accept group/owner names in UTF-8" do
- expect { @securable.group 'tëst' }.not_to raise_error
- expect { @securable.group 'ë' }.not_to raise_error
- expect { @securable.owner 'tëst' }.not_to raise_error
- expect { @securable.owner 'ë' }.not_to raise_error
+ expect { @securable.group "tëst" }.not_to raise_error
+ expect { @securable.group "ë" }.not_to raise_error
+ expect { @securable.owner "tëst" }.not_to raise_error
+ expect { @securable.owner "ë" }.not_to raise_error
end
it "should accept a unix file mode in string form as an octal number" do
@@ -227,9 +227,9 @@ describe Chef::Mixin::Securable do
expect { @securable.mode 0111 }.not_to raise_error
expect { @securable.mode 73 }.not_to raise_error
- expect { @securable.mode -01 }.to raise_error(ArgumentError)
+ expect { @securable.mode(-01) }.to raise_error(ArgumentError)
expect { @securable.mode 010000 }.to raise_error(ArgumentError)
- expect { @securable.mode -1 }.to raise_error(ArgumentError)
+ expect { @securable.mode(-1) }.to raise_error(ArgumentError)
expect { @securable.mode 4096 }.to raise_error(ArgumentError)
end
@@ -253,7 +253,7 @@ describe Chef::Mixin::Securable do
it "should accept a principal as a string or an array" do
expect { @securable.rights :read, "The Dude" }.not_to raise_error
- expect { @securable.rights :read, ["The Dude","Donny"] }.not_to raise_error
+ expect { @securable.rights :read, ["The Dude", "Donny"] }.not_to raise_error
expect { @securable.rights :read, 3 }.to raise_error(ArgumentError)
end
@@ -262,19 +262,19 @@ describe Chef::Mixin::Securable do
expect { @securable.rights :read, "The Dude", :applies_to_children => true }.not_to raise_error
expect { @securable.rights :read, "The Dude", :applies_to_children => :containers_only }.not_to raise_error
expect { @securable.rights :read, "The Dude", :applies_to_children => :objects_only }.not_to raise_error
- expect { @securable.rights :read, "The Dude", :applies_to_children => 'poop' }.to raise_error(ArgumentError)
+ expect { @securable.rights :read, "The Dude", :applies_to_children => "poop" }.to raise_error(ArgumentError)
end
it "should allow you to specify whether the permissions applies_to_self with true/false" do
expect { @securable.rights :read, "The Dude", :applies_to_children => true, :applies_to_self => false }.not_to raise_error
expect { @securable.rights :read, "The Dude", :applies_to_self => true }.not_to raise_error
- expect { @securable.rights :read, "The Dude", :applies_to_self => 'poop' }.to raise_error(ArgumentError)
+ expect { @securable.rights :read, "The Dude", :applies_to_self => "poop" }.to raise_error(ArgumentError)
end
it "should allow you to specify whether the permissions applies one_level_deep with true/false" do
expect { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => false }.not_to raise_error
expect { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => true }.not_to raise_error
- expect { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => 'poop' }.to raise_error(ArgumentError)
+ expect { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => "poop" }.to raise_error(ArgumentError)
end
it "should allow multiple rights and deny_rights declarations" do
diff --git a/spec/unit/mixin/shell_out_spec.rb b/spec/unit/mixin/shell_out_spec.rb
index beaf624ddb..aa38639c1c 100644
--- a/spec/unit/mixin/shell_out_spec.rb
+++ b/spec/unit/mixin/shell_out_spec.rb
@@ -1,10 +1,10 @@
#
-# Author:: Ho-Sheng Hsiao (hosh@opscode.com)
+# Author:: Ho-Sheng Hsiao (hosh@chef.io)
# Code derived from spec/unit/mixin/command_spec.rb
#
# Original header:
# Author:: Hongli Lai (hongli@phusion.nl)
-# Copyright:: Copyright (c) 2009 Phusion
+# Copyright:: Copyright 2009-2016, Phusion
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,63 +20,66 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Mixin::ShellOut do
let(:shell_out_class) { Class.new { include Chef::Mixin::ShellOut } }
subject(:shell_out_obj) { shell_out_class.new }
- describe '#run_command_compatible_options' do
+ describe "#run_command_compatible_options" do
subject { shell_out_obj.run_command_compatible_options(command_args) }
let(:command_args) { [ cmd, options ] }
let(:cmd) { "echo '#{rand(1000)}'" }
let(:output) { StringIO.new }
- let!(:capture_log_output) { Chef::Log.logger = Logger.new(output) }
+ let!(:capture_log_output) { Chef::Log.logger = Logger.new(output) }
let(:assume_deprecation_log_level) { allow(Chef::Log).to receive(:level).and_return(:warn) }
- context 'without options' do
+ before do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ end
+
+ context "without options" do
let(:command_args) { [ cmd ] }
- it 'should not edit command args' do
+ it "should not edit command args" do
is_expected.to eql(command_args)
end
end
- context 'without deprecated options' do
+ context "without deprecated options" do
let(:options) { { :environment => environment } }
- let(:environment) { { 'LC_ALL' => 'C', 'LANG' => 'C', 'LANGUAGE' => 'C' } }
+ let(:environment) { { "LC_ALL" => "C", "LANG" => "C", "LANGUAGE" => "C" } }
- it 'should not edit command args' do
+ it "should not edit command args" do
is_expected.to eql(command_args)
end
end
def self.should_emit_deprecation_warning_about(old_option, new_option)
- it 'should emit a deprecation warning' do
- assume_deprecation_log_level and capture_log_output
+ it "should emit a deprecation warning" do
+ assume_deprecation_log_level && capture_log_output
subject
- expect(output.string).to match /DEPRECATION:/
expect(output.string).to match Regexp.escape(old_option.to_s)
expect(output.string).to match Regexp.escape(new_option.to_s)
end
end
- context 'with :command_log_level option' do
+ context "with :command_log_level option" do
let(:options) { { :command_log_level => command_log_level } }
let(:command_log_level) { :warn }
- it 'should convert :command_log_level to :log_level' do
+ it "should convert :command_log_level to :log_level" do
is_expected.to eql [ cmd, { :log_level => command_log_level } ]
end
should_emit_deprecation_warning_about :command_log_level, :log_level
end
- context 'with :command_log_prepend option' do
+ context "with :command_log_prepend option" do
let(:options) { { :command_log_prepend => command_log_prepend } }
- let(:command_log_prepend) { 'PROVIDER:' }
+ let(:command_log_prepend) { "PROVIDER:" }
- it 'should convert :command_log_prepend to :log_tag' do
+ it "should convert :command_log_prepend to :log_tag" do
is_expected.to eql [ cmd, { :log_tag => command_log_prepend } ]
end
@@ -84,7 +87,7 @@ describe Chef::Mixin::ShellOut do
end
context "with 'command_log_level' option" do
- let(:options) { { 'command_log_level' => command_log_level } }
+ let(:options) { { "command_log_level" => command_log_level } }
let(:command_log_level) { :warn }
it "should convert 'command_log_level' to :log_level" do
@@ -95,8 +98,8 @@ describe Chef::Mixin::ShellOut do
end
context "with 'command_log_prepend' option" do
- let(:options) { { 'command_log_prepend' => command_log_prepend } }
- let(:command_log_prepend) { 'PROVIDER:' }
+ let(:options) { { "command_log_prepend" => command_log_prepend } }
+ let(:command_log_prepend) { "PROVIDER:" }
it "should convert 'command_log_prepend' to :log_tag" do
is_expected.to eql [ cmd, { :log_tag => command_log_prepend } ]
@@ -124,95 +127,95 @@ describe Chef::Mixin::ShellOut do
describe "when the last argument is a Hash" do
describe "and environment is an option" do
it "should not change environment language settings when they are set to nil" do
- options = { :environment => { 'LC_ALL' => nil, 'LANGUAGE' => nil, 'LANG' => nil } }
+ options = { :environment => { "LC_ALL" => nil, "LANGUAGE" => nil, "LANG" => nil } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
shell_out_obj.shell_out(cmd, options)
end
it "should not change environment language settings when they are set to non-nil" do
- options = { :environment => { 'LC_ALL' => 'en_US.UTF-8', 'LANGUAGE' => 'en_US.UTF-8', 'LANG' => 'en_US.UTF-8' } }
+ options = { :environment => { "LC_ALL" => "en_US.UTF-8", "LANGUAGE" => "en_US.UTF-8", "LANG" => "en_US.UTF-8" } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
shell_out_obj.shell_out(cmd, options)
end
it "should set environment language settings to the configured internal locale when they are not present" do
- options = { :environment => { 'HOME' => '/Users/morty' } }
+ options = { :environment => { "HOME" => "/Users/morty" } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, {
:environment => {
- 'HOME' => '/Users/morty',
- 'LC_ALL' => Chef::Config[:internal_locale],
- 'LANG' => Chef::Config[:internal_locale],
- 'LANGUAGE' => Chef::Config[:internal_locale],
+ "HOME" => "/Users/morty",
+ "LC_ALL" => Chef::Config[:internal_locale],
+ "LANG" => Chef::Config[:internal_locale],
+ "LANGUAGE" => Chef::Config[:internal_locale],
},
}).and_return(true)
shell_out_obj.shell_out(cmd, options)
end
it "should not mutate the options hash when it adds language settings" do
- options = { :environment => { 'HOME' => '/Users/morty' } }
+ options = { :environment => { "HOME" => "/Users/morty" } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, {
:environment => {
- 'HOME' => '/Users/morty',
- 'LC_ALL' => Chef::Config[:internal_locale],
- 'LANG' => Chef::Config[:internal_locale],
- 'LANGUAGE' => Chef::Config[:internal_locale],
+ "HOME" => "/Users/morty",
+ "LC_ALL" => Chef::Config[:internal_locale],
+ "LANG" => Chef::Config[:internal_locale],
+ "LANGUAGE" => Chef::Config[:internal_locale],
},
}).and_return(true)
shell_out_obj.shell_out(cmd, options)
- expect(options[:environment].has_key?('LC_ALL')).to be false
+ expect(options[:environment].has_key?("LC_ALL")).to be false
end
end
describe "and env is an option" do
it "should not change env when langauge options are set to nil" do
- options = { :env => { 'LC_ALL' => nil, 'LANG' => nil, 'LANGUAGE' => nil } }
+ options = { :env => { "LC_ALL" => nil, "LANG" => nil, "LANGUAGE" => nil } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
shell_out_obj.shell_out(cmd, options)
end
it "should not change env when language options are set to non-nil" do
- options = { :env => { 'LC_ALL' => 'de_DE.UTF-8', 'LANG' => 'de_DE.UTF-8', 'LANGUAGE' => 'de_DE.UTF-8' }}
+ options = { :env => { "LC_ALL" => "de_DE.UTF-8", "LANG" => "de_DE.UTF-8", "LANGUAGE" => "de_DE.UTF-8" } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
shell_out_obj.shell_out(cmd, options)
end
it "should set environment language settings to the configured internal locale when they are not present" do
- options = { :env => { 'HOME' => '/Users/morty' } }
+ options = { :env => { "HOME" => "/Users/morty" } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, {
:env => {
- 'HOME' => '/Users/morty',
- 'LC_ALL' => Chef::Config[:internal_locale],
- 'LANG' => Chef::Config[:internal_locale],
- 'LANGUAGE' => Chef::Config[:internal_locale],
- }
+ "HOME" => "/Users/morty",
+ "LC_ALL" => Chef::Config[:internal_locale],
+ "LANG" => Chef::Config[:internal_locale],
+ "LANGUAGE" => Chef::Config[:internal_locale],
+ },
}).and_return(true)
shell_out_obj.shell_out(cmd, options)
end
it "should not mutate the options hash when it adds language settings" do
- options = { :env => { 'HOME' => '/Users/morty' } }
+ options = { :env => { "HOME" => "/Users/morty" } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, {
:env => {
- 'HOME' => '/Users/morty',
- 'LC_ALL' => Chef::Config[:internal_locale],
- 'LANG' => Chef::Config[:internal_locale],
- 'LANGUAGE' => Chef::Config[:internal_locale],
- }
+ "HOME" => "/Users/morty",
+ "LC_ALL" => Chef::Config[:internal_locale],
+ "LANG" => Chef::Config[:internal_locale],
+ "LANGUAGE" => Chef::Config[:internal_locale],
+ },
}).and_return(true)
shell_out_obj.shell_out(cmd, options)
- expect(options[:env].has_key?('LC_ALL')).to be false
+ expect(options[:env].has_key?("LC_ALL")).to be false
end
end
describe "and no env/environment option is present" do
it "should set environment language settings to the configured internal locale" do
- options = { :user => 'morty' }
+ options = { :user => "morty" }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, {
- :user => 'morty',
+ :user => "morty",
:environment => {
- 'LC_ALL' => Chef::Config[:internal_locale],
- 'LANG' => Chef::Config[:internal_locale],
- 'LANGUAGE' => Chef::Config[:internal_locale],
+ "LC_ALL" => Chef::Config[:internal_locale],
+ "LANG" => Chef::Config[:internal_locale],
+ "LANGUAGE" => Chef::Config[:internal_locale],
},
}).and_return(true)
shell_out_obj.shell_out(cmd, options)
@@ -224,9 +227,9 @@ describe Chef::Mixin::ShellOut do
it "should set environment language settings to the configured internal locale" do
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, {
:environment => {
- 'LC_ALL' => Chef::Config[:internal_locale],
- 'LANG' => Chef::Config[:internal_locale],
- 'LANGUAGE' => Chef::Config[:internal_locale],
+ "LC_ALL" => Chef::Config[:internal_locale],
+ "LANG" => Chef::Config[:internal_locale],
+ "LANGUAGE" => Chef::Config[:internal_locale],
},
}).and_return(true)
shell_out_obj.shell_out(cmd)
@@ -240,19 +243,19 @@ describe Chef::Mixin::ShellOut do
describe "when the last argument is a Hash" do
describe "and environment is an option" do
it "should not change environment['LC_ALL'] when set to nil" do
- options = { :environment => { 'LC_ALL' => nil } }
+ options = { :environment => { "LC_ALL" => nil } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
shell_out_obj.shell_out_with_systems_locale(cmd, options)
end
it "should not change environment['LC_ALL'] when set to non-nil" do
- options = { :environment => { 'LC_ALL' => 'en_US.UTF-8' } }
+ options = { :environment => { "LC_ALL" => "en_US.UTF-8" } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
shell_out_obj.shell_out_with_systems_locale(cmd, options)
end
it "should no longer set environment['LC_ALL'] to nil when 'LC_ALL' not present" do
- options = { :environment => { 'HOME' => '/Users/morty' } }
+ options = { :environment => { "HOME" => "/Users/morty" } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
shell_out_obj.shell_out_with_systems_locale(cmd, options)
end
@@ -260,19 +263,19 @@ describe Chef::Mixin::ShellOut do
describe "and env is an option" do
it "should not change env when set to nil" do
- options = { :env => { 'LC_ALL' => nil } }
+ options = { :env => { "LC_ALL" => nil } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
shell_out_obj.shell_out_with_systems_locale(cmd, options)
end
it "should not change env when set to non-nil" do
- options = { :env => { 'LC_ALL' => 'en_US.UTF-8'}}
+ options = { :env => { "LC_ALL" => "en_US.UTF-8" } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
shell_out_obj.shell_out_with_systems_locale(cmd, options)
end
it "should no longer set env['LC_ALL'] to nil when 'LC_ALL' not present" do
- options = { :env => { 'HOME' => '/Users/morty' } }
+ options = { :env => { "HOME" => "/Users/morty" } }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
shell_out_obj.shell_out_with_systems_locale(cmd, options)
end
@@ -280,7 +283,7 @@ describe Chef::Mixin::ShellOut do
describe "and no env/environment option is present" do
it "should no longer add environment option and set environment['LC_ALL'] to nil" do
- options = { :user => 'morty' }
+ options = { :user => "morty" }
expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
shell_out_obj.shell_out_with_systems_locale(cmd, options)
end
diff --git a/spec/unit/mixin/subclass_directive_spec.rb b/spec/unit/mixin/subclass_directive_spec.rb
new file mode 100644
index 0000000000..ef3c566838
--- /dev/null
+++ b/spec/unit/mixin/subclass_directive_spec.rb
@@ -0,0 +1,45 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+class SubclassDirectiveParent
+ extend Chef::Mixin::SubclassDirective
+
+ subclass_directive :behave_differently
+end
+
+class SubclassDirectiveChild < SubclassDirectiveParent
+ behave_differently
+end
+
+class ChildWithoutDirective < SubclassDirectiveParent
+end
+
+describe Chef::Mixin::Uris do
+ let (:child) { SubclassDirectiveChild.new }
+
+ let (:other_child) { ChildWithoutDirective.new }
+
+ it "the child instance has the directive set" do
+ expect(child.behave_differently?).to be true
+ end
+
+ it "a child that does not declare it does not have it set" do
+ expect(other_child.behave_differently?).to be false
+ end
+end
diff --git a/spec/unit/mixin/template_spec.rb b/spec/unit/mixin/template_spec.rb
index 95d0eb6711..ab7ed5bc5a 100644
--- a/spec/unit/mixin/template_spec.rb
+++ b/spec/unit/mixin/template_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'cgi'
+require "cgi"
describe Chef::Mixin::Template, "render_template" do
let(:sep) { Chef::Platform.windows? ? "\r\n" : "\n" }
@@ -85,10 +85,10 @@ describe Chef::Mixin::Template, "render_template" do
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
- @rendered_file_location = Dir.tmpdir + '/openldap_stuff.conf'
+ @rendered_file_location = Dir.tmpdir + "/openldap_stuff.conf"
@resource = Chef::Resource::Template.new(@rendered_file_location)
- @resource.cookbook_name = 'openldap'
+ @resource.cookbook_name = "openldap"
@current_resource = @resource.dup
@content_provider = Chef::Provider::Template::Content.new(@resource, @current_resource, @run_context)
@@ -117,7 +117,7 @@ describe Chef::Mixin::Template, "render_template" do
end
it "should render partials from a different cookbook" do
- @template_context[:template_finder] = Chef::Provider::TemplateFinder.new(@run_context, 'apache2', @node)
+ @template_context[:template_finder] = Chef::Provider::TemplateFinder.new(@run_context, "apache2", @node)
output = @template_context.render_template_from_string("before {<%= render('test.erb', :cookbook => 'openldap').strip %>} after")
expect(output).to eq("before {We could be diving for pearls!} after")
@@ -144,7 +144,7 @@ describe Chef::Mixin::Template, "render_template" do
end
it "should pass the original variables to partials" do
- @template_context[:secret] = 'candy'
+ @template_context[:secret] = "candy"
output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb' %>} after")
output == "before {super secret is candy} after"
@@ -161,7 +161,7 @@ describe Chef::Mixin::Template, "render_template" do
end
it "should pass variables to partials even if they are named the same" do
- @template_context[:secret] = 'one'
+ @template_context[:secret] = "one"
output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb', :variables => {:secret => 'two' } %>} after <%= @secret %>")
expect(output).to eq("before {super secret is two} after one")
@@ -172,7 +172,7 @@ describe Chef::Mixin::Template, "render_template" do
expect(output).to eq("before {super secret is } after")
output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb' %>} after")
- expect(output).to eq("before {super secret is } after")
+ expect(output).to eq("before {super secret is } after")
end
it "should render nested partials" do
@@ -199,14 +199,17 @@ describe Chef::Mixin::Template, "render_template" do
mod = Module.new do
def render
end
+
def node
end
+
def render_template
end
+
def render_template_from_string
end
end
- ['node', 'render', 'render_template', 'render_template_from_string'].each do |method_name|
+ %w{node render render_template render_template_from_string}.each do |method_name|
expect(Chef::Log).to receive(:warn).with(/^Core template method `#{method_name}' overridden by extension module/)
end
@template_context._extend_modules([mod])
@@ -225,7 +228,7 @@ describe Chef::Mixin::Template, "render_template" do
end
it "should raise an error if an attempt is made to access node but it is nil" do
- expect {@context.render_template_from_string("<%= node %>") {|r| r}}.to raise_error(Chef::Mixin::Template::TemplateError)
+ expect { @context.render_template_from_string("<%= node %>") { |r| r } }.to raise_error(Chef::Mixin::Template::TemplateError)
end
describe "the raised TemplateError" do
diff --git a/spec/unit/mixin/unformatter_spec.rb b/spec/unit/mixin/unformatter_spec.rb
index 2eae0ac9bb..b2b57c150c 100644
--- a/spec/unit/mixin/unformatter_spec.rb
+++ b/spec/unit/mixin/unformatter_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software
+# Copyright:: Copyright 2015-2016, Chef Software
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/unformatter'
+require "spec_helper"
+require "chef/mixin/unformatter"
class Chef::UnformatterTest
include Chef::Mixin::Unformatter
diff --git a/spec/unit/mixin/uris_spec.rb b/spec/unit/mixin/uris_spec.rb
index d4985c4f67..9005edd7b4 100644
--- a/spec/unit/mixin/uris_spec.rb
+++ b/spec/unit/mixin/uris_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/uris'
+require "spec_helper"
+require "chef/mixin/uris"
class Chef::UrisTest
include Chef::Mixin::Uris
@@ -28,25 +28,25 @@ describe Chef::Mixin::Uris do
describe "#uri_scheme?" do
it "matches 'scheme://foo.com'" do
- expect(uris.uri_scheme?('scheme://foo.com')).to eq(true)
+ expect(uris.uri_scheme?("scheme://foo.com")).to eq(true)
end
it "does not match 'c:/foo.com'" do
- expect(uris.uri_scheme?('c:/foo.com')).to eq(false)
+ expect(uris.uri_scheme?("c:/foo.com")).to eq(false)
end
it "does not match '/usr/bin/foo.com'" do
- expect(uris.uri_scheme?('/usr/bin/foo.com')).to eq(false)
+ expect(uris.uri_scheme?("/usr/bin/foo.com")).to eq(false)
end
it "does not match 'c:/foo.com://bar.com'" do
- expect(uris.uri_scheme?('c:/foo.com://bar.com')).to eq(false)
+ expect(uris.uri_scheme?("c:/foo.com://bar.com")).to eq(false)
end
end
describe "#as_uri" do
it "parses a file scheme uri with spaces" do
- expect{ uris.as_uri("file:///c:/foo bar.txt") }.not_to raise_exception
+ expect { uris.as_uri("file:///c:/foo bar.txt") }.not_to raise_exception
end
it "returns a URI object" do
diff --git a/spec/unit/mixin/versioned_api_spec.rb b/spec/unit/mixin/versioned_api_spec.rb
new file mode 100644
index 0000000000..4f2418ca24
--- /dev/null
+++ b/spec/unit/mixin/versioned_api_spec.rb
@@ -0,0 +1,107 @@
+#
+# Copyright:: Copyright 2015-2017, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/mixin/versioned_api"
+
+describe Chef::Mixin::VersionedAPI do
+ let(:dummy_class) { Class.new { extend Chef::Mixin::VersionedAPI } }
+
+ it "allows a class to declare the minimum supported API version" do
+ dummy_class.minimum_api_version 3
+ expect(dummy_class.minimum_api_version).to eq(3)
+ end
+end
+
+describe Chef::Mixin::VersionedAPIFactory do
+ class V1Class; extend Chef::Mixin::VersionedAPI; minimum_api_version 1; end
+ class V2Class; extend Chef::Mixin::VersionedAPI; minimum_api_version 2; end
+ class V3Class; extend Chef::Mixin::VersionedAPI; minimum_api_version 3; end
+
+ let(:factory_class) { Class.new { extend Chef::Mixin::VersionedAPIFactory } }
+
+ before do
+ Chef::ServerAPIVersions.instance.reset!
+ end
+
+ describe "#add_versioned_api_class" do
+ it "adds a target class" do
+ factory_class.add_versioned_api_class V1Class
+ expect(factory_class.versioned_interfaces).to eq([V1Class])
+ end
+
+ it "can be called many times" do
+ factory_class.add_versioned_api_class V1Class
+ factory_class.add_versioned_api_class V2Class
+ expect(factory_class.versioned_interfaces).to eq([V1Class, V2Class])
+ end
+ end
+
+ describe "#versioned_api_class" do
+ describe "with no known versions" do
+ it "with one class it returns that class" do
+ factory_class.add_versioned_api_class V2Class
+ expect(factory_class.versioned_api_class.minimum_api_version).to eq(2)
+ end
+
+ it "with many classes it returns the highest minimum version" do
+ factory_class.add_versioned_api_class V1Class
+ factory_class.add_versioned_api_class V2Class
+ factory_class.add_versioned_api_class V3Class
+ expect(factory_class.versioned_api_class.minimum_api_version).to eq(3)
+ end
+ end
+
+ describe "with a known version" do
+ it "with one class it returns that class" do
+ Chef::ServerAPIVersions.instance.set_versions({ "min_version" => 0, "max_version" => 2 })
+ factory_class.add_versioned_api_class V2Class
+ expect(factory_class.versioned_api_class.minimum_api_version).to eq(2)
+ end
+
+ it "with a maximum version it returns the highest possible versioned class" do
+ Chef::ServerAPIVersions.instance.set_versions({ "min_version" => 0, "max_version" => 2 })
+ factory_class.add_versioned_api_class V1Class
+ factory_class.add_versioned_api_class V2Class
+ factory_class.add_versioned_api_class V3Class
+ expect(factory_class.versioned_api_class.minimum_api_version).to eq(2)
+ end
+ end
+
+ it "with no classes it returns nil" do
+ expect(factory_class.versioned_api_class).to be_nil
+ end
+ end
+
+ describe "#new" do
+ it "creates an instance of the versioned class" do
+ factory_class.add_versioned_api_class V2Class
+ expect { factory_class.new }.to_not raise_error
+ expect(factory_class.new.class).to eq(V2Class)
+ end
+ end
+
+ describe "#def_versioned_delegator" do
+ it "delegates the method to the correct class" do
+ factory_class.add_versioned_api_class V2Class
+ factory_class.def_versioned_delegator("test_method")
+ expect(V2Class).to receive(:test_method).with("test message").and_return(true)
+
+ factory_class.test_method("test message")
+ end
+ end
+end
diff --git a/spec/unit/mixin/which.rb b/spec/unit/mixin/which.rb
new file mode 100644
index 0000000000..1764b3b89f
--- /dev/null
+++ b/spec/unit/mixin/which.rb
@@ -0,0 +1,160 @@
+#
+# Copyright:: Copyright 2011-2017, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+class TestClass
+ include Chef::Mixin::Which
+end
+
+describe Chef::Mixin::Which do
+
+ let(:test) { TestClass.new }
+
+ describe "#which" do
+ def self.test_which(description, *args, finds: nil, others: [], directory: false, &block)
+ it description do
+ # stub the ENV['PATH']
+ expect(test).to receive(:env_path).and_return(["/dir1", "/dir2" ].join(File::PATH_SEPARATOR))
+
+ # most files should not be found
+ allow(File).to receive(:executable?).and_return(false)
+ allow(File).to receive(:directory?).and_return(false)
+
+ # stub the expectation
+ expect(File).to receive(:executable?).with(finds).and_return(true) if finds
+
+ # if the file we find is a directory
+ expect(File).to receive(:directory?).with(finds).and_return(true) if finds && directory
+
+ # allow for stubbing other paths to exist that we should not find
+ others.each do |other|
+ allow(File).to receive(:executable?).with(other).and_return(true)
+ end
+
+ # setup the actual expectation on the return value
+ if finds && !directory
+ expect(test.which(*args, &block)).to eql(finds)
+ else
+ expect(test.which(*args, &block)).to eql(false)
+ end
+ end
+ end
+
+ context "simple usage" do
+ test_which("returns false when it does not find anything", "foo1")
+
+ ["/dir1", "/dir2", "/bin", "/usr/bin", "/sbin", "/usr/sbin" ].each do |dir|
+ test_which("finds `foo1` in #{dir} when it is stubbed", "foo1", finds: "#{dir}/foo1")
+ end
+
+ test_which("does not find an executable directory", "foo1", finds: "/dir1/foo1", directory: true)
+ end
+
+ context "with an array of args" do
+ test_which("finds the first arg", "foo1", "foo2", finds: "/dir2/foo1")
+
+ test_which("finds the second arg", "foo1", "foo2", finds: "/dir2/foo2")
+
+ test_which("finds the first arg when there's both", "foo1", "foo2", finds: "/dir2/foo1", others: [ "/dir1/foo2" ])
+
+ test_which("and the directory order can be reversed", "foo1", "foo2", finds: "/dir1/foo1", others: [ "/dir2/foo2" ])
+
+ test_which("or be the same", "foo1", "foo2", finds: "/dir1/foo1", others: [ "/dir1/foo2" ])
+ end
+
+ context "with a block" do
+ test_which("doesnt find it if its false", "foo1", others: [ "/dir1/foo1" ]) do |f|
+ false
+ end
+
+ test_which("finds it if its true", "foo1", finds: "/dir1/foo1") do |f|
+ true
+ end
+
+ test_which("passes in the filename as the arg", "foo1", finds: "/dir1/foo1") do |f|
+ raise "bad arg to block" unless f == "/dir1/foo1"
+ true
+ end
+
+ test_which("arrays with blocks", "foo1", "foo2", finds: "/dir2/foo1", others: [ "/dir1/foo2" ]) do |f|
+ raise "bad arg to block" unless f == "/dir2/foo1" || f == "/dir1/foo2"
+ true
+ end
+ end
+ end
+
+ describe "#where" do
+ def self.test_where(description, *args, finds: [], others: [], &block)
+ it description do
+ # stub the ENV['PATH']
+ expect(test).to receive(:env_path).and_return(["/dir1", "/dir2" ].join(File::PATH_SEPARATOR))
+
+ # most files should not be found
+ allow(File).to receive(:executable?).and_return(false)
+ allow(File).to receive(:directory?).and_return(false)
+
+ # allow for stubbing other paths to exist that we should not return
+ others.each do |other|
+ allow(File).to receive(:executable?).with(other).and_return(true)
+ end
+
+ # stub the expectation
+ finds.each do |path|
+ expect(File).to receive(:executable?).with(path).and_return(true)
+ end
+
+ # setup the actual expectation on the return value
+ expect(test.where(*args, &block)).to eql(finds)
+ end
+ end
+
+ context "simple usage" do
+ test_where("returns empty array when it doesn't find anything", "foo1")
+
+ ["/dir1", "/dir2", "/bin", "/usr/bin", "/sbin", "/usr/sbin" ].each do |dir|
+ test_where("finds `foo1` in #{dir} when it is stubbed", "foo1", finds: [ "#{dir}/foo1" ])
+ end
+
+ test_where("finds `foo1` in all directories", "foo1", finds: [ "/dir1/foo1", "/dir2/foo1" ])
+ end
+
+ context "with an array of args" do
+ test_where("finds the first arg", "foo1", "foo2", finds: [ "/dir2/foo1" ])
+
+ test_where("finds the second arg", "foo1", "foo2", finds: [ "/dir2/foo2" ])
+
+ test_where("finds foo1 before foo2", "foo1", "foo2", finds: [ "/dir2/foo1", "/dir1/foo2" ])
+
+ test_where("finds foo1 before foo2 if the dirs are reversed", "foo1", "foo2", finds: [ "/dir1/foo1", "/dir2/foo2" ])
+
+ test_where("finds them both in the same directory", "foo1", "foo2", finds: [ "/dir1/foo1", "/dir1/foo2" ])
+
+ test_where("finds foo2 first if they're reversed", "foo2", "foo1", finds: [ "/dir1/foo2", "/dir1/foo1" ])
+ end
+
+ context "with a block do" do
+ test_where("finds foo1 and foo2 if they exist and the block is true", "foo1", "foo2", finds: [ "/dir1/foo2", "/dir2/foo2" ]) do
+ true
+ end
+
+ test_where("does not finds foo1 and foo2 if they exist and the block is false", "foo1", "foo2", others: [ "/dir1/foo2", "/dir2/foo2" ]) do
+ false
+ end
+ end
+ end
+end
diff --git a/spec/unit/mixin/windows_architecture_helper_spec.rb b/spec/unit/mixin/windows_architecture_helper_spec.rb
index 55eca28dc2..4559702e1c 100644
--- a/spec/unit/mixin/windows_architecture_helper_spec.rb
+++ b/spec/unit/mixin/windows_architecture_helper_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,8 @@
# limitations under the License.
#
-
-require 'spec_helper'
-require 'chef/mixin/windows_architecture_helper'
-
-
+require "spec_helper"
+require "chef/mixin/windows_architecture_helper"
describe Chef::Mixin::WindowsArchitectureHelper do
include Chef::Mixin::WindowsArchitectureHelper
@@ -34,25 +31,25 @@ describe Chef::Mixin::WindowsArchitectureHelper do
end
it "returns true when valid architectures are passed to valid_windows_architecture?" do
- @valid_architectures.each do | architecture |
+ @valid_architectures.each do |architecture|
expect(valid_windows_architecture?(architecture)).to eq(true)
end
end
it "returns false when invalid architectures are passed to valid_windows_architecture?" do
- @invalid_architectures.each do | architecture |
+ @invalid_architectures.each do |architecture|
expect(valid_windows_architecture?(architecture)).to eq(false)
end
end
it "does not raise an exception when a valid architecture is passed to assert_valid_windows_architecture!" do
- @valid_architectures.each do | architecture |
+ @valid_architectures.each do |architecture|
assert_valid_windows_architecture!(architecture)
end
end
it "raises an error if an invalid architecture is passed to assert_valid_windows_architecture!" do
- @invalid_architectures.each do | architecture |
+ @invalid_architectures.each do |architecture|
begin
expect(assert_valid_windows_architecture!(architecture)).to raise_error Chef::Exceptions::Win32ArchitectureIncorrect
rescue Chef::Exceptions::Win32ArchitectureIncorrect
@@ -61,26 +58,26 @@ describe Chef::Mixin::WindowsArchitectureHelper do
end
it "returns true only for supported desired architecture passed to node_supports_windows_architecture" do
- with_node_architecture_combinations do | node, desired_arch |
- expect(node_supports_windows_architecture?(node, desired_arch)).to be true if (node_windows_architecture(node) == :x86_64 || desired_arch == :i386 )
- expect(node_supports_windows_architecture?(node, desired_arch)).to be false if (node_windows_architecture(node) == :i386 && desired_arch == :x86_64 )
+ with_node_architecture_combinations do |node, desired_arch|
+ expect(node_supports_windows_architecture?(node, desired_arch)).to be true if node_windows_architecture(node) == :x86_64 || desired_arch == :i386
+ expect(node_supports_windows_architecture?(node, desired_arch)).to be false if node_windows_architecture(node) == :i386 && desired_arch == :x86_64
end
end
it "returns true only when forced_32bit_override_required? has 64-bit node architecture and 32-bit desired architecture" do
- with_node_architecture_combinations do | node, desired_arch |
- expect(forced_32bit_override_required?(node, desired_arch)).to be true if ((node_windows_architecture(node) == :x86_64) && (desired_arch == :i386) && !is_i386_process_on_x86_64_windows?)
+ with_node_architecture_combinations do |node, desired_arch|
+ expect(forced_32bit_override_required?(node, desired_arch)).to be true if (node_windows_architecture(node) == :x86_64) && (desired_arch == :i386) && !is_i386_process_on_x86_64_windows?
expect(forced_32bit_override_required?(node, desired_arch)).to be false if ! ((node_windows_architecture(node) == :x86_64) && (desired_arch == :i386))
end
end
def with_node_architecture_combinations
- @valid_architectures.each do | node_architecture |
+ @valid_architectures.each do |node_architecture|
new_node = Chef::Node.new
new_node.default["kernel"] = Hash.new
new_node.default["kernel"][:machine] = node_architecture.to_s
- @valid_architectures.each do | architecture |
+ @valid_architectures.each do |architecture|
yield new_node, architecture if block_given?
end
end
diff --git a/spec/unit/mixin/xml_escape_spec.rb b/spec/unit/mixin/xml_escape_spec.rb
index c5156cfb7b..495ad0662c 100644
--- a/spec/unit/mixin/xml_escape_spec.rb
+++ b/spec/unit/mixin/xml_escape_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
class XMLEscapingTestHarness
include Chef::Mixin::XMLEscape
@@ -37,7 +37,7 @@ describe Chef::Mixin::XMLEscape do
end
it "does not modify ASCII strings" do
- expect(@escaper.xml_escape('foobarbaz!@#$%^*()')).to eq('foobarbaz!@#$%^*()')
+ expect(@escaper.xml_escape("foobarbaz!@\#$%^*()")).to eq("foobarbaz!@\#$%^*()")
end
it "converts invalid bytes to asterisks" do
@@ -45,10 +45,10 @@ describe Chef::Mixin::XMLEscape do
end
it "converts UTF-8 correctly" do
- expect(@escaper.xml_escape("\xC2\xA9")).to eq('&#169;')
+ expect(@escaper.xml_escape("\xC2\xA9")).to eq("&#169;")
end
it "converts win 1252 characters correctly" do
- expect(@escaper.xml_escape("\x80")).to eq('&#8364;')
+ expect(@escaper.xml_escape("#{0x80.chr}")).to eq("&#8364;")
end
end
diff --git a/spec/unit/monkey_patches/uri_spec.rb b/spec/unit/monkey_patches/uri_spec.rb
index 9aca1fc9f1..0679705cf4 100644
--- a/spec/unit/monkey_patches/uri_spec.rb
+++ b/spec/unit/monkey_patches/uri_spec.rb
@@ -1,6 +1,6 @@
#--
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe URI do
describe "when a URI contains an IPv6 literal" do
diff --git a/spec/unit/monologger_spec.rb b/spec/unit/monologger_spec.rb
index 8689ea0aaa..e7f2dfb19a 100644
--- a/spec/unit/monologger_spec.rb
+++ b/spec/unit/monologger_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,9 +15,9 @@
# limitations under the License.
#
-require 'chef/monologger'
-require 'tempfile'
-require 'spec_helper'
+require "chef/monologger"
+require "tempfile"
+require "spec_helper"
describe MonoLogger do
it "should disable buffering when passed an IO stream" do
diff --git a/spec/unit/node/attribute_spec.rb b/spec/unit/node/attribute_spec.rb
index 250b8c630c..a3e62ff939 100644
--- a/spec/unit/node/attribute_spec.rb
+++ b/spec/unit/node/attribute_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,178 +17,138 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/node/attribute'
+require "spec_helper"
+require "chef/node/attribute"
describe Chef::Node::Attribute do
+ let(:events) { instance_double(Chef::EventDispatch::Dispatcher) }
+ let(:run_context) { instance_double(Chef::RunContext, :events => events) }
+ let(:node) { instance_double(Chef::Node, :run_context => run_context) }
before(:each) do
+ allow(events).to receive(:attribute_changed)
@attribute_hash =
- {"dmi"=>{},
- "command"=>{"ps"=>"ps -ef"},
- "platform_version"=>"10.5.7",
- "platform"=>"mac_os_x",
- "ipaddress"=>"192.168.0.117",
- "network"=>
- {"default_interface"=>"en1",
- "interfaces"=>
- {"vmnet1"=>
- {"flags"=>
- ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
- "number"=>"1",
- "addresses"=>
- {"00:50:56:c0:00:01"=>{"family"=>"lladdr"},
- "192.168.110.1"=>
- {"broadcast"=>"192.168.110.255",
- "netmask"=>"255.255.255.0",
- "family"=>"inet"}},
- "mtu"=>"1500",
- "type"=>"vmnet",
- "arp"=>{"192.168.110.255"=>"ff:ff:ff:ff:ff:ff"},
- "encapsulation"=>"Ethernet"},
- "stf0"=>
- {"flags"=>[],
- "number"=>"0",
- "addresses"=>{},
- "mtu"=>"1280",
- "type"=>"stf",
- "encapsulation"=>"6to4"},
- "lo0"=>
- {"flags"=>["UP", "LOOPBACK", "RUNNING", "MULTICAST"],
- "number"=>"0",
- "addresses"=>
- {"::1"=>{"scope"=>"Node", "prefixlen"=>"128", "family"=>"inet6"},
- "127.0.0.1"=>{"netmask"=>"255.0.0.0", "family"=>"inet"},
- "fe80::1"=>{"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"}},
- "mtu"=>"16384",
- "type"=>"lo",
- "encapsulation"=>"Loopback"},
- "gif0"=>
- {"flags"=>["POINTOPOINT", "MULTICAST"],
- "number"=>"0",
- "addresses"=>{},
- "mtu"=>"1280",
- "type"=>"gif",
- "encapsulation"=>"IPIP"},
- "vmnet8"=>
- {"flags"=>
- ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
- "number"=>"8",
- "addresses"=>
- {"192.168.4.1"=>
- {"broadcast"=>"192.168.4.255",
- "netmask"=>"255.255.255.0",
- "family"=>"inet"},
- "00:50:56:c0:00:08"=>{"family"=>"lladdr"}},
- "mtu"=>"1500",
- "type"=>"vmnet",
- "arp"=>{"192.168.4.255"=>"ff:ff:ff:ff:ff:ff"},
- "encapsulation"=>"Ethernet"},
- "en0"=>
- {"status"=>"inactive",
- "flags"=>
- ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
- "number"=>"0",
- "addresses"=>{"00:23:32:b0:32:f2"=>{"family"=>"lladdr"}},
- "mtu"=>"1500",
- "media"=>
- {"supported"=>
- {"autoselect"=>{"options"=>[]},
- "none"=>{"options"=>[]},
- "1000baseT"=>
- {"options"=>["full-duplex", "flow-control", "hw-loopback"]},
- "10baseT/UTP"=>
- {"options"=>
- ["half-duplex", "full-duplex", "flow-control", "hw-loopback"]},
- "100baseTX"=>
- {"options"=>
- ["half-duplex", "full-duplex", "flow-control", "hw-loopback"]}},
- "selected"=>{"autoselect"=>{"options"=>[]}}},
- "type"=>"en",
- "encapsulation"=>"Ethernet"},
- "en1"=>
- {"status"=>"active",
- "flags"=>
- ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
- "number"=>"1",
- "addresses"=>
- {"fe80::223:6cff:fe7f:676c"=>
- {"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"},
- "00:23:6c:7f:67:6c"=>{"family"=>"lladdr"},
- "192.168.0.117"=>
- {"broadcast"=>"192.168.0.255",
- "netmask"=>"255.255.255.0",
- "family"=>"inet"}},
- "mtu"=>"1500",
- "media"=>
- {"supported"=>{"autoselect"=>{"options"=>[]}},
- "selected"=>{"autoselect"=>{"options"=>[]}}},
- "type"=>"en",
- "arp"=>
- {"192.168.0.72"=>"0:f:ea:39:fa:d5",
- "192.168.0.1"=>"0:1c:fb:fc:6f:20",
- "192.168.0.255"=>"ff:ff:ff:ff:ff:ff",
- "192.168.0.3"=>"0:1f:33:ea:26:9b",
- "192.168.0.77"=>"0:23:12:70:f8:cf",
- "192.168.0.152"=>"0:26:8:7d:2:4c"},
- "encapsulation"=>"Ethernet"},
- "en2"=>
- {"status"=>"active",
- "flags"=>
- ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
- "number"=>"2",
- "addresses"=>
- {"169.254.206.152"=>
- {"broadcast"=>"169.254.255.255",
- "netmask"=>"255.255.0.0",
- "family"=>"inet"},
- "00:1c:42:00:00:01"=>{"family"=>"lladdr"},
- "fe80::21c:42ff:fe00:1"=>
- {"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"}},
- "mtu"=>"1500",
- "media"=>
- {"supported"=>{"autoselect"=>{"options"=>[]}},
- "selected"=>{"autoselect"=>{"options"=>[]}}},
- "type"=>"en",
- "encapsulation"=>"Ethernet"},
- "fw0"=>
- {"status"=>"inactive",
- "flags"=>["BROADCAST", "SIMPLEX", "MULTICAST"],
- "number"=>"0",
- "addresses"=>{"00:23:32:ff:fe:b0:32:f2"=>{"family"=>"lladdr"}},
- "mtu"=>"4078",
- "media"=>
- {"supported"=>{"autoselect"=>{"options"=>["full-duplex"]}},
- "selected"=>{"autoselect"=>{"options"=>["full-duplex"]}}},
- "type"=>"fw",
- "encapsulation"=>"1394"},
- "en3"=>
- {"status"=>"active",
- "flags"=>
- ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
- "number"=>"3",
- "addresses"=>
- {"169.254.206.152"=>
- {"broadcast"=>"169.254.255.255",
- "netmask"=>"255.255.0.0",
- "family"=>"inet"},
- "00:1c:42:00:00:00"=>{"family"=>"lladdr"},
- "fe80::21c:42ff:fe00:0"=>
- {"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"}},
- "mtu"=>"1500",
- "media"=>
- {"supported"=>{"autoselect"=>{"options"=>[]}},
- "selected"=>{"autoselect"=>{"options"=>[]}}},
- "type"=>"en",
- "encapsulation"=>"Ethernet"}}},
- "fqdn"=>"latte.local",
- "ohai_time"=>1249065590.90391,
- "domain"=>"local",
- "os"=>"darwin",
- "platform_build"=>"9J61",
- "os_version"=>"9.7.0",
- "hostname"=>"latte",
- "macaddress"=>"00:23:6c:7f:67:6c",
- "music" => { "jimmy_eat_world" => "nice", "apophis" => false }
+ { "dmi" => {},
+ "command" => { "ps" => "ps -ef" },
+ "platform_version" => "10.5.7",
+ "platform" => "mac_os_x",
+ "ipaddress" => "192.168.0.117",
+ "network" => { "default_interface" => "en1",
+ "interfaces" => { "vmnet1" => { "flags" => %w{UP BROADCAST SMART RUNNING SIMPLEX MULTICAST},
+ "number" => "1",
+ "addresses" => { "00:50:56:c0:00:01" => { "family" => "lladdr" },
+ "192.168.110.1" => { "broadcast" => "192.168.110.255",
+ "netmask" => "255.255.255.0",
+ "family" => "inet" } },
+ "mtu" => "1500",
+ "type" => "vmnet",
+ "arp" => { "192.168.110.255" => "ff:ff:ff:ff:ff:ff" },
+ "encapsulation" => "Ethernet" },
+ "stf0" => { "flags" => [],
+ "number" => "0",
+ "addresses" => {},
+ "mtu" => "1280",
+ "type" => "stf",
+ "encapsulation" => "6to4" },
+ "lo0" => { "flags" => %w{UP LOOPBACK RUNNING MULTICAST},
+ "number" => "0",
+ "addresses" => { "::1" => { "scope" => "Node", "prefixlen" => "128", "family" => "inet6" },
+ "127.0.0.1" => { "netmask" => "255.0.0.0", "family" => "inet" },
+ "fe80::1" => { "scope" => "Link", "prefixlen" => "64", "family" => "inet6" } },
+ "mtu" => "16384",
+ "type" => "lo",
+ "encapsulation" => "Loopback" },
+ "gif0" => { "flags" => %w{POINTOPOINT MULTICAST},
+ "number" => "0",
+ "addresses" => {},
+ "mtu" => "1280",
+ "type" => "gif",
+ "encapsulation" => "IPIP" },
+ "vmnet8" => { "flags" => %w{UP BROADCAST SMART RUNNING SIMPLEX MULTICAST},
+ "number" => "8",
+ "addresses" => { "192.168.4.1" => { "broadcast" => "192.168.4.255",
+ "netmask" => "255.255.255.0",
+ "family" => "inet" },
+ "00:50:56:c0:00:08" => { "family" => "lladdr" } },
+ "mtu" => "1500",
+ "type" => "vmnet",
+ "arp" => { "192.168.4.255" => "ff:ff:ff:ff:ff:ff" },
+ "encapsulation" => "Ethernet" },
+ "en0" => { "status" => "inactive",
+ "flags" => %w{UP BROADCAST SMART RUNNING SIMPLEX MULTICAST},
+ "number" => "0",
+ "addresses" => { "00:23:32:b0:32:f2" => { "family" => "lladdr" } },
+ "mtu" => "1500",
+ "media" => { "supported" => { "autoselect" => { "options" => [] },
+ "none" => { "options" => [] },
+ "1000baseT" => { "options" => ["full-duplex", "flow-control", "hw-loopback"] },
+ "10baseT/UTP" => { "options" => ["half-duplex", "full-duplex", "flow-control", "hw-loopback"] },
+ "100baseTX" => { "options" => ["half-duplex", "full-duplex", "flow-control", "hw-loopback"] } },
+ "selected" => { "autoselect" => { "options" => [] } } },
+ "type" => "en",
+ "encapsulation" => "Ethernet" },
+ "en1" => { "status" => "active",
+ "flags" => %w{UP BROADCAST SMART RUNNING SIMPLEX MULTICAST},
+ "number" => "1",
+ "addresses" => { "fe80::223:6cff:fe7f:676c" => { "scope" => "Link", "prefixlen" => "64", "family" => "inet6" },
+ "00:23:6c:7f:67:6c" => { "family" => "lladdr" },
+ "192.168.0.117" => { "broadcast" => "192.168.0.255",
+ "netmask" => "255.255.255.0",
+ "family" => "inet" } },
+ "mtu" => "1500",
+ "media" => { "supported" => { "autoselect" => { "options" => [] } },
+ "selected" => { "autoselect" => { "options" => [] } } },
+ "type" => "en",
+ "arp" => { "192.168.0.72" => "0:f:ea:39:fa:d5",
+ "192.168.0.1" => "0:1c:fb:fc:6f:20",
+ "192.168.0.255" => "ff:ff:ff:ff:ff:ff",
+ "192.168.0.3" => "0:1f:33:ea:26:9b",
+ "192.168.0.77" => "0:23:12:70:f8:cf",
+ "192.168.0.152" => "0:26:8:7d:2:4c" },
+ "encapsulation" => "Ethernet" },
+ "en2" => { "status" => "active",
+ "flags" => %w{UP BROADCAST SMART RUNNING SIMPLEX MULTICAST},
+ "number" => "2",
+ "addresses" => { "169.254.206.152" => { "broadcast" => "169.254.255.255",
+ "netmask" => "255.255.0.0",
+ "family" => "inet" },
+ "00:1c:42:00:00:01" => { "family" => "lladdr" },
+ "fe80::21c:42ff:fe00:1" => { "scope" => "Link", "prefixlen" => "64", "family" => "inet6" } },
+ "mtu" => "1500",
+ "media" => { "supported" => { "autoselect" => { "options" => [] } },
+ "selected" => { "autoselect" => { "options" => [] } } },
+ "type" => "en",
+ "encapsulation" => "Ethernet" },
+ "fw0" => { "status" => "inactive",
+ "flags" => %w{BROADCAST SIMPLEX MULTICAST},
+ "number" => "0",
+ "addresses" => { "00:23:32:ff:fe:b0:32:f2" => { "family" => "lladdr" } },
+ "mtu" => "4078",
+ "media" => { "supported" => { "autoselect" => { "options" => ["full-duplex"] } },
+ "selected" => { "autoselect" => { "options" => ["full-duplex"] } } },
+ "type" => "fw",
+ "encapsulation" => "1394" },
+ "en3" => { "status" => "active",
+ "flags" => %w{UP BROADCAST SMART RUNNING SIMPLEX MULTICAST},
+ "number" => "3",
+ "addresses" => { "169.254.206.152" => { "broadcast" => "169.254.255.255",
+ "netmask" => "255.255.0.0",
+ "family" => "inet" },
+ "00:1c:42:00:00:00" => { "family" => "lladdr" },
+ "fe80::21c:42ff:fe00:0" => { "scope" => "Link", "prefixlen" => "64", "family" => "inet6" } },
+ "mtu" => "1500",
+ "media" => { "supported" => { "autoselect" => { "options" => [] } },
+ "selected" => { "autoselect" => { "options" => [] } } },
+ "type" => "en",
+ "encapsulation" => "Ethernet" } } },
+ "fqdn" => "latte.local",
+ "ohai_time" => 1249065590.90391,
+ "domain" => "local",
+ "os" => "darwin",
+ "platform_build" => "9J61",
+ "os_version" => "9.7.0",
+ "hostname" => "latte",
+ "macaddress" => "00:23:6c:7f:67:6c",
+ "music" => { "jimmy_eat_world" => "nice", "apophis" => false },
}
@default_hash = {
"domain" => "opscode.com",
@@ -198,19 +158,19 @@ describe Chef::Node::Attribute do
"mastodon" => "rocks",
"mars_volta" => "is loud and nutty",
"deeper" => { "gates_of_ishtar" => nil },
- "this" => {"apparatus" => {"must" => "be unearthed"}}
- }
+ "this" => { "apparatus" => { "must" => "be unearthed" } },
+ },
}
@override_hash = {
"macaddress" => "00:00:00:00:00:00",
"hot" => { "day" => "sunday" },
"fire" => "still burn",
"music" => {
- "mars_volta" => "cicatriz"
- }
+ "mars_volta" => "cicatriz",
+ },
}
- @automatic_hash = {"week" => "friday"}
- @attributes = Chef::Node::Attribute.new(@attribute_hash, @default_hash, @override_hash, @automatic_hash)
+ @automatic_hash = { "week" => "friday" }
+ @attributes = Chef::Node::Attribute.new(@attribute_hash, @default_hash, @override_hash, @automatic_hash, node)
end
describe "initialize" do
@@ -262,17 +222,17 @@ describe Chef::Node::Attribute do
end
it "gives the value at each level of precedence for a path spec" do
- expected = [["set_unless_enabled?", false],
- ["default", "default"],
- ["env_default", "env_default"],
- ["role_default", "role_default"],
- ["force_default", "force_default"],
- ["normal", "normal"],
- ["override", "override"],
- ["role_override", "role_override"],
- ["env_override", "env_override"],
- ["force_override", "force_override"],
- ["automatic", "automatic"]
+ expected = [
+ %w{default default},
+ %w{env_default env_default},
+ %w{role_default role_default},
+ %w{force_default force_default},
+ %w{normal normal},
+ %w{override override},
+ %w{role_override role_override},
+ %w{env_override env_override},
+ %w{force_override force_override},
+ %w{automatic automatic},
]
expect(@attributes.debug_value(:foo, :bar)).to eq(expected)
end
@@ -354,13 +314,13 @@ describe Chef::Node::Attribute do
it "merges nested hashes between precedence levels" do
@attributes = Chef::Node::Attribute.new({}, {}, {}, {})
- @attributes.env_default = {"a" => {"b" => {"default" => "default"}}}
- @attributes.normal = {"a" => {"b" => {"normal" => "normal"}}}
- @attributes.override = {"a" => {"override" => "role"}}
- @attributes.automatic = {"a" => {"automatic" => "auto"}}
- expect(@attributes["a"]).to eq({"b"=>{"default"=>"default", "normal"=>"normal"},
- "override"=>"role",
- "automatic"=>"auto"})
+ @attributes.env_default = { "a" => { "b" => { "default" => "default" } } }
+ @attributes.normal = { "a" => { "b" => { "normal" => "normal" } } }
+ @attributes.override = { "a" => { "override" => "role" } }
+ @attributes.automatic = { "a" => { "automatic" => "auto" } }
+ expect(@attributes["a"]).to eq({ "b" => { "default" => "default", "normal" => "normal" },
+ "override" => "role",
+ "automatic" => "auto" })
end
end
@@ -431,7 +391,7 @@ describe Chef::Node::Attribute do
describe "[]=" do
it "should error out when the type of attribute to set has not been specified" do
- @attributes.normal["the_ghost"] = { }
+ @attributes.normal["the_ghost"] = {}
expect { @attributes["the_ghost"]["exterminate"] = false }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
end
@@ -452,7 +412,7 @@ describe Chef::Node::Attribute do
end
it "should die if you try and do nested attributes that do not exist without read vivification" do
- expect { @attributes["foo"]["bar"] = :baz }.to raise_error
+ expect { @attributes["foo"]["bar"] = :baz }.to raise_error(NoMethodError)
end
it "should let you set attributes manually without vivification" do
@@ -461,12 +421,6 @@ describe Chef::Node::Attribute do
expect(@attributes.normal["foo"]["bar"]).to eq(:baz)
end
- it "should optionally skip setting the value if one already exists" do
- @attributes.set_unless_value_present = true
- @attributes.normal["hostname"] = "bar"
- expect(@attributes["hostname"]).to eq("latte")
- end
-
it "does not support ||= when setting" do
# This is a limitation of auto-vivification.
# Users who need this behavior can use set_unless and friends
@@ -488,37 +442,37 @@ describe Chef::Node::Attribute do
end
it "should create a deep copy of the node attribute" do
- @attributes.default['foo']['bar']['baz'] = 'fizz'
- hash = @attributes['foo'].to_hash
- expect(hash).to eql({"bar"=>{"baz"=>"fizz"}})
- hash['bar']['baz'] = 'buzz'
- expect(hash).to eql({"bar"=>{"baz"=>"buzz"}})
- expect(@attributes.default['foo']).to eql({"bar"=>{"baz"=>"fizz"}})
+ @attributes.default["foo"]["bar"]["baz"] = "fizz"
+ hash = @attributes["foo"].to_hash
+ expect(hash).to eql({ "bar" => { "baz" => "fizz" } })
+ hash["bar"]["baz"] = "buzz"
+ expect(hash).to eql({ "bar" => { "baz" => "buzz" } })
+ expect(@attributes.default["foo"]).to eql({ "bar" => { "baz" => "fizz" } })
end
it "should create a deep copy of arrays in the node attribute" do
- @attributes.default['foo']['bar'] = ['fizz']
- hash = @attributes['foo'].to_hash
- expect(hash).to eql({"bar"=>[ 'fizz' ]})
- hash['bar'].push('buzz')
- expect(hash).to eql({"bar"=>[ 'fizz', 'buzz' ]})
- expect(@attributes.default['foo']).to eql({"bar"=>[ 'fizz' ]})
+ @attributes.default["foo"]["bar"] = ["fizz"]
+ hash = @attributes["foo"].to_hash
+ expect(hash).to eql({ "bar" => [ "fizz" ] })
+ hash["bar"].push("buzz")
+ expect(hash).to eql({ "bar" => %w{fizz buzz} })
+ expect(@attributes.default["foo"]).to eql({ "bar" => [ "fizz" ] })
end
it "mutating strings should not mutate the attributes" do
pending "this is a bug that should be fixed"
- @attributes.default['foo']['bar']['baz'] = 'fizz'
- hash = @attributes['foo'].to_hash
- expect(hash).to eql({"bar"=>{"baz"=>"fizz"}})
- hash['bar']['baz'] << 'buzz'
- expect(hash).to eql({"bar"=>{"baz"=>"fizzbuzz"}})
- expect(@attributes.default['foo']).to eql({"bar"=>{"baz"=>"fizz"}})
+ @attributes.default["foo"]["bar"]["baz"] = "fizz"
+ hash = @attributes["foo"].to_hash
+ expect(hash).to eql({ "bar" => { "baz" => "fizz" } })
+ hash["bar"]["baz"] << "buzz"
+ expect(hash).to eql({ "bar" => { "baz" => "fizzbuzz" } })
+ expect(@attributes.default["foo"]).to eql({ "bar" => { "baz" => "fizz" } })
end
end
describe "dup" do
it "array can be duped even if some elements can't" do
- @attributes.default[:foo] = %w[foo bar baz] + Array(1..3) + [nil, true, false, [ "el", 0, nil ] ]
+ @attributes.default[:foo] = %w{foo bar baz} + Array(1..3) + [nil, true, false, [ "el", 0, nil ] ]
@attributes.default[:foo].dup
end
end
@@ -537,6 +491,7 @@ describe Chef::Node::Attribute do
end
it "should return true if an attribute exists but is set to nil using dot notation" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
expect(@attributes.music.deeper.has_key?("gates_of_ishtar")).to eq(true)
end
@@ -577,12 +532,14 @@ describe Chef::Node::Attribute do
describe "method_missing" do
it "should behave like a [] lookup" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
expect(@attributes.music.mastodon).to eq("rocks")
end
it "should allow the last method to set a value if it has an = sign on the end" do
- @attributes.normal.music.mastodon = [ "dream", "still", "shining" ]
- expect(@attributes.normal.music.mastodon).to eq([ "dream", "still", "shining" ])
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ @attributes.normal.music.mastodon = %w{dream still shining}
+ expect(@attributes.normal.music.mastodon).to eq(%w{dream still shining})
end
end
@@ -592,15 +549,15 @@ describe Chef::Node::Attribute do
{
"one" => { "two" => "three" },
"hut" => { "two" => "three" },
- "place" => { }
+ "place" => {},
},
{
- "one" => { "four" => "five" },
- "snakes" => "on a plane"
+ "one" => { "four" => "five" },
+ "snakes" => "on a plane",
},
{
- "one" => { "six" => "seven" },
- "snack" => "cookies"
+ "one" => { "six" => "seven" },
+ "snack" => "cookies",
},
{}
)
@@ -621,7 +578,7 @@ describe Chef::Node::Attribute do
it "should yield lower if we go deeper" do
collect = Array.new
- @attributes.one.keys.each do |k|
+ @attributes["one"].keys.each do |k|
collect << k
end
expect(collect.include?("two")).to eq(true)
@@ -631,7 +588,7 @@ describe Chef::Node::Attribute do
end
it "should not raise an exception if one of the hashes has a nil value on a deep lookup" do
- expect { @attributes.place.keys { |k| } }.not_to raise_error
+ expect { @attributes["place"].keys { |k| } }.not_to raise_error
end
end
@@ -644,11 +601,11 @@ describe Chef::Node::Attribute do
},
{
"one" => "four",
- "snakes" => "on a plane"
+ "snakes" => "on a plane",
},
{
"one" => "six",
- "snack" => "cookies"
+ "snack" => "cookies",
},
{}
)
@@ -682,11 +639,11 @@ describe Chef::Node::Attribute do
},
{
"one" => "four",
- "snakes" => "on a plane"
+ "snakes" => "on a plane",
},
{
"one" => "six",
- "snack" => "cookies"
+ "snack" => "cookies",
},
{}
)
@@ -718,11 +675,11 @@ describe Chef::Node::Attribute do
},
{
"one" => "four",
- "snakes" => "on a plane"
+ "snakes" => "on a plane",
},
{
"one" => "six",
- "snack" => "cookies"
+ "snack" => "cookies",
},
{}
)
@@ -754,11 +711,11 @@ describe Chef::Node::Attribute do
},
{
"one" => "four",
- "snakes" => "on a plane"
+ "snakes" => "on a plane",
},
{
"one" => "six",
- "snack" => "cookies"
+ "snack" => "cookies",
},
{}
)
@@ -798,11 +755,11 @@ describe Chef::Node::Attribute do
},
{
"one" => "four",
- "snakes" => "on a plane"
+ "snakes" => "on a plane",
},
{
"one" => "six",
- "snack" => "cookies"
+ "snack" => "cookies",
},
{}
)
@@ -832,11 +789,11 @@ describe Chef::Node::Attribute do
},
{
"one" => "four",
- "snakes" => "on a plane"
+ "snakes" => "on a plane",
},
{
"one" => "six",
- "snack" => "cookies"
+ "snack" => "cookies",
},
{}
)
@@ -852,8 +809,8 @@ describe Chef::Node::Attribute do
"one" => "six",
"hut" => "three",
"snakes" => "on a plane",
- "snack" => "cookies"
- }.each do |k,v|
+ "snack" => "cookies",
+ }.each do |k, v|
expect(@attributes.fetch(k)).to eq(v)
end
end
@@ -889,11 +846,11 @@ describe Chef::Node::Attribute do
},
{
"one" => "four",
- "snakes" => "on a plane"
+ "snakes" => "on a plane",
},
{
"one" => "six",
- "snack" => "cookies"
+ "snack" => "cookies",
},
{}
)
@@ -934,11 +891,11 @@ describe Chef::Node::Attribute do
},
{
"one" => "four",
- "snakes" => "on a plane"
+ "snakes" => "on a plane",
},
{
"one" => "six",
- "snack" => "cookies"
+ "snack" => "cookies",
},
{}
)
@@ -975,11 +932,11 @@ describe Chef::Node::Attribute do
},
{
"one" => "four",
- "snakes" => "on a plane"
+ "snakes" => "on a plane",
},
{
"one" => "six",
- "snack" => "cookies"
+ "snack" => "cookies",
},
{}
)
@@ -1011,11 +968,11 @@ describe Chef::Node::Attribute do
},
{
"one" => "four",
- "snakes" => "on a plane"
+ "snakes" => "on a plane",
},
{
"one" => "six",
- "snack" => "cookies"
+ "snack" => "cookies",
},
{}
)
@@ -1031,7 +988,7 @@ describe Chef::Node::Attribute do
end
else
it "should raise a LocalJumpError if no block is given" do
- expect{ @attributes.select }.to raise_error(LocalJumpError)
+ expect { @attributes.select }.to raise_error(LocalJumpError)
end
end
@@ -1043,10 +1000,10 @@ describe Chef::Node::Attribute do
it "should return a new array of k,v pairs for which the block returns true" do
expect(@attributes.select { true }.sort).to eq(
[
- ["hut", "three"],
- ["one", "six"],
- ["snack", "cookies"],
- ["snakes", "on a plane"]
+ %w{hut three},
+ %w{one six},
+ %w{snack cookies},
+ ["snakes", "on a plane"],
]
)
end
@@ -1061,16 +1018,16 @@ describe Chef::Node::Attribute do
},
{
"one" => "four",
- "snakes" => "on a plane"
+ "snakes" => "on a plane",
},
{
"one" => "six",
- "snack" => "cookies"
+ "snack" => "cookies",
},
{}
)
- @empty = Chef::Node::Attribute.new({},{},{},{})
+ @empty = Chef::Node::Attribute.new({}, {}, {}, {})
end
it "should respond to size" do
@@ -1117,11 +1074,11 @@ describe Chef::Node::Attribute do
it "should output merged attributes" do
default_hash = {
"a" => 1,
- "b" => 2
+ "b" => 2,
}
override_hash = {
"b" => 3,
- "c" => 4
+ "c" => 4,
}
attributes = Chef::Node::Attribute.new(nil, default_hash, override_hash, nil)
expect(attributes.to_s).to eq('{"a"=>1, "b"=>3, "c"=>4}')
@@ -1138,7 +1095,6 @@ describe Chef::Node::Attribute do
end
end
-
describe "when not mutated" do
it "does not reset the cache when dup'd [CHEF-3680]" do
@@ -1216,9 +1172,73 @@ describe Chef::Node::Attribute do
end
it "raises an error when using `attr=value`" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
expect { @attributes.new_key = "new value" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
end
+ end
+ describe "deeply converting values" do
+ it "converts values through an array" do
+ @attributes.default[:foo] = [ { bar: true } ]
+ expect(@attributes["foo"].class).to eql(Chef::Node::ImmutableArray)
+ expect(@attributes["foo"][0].class).to eql(Chef::Node::ImmutableMash)
+ expect(@attributes["foo"][0]["bar"]).to be true
+ end
+
+ it "converts values through nested arrays" do
+ @attributes.default[:foo] = [ [ { bar: true } ] ]
+ expect(@attributes["foo"].class).to eql(Chef::Node::ImmutableArray)
+ expect(@attributes["foo"][0].class).to eql(Chef::Node::ImmutableArray)
+ expect(@attributes["foo"][0][0].class).to eql(Chef::Node::ImmutableMash)
+ expect(@attributes["foo"][0][0]["bar"]).to be true
+ end
+
+ it "converts values through nested hashes" do
+ @attributes.default[:foo] = { baz: { bar: true } }
+ expect(@attributes["foo"].class).to eql(Chef::Node::ImmutableMash)
+ expect(@attributes["foo"]["baz"].class).to eql(Chef::Node::ImmutableMash)
+ expect(@attributes["foo"]["baz"]["bar"]).to be true
+ end
end
+ describe "node state" do
+ it "sets __root__ correctly" do
+ @attributes.default["foo"]["bar"]["baz"] = "quux"
+ expect(@attributes["foo"].__root__).to eql(@attributes)
+ expect(@attributes["foo"]["bar"].__root__).to eql(@attributes)
+ expect(@attributes.default["foo"].__root__).to eql(@attributes)
+ expect(@attributes.default["foo"]["bar"].__root__).to eql(@attributes)
+ end
+
+ it "sets __node__ correctly" do
+ @attributes.default["foo"]["bar"]["baz"] = "quux"
+ expect(@attributes["foo"].__node__).to eql(node)
+ expect(@attributes["foo"]["bar"].__node__).to eql(node)
+ expect(@attributes.default["foo"].__node__).to eql(node)
+ expect(@attributes.default["foo"]["bar"].__node__).to eql(node)
+ end
+
+ it "sets __path__ correctly" do
+ @attributes.default["foo"]["bar"]["baz"] = "quux"
+ expect(@attributes["foo"].__path__).to eql(["foo"])
+ expect(@attributes["foo"]["bar"].__path__).to eql(%w{foo bar})
+ expect(@attributes.default["foo"].__path__).to eql(["foo"])
+ expect(@attributes.default["foo"]["bar"].__path__).to eql(%w{foo bar})
+ end
+
+ it "sets __precedence__ correctly" do
+ @attributes.default["foo"]["bar"]["baz"] = "quux"
+ expect(@attributes["foo"].__precedence__).to eql(:merged)
+ expect(@attributes["foo"]["bar"].__precedence__).to eql(:merged)
+ expect(@attributes.default["foo"].__precedence__).to eql(:default)
+ expect(@attributes.default["foo"]["bar"].__precedence__).to eql(:default)
+ end
+
+ it "notifies on attribute changes" do
+ expect(events).to receive(:attribute_changed).with(:default, ["foo"], {})
+ expect(events).to receive(:attribute_changed).with(:default, %w{foo bar}, {})
+ expect(events).to receive(:attribute_changed).with(:default, %w{foo bar baz}, "quux")
+ @attributes.default["foo"]["bar"]["baz"] = "quux"
+ end
+ end
end
diff --git a/spec/unit/node/immutable_collections_spec.rb b/spec/unit/node/immutable_collections_spec.rb
index d0ec81c7f7..81dd771df3 100644
--- a/spec/unit/node/immutable_collections_spec.rb
+++ b/spec/unit/node/immutable_collections_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
require "chef/node/immutable_collections"
describe Chef::Node::ImmutableMash do
before do
- @data_in = {:top => {:second_level => "some value"},
- "top_level_2" => %w[array of values],
- :top_level_3 => [{:hash_array => 1, :hash_array_b => 2}],
- :top_level_4 => {:level2 => {:key => "value"}}
+ @data_in = { :top => { :second_level => "some value" },
+ "top_level_2" => %w{array of values},
+ :top_level_3 => [{ :hash_array => 1, :hash_array_b => 2 }],
+ :top_level_4 => { :level2 => { :key => "value" } },
}
@immutable_mash = Chef::Node::ImmutableMash.new(@data_in)
end
@@ -34,7 +34,7 @@ describe Chef::Node::ImmutableMash do
end
it "element references like a regular Mash" do
- expect(@immutable_mash[:top_level_2]).to eq(%w[array of values])
+ expect(@immutable_mash[:top_level_2]).to eq(%w{array of values})
end
it "converts Hash-like inputs into ImmutableMash's" do
@@ -64,19 +64,19 @@ describe Chef::Node::ImmutableMash do
end
it "converts an immutable nested mash to a new mutable hash" do
- expect(@copy['top_level_4']['level2']).to be_instance_of(Hash)
+ expect(@copy["top_level_4"]["level2"]).to be_instance_of(Hash)
end
it "converts an immutable nested array to a new mutable array" do
- expect(@copy['top_level_2']).to be_instance_of(Array)
+ expect(@copy["top_level_2"]).to be_instance_of(Array)
end
it "should create a mash with the same content" do
expect(@copy).to eq(@immutable_mash)
end
- it 'should allow mutation' do
- expect { @copy['m'] = 'm' }.not_to raise_error
+ it "should allow mutation" do
+ expect { @copy["m"] = "m" }.not_to raise_error
end
end
@@ -94,10 +94,14 @@ describe Chef::Node::ImmutableMash do
:reject!,
:replace,
:select!,
- :shift
+ :shift,
+ :write,
+ :write!,
+ :unlink,
+ :unlink!,
].each do |mutator|
it "doesn't allow mutation via `#{mutator}'" do
- expect { @immutable_mash.send(mutator) }.to raise_error
+ expect { @immutable_mash.send(mutator) }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
end
end
@@ -112,9 +116,9 @@ end
describe Chef::Node::ImmutableArray do
before do
- @immutable_array = Chef::Node::ImmutableArray.new(%w[foo bar baz] + Array(1..3) + [nil, true, false, [ "el", 0, nil ] ])
- immutable_mash = Chef::Node::ImmutableMash.new({:m => 'm'})
- @immutable_nested_array = Chef::Node::ImmutableArray.new(["level1",@immutable_array, immutable_mash])
+ @immutable_array = Chef::Node::ImmutableArray.new(%w{foo bar baz} + Array(1..3) + [nil, true, false, [ "el", 0, nil ] ])
+ immutable_mash = Chef::Node::ImmutableMash.new({ :m => "m" })
+ @immutable_nested_array = Chef::Node::ImmutableArray.new(["level1", @immutable_array, immutable_mash])
end
##
@@ -151,10 +155,10 @@ describe Chef::Node::ImmutableArray do
:sort!,
:sort_by!,
:uniq!,
- :unshift
+ :unshift,
].each do |mutator|
it "does not allow mutation via `#{mutator}" do
- expect { @immutable_array.send(mutator)}.to raise_error
+ expect { @immutable_array.send(mutator) }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
end
end
@@ -189,10 +193,14 @@ describe Chef::Node::ImmutableArray do
expect(@copy).to eq(@immutable_nested_array)
end
- it 'should allow mutation' do
- expect { @copy << 'm' }.not_to raise_error
+ it "should allow mutation" do
+ expect { @copy << "m" }.not_to raise_error
end
end
+ describe "#[]" do
+ it "works with array slices" do
+ expect(@immutable_array[1, 2]).to eql(%w{bar baz})
+ end
+ end
end
-
diff --git a/spec/unit/node/vivid_mash_spec.rb b/spec/unit/node/vivid_mash_spec.rb
new file mode 100644
index 0000000000..4898c22380
--- /dev/null
+++ b/spec/unit/node/vivid_mash_spec.rb
@@ -0,0 +1,353 @@
+#
+# Copyright:: Copyright 2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/node/attribute_collections"
+
+describe Chef::Node::VividMash do
+ let(:root) { instance_double(Chef::Node::Attribute) }
+
+ let(:vivid) do
+ Chef::Node::VividMash.new(
+ { "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil },
+ root
+ )
+ end
+
+ context "without a root node" do
+ let(:vivid) do
+ Chef::Node::VividMash.new(
+ { "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil }
+ )
+ end
+
+ it "sets the root to the root object" do
+ expect(vivid["one"]["two"].__root__).to eql(vivid)
+ end
+
+ it "does not send reset cache" do
+ # if we setup the expectation here then the object winds up responding to :reset_cache and then it fails...
+ # expect(vivid).not_to receive(:reset_cache)
+ # but even so we expect to blow up here with NoMethodError if we screw up and send :reset_cache to a root VividMash
+ vivid["one"]["foo"] = "bar"
+ end
+ end
+
+ context "#[]" do
+ it "works with array slices" do
+ expect(vivid["array"][1, 2]).to eql([1, 2])
+ end
+ end
+
+ context "#[]=" do
+ it "works with array slices" do
+ vivid["array"][3, 2] = [ 3, 4 ]
+ expect(vivid["array"]).to eql([0, 1, 2, 3, 4])
+ end
+
+ it "deep converts values through arrays" do
+ expect(root).to receive(:reset_cache).with("foo")
+ vivid["foo"] = [ { :bar => true } ]
+ expect(vivid["foo"].class).to eql(Chef::Node::AttrArray)
+ expect(vivid["foo"][0].class).to eql(Chef::Node::VividMash)
+ expect(vivid["foo"][0]["bar"]).to be true
+ end
+
+ it "deep converts values through nested arrays" do
+ expect(root).to receive(:reset_cache).with("foo")
+ vivid["foo"] = [ [ { :bar => true } ] ]
+ expect(vivid["foo"].class).to eql(Chef::Node::AttrArray)
+ expect(vivid["foo"][0].class).to eql(Chef::Node::AttrArray)
+ expect(vivid["foo"][0][0].class).to eql(Chef::Node::VividMash)
+ expect(vivid["foo"][0][0]["bar"]).to be true
+ end
+
+ it "deep converts values through hashes" do
+ expect(root).to receive(:reset_cache).with("foo")
+ vivid["foo"] = { baz: { :bar => true } }
+ expect(vivid["foo"]).to be_an_instance_of(Chef::Node::VividMash)
+ expect(vivid["foo"]["baz"]).to be_an_instance_of(Chef::Node::VividMash)
+ expect(vivid["foo"]["baz"]["bar"]).to be true
+ end
+ end
+
+ context "#read" do
+ before do
+ expect(root).not_to receive(:reset_cache)
+ end
+
+ it "reads hashes deeply" do
+ expect(vivid.read("one", "two", "three")).to eql("four")
+ end
+
+ it "does not trainwreck when hitting hash keys that do not exist" do
+ expect(vivid.read("one", "five", "six")).to eql(nil)
+ end
+
+ it "does not trainwreck when hitting an array with an out of bounds index" do
+ expect(vivid.read("array", 5, "one")).to eql(nil)
+ end
+
+ it "does not trainwreck when hitting an array with a string key" do
+ expect(vivid.read("array", "one", "two")).to eql(nil)
+ end
+
+ it "does not trainwreck when traversing a nil" do
+ expect(vivid.read("nil", "one", "two")).to eql(nil)
+ end
+ end
+
+ context "#exist?" do
+ before do
+ expect(root).not_to receive(:reset_cache)
+ end
+
+ it "true if there's a hash key there" do
+ expect(vivid.exist?("one", "two", "three")).to be true
+ end
+
+ it "true for intermediate hashes" do
+ expect(vivid.exist?("one")).to be true
+ end
+
+ it "true for arrays that exist" do
+ expect(vivid.exist?("array", 1)).to be true
+ end
+
+ it "true when the value of the key is nil" do
+ expect(vivid.exist?("nil")).to be true
+ end
+
+ it "false when attributes don't exist" do
+ expect(vivid.exist?("one", "five", "six")).to be false
+ end
+
+ it "false when traversing a non-container" do
+ expect(vivid.exist?("one", "two", "three", "four")).to be false
+ end
+
+ it "false when an array index does not exist" do
+ expect(vivid.exist?("array", 3)).to be false
+ end
+
+ it "false when traversing a nil" do
+ expect(vivid.exist?("nil", "foo", "bar")).to be false
+ end
+ end
+
+ context "#read!" do
+ before do
+ expect(root).not_to receive(:reset_cache)
+ end
+
+ it "reads hashes deeply" do
+ expect(vivid.read!("one", "two", "three")).to eql("four")
+ end
+
+ it "reads arrays deeply" do
+ expect(vivid.read!("array", 1)).to eql(1)
+ end
+
+ it "throws an exception when attributes do not exist" do
+ expect { vivid.read!("one", "five", "six") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
+ end
+
+ it "throws an exception when traversing a non-container" do
+ expect { vivid.read!("one", "two", "three", "four") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
+ end
+
+ it "throws an exception when an array element does not exist" do
+ expect { vivid.read!("array", 3) }.to raise_error(Chef::Exceptions::NoSuchAttribute)
+ end
+ end
+
+ context "#write" do
+ it "should write into hashes" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("one")
+ vivid.write("one", "five", "six")
+ expect(vivid["one"]["five"]).to eql("six")
+ end
+
+ it "should deeply autovivify" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("one")
+ vivid.write("one", "five", "six", "seven", "eight", "nine", "ten")
+ expect(vivid["one"]["five"]["six"]["seven"]["eight"]["nine"]).to eql("ten")
+ end
+
+ it "should raise an exception if you overwrite an array with a hash" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("array")
+ vivid.write("array", "five", "six")
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => { "five" => "six" }, "nil" => nil })
+ end
+
+ it "should raise an exception if you traverse through an array with a hash" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("array")
+ vivid.write("array", "five", "six", "seven")
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => { "five" => { "six" => "seven" } }, "nil" => nil })
+ end
+
+ it "should raise an exception if you overwrite a string with a hash" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("one")
+ vivid.write("one", "two", "three", "four", "five")
+ expect(vivid).to eql({ "one" => { "two" => { "three" => { "four" => "five" } } }, "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+
+ it "should raise an exception if you traverse through a string with a hash" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("one")
+ vivid.write("one", "two", "three", "four", "five", "six")
+ expect(vivid).to eql({ "one" => { "two" => { "three" => { "four" => { "five" => "six" } } } }, "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+
+ it "should raise an exception if you overwrite a nil with a hash" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("nil")
+ vivid.write("nil", "one", "two")
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => { "one" => "two" } })
+ end
+
+ it "should raise an exception if you traverse through a nil with a hash" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("nil")
+ vivid.write("nil", "one", "two", "three")
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => { "one" => { "two" => "three" } } })
+ end
+
+ it "writes with a block" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("one")
+ vivid.write("one", "five") { "six" }
+ expect(vivid["one"]["five"]).to eql("six")
+ end
+ end
+
+ context "#write!" do
+ it "should write into hashes" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("one")
+ vivid.write!("one", "five", "six")
+ expect(vivid["one"]["five"]).to eql("six")
+ end
+
+ it "should deeply autovivify" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("one")
+ vivid.write!("one", "five", "six", "seven", "eight", "nine", "ten")
+ expect(vivid["one"]["five"]["six"]["seven"]["eight"]["nine"]).to eql("ten")
+ end
+
+ it "should raise an exception if you overwrite an array with a hash" do
+ expect(root).not_to receive(:reset_cache)
+ expect { vivid.write!("array", "five", "six") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+
+ it "should raise an exception if you traverse through an array with a hash" do
+ expect(root).not_to receive(:reset_cache)
+ expect { vivid.write!("array", "five", "six", "seven") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+
+ it "should raise an exception if you overwrite a string with a hash" do
+ expect(root).not_to receive(:reset_cache)
+ expect { vivid.write!("one", "two", "three", "four", "five") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+
+ it "should raise an exception if you traverse through a string with a hash" do
+ expect(root).not_to receive(:reset_cache)
+ expect { vivid.write!("one", "two", "three", "four", "five", "six") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+
+ it "should raise an exception if you overwrite a nil with a hash" do
+ expect(root).not_to receive(:reset_cache)
+ expect { vivid.write!("nil", "one", "two") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+
+ it "should raise an exception if you traverse through a nil with a hash" do
+ expect(root).not_to receive(:reset_cache)
+ expect { vivid.write!("nil", "one", "two", "three") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+
+ it "writes with a block" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("one")
+ vivid.write!("one", "five") { "six" }
+ expect(vivid["one"]["five"]).to eql("six")
+ end
+ end
+
+ context "#unlink" do
+ it "should return nil if the keys don't already exist" do
+ expect(root).not_to receive(:reset_cache)
+ expect(vivid.unlink("five", "six", "seven", "eight")).to eql(nil)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+
+ it "should unlink hashes" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("one")
+ expect( vivid.unlink("one") ).to eql({ "two" => { "three" => "four" } })
+ expect(vivid).to eql({ "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+
+ it "should unlink array elements" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("array")
+ expect(vivid.unlink("array", 2)).to eql(2)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1 ], "nil" => nil })
+ end
+
+ it "should unlink nil" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("nil")
+ expect(vivid.unlink("nil")).to eql(nil)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ] })
+ end
+
+ it "should traverse a nil and safely do nothing" do
+ expect(root).not_to receive(:reset_cache)
+ expect(vivid.unlink("nil", "foo")).to eql(nil)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+ end
+
+ context "#unlink!" do
+ it "should raise an exception if the keys don't already exist" do
+ expect(root).not_to receive(:reset_cache)
+ expect { vivid.unlink!("five", "six", "seven", "eight") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+
+ it "should unlink! hashes" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("one")
+ expect( vivid.unlink!("one") ).to eql({ "two" => { "three" => "four" } })
+ expect(vivid).to eql({ "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+
+ it "should unlink! array elements" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("array")
+ expect(vivid.unlink!("array", 2)).to eql(2)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1 ], "nil" => nil })
+ end
+
+ it "should unlink! nil" do
+ expect(root).to receive(:reset_cache).at_least(:once).with("nil")
+ expect(vivid.unlink!("nil")).to eql(nil)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ] })
+ end
+
+ it "should raise an exception if it traverses a nil" do
+ expect(root).not_to receive(:reset_cache)
+ expect { vivid.unlink!("nil", "foo") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
+ expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
+ end
+ end
+end
diff --git a/spec/unit/node_map_spec.rb b/spec/unit/node_map_spec.rb
index 7b37ea59f4..0480a721af 100644
--- a/spec/unit/node_map_spec.rb
+++ b/spec/unit/node_map_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Lamont Granquist (<lamont@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/node_map'
+require "spec_helper"
+require "chef/node_map"
describe Chef::NodeMap do
@@ -27,7 +27,7 @@ describe Chef::NodeMap do
describe "with a bad filter name" do
it "should raise an error" do
- expect{ node_map.set(node, :thing, on_platform_family: 'rhel') }.to raise_error
+ expect { node_map.set(node, :thing, on_platform_family: "rhel") }.to raise_error(ArgumentError)
end
end
@@ -156,7 +156,7 @@ describe Chef::NodeMap do
expect(node_map.get(node, :chef_gem)).to eql(:foo)
end
it "should handle :on_platforms => [ 'windows' ]" do
- node_map.set(:dsc_script, :foo, :on_platforms => [ 'windows' ])
+ node_map.set(:dsc_script, :foo, :on_platforms => [ "windows" ])
allow(node).to receive(:[]).with(:platform).and_return("windows")
expect(node_map.get(node, :dsc_script)).to eql(:foo)
end
diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb
index 17e085a465..ac227c5479 100644
--- a/spec/unit/node_spec.rb
+++ b/spec/unit/node_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Node do
@@ -27,32 +27,32 @@ describe Chef::Node do
it_behaves_like "a platform introspector"
it "creates a node and assigns it a name" do
- node = Chef::Node.build('solo-node')
- expect(node.name).to eq('solo-node')
+ node = Chef::Node.build("solo-node")
+ expect(node.name).to eq("solo-node")
end
it "should validate the name of the node" do
- expect{Chef::Node.build('solo node')}.to raise_error(Chef::Exceptions::ValidationFailed)
+ expect { Chef::Node.build("solo node") }.to raise_error(Chef::Exceptions::ValidationFailed)
end
it "should be sortable" do
- n1 = Chef::Node.build('alpha')
- n2 = Chef::Node.build('beta')
- n3 = Chef::Node.build('omega')
+ n1 = Chef::Node.build("alpha")
+ n2 = Chef::Node.build("beta")
+ n3 = Chef::Node.build("omega")
expect([n3, n1, n2].sort).to eq([n1, n2, n3])
end
it "should share identity only with others of the same name" do
- n1 = Chef::Node.build('foo')
- n2 = Chef::Node.build('foo')
- n3 = Chef::Node.build('bar')
+ n1 = Chef::Node.build("foo")
+ n2 = Chef::Node.build("foo")
+ n3 = Chef::Node.build("bar")
expect(n1).to eq(n2)
expect(n1).not_to eq(n3)
end
describe "when the node does not exist on the server" do
before do
- response = OpenStruct.new(:code => '404')
+ response = OpenStruct.new(:code => "404")
exception = Net::HTTPServerException.new("404 not found", response)
allow(Chef::Node).to receive(:load).and_raise(exception)
node.name("created-node")
@@ -62,19 +62,19 @@ describe Chef::Node do
allow(Chef::Node).to receive(:new).and_return(node)
expect(node).to receive(:create).and_return(node)
node = Chef::Node.find_or_create("created-node")
- expect(node.name).to eq('created-node')
+ expect(node.name).to eq("created-node")
expect(node).to equal(node)
end
end
describe "when the node exists on the server" do
before do
- node.name('existing-node')
+ node.name("existing-node")
allow(Chef::Node).to receive(:load).and_return(node)
end
it "loads the node via the REST API for find_or_create" do
- expect(Chef::Node.find_or_create('existing-node')).to equal(node)
+ expect(Chef::Node.find_or_create("existing-node")).to equal(node)
end
end
@@ -88,7 +88,7 @@ describe Chef::Node do
describe "initialize" do
it "should default to the '_default' chef_environment" do
n = Chef::Node.new
- expect(n.chef_environment).to eq('_default')
+ expect(n.chef_environment).to eq("_default")
end
end
@@ -107,11 +107,11 @@ describe Chef::Node do
end
it "cannot be blank" do
- expect { node.name("")}.to raise_error(Chef::Exceptions::ValidationFailed)
+ expect { node.name("") }.to raise_error(Chef::Exceptions::ValidationFailed)
end
it "should not accept name doesn't match /^[\-[:alnum:]_:.]+$/" do
- expect { node.name("space in it")}.to raise_error(Chef::Exceptions::ValidationFailed)
+ expect { node.name("space in it") }.to raise_error(Chef::Exceptions::ValidationFailed)
end
end
@@ -131,7 +131,7 @@ describe Chef::Node do
end
it "cannot be blank" do
- expect { node.chef_environment("")}.to raise_error(Chef::Exceptions::ValidationFailed)
+ expect { node.chef_environment("") }.to raise_error(Chef::Exceptions::ValidationFailed)
end
end
@@ -147,7 +147,7 @@ describe Chef::Node do
end
it "allows policy_name with every valid character" do
- expect { node.policy_name = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqurstuvwxyz0123456789-_:.' }.to_not raise_error
+ expect { node.policy_name = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqurstuvwxyz0123456789-_:." }.to_not raise_error
end
it "sets policy_name when given an argument" do
@@ -167,7 +167,7 @@ describe Chef::Node do
end
it "cannot be blank" do
- expect { node.policy_name("")}.to raise_error(Chef::Exceptions::ValidationFailed)
+ expect { node.policy_name("") }.to raise_error(Chef::Exceptions::ValidationFailed)
end
end
@@ -183,7 +183,7 @@ describe Chef::Node do
end
it "allows policy_group with every valid character" do
- expect { node.policy_group = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqurstuvwxyz0123456789-_:.' }.to_not raise_error
+ expect { node.policy_group = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqurstuvwxyz0123456789-_:." }.to_not raise_error
end
it "sets an environment with chef_environment(something)" do
@@ -203,7 +203,7 @@ describe Chef::Node do
end
it "cannot be blank" do
- expect { node.policy_group("")}.to raise_error(Chef::Exceptions::ValidationFailed)
+ expect { node.policy_group("") }.to raise_error(Chef::Exceptions::ValidationFailed)
end
end
@@ -223,7 +223,7 @@ describe Chef::Node do
end
it "does not allow you to set an attribute via node[]=" do
- expect { node["secret"] = "shush" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+ expect { node["secret"] = "shush" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
end
it "should allow you to query whether an attribute exists with attribute?" do
@@ -233,61 +233,139 @@ describe Chef::Node do
end
it "should let you go deep with attribute?" do
- node.set["battles"]["people"]["wonkey"] = true
+ node.normal["battles"]["people"]["wonkey"] = true
expect(node["battles"]["people"].attribute?("wonkey")).to eq(true)
expect(node["battles"]["people"].attribute?("snozzberry")).to eq(false)
end
it "does not allow you to set an attribute via method_missing" do
- expect { node.sunshine = "is bright"}.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect { node.sunshine = "is bright" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+ end
+
+ it "does not allow modification of node attributes via hash methods" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.default["h4sh"] = { foo: "bar" }
+ expect { node["h4sh"].delete("foo") }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+ expect { node.h4sh.delete("foo") }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+ end
+
+ it "does not allow modification of node attributes via array methods" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.default["array"] = []
+ expect { node["array"] << "boom" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+ expect { node.array << "boom" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+ end
+
+ it "returns merged immutable attributes for arrays" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.default["array"] = []
+ expect( node["array"].class ).to eql(Chef::Node::ImmutableArray)
+ expect( node.array.class ).to eql(Chef::Node::ImmutableArray)
+ end
+
+ it "returns merged immutable attributes for hashes" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.default["h4sh"] = {}
+ expect( node["h4sh"].class ).to eql(Chef::Node::ImmutableMash)
+ expect( node.h4sh.class ).to eql(Chef::Node::ImmutableMash)
end
it "should allow you get get an attribute via method_missing" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
node.default.sunshine = "is bright"
expect(node.sunshine).to eql("is bright")
end
describe "normal attributes" do
it "should allow you to set an attribute with set, without pre-declaring a hash" do
- node.set[:snoopy][:is_a_puppy] = true
+ node.normal[:snoopy][:is_a_puppy] = true
expect(node[:snoopy][:is_a_puppy]).to eq(true)
end
+ it "should allow you to set an attribute with set_unless with method_missing but emit a deprecation warning" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.normal_unless.snoopy.is_a_puppy = false
+ expect(node[:snoopy][:is_a_puppy]).to eq(false)
+ end
+
it "should allow you to set an attribute with set_unless" do
- node.set_unless[:snoopy][:is_a_puppy] = false
+ node.normal_unless[:snoopy][:is_a_puppy] = false
expect(node[:snoopy][:is_a_puppy]).to eq(false)
end
it "should not allow you to set an attribute with set_unless if it already exists" do
- node.set[:snoopy][:is_a_puppy] = true
- node.set_unless[:snoopy][:is_a_puppy] = false
+ node.normal[:snoopy][:is_a_puppy] = true
+ node.normal_unless[:snoopy][:is_a_puppy] = false
expect(node[:snoopy][:is_a_puppy]).to eq(true)
end
+ it "should allow you to set an attribute with set_unless if is a nil value" do
+ node.attributes.normal = { snoopy: { is_a_puppy: nil } }
+ node.normal_unless[:snoopy][:is_a_puppy] = false
+ expect(node[:snoopy][:is_a_puppy]).to eq(false)
+ end
+
it "should allow you to set a value after a set_unless" do
# this tests for set_unless_present state bleeding between statements CHEF-3806
- node.set_unless[:snoopy][:is_a_puppy] = false
- node.set[:snoopy][:is_a_puppy] = true
+ node.normal_unless[:snoopy][:is_a_puppy] = false
+ node.normal[:snoopy][:is_a_puppy] = true
expect(node[:snoopy][:is_a_puppy]).to eq(true)
end
it "should let you set a value after a 'dangling' set_unless" do
# this tests for set_unless_present state bleeding between statements CHEF-3806
- node.set[:snoopy][:is_a_puppy] = "what"
- node.set_unless[:snoopy][:is_a_puppy]
- node.set[:snoopy][:is_a_puppy] = true
+ node.normal[:snoopy][:is_a_puppy] = "what"
+ node.normal_unless[:snoopy][:is_a_puppy]
+ node.normal[:snoopy][:is_a_puppy] = true
expect(node[:snoopy][:is_a_puppy]).to eq(true)
end
it "auto-vivifies attributes created via method syntax" do
- node.set.fuu.bahrr.baz = "qux"
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.normal.fuu.bahrr.baz = "qux"
expect(node.fuu.bahrr.baz).to eq("qux")
end
it "should let you use tag as a convience method for the tags attribute" do
- node.normal['tags'] = ['one', 'two']
- node.tag('three', 'four')
- expect(node['tags']).to eq(['one', 'two', 'three', 'four'])
+ node.normal["tags"] = %w{one two}
+ node.tag("three", "four")
+ expect(node["tags"]).to eq(%w{one two three four})
+ end
+
+ it "set is a deprecated alias for normal" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(Chef).to receive(:deprecated).with(:attributes, /set is deprecated/)
+ node.set[:snoopy][:is_a_puppy] = true
+ expect(node.normal[:snoopy][:is_a_puppy]).to eq(true)
+ end
+
+ it "set_unless is a deprecated alias for normal_unless" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(Chef).to receive(:deprecated).with(:attributes, /set_unless is deprecated/)
+ node.set_unless[:snoopy][:is_a_puppy] = false
+ expect(node.normal[:snoopy][:is_a_puppy]).to eq(false)
+ end
+
+ it "normal_unless sets a value even if default or override attrs are set" do
+ node.default[:decontamination] = true
+ node.override[:decontamination] = false
+ node.normal_unless[:decontamination] = "foo"
+ expect(node.normal[:decontamination]).to eql("foo")
+ end
+
+ it "default_unless sets a value even if normal or override attrs are set" do
+ node.normal[:decontamination] = true
+ node.override[:decontamination] = false
+ node.default_unless[:decontamination] = "foo"
+ expect(node.default[:decontamination]).to eql("foo")
+ end
+
+ it "override_unless sets a value even if default or normal attrs are set" do
+ node.default[:decontamination] = true
+ node.normal[:decontamination] = false
+ node.override_unless[:decontamination] = "foo"
+ expect(node.override[:decontamination]).to eql("foo")
end
end
@@ -323,10 +401,41 @@ describe Chef::Node do
expect(node[:snoopy][:is_a_puppy]).to eq(true)
end
+ it "does not exhibit chef/chef/issues/5005 bug" do
+ node.env_default["a"]["r1"]["g"]["u"] = "u1"
+ node.default_unless["a"]["r1"]["g"]["r"] = "r"
+ expect(node["a"]["r1"]["g"]["u"]).to eql("u1")
+ end
+
it "auto-vivifies attributes created via method syntax" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
node.default.fuu.bahrr.baz = "qux"
expect(node.fuu.bahrr.baz).to eq("qux")
end
+
+ it "default_unless correctly resets the deep merge cache" do
+ node.normal["tags"] = [] # this sets our top-level breadcrumb
+ node.default_unless["foo"]["bar"] = "NK-19V"
+ expect(node["foo"]["bar"]).to eql("NK-19V")
+ node.default_unless["foo"]["baz"] = "NK-33"
+ expect(node["foo"]["baz"]).to eql("NK-33")
+ end
+
+ it "normal_unless correctly resets the deep merge cache" do
+ node.normal["tags"] = [] # this sets our top-level breadcrumb
+ node.normal_unless["foo"]["bar"] = "NK-19V"
+ expect(node["foo"]["bar"]).to eql("NK-19V")
+ node.normal_unless["foo"]["baz"] = "NK-33"
+ expect(node["foo"]["baz"]).to eql("NK-33")
+ end
+
+ it "override_unless correctly resets the deep merge cache" do
+ node.normal["tags"] = [] # this sets our top-level breadcrumb
+ node.override_unless["foo"]["bar"] = "NK-19V"
+ expect(node["foo"]["bar"]).to eql("NK-19V")
+ node.override_unless["foo"]["baz"] = "NK-33"
+ expect(node["foo"]["baz"]).to eql("NK-33")
+ end
end
describe "override attributes" do
@@ -362,6 +471,7 @@ describe Chef::Node do
end
it "auto-vivifies attributes created via method syntax" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
node.override.fuu.bahrr.baz = "qux"
expect(node.fuu.bahrr.baz).to eq("qux")
end
@@ -383,7 +493,7 @@ describe Chef::Node do
it "deletes nested things correctly" do
node.default["mysql"]["client"]["client_setting"] = "foo"
- expect( node.rm("mysql", "server") ).to eql( {"port" => 3456} )
+ expect( node.rm("mysql", "server") ).to eql( { "port" => 3456 } )
expect( node["mysql"] ).to eql( { "client" => { "client_setting" => "foo" } } )
end
@@ -392,7 +502,7 @@ describe Chef::Node do
end
it "can delete the entire tree" do
- expect( node.rm("mysql") ).to eql({"server"=>{"port"=>3456}})
+ expect( node.rm("mysql") ).to eql({ "server" => { "port" => 3456 } })
end
end
@@ -447,8 +557,9 @@ describe Chef::Node do
expect( node["mysql"]["server"][0]["port"] ).to be_nil
end
- it "does not have a horrible error message when mistaking arrays for hashes" do
- expect { node.rm("mysql", "server", "port") }.to raise_error(TypeError, "Wrong type in index of attribute (did you use a Hash index on an Array?)")
+ it "when mistaking arrays for hashes, it considers the value removed and does nothing" do
+ node.rm("mysql", "server", "port")
+ expect(node["mysql"]["server"][0]["port"]).to eql(3456)
end
end
end
@@ -694,35 +805,38 @@ describe Chef::Node do
# In Chef-12.0 there is a deep_merge cache on the top level attribute which had a bug
# where it cached node[:foo] separate from node['foo']. These tests exercise those edge conditions.
#
- # https://github.com/opscode/chef/issues/2700
- # https://github.com/opscode/chef/issues/2712
- # https://github.com/opscode/chef/issues/2745
+ # https://github.com/chef/chef/issues/2700
+ # https://github.com/chef/chef/issues/2712
+ # https://github.com/chef/chef/issues/2745
#
describe "deep merge attribute cache edge conditions" do
it "does not error with complicated attribute substitution" do
- node.default['chef_attribute_hell']['attr1'] = "attribute1"
- node.default['chef_attribute_hell']['attr2'] = "#{node.chef_attribute_hell.attr1}/attr2"
- expect { node.default['chef_attribute_hell']['attr3'] = "#{node.chef_attribute_hell.attr2}/attr3" }.not_to raise_error
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.default["chef_attribute_hell"]["attr1"] = "attribute1"
+ node.default["chef_attribute_hell"]["attr2"] = "#{node.chef_attribute_hell.attr1}/attr2"
+ expect { node.default["chef_attribute_hell"]["attr3"] = "#{node.chef_attribute_hell.attr2}/attr3" }.not_to raise_error
end
it "caches both strings and symbols correctly" do
- node.force_default[:solr][:version] = '4.10.2'
+ node.force_default[:solr][:version] = "4.10.2"
node.force_default[:solr][:data_dir] = "/opt/solr-#{node['solr'][:version]}/example/solr"
node.force_default[:solr][:xms] = "512M"
expect(node[:solr][:xms]).to eql("512M")
- expect(node['solr'][:xms]).to eql("512M")
+ expect(node["solr"][:xms]).to eql("512M")
end
it "method interpolation syntax also works" do
- node.default['passenger']['version'] = '4.0.57'
- node.default['passenger']['root_path'] = "passenger-#{node['passenger']['version']}"
- node.default['passenger']['root_path_2'] = "passenger-#{node.passenger['version']}"
- expect(node['passenger']['root_path_2']).to eql("passenger-4.0.57")
- expect(node[:passenger]['root_path_2']).to eql("passenger-4.0.57")
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.default["passenger"]["version"] = "4.0.57"
+ node.default["passenger"]["root_path"] = "passenger-#{node['passenger']['version']}"
+ node.default["passenger"]["root_path_2"] = "passenger-#{node.passenger['version']}"
+ expect(node["passenger"]["root_path_2"]).to eql("passenger-4.0.57")
+ expect(node[:passenger]["root_path_2"]).to eql("passenger-4.0.57")
end
end
it "should raise an ArgumentError if you ask for an attribute that doesn't exist via method_missing" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
expect { node.sunshine }.to raise_error(NoMethodError)
end
@@ -730,7 +844,7 @@ describe Chef::Node do
node.default.sunshine = "is bright"
node.default.canada = "is a nice place"
seen_attributes = Hash.new
- node.each_attribute do |a,v|
+ node.each_attribute do |a, v|
seen_attributes[a] = v
end
expect(seen_attributes).to have_key("sunshine")
@@ -738,17 +852,62 @@ describe Chef::Node do
expect(seen_attributes["sunshine"]).to eq("is bright")
expect(seen_attributes["canada"]).to eq("is a nice place")
end
+
+ describe "functional attribute API" do
+ # deeper functional testing of this API is in the VividMash spec tests
+ it "should have an exist? function" do
+ node.default["foo"]["bar"] = "baz"
+ expect(node.exist?("foo", "bar")).to be true
+ expect(node.exist?("bar", "foo")).to be false
+ end
+
+ it "should have a read function" do
+ node.override["foo"]["bar"] = "baz"
+ expect(node.read("foo", "bar")).to eql("baz")
+ expect(node.read("bar", "foo")).to eql(nil)
+ end
+
+ it "should have a read! function" do
+ node.override["foo"]["bar"] = "baz"
+ expect(node.read!("foo", "bar")).to eql("baz")
+ expect { node.read!("bar", "foo") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
+ end
+
+ it "delegates write(:level) to node.level.write()" do
+ node.write(:default, "foo", "bar", "baz")
+ expect(node.default["foo"]["bar"]).to eql("baz")
+ end
+
+ it "delegates write!(:level) to node.level.write!()" do
+ node.write!(:default, "foo", "bar", "baz")
+ expect(node.default["foo"]["bar"]).to eql("baz")
+ node.default["bar"] = true
+ expect { node.write!(:default, "bar", "foo", "baz") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
+ end
+
+ it "delegates unlink(:level) to node.level.unlink()" do
+ node.default["foo"]["bar"] = "baz"
+ expect(node.unlink(:default, "foo", "bar")).to eql("baz")
+ expect(node.unlink(:default, "bar", "foo")).to eql(nil)
+ end
+
+ it "delegates unlink!(:level) to node.level.unlink!()" do
+ node.default["foo"]["bar"] = "baz"
+ expect(node.unlink!(:default, "foo", "bar")).to eql("baz")
+ expect { node.unlink!(:default, "bar", "foo") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
+ end
+ end
end
describe "consuming json" do
before do
- @ohai_data = {:platform => 'foo', :platform_version => 'bar'}
+ @ohai_data = { :platform => "foo", :platform_version => "bar" }
end
it "consumes the run list portion of a collection of attributes and returns the remainder" do
- attrs = {"run_list" => [ "role[base]", "recipe[chef::server]" ], "foo" => "bar"}
- expect(node.consume_run_list(attrs)).to eq({"foo" => "bar"})
+ attrs = { "run_list" => [ "role[base]", "recipe[chef::server]" ], "foo" => "bar" }
+ expect(node.consume_run_list(attrs)).to eq({ "foo" => "bar" })
expect(node.run_list).to eq([ "role[base]", "recipe[chef::server]" ])
end
@@ -756,19 +915,19 @@ describe Chef::Node do
attrs = { "chef_environment" => "foo_environment", "bar" => "baz" }
expect(node.consume_chef_environment(attrs)).to eq({ "bar" => "baz" })
expect(node.chef_environment).to eq("foo_environment")
- expect(node['chef_environment']).to be nil
+ expect(node["chef_environment"]).to be nil
end
it "should overwrites the run list with the run list it consumes" do
- node.consume_run_list "recipes" => [ "one", "two" ]
+ node.consume_run_list "recipes" => %w{one two}
node.consume_run_list "recipes" => [ "three" ]
expect(node.run_list).to eq([ "three" ])
end
it "should not add duplicate recipes from the json attributes" do
node.run_list << "one"
- node.consume_run_list "recipes" => [ "one", "two", "three" ]
- expect(node.run_list).to eq([ "one", "two", "three" ])
+ node.consume_run_list "recipes" => %w{one two three}
+ expect(node.run_list).to eq(%w{one two three})
end
it "doesn't change the run list if no run_list is specified in the json" do
@@ -782,9 +941,9 @@ describe Chef::Node do
end
it "should add json attributes to the node" do
- node.consume_external_attrs(@ohai_data, {"one" => "two", "three" => "four"})
- expect(node.one).to eql("two")
- expect(node.three).to eql("four")
+ node.consume_external_attrs(@ohai_data, { "one" => "two", "three" => "four" })
+ expect(node["one"]).to eql("two")
+ expect(node["three"]).to eql("four")
end
it "should set the tags attribute to an empty array if it is not already defined" do
@@ -793,50 +952,68 @@ describe Chef::Node do
end
it "should not set the tags attribute to an empty array if it is already defined" do
- node.normal[:tags] = [ "radiohead" ]
+ node.tag("radiohead")
node.consume_external_attrs(@ohai_data, {})
expect(node.tags).to eql([ "radiohead" ])
end
+ it "should set the tags attribute to an empty array if it is nil" do
+ node.attributes.normal = { "tags" => nil }
+ node.consume_external_attrs(@ohai_data, {})
+ expect(node.tags).to eql([])
+ end
+
+ it "should return an array if it is fed a string" do
+ node.normal[:tags] = "string"
+ node.consume_external_attrs(@ohai_data, {})
+ expect(node.tags).to eql(["string"])
+ end
+
+ it "should return an array if it is fed a hash" do
+ node.normal[:tags] = {}
+ node.consume_external_attrs(@ohai_data, {})
+ expect(node.tags).to eql([])
+ end
+
it "deep merges attributes instead of overwriting them" do
- node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "four"}})
- expect(node.one.to_hash).to eq({"two" => {"three" => "four"}})
- node.consume_external_attrs(@ohai_data, "one" => {"abc" => "123"})
- node.consume_external_attrs(@ohai_data, "one" => {"two" => {"foo" => "bar"}})
- expect(node.one.to_hash).to eq({"two" => {"three" => "four", "foo" => "bar"}, "abc" => "123"})
+ node.consume_external_attrs(@ohai_data, "one" => { "two" => { "three" => "four" } })
+ expect(node["one"].to_hash).to eq({ "two" => { "three" => "four" } })
+ node.consume_external_attrs(@ohai_data, "one" => { "abc" => "123" })
+ node.consume_external_attrs(@ohai_data, "one" => { "two" => { "foo" => "bar" } })
+ expect(node["one"].to_hash).to eq({ "two" => { "three" => "four", "foo" => "bar" }, "abc" => "123" })
end
it "gives attributes from JSON priority when deep merging" do
- node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "four"}})
- expect(node.one.to_hash).to eq({"two" => {"three" => "four"}})
- node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "forty-two"}})
- expect(node.one.to_hash).to eq({"two" => {"three" => "forty-two"}})
+ node.consume_external_attrs(@ohai_data, "one" => { "two" => { "three" => "four" } })
+ expect(node["one"].to_hash).to eq({ "two" => { "three" => "four" } })
+ node.consume_external_attrs(@ohai_data, "one" => { "two" => { "three" => "forty-two" } })
+ expect(node["one"].to_hash).to eq({ "two" => { "three" => "forty-two" } })
end
end
describe "preparing for a chef client run" do
before do
- @ohai_data = {:platform => 'foobuntu', :platform_version => '23.42'}
+ @ohai_data = { :platform => "foobuntu", :platform_version => "23.42" }
end
it "sets its platform according to platform detection" do
node.consume_external_attrs(@ohai_data, {})
- expect(node.automatic_attrs[:platform]).to eq('foobuntu')
- expect(node.automatic_attrs[:platform_version]).to eq('23.42')
+ expect(node.automatic_attrs[:platform]).to eq("foobuntu")
+ expect(node.automatic_attrs[:platform_version]).to eq("23.42")
end
it "consumes the run list from provided json attributes" do
- node.consume_external_attrs(@ohai_data, {"run_list" => ['recipe[unicorn]']})
- expect(node.run_list).to eq(['recipe[unicorn]'])
+ node.consume_external_attrs(@ohai_data, { "run_list" => ["recipe[unicorn]"] })
+ expect(node.run_list).to eq(["recipe[unicorn]"])
end
it "saves non-runlist json attrs for later" do
- expansion = Chef::RunList::RunListExpansion.new('_default', [])
+ expansion = Chef::RunList::RunListExpansion.new("_default", [])
allow(node.run_list).to receive(:expand).and_return(expansion)
- node.consume_external_attrs(@ohai_data, {"foo" => "bar"})
+ node.consume_external_attrs(@ohai_data, { "foo" => "bar" })
node.expand!
- expect(node.normal_attrs).to eq({"foo" => "bar", "tags" => []})
+ expect(node.normal_attrs).to eq({ "foo" => "bar", "tags" => [] })
end
end
@@ -844,7 +1021,7 @@ describe Chef::Node do
describe "when expanding its run list and merging attributes" do
before do
@environment = Chef::Environment.new.tap do |e|
- e.name('rspec_env')
+ e.name("rspec_env")
e.default_attributes("env default key" => "env default value")
e.override_attributes("env override key" => "env override value")
end
@@ -855,15 +1032,15 @@ describe Chef::Node do
end
it "sets the 'recipes' automatic attribute to the recipes in the expanded run_list" do
- @expansion.recipes << 'recipe[chef::client]' << 'recipe[nginx::default]'
+ @expansion.recipes << "recipe[chef::client]" << "recipe[nginx::default]"
node.expand!
- expect(node.automatic_attrs[:recipes]).to eq(['recipe[chef::client]', 'recipe[nginx::default]'])
+ expect(node.automatic_attrs[:recipes]).to eq(["recipe[chef::client]", "recipe[nginx::default]"])
end
it "sets the 'roles' automatic attribute to the expanded role list" do
- @expansion.instance_variable_set(:@applied_roles, {'arf' => nil, 'countersnark' => nil})
+ @expansion.instance_variable_set(:@applied_roles, { "arf" => nil, "countersnark" => nil })
node.expand!
- expect(node.automatic_attrs[:roles].sort).to eq(['arf', 'countersnark'])
+ expect(node.automatic_attrs[:roles].sort).to eq(%w{arf countersnark})
end
it "applies default attributes from the environment as environment defaults" do
@@ -961,12 +1138,12 @@ describe Chef::Node do
before do
node.chef_environment = "rspec"
@expansion = Chef::RunList::RunListExpansion.new("rspec", [])
- @expansion.default_attrs.replace({:default => "from role", :d_role => "role only"})
- @expansion.override_attrs.replace({:override => "from role", :o_role => "role only"})
+ @expansion.default_attrs.replace({ :default => "from role", :d_role => "role only" })
+ @expansion.override_attrs.replace({ :override => "from role", :o_role => "role only" })
@environment = Chef::Environment.new
- @environment.default_attributes = {:default => "from env", :d_env => "env only" }
- @environment.override_attributes = {:override => "from env", :o_env => "env only"}
+ @environment.default_attributes = { :default => "from env", :d_env => "env only" }
+ @environment.override_attributes = { :override => "from env", :o_env => "env only" }
allow(Chef::Environment).to receive(:load).and_return(@environment)
node.apply_expansion_attributes(@expansion)
end
@@ -1012,10 +1189,10 @@ describe Chef::Node do
end
it "sets attributes from the files" do
- expect(node.ldap_server).to eql("ops1prod")
- expect(node.ldap_basedn).to eql("dc=hjksolutions,dc=com")
- expect(node.ldap_replication_password).to eql("forsure")
- expect(node.smokey).to eql("robinson")
+ expect(node["ldap_server"]).to eql("ops1prod")
+ expect(node["ldap_basedn"]).to eql("dc=hjksolutions,dc=com")
+ expect(node["ldap_replication_password"]).to eql("forsure")
+ expect(node["smokey"]).to eql("robinson")
end
it "gives a sensible error when attempting to load a missing attributes file" do
@@ -1059,8 +1236,8 @@ describe Chef::Node do
it "should load a node from a ruby file" do
node.from_file(File.expand_path(File.join(CHEF_SPEC_DATA, "nodes", "test.rb")))
expect(node.name).to eql("test.example.com-short")
- expect(node.sunshine).to eql("in")
- expect(node.something).to eql("else")
+ expect(node["sunshine"]).to eql("in")
+ expect(node["something"]).to eql("else")
expect(node.run_list).to eq(["operations-master", "operations-monitoring"])
end
@@ -1128,7 +1305,7 @@ describe Chef::Node do
expect(h["chef_environment"]).to eq("dev")
end
- it 'should return an empty array for empty run_list' do
+ it "should return an empty array for empty run_list" do
expect(node.to_hash["run_list"]).to eq([])
end
end
@@ -1146,11 +1323,11 @@ describe Chef::Node do
expect(json).to match(/run_list/)
end
- it 'should serialize valid json with a run list', :json => true do
+ it "should serialize valid json with a run list", :json => true do
#This test came about because activesupport mucks with Chef json serialization
#Test should pass with and without Activesupport
- node.run_list << {"type" => "role", "name" => 'Cthulu'}
- node.run_list << {"type" => "role", "name" => 'Hastur'}
+ node.run_list << { "type" => "role", "name" => "Cthulu" }
+ node.run_list << { "type" => "role", "name" => "Hastur" }
json = Chef::JSONCompat.to_json(node)
expect(json).to match(/\"run_list\":\[\"role\[Cthulu\]\",\"role\[Hastur\]\"\]/)
end
@@ -1183,11 +1360,11 @@ describe Chef::Node do
it "should deserialize itself from json", :json => true do
node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA))
json = Chef::JSONCompat.to_json(node)
- serialized_node = Chef::JSONCompat.from_json(json)
+ serialized_node = Chef::Node.from_hash(Chef::JSONCompat.parse(json))
expect(serialized_node).to be_a_kind_of(Chef::Node)
expect(serialized_node.name).to eql(node.name)
expect(serialized_node.chef_environment).to eql(node.chef_environment)
- node.each_attribute do |k,v|
+ node.each_attribute do |k, v|
expect(serialized_node[k]).to eql(v)
end
expect(serialized_node.run_list).to eq(node.run_list)
@@ -1222,7 +1399,7 @@ describe Chef::Node do
end
it "parses policyfile attributes from JSON" do
- round_tripped_node = Chef::Node.json_create(node.for_json)
+ round_tripped_node = Chef::Node.from_hash(node.for_json)
expect(round_tripped_node.policy_name).to eq("my-application")
expect(round_tripped_node.policy_group).to eq("staging")
@@ -1231,10 +1408,10 @@ describe Chef::Node do
end
include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
- let(:jsonable) {
+ let(:jsonable) do
node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA))
node
- }
+ end
end
end
@@ -1247,8 +1424,8 @@ describe Chef::Node do
describe "api model" do
before(:each) do
- @rest = double("Chef::REST")
- allow(Chef::REST).to receive(:new).and_return(@rest)
+ @rest = double("Chef::ServerAPI")
+ allow(Chef::ServerAPI).to receive(:new).and_return(@rest)
@query = double("Chef::Search::Query")
allow(Chef::Search::Query).to receive(:new).and_return(@query)
end
@@ -1257,6 +1434,7 @@ describe Chef::Node do
describe "inflated" do
it "should return a hash of node names and objects" do
n1 = double("Chef::Node", :name => "one")
+ allow(n1).to receive(:kind_of?).with(Chef::Node) { true }
expect(@query).to receive(:search).with(:node).and_yield(n1)
r = Chef::Node.list(true)
expect(r["one"]).to eq(n1)
@@ -1264,7 +1442,7 @@ describe Chef::Node do
end
it "should return a hash of node names and urls" do
- expect(@rest).to receive(:get_rest).and_return({ "one" => "http://foo" })
+ expect(@rest).to receive(:get).and_return({ "one" => "http://foo" })
r = Chef::Node.list
expect(r["one"]).to eq("http://foo")
end
@@ -1272,14 +1450,19 @@ describe Chef::Node do
describe "load" do
it "should load a node by name" do
- expect(@rest).to receive(:get_rest).with("nodes/monkey").and_return("foo")
- expect(Chef::Node.load("monkey")).to eq("foo")
+ node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA))
+ json = Chef::JSONCompat.to_json(node)
+ parsed = Chef::JSONCompat.parse(json)
+ expect(@rest).to receive(:get).with("nodes/test.example.com").and_return(parsed)
+ serialized_node = Chef::Node.load("test.example.com")
+ expect(serialized_node).to be_a_kind_of(Chef::Node)
+ expect(serialized_node.name).to eql(node.name)
end
end
describe "destroy" do
it "should destroy a node" do
- expect(@rest).to receive(:delete_rest).with("nodes/monkey").and_return("foo")
+ expect(@rest).to receive(:delete).with("nodes/monkey").and_return("foo")
node.name("monkey")
node.destroy
end
@@ -1289,15 +1472,15 @@ describe Chef::Node do
it "should update a node if it already exists" do
node.name("monkey")
allow(node).to receive(:data_for_save).and_return({})
- expect(@rest).to receive(:put_rest).with("nodes/monkey", {}).and_return("foo")
+ expect(@rest).to receive(:put).with("nodes/monkey", {}).and_return("foo")
node.save
end
it "should not try and create if it can update" do
node.name("monkey")
allow(node).to receive(:data_for_save).and_return({})
- expect(@rest).to receive(:put_rest).with("nodes/monkey", {}).and_return("foo")
- expect(@rest).not_to receive(:post_rest)
+ expect(@rest).to receive(:put).with("nodes/monkey", {}).and_return("foo")
+ expect(@rest).not_to receive(:post)
node.save
end
@@ -1305,8 +1488,8 @@ describe Chef::Node do
node.name("monkey")
allow(node).to receive(:data_for_save).and_return({})
exception = double("404 error", :code => "404")
- expect(@rest).to receive(:put_rest).and_raise(Net::HTTPServerException.new("foo", exception))
- expect(@rest).to receive(:post_rest).with("nodes", {})
+ expect(@rest).to receive(:put).and_raise(Net::HTTPServerException.new("foo", exception))
+ expect(@rest).to receive(:post).with("nodes", {})
node.save
end
@@ -1319,8 +1502,8 @@ describe Chef::Node do
end
it "should not save" do
node.name("monkey")
- expect(@rest).not_to receive(:put_rest)
- expect(@rest).not_to receive(:post_rest)
+ expect(@rest).not_to receive(:put)
+ expect(@rest).not_to receive(:post)
node.save
end
end
@@ -1329,21 +1512,21 @@ describe Chef::Node do
it "should only save whitelisted attributes (and subattributes)" do
Chef::Config[:automatic_attribute_whitelist] = [
["filesystem", "/dev/disk0s2"],
- "network/interfaces/eth0"
+ "network/interfaces/eth0",
]
data = {
"automatic" => {
"filesystem" => {
"/dev/disk0s2" => { "size" => "10mb" },
- "map - autohome" => { "size" => "10mb" }
+ "map - autohome" => { "size" => "10mb" },
},
"network" => {
"interfaces" => {
"eth0" => {},
- "eth1" => {}
- }
- }
+ "eth1" => {},
+ },
+ },
},
"default" => {}, "normal" => {}, "override" => {}
}
@@ -1351,26 +1534,26 @@ describe Chef::Node do
selected_data = {
"automatic" => {
"filesystem" => {
- "/dev/disk0s2" => { "size" => "10mb" }
+ "/dev/disk0s2" => { "size" => "10mb" },
},
"network" => {
"interfaces" => {
- "eth0" => {}
- }
- }
+ "eth0" => {},
+ },
+ },
},
"default" => {}, "normal" => {}, "override" => {}
}
node.name("picky-monkey")
allow(node).to receive(:for_json).and_return(data)
- expect(@rest).to receive(:put_rest).with("nodes/picky-monkey", selected_data).and_return("foo")
+ expect(@rest).to receive(:put).with("nodes/picky-monkey", selected_data).and_return("foo")
node.save
end
it "should save false-y whitelisted attributes" do
Chef::Config[:default_attribute_whitelist] = [
- "foo/bar/baz"
+ "foo/bar/baz",
]
data = {
@@ -1381,9 +1564,9 @@ describe Chef::Node do
},
"other" => {
"stuff" => true,
- }
- }
- }
+ },
+ },
+ },
}
selected_data = {
@@ -1391,14 +1574,14 @@ describe Chef::Node do
"foo" => {
"bar" => {
"baz" => false,
- }
- }
- }
+ },
+ },
+ },
}
node.name("falsey-monkey")
allow(node).to receive(:for_json).and_return(data)
- expect(@rest).to receive(:put_rest).with("nodes/falsey-monkey", selected_data).and_return("foo")
+ expect(@rest).to receive(:put).with("nodes/falsey-monkey", selected_data).and_return("foo")
node.save
end
@@ -1409,8 +1592,8 @@ describe Chef::Node do
"automatic" => {
"filesystem" => {
"/dev/disk0s2" => { "size" => "10mb" },
- "map - autohome" => { "size" => "10mb" }
- }
+ "map - autohome" => { "size" => "10mb" },
+ },
},
"default" => {}, "normal" => {}, "override" => {}
}
@@ -1421,7 +1604,7 @@ describe Chef::Node do
node.name("picky-monkey")
allow(node).to receive(:for_json).and_return(data)
- expect(@rest).to receive(:put_rest).with("nodes/picky-monkey", selected_data).and_return("foo")
+ expect(@rest).to receive(:put).with("nodes/picky-monkey", selected_data).and_return("foo")
node.save
end
end
@@ -1437,12 +1620,12 @@ describe Chef::Node do
context "and the server supports policyfile attributes in node JSON" do
it "creates the object normally" do
- expect(@rest).to receive(:post_rest).with("nodes", node.for_json)
+ expect(@rest).to receive(:post).with("nodes", node.for_json)
node.create
end
it "saves the node object normally" do
- expect(@rest).to receive(:put_rest).with("nodes/example-node", node.for_json)
+ expect(@rest).to receive(:put).with("nodes/example-node", node.for_json)
node.save
end
end
@@ -1481,7 +1664,7 @@ describe Chef::Node do
# added the policyfile attributes to the node JSON, therefore
# policyfile users need to be on 12.3 minimum when upgrading Chef
# Client to 13+
- it "lets the 400 pass through", :chef_gte_13_only do
+ it "lets the 400 pass through", chef: ">= 13" do
expect { node.save }.to raise_error(http_exception)
end
@@ -1490,8 +1673,8 @@ describe Chef::Node do
context "when the node exists" do
it "falls back to saving without policyfile attributes" do
- expect(@rest).to receive(:put_rest).with("nodes/example-node", node.for_json).and_raise(http_exception)
- expect(@rest).to receive(:put_rest).with("nodes/example-node", trimmed_node).and_return(@node)
+ expect(@rest).to receive(:put).with("nodes/example-node", node.for_json).and_raise(http_exception)
+ expect(@rest).to receive(:put).with("nodes/example-node", trimmed_node).and_return(@node)
expect { node.save }.to_not raise_error
end
@@ -1512,15 +1695,15 @@ describe Chef::Node do
end
it "falls back to saving without policyfile attributes" do
- expect(@rest).to receive(:put_rest).with("nodes/example-node", node.for_json).and_raise(http_exception)
- expect(@rest).to receive(:put_rest).with("nodes/example-node", trimmed_node).and_raise(http_exception_404)
- expect(@rest).to receive(:post_rest).with("nodes", trimmed_node).and_return(@node)
+ expect(@rest).to receive(:put).with("nodes/example-node", node.for_json).and_raise(http_exception)
+ expect(@rest).to receive(:put).with("nodes/example-node", trimmed_node).and_raise(http_exception_404)
+ expect(@rest).to receive(:post).with("nodes", trimmed_node).and_return(@node)
node.save
end
it "creates the node without policyfile attributes" do
- expect(@rest).to receive(:post_rest).with("nodes", node.for_json).and_raise(http_exception)
- expect(@rest).to receive(:post_rest).with("nodes", trimmed_node).and_return(@node)
+ expect(@rest).to receive(:post).with("nodes", node.for_json).and_raise(http_exception)
+ expect(@rest).to receive(:post).with("nodes", trimmed_node).and_return(@node)
node.create
end
end
@@ -1532,4 +1715,122 @@ describe Chef::Node do
end
end
+ describe "method_missing handling" do
+ it "should have an #empty? method via Chef::Node::Attribute" do
+ node.default["foo"] = "bar"
+ expect(node.empty?).to be false
+ end
+
+ it "it should correctly implement #respond_to?" do
+ expect(node.respond_to?(:empty?)).to be true
+ end
+
+ it "it should correctly retrieve the method with #method" do
+ expect(node.method(:empty?)).to be_kind_of(Method)
+ end
+ end
+
+ describe "path tracking via __path__" do
+ it "works through hash keys" do
+ node.default["foo"] = { "bar" => { "baz" => "qux" } }
+ expect(node["foo"]["bar"].__path__).to eql(%w{foo bar})
+ end
+
+ it "works through the default level" do
+ node.default["foo"] = { "bar" => { "baz" => "qux" } }
+ expect(node.default["foo"]["bar"].__path__).to eql(%w{foo bar})
+ end
+
+ it "works through arrays" do
+ node.default["foo"] = [ { "bar" => { "baz" => "qux" } } ]
+ expect(node["foo"][0].__path__).to eql(["foo", 0])
+ expect(node["foo"][0]["bar"].__path__).to eql(["foo", 0, "bar"])
+ end
+
+ it "works through arrays at the default level" do
+ node.default["foo"] = [ { "bar" => { "baz" => "qux" } } ]
+ expect(node.default["foo"][0].__path__).to eql(["foo", 0])
+ expect(node.default["foo"][0]["bar"].__path__).to eql(["foo", 0, "bar"])
+ end
+
+ # if we set __path__ in the initializer we'd get this wrong, this is why we
+ # update the path on every #[] or #[]= operator
+ it "works on access when the node has been rearranged" do
+ node.default["foo"] = { "bar" => { "baz" => "qux" } }
+ a = node.default["foo"]
+ node.default["fizz"] = a
+ expect(node["fizz"]["bar"].__path__).to eql(%w{fizz bar})
+ expect(node["foo"]["bar"].__path__).to eql(%w{foo bar})
+ end
+
+ # We have a problem because the __path__ is stored on in each node, but the
+ # node can be wired up at multiple locations in the tree via pointers. One
+ # solution would be to deep-dup the value in `#[]=(key, value)` and fix the
+ # __path__ on all the dup'd nodes. The problem is that this would create an
+ # unusual situation where after assignment, you couldn't mutate the thing you
+ # hand a handle on. I'm not entirely positive this behavior is the correct
+ # thing to support, but it is more hash-like (although if we start with a hash
+ # then convert_value does its thing and we *do* get dup'd on assignment). This
+ # behavior likely makes any implementation of a deep merge cache built over the
+ # top of __path__ tracking have edge conditions where it will fail.
+ #
+ # Removing this support would be a breaking change. The test is included here
+ # because it seems most likely that someone would break this behavior while trying
+ # to fix __path__ behavior.
+ it "does not dup in the background when a node is assigned" do
+ # get a handle on a vividmash (can't be a hash or else we convert_value it)
+ node.default["foo"] = { "bar" => { "baz" => "qux" } }
+ a = node.default["foo"]
+ # assign that somewhere else in the tree
+ node.default["fizz"] = a
+ # now upate the source
+ a["duptest"] = true
+ # the tree should have been updated
+ expect(node.default["fizz"]["duptest"]).to be true
+ expect(node["fizz"]["duptest"]).to be true
+ end
+ end
+
+ describe "root tracking via __root__" do
+ it "works through hash keys" do
+ node.default["foo"] = { "bar" => { "baz" => "qux" } }
+ expect(node["foo"]["bar"].__root__).to eql(node.attributes)
+ end
+
+ it "works through the default level" do
+ node.default["foo"] = { "bar" => { "baz" => "qux" } }
+ expect(node.default["foo"]["bar"].__root__).to eql(node.attributes)
+ end
+
+ it "works through arrays" do
+ node.default["foo"] = [ { "bar" => { "baz" => "qux" } } ]
+ expect(node["foo"][0].__root__).to eql(node.attributes)
+ expect(node["foo"][0]["bar"].__root__).to eql(node.attributes)
+ end
+
+ it "works through arrays at the default level" do
+ node.default["foo"] = [ { "bar" => { "baz" => "qux" } } ]
+ expect(node.default["foo"][0].__root__).to eql(node.attributes)
+ expect(node.default["foo"][0]["bar"].__root__).to eql(node.attributes)
+ end
+ end
+
+ describe "ways of abusing Chef 12 node state" do
+ # these tests abuse the top_level_breadcrumb state in Chef 12
+ it "derived attributes work correctly" do
+ node.default["v1"] = 1
+ expect(node["a"]).to eql(nil)
+ node.default["a"] = node["v1"]
+ expect(node["a"]).to eql(1)
+ end
+
+ it "works when saving nodes to variables" do
+ a = node.default["a"]
+ expect(node["a"]).to eql({})
+ node.default["b"] = 0
+ a["key"] = 1
+
+ expect(node["a"]["key"]).to eql(1)
+ end
+ end
end
diff --git a/spec/unit/org_spec.rb b/spec/unit/org_spec.rb
index cd6cc94d91..49557417a5 100644
--- a/spec/unit/org_spec.rb
+++ b/spec/unit/org_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (steve@opscode.com)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc
+# Author:: Steven Danna (steve@chef.io)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/org'
-require 'tempfile'
+require "chef/org"
+require "tempfile"
describe Chef::Org do
let(:org) { Chef::Org.new("an_org") }
@@ -110,8 +110,8 @@ describe Chef::Org do
describe "when deserializing from JSON" do
let(:org) do
o = { "name" => "turtle",
- "full_name" => "turtle_club",
- "private_key" => "pandas" }
+ "full_name" => "turtle_club",
+ "private_key" => "pandas" }
Chef::Org.from_json(o.to_json)
end
@@ -135,8 +135,8 @@ describe Chef::Org do
describe "API Interactions" do
let(:rest) do
Chef::Config[:chef_server_root] = "http://www.example.com"
- r = double('rest')
- allow(Chef::REST).to receive(:new).and_return(r)
+ r = double("rest")
+ allow(Chef::ServerAPI).to receive(:new).and_return(r)
r
end
@@ -147,31 +147,31 @@ describe Chef::Org do
end
describe "list" do
- let(:response) { {"foobar" => "http://www.example.com/organizations/foobar"} }
- let(:inflated_response) { {"foobar" => org } }
+ let(:response) { { "foobar" => "http://www.example.com/organizations/foobar" } }
+ let(:inflated_response) { { "foobar" => org } }
it "lists all orgs" do
- expect(rest).to receive(:get_rest).with("organizations").and_return(response)
+ expect(rest).to receive(:get).with("organizations").and_return(response)
expect(Chef::Org.list).to eq(response)
end
it "inflate all orgs" do
allow(Chef::Org).to receive(:load).with("foobar").and_return(org)
- expect(rest).to receive(:get_rest).with("organizations").and_return(response)
+ expect(rest).to receive(:get).with("organizations").and_return(response)
expect(Chef::Org.list(true)).to eq(inflated_response)
end
end
describe "create" do
it "creates a new org via the API" do
- expect(rest).to receive(:post_rest).with("organizations", {:name => "foobar", :full_name => "foo bar bat"}).and_return({})
+ expect(rest).to receive(:post).with("organizations", { :name => "foobar", :full_name => "foo bar bat" }).and_return({})
org.create
end
end
describe "read" do
it "loads a named org from the API" do
- expect(rest).to receive(:get_rest).with("organizations/foobar").and_return({"name" => "foobar", "full_name" => "foo bar bat", "private_key" => "private"})
+ expect(rest).to receive(:get).with("organizations/foobar").and_return({ "name" => "foobar", "full_name" => "foo bar bat", "private_key" => "private" })
org = Chef::Org.load("foobar")
expect(org.name).to eq("foobar")
expect(org.full_name).to eq("foo bar bat")
@@ -181,14 +181,14 @@ describe Chef::Org do
describe "update" do
it "updates an existing org on via the API" do
- expect(rest).to receive(:put_rest).with("organizations/foobar", {:name => "foobar", :full_name => "foo bar bat"}).and_return({})
+ expect(rest).to receive(:put).with("organizations/foobar", { :name => "foobar", :full_name => "foo bar bat" }).and_return({})
org.update
end
end
describe "destroy" do
it "deletes the specified org via the API" do
- expect(rest).to receive(:delete_rest).with("organizations/foobar")
+ expect(rest).to receive(:delete).with("organizations/foobar")
org.destroy
end
end
diff --git a/spec/unit/platform/query_helpers_spec.rb b/spec/unit/platform/query_helpers_spec.rb
index d18b6f7902..aa2b3c1f11 100644
--- a/spec/unit/platform/query_helpers_spec.rb
+++ b/spec/unit/platform/query_helpers_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe "Chef::Platform#windows_server_2003?" do
it "returns false early when not on windows" do
@@ -51,8 +51,8 @@ describe "Chef::Platform#windows_nano_server?" do
end
after do
- Win32::Registry.send(:remove_const, 'HKEY_LOCAL_MACHINE') if defined?(Win32::Registry::HKEY_LOCAL_MACHINE)
- Win32::Registry.send(:remove_const, 'KEY_QUERY_VALUE') if defined?(Win32::Registry::KEY_QUERY_VALUE)
+ Win32::Registry.send(:remove_const, "HKEY_LOCAL_MACHINE") if defined?(Win32::Registry::HKEY_LOCAL_MACHINE)
+ Win32::Registry.send(:remove_const, "KEY_QUERY_VALUE") if defined?(Win32::Registry::KEY_QUERY_VALUE)
end
it "returns false early when not on windows" do
@@ -63,7 +63,7 @@ describe "Chef::Platform#windows_nano_server?" do
it "returns true when the registry value is 1" do
allow(ChefConfig).to receive(:windows?).and_return(true)
- allow(Chef::Platform).to receive(:require).with('win32/registry')
+ allow(Chef::Platform).to receive(:require).with("win32/registry")
expect(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).
with(key, access).
and_yield(registry)
@@ -73,7 +73,7 @@ describe "Chef::Platform#windows_nano_server?" do
it "returns false when the registry value is not 1" do
allow(ChefConfig).to receive(:windows?).and_return(true)
- allow(Chef::Platform).to receive(:require).with('win32/registry')
+ allow(Chef::Platform).to receive(:require).with("win32/registry")
expect(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).
with(key, access).
and_yield(registry)
@@ -83,7 +83,7 @@ describe "Chef::Platform#windows_nano_server?" do
it "returns false when the registry value does not exist" do
allow(ChefConfig).to receive(:windows?).and_return(true)
- allow(Chef::Platform).to receive(:require).with('win32/registry')
+ allow(Chef::Platform).to receive(:require).with("win32/registry")
expect(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).
with(key, access).
and_yield(registry)
@@ -94,7 +94,7 @@ describe "Chef::Platform#windows_nano_server?" do
it "returns false when the registry key does not exist" do
allow(ChefConfig).to receive(:windows?).and_return(true)
- allow(Chef::Platform).to receive(:require).with('win32/registry')
+ allow(Chef::Platform).to receive(:require).with("win32/registry")
expect(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).
with(key, access).
and_raise(Win32::Registry::Error, "The system cannot find the file specified.")
@@ -103,7 +103,7 @@ describe "Chef::Platform#windows_nano_server?" do
end
describe "Chef::Platform#supports_msi?" do
- include_context "Win32" # clear and restore Win32:: namespace
+ include_context "Win32" # clear and restore Win32:: namespace
let(:key) { "System\\CurrentControlSet\\Services\\msiserver" }
let(:key_query_value) { 0x0001 }
@@ -122,8 +122,8 @@ describe "Chef::Platform#supports_msi?" do
end
after do
- Win32::Registry.send(:remove_const, 'HKEY_LOCAL_MACHINE') if defined?(Win32::Registry::HKEY_LOCAL_MACHINE)
- Win32::Registry.send(:remove_const, 'KEY_QUERY_VALUE') if defined?(Win32::Registry::KEY_QUERY_VALUE)
+ Win32::Registry.send(:remove_const, "HKEY_LOCAL_MACHINE") if defined?(Win32::Registry::HKEY_LOCAL_MACHINE)
+ Win32::Registry.send(:remove_const, "KEY_QUERY_VALUE") if defined?(Win32::Registry::KEY_QUERY_VALUE)
end
it "returns false early when not on windows" do
@@ -134,7 +134,7 @@ describe "Chef::Platform#supports_msi?" do
it "returns true when the registry key exists" do
allow(ChefConfig).to receive(:windows?).and_return(true)
- allow(Chef::Platform).to receive(:require).with('win32/registry')
+ allow(Chef::Platform).to receive(:require).with("win32/registry")
expect(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).
with(key, access).
and_yield(registry)
@@ -143,7 +143,7 @@ describe "Chef::Platform#supports_msi?" do
it "returns false when the registry key does not exist" do
allow(ChefConfig).to receive(:windows?).and_return(true)
- allow(Chef::Platform).to receive(:require).with('win32/registry')
+ allow(Chef::Platform).to receive(:require).with("win32/registry")
expect(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).
with(key, access).
and_raise(Win32::Registry::Error, "The system cannot find the file specified.")
@@ -151,13 +151,13 @@ describe "Chef::Platform#supports_msi?" do
end
end
-describe 'Chef::Platform#supports_dsc?' do
- it 'returns false if powershell is not present' do
+describe "Chef::Platform#supports_dsc?" do
+ it "returns false if powershell is not present" do
node = Chef::Node.new
expect(Chef::Platform.supports_dsc?(node)).to be_falsey
end
- ['1.0', '2.0', '3.0'].each do |version|
+ ["1.0", "2.0", "3.0"].each do |version|
it "returns false for Powershell #{version}" do
node = Chef::Node.new
node.automatic[:languages][:powershell][:version] = version
@@ -165,7 +165,7 @@ describe 'Chef::Platform#supports_dsc?' do
end
end
- ['4.0', '5.0'].each do |version|
+ ["4.0", "5.0"].each do |version|
it "returns true for Powershell #{version}" do
node = Chef::Node.new
node.automatic[:languages][:powershell][:version] = version
@@ -174,13 +174,13 @@ describe 'Chef::Platform#supports_dsc?' do
end
end
-describe 'Chef::Platform#supports_dsc_invoke_resource?' do
- it 'returns false if powershell is not present' do
+describe "Chef::Platform#supports_dsc_invoke_resource?" do
+ it "returns false if powershell is not present" do
node = Chef::Node.new
expect(Chef::Platform.supports_dsc_invoke_resource?(node)).to be_falsey
end
- ['1.0', '2.0', '3.0', '4.0', '5.0.10017.9'].each do |version|
+ ["1.0", "2.0", "3.0", "4.0", "5.0.10017.9"].each do |version|
it "returns false for Powershell #{version}" do
node = Chef::Node.new
node.automatic[:languages][:powershell][:version] = version
@@ -195,17 +195,17 @@ describe 'Chef::Platform#supports_dsc_invoke_resource?' do
end
end
-describe 'Chef::Platform#dsc_refresh_mode_disabled?' do
- let(:node) { instance_double('Chef::Node') }
- let(:cmdlet) { instance_double('Chef::Util::Powershell::Cmdlet') }
- let(:cmdlet_result) { instance_double('Chef::Util::Powershell::CmdletResult')}
+describe "Chef::Platform#dsc_refresh_mode_disabled?" do
+ let(:node) { instance_double("Chef::Node") }
+ let(:cmdlet) { instance_double("Chef::Util::Powershell::Cmdlet") }
+ let(:cmdlet_result) { instance_double("Chef::Util::Powershell::CmdletResult") }
it "returns true when RefreshMode is Disabled" do
expect(Chef::Util::Powershell::Cmdlet).to receive(:new).
with(node, "Get-DscLocalConfigurationManager", :object).
and_return(cmdlet)
expect(cmdlet).to receive(:run!).and_return(cmdlet_result)
- expect(cmdlet_result).to receive(:return_value).and_return({ 'RefreshMode' => 'Disabled' })
+ expect(cmdlet_result).to receive(:return_value).and_return({ "RefreshMode" => "Disabled" })
expect(Chef::Platform.dsc_refresh_mode_disabled?(node)).to be true
end
@@ -214,7 +214,7 @@ describe 'Chef::Platform#dsc_refresh_mode_disabled?' do
with(node, "Get-DscLocalConfigurationManager", :object).
and_return(cmdlet)
expect(cmdlet).to receive(:run!).and_return(cmdlet_result)
- expect(cmdlet_result).to receive(:return_value).and_return({ 'RefreshMode' => 'LaLaLa' })
+ expect(cmdlet_result).to receive(:return_value).and_return({ "RefreshMode" => "LaLaLa" })
expect(Chef::Platform.dsc_refresh_mode_disabled?(node)).to be false
end
end
diff --git a/spec/unit/platform_spec.rb b/spec/unit/platform_spec.rb
index 34b46f657f..3a562d3ce6 100644
--- a/spec/unit/platform_spec.rb
+++ b/spec/unit/platform_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,19 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Platform do
context "while testing with fake data" do
+ def expect_platform_warning(method_name, times: 1, recurse: true)
+ expect(Chef).to receive(:deprecated).with(:chef_platform_methods, "Chef::Platform.#{method_name} is deprecated").exactly(times).times
+ return unless recurse
+
+ expect_platform_warning(:find_provider_for_node, times: times) if method_name == :provider_for_resource
+ expect_platform_warning(:find_provider, times: times) if method_name == :find_provider_for_node
+ expect_platform_warning(:find, times: times) if method_name == :find_provider
+ end
before :all do
@original_platform_map = Chef::Platform.platforms
@@ -34,80 +42,90 @@ describe Chef::Platform do
Chef::Platform.platforms = {
:darwin => {
">= 10.11" => {
- :file => "new_darwinian"
+ :file => "new_darwinian",
},
"9.2.2" => {
:file => "darwinian",
- :else => "thing"
+ :else => "thing",
},
:default => {
:file => "old school",
- :snicker => "snack"
- }
+ :snicker => "snack",
+ },
},
:mars_volta => {
},
:default => {
:file => Chef::Provider::File,
:pax => "brittania",
- :cat => "nice"
- }
+ :cat => "nice",
+ },
}
@events = Chef::EventDispatch::Dispatcher.new
end
it "should allow you to look up a platform by name and version, returning the provider map for it" do
+ expect_platform_warning(:find)
pmap = Chef::Platform.find("Darwin", "9.2.2")
expect(pmap).to be_a_kind_of(Hash)
expect(pmap[:file]).to eql("darwinian")
end
it "should allow you to look up a platform by name and version using \"greater than\" style operators" do
+ expect_platform_warning(:find)
pmap = Chef::Platform.find("Darwin", "11.1.0")
expect(pmap).to be_a_kind_of(Hash)
expect(pmap[:file]).to eql("new_darwinian")
end
it "should use the default providers for an os if the specific version does not exist" do
+ expect_platform_warning(:find)
pmap = Chef::Platform.find("Darwin", "1")
expect(pmap).to be_a_kind_of(Hash)
expect(pmap[:file]).to eql("old school")
end
it "should use the default providers if the os doesn't give me a default, but does exist" do
+ expect_platform_warning(:find)
pmap = Chef::Platform.find("mars_volta", "1")
expect(pmap).to be_a_kind_of(Hash)
expect(pmap[:file]).to eql(Chef::Provider::File)
end
it "should use the default provider if the os does not exist" do
+ expect_platform_warning(:find)
pmap = Chef::Platform.find("AIX", "1")
expect(pmap).to be_a_kind_of(Hash)
expect(pmap[:file]).to eql(Chef::Provider::File)
end
it "should merge the defaults for an os with the specific version" do
+ expect_platform_warning(:find)
pmap = Chef::Platform.find("Darwin", "9.2.2")
expect(pmap[:file]).to eql("darwinian")
expect(pmap[:snicker]).to eql("snack")
end
it "should merge the defaults for an os with the universal defaults" do
+ expect_platform_warning(:find)
pmap = Chef::Platform.find("Darwin", "9.2.2")
expect(pmap[:file]).to eql("darwinian")
expect(pmap[:pax]).to eql("brittania")
end
it "should allow you to look up a provider for a platform directly by symbol" do
+ expect_platform_warning(:find_provider)
expect(Chef::Platform.find_provider("Darwin", "9.2.2", :file)).to eql("darwinian")
end
it "should raise an exception if a provider cannot be found for a resource type" do
+ expect_platform_warning(:find_provider)
expect { Chef::Platform.find_provider("Darwin", "9.2.2", :coffee) }.to raise_error(Chef::Exceptions::ProviderNotFound)
end
it "should look up a provider for a resource with a Chef::Resource object" do
kitty = Chef::Resource::Cat.new("loulou")
+ expect_platform_warning(:find_provider)
expect(Chef::Platform.find_provider("Darwin", "9.2.2", kitty)).to eql("nice")
end
@@ -117,10 +135,12 @@ describe Chef::Platform do
node.name("Intel")
node.automatic_attrs[:platform] = "mac_os_x"
node.automatic_attrs[:platform_version] = "9.2.2"
+ expect_platform_warning(:find_provider_for_node)
expect(Chef::Platform.find_provider_for_node(node, kitty)).to eql("nice")
end
it "should not throw an exception when the platform version has an unknown format" do
+ expect_platform_warning(:find_provider)
expect(Chef::Platform.find_provider(:darwin, "bad-version", :file)).to eql("old school")
end
@@ -131,6 +151,8 @@ describe Chef::Platform do
node.name("Intel")
node.automatic_attrs[:platform] = "mac_os_x"
node.automatic_attrs[:platform_version] = "9.2.2"
+ expect_platform_warning(:find_provider_for_node, recurse: false)
+ expect_platform_warning(:find_provider, recurse: false)
expect(Chef::Platform.find_provider_for_node(node, kitty)).to eql(Chef::Provider::File)
end
@@ -142,6 +164,7 @@ describe Chef::Platform do
node.name("Intel")
node.automatic_attrs[:platform] = "mac_os_x"
node.automatic_attrs[:platform_version] = "8.5"
+ expect_platform_warning(:find_provider_for_node)
expect(Chef::Platform.find_provider_for_node(node, kitty)).to eql(Chef::Provider::Cat)
end
@@ -155,6 +178,7 @@ describe Chef::Platform do
it "returns a provider object given a Chef::Resource object which has a valid run context and an action" do
file, run_context = setup_file_resource
+ expect_platform_warning(:provider_for_resource)
provider = Chef::Platform.provider_for_resource(file, :foo)
expect(provider).to be_an_instance_of(Chef::Provider::File)
expect(provider.new_resource).to equal(file)
@@ -163,6 +187,7 @@ describe Chef::Platform do
it "returns a provider object given a Chef::Resource object which has a valid run context without an action" do
file, run_context = setup_file_resource
+ expect_platform_warning(:provider_for_resource)
provider = Chef::Platform.provider_for_resource(file)
expect(provider).to be_an_instance_of(Chef::Provider::File)
expect(provider.new_resource).to equal(file)
@@ -171,14 +196,16 @@ describe Chef::Platform do
it "raises an error when trying to find the provider for a resource with no run context" do
file = Chef::Resource::File.new("whateva")
- expect {Chef::Platform.provider_for_resource(file)}.to raise_error(ArgumentError)
+ expect_platform_warning(:provider_for_resource, recurse: false)
+ expect { Chef::Platform.provider_for_resource(file) }.to raise_error(ArgumentError)
end
it "does not support finding a provider by resource and node -- a run context is required" do
- expect {Chef::Platform.provider_for_node('node', 'resource')}.to raise_error(NotImplementedError)
+ expect { Chef::Platform.provider_for_node("node", "resource") }.to raise_error(NotImplementedError)
end
it "should update the provider map with map" do
+ expect_platform_warning(:set, times: 7)
Chef::Platform.set(
:platform => :darwin,
:version => "9.2.2",
@@ -227,6 +254,7 @@ describe Chef::Platform do
end
it "does not overwrite the platform map when using :default platform" do
+ expect_platform_warning(:set)
Chef::Platform.set(
:resource => :file,
:platform => :default,
diff --git a/spec/unit/policy_builder/dynamic_spec.rb b/spec/unit/policy_builder/dynamic_spec.rb
index aff19f4d11..d94b2a69a2 100644
--- a/spec/unit/policy_builder/dynamic_spec.rb
+++ b/spec/unit/policy_builder/dynamic_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/policy_builder'
+require "spec_helper"
+require "chef/policy_builder"
describe Chef::PolicyBuilder::Dynamic do
let(:node_name) { "joe_node" }
- let(:ohai_data) { {"platform" => "ubuntu", "platform_version" => "13.04", "fqdn" => "joenode.example.com"} }
- let(:json_attribs) { {"custom_attr" => "custom_attr_value"} }
+ let(:ohai_data) { { "platform" => "ubuntu", "platform_version" => "13.04", "fqdn" => "joenode.example.com" } }
+ let(:json_attribs) { { "custom_attr" => "custom_attr_value" } }
let(:override_runlist) { nil }
let(:events) { Chef::EventDispatch::Dispatcher.new }
@@ -123,7 +123,7 @@ describe Chef::PolicyBuilder::Dynamic do
context "and no policyfile attributes are present in json_attribs" do
- let(:json_attribs) { {"foo" => "bar"} }
+ let(:json_attribs) { { "foo" => "bar" } }
it "uses the ExpandNodeObject implementation" do
expect(implementation).to be_a(Chef::PolicyBuilder::ExpandNodeObject)
@@ -171,7 +171,7 @@ describe Chef::PolicyBuilder::Dynamic do
context "and policyfile attributes are present in json_attribs" do
- let(:json_attribs) { {"policy_name" => "example-policy", "policy_group" => "testing"} }
+ let(:json_attribs) { { "policy_name" => "example-policy", "policy_group" => "testing" } }
it "uses the Policyfile implementation" do
expect(implementation).to be_a(Chef::PolicyBuilder::Policyfile)
@@ -207,7 +207,6 @@ describe Chef::PolicyBuilder::Dynamic do
context "when not running chef solo" do
-
context "when successful" do
before do
@@ -243,7 +242,6 @@ describe Chef::PolicyBuilder::Dynamic do
expect(implementation).to receive(:finish_load_node).and_raise("oops")
end
-
it "sends a node_load_failed event and re-raises" do
expect(events).to receive(:node_load_failed)
expect { policy_builder.load_node }.to raise_error("oops")
@@ -256,7 +254,7 @@ describe Chef::PolicyBuilder::Dynamic do
context "when running chef solo" do
before do
- Chef::Config[:solo] = true
+ Chef::Config[:solo_legacy_mode] = true
expect(Chef::Node).to receive(:build).with(node_name).and_return(node)
expect(policy_builder).to receive(:select_implementation).with(node)
expect(implementation).to receive(:finish_load_node).with(node)
diff --git a/spec/unit/policy_builder/expand_node_object_spec.rb b/spec/unit/policy_builder/expand_node_object_spec.rb
index 306d677108..420db2e855 100644
--- a/spec/unit/policy_builder/expand_node_object_spec.rb
+++ b/spec/unit/policy_builder/expand_node_object_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/policy_builder'
+require "spec_helper"
+require "chef/policy_builder"
describe Chef::PolicyBuilder::ExpandNodeObject do
let(:node_name) { "joe_node" }
- let(:ohai_data) { {"platform" => "ubuntu", "platform_version" => "13.04", "fqdn" => "joenode.example.com"} }
- let(:json_attribs) { {"run_list" => []} }
+ let(:ohai_data) { { "platform" => "ubuntu", "platform_version" => "13.04", "fqdn" => "joenode.example.com" } }
+ let(:json_attribs) { { "run_list" => [] } }
let(:override_runlist) { "recipe[foo::default]" }
let(:events) { Chef::EventDispatch::Dispatcher.new }
let(:policy_builder) { Chef::PolicyBuilder::ExpandNodeObject.new(node_name, ohai_data, json_attribs, override_runlist, events) }
@@ -38,7 +38,7 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
expect(policy_builder).to respond_to(:load_node)
end
- it "has removed the deprecated #load_node method", :chef_gte_13_only do
+ it "has removed the deprecated #load_node method", chef: ">= 13" do
expect(policy_builder).to_not respond_to(:load_node)
end
@@ -155,8 +155,8 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
let(:override_runlist) { nil }
let(:primary_runlist) { ["recipe[primary::default]"] }
- let(:original_default_attrs) { {"default_key" => "default_value"} }
- let(:original_override_attrs) { {"override_key" => "override_value"} }
+ let(:original_default_attrs) { { "default_key" => "default_value" } }
+ let(:original_override_attrs) { { "override_key" => "override_value" } }
let(:node) do
node = Chef::Node.new
@@ -227,7 +227,7 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
context "when JSON attributes are given on the command line" do
- let(:json_attribs) { {"run_list" => ["recipe[json_attribs::default]"], "json_attribs_key" => "json_attribs_value" } }
+ let(:json_attribs) { { "run_list" => ["recipe[json_attribs::default]"], "json_attribs_key" => "json_attribs_value" } }
it "sets the run list according to the given JSON" do
expect(node.run_list).to eq(["recipe[json_attribs::default]"])
@@ -267,7 +267,7 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
let(:configured_environment) { environment.name }
let(:environment) do
- environment = Chef::Environment.new.tap {|e| e.name("prod") }
+ environment = Chef::Environment.new.tap { |e| e.name("prod") }
expect(Chef::Environment).to receive(:load).with("prod").and_return(environment)
environment
end
@@ -290,15 +290,16 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
node
end
- let(:chef_http) { double("Chef::REST") }
+ let(:chef_http) { double("Chef::ServerAPI") }
let(:cookbook_resolve_url) { "environments/#{node.chef_environment}/cookbook_versions" }
- let(:cookbook_resolve_post_data) { {:run_list=>["first::default", "second::default"]} }
+ let(:cookbook_resolve_post_data) { { :run_list => ["first::default", "second::default"] } }
# cookbook_hash is just a hash, but since we're passing it between mock
# objects, we get a little better test strictness by using a double (which
# will have object equality rather than semantic equality #== semantics).
- let(:cookbook_hash) { double("cookbook hash", :each => nil) }
+ let(:cookbook_hash) { double("cookbook hash") }
+ let(:expanded_cookbook_hash) { double("expanded cookbook hash", :each => nil) }
let(:cookbook_synchronizer) { double("CookbookSynchronizer") }
@@ -310,8 +311,9 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
run_list_expansion = policy_builder.run_list_expansion
+ expect(cookbook_hash).to receive(:inject).and_return(expanded_cookbook_hash)
expect(chef_http).to receive(:post).with(cookbook_resolve_url, cookbook_resolve_post_data).and_return(cookbook_hash)
- expect(Chef::CookbookSynchronizer).to receive(:new).with(cookbook_hash, events).and_return(cookbook_synchronizer)
+ expect(Chef::CookbookSynchronizer).to receive(:new).with(expanded_cookbook_hash, events).and_return(cookbook_synchronizer)
expect(cookbook_synchronizer).to receive(:sync_cookbooks)
expect_any_instance_of(Chef::RunContext).to receive(:load).with(run_list_expansion)
diff --git a/spec/unit/policy_builder/policyfile_spec.rb b/spec/unit/policy_builder/policyfile_spec.rb
index b656a66ec3..307bd45c18 100644
--- a/spec/unit/policy_builder/policyfile_spec.rb
+++ b/spec/unit/policy_builder/policyfile_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/policy_builder'
+require "spec_helper"
+require "chef/policy_builder"
describe Chef::PolicyBuilder::Policyfile do
let(:node_name) { "joe_node" }
- let(:ohai_data) { {"platform" => "ubuntu", "platform_version" => "13.04", "fqdn" => "joenode.example.com"} }
- let(:json_attribs) { {"custom_attr" => "custom_attr_value"} }
+ let(:ohai_data) { { "platform" => "ubuntu", "platform_version" => "13.04", "fqdn" => "joenode.example.com" } }
+ let(:json_attribs) { { "custom_attr" => "custom_attr_value" } }
let(:override_runlist) { nil }
let(:events) { Chef::EventDispatch::Dispatcher.new }
let(:policy_builder) { Chef::PolicyBuilder::Policyfile.new(node_name, ohai_data, json_attribs, override_runlist, events) }
@@ -40,11 +40,10 @@ describe Chef::PolicyBuilder::Policyfile do
major = sha1_id[0...14]
minor = sha1_id[14...28]
patch = sha1_id[28..40]
- decimal_integers =[major, minor, patch].map {|hex| hex.to_i(16) }
+ decimal_integers = [major, minor, patch].map { |hex| hex.to_i(16) }
decimal_integers.join(".")
end
-
let(:example1_lock_data) do
# based on https://github.com/danielsdeleo/chef-workflow2-prototype/blob/master/skeletons/basic_policy/Policyfile.lock.json
{
@@ -53,11 +52,11 @@ describe Chef::PolicyBuilder::Policyfile do
# NOTE: for compatibility mode we include the dotted id in the policyfile to enhance discoverability.
"dotted_decimal_identifier" => id_to_dotted("168d2102fb11c9617cd8a981166c8adc30a6e915"),
"source" => { "path" => "./cookbooks/demo" },
- "scm_identifier"=> {
- "vcs"=> "git",
- "rev_id"=> "9d5b09026470c322c3cb5ca8a4157c4d2f16cef3",
- "remote"=> nil
- }
+ "scm_identifier" => {
+ "vcs" => "git",
+ "rev_id" => "9d5b09026470c322c3cb5ca8a4157c4d2f16cef3",
+ "remote" => nil,
+ },
}
end
@@ -67,12 +66,12 @@ describe Chef::PolicyBuilder::Policyfile do
"version" => "4.2.0",
# NOTE: for compatibility mode we include the dotted id in the policyfile to enhance discoverability.
"dotted_decimal_identifier" => id_to_dotted("feab40e1fca77c7360ccca1481bb8ba5f919ce3a"),
- "source" => { "api" => "https://community.getchef.com/api/v1/cookbooks/example2" }
+ "source" => { "api" => "https://community.getchef.com/api/v1/cookbooks/example2" },
}
end
- let(:policyfile_default_attributes) { {"policyfile_default_attr" => "policyfile_default_value"} }
- let(:policyfile_override_attributes) { {"policyfile_override_attr" => "policyfile_override_value"} }
+ let(:policyfile_default_attributes) { { "policyfile_default_attr" => "policyfile_default_value" } }
+ let(:policyfile_override_attributes) { { "policyfile_override_attr" => "policyfile_override_value" } }
let(:policyfile_run_list) { ["recipe[example1::default]", "recipe[example2::server]"] }
@@ -85,11 +84,11 @@ describe Chef::PolicyBuilder::Policyfile do
"cookbook_locks" => {
"example1" => example1_lock_data,
- "example2" => example2_lock_data
+ "example2" => example2_lock_data,
},
"default_attributes" => policyfile_default_attributes,
- "override_attributes" => policyfile_override_attributes
+ "override_attributes" => policyfile_override_attributes,
}
end
@@ -98,10 +97,10 @@ describe Chef::PolicyBuilder::Policyfile do
let(:err_namespace) { Chef::PolicyBuilder::Policyfile }
it "configures a Chef HTTP API client" do
- http = double("Chef::REST")
+ http = double("Chef::ServerAPI")
server_url = "https://api.opscode.com/organizations/example"
Chef::Config[:chef_server_url] = server_url
- expect(Chef::REST).to receive(:new).with(server_url).and_return(http)
+ expect(Chef::ServerAPI).to receive(:new).with(server_url).and_return(http)
expect(policy_builder.http_api).to eq(http)
end
@@ -116,7 +115,7 @@ describe Chef::PolicyBuilder::Policyfile do
end
context "chef-solo" do
- before { Chef::Config[:solo] = true }
+ before { Chef::Config[:solo_legacy_mode] = true }
it "errors on create" do
expect { initialize_pb }.to raise_error(err_namespace::UnsupportedFeature)
@@ -132,7 +131,7 @@ describe Chef::PolicyBuilder::Policyfile do
end
context "when json_attribs contains a run_list" do
- let(:json_attribs) { {"run_list" => []} }
+ let(:json_attribs) { { "run_list" => [] } }
it "errors on create" do
expect { initialize_pb }.to raise_error(err_namespace::UnsupportedFeature)
@@ -151,15 +150,15 @@ describe Chef::PolicyBuilder::Policyfile do
describe "loading policy data" do
- let(:http_api) { double("Chef::REST") }
+ let(:http_api) { double("Chef::ServerAPI") }
let(:configured_environment) { nil }
let(:override_runlist) { nil }
let(:primary_runlist) { nil }
- let(:original_default_attrs) { {"default_key" => "default_value"} }
- let(:original_override_attrs) { {"override_key" => "override_value"} }
+ let(:original_default_attrs) { { "default_key" => "default_value" } }
+ let(:original_override_attrs) { { "override_key" => "override_value" } }
let(:node) do
node = Chef::Node.new
@@ -268,7 +267,6 @@ describe Chef::PolicyBuilder::Policyfile do
end
-
describe "building policy from the policyfile" do
before do
@@ -286,7 +284,7 @@ describe Chef::PolicyBuilder::Policyfile do
it "extracts the cookbooks and versions for display from the policyfile" do
expected = [
"example1::default@2.3.5 (168d210)",
- "example2::server@4.2.0 (feab40e)"
+ "example2::server@4.2.0 (feab40e)",
]
expect(policy_builder.run_list_with_versions_for_display).to eq(expected)
@@ -304,7 +302,6 @@ describe Chef::PolicyBuilder::Policyfile do
expect(policy_builder.expand_run_list.roles).to eq([])
end
-
describe "validating the Policyfile.lock" do
it "errors if the policyfile json contains any non-recipe items" do
@@ -357,7 +354,7 @@ describe Chef::PolicyBuilder::Policyfile do
let(:json_attribs) do
{
"policy_name" => "policy_name_from_node_json",
- "policy_group" => "policy_group_from_node_json"
+ "policy_group" => "policy_group_from_node_json",
}
end
@@ -378,7 +375,7 @@ describe Chef::PolicyBuilder::Policyfile do
let(:extra_chef_config) do
{
policy_name: "policy_name_from_config",
- policy_group: "policy_group_from_config"
+ policy_group: "policy_group_from_config",
}
end
@@ -419,7 +416,7 @@ describe Chef::PolicyBuilder::Policyfile do
let(:extra_chef_config) do
{
policy_name: "policy_name_from_config",
- policy_group: "policy_group_from_config"
+ policy_group: "policy_group_from_config",
}
end
@@ -435,7 +432,7 @@ describe Chef::PolicyBuilder::Policyfile do
let(:json_attribs) do
{
"policy_name" => "policy_name_from_node_json",
- "policy_group" => "policy_group_from_node_json"
+ "policy_group" => "policy_group_from_node_json",
}
end
@@ -447,7 +444,6 @@ describe Chef::PolicyBuilder::Policyfile do
node
end
-
it "prefers the policy_name and policy_group from the node json" do
expect(policy_builder.policy_name).to eq("policy_name_from_node_json")
expect(policy_builder.policy_group).to eq("policy_group_from_node_json")
@@ -465,7 +461,7 @@ describe Chef::PolicyBuilder::Policyfile do
let(:json_attribs) do
{
"policy_name" => "policy_name_from_node_json",
- "policy_group" => "policy_group_from_node_json"
+ "policy_group" => "policy_group_from_node_json",
}
end
@@ -480,7 +476,7 @@ describe Chef::PolicyBuilder::Policyfile do
let(:extra_chef_config) do
{
policy_name: "policy_name_from_config",
- policy_group: "policy_group_from_config"
+ policy_group: "policy_group_from_config",
}
end
@@ -564,7 +560,7 @@ describe Chef::PolicyBuilder::Policyfile do
let(:parsed_policyfile_json) do
basic_valid_policy_data.dup.tap do |p|
p["named_run_lists"] = {
- "deploy-app" => [ "recipe[example1::default]" ]
+ "deploy-app" => [ "recipe[example1::default]" ],
}
end
end
@@ -592,7 +588,6 @@ describe Chef::PolicyBuilder::Policyfile do
end
end
-
describe "fetching the desired cookbook set" do
let(:example1_cookbook_data) { double("CookbookVersion Hash for example1 cookbook") }
@@ -662,14 +657,18 @@ describe Chef::PolicyBuilder::Policyfile do
it "builds a run context" do
expect(cookbook_synchronizer).to receive(:sync_cookbooks)
expect_any_instance_of(Chef::RunContext).to receive(:load).with(policy_builder.run_list_expansion_ish)
+ expect_any_instance_of(Chef::CookbookCollection).to receive(:validate!)
+ expect_any_instance_of(Chef::CookbookCollection).to receive(:install_gems)
run_context = policy_builder.setup_run_context
expect(run_context.node).to eq(node)
- expect(run_context.cookbook_collection.keys).to match_array(["example1", "example2"])
+ expect(run_context.cookbook_collection.keys).to match_array(%w{example1 example2})
end
it "makes the run context available via static method on Chef" do
expect(cookbook_synchronizer).to receive(:sync_cookbooks)
expect_any_instance_of(Chef::RunContext).to receive(:load).with(policy_builder.run_list_expansion_ish)
+ expect_any_instance_of(Chef::CookbookCollection).to receive(:validate!)
+ expect_any_instance_of(Chef::CookbookCollection).to receive(:install_gems)
run_context = policy_builder.setup_run_context
expect(Chef.run_context).to eq(run_context)
end
@@ -689,14 +688,18 @@ describe Chef::PolicyBuilder::Policyfile do
before do
expect(http_api).to receive(:get).with(cookbook1_url).
- and_return(example1_cookbook_object)
+ and_return(example1_cookbook_data)
expect(http_api).to receive(:get).with(cookbook2_url).
+ and_return(example2_cookbook_data)
+
+ expect(Chef::CookbookVersion).to receive(:from_cb_artifact_data).with(example1_cookbook_data).
+ and_return(example1_cookbook_object)
+ expect(Chef::CookbookVersion).to receive(:from_cb_artifact_data).with(example2_cookbook_data).
and_return(example2_cookbook_object)
end
include_examples "fetching cookbooks when they exist"
end
-
end
context "when using native API mode (policy_document_native_api == true)" do
@@ -714,7 +717,6 @@ describe Chef::PolicyBuilder::Policyfile do
include_examples "fetching cookbooks when they don't exist"
end
-
context "when the cookbooks exist on the server" do
before do
@@ -733,7 +735,6 @@ describe Chef::PolicyBuilder::Policyfile do
end
-
end
end
diff --git a/spec/unit/policy_builder_spec.rb b/spec/unit/policy_builder_spec.rb
index 506911452c..674978ab63 100644
--- a/spec/unit/policy_builder_spec.rb
+++ b/spec/unit/policy_builder_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@getchef.com>)
-# Copyright:: Copyright 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/policy_builder'
+require "spec_helper"
+require "chef/policy_builder"
describe Chef::PolicyBuilder do
diff --git a/spec/unit/property/state_spec.rb b/spec/unit/property/state_spec.rb
index e7fee0387f..be19dd7ec2 100644
--- a/spec/unit/property/state_spec.rb
+++ b/spec/unit/property/state_spec.rb
@@ -1,4 +1,4 @@
-require 'support/shared/integration/integration_helper'
+require "support/shared/integration/integration_helper"
describe "Chef::Resource#identity and #state" do
include IntegrationSupport
@@ -26,15 +26,15 @@ describe "Chef::Resource#identity and #state" do
end
def self.english_join(values)
- return '<nothing>' if values.size == 0
+ return "<nothing>" if values.size == 0
return values[0].inspect if values.size == 1
"#{values[0..-2].map { |v| v.inspect }.join(", ")} and #{values[-1].inspect}"
end
def self.with_property(*properties, &block)
- tags_index = properties.find_index { |p| !p.is_a?(String)}
+ tags_index = properties.find_index { |p| !p.is_a?(String) }
if tags_index
- properties, tags = properties[0..tags_index-1], properties[tags_index..-1]
+ properties, tags = properties[0..tags_index - 1], properties[tags_index..-1]
else
tags = []
end
@@ -55,8 +55,8 @@ describe "Chef::Resource#identity and #state" do
it "name is the default identity" do
expect(resource_class.identity_properties).to eq [ Chef::Resource.properties[:name] ]
expect(Chef::Resource.properties[:name].identity?).to be_falsey
- expect(resource.name).to eq 'blah'
- expect(resource.identity).to eq 'blah'
+ expect(resource.name).to eq "blah"
+ expect(resource.identity).to eq "blah"
end
it "identity_properties :x changes the identity" do
@@ -65,11 +65,11 @@ describe "Chef::Resource#identity and #state" do
expect(Chef::Resource.properties[:name].identity?).to be_falsey
expect(resource_class.properties[:x].identity?).to be_truthy
- expect(resource.x 'woo').to eq 'woo'
- expect(resource.x).to eq 'woo'
+ expect(resource.x "woo").to eq "woo"
+ expect(resource.x).to eq "woo"
- expect(resource.name).to eq 'blah'
- expect(resource.identity).to eq 'woo'
+ expect(resource.name).to eq "blah"
+ expect(resource.identity).to eq "woo"
end
with_property ":y, identity: true" do
@@ -81,19 +81,19 @@ describe "Chef::Resource#identity and #state" do
end
it "only returns :x as identity" do
- resource.x 'foo'
- resource.y 'bar'
+ resource.x "foo"
+ resource.y "bar"
expect(resource_class.identity_properties).to eq [ resource_class.properties[:x] ]
- expect(resource.identity).to eq 'foo'
+ expect(resource.identity).to eq "foo"
end
it "does not flip y.desired_state off" do
- resource.x 'foo'
- resource.y 'bar'
+ resource.x "foo"
+ resource.y "bar"
expect(resource_class.state_properties).to eq [
resource_class.properties[:x],
- resource_class.properties[:y]
+ resource_class.properties[:y],
]
- expect(resource.state_for_resource_reporter).to eq(x: 'foo', y: 'bar')
+ expect(resource.state_for_resource_reporter).to eq(x: "foo", y: "bar")
end
end
end
@@ -106,14 +106,14 @@ describe "Chef::Resource#identity and #state" do
end
end
let(:subresource) do
- subresource_class.new('sub')
+ subresource_class.new("sub")
end
it "name is the default identity on the subclass" do
expect(subresource_class.identity_properties).to eq [ Chef::Resource.properties[:name] ]
expect(Chef::Resource.properties[:name].identity?).to be_falsey
- expect(subresource.name).to eq 'sub'
- expect(subresource.identity).to eq 'sub'
+ expect(subresource.name).to eq "sub"
+ expect(subresource.identity).to eq "sub"
end
context "With identity_properties :x on the superclass" do
@@ -128,8 +128,8 @@ describe "Chef::Resource#identity and #state" do
expect(Chef::Resource.properties[:name].identity?).to be_falsey
expect(subresource_class.properties[:x].identity?).to be_truthy
- subresource.x 'foo'
- expect(subresource.identity).to eq 'foo'
+ subresource.x "foo"
+ expect(subresource.identity).to eq "foo"
end
context "With property :y, identity: true on the subclass" do
@@ -141,11 +141,11 @@ describe "Chef::Resource#identity and #state" do
it "The subclass's identity includes both x and y" do
expect(subresource_class.identity_properties).to eq [
subresource_class.properties[:x],
- subresource_class.properties[:y]
+ subresource_class.properties[:y],
]
- subresource.x 'foo'
- subresource.y 'bar'
- expect(subresource.identity).to eq(x: 'foo', y: 'bar')
+ subresource.x "foo"
+ subresource.y "bar"
+ expect(subresource.identity).to eq(x: "foo", y: "bar")
end
end
@@ -157,19 +157,19 @@ describe "Chef::Resource#identity and #state" do
end
end
it "y is part of state" do
- subresource.x 'foo'
- subresource.y 'bar'
- expect(subresource.state_for_resource_reporter).to eq(x: 'foo', y: 'bar')
+ subresource.x "foo"
+ subresource.y "bar"
+ expect(subresource.state_for_resource_reporter).to eq(x: "foo", y: "bar")
expect(subresource_class.state_properties).to eq [
subresource_class.properties[:x],
- subresource_class.properties[:y]
+ subresource_class.properties[:y],
]
end
it "y is the identity" do
expect(subresource_class.identity_properties).to eq [ subresource_class.properties[:y] ]
- subresource.x 'foo'
- subresource.y 'bar'
- expect(subresource.identity).to eq 'bar'
+ subresource.x "foo"
+ subresource.y "bar"
+ expect(subresource.identity).to eq "bar"
end
it "y still has validation" do
expect { subresource.y 12 }.to raise_error Chef::Exceptions::ValidationFailed
@@ -191,8 +191,8 @@ describe "Chef::Resource#identity and #state" do
with_property ":x, desired_state: false" do
it "identity_properties does not change desired_state" do
resource_class.identity_properties :x
- resource.x 'hi'
- expect(resource.identity).to eq 'hi'
+ resource.x "hi"
+ expect(resource.identity).to eq "hi"
expect(resource_class.properties[:x].desired_state?).to be_falsey
expect(resource_class.state_properties).to eq []
expect(resource.state_for_resource_reporter).to eq({})
@@ -203,10 +203,11 @@ describe "Chef::Resource#identity and #state" do
before do
resource_class.class_eval do
def custom_property
- @blarghle ? @blarghle*3 : nil
+ @blarghle ? @blarghle * 3 : nil
end
+
def custom_property=(x)
- @blarghle = x*2
+ @blarghle = x * 2
end
end
end
@@ -227,7 +228,7 @@ describe "Chef::Resource#identity and #state" do
expect(resource.state_for_resource_reporter).to eq(custom_property: 6)
expect(resource_class.properties[:custom_property].desired_state?).to be_truthy
expect(resource_class.state_properties).to eq [
- resource_class.properties[:custom_property]
+ resource_class.properties[:custom_property],
]
end
it "identity_properties does not change custom_property's getter or setter" do
@@ -247,8 +248,8 @@ describe "Chef::Resource#identity and #state" do
with_property ":x, identity: true" do
it "name is only part of the identity if an identity attribute is defined" do
expect(resource_class.identity_properties).to eq [ resource_class.properties[:x] ]
- resource.x 'woo'
- expect(resource.identity).to eq 'woo'
+ resource.x "woo"
+ expect(resource.identity).to eq "woo"
end
end
@@ -262,29 +263,29 @@ describe "Chef::Resource#identity and #state" do
expect { resource_class.identity_attr }.to raise_error Chef::Exceptions::MultipleIdentityError
end
it "identity returns all identity values in a hash if multiple are defined" do
- resource.x 'foo'
- resource.y 'bar'
- resource.z 'baz'
- expect(resource.identity).to eq(x: 'foo', y: 'bar', z: 'baz')
+ resource.x "foo"
+ resource.y "bar"
+ resource.z "baz"
+ expect(resource.identity).to eq(x: "foo", y: "bar", z: "baz")
end
it "identity returns all values whether any value is set or not" do
- expect(resource.identity).to eq(x: 'xxx', y: 'yyy', z: 'zzz')
+ expect(resource.identity).to eq(x: "xxx", y: "yyy", z: "zzz")
end
it "identity_properties wipes out any other identity attributes if multiple are defined" do
resource_class.identity_properties :y
- resource.x 'foo'
- resource.y 'bar'
- resource.z 'baz'
- expect(resource.identity).to eq 'bar'
+ resource.x "foo"
+ resource.y "bar"
+ resource.z "baz"
+ expect(resource.identity).to eq "bar"
end
end
with_property ":x, identity: true, name_property: true" do
it "identity when x is not defined returns the value of x" do
- expect(resource.identity).to eq 'blah'
+ expect(resource.identity).to eq "blah"
end
it "state when x is not defined returns the value of x" do
- expect(resource.state_for_resource_reporter).to eq(x: 'blah')
+ expect(resource.state_for_resource_reporter).to eq(x: "blah")
end
end
end
@@ -304,7 +305,7 @@ describe "Chef::Resource#identity and #state" do
expect(resource_class.state_properties).to eq [
resource_class.properties[:x],
resource_class.properties[:y],
- resource_class.properties[:z]
+ resource_class.properties[:z],
]
expect(resource.state_for_resource_reporter).to eq(x: 1, y: 2, z: 3)
end
@@ -323,7 +324,7 @@ describe "Chef::Resource#identity and #state" do
resource.z 3
expect(resource_class.state_properties).to eq [
resource_class.properties[:x],
- resource_class.properties[:z]
+ resource_class.properties[:z],
]
expect(resource.state_for_resource_reporter).to eq(x: 1, z: 3)
end
@@ -353,10 +354,11 @@ describe "Chef::Resource#identity and #state" do
before do
resource_class.class_eval do
def x
- @blah*3
+ @blah * 3
end
+
def x=(value)
- @blah = value*2
+ @blah = value * 2
end
end
end
@@ -391,13 +393,13 @@ describe "Chef::Resource#identity and #state" do
expect(resource_class.properties[:x].desired_state?).to be_truthy
expect(resource_class.state_properties).to eq [
- resource_class.properties[:x]
+ resource_class.properties[:x],
]
expect(resource.state_for_resource_reporter).to eq(x: 10)
end
it "state_properties(:x) does not turn off validation" do
resource_class.state_properties(:x)
- expect { resource.x 'ouch' }.to raise_error Chef::Exceptions::ValidationFailed
+ expect { resource.x "ouch" }.to raise_error Chef::Exceptions::ValidationFailed
end
it "state_properties(:x) does not turn off identity" do
resource_class.state_properties(:x)
@@ -428,11 +430,11 @@ describe "Chef::Resource#identity and #state" do
expect(resource_class.properties[:x].desired_state?).to be_truthy
expect(resource_class.properties[:x].identity?).to be_truthy
expect(resource_class.identity_properties).to eq [
- resource_class.properties[:x]
+ resource_class.properties[:x],
]
expect(resource.identity).to eq(10)
expect(resource_class.state_properties).to eq [
- resource_class.properties[:x]
+ resource_class.properties[:x],
]
expect(resource.state_for_resource_reporter).to eq(x: 10)
end
@@ -446,7 +448,7 @@ describe "Chef::Resource#identity and #state" do
expect(resource_class.properties[:x].desired_state?).to be_falsey
expect(resource_class.properties[:y].desired_state?).to be_truthy
expect(resource_class.state_properties).to eq [
- resource_class.properties[:y]
+ resource_class.properties[:y],
]
expect(resource.state_for_resource_reporter).to eq(y: 20)
end
@@ -459,7 +461,7 @@ describe "Chef::Resource#identity and #state" do
end
end
let(:subresource) do
- subresource_class.new('blah')
+ subresource_class.new("blah")
end
it "state_properties(:x) adds x to desired state" do
@@ -472,11 +474,11 @@ describe "Chef::Resource#identity and #state" do
expect(subresource_class.properties[:x].desired_state?).to be_truthy
expect(subresource_class.properties[:x].identity?).to be_truthy
expect(subresource_class.identity_properties).to eq [
- subresource_class.properties[:x]
+ subresource_class.properties[:x],
]
expect(subresource.identity).to eq(10)
expect(subresource_class.state_properties).to eq [
- subresource_class.properties[:x]
+ subresource_class.properties[:x],
]
expect(subresource.state_for_resource_reporter).to eq(x: 10)
end
@@ -489,13 +491,13 @@ describe "Chef::Resource#identity and #state" do
expect(subresource_class.properties[:x].object_id).to eq old_value.object_id
expect(subresource_class.properties[:y].desired_state?).to be_truthy
expect(subresource_class.state_properties).to eq [
- subresource_class.properties[:y]
+ subresource_class.properties[:y],
]
expect(subresource.state_for_resource_reporter).to eq(y: 20)
expect(subresource_class.properties[:x].identity?).to be_truthy
expect(subresource_class.identity_properties).to eq [
- subresource_class.properties[:x]
+ subresource_class.properties[:x],
]
expect(subresource.identity).to eq(10)
end
diff --git a/spec/unit/property/validation_spec.rb b/spec/unit/property/validation_spec.rb
index 31bb3f0739..4e1b252863 100644
--- a/spec/unit/property/validation_spec.rb
+++ b/spec/unit/property/validation_spec.rb
@@ -1,4 +1,4 @@
-require 'support/shared/integration/integration_helper'
+require "support/shared/integration/integration_helper"
describe "Chef::Resource.property validation" do
include IntegrationSupport
@@ -8,12 +8,15 @@ describe "Chef::Resource.property validation" do
def self.next_resource_name
"chef_resource_property_spec_#{@i += 1}"
end
+
def self.reset_index
@current_index = 0
end
+
def self.current_index
@current_index
end
+
def self.next_index
@current_index += 1
end
@@ -38,6 +41,7 @@ describe "Chef::Resource.property validation" do
def blah
Namer.next_index
end
+
def self.blah
"class#{Namer.next_index}"
end
@@ -49,15 +53,15 @@ describe "Chef::Resource.property validation" do
end
def self.english_join(values)
- return '<nothing>' if values.size == 0
+ return "<nothing>" if values.size == 0
return values[0].inspect if values.size == 1
"#{values[0..-2].map { |v| v.inspect }.join(", ")} and #{values[-1].inspect}"
end
def self.with_property(*properties, &block)
- tags_index = properties.find_index { |p| !p.is_a?(String)}
+ tags_index = properties.find_index { |p| !p.is_a?(String) }
if tags_index
- properties, tags = properties[0..tags_index-1], properties[tags_index..-1]
+ properties, tags = properties[0..tags_index - 1], properties[tags_index..-1]
else
tags = []
end
@@ -72,14 +76,14 @@ describe "Chef::Resource.property validation" do
end
end
- def self.validation_test(validation, success_values, failure_values, getter_values=[], *tags)
+ def self.validation_test(validation, success_values, failure_values, *tags)
with_property ":x, #{validation}", *tags do
it "gets nil when retrieving the initial (non-set) value" do
expect(resource.x).to be_nil
end
success_values.each do |v|
it "value #{v.inspect} is valid" do
- resource.instance_eval { @x = 'default' }
+ resource.instance_eval { @x = "default" }
expect(resource.x v).to eq v
expect(resource.x).to eq v
end
@@ -87,16 +91,68 @@ describe "Chef::Resource.property validation" do
failure_values.each do |v|
it "value #{v.inspect} is invalid" do
expect { resource.x v }.to raise_error Chef::Exceptions::ValidationFailed
- resource.instance_eval { @x = 'default' }
+ resource.instance_eval { @x = "default" }
expect { resource.x v }.to raise_error Chef::Exceptions::ValidationFailed
end
end
- getter_values.each do |v|
- it "setting value to #{v.inspect} does not change the value" do
+ it "setting x to nil when it is already nil does not emit a warning" do
+ expect(resource.x nil).to be_nil
+ expect(resource.x).to be_nil
+ end
+ unless tags.include?(:nillable)
+ it "changing x to nil warns that the get will change to a set in Chef 13 and does not change the value" do
+ resource.instance_eval { @x = "default" }
+ expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+ /An attempt was made to change x from "default" to nil by calling x\(nil\). In Chef 12, this does a get rather than a set. In Chef 13, this will change to set the value to nil./
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(resource.x nil).to eq "default"
+ expect(resource.x).to eq "default"
+ end
+ end
+ end
+ if tags.include?(:nil_is_valid)
+ with_property ":x, #{validation}, default: nil" do
+ it "setting x to nil when it is already nil does not emit a warning" do
+ expect(resource.x nil).to be_nil
+ expect(resource.x).to be_nil
+ end
+ it "changing x to nil warns that the get will change to a set in Chef 13 and does not change the value" do
+ resource.instance_eval { @x = "default" }
+ expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+ /An attempt was made to change x from "default" to nil by calling x\(nil\). In Chef 12, this does a get rather than a set. In Chef 13, this will change to set the value to nil./
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(resource.x nil).to eq "default"
+ expect(resource.x).to eq "default"
+ end
+ end
+ elsif tags.include?(:nillable)
+ with_property ":x, #{validation}, nillable: true" do
+ it "changing x to nil with nillable true overwrites defaults and just works" do
+ resource.instance_eval { @x = "default" }
+ expect { resource.x nil }.not_to raise_error
+ expect(resource.x nil).to eq nil
+ expect(resource.x).to eq nil
+ end
+ end
+ else
+ it "property :x, #{validation}, default: nil warns that the default is invalid" do
+ expect { resource_class.class_eval("property :x, #{validation}, default: nil", __FILE__, __LINE__) }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+ /Default value nil is invalid for property x of resource chef_resource_property_spec_(\d+). Possible fixes: 1. Remove 'default: nil' if nil means 'undefined'. 2. Set a valid default value if there is a reasonable one. 3. Allow nil as a valid value of your property \(for example, 'property :x, \[ String, nil \], default: nil'\)./
+ end
+ context "With property :x, #{validation}, default: nil" do
+ before do
Chef::Config[:treat_deprecation_warnings_as_errors] = false
- resource.instance_eval { @x = 'default' }
- expect(resource.x v).to eq 'default'
- expect(resource.x).to eq 'default'
+ resource_class.class_eval("property :x, #{validation}, default: nil", __FILE__, __LINE__)
+ Chef::Config[:treat_deprecation_warnings_as_errors] = true
+ end
+
+ it "changing x to nil emits a warning that the value is invalid and does not change the value" do
+ resource.instance_eval { @x = "default" }
+ expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+ /nil is an invalid value for x of resource chef_resource_property_spec_(\d+). In Chef 13, this warning will change to an error./
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(resource.x nil).to eq "default"
+ expect(resource.x).to eq "default"
end
end
end
@@ -106,14 +162,14 @@ describe "Chef::Resource.property validation" do
with_property ":x, kind_of: String" do
context "when the variable already has a value" do
before do
- resource.instance_eval { @x = 'default' }
+ resource.instance_eval { @x = "default" }
end
it "get succeeds" do
- expect(resource.x).to eq 'default'
+ expect(resource.x).to eq "default"
end
it "set to valid value succeeds" do
- expect(resource.x 'str').to eq 'str'
- expect(resource.x).to eq 'str'
+ expect(resource.x "str").to eq "str"
+ expect(resource.x).to eq "str"
end
it "set to invalid value raises ValidationFailed" do
expect { resource.x 10 }.to raise_error Chef::Exceptions::ValidationFailed
@@ -121,9 +177,9 @@ describe "Chef::Resource.property validation" do
it "set to nil emits a deprecation warning and does a get" do
expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError
Chef::Config[:treat_deprecation_warnings_as_errors] = false
- resource.x 'str'
- expect(resource.x nil).to eq 'str'
- expect(resource.x).to eq 'str'
+ resource.x "str"
+ expect(resource.x nil).to eq "str"
+ expect(resource.x).to eq "str"
end
end
context "when the variable does not have an initial value" do
@@ -131,36 +187,35 @@ describe "Chef::Resource.property validation" do
expect(resource.x).to be_nil
end
it "set to valid value succeeds" do
- expect(resource.x 'str').to eq 'str'
- expect(resource.x).to eq 'str'
+ expect(resource.x "str").to eq "str"
+ expect(resource.x).to eq "str"
end
it "set to invalid value raises ValidationFailed" do
expect { resource.x 10 }.to raise_error Chef::Exceptions::ValidationFailed
end
- it "set to nil emits a deprecation warning and does a get" do
- expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError
- Chef::Config[:treat_deprecation_warnings_as_errors] = false
- resource.x 'str'
- expect(resource.x nil).to eq 'str'
- expect(resource.x).to eq 'str'
+ it "set to nil emits no warning because the value would not change" do
+ expect(resource.x nil).to be_nil
end
end
end
with_property ":x, [ String, nil ]" do
context "when the variable already has a value" do
before do
- resource.instance_eval { @x = 'default' }
+ resource.instance_eval { @x = "default" }
end
it "get succeeds" do
- expect(resource.x).to eq 'default'
+ expect(resource.x).to eq "default"
end
- it "set(nil) sets the value" do
- expect(resource.x nil).to be_nil
- expect(resource.x).to be_nil
+ it "set(nil) emits a warning that the value will be set, but does not set the value" do
+ expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+ /An attempt was made to change x from "default" to nil by calling x\(nil\). In Chef 12, this does a get rather than a set. In Chef 13, this will change to set the value to nil./
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(resource.x nil).to eq "default"
+ expect(resource.x).to eq "default"
end
it "set to valid value succeeds" do
- expect(resource.x 'str').to eq 'str'
- expect(resource.x).to eq 'str'
+ expect(resource.x "str").to eq "str"
+ expect(resource.x).to eq "str"
end
it "set to invalid value raises ValidationFailed" do
expect { resource.x 10 }.to raise_error Chef::Exceptions::ValidationFailed
@@ -175,8 +230,8 @@ describe "Chef::Resource.property validation" do
expect(resource.x).to be_nil
end
it "set to valid value succeeds" do
- expect(resource.x 'str').to eq 'str'
- expect(resource.x).to eq 'str'
+ expect(resource.x "str").to eq "str"
+ expect(resource.x).to eq "str"
end
it "set to invalid value raises ValidationFailed" do
expect { resource.x 10 }.to raise_error Chef::Exceptions::ValidationFailed
@@ -187,84 +242,79 @@ describe "Chef::Resource.property validation" do
# Bare types
context "bare types" do
- validation_test 'String',
- [ 'hi' ],
- [ 10 ],
- [ nil ]
+ validation_test "String",
+ [ "hi" ],
+ [ 10 ]
- validation_test ':a',
+ validation_test ":a",
[ :a ],
- [ :b ],
- [ nil ]
+ [ :b ]
- validation_test ':a, is: :b',
+ validation_test ":a, is: :b",
[ :a, :b ],
- [ :c ],
- [ nil ]
+ [ :c ]
- validation_test ':a, is: [ :b, :c ]',
+ validation_test ":a, is: [ :b, :c ]",
[ :a, :b, :c ],
- [ :d ],
- [ nil ]
+ [ :d ]
- validation_test '[ :a, :b ], is: :c',
+ validation_test "[ :a, :b ], is: :c",
[ :a, :b, :c ],
- [ :d ],
- [ nil ]
+ [ :d ]
- validation_test '[ :a, :b ], is: [ :c, :d ]',
+ validation_test "[ :a, :b ], is: [ :c, :d ]",
[ :a, :b, :c, :d ],
- [ :e ],
- [ nil ]
+ [ :e ]
- validation_test 'nil',
- [ nil ],
- [ :a ]
+ validation_test "nil",
+ [ ],
+ [ :a ],
+ :nil_is_valid
- validation_test '[ nil ]',
- [ nil ],
- [ :a ]
+ validation_test "[ nil ]",
+ [ ],
+ [ :a ],
+ :nil_is_valid
- validation_test '[]',
+ validation_test "[]",
[],
- [ :a ],
- [ nil ]
+ [ :a ]
+
+ validation_test "[ String, nil ], nillable: true",
+ [ nil, "thing" ],
+ [ :nope, false ],
+ :nillable
end
# is
context "is" do
# Class
- validation_test 'is: String',
- [ 'a', '' ],
- [ :a, 1 ],
- [ nil ]
+ validation_test "is: String",
+ [ "a", "" ],
+ [ :a, 1 ]
# Value
- validation_test 'is: :a',
+ validation_test "is: :a",
[ :a ],
- [ :b ],
- [ nil ]
+ [ :b ]
- validation_test 'is: [ :a, :b ]',
+ validation_test "is: [ :a, :b ]",
[ :a, :b ],
- [ [ :a, :b ] ],
- [ nil ]
+ [ [ :a, :b ] ]
- validation_test 'is: [ [ :a, :b ] ]',
+ validation_test "is: [ [ :a, :b ] ]",
[ [ :a, :b ] ],
- [ :a, :b ],
- [ nil ]
+ [ :a, :b ]
# Regex
- validation_test 'is: /abc/',
- [ 'abc', 'wowabcwow' ],
- [ '', 'abac' ],
- [ nil ]
+ validation_test "is: /abc/",
+ %w{abc wowabcwow},
+ [ "", "abac" ]
# Property
- validation_test 'is: Chef::Property.new(is: :a)',
+ validation_test "is: Chef::Property.new(is: :a)",
[ :a ],
- [ :b, nil ]
+ [ :b ]
# RSpec Matcher
class Globalses
@@ -273,260 +323,262 @@ describe "Chef::Resource.property validation" do
validation_test "is: Globalses.eq(10)",
[ 10 ],
- [ 1 ],
- [ nil ]
+ [ 1 ]
# Proc
- validation_test 'is: proc { |x| x }',
+ validation_test "is: proc { |x| x }",
[ true, 1 ],
- [ false ],
- [ nil ]
+ [ false ]
- validation_test 'is: proc { |x| x > blah }',
+ validation_test "is: proc { |x| x > blah }",
[ 10 ],
[ -1 ]
- validation_test 'is: nil',
- [ nil ],
- [ 'a' ]
+ validation_test "is: nil",
+ [ ],
+ [ "a" ],
+ :nil_is_valid
- validation_test 'is: [ String, nil ]',
- [ 'a', nil ],
- [ :b ]
+ validation_test "is: [ String, nil ]",
+ [ "a" ],
+ [ :b ],
+ :nil_is_valid
- validation_test 'is: []',
+ validation_test "is: []",
[],
- [ :a ],
- [ nil ]
+ [ :a ]
end
# Combination
context "combination" do
validation_test 'kind_of: String, equal_to: "a"',
- [ 'a' ],
- [ 'b' ],
- [ nil ]
+ [ "a" ],
+ [ "b" ],
+ :nil_is_valid
end
# equal_to
context "equal_to" do
# Value
- validation_test 'equal_to: :a',
+ validation_test "equal_to: :a",
[ :a ],
[ :b ],
- [ nil ]
+ :nil_is_valid
- validation_test 'equal_to: [ :a, :b ]',
+ validation_test "equal_to: [ :a, :b ]",
[ :a, :b ],
[ [ :a, :b ] ],
- [ nil ]
+ :nil_is_valid
- validation_test 'equal_to: [ [ :a, :b ] ]',
+ validation_test "equal_to: [ [ :a, :b ] ]",
[ [ :a, :b ] ],
[ :a, :b ],
- [ nil ]
+ :nil_is_valid
- validation_test 'equal_to: nil',
+ validation_test "equal_to: nil",
[ ],
- [ 'a' ],
- [ nil ]
+ [ "a" ],
+ :nil_is_valid
validation_test 'equal_to: [ "a", nil ]',
- [ 'a' ],
- [ 'b' ],
- [ nil ]
+ [ "a" ],
+ [ "b" ],
+ :nil_is_valid
validation_test 'equal_to: [ nil, "a" ]',
- [ 'a' ],
- [ 'b' ],
- [ nil ]
+ [ "a" ],
+ [ "b" ],
+ :nil_is_valid
- validation_test 'equal_to: []',
+ validation_test "equal_to: []",
[],
[ :a ],
- [ nil ]
+ :nil_is_valid
+
end
# kind_of
context "kind_of" do
- validation_test 'kind_of: String',
- [ 'a' ],
+ validation_test "kind_of: String",
+ [ "a" ],
[ :b ],
- [ nil ]
+ :nil_is_valid
- validation_test 'kind_of: [ String, Symbol ]',
- [ 'a', :b ],
+ validation_test "kind_of: [ String, Symbol ]",
+ [ "a", :b ],
[ 1 ],
- [ nil ]
+ :nil_is_valid
- validation_test 'kind_of: [ Symbol, String ]',
- [ 'a', :b ],
+ validation_test "kind_of: [ Symbol, String ]",
+ [ "a", :b ],
[ 1 ],
- [ nil ]
+ :nil_is_valid
- validation_test 'kind_of: NilClass',
+ validation_test "kind_of: NilClass",
[ ],
- [ 'a' ],
- [ nil ]
+ [ "a" ],
+ :nil_is_valid
- validation_test 'kind_of: [ NilClass, String ]',
- [ 'a' ],
+ validation_test "kind_of: [ NilClass, String ]",
+ [ "a" ],
[ :a ],
- [ nil ]
+ :nil_is_valid
- validation_test 'kind_of: []',
+ validation_test "kind_of: []",
[],
[ :a ],
- [ nil ]
+ :nil_is_valid
- validation_test 'kind_of: nil',
+ validation_test "kind_of: nil",
[],
[ :a ],
- [ nil ]
+ :nil_is_valid
end
# regex
context "regex" do
- validation_test 'regex: /abc/',
- [ 'xabcy' ],
- [ 'gbh', 123 ],
- [ nil ]
-
- validation_test 'regex: [ /abc/, /z/ ]',
- [ 'xabcy', 'aza' ],
- [ 'gbh', 123 ],
- [ nil ]
-
- validation_test 'regex: [ /z/, /abc/ ]',
- [ 'xabcy', 'aza' ],
- [ 'gbh', 123 ],
- [ nil ]
-
- validation_test 'regex: [ [ /z/, /abc/ ], [ /n/ ] ]',
- [ 'xabcy', 'aza', 'ana' ],
- [ 'gbh', 123 ],
- [ nil ]
-
- validation_test 'regex: []',
+ validation_test "regex: /abc/",
+ [ "xabcy" ],
+ [ "gbh", 123 ],
+ :nil_is_valid
+
+ validation_test "regex: [ /abc/, /z/ ]",
+ %w{xabcy aza},
+ [ "gbh", 123 ],
+ :nil_is_valid
+
+ validation_test "regex: [ /z/, /abc/ ]",
+ %w{xabcy aza},
+ [ "gbh", 123 ],
+ :nil_is_valid
+
+ validation_test "regex: [ [ /z/, /abc/ ], [ /n/ ] ]",
+ %w{xabcy aza ana},
+ [ "gbh", 123 ],
+ :nil_is_valid
+
+ validation_test "regex: []",
[],
[ :a ],
- [ nil ]
+ :nil_is_valid
- validation_test 'regex: nil',
+ validation_test "regex: nil",
[],
[ :a ],
- [ nil ]
+ :nil_is_valid
end
# callbacks
context "callbacks" do
validation_test 'callbacks: { "a" => proc { |x| x > 10 }, "b" => proc { |x| x%2 == 0 } }',
[ 12 ],
- [ 11, 4 ]
+ [ 11, 4 ],
+ :nil_is_valid
validation_test 'callbacks: { "a" => proc { |x| x%2 == 0 }, "b" => proc { |x| x > 10 } }',
[ 12 ],
- [ 11, 4 ]
+ [ 11, 4 ],
+ :nil_is_valid
validation_test 'callbacks: { "a" => proc { |x| x.nil? } }',
[ ],
- [ 'a' ],
- [ nil ]
+ [ "a" ],
+ :nil_is_valid
- validation_test 'callbacks: {}',
+ validation_test "callbacks: {}",
[ :a ],
[],
- [ nil ]
+ :nil_is_valid
end
# respond_to
context "respond_to" do
- validation_test 'respond_to: :split',
- [ 'hi' ],
+ validation_test "respond_to: :split",
+ [ "hi" ],
[ 1 ],
- [ nil ]
+ :nil_is_valid
validation_test 'respond_to: "split"',
- [ 'hi' ],
+ [ "hi" ],
[ 1 ],
- [ nil ]
+ :nil_is_valid
- validation_test 'respond_to: :to_s',
+ validation_test "respond_to: :to_s",
[ :a ],
[],
- [ nil ]
+ :nil_is_valid
- validation_test 'respond_to: [ :split, :to_s ]',
- [ 'hi' ],
+ validation_test "respond_to: [ :split, :to_s ]",
+ [ "hi" ],
[ 1 ],
- [ nil ]
+ :nil_is_valid
- validation_test 'respond_to: %w(split to_s)',
- [ 'hi' ],
+ validation_test "respond_to: %w(split to_s)",
+ [ "hi" ],
[ 1 ],
- [ nil ]
+ :nil_is_valid
- validation_test 'respond_to: [ :to_s, :split ]',
- [ 'hi' ],
- [ 1, ],
- [ nil ]
+ validation_test "respond_to: [ :to_s, :split ]",
+ [ "hi" ],
+ [ 1 ],
+ :nil_is_valid
- validation_test 'respond_to: []',
+ validation_test "respond_to: []",
[ :a ],
[],
- [ nil ]
+ :nil_is_valid
- validation_test 'respond_to: nil',
+ validation_test "respond_to: nil",
[ :a ],
[],
- [ nil ]
+ :nil_is_valid
end
context "cannot_be" do
- validation_test 'cannot_be: :empty',
- [ 1, [1,2], { a: 10 } ],
+ validation_test "cannot_be: :empty",
+ [ 1, [1, 2], { a: 10 } ],
[ [] ],
- [ nil ]
+ :nil_is_valid
validation_test 'cannot_be: "empty"',
- [ 1, [1,2], { a: 10 } ],
+ [ 1, [1, 2], { a: 10 } ],
[ [] ],
- [ nil ]
+ :nil_is_valid
- validation_test 'cannot_be: [ :empty, :nil ]',
- [ 1, [1,2], { a: 10 } ],
+ validation_test "cannot_be: [ :empty, :nil ]",
+ [ 1, [1, 2], { a: 10 } ],
[ [] ],
- [ nil ]
+ :nil_is_valid
validation_test 'cannot_be: [ "empty", "nil" ]',
- [ 1, [1,2], { a: 10 } ],
+ [ 1, [1, 2], { a: 10 } ],
[ [] ],
- [ nil ]
+ :nil_is_valid
- validation_test 'cannot_be: [ :nil, :empty ]',
- [ 1, [1,2], { a: 10 } ],
+ validation_test "cannot_be: [ :nil, :empty ]",
+ [ 1, [1, 2], { a: 10 } ],
[ [] ],
- [ nil ]
+ :nil_is_valid
- validation_test 'cannot_be: [ :empty, :nil, :blahblah ]',
- [ 1, [1,2], { a: 10 } ],
+ validation_test "cannot_be: [ :empty, :nil, :blahblah ]",
+ [ 1, [1, 2], { a: 10 } ],
[ [] ],
- [ nil ]
+ :nil_is_valid
- validation_test 'cannot_be: []',
+ validation_test "cannot_be: []",
[ :a ],
[],
- [ nil ]
+ :nil_is_valid
- validation_test 'cannot_be: nil',
+ validation_test "cannot_be: nil",
[ :a ],
[],
- [ nil ]
+ :nil_is_valid
end
context "required" do
- with_property ':x, required: true' do
+ with_property ":x, required: true" do
it "if x is not specified, retrieval fails" do
expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
end
@@ -534,35 +586,40 @@ describe "Chef::Resource.property validation" do
expect(resource.x 1).to eq 1
expect(resource.x).to eq 1
end
- it "value nil emits a deprecation warning and does a get" do
- expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError
- Chef::Config[:treat_deprecation_warnings_as_errors] = false
- resource.x 1
- expect(resource.x nil).to eq 1
- expect(resource.x).to eq 1
+ it "value nil emits a validation failed error because it must have a value" do
+ expect { resource.x nil }.to raise_error Chef::Exceptions::ValidationFailed
+ end
+ context "and value is set to something other than nil" do
+ before { resource.x 10 }
+ it "value nil emits a deprecation warning and does a get" do
+ expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ resource.x 1
+ expect(resource.x nil).to eq 1
+ expect(resource.x).to eq 1
+ end
end
end
- with_property ':x, [String, nil], required: true' do
+ with_property ":x, [String, nil], required: true" do
it "if x is not specified, retrieval fails" do
expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
end
- it "value nil is valid" do
- expect(resource.x nil).to be_nil
- expect(resource.x).to be_nil
+ it "value nil is not valid (required means 'not nil')" do
+ expect { resource.x nil }.to raise_error Chef::Exceptions::ValidationFailed
end
it "value '1' is valid" do
- expect(resource.x '1').to eq '1'
- expect(resource.x).to eq '1'
+ expect(resource.x "1").to eq "1"
+ expect(resource.x).to eq "1"
end
it "value 1 is invalid" do
expect { resource.x 1 }.to raise_error Chef::Exceptions::ValidationFailed
end
end
- with_property ':x, name_property: true, required: true' do
+ with_property ":x, name_property: true, required: true" do
it "if x is not specified, the name property is returned" do
- expect(resource.x).to eq 'blah'
+ expect(resource.x).to eq "blah"
end
it "value 1 is valid" do
expect(resource.x 1).to eq 1
@@ -577,7 +634,7 @@ describe "Chef::Resource.property validation" do
end
end
- with_property ':x, default: 10, required: true' do
+ with_property ":x, default: 10, required: true" do
it "if x is not specified, the default is returned" do
expect(resource.x).to eq 10
end
@@ -600,7 +657,7 @@ describe "Chef::Resource.property validation" do
Chef::Config[:treat_deprecation_warnings_as_errors] = false
end
- with_property ':x, blarghle: 1' do
+ with_property ":x, blarghle: 1" do
context "and a class that implements _pv_blarghle" do
before do
resource_class.class_eval do
@@ -619,7 +676,7 @@ describe "Chef::Resource.property validation" do
it "value '1' is invalid" do
Chef::Config[:treat_deprecation_warnings_as_errors] = false
- expect { resource.x '1' }.to raise_error Chef::Exceptions::ValidationFailed
+ expect { resource.x "1" }.to raise_error Chef::Exceptions::ValidationFailed
end
it "value nil does a get" do
@@ -631,7 +688,7 @@ describe "Chef::Resource.property validation" do
end
end
- with_property ':x, blarghle: 1' do
+ with_property ":x, blarghle: 1" do
context "and a class that implements _pv_blarghle" do
before do
resource_class.class_eval do
@@ -649,7 +706,7 @@ describe "Chef::Resource.property validation" do
end
it "value '1' is invalid" do
- expect { resource.x '1' }.to raise_error Chef::Exceptions::ValidationFailed
+ expect { resource.x "1" }.to raise_error Chef::Exceptions::ValidationFailed
end
it "value nil does a get" do
diff --git a/spec/unit/property_spec.rb b/spec/unit/property_spec.rb
index dc06cb3326..50ff3434f6 100644
--- a/spec/unit/property_spec.rb
+++ b/spec/unit/property_spec.rb
@@ -1,4 +1,4 @@
-require 'support/shared/integration/integration_helper'
+require "support/shared/integration/integration_helper"
describe "Chef::Resource.property" do
include IntegrationSupport
@@ -8,12 +8,15 @@ describe "Chef::Resource.property" do
def self.next_resource_name
"chef_resource_property_spec_#{@i += 1}"
end
+
def self.reset_index
@current_index = 0
end
+
def self.current_index
@current_index
end
+
def self.next_index
@current_index += 1
end
@@ -46,15 +49,15 @@ describe "Chef::Resource.property" do
end
def self.english_join(values)
- return '<nothing>' if values.size == 0
+ return "<nothing>" if values.size == 0
return values[0].inspect if values.size == 1
"#{values[0..-2].map { |v| v.inspect }.join(", ")} and #{values[-1].inspect}"
end
def self.with_property(*properties, &block)
- tags_index = properties.find_index { |p| !p.is_a?(String)}
+ tags_index = properties.find_index { |p| !p.is_a?(String) }
if tags_index
- properties, tags = properties[0..tags_index-1], properties[tags_index..-1]
+ properties, tags = properties[0..tags_index - 1], properties[tags_index..-1]
else
tags = []
end
@@ -74,7 +77,7 @@ describe "Chef::Resource.property" do
end
# Basic properties
- with_property ':bare_property' do
+ with_property ":bare_property" do
it "can be set" do
expect(resource.bare_property 10).to eq 10
expect(resource.bare_property).to eq 10
@@ -116,7 +119,7 @@ describe "Chef::Resource.property" do
end
end
let(:subresource) do
- subresource_class.new('blah')
+ subresource_class.new("blah")
end
context "with property :x on the subclass" do
@@ -127,7 +130,7 @@ describe "Chef::Resource.property" do
end
it "x is still name_property" do
- expect(subresource.x).to eq 'blah'
+ expect(subresource.x).to eq "blah"
end
end
@@ -166,7 +169,7 @@ describe "Chef::Resource.property" do
end
end
let(:subresource) do
- subresource_class.new('blah')
+ subresource_class.new("blah")
end
it "x is inherited" do
@@ -178,7 +181,7 @@ describe "Chef::Resource.property" do
end
it "x's validation is inherited" do
- expect { subresource.x 'ohno' }.to raise_error Chef::Exceptions::ValidationFailed
+ expect { subresource.x "ohno" }.to raise_error Chef::Exceptions::ValidationFailed
end
context "with property :y on the subclass" do
@@ -203,7 +206,7 @@ describe "Chef::Resource.property" do
expect(subresource_class.properties[:y]).not_to be_nil
end
it "y is not on the superclass" do
- expect { resource_class.y 10 }.to raise_error
+ expect { resource_class.y 10 }.to raise_error NoMethodError
expect(resource_class.properties[:y]).to be_nil
end
end
@@ -225,7 +228,7 @@ describe "Chef::Resource.property" do
end
it "x's validation is inherited" do
- expect { subresource.x 'ohno' }.to raise_error Chef::Exceptions::ValidationFailed
+ expect { subresource.x "ohno" }.to raise_error Chef::Exceptions::ValidationFailed
end
end
@@ -250,7 +253,7 @@ describe "Chef::Resource.property" do
end
it "x's validation is inherited" do
- expect { subresource.x 'ohno' }.to raise_error Chef::Exceptions::ValidationFailed
+ expect { subresource.x "ohno" }.to raise_error Chef::Exceptions::ValidationFailed
end
end
@@ -272,12 +275,12 @@ describe "Chef::Resource.property" do
it "x's validation is overwritten" do
expect { subresource.x 10 }.to raise_error Chef::Exceptions::ValidationFailed
- expect(subresource.x 'ohno').to eq 'ohno'
- expect(subresource.x).to eq 'ohno'
+ expect(subresource.x "ohno").to eq "ohno"
+ expect(subresource.x).to eq "ohno"
end
it "the superclass's validation for x is still there" do
- expect { resource.x 'ohno' }.to raise_error Chef::Exceptions::ValidationFailed
+ expect { resource.x "ohno" }.to raise_error Chef::Exceptions::ValidationFailed
expect(resource.x 10).to eq 10
expect(resource.x).to eq 10
end
@@ -297,7 +300,7 @@ describe "Chef::Resource.property" do
expect { resource.reset_property(:x) }.to raise_error(ArgumentError)
end
- with_property ':x' do
+ with_property ":x" do
it "when the resource is newly created, reset_property(:x) does nothing" do
expect(resource.property_is_set?(:x)).to be_falsey
resource.reset_property(:x)
@@ -313,7 +316,7 @@ describe "Chef::Resource.property" do
end
end
- with_property ':x, Integer' do
+ with_property ":x, Integer" do
it "when the resource is newly created, reset_property(:x) does nothing" do
expect(resource.property_is_set?(:x)).to be_falsey
resource.reset_property(:x)
@@ -329,7 +332,7 @@ describe "Chef::Resource.property" do
end
end
- with_property ':x, default: 10' do
+ with_property ":x, default: 10" do
it "when the resource is newly created, reset_property(:x) does nothing" do
expect(resource.property_is_set?(:x)).to be_falsey
resource.reset_property(:x)
@@ -344,7 +347,7 @@ describe "Chef::Resource.property" do
end
end
- with_property ':x, default: lazy { 10 }' do
+ with_property ":x, default: lazy { 10 }" do
it "when the resource is newly created, reset_property(:x) does nothing" do
expect(resource.property_is_set?(:x)).to be_falsey
resource.reset_property(:x)
@@ -369,7 +372,7 @@ describe "Chef::Resource.property" do
expect { resource.property_is_set?(:x) }.to raise_error(ArgumentError)
end
- with_property ':x' do
+ with_property ":x" do
it "when the resource is newly created, property_is_set?(:x) is false" do
expect(resource.property_is_set?(:x)).to be_falsey
end
@@ -391,7 +394,7 @@ describe "Chef::Resource.property" do
end
end
- with_property ':x, default: 10' do
+ with_property ":x, default: 10" do
it "when the resource is newly created, property_is_set?(:x) is false" do
expect(resource.property_is_set?(:x)).to be_falsey
end
@@ -413,7 +416,7 @@ describe "Chef::Resource.property" do
end
end
- with_property ':x, default: nil' do
+ with_property ":x, default: nil" do
it "when the resource is newly created, property_is_set?(:x) is false" do
expect(resource.property_is_set?(:x)).to be_falsey
end
@@ -435,7 +438,7 @@ describe "Chef::Resource.property" do
end
end
- with_property ':x, default: lazy { 10 }' do
+ with_property ":x, default: lazy { 10 }" do
it "when the resource is newly created, property_is_set?(:x) is false" do
expect(resource.property_is_set?(:x)).to be_falsey
end
@@ -455,7 +458,7 @@ describe "Chef::Resource.property" do
end
context "Chef::Resource::Property#default" do
- with_property ':x, default: 10' do
+ with_property ":x, default: 10" do
it "when x is set, it returns its value" do
expect(resource.x 20).to eq 20
expect(resource.property_is_set?(:x)).to be_truthy
@@ -479,33 +482,33 @@ describe "Chef::Resource.property" do
resource_name new_resource_name
end
end
- let(:subresource) { subresource_class.new('blah') }
+ let(:subresource) { subresource_class.new("blah") }
it "The default is inherited" do
expect(subresource.x).to eq 10
end
end
end
- with_property ':x, default: 10, identity: true' do
+ with_property ":x, default: 10, identity: true" do
it "when x is not set, it is included in identity" do
expect(resource.identity).to eq(10)
end
end
- with_property ':x, default: 1, identity: true', ':y, default: 2, identity: true' do
+ with_property ":x, default: 1, identity: true", ":y, default: 2, identity: true" do
it "when x is not set, it is still included in identity" do
resource.y 20
expect(resource.identity).to eq(x: 1, y: 20)
end
end
- with_property ':x, default: nil' do
+ with_property ":x, default: nil" do
it "when x is not set, it returns nil" do
expect(resource.x).to be_nil
end
end
- with_property ':x' do
+ with_property ":x" do
it "when x is not set, it returns nil" do
expect(resource.x).to be_nil
end
@@ -515,7 +518,7 @@ describe "Chef::Resource.property" do
context "(deprecations allowed)" do
before { Chef::Config[:treat_deprecation_warnings_as_errors] = false }
- with_property ':x, default: {}' do
+ with_property ":x, default: {}" do
it "when x is not set, it returns {}" do
expect(resource.x).to eq({})
end
@@ -525,12 +528,12 @@ describe "Chef::Resource.property" do
expect(resource.x.object_id).to eq(value.object_id)
end
it "Multiple instances of x receive the exact same value" do
- expect(resource.x.object_id).to eq(resource_class.new('blah2').x.object_id)
+ expect(resource.x.object_id).to eq(resource_class.new("blah2").x.object_id)
end
end
end
- with_property ':x, default: lazy { {} }' do
+ with_property ":x, default: lazy { {} }" do
it "when x is not set, it returns {}" do
expect(resource.x).to eq({})
end
@@ -540,7 +543,7 @@ describe "Chef::Resource.property" do
# expect(resource.x.object_id).not_to eq(value.object_id)
# end
it "Multiple instances of x receive different values" do
- expect(resource.x.object_id).not_to eq(resource_class.new('blah2').x.object_id)
+ expect(resource.x.object_id).not_to eq(resource_class.new("blah2").x.object_id)
end
end
end
@@ -549,21 +552,22 @@ describe "Chef::Resource.property" do
before do
resource_class.class_eval do
def self.blah
- 'class'
+ "class"
end
+
def blah
"#{name}#{next_index}"
end
end
end
- with_property ':x, default: lazy { blah }' do
+ with_property ":x, default: lazy { blah }" do
it "x is run in context of the instance" do
expect(resource.x).to eq "blah1"
end
it "x is run in the context of each instance it is run in" do
expect(resource.x).to eq "blah1"
- expect(resource_class.new('another').x).to eq "another2"
+ expect(resource_class.new("another").x).to eq "another2"
# expect(resource.x).to eq "blah3"
end
end
@@ -574,27 +578,31 @@ describe "Chef::Resource.property" do
end
it "x is passed the value of each instance it is run in" do
expect(resource.x).to eq "classblah1"
- expect(resource_class.new('another').x).to eq "classanother2"
+ expect(resource_class.new("another").x).to eq "classanother2"
# expect(resource.x).to eq "classblah3"
end
end
end
context "validation of defaults" do
- with_property ':x, String, default: 10' do
- it "when the resource is created, no error is raised" do
- resource
+ it "When a class is declared with property :x, String, default: 10, a warning is emitted" do
+ expect { resource_class.class_eval { property :x, String, default: 10 } }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+ /Default value 10 is invalid for property x of resource chef_resource_property_spec_(\d+). In Chef 13 this will become an error: Property x must be one of: String! You passed 10./
+ end
+ context "With property :x, String, default: 10" do
+ before do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ resource_class.class_eval { property :x, String, default: 10 }
+ Chef::Config[:treat_deprecation_warnings_as_errors] = true
end
+
it "when x is set, no error is raised" do
- expect(resource.x 'hi').to eq 'hi'
- expect(resource.x).to eq 'hi'
+ expect(resource.x "hi").to eq "hi"
+ expect(resource.x).to eq "hi"
end
it "when x is retrieved, no validation error is raised" do
expect(resource.x).to eq 10
end
- # it "when x is retrieved, a validation error is raised" do
- # expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
- # end
end
with_property ":x, String, default: lazy { Namer.next_index }" do
@@ -602,43 +610,34 @@ describe "Chef::Resource.property" do
resource
end
it "when x is set, no error is raised" do
- expect(resource.x 'hi').to eq 'hi'
- expect(resource.x).to eq 'hi'
+ expect(resource.x "hi").to eq "hi"
+ expect(resource.x).to eq "hi"
end
- it "when x is retrieved, no validation error is raised" do
- expect(resource.x).to eq 1
+ it "when x is retrieved, an invalid default warning is emitted and the value is returned" do
+ expect { resource.x }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+ /Default value 1 is invalid for property x of resource chef_resource_property_spec_(\d+). In Chef 13 this will become an error: Property x must be one of: String! You passed 1./
expect(Namer.current_index).to eq 1
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(resource.x).to eq 2
end
- # it "when x is retrieved, a validation error is raised" do
- # expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
- # expect(Namer.current_index).to eq 1
- # end
end
with_property ":x, default: lazy { Namer.next_index.to_s }, is: proc { |v| Namer.next_index; true }" do
- it "validation is not run at all on the default value" do
- expect(resource.x).to eq '1'
- expect(Namer.current_index).to eq 1
+ it "coercion and validation is only run the first time" do
+ expect(resource.x).to eq "1"
+ expect(Namer.current_index).to eq 2
+ expect(resource.x).to eq "1"
+ expect(Namer.current_index).to eq 2
end
- # it "validation is run each time" do
- # expect(resource.x).to eq '1'
- # expect(Namer.current_index).to eq 2
- # expect(resource.x).to eq '1'
- # expect(Namer.current_index).to eq 2
- # end
end
with_property ":x, default: lazy { Namer.next_index.to_s.freeze }, is: proc { |v| Namer.next_index; true }" do
- it "validation is not run at all on the default value" do
- expect(resource.x).to eq '1'
- expect(Namer.current_index).to eq 1
+ it "coercion and validation is run each time" do
+ expect(resource.x).to eq "1"
+ expect(Namer.current_index).to eq 2
+ expect(resource.x).to eq "3"
+ expect(Namer.current_index).to eq 4
end
- # it "validation is only run the first time" do
- # expect(resource.x).to eq '1'
- # expect(Namer.current_index).to eq 2
- # expect(resource.x).to eq '1'
- # expect(Namer.current_index).to eq 2
- # end
end
end
@@ -650,13 +649,13 @@ describe "Chef::Resource.property" do
expect(Namer.current_index).to eq 0
end
it "when x is set, coercion is run" do
- expect(resource.x 'hi').to eq 'hi1'
- expect(resource.x).to eq 'hi1'
+ expect(resource.x "hi").to eq "hi1"
+ expect(resource.x).to eq "hi1"
expect(Namer.current_index).to eq 1
end
it "when x is retrieved, coercion is run exactly once" do
- expect(resource.x).to eq '101'
- expect(resource.x).to eq '101'
+ expect(resource.x).to eq "101"
+ expect(resource.x).to eq "101"
expect(Namer.current_index).to eq 1
end
end
@@ -668,13 +667,13 @@ describe "Chef::Resource.property" do
expect(Namer.current_index).to eq 0
end
it "when x is set, coercion is run" do
- expect(resource.x 'hi').to eq 'hi1'
- expect(resource.x).to eq 'hi1'
+ expect(resource.x "hi").to eq "hi1"
+ expect(resource.x).to eq "hi1"
expect(Namer.current_index).to eq 1
end
it "when x is retrieved, coercion is run each time" do
- expect(resource.x).to eq '101'
- expect(resource.x).to eq '102'
+ expect(resource.x).to eq "101"
+ expect(resource.x).to eq "102"
expect(Namer.current_index).to eq 2
end
end
@@ -686,13 +685,13 @@ describe "Chef::Resource.property" do
expect(Namer.current_index).to eq 0
end
it "when x is set, coercion is run" do
- expect(resource.x 'hi').to eq 'hi1'
- expect(resource.x).to eq 'hi1'
+ expect(resource.x "hi").to eq "hi1"
+ expect(resource.x).to eq "hi1"
expect(Namer.current_index).to eq 1
end
it "when x is retrieved, coercion is run exactly once" do
- expect(resource.x).to eq '101'
- expect(resource.x).to eq '101'
+ expect(resource.x).to eq "101"
+ expect(resource.x).to eq "101"
expect(Namer.current_index).to eq 1
end
end
@@ -704,61 +703,61 @@ describe "Chef::Resource.property" do
expect(Namer.current_index).to eq 0
end
it "when x is set, coercion is run" do
- expect(resource.x 'hi').to eq 'hi1'
- expect(resource.x).to eq 'hi1'
+ expect(resource.x "hi").to eq "hi1"
+ expect(resource.x).to eq "hi1"
expect(Namer.current_index).to eq 1
end
it "when x is retrieved, coercion is run each time" do
- expect(resource.x).to eq '101'
- expect(resource.x).to eq '102'
+ expect(resource.x).to eq "101"
+ expect(resource.x).to eq "102"
expect(Namer.current_index).to eq 2
end
end
with_property ':x, proc { |v| Namer.next_index; true }, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
- it "coercion is only run the first time x is retrieved, and validation is not run" do
+ it "coercion and validation is only run the first time x is retrieved" do
expect(Namer.current_index).to eq 0
- expect(resource.x).to eq '101'
- expect(Namer.current_index).to eq 1
- expect(resource.x).to eq '101'
- expect(Namer.current_index).to eq 1
+ expect(resource.x).to eq "101"
+ expect(Namer.current_index).to eq 2
+ expect(resource.x).to eq "101"
+ expect(Namer.current_index).to eq 2
end
end
context "validation and coercion of defaults" do
with_property ':x, String, coerce: proc { |v| "#{v}#{next_index}" }, default: 10' do
it "when x is retrieved, it is coerced before validating and passes" do
- expect(resource.x).to eq '101'
+ expect(resource.x).to eq "101"
end
end
with_property ':x, Integer, coerce: proc { |v| "#{v}#{next_index}" }, default: 10' do
- it "when x is retrieved, it is coerced and not validated" do
- expect(resource.x).to eq '101'
+ it "when x is retrieved, it is coerced and emits an invalid default warning, but still returns the value" do
+ expect { resource.x }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+ /Default value 10 is invalid for property x of resource chef_resource_property_spec_(\d+). In Chef 13 this will become an error: Property x must be one of: Integer! You passed "101"./
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(resource.x).to eq "102"
end
- # it "when x is retrieved, it is coerced before validating and fails" do
- # expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
- # end
end
with_property ':x, String, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
it "when x is retrieved, it is coerced before validating and passes" do
- expect(resource.x).to eq '101'
+ expect(resource.x).to eq "101"
end
end
with_property ':x, Integer, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
- it "when x is retrieved, it is coerced and not validated" do
- expect(resource.x).to eq '101'
+ it "when x is retrieved, it is coerced and emits an invalid default warning; the value is still returned." do
+ expect { resource.x }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+ /Default value 10 is invalid for property x of resource chef_resource_property_spec_(\d+). In Chef 13 this will become an error: Property x must be one of: Integer! You passed "101"./
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(resource.x).to eq "102"
end
- # it "when x is retrieved, it is coerced before validating and fails" do
- # expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
- # end
end
with_property ':x, proc { |v| Namer.next_index; true }, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
- it "coercion is only run the first time x is retrieved, and validation is not run" do
+ it "coercion is only run the first time x is retrieved, and validation is run" do
expect(Namer.current_index).to eq 0
- expect(resource.x).to eq '101'
- expect(Namer.current_index).to eq 1
- expect(resource.x).to eq '101'
- expect(Namer.current_index).to eq 1
+ expect(resource.x).to eq "101"
+ expect(Namer.current_index).to eq 2
+ expect(resource.x).to eq "101"
+ expect(Namer.current_index).to eq 2
end
end
end
@@ -766,7 +765,7 @@ describe "Chef::Resource.property" do
end
context "Chef::Resource#lazy" do
- with_property ':x' do
+ with_property ":x" do
it "setting x to a lazy value does not run it immediately" do
resource.x lazy { Namer.next_index }
expect(Namer.current_index).to eq 0
@@ -805,6 +804,7 @@ describe "Chef::Resource.property" do
def self.blah
"class"
end
+
def blah
"#{name}#{Namer.next_index}"
end
@@ -861,7 +861,7 @@ describe "Chef::Resource.property" do
end
end
- with_property ':x, String' do
+ with_property ":x, String" do
it "lazy values are not validated on set" do
resource.x lazy { Namer.next_index }
expect(Namer.current_index).to eq 0
@@ -873,7 +873,7 @@ describe "Chef::Resource.property" do
end
end
- with_property ':x, is: proc { |v| Namer.next_index; true }' do
+ with_property ":x, is: proc { |v| Namer.next_index; true }" do
it "lazy values are validated on each access" do
resource.x lazy { Namer.next_index }
expect(resource.x).to eq 1
@@ -922,7 +922,8 @@ describe "Chef::Resource.property" do
expect(Namer.current_index).to eq 1
end
it "does not emit a deprecation warning if set to nil" do
- expect(resource.x nil).to eq "1"
+ # nil is never coerced
+ expect(resource.x nil).to be_nil
end
it "coercion sets the value (and coercion does not run on get)" do
expect(resource.x 10).to eq "101"
@@ -936,7 +937,7 @@ describe "Chef::Resource.property" do
expect(Namer.current_index).to eq 2
end
end
- with_property ':x, coerce: proc { |x| x }' do
+ with_property ":x, coerce: proc { |x| x }" do
it "does not emit a deprecation warning if set to nil" do
expect(resource.x nil).to be_nil
end
@@ -946,19 +947,19 @@ describe "Chef::Resource.property" do
resource.x 20
expect(resource.x).to eq 20
expect(Namer.current_index).to eq 2
- expect { resource.x 10 }.to raise_error 'hi'
+ expect { resource.x 10 }.to raise_error "hi"
expect(resource.x).to eq 20
expect(Namer.current_index).to eq 3
end
it "validation does not run if coercion fails" do
- expect { resource.x 10 }.to raise_error 'hi'
+ expect { resource.x 10 }.to raise_error "hi"
expect(Namer.current_index).to eq 1
end
end
end
context "Chef::Resource::Property validation" do
- with_property ':x, is: proc { |v| Namer.next_index; v.is_a?(Integer) }' do
+ with_property ":x, is: proc { |v| Namer.next_index; v.is_a?(Integer) }" do
it "validation runs on set" do
expect(resource.x 10).to eq 10
expect(Namer.current_index).to eq 1
@@ -977,31 +978,31 @@ describe "Chef::Resource.property" do
it "failed validation fails to set the value" do
expect(resource.x 10).to eq 10
expect(Namer.current_index).to eq 1
- expect { resource.x 'blah' }.to raise_error Chef::Exceptions::ValidationFailed
+ expect { resource.x "blah" }.to raise_error Chef::Exceptions::ValidationFailed
expect(resource.x).to eq 10
expect(Namer.current_index).to eq 2
end
end
end
- [ 'name_attribute', 'name_property' ].each do |name|
+ %w{name_attribute name_property}.each do |name|
context "Chef::Resource::Property##{name}" do
with_property ":x, #{name}: true" do
it "defaults x to resource.name" do
- expect(resource.x).to eq 'blah'
+ expect(resource.x).to eq "blah"
end
it "does not pick up resource.name if set" do
expect(resource.x 10).to eq 10
expect(resource.x).to eq 10
end
it "binds to the latest resource.name when run" do
- resource.name 'foo'
- expect(resource.x).to eq 'foo'
+ resource.name "foo"
+ expect(resource.x).to eq "foo"
end
it "caches resource.name" do
- expect(resource.x).to eq 'blah'
- resource.name 'foo'
- expect(resource.x).to eq 'blah'
+ expect(resource.x).to eq "blah"
+ resource.name "foo"
+ expect(resource.x).to eq "blah"
end
end
@@ -1045,17 +1046,17 @@ describe "Chef::Resource.property" do
end
with_property ":x, default: nil, #{name}: true" do
it "chooses #{name} over default" do
- expect(resource.x).to eq 'blah'
+ expect(resource.x).to eq "blah"
end
end
with_property ":x, #{name}: true, default: 10" do
it "chooses #{name} over default" do
- expect(resource.x).to eq 'blah'
+ expect(resource.x).to eq "blah"
end
end
with_property ":x, #{name}: true, default: nil" do
it "chooses #{name} over default" do
- expect(resource.x).to eq 'blah'
+ expect(resource.x).to eq "blah"
end
end
end
@@ -1099,4 +1100,128 @@ describe "Chef::Resource.property" do
expect { resource_class.property :x, :name_property => true, :name_attribute => true }.to raise_error ArgumentError,
/Cannot specify both name_property and name_attribute together on property x of resource chef_resource_property_spec_(\d+)./
end
+
+ context "property_type" do
+ it "property_types validate their defaults" do
+ expect do
+ module ::PropertySpecPropertyTypes
+ include Chef::Mixin::Properties
+ property_type(is: [:a, :b], default: :c)
+ end
+ end.to raise_error(Chef::Exceptions::DeprecatedFeatureError, /Default value :c is invalid for property <property type>./)
+ expect do
+ module ::PropertySpecPropertyTypes
+ include Chef::Mixin::Properties
+ property_type(is: [:a, :b], default: :b)
+ end
+ end.not_to raise_error
+ end
+
+ context "With property_type ABType (is: [:a, :b]) and CDType (is: [:c, :d])" do
+ before :all do
+ module ::PropertySpecPropertyTypes
+ include Chef::Mixin::Properties
+ ABType = property_type(is: [:a, :b])
+ CDType = property_type(is: [:c, :d])
+ end
+ end
+
+ with_property ":x, [PropertySpecPropertyTypes::ABType, nil, PropertySpecPropertyTypes::CDType]" do
+ it "The property can be set to nil without triggering a warning" do
+ expect(resource.x nil).to be_nil
+ expect(resource.x).to be_nil
+ end
+ it "The property can be set to :a" do
+ expect(resource.x :a).to eq(:a)
+ expect(resource.x).to eq(:a)
+ end
+ it "The property can be set to :c" do
+ expect(resource.x :c).to eq(:c)
+ expect(resource.x).to eq(:c)
+ end
+ it "The property cannot be set to :z" do
+ expect { resource.x :z }.to raise_error(Chef::Exceptions::ValidationFailed, /Property x must be one of/)
+ end
+ end
+
+ with_property ":x, [nil, PropertySpecPropertyTypes::ABType, PropertySpecPropertyTypes::CDType]" do
+ it "The property can be set to nil without triggering a warning" do
+ expect(resource.x nil).to be_nil
+ expect(resource.x).to be_nil
+ end
+ it "The property can be set to :a" do
+ expect(resource.x :a).to eq(:a)
+ expect(resource.x).to eq(:a)
+ end
+ it "The property can be set to :c" do
+ expect(resource.x :c).to eq(:c)
+ expect(resource.x).to eq(:c)
+ end
+ it "The property cannot be set to :z" do
+ expect { resource.x :z }.to raise_error(Chef::Exceptions::ValidationFailed, /Property x must be one of/)
+ end
+ end
+
+ with_property ":x, [PropertySpecPropertyTypes::ABType, nil], default: nil" do
+ it "The value defaults to nil" do
+ expect(resource.x).to be_nil
+ end
+ end
+
+ with_property ":x, [PropertySpecPropertyTypes::ABType, nil], default: lazy { nil }" do
+ it "The value defaults to nil" do
+ expect(resource.x).to be_nil
+ end
+ end
+ end
+
+ end
+
+ context "with a custom property type" do
+ class CustomPropertyType < Chef::Property
+ end
+
+ with_property ":x, CustomPropertyType.new" do
+ it "creates x with the given type" do
+ expect(resource_class.properties[:x]).to be_kind_of(CustomPropertyType)
+ end
+
+ context "and a subclass" do
+ let(:subresource_class) do
+ new_resource_name = self.class.new_resource_name
+ Class.new(resource_class) do
+ resource_name new_resource_name
+ end
+ end
+ let(:subresource) do
+ subresource_class.new("blah")
+ end
+
+ context "with property :x, default: 10 on the subclass" do
+ before do
+ subresource_class.class_eval do
+ property :x, default: 10
+ end
+ end
+
+ it "x has the given type and default on the subclass" do
+ expect(subresource_class.properties[:x]).to be_kind_of(CustomPropertyType)
+ expect(subresource_class.properties[:x].default).to eq(10)
+ end
+
+ it "x does not have the default on the superclass" do
+ expect(resource_class.properties[:x]).to be_kind_of(CustomPropertyType)
+ expect(resource_class.properties[:x].default).to be_nil
+ end
+ end
+ end
+ end
+
+ with_property ":x, CustomPropertyType.new, default: 10" do
+ it "passes the default to the custom property type" do
+ expect(resource_class.properties[:x]).to be_kind_of(CustomPropertyType)
+ expect(resource_class.properties[:x].default).to eq(10)
+ end
+ end
+ end
end
diff --git a/spec/unit/provider/apt_repository_spec.rb b/spec/unit/provider/apt_repository_spec.rb
new file mode 100644
index 0000000000..d8f2c85cb7
--- /dev/null
+++ b/spec/unit/provider/apt_repository_spec.rb
@@ -0,0 +1,183 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+APT_KEY_FINGER = <<-EOF
+/etc/apt/trusted.gpg
+--------------------
+pub 1024D/437D05B5 2004-09-12
+ Key fingerprint = 6302 39CC 130E 1A7F D81A 27B1 4097 6EAF 437D 05B5
+uid Ubuntu Archive Automatic Signing Key <ftpmaster@ubuntu.com>
+sub 2048g/79164387 2004-09-12
+
+pub 1024D/FBB75451 2004-12-30
+ Key fingerprint = C598 6B4F 1257 FFA8 6632 CBA7 4618 1433 FBB7 5451
+uid Ubuntu CD Image Automatic Signing Key <cdimage@ubuntu.com>
+
+pub 4096R/C0B21F32 2012-05-11
+ Key fingerprint = 790B C727 7767 219C 42C8 6F93 3B4F E6AC C0B2 1F32
+uid Ubuntu Archive Automatic Signing Key (2012) <ftpmaster@ubuntu.com>
+
+pub 4096R/EFE21092 2012-05-11
+ Key fingerprint = 8439 38DF 228D 22F7 B374 2BC0 D94A A3F0 EFE2 1092
+uid Ubuntu CD Image Automatic Signing Key (2012) <cdimage@ubuntu.com>
+
+EOF
+
+GPG_FINGER = <<-EOF
+pub 1024D/02A818DD 2009-04-22 Cloudera Apt Repository
+ Key fingerprint = F36A 89E3 3CC1 BD0F 7107 9007 3275 74EE 02A8 18DD
+sub 2048g/D1CA74A1 2009-04-22
+EOF
+
+describe Chef::Provider::AptRepository do
+ let(:new_resource) { Chef::Resource::AptRepository.new("multiverse") }
+
+ let(:shellout_env) { { env: { "LANG" => "en_US", "LANGUAGE" => "en_US" } } }
+ let(:provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::AptRepository.new(new_resource, run_context)
+ end
+
+ let(:apt_key_finger) do
+ r = double("Mixlib::ShellOut", stdout: APT_KEY_FINGER, exitstatus: 0, live_stream: true)
+ allow(r).to receive(:run_command)
+ r
+ end
+
+ let(:gpg_finger) do
+ r = double("Mixlib::ShellOut", stdout: GPG_FINGER, exitstatus: 0, live_stream: true)
+ allow(r).to receive(:run_command)
+ r
+ end
+
+ let(:apt_fingerprints) do
+ %w{630239CC130E1A7FD81A27B140976EAF437D05B5
+C5986B4F1257FFA86632CBA746181433FBB75451
+790BC7277767219C42C86F933B4FE6ACC0B21F32
+843938DF228D22F7B3742BC0D94AA3F0EFE21092}
+ end
+
+ it "responds to load_current_resource" do
+ expect(provider).to respond_to(:load_current_resource)
+ end
+
+ describe "#is_key_id?" do
+ it "should detect a key" do
+ expect(provider.is_key_id?("A4FF2279")).to be_truthy
+ end
+ it "should detect a key with a hex signifier" do
+ expect(provider.is_key_id?("0xA4FF2279")).to be_truthy
+ end
+ it "should reject a key with the wrong length" do
+ expect(provider.is_key_id?("4FF2279")).to be_falsey
+ end
+ it "should reject a key with non-hex characters" do
+ expect(provider.is_key_id?("A4KF2279")).to be_falsey
+ end
+ end
+
+ describe "#extract_fingerprints_from_cmd" do
+ before do
+ expect(Mixlib::ShellOut).to receive(:new).and_return(apt_key_finger)
+ end
+
+ it "should run the desired command" do
+ expect(apt_key_finger).to receive(:run_command)
+ provider.extract_fingerprints_from_cmd("apt-key finger")
+ end
+
+ it "should return a list of key fingerprints" do
+ expect(provider.extract_fingerprints_from_cmd("apt-key finger")).to eql(apt_fingerprints)
+ end
+ end
+
+ describe "#no_new_keys?" do
+ before do
+ allow(provider).to receive(:extract_fingerprints_from_cmd).with("apt-key finger").and_return(apt_fingerprints)
+ end
+
+ let(:file) { "/tmp/remote-gpg-keyfile" }
+
+ it "should match a set of keys" do
+ allow(provider).to receive(:extract_fingerprints_from_cmd).with("gpg --with-fingerprint #{file}").and_return(Array(apt_fingerprints.first))
+ expect(provider.no_new_keys?(file)).to be_truthy
+ end
+
+ it "should notice missing keys" do
+ allow(provider).to receive(:extract_fingerprints_from_cmd).with("gpg --with-fingerprint #{file}").and_return(%w{ F36A89E33CC1BD0F71079007327574EE02A818DD })
+ expect(provider.no_new_keys?(file)).to be_falsey
+ end
+ end
+
+ describe "#install_ppa_key" do
+ let(:url) { "https://launchpad.net/api/1.0/~chef/+archive/main" }
+ let(:key) { "C5986B4F1257FFA86632CBA746181433FBB75451" }
+
+ it "should get a key" do
+ simples = double("HTTP")
+ allow(simples).to receive(:get).and_return("\"#{key}\"")
+ expect(Chef::HTTP::Simple).to receive(:new).with(url).and_return(simples)
+ expect(provider).to receive(:install_key_from_keyserver).with(key, "keyserver.ubuntu.com")
+ provider.install_ppa_key("chef", "main")
+ end
+ end
+
+ describe "#make_ppa_url" do
+ it "should ignore non-ppa repositories" do
+ expect(provider.make_ppa_url("some_string")).to be_nil
+ end
+
+ it "should create a URL" do
+ expect(provider).to receive(:install_ppa_key).with("chef", "main").and_return(true)
+ expect(provider.make_ppa_url("ppa:chef/main")).to eql("http://ppa.launchpad.net/chef/main/ubuntu")
+ end
+ end
+
+ describe "#build_repo" do
+ it "should create a repository string" do
+ target = %Q{deb "http://test/uri" unstable main\n}
+ expect(provider.build_repo("http://test/uri", "unstable", "main", false, nil)).to eql(target)
+ end
+
+ it "should create a repository string with no distribution" do
+ target = %Q{deb "http://test/uri" main\n}
+ expect(provider.build_repo("http://test/uri", nil, "main", false, nil)).to eql(target)
+ end
+
+ it "should create a repository string with source" do
+ target = %Q{deb "http://test/uri" unstable main\ndeb-src "http://test/uri" unstable main\n}
+ expect(provider.build_repo("http://test/uri", "unstable", "main", false, nil, true)).to eql(target)
+ end
+
+ it "should create a repository string with options" do
+ target = %Q{deb [trusted=yes] "http://test/uri" unstable main\n}
+ expect(provider.build_repo("http://test/uri", "unstable", "main", true, nil)).to eql(target)
+ end
+
+ it "should handle a ppa repo" do
+ target = %Q{deb "http://ppa.launchpad.net/chef/main/ubuntu" unstable main\n}
+ expect(provider).to receive(:make_ppa_url).with("ppa:chef/main").and_return("http://ppa.launchpad.net/chef/main/ubuntu")
+ expect(provider.build_repo("ppa:chef/main", "unstable", "main", false, nil)).to eql(target)
+ end
+ end
+
+end
diff --git a/spec/unit/provider/apt_update_spec.rb b/spec/unit/provider/apt_update_spec.rb
new file mode 100644
index 0000000000..351a10051c
--- /dev/null
+++ b/spec/unit/provider/apt_update_spec.rb
@@ -0,0 +1,114 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::AptUpdate do
+ let(:new_resource) { Chef::Resource::AptUpdate.new("update") }
+
+ let(:config_dir) { Dir.mktmpdir("apt_update_apt_conf_d") }
+ let(:config_file) { File.join(config_dir, "15update-stamp") }
+ let(:stamp_dir) { Dir.mktmpdir("apt_update_periodic") }
+
+ before do
+ stub_const("Chef::Provider::AptUpdate::APT_CONF_DIR", config_dir)
+ stub_const("Chef::Provider::AptUpdate::STAMP_DIR", stamp_dir)
+ end
+
+ let(:provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::AptUpdate.new(new_resource, run_context)
+ end
+
+ it "responds to load_current_resource" do
+ expect(provider).to respond_to(:load_current_resource)
+ end
+
+ context "when the apt config directory does not exist" do
+ before do
+ FileUtils.rmdir config_dir
+ expect(File.exist?(config_dir)).to be false
+ allow_any_instance_of(Chef::Provider::Execute).to receive(:shell_out!).with("apt-get -q update", anything())
+ end
+
+ it "should create the directory" do
+ provider.run_action(:update)
+ expect(File.exist?(config_dir)).to be true
+ expect(File.directory?(config_dir)).to be true
+ end
+
+ it "should create the config file" do
+ provider.run_action(:update)
+ expect(File.exist?(config_file)).to be true
+ expect(File.read(config_file)).to match(/^APT::Update.*#{stamp_dir}/)
+ end
+ end
+
+ describe "#action_update" do
+ it "should update the apt cache" do
+ provider.load_current_resource
+ expect_any_instance_of(Chef::Provider::Execute).to receive(:shell_out!).with("apt-get -q update", anything())
+ provider.run_action(:update)
+ expect(new_resource).to be_updated_by_last_action
+ end
+ end
+
+ describe "#action_periodic" do
+ before do
+ allow(File).to receive(:exist?)
+ allow(File).to receive(:exist?).with(Dir.tmpdir).and_return(true)
+ expect(File).to receive(:exist?).with("#{stamp_dir}/update-success-stamp").and_return(true)
+ end
+
+ it "should run if the time stamp is old" do
+ expect(File).to receive(:mtime).with("#{stamp_dir}/update-success-stamp").and_return(Time.now - 86_500)
+ expect_any_instance_of(Chef::Provider::Execute).to receive(:shell_out!).with("apt-get -q update", anything())
+ provider.run_action(:periodic)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "should not run if the time stamp is new" do
+ expect(File).to receive(:mtime).with("#{stamp_dir}/update-success-stamp").and_return(Time.now)
+ expect_any_instance_of(Chef::Provider::Execute).not_to receive(:shell_out!).with("apt-get -q update", anything())
+ provider.run_action(:periodic)
+ expect(new_resource).to_not be_updated_by_last_action
+ end
+
+ context "with a different frequency" do
+ before do
+ new_resource.frequency(400)
+ end
+
+ it "should run if the time stamp is old" do
+ expect(File).to receive(:mtime).with("#{stamp_dir}/update-success-stamp").and_return(Time.now - 500)
+ expect_any_instance_of(Chef::Provider::Execute).to receive(:shell_out!).with("apt-get -q update", anything())
+ provider.run_action(:periodic)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "should not run if the time stamp is new" do
+ expect(File).to receive(:mtime).with("#{stamp_dir}/update-success-stamp").and_return(Time.now - 300)
+ expect_any_instance_of(Chef::Provider::Execute).not_to receive(:shell_out!).with("apt-get -q update", anything())
+ provider.run_action(:periodic)
+ expect(new_resource).to_not be_updated_by_last_action
+ end
+ end
+ end
+end
diff --git a/spec/unit/provider/breakpoint_spec.rb b/spec/unit/provider/breakpoint_spec.rb
index 386e5a1d17..ffe8c8261f 100644
--- a/spec/unit/provider/breakpoint_spec.rb
+++ b/spec/unit/provider/breakpoint_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,7 @@
# limitations under the License.
#
-
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Breakpoint do
before do
diff --git a/spec/unit/provider/cookbook_file/content_spec.rb b/spec/unit/provider/cookbook_file/content_spec.rb
index 6946966153..096ac85b64 100644
--- a/spec/unit/provider/cookbook_file/content_spec.rb
+++ b/spec/unit/provider/cookbook_file/content_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,25 +16,24 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::CookbookFile::Content do
- let(:new_resource) { double('Chef::Resource::CookbookFile (new)', :cookbook_name => 'apache2', :cookbook => 'apache2') }
+ let(:new_resource) { double("Chef::Resource::CookbookFile (new)", :cookbook_name => "apache2", :cookbook => "apache2") }
let(:content) do
- @run_context = double('Chef::RunContext')
- @current_resource = double('Chef::Resource::CookbookFile (current)')
+ @run_context = double("Chef::RunContext")
+ @current_resource = double("Chef::Resource::CookbookFile (current)")
Chef::Provider::CookbookFile::Content.new(new_resource, @current_resource, @run_context)
end
it "prefers the explicit cookbook name on the resource to the implicit one" do
- allow(new_resource).to receive(:cookbook).and_return('nginx')
- expect(content.send(:resource_cookbook)).to eq('nginx')
+ allow(new_resource).to receive(:cookbook).and_return("nginx")
+ expect(content.send(:resource_cookbook)).to eq("nginx")
end
it "falls back to the implicit cookbook name on the resource" do
- expect(content.send(:resource_cookbook)).to eq('apache2')
+ expect(content.send(:resource_cookbook)).to eq("apache2")
end
end
-
diff --git a/spec/unit/provider/cookbook_file_spec.rb b/spec/unit/provider/cookbook_file_spec.rb
index a7cbba97cb..f49cc7d3da 100644
--- a/spec/unit/provider/cookbook_file_spec.rb
+++ b/spec/unit/provider/cookbook_file_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2009-2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,21 +17,21 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
-require 'support/shared/unit/provider/file'
+require "support/shared/unit/provider/file"
describe Chef::Provider::CookbookFile do
- let(:node) { double('Chef::Node') }
- let(:events) { double('Chef::Events').as_null_object } # mock all the methods
- let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
- let(:enclosing_directory) {
+ let(:node) { double("Chef::Node") }
+ let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+ let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
+ let(:enclosing_directory) do
canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
- }
- let(:resource_path) {
+ end
+ let(:resource_path) do
canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt")))
- }
+ end
# Subject
@@ -44,12 +44,12 @@ describe Chef::Provider::CookbookFile do
let(:resource) do
resource = Chef::Resource::CookbookFile.new("seattle", @run_context)
resource.path(resource_path)
- resource.cookbook_name = 'apache2'
+ resource.cookbook_name = "apache2"
resource
end
let(:content) do
- content = double('Chef::Provider::CookbookFile::Content')
+ content = double("Chef::Provider::CookbookFile::Content")
end
it_behaves_like Chef::Provider::File
diff --git a/spec/unit/provider/cron/unix_spec.rb b/spec/unit/provider/cron/unix_spec.rb
index 3d7a5675fc..5e1fcb35ab 100644
--- a/spec/unit/provider/cron/unix_spec.rb
+++ b/spec/unit/provider/cron/unix_spec.rb
@@ -1,8 +1,8 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
# Author:: Toomas Pelberg (toomasp@gmx.net)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
-# Copyright:: Copyright (c) 2010 Toomas Pelberg
+# Copyright:: Copyright 2009-2016, Bryan McLellan
+# Copyright:: Copyright 2010-2016, Toomas Pelberg
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Cron::Unix do
@@ -37,9 +37,9 @@ describe Chef::Provider::Cron::Unix do
end
end
- let(:status) { double('Process::Status', :exitstatus => exitstatus) }
+ let(:status) { double("Process::Status", :exitstatus => exitstatus) }
let(:exitstatus) { 0 }
- let(:shell_out) { double('Mixlib::ShellOut', :status => status, :stdout => stdout, :stderr => stderr) }
+ let(:shell_out) { double("Mixlib::ShellOut", :status => status, :stdout => stdout, :stderr => stderr) }
it "is a Chef::Provider:Cron" do
expect(provider).to be_a(Chef::Provider::Cron)
@@ -61,12 +61,12 @@ describe Chef::Provider::Cron::Unix do
before do
allow(Chef::Log).to receive(:debug)
allow(shell_out).to receive(:format_for_exception).and_return("formatted command output")
- allow(provider).to receive(:shell_out).with('/usr/bin/crontab -l', :user => username).and_return(shell_out)
+ allow(provider).to receive(:shell_out).with("/usr/bin/crontab -l", :user => username).and_return(shell_out)
end
it "should call crontab -l with the user" do
provider.send(:read_crontab)
- expect(provider).to have_received(:shell_out).with('/usr/bin/crontab -l', :user => username)
+ expect(provider).to have_received(:shell_out).with("/usr/bin/crontab -l", :user => username)
end
it "should return the contents of the crontab" do
@@ -91,9 +91,9 @@ describe Chef::Provider::Cron::Unix do
let (:exitstatus) { 2 }
it "should raise an exception if another error occurs" do
- expect {
+ expect do
provider.send(:read_crontab)
- }.to raise_error(Chef::Exceptions::Cron, "Error determining state of #{new_resource.name}, exit: 2")
+ end.to raise_error(Chef::Exceptions::Cron, "Error determining state of #{new_resource.name}, exit: 2")
end
it "logs the crontab output to debug" do
@@ -130,9 +130,9 @@ describe Chef::Provider::Cron::Unix do
context "when writing the crontab fails" do
let(:exitstatus) { 1 }
it "should raise an exception if the command returns non-zero" do
- expect {
+ expect do
provider.send(:write_crontab, "Foo")
- }.to raise_error(Chef::Exceptions::Cron, /Error updating state of #{new_resource.name}, exit: 1/)
+ end.to raise_error(Chef::Exceptions::Cron, /Error updating state of #{new_resource.name}, exit: 1/)
end
end
end
diff --git a/spec/unit/provider/cron_spec.rb b/spec/unit/provider/cron_spec.rb
index 7a917a4f27..64916ef454 100644
--- a/spec/unit/provider/cron_spec.rb
+++ b/spec/unit/provider/cron_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Cron do
describe "when with special time string" do
@@ -56,7 +56,7 @@ CRONTAB
it "should pull the details out of the cron line" do
cron = @provider.load_current_resource
expect(cron.time).to eq(:reboot)
- expect(cron.command).to eq('/bin/true param1 param2')
+ expect(cron.command).to eq("/bin/true param1 param2")
end
it "should pull env vars out" do
@@ -75,12 +75,12 @@ HOME=/home/foo
# Another comment
CRONTAB
cron = @provider.load_current_resource
- expect(cron.mailto).to eq('foo@example.com')
- expect(cron.shell).to eq('/bin/foosh')
- expect(cron.path).to eq('/bin:/foo')
- expect(cron.home).to eq('/home/foo')
+ expect(cron.mailto).to eq("foo@example.com")
+ expect(cron.shell).to eq("/bin/foosh")
+ expect(cron.path).to eq("/bin:/foo")
+ expect(cron.home).to eq("/home/foo")
expect(cron.time).to eq(:reboot)
- expect(cron.command).to eq('/bin/true param1 param2')
+ expect(cron.command).to eq("/bin/true param1 param2")
end
it "should parse and load generic and standard environment variables from cron entry" do
@@ -94,7 +94,7 @@ CRONTAB
cron = @provider.load_current_resource
expect(cron.mailto).to eq("warn@example.com")
- expect(cron.environment).to eq({"TEST" => "lol", "FLAG" => "1"})
+ expect(cron.environment).to eq({ "TEST" => "lol", "FLAG" => "1" })
end
it "should not break with variables that match the cron resource internals" do
@@ -109,7 +109,7 @@ CRONTAB
cron = @provider.load_current_resource
expect(cron.time).to eq(:reboot)
- expect(cron.environment).to eq({"MINUTE" => "40", "REBOOT" => "midnight", "TEST" => "lol", "ENVIRONMENT" => "production"})
+ expect(cron.environment).to eq({ "MINUTE" => "40", "REBOOT" => "midnight", "TEST" => "lol", "ENVIRONMENT" => "production" })
end
it "should report the match" do
@@ -199,9 +199,9 @@ CRONTAB
# Chef Name: foo[bar] (baz)
21 */4 * * * some_prog 1234567
CRONTAB
- expect {
+ expect do
@provider.load_current_resource
- }.not_to raise_error
+ end.not_to raise_error
end
end
@@ -227,13 +227,13 @@ CRONTAB
it "should pull the details out of the cron line" do
cron = @provider.load_current_resource
- expect(cron.minute).to eq('*')
- expect(cron.hour).to eq('5')
- expect(cron.day).to eq('*')
- expect(cron.month).to eq('1')
- expect(cron.weekday).to eq('*')
+ expect(cron.minute).to eq("*")
+ expect(cron.hour).to eq("5")
+ expect(cron.day).to eq("*")
+ expect(cron.month).to eq("1")
+ expect(cron.weekday).to eq("*")
expect(cron.time).to eq(nil)
- expect(cron.command).to eq('/bin/true param1 param2')
+ expect(cron.command).to eq("/bin/true param1 param2")
end
it "should pull env vars out" do
@@ -252,17 +252,17 @@ HOME=/home/foo
# Another comment
CRONTAB
cron = @provider.load_current_resource
- expect(cron.mailto).to eq('foo@example.com')
- expect(cron.shell).to eq('/bin/foosh')
- expect(cron.path).to eq('/bin:/foo')
- expect(cron.home).to eq('/home/foo')
- expect(cron.minute).to eq('*')
- expect(cron.hour).to eq('5')
- expect(cron.day).to eq('*')
- expect(cron.month).to eq('1')
- expect(cron.weekday).to eq('*')
+ expect(cron.mailto).to eq("foo@example.com")
+ expect(cron.shell).to eq("/bin/foosh")
+ expect(cron.path).to eq("/bin:/foo")
+ expect(cron.home).to eq("/home/foo")
+ expect(cron.minute).to eq("*")
+ expect(cron.hour).to eq("5")
+ expect(cron.day).to eq("*")
+ expect(cron.month).to eq("1")
+ expect(cron.weekday).to eq("*")
expect(cron.time).to eq(nil)
- expect(cron.command).to eq('/bin/true param1 param2')
+ expect(cron.command).to eq("/bin/true param1 param2")
end
it "should parse and load generic and standard environment variables from cron entry" do
@@ -276,7 +276,7 @@ CRONTAB
cron = @provider.load_current_resource
expect(cron.mailto).to eq("warn@example.com")
- expect(cron.environment).to eq({"TEST" => "lol", "FLAG" => "1"})
+ expect(cron.environment).to eq({ "TEST" => "lol", "FLAG" => "1" })
end
it "should not break with variabels that match the cron resource internals" do
@@ -290,9 +290,9 @@ ENVIRONMENT=production
CRONTAB
cron = @provider.load_current_resource
- expect(cron.minute).to eq('*')
- expect(cron.hour).to eq('5')
- expect(cron.environment).to eq({"MINUTE" => "40", "HOUR" => "midnight", "TEST" => "lol", "ENVIRONMENT" => "production"})
+ expect(cron.minute).to eq("*")
+ expect(cron.hour).to eq("5")
+ expect(cron.environment).to eq({ "MINUTE" => "40", "HOUR" => "midnight", "TEST" => "lol", "ENVIRONMENT" => "production" })
end
it "should report the match" do
@@ -323,12 +323,12 @@ CRONTAB
it "should pull the details out of the cron line" do
cron = @provider.load_current_resource
- expect(cron.minute).to eq('*')
- expect(cron.hour).to eq('5')
- expect(cron.day).to eq('*')
- expect(cron.month).to eq('Jan')
- expect(cron.weekday).to eq('Mon')
- expect(cron.command).to eq('/bin/true param1 param2')
+ expect(cron.minute).to eq("*")
+ expect(cron.hour).to eq("5")
+ expect(cron.day).to eq("*")
+ expect(cron.month).to eq("Jan")
+ expect(cron.weekday).to eq("Mon")
+ expect(cron.command).to eq("/bin/true param1 param2")
end
it "should report the match" do
@@ -346,11 +346,11 @@ CRONTAB
CRONTAB
cron = @provider.load_current_resource
expect(@provider.cron_exists).to eq(true)
- expect(cron.minute).to eq('*')
- expect(cron.hour).to eq('*')
- expect(cron.day).to eq('*')
- expect(cron.month).to eq('*')
- expect(cron.weekday).to eq('*')
+ expect(cron.minute).to eq("*")
+ expect(cron.hour).to eq("*")
+ expect(cron.day).to eq("*")
+ expect(cron.month).to eq("*")
+ expect(cron.weekday).to eq("*")
expect(cron.time).to eq(nil)
expect(cron.command).to eq(nil)
end
@@ -364,11 +364,11 @@ CRONTAB
CRONTAB
cron = @provider.load_current_resource
expect(@provider.cron_exists).to eq(true)
- expect(cron.minute).to eq('*')
- expect(cron.hour).to eq('*')
- expect(cron.day).to eq('*')
- expect(cron.month).to eq('*')
- expect(cron.weekday).to eq('*')
+ expect(cron.minute).to eq("*")
+ expect(cron.hour).to eq("*")
+ expect(cron.day).to eq("*")
+ expect(cron.month).to eq("*")
+ expect(cron.weekday).to eq("*")
expect(cron.time).to eq(nil)
expect(cron.command).to eq(nil)
end
@@ -386,11 +386,11 @@ CRONTAB
CRONTAB
cron = @provider.load_current_resource
expect(@provider.cron_exists).to eq(true)
- expect(cron.minute).to eq('*')
- expect(cron.hour).to eq('*')
- expect(cron.day).to eq('*')
- expect(cron.month).to eq('*')
- expect(cron.weekday).to eq('*')
+ expect(cron.minute).to eq("*")
+ expect(cron.hour).to eq("*")
+ expect(cron.day).to eq("*")
+ expect(cron.month).to eq("*")
+ expect(cron.weekday).to eq("*")
expect(cron.time).to eq(nil)
expect(cron.command).to eq(nil)
end
@@ -455,17 +455,17 @@ CRONTAB
end
it "should include env variables that are set" do
- @new_resource.mailto 'foo@example.com'
- @new_resource.path '/usr/bin:/my/custom/path'
- @new_resource.shell '/bin/foosh'
- @new_resource.home '/home/foo'
+ @new_resource.mailto "foo@example.com"
+ @new_resource.path "/usr/bin:/my/custom/path"
+ @new_resource.shell "/bin/foosh"
+ @new_resource.home "/home/foo"
@new_resource.environment "TEST" => "LOL"
expect(@provider).to receive(:write_crontab).with(<<-ENDCRON)
# Chef Name: cronhole some stuff
-MAILTO=foo@example.com
-PATH=/usr/bin:/my/custom/path
-SHELL=/bin/foosh
-HOME=/home/foo
+MAILTO="foo@example.com"
+PATH="/usr/bin:/my/custom/path"
+SHELL="/bin/foosh"
+HOME="/home/foo"
TEST=LOL
30 * * * * /bin/true
ENDCRON
@@ -511,10 +511,10 @@ TEST=LOL
end
it "should include env variables that are set" do
- @new_resource.mailto 'foo@example.com'
- @new_resource.path '/usr/bin:/my/custom/path'
- @new_resource.shell '/bin/foosh'
- @new_resource.home '/home/foo'
+ @new_resource.mailto "foo@example.com"
+ @new_resource.path "/usr/bin:/my/custom/path"
+ @new_resource.shell "/bin/foosh"
+ @new_resource.home "/home/foo"
@new_resource.environment "TEST" => "LOL"
expect(@provider).to receive(:write_crontab).with(<<-ENDCRON)
0 2 * * * /some/other/command
@@ -524,10 +524,10 @@ TEST=LOL
# Another comment
# Chef Name: cronhole some stuff
-MAILTO=foo@example.com
-PATH=/usr/bin:/my/custom/path
-SHELL=/bin/foosh
-HOME=/home/foo
+MAILTO="foo@example.com"
+PATH="/usr/bin:/my/custom/path"
+SHELL="/bin/foosh"
+HOME="/home/foo"
TEST=LOL
30 * * * * /bin/true
ENDCRON
@@ -576,19 +576,19 @@ TEST=LOL
end
it "should include env variables that are set" do
- @new_resource.mailto 'foo@example.com'
- @new_resource.path '/usr/bin:/my/custom/path'
- @new_resource.shell '/bin/foosh'
- @new_resource.home '/home/foo'
+ @new_resource.mailto "foo@example.com"
+ @new_resource.path "/usr/bin:/my/custom/path"
+ @new_resource.shell "/bin/foosh"
+ @new_resource.home "/home/foo"
@new_resource.environment "TEST" => "LOL"
expect(@provider).to receive(:write_crontab).with(<<-ENDCRON)
0 2 * * * /some/other/command
# Chef Name: cronhole some stuff
-MAILTO=foo@example.com
-PATH=/usr/bin:/my/custom/path
-SHELL=/bin/foosh
-HOME=/home/foo
+MAILTO="foo@example.com"
+PATH="/usr/bin:/my/custom/path"
+SHELL="/bin/foosh"
+HOME="/home/foo"
TEST=LOL
30 * * * * /bin/true
# Chef Name: something else
@@ -671,18 +671,18 @@ HOME=/home/foo
# Another comment
CRONTAB
- @new_resource.mailto 'foo@example.com'
- @new_resource.path '/usr/bin:/my/custom/path'
- @new_resource.shell '/bin/foosh'
- @new_resource.home '/home/foo'
+ @new_resource.mailto "foo@example.com"
+ @new_resource.path "/usr/bin:/my/custom/path"
+ @new_resource.shell "/bin/foosh"
+ @new_resource.home "/home/foo"
expect(@provider).to receive(:write_crontab).with(<<-ENDCRON)
0 2 * * * /some/other/command
# Chef Name: cronhole some stuff
-MAILTO=foo@example.com
-PATH=/usr/bin:/my/custom/path
-SHELL=/bin/foosh
-HOME=/home/foo
+MAILTO="foo@example.com"
+PATH="/usr/bin:/my/custom/path"
+SHELL="/bin/foosh"
+HOME="/home/foo"
30 * * * * /bin/true
# Chef Name: something else
diff --git a/spec/unit/provider/deploy/revision_spec.rb b/spec/unit/provider/deploy/revision_spec.rb
index caa60878e1..8f8280e11d 100644
--- a/spec/unit/provider/deploy/revision_spec.rb
+++ b/spec/unit/provider/deploy/revision_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Deploy::Revision do
@@ -41,7 +41,6 @@ describe Chef::Provider::Deploy::Revision do
FileUtils.rm_rf @temp_dir if File.directory?( @temp_dir )
end
-
it "uses the resolved revision from the SCM as the release slug" do
allow(@provider.scm_provider).to receive(:revision_slug).and_return("uglySlugly")
expect(@provider.send(:release_slug)).to eq("uglySlugly")
@@ -60,7 +59,7 @@ describe Chef::Provider::Deploy::Revision do
@provider.cleanup!
second_release = "/my/deploy/dir/releases/73219b87e977d9c7ba1aa57e9ad1d88fa91a0ec2"
- expect(@provider.all_releases).to eq([@expected_release_dir,second_release])
+ expect(@provider.all_releases).to eq([@expected_release_dir, second_release])
end
it "removes a release from the file cache when it's used again in another release and append it to the end" do
@@ -71,7 +70,7 @@ describe Chef::Provider::Deploy::Revision do
@provider.load_current_resource
@provider.cleanup!
second_release = "/my/deploy/dir/releases/73219b87e977d9c7ba1aa57e9ad1d88fa91a0ec2"
- expect(@provider.all_releases).to eq([@expected_release_dir,second_release])
+ expect(@provider.all_releases).to eq([@expected_release_dir, second_release])
@provider.cleanup!
allow(@provider).to receive(:release_slug).and_return("8a3195bf3efa246f743c5dfa83683201880f935c")
@@ -82,7 +81,7 @@ describe Chef::Provider::Deploy::Revision do
it "removes a release from the file cache when it's deleted by :cleanup!" do
release_paths = %w{first second third fourth fifth}.map do |release_name|
- "/my/deploy/dir/releases/#{release_name}"
+ "/my/deploy/dir/releases/#{release_name}"
end
release_paths.each do |release_path|
@provider.send(:release_created, release_path)
@@ -93,7 +92,7 @@ describe Chef::Provider::Deploy::Revision do
@provider.cleanup!
expected_release_paths = (%w{second third fourth fifth} << @resource.revision).map do |release_name|
- "/my/deploy/dir/releases/#{release_name}"
+ "/my/deploy/dir/releases/#{release_name}"
end
expect(@provider.all_releases).to eq(expected_release_paths)
diff --git a/spec/unit/provider/deploy/timestamped_spec.rb b/spec/unit/provider/deploy/timestamped_spec.rb
index b189d33502..fdb90bf438 100644
--- a/spec/unit/provider/deploy/timestamped_spec.rb
+++ b/spec/unit/provider/deploy/timestamped_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Deploy::Timestamped do
diff --git a/spec/unit/provider/deploy_spec.rb b/spec/unit/provider/deploy_spec.rb
index adcb9431eb..b0ede7e260 100644
--- a/spec/unit/provider/deploy_spec.rb
+++ b/spec/unit/provider/deploy_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Deploy do
@@ -163,24 +163,24 @@ describe Chef::Provider::Deploy do
end
it "dont care by default if error happens on deploy" do
- allow(@provider).to receive(:all_releases).and_return(['previous_release'])
- allow(@provider).to receive(:deploy){ raise "Unexpected error" }
- allow(@provider).to receive(:previous_release_path).and_return('previous_release')
+ allow(@provider).to receive(:all_releases).and_return(["previous_release"])
+ allow(@provider).to receive(:deploy) { raise "Unexpected error" }
+ allow(@provider).to receive(:previous_release_path).and_return("previous_release")
expect(@provider).not_to receive(:rollback)
- expect {
+ expect do
@provider.run_action(:deploy)
- }.to raise_exception(RuntimeError, "Unexpected error")
+ end.to raise_exception(RuntimeError, "Unexpected error")
end
it "rollbacks to previous release if error happens on deploy" do
@resource.rollback_on_error true
- allow(@provider).to receive(:all_releases).and_return(['previous_release'])
- allow(@provider).to receive(:deploy){ raise "Unexpected error" }
- allow(@provider).to receive(:previous_release_path).and_return('previous_release')
+ allow(@provider).to receive(:all_releases).and_return(["previous_release"])
+ allow(@provider).to receive(:deploy) { raise "Unexpected error" }
+ allow(@provider).to receive(:previous_release_path).and_return("previous_release")
expect(@provider).to receive(:rollback)
- expect {
+ expect do
@provider.run_action(:deploy)
- }.to raise_exception(RuntimeError, "Unexpected error")
+ end.to raise_exception(RuntimeError, "Unexpected error")
end
describe "on systems without broken Dir.glob results" do
@@ -232,17 +232,17 @@ describe Chef::Provider::Deploy do
#FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/20040815162342")
#@provider.run_action(:rollback)
#@provider.release_path.should eql(NIL) -- no check needed since assertions will fail
- expect {
+ expect do
@provider.run_action(:rollback)
- }.to raise_exception(RuntimeError, "There is no release to rollback to!")
+ end.to raise_exception(RuntimeError, "There is no release to rollback to!")
end
it "an exception is raised when there are no releases" do
all_releases = []
allow(Dir).to receive(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases)
- expect {
+ expect do
@provider.run_action(:rollback)
- }.to raise_exception(RuntimeError, "There is no release to rollback to!")
+ end.to raise_exception(RuntimeError, "There is no release to rollback to!")
end
end
end
@@ -266,7 +266,7 @@ describe Chef::Provider::Deploy do
it "raises a runtime error when there's no release to rollback to" do
all_releases = []
allow(Dir).to receive(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases)
- expect {@provider.run_action(:rollback)}.to raise_error(RuntimeError)
+ expect { @provider.run_action(:rollback) }.to raise_error(RuntimeError)
end
it "runs the new resource collection in the runner during a callback" do
@@ -286,12 +286,12 @@ describe Chef::Provider::Deploy do
end
it "raises a runtime error if a callback file is explicitly specified but does not exist" do
- baz_callback = "/deploy/baz.rb"
+ baz_callback = "/deploy/baz.rb"
expect(::File).to receive(:exist?).with("#{@expected_release_dir}/#{baz_callback}").and_return(false)
- @resource.before_migrate baz_callback
+ @resource.before_migrate baz_callback
@provider.define_resource_requirements
@provider.action = :deploy
- expect {@provider.process_resource_requirements}.to raise_error(RuntimeError)
+ expect { @provider.process_resource_requirements }.to raise_error(RuntimeError)
end
it "runs a default callback if the callback code is nil" do
@@ -378,11 +378,11 @@ describe Chef::Provider::Deploy do
allow(STDOUT).to receive(:tty?).and_return(true)
allow(Chef::Log).to receive(:info?).and_return(true)
- expect(@provider).to receive(:shell_out!).with("migration_foo",:cwd => @expected_release_dir,
- :user => "deployNinja", :group => "deployNinjas",
- :log_level => :info, :live_stream => STDOUT,
- :log_tag => "deploy[/my/deploy/dir]",
- :environment => {"RAILS_ENV"=>"production"})
+ expect(@provider).to receive(:shell_out!).with("migration_foo", :cwd => @expected_release_dir,
+ :user => "deployNinja", :group => "deployNinjas",
+ :log_level => :info, :live_stream => STDOUT,
+ :log_tag => "deploy[/my/deploy/dir]",
+ :environment => { "RAILS_ENV" => "production" })
@provider.migrate
end
@@ -518,7 +518,7 @@ describe Chef::Provider::Deploy do
it "runs an inline recipe with the provided block for :callback_name == {:recipe => &block} " do
snitch = nil
- recipe_code = Proc.new {snitch = 42}
+ recipe_code = Proc.new { snitch = 42 }
#@provider.should_receive(:instance_eval).with(&recipe_code)
@provider.callback(:whateverz, recipe_code)
expect(snitch).to eq(42)
@@ -533,7 +533,7 @@ describe Chef::Provider::Deploy do
it "instance_evals a block/proc for restart command" do
snitch = nil
- restart_cmd = Proc.new {snitch = 42}
+ restart_cmd = Proc.new { snitch = 42 }
@resource.restart(&restart_cmd)
@provider.restart
expect(snitch).to eq(42)
@@ -552,11 +552,11 @@ describe Chef::Provider::Deploy do
expect(@provider).to receive(:execute).with("iGoToHell4this").and_return(mock_execution)
@resource.user("notCoolMan")
@resource.group("Ggroup")
- @resource.environment("APP_ENV" => 'staging')
+ @resource.environment("APP_ENV" => "staging")
@resource.deploy_to("/my/app")
expect(mock_execution).to receive(:user).with("notCoolMan")
expect(mock_execution).to receive(:group).with("Ggroup")
- expect(mock_execution).to receive(:cwd){|*args|
+ expect(mock_execution).to receive(:cwd) { |*args|
if args.empty?
nil
else
@@ -564,12 +564,12 @@ describe Chef::Provider::Deploy do
expect(args.first).to eq(@provider.release_path)
end
}.twice
- expect(mock_execution).to receive(:environment){ |*args|
+ expect(mock_execution).to receive(:environment) { |*args|
if args.empty?
nil
else
expect(args.size).to eq(1)
- expect(args.first).to eq({"APP_ENV" => "staging"})
+ expect(args.first).to eq({ "APP_ENV" => "staging" })
end
}.twice
@provider.run("iGoToHell4this")
@@ -586,7 +586,6 @@ describe Chef::Provider::Deploy do
@provider.run("iGoToHell4this")
end
-
it "converts sudo and run to exec resources in hooks" do
runner = double("tehRunner")
allow(Chef::Runner).to receive(:new).and_return(runner)
@@ -596,7 +595,7 @@ describe Chef::Provider::Deploy do
callback_code = Proc.new do
snitch = 42
- temp_collection = self.resource_collection
+ temp_collection = resource_collection
run("tehMice")
snitch = temp_collection.lookup("execute[tehMice]")
end
@@ -613,7 +612,7 @@ describe Chef::Provider::Deploy do
before do
allow(::File).to receive(:exist?).with("#{@expected_release_dir}/gems.yml").and_return(true)
- @gem_list = [{:name=>"eventmachine", :version=>"0.12.9"}]
+ @gem_list = [{ :name => "eventmachine", :version => "0.12.9" }]
end
it "reads a gems.yml file, creating gem providers for each with action :upgrade" do
diff --git a/spec/unit/provider/directory_spec.rb b/spec/unit/provider/directory_spec.rb
index 4fad8c8906..4672db7d8d 100644
--- a/spec/unit/provider/directory_spec.rb
+++ b/spec/unit/provider/directory_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
describe Chef::Provider::Directory do
let(:tmp_dir) { Dir.mktmpdir }
@@ -148,6 +148,16 @@ describe Chef::Provider::Directory do
directory.run_action(:create)
expect(new_resource).not_to be_updated
end
+
+ context "in why run mode" do
+ before { Chef::Config[:why_run] = true }
+ after { Chef::Config[:why_run] = false }
+
+ it "does not modify new_resource" do
+ expect(directory).not_to receive(:load_resource_attributes_from_file).with(new_resource)
+ directory.run_action(:create)
+ end
+ end
end
describe "when the directory does not exist" do
@@ -187,27 +197,20 @@ describe Chef::Provider::Directory do
it "raises an exception when the parent directory is a file and recursive is true" do
FileUtils.touch tmp_dir
new_resource.recursive true
- expect { directory.run_action(:create) }.to raise_error
- end
-
- it "raises the right exception when the parent directory is a file and recursive is true" do
- pending "this seems to return the wrong error" # FIXME
- FileUtils.touch tmp_dir
- new_resource.recursive true
expect { directory.run_action(:create) }.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
end
end
describe "on OS X" do
before do
- allow(node).to receive(:[]).with("platform").and_return('mac_os_x')
+ allow(node).to receive(:[]).with("platform").and_return("mac_os_x")
new_resource.path "/usr/bin/chef_test"
new_resource.recursive false
allow_any_instance_of(Chef::Provider::File).to receive(:do_selinux)
end
it "os x 10.10 can write to sip locations" do
- allow(node).to receive(:[]).with("platform_version").and_return('10.10')
+ allow(node).to receive(:[]).with("platform_version").and_return("10.10")
allow(Dir).to receive(:mkdir).and_return([true], [])
allow(::File).to receive(:directory?).and_return(true)
allow(Chef::FileAccessControl).to receive(:writable?).and_return(true)
@@ -216,15 +219,15 @@ describe Chef::Provider::Directory do
end
it "os x 10.11 cannot write to sip locations" do
- allow(node).to receive(:[]).with("platform_version").and_return('10.11')
+ allow(node).to receive(:[]).with("platform_version").and_return("10.11")
allow(::File).to receive(:directory?).and_return(true)
allow(Chef::FileAccessControl).to receive(:writable?).and_return(false)
- expect {directory.run_action(:create) }.to raise_error(Chef::Exceptions::InsufficientPermissions)
+ expect { directory.run_action(:create) }.to raise_error(Chef::Exceptions::InsufficientPermissions)
end
it "os x 10.11 can write to sip exlcusions" do
new_resource.path "/usr/local/chef_test"
- allow(node).to receive(:[]).with("platform_version").and_return('10.11')
+ allow(node).to receive(:[]).with("platform_version").and_return("10.11")
allow(::File).to receive(:directory?).and_return(true)
allow(Dir).to receive(:mkdir).and_return([true], [])
allow(Chef::FileAccessControl).to receive(:writable?).and_return(false)
@@ -234,7 +237,7 @@ describe Chef::Provider::Directory do
end
end
- describe "#run_action(:create)" do
+ describe "#run_action(:delete)" do
describe "when the directory exists" do
it "deletes the directory" do
directory.run_action(:delete)
@@ -245,6 +248,16 @@ describe Chef::Provider::Directory do
directory.run_action(:delete)
expect(new_resource).to be_updated
end
+
+ it "does not use rm_rf which silently consumes errors" do
+ expect(FileUtils).not_to receive(:rm_rf)
+ expect(FileUtils).to receive(:rm_r)
+ # set recursive or FileUtils isn't used at all.
+ new_resource.recursive(true)
+ directory.run_action(:delete)
+ # reset back...
+ new_resource.recursive(false)
+ end
end
describe "when the directory does not exist" do
@@ -269,7 +282,7 @@ describe Chef::Provider::Directory do
end
it "cannot delete it and raises an exception" do
- expect { directory.run_action(:delete) }.to raise_error(RuntimeError)
+ expect { directory.run_action(:delete) }.to raise_error(RuntimeError)
end
end
@@ -280,7 +293,7 @@ describe Chef::Provider::Directory do
end
it "cannot delete it and raises an exception" do
- expect { directory.run_action(:delete) }.to raise_error(RuntimeError)
+ expect { directory.run_action(:delete) }.to raise_error(RuntimeError)
end
end
end
diff --git a/spec/unit/provider/dsc_resource_spec.rb b/spec/unit/provider/dsc_resource_spec.rb
index 9946ab8410..96356e5d73 100644
--- a/spec/unit/provider/dsc_resource_spec.rb
+++ b/spec/unit/provider/dsc_resource_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
-require 'chef'
-require 'spec_helper'
+require "chef"
+require "spec_helper"
describe Chef::Provider::DscResource do
let (:events) { Chef::EventDispatch::Dispatcher.new }
@@ -28,50 +27,317 @@ describe Chef::Provider::DscResource do
Chef::Provider::DscResource.new(resource, run_context)
end
- context 'when Powershell does not support Invoke-DscResource' do
- let (:node) {
+ context "when Powershell does not support Invoke-DscResource" do
+ let (:node) do
node = Chef::Node.new
- node.automatic[:languages][:powershell][:version] = '4.0'
+ node.automatic[:languages][:powershell][:version] = "4.0"
node
- }
-
- it 'raises a ProviderNotFound exception' do
+ end
+ it "raises a ProviderNotFound exception" do
expect(provider).not_to receive(:meta_configuration)
- expect{provider.run_action(:run)}.to raise_error(
+ expect { provider.run_action(:run) }.to raise_error(
Chef::Exceptions::ProviderNotFound, /5\.0\.10018\.0/)
end
end
- context 'when Powershell supports Invoke-DscResource' do
- let (:node) {
+ context "when Powershell supports Invoke-DscResource" do
+
+ context "when RefreshMode is not set to Disabled" do
+ context "and the WMF 5 is a preview release" do
+ let (:node) do
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = "5.0.10018.0"
+ node
+ end
+ it "raises an exception" do
+ expect(provider).to receive(:dsc_refresh_mode_disabled?).and_return(false)
+ expect { provider.run_action(:run) }.to raise_error(
+ Chef::Exceptions::ProviderNotFound, /Disabled/)
+ end
+ end
+ context "and the WMF is 5 RTM or newer" do
+ let (:node) do
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = "5.0.10586.0"
+ node
+ end
+ it "does not raises an exception" do
+ expect(provider).to receive(:test_resource)
+ expect(provider).to receive(:set_resource)
+ expect(provider).to receive(:reboot_if_required)
+ expect { provider.run_action(:run) }.to_not raise_error
+ end
+ end
+ end
+ end
+
+ context "when the LCM supports Invoke-DscResource" do
+ let (:node) do
node = Chef::Node.new
- node.automatic[:languages][:powershell][:version] = '5.0.10018.0'
+ node.automatic[:languages][:powershell][:version] = "5.0.10018.0"
node
- }
+ end
+ let (:resource_result) { double("CmdletResult", return_value: { "InDesiredState" => true }, stream: "description") }
+ let (:invoke_dsc_resource) { double("cmdlet", run!: resource_result) }
+ let (:store) { double("ResourceStore", find: resource_records) }
+ let (:resource_records) { [] }
+
+ before do
+ allow(Chef::Util::DSC::ResourceStore).to receive(:instance).and_return(store)
+ allow(Chef::Util::Powershell::Cmdlet).to receive(:new).and_return(invoke_dsc_resource)
+ allow(provider).to receive(:dsc_refresh_mode_disabled?).and_return(true)
+ end
- context 'when RefreshMode is not set to Disabled' do
- it 'raises an exception' do
- expect(provider).to receive(:dsc_refresh_mode_disabled?).and_return(false)
- expect { provider.run_action(:run) }.to raise_error(
- Chef::Exceptions::ProviderNotFound, /Disabled/)
+ it "does not update the resource if it is up to date" do
+ expect(provider).to receive(:test_resource).and_return(true)
+ provider.run_action(:run)
+ expect(resource).not_to be_updated
+ end
+
+ it "converges the resource if it is not up to date" do
+ expect(provider).to receive(:test_resource).and_return(false)
+ expect(provider).to receive(:set_resource)
+ provider.run_action(:run)
+ expect(resource).to be_updated
+ end
+
+ it "flags the resource as reboot required when required" do
+ expect(provider).to receive(:test_resource).and_return(false)
+ expect(provider).to receive(:invoke_resource).
+ and_return(double(:stdout => "", :return_value => nil))
+ expect(provider).to receive(:add_dsc_verbose_log)
+ expect(provider).to receive(:return_dsc_resource_result).and_return(true)
+ expect(provider).to receive(:create_reboot_resource)
+ provider.run_action(:run)
+ end
+
+ it "does not flag the resource as reboot required when not required" do
+ expect(provider).to receive(:test_resource).and_return(false)
+ expect(provider).to receive(:invoke_resource).
+ and_return(double(:stdout => "", :return_value => nil))
+ expect(provider).to receive(:add_dsc_verbose_log)
+ expect(provider).to receive(:return_dsc_resource_result).and_return(false)
+ expect(provider).to_not receive(:create_reboot_resource)
+ provider.run_action(:run)
+ end
+
+ context "resource name cannot be found" do
+ let (:resource_records) { [] }
+
+ it "raises ResourceNotFound" do
+ expect { provider.run_action(:run) }.to raise_error(Chef::Exceptions::ResourceNotFound)
end
end
- context 'when RefreshMode is set to Disabled' do
- it 'does not update the resource if it is up to date' do
- expect(provider).to receive(:dsc_refresh_mode_disabled?).and_return(true)
- expect(provider).to receive(:test_resource).and_return(true)
- provider.run_action(:run)
- expect(resource).not_to be_updated
+ context "resource name is found" do
+ context "no module name for resource found" do
+ let (:resource_records) { [{}] }
+
+ it "returns the default dsc resource module" do
+ expect(Chef::Util::Powershell::Cmdlet).to receive(:new) do |node, cmdlet, format|
+ expect(cmdlet).to match(/Module PSDesiredStateConfiguration /)
+ end.and_return(invoke_dsc_resource)
+ provider.run_action(:run)
+ end
end
- it 'converges the resource if it is not up to date' do
- expect(provider).to receive(:dsc_refresh_mode_disabled?).and_return(true)
- expect(provider).to receive(:test_resource).and_return(false)
- expect(provider).to receive(:set_resource)
- provider.run_action(:run)
- expect(resource).to be_updated
+ context "a module name for resource is found" do
+ let (:resource_records) { [{ "Module" => { "Name" => "ModuleName" } }] }
+
+ it "returns the default dsc resource module" do
+ expect(Chef::Util::Powershell::Cmdlet).to receive(:new) do |node, cmdlet, format|
+ expect(cmdlet).to match(/Module ModuleName /)
+ end.and_return(invoke_dsc_resource)
+ provider.run_action(:run)
+ end
+ end
+
+ context "multiple resource are found" do
+ let (:resource_records) do
+ [
+ { "Module" => { "Name" => "ModuleName1" } },
+ { "Module" => { "Name" => "ModuleName2" } },
+ ] end
+
+ it "raises MultipleDscResourcesFound" do
+ expect { provider.run_action(:run) }.to raise_error(Chef::Exceptions::MultipleDscResourcesFound)
+ end
end
end
end
+
+ describe "define_resource_requirements" do
+ let (:node) do
+ set_node_object
+ end
+
+ context "module usage is valid" do
+ before do
+ allow(provider).to receive(:module_usage_valid?).and_return(true)
+ allow(provider).to receive(:action_run)
+ end
+
+ [:run].each do |action|
+ context "action #{action}" do
+ it "does not raise the exception" do
+ expect { provider.run_action(action) }.not_to raise_error
+ end
+ end
+ end
+ end
+
+ context "module usage is invalid" do
+ before do
+ allow(provider).to receive(:module_usage_valid?).and_return(false)
+ allow(provider).to receive(:action_run)
+ end
+
+ [:run].each do |action|
+ context "action #{action}" do
+ it "raises the exception" do
+ expect { provider.run_action(action) }.to raise_error(
+ Chef::Exceptions::DSCModuleNameMissing
+ )
+ end
+ end
+ end
+ end
+ end
+
+ describe "module_usage_valid?" do
+ let (:node) do
+ set_node_object
+ end
+
+ context "module_name and module_version both are not provided" do
+ before do
+ provider.instance_variable_set(:@module_name, nil)
+ provider.instance_variable_set(:@module_version, nil)
+ end
+
+ it "returns true" do
+ response = provider.send(:module_usage_valid?)
+ expect(response).to be == true
+ end
+ end
+
+ context "module_name and module_version both are provided" do
+ before do
+ provider.instance_variable_set(:@module_name, "my_module")
+ provider.instance_variable_set(:@module_version, "1.3")
+ end
+
+ it "returns true" do
+ response = provider.send(:module_usage_valid?)
+ expect(response).to be == true
+ end
+ end
+
+ context "module_name is given but module_version is not given" do
+ before do
+ provider.instance_variable_set(:@module_name, "my_module")
+ provider.instance_variable_set(:@module_version, nil)
+ end
+
+ it "returns true" do
+ response = provider.send(:module_usage_valid?)
+ expect(response).to be == true
+ end
+ end
+
+ context "module_name is not given but module_version is given" do
+ before do
+ provider.instance_variable_set(:@module_name, nil)
+ provider.instance_variable_set(:@module_version, "1.4.0.1")
+ end
+
+ it "returns false" do
+ response = provider.send(:module_usage_valid?)
+ expect(response).to be == false
+ end
+ end
+ end
+
+ describe "module_info_object" do
+ let (:node) do
+ set_node_object
+ end
+
+ context "module_version is not given" do
+ before do
+ provider.instance_variable_set(:@module_version, nil)
+ allow(provider).to receive(:module_name).and_return("my_module")
+ end
+
+ it "returns only name of the module" do
+ response = provider.send(:module_info_object)
+ expect(response).to be == "my_module"
+ end
+ end
+
+ context "module_version is given" do
+ before do
+ provider.instance_variable_set(:@module_version, "1.3.1")
+ allow(provider).to receive(:module_name).and_return("my_module")
+ end
+
+ it "returns the module info object" do
+ response = provider.send(:module_info_object)
+ expect(response).to be == "@{ModuleName='my_module';ModuleVersion='1.3.1'}"
+ end
+ end
+ end
+
+ describe "invoke_resource" do
+ let (:node) do
+ set_node_object
+ end
+
+ let(:cmdlet) { double(:run! => nil) }
+
+ before(:each) do
+ allow(provider).to receive(:translate_type).and_return("my_properties")
+ provider.instance_variable_set(:@new_resource, double(
+ :properties => "my_properties", :resource => "my_resource", :timeout => 123
+ ))
+ end
+
+ context "when module_version is not given" do
+ before do
+ allow(provider).to receive(:module_info_object).and_return("my_module")
+ end
+
+ it "invokes Invoke-DscResource command with module name" do
+ expect(Chef::Util::Powershell::Cmdlet).to receive(:new).with(
+ node,
+ "Invoke-DscResource -Method my_method -Name my_resource -Property my_properties -Module my_module -Verbose",
+ "my_output_format"
+ ).and_return(cmdlet)
+ provider.send(:invoke_resource, "my_method", "my_output_format")
+ end
+ end
+
+ context "when module_version is given" do
+ before do
+ allow(provider).to receive(:module_info_object).and_return(
+ "@{ModuleName='my_module';ModuleVersion='my_module_version'}"
+ )
+ end
+
+ it "invokes Invoke-DscResource command with module info object" do
+ expect(Chef::Util::Powershell::Cmdlet).to receive(:new).with(
+ node,
+ "Invoke-DscResource -Method my_method -Name my_resource -Property my_properties -Module @{ModuleName='my_module';ModuleVersion='my_module_version'} -Verbose",
+ "my_output_format"
+ ).and_return(cmdlet)
+ provider.send(:invoke_resource, "my_method", "my_output_format")
+ end
+ end
+ end
+end
+
+def set_node_object
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = "5.0.10586.0"
+ node
end
diff --git a/spec/unit/provider/dsc_script_spec.rb b/spec/unit/provider/dsc_script_spec.rb
index 76589e71c1..5f091b8813 100644
--- a/spec/unit/provider/dsc_script_spec.rb
+++ b/spec/unit/provider/dsc_script_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Jay Mundrawala (<jdm@getchef.com>)
+# Author:: Jay Mundrawala (<jdm@chef.io>)
#
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,17 +17,17 @@
# limitations under the License.
#
-require 'chef'
-require 'chef/util/dsc/resource_info'
-require 'spec_helper'
+require "chef"
+require "chef/util/dsc/resource_info"
+require "spec_helper"
describe Chef::Provider::DscScript do
- context 'when DSC is available' do
- let (:node) {
+ context "when DSC is available" do
+ let (:node) do
node = Chef::Node.new
- node.automatic[:languages][:powershell][:version] = '4.0'
+ node.automatic[:languages][:powershell][:version] = "4.0"
node
- }
+ end
let (:events) { Chef::EventDispatch::Dispatcher.new }
let (:run_context) { Chef::RunContext.new(node, {}, events) }
let (:resource) { Chef::Resource::DscScript.new("script", run_context) }
@@ -35,79 +35,79 @@ describe Chef::Provider::DscScript do
Chef::Provider::DscScript.new(resource, run_context)
end
- describe '#load_current_resource' do
+ describe "#load_current_resource" do
it "describes the resource as converged if there were 0 DSC resources" do
allow(provider).to receive(:run_configuration).with(:test).and_return([])
provider.load_current_resource
- expect(provider.instance_variable_get('@resource_converged')).to be_truthy
+ expect(provider.instance_variable_get("@resource_converged")).to be_truthy
end
it "describes the resource as not converged if there is 1 DSC resources that is converged" do
- dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new("resource", false, ["nothing will change something"])
allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
provider.load_current_resource
- expect(provider.instance_variable_get('@resource_converged')).to be_truthy
+ expect(provider.instance_variable_get("@resource_converged")).to be_truthy
end
it "describes the resource as not converged if there is 1 DSC resources that is not converged" do
- dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new("resource", true, ["will change something"])
allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
provider.load_current_resource
- expect(provider.instance_variable_get('@resource_converged')).to be_falsey
+ expect(provider.instance_variable_get("@resource_converged")).to be_falsey
end
it "describes the resource as not converged if there are any DSC resources that are not converged" do
- dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
- dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
+ dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new("resource", true, ["will change something"])
+ dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new("resource", false, ["nothing will change something"])
allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
provider.load_current_resource
- expect(provider.instance_variable_get('@resource_converged')).to be_falsey
+ expect(provider.instance_variable_get("@resource_converged")).to be_falsey
end
it "describes the resource as converged if all DSC resources that are converged" do
- dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
- dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
+ dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new("resource", false, ["nothing will change something"])
+ dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new("resource", false, ["nothing will change something"])
allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
provider.load_current_resource
- expect(provider.instance_variable_get('@resource_converged')).to be_truthy
+ expect(provider.instance_variable_get("@resource_converged")).to be_truthy
end
end
- describe '#generate_configuration_document' do
+ describe "#generate_configuration_document" do
# I think integration tests should cover these cases
- it 'uses configuration_document_from_script_path when a dsc script file is given' do
+ it "uses configuration_document_from_script_path when a dsc script file is given" do
allow(provider).to receive(:load_current_resource)
resource.command("path_to_script")
- generator = double('Chef::Util::DSC::ConfigurationGenerator')
+ generator = double("Chef::Util::DSC::ConfigurationGenerator")
expect(generator).to receive(:configuration_document_from_script_path)
allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
- provider.send(:generate_configuration_document, 'tmp', nil)
+ provider.send(:generate_configuration_document, "tmp", nil)
end
- it 'uses configuration_document_from_script_code when a the dsc resource is given' do
+ it "uses configuration_document_from_script_code when a the dsc resource is given" do
allow(provider).to receive(:load_current_resource)
resource.code("ImADSCResource{}")
- generator = double('Chef::Util::DSC::ConfigurationGenerator')
+ generator = double("Chef::Util::DSC::ConfigurationGenerator")
expect(generator).to receive(:configuration_document_from_script_code)
allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
- provider.send(:generate_configuration_document, 'tmp', nil)
+ provider.send(:generate_configuration_document, "tmp", nil)
end
- it 'should noop if neither code or command are provided' do
+ it "should noop if neither code or command are provided" do
allow(provider).to receive(:load_current_resource)
- generator = double('Chef::Util::DSC::ConfigurationGenerator')
- expect(generator).to receive(:configuration_document_from_script_code).with('', anything(), anything(), anything())
+ generator = double("Chef::Util::DSC::ConfigurationGenerator")
+ expect(generator).to receive(:configuration_document_from_script_code).with("", anything(), anything(), anything())
allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
- provider.send(:generate_configuration_document, 'tmp', nil)
+ provider.send(:generate_configuration_document, "tmp", nil)
end
end
- describe 'action_run' do
- it 'should converge the script if it is not converged' do
- dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
+ describe "action_run" do
+ it "should converge the script if it is not converged" do
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new("resource", true, ["will change something"])
allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
allow(provider).to receive(:run_configuration).with(:set)
@@ -115,60 +115,59 @@ describe Chef::Provider::DscScript do
expect(resource).to be_updated
end
- it 'should not converge if the script is already converged' do
+ it "should not converge if the script is already converged" do
allow(provider).to receive(:run_configuration).with(:test).and_return([])
-
+
provider.run_action(:run)
expect(resource).not_to be_updated
end
end
- describe '#generate_description' do
- it 'removes the resource name from the beginning of any log line from the LCM' do
- dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
- provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
+ describe "#generate_description" do
+ it "removes the resource name from the beginning of any log line from the LCM" do
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new("resourcename", true, ["resourcename doing something", "lastline"])
+ provider.instance_variable_set("@dsc_resources_info", [dsc_resource_info])
expect(provider.send(:generate_description)[1]).to match(/converge DSC resource resourcename by doing something/)
end
- it 'ignores the last line' do
- dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
- provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
+ it "ignores the last line" do
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new("resourcename", true, ["resourcename doing something", "lastline"])
+ provider.instance_variable_set("@dsc_resources_info", [dsc_resource_info])
expect(provider.send(:generate_description)[1]).not_to match(/lastline/)
end
- it 'reports a dsc resource has not been changed if the LCM reported no change was required' do
- dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', false, ['resourcename does nothing', 'lastline'])
- provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
+ it "reports a dsc resource has not been changed if the LCM reported no change was required" do
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new("resourcename", false, ["resourcename does nothing", "lastline"])
+ provider.instance_variable_set("@dsc_resources_info", [dsc_resource_info])
expect(provider.send(:generate_description)[1]).to match(/converge DSC resource resourcename by doing nothing/)
end
end
end
- context 'when Dsc is not available' do
+ context "when Dsc is not available" do
let (:node) { Chef::Node.new }
let (:events) { Chef::EventDispatch::Dispatcher.new }
let (:run_context) { Chef::RunContext.new(node, {}, events) }
- let (:resource) { Chef::Resource::DscScript.new('script', run_context) }
+ let (:resource) { Chef::Resource::DscScript.new("script", run_context) }
let (:provider) { Chef::Provider::DscScript.new(resource, run_context) }
- describe 'action_run' do
- ['1.0', '2.0', '3.0'].each do |version|
+ describe "action_run" do
+ ["1.0", "2.0", "3.0"].each do |version|
it "raises an exception for powershell version '#{version}'" do
node.automatic[:languages][:powershell][:version] = version
- expect {
+ expect do
provider.run_action(:run)
- }.to raise_error(Chef::Exceptions::ProviderNotFound)
+ end.to raise_error(Chef::Exceptions::ProviderNotFound)
end
end
- it 'raises an exception if Powershell is not present' do
- expect {
+ it "raises an exception if Powershell is not present" do
+ expect do
provider.run_action(:run)
- }.to raise_error(Chef::Exceptions::ProviderNotFound)
+ end.to raise_error(Chef::Exceptions::ProviderNotFound)
end
end
end
end
-
diff --git a/spec/unit/provider/env/windows_spec.rb b/spec/unit/provider/env/windows_spec.rb
index 99f33d392a..5ddc1d6f91 100644
--- a/spec/unit/provider/env/windows_spec.rb
+++ b/spec/unit/provider/env/windows_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Sander van Harmelen <svanharmelen@schubergphilis.com>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,86 +16,86 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Env::Windows, :windows_only do
let(:node) { Chef::Node.new }
- let(:events) {Chef::EventDispatch::Dispatcher.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
let(:run_context) { Chef::RunContext.new(node, {}, events) }
- context 'when environment variable is not PATH' do
- let(:new_resource) {
+ context "when environment variable is not PATH" do
+ let(:new_resource) do
new_resource = Chef::Resource::Env.new("CHEF_WINDOWS_ENV_TEST")
new_resource.value("foo")
new_resource
- }
- let(:provider) {
- provider = Chef::Provider::Env::Windows.new(new_resource, run_context)
- allow(provider).to receive(:env_obj).and_return(double('null object').as_null_object)
+ end
+ let(:provider) do
+ provider = Chef::Provider::Env::Windows.new(new_resource, run_context)
+ allow(provider).to receive(:env_obj).and_return(double("null object").as_null_object)
provider
- }
+ end
describe "action_create" do
before do
- ENV.delete('CHEF_WINDOWS_ENV_TEST')
+ ENV.delete("CHEF_WINDOWS_ENV_TEST")
provider.key_exists = false
end
it "should update the ruby ENV object when it creates the key" do
provider.action_create
- expect(ENV['CHEF_WINDOWS_ENV_TEST']).to eql('foo')
+ expect(ENV["CHEF_WINDOWS_ENV_TEST"]).to eql("foo")
end
end
describe "action_modify" do
before do
- ENV['CHEF_WINDOWS_ENV_TEST'] = 'foo'
+ ENV["CHEF_WINDOWS_ENV_TEST"] = "foo"
end
it "should update the ruby ENV object when it updates the value" do
expect(provider).to receive(:requires_modify_or_create?).and_return(true)
new_resource.value("foobar")
provider.action_modify
- expect(ENV['CHEF_WINDOWS_ENV_TEST']).to eql('foobar')
+ expect(ENV["CHEF_WINDOWS_ENV_TEST"]).to eql("foobar")
end
describe "action_delete" do
before do
- ENV['CHEF_WINDOWS_ENV_TEST'] = 'foo'
+ ENV["CHEF_WINDOWS_ENV_TEST"] = "foo"
end
it "should update the ruby ENV object when it deletes the key" do
provider.action_delete
- expect(ENV['CHEF_WINDOWS_ENV_TEST']).to eql(nil)
+ expect(ENV["CHEF_WINDOWS_ENV_TEST"]).to eql(nil)
end
end
end
end
- context 'when environment is PATH' do
+ context "when environment is PATH" do
describe "for PATH" do
- let(:system_root) {'%SystemRoot%'}
+ let(:system_root) { "%SystemRoot%" }
let(:system_root_value) { 'D:\Windows' }
- let(:new_resource) {
- new_resource = Chef::Resource::Env.new('PATH')
+ let(:new_resource) do
+ new_resource = Chef::Resource::Env.new("PATH")
new_resource.value(system_root)
new_resource
- }
- let(:provider) {
- provider = Chef::Provider::Env::Windows.new(new_resource, run_context)
- allow(provider).to receive(:env_obj).and_return(double('null object').as_null_object)
+ end
+ let(:provider) do
+ provider = Chef::Provider::Env::Windows.new(new_resource, run_context)
+ allow(provider).to receive(:env_obj).and_return(double("null object").as_null_object)
provider
- }
+ end
before do
- stub_const('ENV', {'PATH' => ''})
+ stub_const("ENV", { "PATH" => "" })
end
it "replaces Windows system variables" do
expect(provider).to receive(:requires_modify_or_create?).and_return(true)
expect(provider).to receive(:expand_path).with(system_root).and_return(system_root_value)
provider.action_modify
- expect(ENV['PATH']).to eql(system_root_value)
+ expect(ENV["PATH"]).to eql(system_root_value)
end
end
diff --git a/spec/unit/provider/env_spec.rb b/spec/unit/provider/env_spec.rb
index 230603dcb3..e99aee5ad1 100644
--- a/spec/unit/provider/env_spec.rb
+++ b/spec/unit/provider/env_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Env do
@@ -199,12 +199,12 @@ describe Chef::Provider::Env do
expect(@new_resource).to be_updated
end
- context "when new_resource's value contains the delimiter" do
+ context "when new_resource's value contains the delimiter" do
it "should return false if all the elements are deleted" do
# This indicates that the entire key needs to be deleted
@new_resource.value("C:/foo/bin;C:/bar/bin")
expect(@provider.delete_element).to eql(false)
- expect(@new_resource).not_to be_updated # This will be updated in action_delete
+ expect(@new_resource).not_to be_updated # This will be updated in action_delete
end
it "should return true if any, but not all, of the elements are deleted" do
@@ -251,7 +251,7 @@ describe Chef::Provider::Env do
expect(@provider.requires_modify_or_create?).to be_truthy
end
- context "when new_resource's value contains the delimiter" do
+ context "when new_resource's value contains the delimiter" do
it "should return false if all the current values are contained in specified order" do
@new_resource.value("C:/biz;C:/baz")
@new_resource.delim(";")
diff --git a/spec/unit/provider/erl_call_spec.rb b/spec/unit/provider/erl_call_spec.rb
index 2fb7e5b737..f1c229028a 100644
--- a/spec/unit/provider/erl_call_spec.rb
+++ b/spec/unit/provider/erl_call_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::ErlCall do
before(:each) do
@@ -33,7 +33,7 @@ describe Chef::Provider::ErlCall do
allow(@provider).to receive(:popen4).and_return(@status)
@stdin = StringIO.new
- @stdout = StringIO.new('{ok, woohoo}')
+ @stdout = StringIO.new("{ok, woohoo}")
@stderr = StringIO.new
@pid = 2342999
end
@@ -83,4 +83,3 @@ describe Chef::Provider::ErlCall do
end
end
-
diff --git a/spec/unit/provider/execute_spec.rb b/spec/unit/provider/execute_spec.rb
index e7607d9417..1901e2ea03 100644
--- a/spec/unit/provider/execute_spec.rb
+++ b/spec/unit/provider/execute_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Prajakta Purohit (<prajakta@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Execute do
@@ -25,6 +25,8 @@ describe Chef::Provider::Execute do
let(:run_context) { Chef::RunContext.new(node, {}, events) }
let(:provider) { Chef::Provider::Execute.new(new_resource, run_context) }
let(:current_resource) { Chef::Resource::Ifconfig.new("foo_resource", run_context) }
+ # You will be the same object, I promise.
+ @live_stream = Chef::EventDispatch::EventsOutputStream.new(run_context.events, :name => :execute)
let(:opts) do
{
@@ -32,21 +34,23 @@ describe Chef::Provider::Execute do
returns: 0,
log_level: :info,
log_tag: new_resource.to_s,
- live_stream: STDOUT,
}
end
let(:new_resource) { Chef::Resource::Execute.new("foo_resource", run_context) }
before do
+ allow(Chef::EventDispatch::EventsOutputStream).to receive(:new) { @live_stream }
allow(ChefConfig).to receive(:windows?) { false }
@original_log_level = Chef::Log.level
Chef::Log.level = :info
- allow(STDOUT).to receive(:tty?).and_return(true)
+ allow(STDOUT).to receive(:tty?).and_return(false)
end
after do
Chef::Log.level = @original_log_level
+ Chef::Config[:always_stream_execute] = false
+ Chef::Config[:daemon] = false
end
describe "#initialize" do
@@ -114,7 +118,7 @@ describe Chef::Provider::Execute do
new_resource.creates "foo_resource"
end
- it "should warn in Chef-12", :chef_lt_13_only do
+ it "should warn in Chef-12", chef: "< 13" do
expect(Chef::Log).to receive(:warn).with(/relative path/)
expect(FileTest).to receive(:exist?).with(new_resource.creates).and_return(true)
expect(provider).not_to receive(:shell_out!)
@@ -122,11 +126,11 @@ describe Chef::Provider::Execute do
expect(new_resource).not_to be_updated
end
- it "should raise if user specified relative path without cwd for Chef-13", :chef_gte_13_only do
+ it "should raise if user specified relative path without cwd for Chef-13", chef: ">= 13" do
expect(Chef::Log).to receive(:warn).with(/relative path/)
expect(FileTest).to receive(:exist?).with(new_resource.creates).and_return(true)
expect(provider).not_to receive(:shell_out!)
- expect { provider.run_action(:run) }.to raise_error # @todo: add a real error for Chef-13
+ expect { provider.run_action(:run) }.to raise_error # @todo: add a real error for Chef-13
end
end
@@ -142,37 +146,6 @@ describe Chef::Provider::Execute do
expect(new_resource).not_to be_updated
end
- it "should unset the live_stream if STDOUT is not a tty" do
- expect(STDOUT).to receive(:tty?).and_return(false)
- opts.delete(:live_stream)
- expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
- expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
- expect(Chef::Log).not_to receive(:warn)
- provider.run_action(:run)
- expect(new_resource).to be_updated
- end
-
- it "should unset the live_stream if chef is running as a daemon" do
- allow(Chef::Config).to receive(:[]).and_call_original
- expect(Chef::Config).to receive(:[]).with(:daemon).and_return(true)
- opts.delete(:live_stream)
- expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
- expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
- expect(Chef::Log).not_to receive(:warn)
- provider.run_action(:run)
- expect(new_resource).to be_updated
- end
-
- it "should unset the live_stream if we are not running with a log level of at least :info" do
- expect(Chef::Log).to receive(:info?).and_return(false)
- opts.delete(:live_stream)
- expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
- expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
- expect(Chef::Log).not_to receive(:warn)
- provider.run_action(:run)
- expect(new_resource).to be_updated
- end
-
it "should not include stdout/stderr in failure exception for sensitive resource" do
opts.delete(:live_stream)
new_resource.sensitive true
@@ -181,5 +154,89 @@ describe Chef::Provider::Execute do
provider.run_action(:run)
end.to raise_error(Mixlib::ShellOut::ShellCommandFailed, /suppressed for sensitive resource/)
end
+
+ describe "streaming output" do
+ it "should not set the live_stream if sensitive is on" do
+ new_resource.sensitive true
+ expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
+ expect(provider).to receive(:converge_by).with("execute sensitive resource").and_call_original
+ expect(Chef::Log).not_to receive(:warn)
+ provider.run_action(:run)
+ expect(new_resource).to be_updated
+ end
+
+ describe "with an output formatter listening" do
+ let(:events) { d = Chef::EventDispatch::Dispatcher.new; d.register(Chef::Formatters::Doc.new(StringIO.new, StringIO.new)); d }
+
+ before do
+ Chef::Config[:stream_execute_output] = true
+ end
+
+ it "should set the live_stream if the log level is info or above" do
+ nopts = opts
+ nopts[:live_stream] = @live_stream
+ expect(provider).to receive(:shell_out!).with(new_resource.name, nopts)
+ expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
+ expect(Chef::Log).not_to receive(:warn)
+ provider.run_action(:run)
+ expect(new_resource).to be_updated
+ end
+
+ it "should set the live_stream if the resource requests live streaming" do
+ Chef::Log.level = :warn
+ new_resource.live_stream true
+ nopts = opts
+ nopts[:live_stream] = @live_stream
+ expect(provider).to receive(:shell_out!).with(new_resource.name, nopts)
+ expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
+ expect(Chef::Log).not_to receive(:warn)
+ provider.run_action(:run)
+ expect(new_resource).to be_updated
+ end
+
+ it "should not set the live_stream if the resource is sensitive" do
+ new_resource.sensitive true
+ expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
+ expect(provider).to receive(:converge_by).with("execute sensitive resource").and_call_original
+ expect(Chef::Log).not_to receive(:warn)
+ provider.run_action(:run)
+ expect(new_resource).to be_updated
+ end
+ end
+
+ describe "with only logging enabled" do
+ it "should set the live_stream to STDOUT if we are a TTY, not daemonized, not sensitive, and info is enabled" do
+ nopts = opts
+ nopts[:live_stream] = STDOUT
+ allow(STDOUT).to receive(:tty?).and_return(true)
+ expect(provider).to receive(:shell_out!).with(new_resource.name, nopts)
+ expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
+ expect(Chef::Log).not_to receive(:warn)
+ provider.run_action(:run)
+ expect(new_resource).to be_updated
+ end
+
+ it "should not set the live_stream to STDOUT if we are a TTY, not daemonized, but sensitive" do
+ new_resource.sensitive true
+ allow(STDOUT).to receive(:tty?).and_return(true)
+ expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
+ expect(provider).to receive(:converge_by).with("execute sensitive resource").and_call_original
+ expect(Chef::Log).not_to receive(:warn)
+ provider.run_action(:run)
+ expect(new_resource).to be_updated
+ end
+
+ it "should not set the live_stream to STDOUT if we are a TTY, but daemonized" do
+ Chef::Config[:daemon] = true
+ allow(STDOUT).to receive(:tty?).and_return(true)
+ expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
+ expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
+ expect(Chef::Log).not_to receive(:warn)
+ provider.run_action(:run)
+ expect(new_resource).to be_updated
+ end
+
+ end
+ end
end
end
diff --git a/spec/unit/provider/file/content_spec.rb b/spec/unit/provider/file/content_spec.rb
index 0a45d15bc9..f840d92dbb 100644
--- a/spec/unit/provider/file/content_spec.rb
+++ b/spec/unit/provider/file/content_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::File::Content do
@@ -28,12 +28,12 @@ describe Chef::Provider::File::Content do
double("Chef::Provider::File::Resource (current)")
end
- let(:enclosing_directory) {
+ let(:enclosing_directory) do
canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
- }
- let(:resource_path) {
+ end
+ let(:resource_path) do
canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt")))
- }
+ end
let(:new_resource) do
double("Chef::Provider::File::Resource (new)", :name => "seattle.txt", :path => resource_path)
@@ -66,34 +66,34 @@ describe Chef::Provider::File::Content do
it "returns a tempfile in the tempdir when :file_staging_uses_destdir is not set" do
Chef::Config[:file_staging_uses_destdir] = false
- expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be_truthy
+ expect(content.tempfile.path.start_with?(Dir.tmpdir)).to be_truthy
expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be_falsey
end
it "returns a tempfile in the destdir when :file_deployment_uses_destdir is set" do
Chef::Config[:file_staging_uses_destdir] = true
- expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be_falsey
+ expect(content.tempfile.path.start_with?(Dir.tmpdir)).to be_falsey
expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be_truthy
end
context "when creating a tempfiles in destdir fails" do
- let(:enclosing_directory) {
+ let(:enclosing_directory) do
canonicalize_path("/nonexisting/path")
- }
+ end
it "returns a tempfile in the tempdir when :file_deployment_uses_destdir is set to :auto" do
Chef::Config[:file_staging_uses_destdir] = :auto
- expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be_truthy
+ expect(content.tempfile.path.start_with?(Dir.tmpdir)).to be_truthy
expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be_falsey
end
it "fails when :file_desployment_uses_destdir is set" do
Chef::Config[:file_staging_uses_destdir] = true
- expect{content.tempfile}.to raise_error
+ expect { content.tempfile }.to raise_error(Chef::Exceptions::FileContentStagingError)
end
it "returns a tempfile in the tempdir when :file_desployment_uses_destdir is not set" do
- expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be_truthy
+ expect(content.tempfile.path.start_with?(Dir.tmpdir)).to be_truthy
expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be_falsey
end
end
diff --git a/spec/unit/provider/file_spec.rb b/spec/unit/provider/file_spec.rb
index 504ae045d9..d8d4ed2286 100644
--- a/spec/unit/provider/file_spec.rb
+++ b/spec/unit/provider/file_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2008-2013 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'support/shared/unit/provider/file'
+require "support/shared/unit/provider/file"
describe Chef::Provider::File do
@@ -29,18 +29,18 @@ describe Chef::Provider::File do
end
let(:content) do
- content = double('Chef::Provider::File::Content')
+ content = double("Chef::Provider::File::Content")
end
- let(:node) { double('Chef::Node') }
- let(:events) { double('Chef::Events').as_null_object } # mock all the methods
- let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
- let(:enclosing_directory) {
+ let(:node) { double("Chef::Node") }
+ let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+ let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
+ let(:enclosing_directory) do
canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
- }
- let(:resource_path) {
+ end
+ let(:resource_path) do
canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt")))
- }
+ end
# Subject
@@ -54,4 +54,3 @@ describe Chef::Provider::File do
it_behaves_like "a file provider with content field"
end
-
diff --git a/spec/unit/provider/git_spec.rb b/spec/unit/provider/git_spec.rb
index 0106244665..a60c1b44c3 100644
--- a/spec/unit/provider/git_spec.rb
+++ b/spec/unit/provider/git_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,7 @@
# limitations under the License.
#
-
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Git do
before(:each) do
@@ -59,7 +58,7 @@ describe Chef::Provider::Git do
it "determines the current revision when there is one" do
expect(::File).to receive(:exist?).with("/my/deploy/dir/.git").and_return(true)
@stdout = "9b4d8dc38dd471246e7cfb1c3c1ad14b0f2bee13\n"
- expect(@provider).to receive(:shell_out!).with('git rev-parse HEAD', {:cwd => '/my/deploy/dir', :returns => [0,128]}).and_return(double("ShellOut result", :stdout => @stdout))
+ expect(@provider).to receive(:shell_out!).with("git rev-parse HEAD", { :cwd => "/my/deploy/dir", :returns => [0, 128], :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
expect(@provider.find_current_revision).to eql("9b4d8dc38dd471246e7cfb1c3c1ad14b0f2bee13")
end
@@ -67,7 +66,7 @@ describe Chef::Provider::Git do
expect(::File).to receive(:exist?).with("/my/deploy/dir/.git").and_return(true)
@stderr = "fatal: Not a git repository (or any of the parent directories): .git"
@stdout = ""
- expect(@provider).to receive(:shell_out!).with('git rev-parse HEAD', :cwd => '/my/deploy/dir', :returns => [0,128]).and_return(double("ShellOut result", :stdout => "", :stderr => @stderr))
+ expect(@provider).to receive(:shell_out!).with("git rev-parse HEAD", :cwd => "/my/deploy/dir", :returns => [0, 128], :log_tag => "git[web2.0 app]" ).and_return(double("ShellOut result", :stdout => "", :stderr => @stderr))
expect(@provider.find_current_revision).to be_nil
end
end
@@ -98,7 +97,7 @@ describe Chef::Provider::Git do
@resource.revision "v1.0"
@stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
"503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
- expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
expect(@provider.target_revision).to eql("503c22a5e41f5ae3193460cca044ed1435029f53")
end
@@ -107,7 +106,7 @@ describe Chef::Provider::Git do
@stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
"503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n" +
"663c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0^{}\n")
- expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
expect(@provider.target_revision).to eql("663c22a5e41f5ae3193460cca044ed1435029f53")
end
@@ -116,7 +115,7 @@ describe Chef::Provider::Git do
@stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
"663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/releases/v1.0\n" +
"503c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n")
- expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
expect(@provider.target_revision).to eql("503c22a5e41f5ae3193460cca044ed1435029f53")
end
@@ -125,7 +124,7 @@ describe Chef::Provider::Git do
@stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
"663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n" +
"503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
- expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
expect(@provider.target_revision).to eql("663c22a5e41f5ae3193460cca044ed1435029f53")
end
@@ -134,7 +133,7 @@ describe Chef::Provider::Git do
@stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
"663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.1\n" +
"503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
- expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
expect(@provider.target_revision).to eql("503c22a5e41f5ae3193460cca044ed1435029f53")
end
@@ -144,7 +143,7 @@ describe Chef::Provider::Git do
"663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n" +
"805c22a5e41f5ae3193460cca044ed1435029f53\trefs/pulls/v1.0\n" +
"503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
- expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"refs/pulls/v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"refs/pulls/v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
expect(@provider.target_revision).to eql("805c22a5e41f5ae3193460cca044ed1435029f53")
end
@@ -153,7 +152,7 @@ describe Chef::Provider::Git do
@stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
"663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n" +
"503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
- expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"refs/heads/v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"refs/heads/v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
expect(@provider.target_revision).to eql("503c22a5e41f5ae3193460cca044ed1435029f53")
end
@@ -162,7 +161,7 @@ describe Chef::Provider::Git do
@provider.action = :checkout
@provider.define_resource_requirements
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
- expect {@provider.process_resource_requirements}.to raise_error(Chef::Exceptions::InvalidRemoteGitReference)
+ expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::InvalidRemoteGitReference)
end
it "raises an unresolvable git reference error if the revision can't be resolved to any revision and assertions are run" do
@@ -182,7 +181,7 @@ describe Chef::Provider::Git do
it "does not raise an error when the revision is valid and assertions are run." do
@resource.revision "0.8-alpha"
@stdout = "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n"
- expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"0.8-alpha*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"0.8-alpha*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
@provider.action = :checkout
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
@provider.define_resource_requirements
@@ -190,7 +189,7 @@ describe Chef::Provider::Git do
end
it "gives the latest HEAD revision SHA if nothing is specified" do
- @stdout =<<-SHAS
+ @stdout = <<-SHAS
28af684d8460ba4793eda3e7ac238c864a5d029a\tHEAD
503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha
28af684d8460ba4793eda3e7ac238c864a5d029a\trefs/heads/master
@@ -206,8 +205,8 @@ d7b9957f67236fa54e660cc3ab45ffecd6e0ba38\trefs/tags/0.7.8
b7d19519a1c15f1c1a324e2683bd728b6198ce5a\trefs/tags/0.7.8^{}
ebc1b392fe7e8f0fbabc305c299b4d365d2b4d9b\trefs/tags/chef-server-package
SHAS
- @resource.revision ''
- expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"HEAD\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ @resource.revision ""
+ expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"HEAD\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
expect(@provider.target_revision).to eql("28af684d8460ba4793eda3e7ac238c864a5d029a")
end
end
@@ -219,12 +218,12 @@ SHAS
context "with an ssh wrapper" do
let(:deploy_user) { "deployNinja" }
let(:wrapper) { "do_it_this_way.sh" }
- let(:expected_cmd) { 'git clone "git://github.com/opscode/chef.git" "/my/deploy/dir"' }
+ let(:expected_cmd) { 'git clone "git://github.com/opscode/chef.git" "/my/deploy/dir"' }
let(:default_options) do
{
:user => deploy_user,
:environment => { "GIT_SSH" => wrapper, "HOME" => "/home/deployNinja" },
- :log_tag => "git[web2.0 app]"
+ :log_tag => "git[web2.0 app]",
}
end
before do
@@ -248,13 +247,13 @@ SHAS
end
context "with a specific home" do
let (:override_home) do
- {"HOME" => "/home/masterNinja"}
+ { "HOME" => "/home/masterNinja" }
end
let(:overrided_options) do
{
:user => deploy_user,
:environment => { "GIT_SSH" => wrapper, "HOME" => "/home/masterNinja" },
- :log_tag => "git[web2.0 app]"
+ :log_tag => "git[web2.0 app]",
}
end
before do
@@ -268,24 +267,60 @@ SHAS
end
end
+ context "with a user id" do
+ let(:deploy_user) { 123 }
+ let(:expected_cmd) { 'git clone "git://github.com/opscode/chef.git" "/my/deploy/dir"' }
+ let(:default_options) do
+ {
+ :user => 123,
+ :environment => { "HOME" => "/home/deployNinja" },
+ :log_tag => "git[web2.0 app]",
+ }
+ end
+ before do
+ @resource.user deploy_user
+ allow(Etc).to receive(:getpwuid).and_return(double("Struct::Passwd", :name => @resource.user, :dir => "/home/deployNinja"))
+ end
+ context "with a specific home" do
+ let (:override_home) do
+ { "HOME" => "/home/masterNinja" }
+ end
+ let(:overrided_options) do
+ {
+ :user => 123,
+ :environment => { "HOME" => "/home/masterNinja" },
+ :log_tag => "git[web2.0 app]",
+ }
+ end
+ before do
+ @resource.environment(override_home)
+ end
+ before { @resource.environment(override_home) }
+ it "clones a repo with amended git options with specific home" do
+ expect(@provider).to receive(:shell_out!).with(expected_cmd, hash_including(overrided_options))
+ @provider.clone
+ end
+ end
+ end
+
it "runs a clone command with escaped destination" do
@resource.user "deployNinja"
allow(Etc).to receive(:getpwnam).and_return(double("Struct::Passwd", :name => @resource.user, :dir => "/home/deployNinja"))
@resource.destination "/Application Support/with/space"
@resource.ssh_wrapper "do_it_this_way.sh"
- expected_cmd = "git clone \"git://github.com/opscode/chef.git\" \"/Application Support/with/space\""
+ expected_cmd = "git clone \"git://github.com/opscode/chef.git\" \"/Application Support/with/space\""
expect(@provider).to receive(:shell_out!).with(expected_cmd, :user => "deployNinja",
- :environment =>{"GIT_SSH"=>"do_it_this_way.sh",
- "HOME" => "/home/deployNinja"},
- :log_tag => "git[web2.0 app]")
+ :log_tag => "git[web2.0 app]",
+ :environment => { "HOME" => "/home/deployNinja",
+ "GIT_SSH" => "do_it_this_way.sh" })
@provider.clone
end
it "compiles a clone command using --depth for shallow cloning" do
@resource.depth 5
expected_cmd = "git clone --depth 5 \"git://github.com/opscode/chef.git\" \"/my/deploy/dir\""
- version_response = double('shell_out')
- allow(version_response).to receive(:stdout) { 'git version 1.7.9' }
+ version_response = double("shell_out")
+ allow(version_response).to receive(:stdout) { "git version 1.7.9" }
expect(@provider).to receive(:shell_out!).with("git --version",
:log_tag => "git[web2.0 app]").and_return(version_response)
expect(@provider).to receive(:shell_out!).with(expected_cmd, :log_tag => "git[web2.0 app]")
@@ -295,8 +330,8 @@ SHAS
it "compiles a clone command using --no-single-branch for shallow cloning when git >= 1.7.10" do
@resource.depth 5
expected_cmd = "git clone --depth 5 --no-single-branch \"git://github.com/opscode/chef.git\" \"/my/deploy/dir\""
- version_response = double('shell_out')
- allow(version_response).to receive(:stdout) { 'git version 1.7.10' }
+ version_response = double("shell_out")
+ allow(version_response).to receive(:stdout) { "git version 1.7.10" }
expect(@provider).to receive(:shell_out!).with("git --version",
:log_tag => "git[web2.0 app]").and_return(version_response)
expect(@provider).to receive(:shell_out!).with(expected_cmd, :log_tag => "git[web2.0 app]")
@@ -311,10 +346,10 @@ SHAS
end
it "runs a checkout command with default options" do
- expect(@provider).to receive(:shell_out!).with('git branch -f deploy d35af14d41ae22b19da05d7d03a0bafc321b244c', :cwd => "/my/deploy/dir",
- :log_tag => "git[web2.0 app]").ordered
- expect(@provider).to receive(:shell_out!).with('git checkout deploy', :cwd => "/my/deploy/dir",
- :log_tag => "git[web2.0 app]").ordered
+ expect(@provider).to receive(:shell_out!).with("git branch -f deploy d35af14d41ae22b19da05d7d03a0bafc321b244c", :cwd => "/my/deploy/dir",
+ :log_tag => "git[web2.0 app]").ordered
+ expect(@provider).to receive(:shell_out!).with("git checkout deploy", :cwd => "/my/deploy/dir",
+ :log_tag => "git[web2.0 app]").ordered
@provider.checkout
end
@@ -322,7 +357,7 @@ SHAS
@resource.enable_submodules true
expected_cmd = "git submodule sync"
expect(@provider).to receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir",
- :log_tag => "git[web2.0 app]")
+ :log_tag => "git[web2.0 app]")
expected_cmd = "git submodule update --init --recursive"
expect(@provider).to receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
@provider.enable_submodules
@@ -335,8 +370,12 @@ SHAS
it "runs a sync command with default options" do
expect(@provider).to receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository)
- expected_cmd = "git fetch origin && git fetch origin --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c"
- expect(@provider).to receive(:shell_out!).with(expected_cmd, :cwd=> "/my/deploy/dir", :log_tag => "git[web2.0 app]")
+ expected_cmd1 = "git fetch origin"
+ expect(@provider).to receive(:shell_out!).with(expected_cmd1, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
+ expected_cmd2 = "git fetch origin --tags"
+ expect(@provider).to receive(:shell_out!).with(expected_cmd2, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
+ expected_cmd3 = "git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c"
+ expect(@provider).to receive(:shell_out!).with(expected_cmd3, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
@provider.fetch_updates
end
@@ -345,40 +384,59 @@ SHAS
allow(Etc).to receive(:getpwnam).and_return(double("Struct::Passwd", :name => @resource.user, :dir => "/home/whois"))
@resource.group("thisis")
expect(@provider).to receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository)
- expected_cmd = "git fetch origin && git fetch origin --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c"
- expect(@provider).to receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir",
- :user => "whois", :group => "thisis",
- :log_tag => "git[web2.0 app]",
- :environment=>{"HOME"=>"/home/whois"})
+
+ expected_cmd1 = "git fetch origin"
+ expect(@provider).to receive(:shell_out!).with(expected_cmd1, :cwd => "/my/deploy/dir",
+ :user => "whois", :group => "thisis",
+ :log_tag => "git[web2.0 app]",
+ :environment => { "HOME" => "/home/whois" })
+ expected_cmd2 = "git fetch origin --tags"
+ expect(@provider).to receive(:shell_out!).with(expected_cmd2, :cwd => "/my/deploy/dir",
+ :user => "whois", :group => "thisis",
+ :log_tag => "git[web2.0 app]",
+ :environment => { "HOME" => "/home/whois" })
+ expected_cmd3 = "git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c"
+ expect(@provider).to receive(:shell_out!).with(expected_cmd3, :cwd => "/my/deploy/dir",
+ :user => "whois", :group => "thisis",
+ :log_tag => "git[web2.0 app]",
+ :environment => { "HOME" => "/home/whois" })
@provider.fetch_updates
end
it "configures remote tracking branches when remote is ``origin''" do
@resource.remote "origin"
expect(@provider).to receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository)
- fetch_command = "git fetch origin && git fetch origin --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c"
- expect(@provider).to receive(:shell_out!).with(fetch_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
+ fetch_command1 = "git fetch origin"
+ expect(@provider).to receive(:shell_out!).with(fetch_command1, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
+ fetch_command2 = "git fetch origin --tags"
+ expect(@provider).to receive(:shell_out!).with(fetch_command2, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
+ fetch_command3 = "git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c"
+ expect(@provider).to receive(:shell_out!).with(fetch_command3, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
@provider.fetch_updates
end
it "configures remote tracking branches when remote is not ``origin''" do
@resource.remote "opscode"
expect(@provider).to receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository)
- fetch_command = "git fetch opscode && git fetch opscode --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c"
- expect(@provider).to receive(:shell_out!).with(fetch_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
+ fetch_command1 = "git fetch opscode"
+ expect(@provider).to receive(:shell_out!).with(fetch_command1, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
+ fetch_command2 = "git fetch opscode --tags"
+ expect(@provider).to receive(:shell_out!).with(fetch_command2, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
+ fetch_command3 = "git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c"
+ expect(@provider).to receive(:shell_out!).with(fetch_command3, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
@provider.fetch_updates
end
context "configuring remote tracking branches" do
it "checks if a remote with this name already exists" do
- command_response = double('shell_out')
+ command_response = double("shell_out")
allow(command_response).to receive(:exitstatus) { 1 }
expected_command = "git config --get remote.#{@resource.remote}.url"
expect(@provider).to receive(:shell_out!).with(expected_command,
:cwd => "/my/deploy/dir",
:log_tag => "git[web2.0 app]",
- :returns => [0,1,2]).and_return(command_response)
+ :returns => [0, 1, 2]).and_return(command_response)
add_remote_command = "git remote add #{@resource.remote} #{@resource.repository}"
expect(@provider).to receive(:shell_out!).with(add_remote_command,
:cwd => "/my/deploy/dir",
@@ -390,7 +448,7 @@ SHAS
@resource.user("whois")
@resource.group("thisis")
allow(Etc).to receive(:getpwnam).and_return(double("Struct::Passwd", :name => @resource.user, :dir => "/home/whois"))
- command_response = double('shell_out')
+ command_response = double("shell_out")
allow(command_response).to receive(:exitstatus) { 1 }
expected_command = "git config --get remote.#{@resource.remote}.url"
expect(@provider).to receive(:shell_out!).with(expected_command,
@@ -398,27 +456,27 @@ SHAS
:log_tag => "git[web2.0 app]",
:user => "whois",
:group => "thisis",
- :environment=>{"HOME"=>"/home/whois"},
- :returns => [0,1,2]).and_return(command_response)
+ :environment => { "HOME" => "/home/whois" },
+ :returns => [0, 1, 2]).and_return(command_response)
add_remote_command = "git remote add #{@resource.remote} #{@resource.repository}"
expect(@provider).to receive(:shell_out!).with(add_remote_command,
:cwd => "/my/deploy/dir",
:log_tag => "git[web2.0 app]",
:user => "whois",
:group => "thisis",
- :environment=>{"HOME"=>"/home/whois"})
+ :environment => { "HOME" => "/home/whois" })
@provider.setup_remote_tracking_branches(@resource.remote, @resource.repository)
end
describe "when a remote with a given name hasn't been configured yet" do
it "adds a new remote " do
- command_response = double('shell_out')
+ command_response = double("shell_out")
allow(command_response).to receive(:exitstatus) { 1 }
check_remote_command = "git config --get remote.#{@resource.remote}.url"
expect(@provider).to receive(:shell_out!).with(check_remote_command,
:cwd => "/my/deploy/dir",
:log_tag => "git[web2.0 app]",
- :returns => [0,1,2]).and_return(command_response)
+ :returns => [0, 1, 2]).and_return(command_response)
expected_command = "git remote add #{@resource.remote} #{@resource.repository}"
expect(@provider).to receive(:shell_out!).with(expected_command,
:cwd => "/my/deploy/dir",
@@ -429,14 +487,14 @@ SHAS
describe "when a remote with a given name has already been configured" do
it "updates remote url when the url is different" do
- command_response = double('shell_out')
+ command_response = double("shell_out")
allow(command_response).to receive(:exitstatus) { 0 }
allow(command_response).to receive(:stdout) { "some_other_url" }
check_remote_command = "git config --get remote.#{@resource.remote}.url"
expect(@provider).to receive(:shell_out!).with(check_remote_command,
:cwd => "/my/deploy/dir",
:log_tag => "git[web2.0 app]",
- :returns => [0,1,2]).and_return(command_response)
+ :returns => [0, 1, 2]).and_return(command_response)
expected_command = "git config --replace-all remote.#{@resource.remote}.url #{@resource.repository}"
expect(@provider).to receive(:shell_out!).with(expected_command,
:cwd => "/my/deploy/dir",
@@ -445,14 +503,14 @@ SHAS
end
it "doesn't update remote url when the url is the same" do
- command_response = double('shell_out')
+ command_response = double("shell_out")
allow(command_response).to receive(:exitstatus) { 0 }
allow(command_response).to receive(:stdout) { @resource.repository }
check_remote_command = "git config --get remote.#{@resource.remote}.url"
expect(@provider).to receive(:shell_out!).with(check_remote_command,
:cwd => "/my/deploy/dir",
:log_tag => "git[web2.0 app]",
- :returns => [0,1,2]).and_return(command_response)
+ :returns => [0, 1, 2]).and_return(command_response)
unexpected_command = "git config --replace-all remote.#{@resource.remote}.url #{@resource.repository}"
expect(@provider).not_to receive(:shell_out!).with(unexpected_command,
:cwd => "/my/deploy/dir",
@@ -461,13 +519,13 @@ SHAS
end
it "resets remote url when it has multiple values" do
- command_response = double('shell_out')
+ command_response = double("shell_out")
allow(command_response).to receive(:exitstatus) { 2 }
check_remote_command = "git config --get remote.#{@resource.remote}.url"
expect(@provider).to receive(:shell_out!).with(check_remote_command,
:cwd => "/my/deploy/dir",
:log_tag => "git[web2.0 app]",
- :returns => [0,1,2]).and_return(command_response)
+ :returns => [0, 1, 2]).and_return(command_response)
expected_command = "git config --replace-all remote.#{@resource.remote}.url #{@resource.repository}"
expect(@provider).to receive(:shell_out!).with(expected_command,
:cwd => "/my/deploy/dir",
@@ -479,7 +537,7 @@ SHAS
it "raises an error if the git clone command would fail because the enclosing directory doesn't exist" do
allow(@provider).to receive(:shell_out!)
- expect {@provider.run_action(:sync)}.to raise_error(Chef::Exceptions::MissingParentDirectory)
+ expect { @provider.run_action(:sync) }.to raise_error(Chef::Exceptions::MissingParentDirectory)
end
it "does a checkout by cloning the repo and then enabling submodules" do
@@ -488,7 +546,7 @@ SHAS
allow(::File).to receive(:exist?).with("/my/deploy/dir").and_return(true)
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
- allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return(['.','..'])
+ allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return([".", ".."])
expect(@provider).to receive(:clone)
expect(@provider).to receive(:checkout)
expect(@provider).to receive(:enable_submodules)
@@ -504,7 +562,7 @@ SHAS
allow(::File).to receive(:exist?).with("/my/deploy/dir").and_return(true)
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
- allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return(['.','..'])
+ allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return([".", ".."])
@resource.enable_checkout false
expect(@provider).to receive(:clone)
@@ -519,7 +577,7 @@ SHAS
allow(::File).to receive(:exist?).with("/my/deploy/dir/.git").and_return(false)
allow(::File).to receive(:exist?).with("/my/deploy/dir").and_return(false)
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
- allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return(['..','.'])
+ allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return(["..", "."])
expect(@provider).to receive(:clone)
expect(@provider).to receive(:checkout)
expect(@provider).to receive(:enable_submodules)
@@ -534,7 +592,7 @@ SHAS
allow(::File).to receive(:exist?).with("/my/deploy/dir").and_return(true)
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
- allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return(['.','..','foo','bar'])
+ allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return([".", "..", "foo", "bar"])
expect(@provider).not_to receive(:clone)
expect(@provider).not_to receive(:checkout)
expect(@provider).not_to receive(:enable_submodules)
@@ -546,7 +604,7 @@ SHAS
it "syncs the code by updating the source when the repo has already been checked out" do
expect(::File).to receive(:exist?).with("/my/deploy/dir/.git").and_return(true)
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
- expect(@provider).to receive(:find_current_revision).exactly(1).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c')
+ expect(@provider).to receive(:find_current_revision).exactly(1).and_return("d35af14d41ae22b19da05d7d03a0bafc321b244c")
expect(@provider).not_to receive(:fetch_updates)
expect(@provider).to receive(:add_remotes)
@provider.run_action(:sync)
@@ -557,8 +615,8 @@ SHAS
expect(::File).to receive(:exist?).with("/my/deploy/dir/.git").and_return(true)
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
# invoked twice - first time from load_current_resource
- expect(@provider).to receive(:find_current_revision).exactly(1).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c')
- allow(@provider).to receive(:target_revision).and_return('28af684d8460ba4793eda3e7ac238c864a5d029a')
+ expect(@provider).to receive(:find_current_revision).exactly(1).and_return("d35af14d41ae22b19da05d7d03a0bafc321b244c")
+ allow(@provider).to receive(:target_revision).and_return("28af684d8460ba4793eda3e7ac238c864a5d029a")
expect(@provider).to receive(:fetch_updates)
expect(@provider).to receive(:enable_submodules)
expect(@provider).to receive(:add_remotes)
@@ -569,8 +627,8 @@ SHAS
it "does not fetch any updates if the remote revision matches the current revision" do
expect(::File).to receive(:exist?).with("/my/deploy/dir/.git").and_return(true)
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
- allow(@provider).to receive(:find_current_revision).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c')
- allow(@provider).to receive(:target_revision).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c')
+ allow(@provider).to receive(:find_current_revision).and_return("d35af14d41ae22b19da05d7d03a0bafc321b244c")
+ allow(@provider).to receive(:target_revision).and_return("d35af14d41ae22b19da05d7d03a0bafc321b244c")
expect(@provider).not_to receive(:fetch_updates)
expect(@provider).to receive(:add_remotes)
@provider.run_action(:sync)
@@ -606,10 +664,10 @@ SHAS
describe "calling add_remotes" do
it "adds a new remote for each entry in additional remotes hash" do
- @resource.additional_remotes({:opscode => "opscode_repo_url",
- :another_repo => "some_other_repo_url"})
+ @resource.additional_remotes({ :opscode => "opscode_repo_url",
+ :another_repo => "some_other_repo_url" })
allow(STDOUT).to receive(:tty?).and_return(false)
- command_response = double('shell_out')
+ command_response = double("shell_out")
allow(command_response).to receive(:exitstatus) { 0 }
@resource.additional_remotes.each_pair do |remote_name, remote_url|
expect(@provider).to receive(:setup_remote_tracking_branches).with(remote_name, remote_url)
@@ -620,7 +678,7 @@ SHAS
describe "calling multiple_remotes?" do
before(:each) do
- @command_response = double('shell_out')
+ @command_response = double("shell_out")
end
describe "when check remote command returns with status 2" do
@@ -647,7 +705,7 @@ SHAS
describe "calling remote_matches?" do
before(:each) do
- @command_response = double('shell_out')
+ @command_response = double("shell_out")
end
describe "when output of the check remote command matches the repository url" do
diff --git a/spec/unit/provider/group/dscl_spec.rb b/spec/unit/provider/group/dscl_spec.rb
index d84e4e1d57..52d43f907d 100644
--- a/spec/unit/provider/group/dscl_spec.rb
+++ b/spec/unit/provider/group/dscl_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Dreamcat4 (<dreamcat4@gmail.com>)
-# Copyright:: Copyright (c) 2009 OpsCode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Group::Dscl do
before do
@@ -28,19 +28,19 @@ describe Chef::Provider::Group::Dscl do
@provider = Chef::Provider::Group::Dscl.new(@new_resource, @run_context)
@provider.current_resource = @current_resource
- @status = double(:stdout => "\n", :stderr => "", :exitstatus => 0)
+ @status = double(stdout: "\n", stderr: "", exitstatus: 0)
allow(@provider).to receive(:shell_out).and_return(@status)
end
it "should run shell_out with the supplied array of arguments appended to the dscl command" do
- expect(@provider).to receive(:shell_out).with("dscl . -cmd /Path arg1 arg2")
+ expect(@provider).to receive(:shell_out).with("dscl", ".", "-cmd", "/Path", "arg1", "arg2")
@provider.dscl("cmd", "/Path", "arg1", "arg2")
end
it "should return an array of four elements - cmd, status, stdout, stderr" do
dscl_retval = @provider.dscl("cmd /Path args")
expect(dscl_retval).to be_a_kind_of(Array)
- expect(dscl_retval).to eq(["dscl . -cmd /Path args",@status,"\n",""])
+ expect(dscl_retval).to eq(["dscl . -cmd /Path args", @status, "\n", ""])
end
describe "safe_dscl" do
@@ -51,24 +51,24 @@ describe Chef::Provider::Group::Dscl do
end
it "should run dscl with the supplied cmd /Path args" do
- expect(@provider).to receive(:dscl).with("cmd /Path args")
- @provider.safe_dscl("cmd /Path args")
+ expect(@provider).to receive(:dscl).with(*"cmd /Path args".split(" "))
+ @provider.safe_dscl(*"cmd /Path args".split(" "))
end
describe "with the dscl command returning a non zero exit status for a delete" do
before do
- @status = double("Process::Status", :exitstatus => 1)
+ @status = double("Process::Status", exitstatus: 1)
allow(@provider).to receive(:dscl).and_return(["cmd", @status, "stdout", "stderr"])
end
it "should return an empty string of standard output for a delete" do
- safe_dscl_retval = @provider.safe_dscl("delete /Path args")
+ safe_dscl_retval = @provider.safe_dscl(*"delete /Path args".split(" "))
expect(safe_dscl_retval).to be_a_kind_of(String)
expect(safe_dscl_retval).to eq("")
end
it "should raise an exception for any other command" do
- expect { @provider.safe_dscl("cmd /Path arguments") }.to raise_error(Chef::Exceptions::Group)
+ expect { @provider.safe_dscl(*"cmd /Path arguments".split(" ")) }.to raise_error(Chef::Exceptions::Group)
end
end
@@ -78,13 +78,13 @@ describe Chef::Provider::Group::Dscl do
end
it "should raise an exception" do
- expect { @provider.safe_dscl("cmd /Path arguments") }.to raise_error(Chef::Exceptions::Group)
+ expect { @provider.safe_dscl(*"cmd /Path arguments".split(" ")) }.to raise_error(Chef::Exceptions::Group)
end
end
describe "with the dscl command returning a zero exit status" do
it "should return the third array element, the string of standard output" do
- safe_dscl_retval = @provider.safe_dscl("cmd /Path args")
+ safe_dscl_retval = @provider.safe_dscl(*"cmd /Path args".split(" "))
expect(safe_dscl_retval).to be_a_kind_of(String)
expect(safe_dscl_retval).to eq("stdout")
end
@@ -99,7 +99,7 @@ describe Chef::Provider::Group::Dscl do
end
it "should run safe_dscl with list /Groups gid" do
- expect(@provider).to receive(:safe_dscl).with("list /Groups gid")
+ expect(@provider).to receive(:safe_dscl).with(*"list /Groups gid".split(" "))
@provider.get_free_gid
end
@@ -121,7 +121,7 @@ describe Chef::Provider::Group::Dscl do
end
it "should run safe_dscl with list /Groups gid" do
- expect(@provider).to receive(:safe_dscl).with("list /Groups gid")
+ expect(@provider).to receive(:safe_dscl).with(*"list /Groups gid".split(" "))
@provider.gid_used?(500)
end
@@ -171,8 +171,8 @@ describe Chef::Provider::Group::Dscl do
describe "with a valid gid number which is not already in use" do
it "should run safe_dscl with create /Groups/group PrimaryGroupID gid" do
allow(@provider).to receive(:get_free_gid).and_return(50)
- expect(@provider).to receive(:safe_dscl).with("list /Groups gid")
- expect(@provider).to receive(:safe_dscl).with("create /Groups/aj PrimaryGroupID 50").and_return(true)
+ expect(@provider).to receive(:safe_dscl).with(*"list /Groups gid".split(" "))
+ expect(@provider).to receive(:safe_dscl).with("create", "/Groups/aj", "PrimaryGroupID", 50).and_return(true)
@provider.set_gid
end
end
@@ -184,7 +184,7 @@ describe Chef::Provider::Group::Dscl do
before do
allow(@new_resource).to receive(:members).and_return([])
allow(@new_resource).to receive(:append).and_return(false)
- allow(@current_resource).to receive(:members).and_return(["all", "your", "base"])
+ allow(@current_resource).to receive(:members).and_return(%w{all your base})
end
it "should log an appropriate message" do
@@ -193,15 +193,15 @@ describe Chef::Provider::Group::Dscl do
end
it "should run safe_dscl with create /Groups/group GroupMembership to clear the Group's UID list" do
- expect(@provider).to receive(:safe_dscl).with("create /Groups/aj GroupMembers ''").and_return(true)
- expect(@provider).to receive(:safe_dscl).with("create /Groups/aj GroupMembership ''").and_return(true)
+ expect(@provider).to receive(:safe_dscl).with("create", "/Groups/aj", "GroupMembers", "").and_return(true)
+ expect(@provider).to receive(:safe_dscl).with("create", "/Groups/aj", "GroupMembership", "").and_return(true)
@provider.set_members
end
end
describe "with supplied members in the new resource" do
before do
- @new_resource.members(["all", "your", "base"])
+ @new_resource.members(%w{all your base})
@current_resource.members([])
end
@@ -211,9 +211,9 @@ describe Chef::Provider::Group::Dscl do
end
it "should run safe_dscl with append /Groups/group GroupMembership and group members all, your, base" do
- expect(@provider).to receive(:safe_dscl).with("create /Groups/aj GroupMembers ''").and_return(true)
- expect(@provider).to receive(:safe_dscl).with("append /Groups/aj GroupMembership all your base").and_return(true)
- expect(@provider).to receive(:safe_dscl).with("create /Groups/aj GroupMembership ''").and_return(true)
+ expect(@provider).to receive(:safe_dscl).with("create", "/Groups/aj", "GroupMembers", "").and_return(true)
+ expect(@provider).to receive(:safe_dscl).with(*"append /Groups/aj GroupMembership all your base".split(" ")).and_return(true)
+ expect(@provider).to receive(:safe_dscl).with("create", "/Groups/aj", "GroupMembership", "").and_return(true)
@provider.set_members
end
end
@@ -232,20 +232,20 @@ describe Chef::Provider::Group::Dscl do
end
describe "when loading the current system state" do
- before (:each) do
+ before(:each) do
@provider.action = :create
@provider.load_current_resource
@provider.define_resource_requirements
end
it "raises an error if the required binary /usr/bin/dscl doesn't exist" do
- expect(File).to receive(:exists?).with("/usr/bin/dscl").and_return(false)
+ expect(File).to receive(:exist?).with("/usr/bin/dscl").and_return(false)
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
end
it "doesn't raise an error if /usr/bin/dscl exists" do
- allow(File).to receive(:exists?).and_return(true)
+ allow(File).to receive(:exist?).and_return(true)
expect { @provider.process_resource_requirements }.not_to raise_error
end
end
@@ -254,8 +254,8 @@ describe Chef::Provider::Group::Dscl do
it "creates the group, password field, gid, and sets group membership" do
expect(@provider).to receive(:set_gid).and_return(true)
expect(@provider).to receive(:set_members).and_return(true)
- expect(@provider).to receive(:safe_dscl).with("create /Groups/aj Password '*'")
- expect(@provider).to receive(:safe_dscl).with("create /Groups/aj")
+ expect(@provider).to receive(:safe_dscl).with(*"create /Groups/aj Password *".split(" "))
+ expect(@provider).to receive(:safe_dscl).with(*"create /Groups/aj".split(" "))
@provider.create_group
end
end
@@ -265,8 +265,8 @@ describe Chef::Provider::Group::Dscl do
@current_resource.group_name("oldval")
@new_resource.group_name("newname")
expect(@provider).to receive(:set_members).and_return(true)
- expect(@provider).to receive(:safe_dscl).with("create /Groups/newname")
- expect(@provider).to receive(:safe_dscl).with("create /Groups/newname Password '*'")
+ expect(@provider).to receive(:safe_dscl).with(*"create /Groups/newname".split(" "))
+ expect(@provider).to receive(:safe_dscl).with(*"create /Groups/newname Password *".split(" "))
@provider.manage_group
end
@@ -287,13 +287,13 @@ describe Chef::Provider::Group::Dscl do
describe "remove_group" do
it "should run safe_dscl with delete /Groups/group and with the new resources group name" do
- expect(@provider).to receive(:safe_dscl).with("delete /Groups/aj").and_return(true)
+ expect(@provider).to receive(:safe_dscl).with(*"delete /Groups/aj".split(" ")).and_return(true)
@provider.remove_group
end
end
end
-describe 'Test DSCL loading' do
+describe "Test DSCL loading" do
before do
@node = Chef::Node.new
@events = Chef::EventDispatch::Dispatcher.new
@@ -315,17 +315,17 @@ RecordName: com.apple.aj
RecordType: dsRecTypeStandard:Groups
GroupMembership: waka bar
EOF
- allow(@provider).to receive(:safe_dscl).with("read /Groups/aj").and_return(@output)
+ allow(@provider).to receive(:safe_dscl).with(*"read /Groups/aj".split(" ")).and_return(@output)
@current_resource = @provider.load_current_resource
end
- it 'should parse gid properly' do
- allow(File).to receive(:exists?).and_return(true)
+ it "should parse gid properly" do
+ allow(File).to receive(:exist?).and_return(true)
expect(@current_resource.gid).to eq("999")
end
- it 'should parse members properly' do
- allow(File).to receive(:exists?).and_return(true)
- expect(@current_resource.members).to eq(['waka', 'bar'])
+ it "should parse members properly" do
+ allow(File).to receive(:exist?).and_return(true)
+ expect(@current_resource.members).to eq(%w{waka bar})
end
end
diff --git a/spec/unit/provider/group/gpasswd_spec.rb b/spec/unit/provider/group/gpasswd_spec.rb
index 55d978fa7e..add87bf008 100644
--- a/spec/unit/provider/group/gpasswd_spec.rb
+++ b/spec/unit/provider/group/gpasswd_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Group::Gpasswd, "modify_group_members" do
before do
@@ -27,11 +27,11 @@ describe Chef::Provider::Group::Gpasswd, "modify_group_members" do
@new_resource.members %w{lobster rage fist}
@new_resource.append false
@provider = Chef::Provider::Group::Gpasswd.new(@new_resource, @run_context)
- #@provider.stub(:run_command).and_return(true)
+ # @provider.stub(:run_command).and_return(true)
end
describe "when determining the current group state" do
- before (:each) do
+ before(:each) do
@provider.action = :create
@provider.load_current_resource
@provider.define_resource_requirements
@@ -41,13 +41,13 @@ describe Chef::Provider::Group::Gpasswd, "modify_group_members" do
# for Chef::Provider::Group - no need to repeat it here. We'll
# include only what's specific to this provider.
it "should raise an error if the required binary /usr/bin/gpasswd doesn't exist" do
- allow(File).to receive(:exists?).and_return(true)
- expect(File).to receive(:exists?).with("/usr/bin/gpasswd").and_return(false)
+ allow(File).to receive(:exist?).and_return(true)
+ expect(File).to receive(:exist?).with("/usr/bin/gpasswd").and_return(false)
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
end
it "shouldn't raise an error if the required binaries exist" do
- allow(File).to receive(:exists?).and_return(true)
+ allow(File).to receive(:exist?).and_return(true)
expect { @provider.process_resource_requirements }.not_to raise_error
end
end
@@ -66,7 +66,7 @@ describe Chef::Provider::Group::Gpasswd, "modify_group_members" do
it "logs a message and sets group's members to 'none'" do
expect(Chef::Log).to receive(:debug).with("group[wheel] setting group members to: none")
- expect(@provider).to receive(:shell_out!).with("gpasswd -M \"\" wheel")
+ expect(@provider).to receive(:shell_out!).with("gpasswd", "-M", "", "wheel")
@provider.modify_group_members
end
end
@@ -91,7 +91,7 @@ describe Chef::Provider::Group::Gpasswd, "modify_group_members" do
end
it "should run gpasswd with the members joined by ',' followed by the target group" do
- expect(@provider).to receive(:shell_out!).with("gpasswd -M lobster,rage,fist wheel")
+ expect(@provider).to receive(:shell_out!).with("gpasswd", "-M", "lobster,rage,fist", "wheel")
@provider.modify_group_members
end
@@ -104,9 +104,9 @@ describe Chef::Provider::Group::Gpasswd, "modify_group_members" do
it "should run gpasswd individually for each user when the append option is set" do
@new_resource.append(true)
- expect(@provider).to receive(:shell_out!).with("gpasswd -a lobster wheel")
- expect(@provider).to receive(:shell_out!).with("gpasswd -a rage wheel")
- expect(@provider).to receive(:shell_out!).with("gpasswd -a fist wheel")
+ expect(@provider).to receive(:shell_out!).with("gpasswd", "-a", "lobster", "wheel")
+ expect(@provider).to receive(:shell_out!).with("gpasswd", "-a", "rage", "wheel")
+ expect(@provider).to receive(:shell_out!).with("gpasswd", "-a", "fist", "wheel")
@provider.modify_group_members
end
end
diff --git a/spec/unit/provider/group/groupadd_spec.rb b/spec/unit/provider/group/groupadd_spec.rb
index 94150b7a88..929dd00450 100644
--- a/spec/unit/provider/group/groupadd_spec.rb
+++ b/spec/unit/provider/group/groupadd_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,158 +16,178 @@
# limitations under the License.
#
-require 'spec_helper'
-
-describe Chef::Provider::Group::Groupadd, "set_options" do
- before do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Group.new("aj")
- @new_resource.gid(50)
- @new_resource.members(["root", "aj"])
- @new_resource.system false
- @new_resource.non_unique false
- @current_resource = Chef::Resource::Group.new("aj")
- @current_resource.gid(50)
- @current_resource.members(["root", "aj"])
- @current_resource.system false
- @current_resource.non_unique false
- @provider = Chef::Provider::Group::Groupadd.new(@new_resource, @run_context)
- @provider.current_resource = @current_resource
- end
-
- field_list = {
- :gid => "-g"
- }
+require "spec_helper"
- field_list.each do |attribute, option|
- it "should check for differences in #{attribute.to_s} between the current and new resources" do
- expect(@new_resource).to receive(attribute)
- expect(@current_resource).to receive(attribute)
- @provider.set_options
+describe Chef::Provider::Group::Groupadd do
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:new_resource) do
+ Chef::Resource::Group.new("aj").tap do |r|
+ r.gid 50
+ r.members %w{root aj}
+ r.system false
+ r.non_unique false
end
- it "should set the option for #{attribute} if the new resources #{attribute} is not null" do
- allow(@new_resource).to receive(attribute).and_return("wowaweea")
- expect(@provider.set_options).to eql(" #{option} '#{@new_resource.send(attribute)}' #{@new_resource.group_name}")
+ end
+ let(:current_resource) do
+ Chef::Resource::Group.new("aj").tap do |r|
+ r.gid 50
+ r.members %w{root aj}
+ r.system false
+ r.non_unique false
end
end
-
- it "should combine all the possible options" do
- match_string = ""
- field_list.sort{ |a,b| a[0] <=> b[0] }.each do |attribute, option|
- allow(@new_resource).to receive(attribute).and_return("hola")
- match_string << " #{option} 'hola'"
+ let(:provider) do
+ described_class.new(new_resource, run_context).tap do |p|
+ p.current_resource = current_resource
end
- match_string << " aj"
- expect(@provider.set_options).to eql(match_string)
end
- describe "when we want to create a system group" do
- it "should not set groupadd_options '-r' when system is false" do
- @new_resource.system(false)
- expect(@provider.groupadd_options).not_to match(/-r/)
+ describe "#set_options" do
+ field_list = {
+ gid: "-g",
+ }
+
+ field_list.each do |attribute, option|
+ it "should check for differences in #{attribute} between the current and new resources" do
+ expect(new_resource).to receive(attribute)
+ expect(current_resource).to receive(attribute)
+ provider.set_options
+ end
+
+ it "should set the option for #{attribute} if the new resources #{attribute} is not null" do
+ allow(new_resource).to receive(attribute).and_return("wowaweea")
+ expect(provider.set_options).to eql([ option, new_resource.send(attribute), new_resource.group_name])
+ end
end
- it "should set groupadd -r if system is true" do
- @new_resource.system(true)
- expect(@provider.groupadd_options).to eq(" -r")
+ it "should combine all the possible options" do
+ match_array = []
+ field_list.sort { |a, b| a[0] <=> b[0] }.each do |attribute, option|
+ allow(new_resource).to receive(attribute).and_return("hola")
+ match_array << option
+ match_array << "hola"
+ end
+ match_array << "aj"
+ expect(provider.set_options).to eql(match_array)
end
- end
- describe "when we want to create a non_unique gid group" do
- it "should not set groupadd_options '-o' when non_unique is false" do
- @new_resource.non_unique(false)
- expect(@provider.groupadd_options).not_to match(/-o/)
+ describe "when we want to create a system group" do
+ it "should not set groupadd_options '-r' when system is false" do
+ new_resource.system(false)
+ expect(provider.groupadd_options).to eq([])
+ end
+
+ it "should set groupadd -r if system is true" do
+ new_resource.system(true)
+ expect(provider.groupadd_options).to eq(["-r"])
+ end
+
+ context "on Solaris" do
+ before { node.automatic["platform"] = "solaris2" }
+ it "should not set groupadd -r if system is true" do
+ new_resource.system(true)
+ expect(provider.groupadd_options).to eql([])
+ end
+ end
end
- it "should set groupadd -o if non_unique is true" do
- @new_resource.non_unique(true)
- expect(@provider.groupadd_options).to eq(" -o")
- end
- end
-end
+ describe "when we want to create a non_unique gid group" do
+ it "should not set groupadd_options '-o' when non_unique is false" do
+ new_resource.non_unique(false)
+ expect(provider.groupadd_options).to eq([])
+ end
-describe Chef::Provider::Group::Groupadd, "create_group" do
- before do
- @node = Chef::Node.new
- @new_resource = Chef::Resource::Group.new("aj")
- @provider = Chef::Provider::Group::Groupadd.new(@node, @new_resource)
- allow(@provider).to receive(:run_command).and_return(true)
- allow(@provider).to receive(:set_options).and_return(" monkey")
- allow(@provider).to receive(:groupadd_options).and_return("")
- allow(@provider).to receive(:modify_group_members).and_return(true)
+ it "should set groupadd -o if non_unique is true" do
+ new_resource.non_unique(true)
+ expect(provider.groupadd_options).to eq(["-o"])
+ end
+ end
end
- it "should run groupadd with the return of set_options" do
- expect(@provider).to receive(:run_command).with({ :command => "groupadd monkey" }).and_return(true)
- @provider.create_group
- end
+ describe "#create_group" do
+ before do
+ allow(provider).to receive(:shell_out!).and_return(true)
+ allow(provider).to receive(:set_options).and_return("monkey")
+ allow(provider).to receive(:groupadd_options).and_return([])
+ allow(provider).to receive(:modify_group_members).and_return(true)
+ end
- it "should modify the group members" do
- expect(@provider).to receive(:modify_group_members).and_return(true)
- @provider.create_group
- end
-end
+ it "should run groupadd with the return of set_options" do
+ expect(provider).to receive(:shell_out!).with("groupadd", "monkey").and_return(true)
+ provider.create_group
+ end
-describe Chef::Provider::Group::Groupadd do
- before do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Group.new("aj")
- @provider = Chef::Provider::Group::Groupadd.new(@new_resource, @run_context)
- allow(@provider).to receive(:run_command).and_return(true)
- allow(@provider).to receive(:set_options).and_return(" monkey")
+ it "should modify the group members" do
+ expect(provider).to receive(:modify_group_members).and_return(true)
+ provider.create_group
+ end
end
- describe "manage group" do
+ describe "#manage_group" do
+ before do
+ allow(provider).to receive(:shell_out!).and_return(true)
+ allow(provider).to receive(:set_options).and_return("monkey")
+ end
it "should run groupmod with the return of set_options" do
- allow(@provider).to receive(:modify_group_members).and_return(true)
- expect(@provider).to receive(:run_command).with({ :command => "groupmod monkey" }).and_return(true)
- @provider.manage_group
+ allow(provider).to receive(:modify_group_members).and_return(true)
+ expect(provider).to receive(:shell_out!).with("groupmod", "monkey").and_return(true)
+ provider.manage_group
end
it "should modify the group members" do
- expect(@provider).to receive(:modify_group_members).and_return(true)
- @provider.manage_group
+ expect(provider).to receive(:modify_group_members).and_return(true)
+ provider.manage_group
end
end
- describe "remove_group" do
+ describe "#remove_group" do
+ before do
+ allow(provider).to receive(:shell_out!).and_return(true)
+ allow(provider).to receive(:set_options).and_return("monkey")
+ end
it "should run groupdel with the new resources group name" do
- expect(@provider).to receive(:run_command).with({ :command => "groupdel aj" }).and_return(true)
- @provider.remove_group
+ expect(provider).to receive(:shell_out!).with("groupdel", "aj").and_return(true)
+ provider.remove_group
end
end
[:add_member, :remove_member, :set_members].each do |m|
it "should raise an error when calling #{m}" do
- expect { @provider.send(m, [ ]) }.to raise_error(Chef::Exceptions::Group, "you must override #{m} in #{@provider.to_s}")
+ expect { provider.send(m, [ ]) }.to raise_error(Chef::Exceptions::Group, "you must override #{m} in #{provider}")
end
end
- describe "load_current_resource" do
+ describe "#load_current_resource" do
+ before do
+ allow(provider).to receive(:shell_out!).and_return(true)
+ allow(provider).to receive(:set_options).and_return("monkey")
+ end
+
before do
- allow(File).to receive(:exists?).and_return(false)
- @provider.define_resource_requirements
+ allow(File).to receive(:exist?).and_return(false)
+ provider.define_resource_requirements
end
+
it "should raise an error if the required binary /usr/sbin/groupadd doesn't exist" do
- expect(File).to receive(:exists?).with("/usr/sbin/groupadd").and_return(false)
- expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
+ expect(File).to receive(:exist?).with("/usr/sbin/groupadd").and_return(false)
+ expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
end
+
it "should raise an error if the required binary /usr/sbin/groupmod doesn't exist" do
- expect(File).to receive(:exists?).with("/usr/sbin/groupadd").and_return(true)
- expect(File).to receive(:exists?).with("/usr/sbin/groupmod").and_return(false)
- expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
+ expect(File).to receive(:exist?).with("/usr/sbin/groupadd").and_return(true)
+ expect(File).to receive(:exist?).with("/usr/sbin/groupmod").and_return(false)
+ expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
end
+
it "should raise an error if the required binary /usr/sbin/groupdel doesn't exist" do
- expect(File).to receive(:exists?).with("/usr/sbin/groupadd").and_return(true)
- expect(File).to receive(:exists?).with("/usr/sbin/groupmod").and_return(true)
- expect(File).to receive(:exists?).with("/usr/sbin/groupdel").and_return(false)
- expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
+ expect(File).to receive(:exist?).with("/usr/sbin/groupadd").and_return(true)
+ expect(File).to receive(:exist?).with("/usr/sbin/groupmod").and_return(true)
+ expect(File).to receive(:exist?).with("/usr/sbin/groupdel").and_return(false)
+ expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
end
end
diff --git a/spec/unit/provider/group/groupmod_spec.rb b/spec/unit/provider/group/groupmod_spec.rb
index 496d1e28fa..6629b718d0 100644
--- a/spec/unit/provider/group/groupmod_spec.rb
+++ b/spec/unit/provider/group/groupmod_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Dan Crosta (<dcrosta@late.am>)
-# Copyright:: Copyright (c) 2012 OpsCode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,34 +16,34 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Group::Groupmod do
- before do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Group.new("wheel")
- @new_resource.gid 123
- @new_resource.members %w{lobster rage fist}
- @new_resource.append false
- @provider = Chef::Provider::Group::Groupmod.new(@new_resource, @run_context)
- end
+ before do
+ @node = Chef::Node.new
+ @events = Chef::EventDispatch::Dispatcher.new
+ @run_context = Chef::RunContext.new(@node, {}, @events)
+ @new_resource = Chef::Resource::Group.new("wheel")
+ @new_resource.gid 123
+ @new_resource.members %w{lobster rage fist}
+ @new_resource.append false
+ @provider = Chef::Provider::Group::Groupmod.new(@new_resource, @run_context)
+ end
describe "manage_group" do
describe "when determining the current group state" do
it "should raise an error if the required binary /usr/sbin/group doesn't exist" do
- expect(File).to receive(:exists?).with("/usr/sbin/group").and_return(false)
+ expect(File).to receive(:exist?).with("/usr/sbin/group").and_return(false)
expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Group)
end
it "should raise an error if the required binary /usr/sbin/user doesn't exist" do
- expect(File).to receive(:exists?).with("/usr/sbin/group").and_return(true)
- expect(File).to receive(:exists?).with("/usr/sbin/user").and_return(false)
+ expect(File).to receive(:exist?).with("/usr/sbin/group").and_return(true)
+ expect(File).to receive(:exist?).with("/usr/sbin/user").and_return(false)
expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Group)
end
it "shouldn't raise an error if the required binaries exist" do
- allow(File).to receive(:exists?).and_return(true)
+ allow(File).to receive(:exist?).and_return(true)
expect { @provider.load_current_resource }.not_to raise_error
end
end
@@ -62,9 +62,9 @@ describe Chef::Provider::Group::Groupmod do
it "logs a message and sets group's members to 'none', then removes existing group members" do
expect(Chef::Log).to receive(:debug).with("group[wheel] setting group members to: none")
- expect(@provider).to receive(:shell_out!).with("group mod -n wheel_bak wheel")
- expect(@provider).to receive(:shell_out!).with("group add -g '123' -o wheel")
- expect(@provider).to receive(:shell_out!).with("group del wheel_bak")
+ expect(@provider).to receive(:shell_out!).with("group", "mod", "-n", "wheel_bak", "wheel")
+ expect(@provider).to receive(:shell_out!).with("group", "add", "-g", "123", "-o", "wheel")
+ expect(@provider).to receive(:shell_out!).with("group", "del", "wheel_bak")
@provider.manage_group
end
end
@@ -90,10 +90,10 @@ describe Chef::Provider::Group::Groupmod do
it "updates group membership correctly" do
allow(Chef::Log).to receive(:debug)
- expect(@provider).to receive(:shell_out!).with("group mod -n wheel_bak wheel")
- expect(@provider).to receive(:shell_out!).with("user mod -G wheel lobster")
- expect(@provider).to receive(:shell_out!).with("group add -g '123' -o wheel")
- expect(@provider).to receive(:shell_out!).with("group del wheel_bak")
+ expect(@provider).to receive(:shell_out!).with("group", "mod", "-n", "wheel_bak", "wheel")
+ expect(@provider).to receive(:shell_out!).with("user", "mod", "-G", "wheel", "lobster")
+ expect(@provider).to receive(:shell_out!).with("group", "add", "-g", "123", "-o", "wheel")
+ expect(@provider).to receive(:shell_out!).with("group", "del", "wheel_bak")
@provider.manage_group
end
end
@@ -108,10 +108,10 @@ describe Chef::Provider::Group::Groupmod do
end
it "should run a group add command and some user mod commands" do
- expect(@provider).to receive(:shell_out!).with("group add -g '123' wheel")
- expect(@provider).to receive(:shell_out!).with("user mod -G wheel lobster")
- expect(@provider).to receive(:shell_out!).with("user mod -G wheel rage")
- expect(@provider).to receive(:shell_out!).with("user mod -G wheel fist")
+ expect(@provider).to receive(:shell_out!).with("group", "add", "-g", "123", "wheel")
+ expect(@provider).to receive(:shell_out!).with("user", "mod", "-G", "wheel", "lobster")
+ expect(@provider).to receive(:shell_out!).with("user", "mod", "-G", "wheel", "rage")
+ expect(@provider).to receive(:shell_out!).with("user", "mod", "-G", "wheel", "fist")
@provider.create_group
end
end
@@ -125,7 +125,7 @@ describe Chef::Provider::Group::Groupmod do
end
it "should run a group del command" do
- expect(@provider).to receive(:shell_out!).with("group del wheel")
+ expect(@provider).to receive(:shell_out!).with("group", "del", "wheel")
@provider.remove_group
end
end
diff --git a/spec/unit/provider/group/pw_spec.rb b/spec/unit/provider/group/pw_spec.rb
index af74b3b2ce..f109ba6ba1 100644
--- a/spec/unit/provider/group/pw_spec.rb
+++ b/spec/unit/provider/group/pw_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Stephen Haynes (<sh@nomitor.com>)
-# Copyright:: Copyright (c) 2009 OpsCode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Group::Pw do
before do
@@ -26,30 +26,30 @@ describe Chef::Provider::Group::Pw do
@new_resource = Chef::Resource::Group.new("wheel")
@new_resource.gid 50
- @new_resource.members [ "root", "aj"]
+ @new_resource.members %w{root aj}
@current_resource = Chef::Resource::Group.new("aj")
@current_resource.gid 50
- @current_resource.members [ "root", "aj"]
+ @current_resource.members %w{root aj}
@provider = Chef::Provider::Group::Pw.new(@new_resource, @run_context)
@provider.current_resource = @current_resource
end
describe "when setting options for the pw command" do
it "does not set the gid option if gids match or are unmanaged" do
- expect(@provider.set_options).to eq(" wheel")
+ expect(@provider.set_options).to eq(["wheel"])
end
it "sets the option for gid if it is not nil" do
@new_resource.gid(42)
- expect(@provider.set_options).to eql(" wheel -g '42'")
+ expect(@provider.set_options).to eql(["wheel", "-g", 42])
end
end
describe "when creating a group" do
it "should run pw groupadd with the return of set_options and set_members_option" do
@new_resource.gid(23)
- expect(@provider).to receive(:run_command).with({ :command => "pw groupadd wheel -g '23' -M root,aj" }).and_return(true)
+ expect(@provider).to receive(:shell_out!).with("pw", "groupadd", "wheel", "-g", "23", "-M", "root,aj").and_return(true)
@provider.create_group
end
end
@@ -59,8 +59,8 @@ describe Chef::Provider::Group::Pw do
it "should run pw groupmod with the return of set_options" do
@new_resource.gid(42)
@new_resource.members(["someone"])
- expect(@provider).to receive(:run_command).with({ :command => "pw groupmod wheel -g '42' -m someone" }).and_return(true)
- expect(@provider).to receive(:run_command).with({ :command => "pw groupmod wheel -g '42' -d root,aj" }).and_return(true)
+ expect(@provider).to receive(:shell_out!).with("pw", "groupmod", "wheel", "-g", "42", "-m", "someone").and_return(true)
+ expect(@provider).to receive(:shell_out!).with("pw", "groupmod", "wheel", "-g", "42", "-d", "root,aj").and_return(true)
@provider.manage_group
end
@@ -68,7 +68,7 @@ describe Chef::Provider::Group::Pw do
describe "when removing the group" do
it "should run pw groupdel with the new resources group name" do
- expect(@provider).to receive(:run_command).with({ :command => "pw groupdel wheel" }).and_return(true)
+ expect(@provider).to receive(:shell_out!).with("pw", "groupdel", "wheel").and_return(true)
@provider.remove_group
end
end
@@ -89,7 +89,7 @@ describe Chef::Provider::Group::Pw do
describe "with an empty members array in the new resource and existing members in the current resource" do
before do
allow(@new_resource).to receive(:members).and_return([])
- allow(@current_resource).to receive(:members).and_return(["all", "your", "base"])
+ allow(@current_resource).to receive(:members).and_return(%w{all your base})
end
it "should log an appropriate message" do
@@ -98,13 +98,13 @@ describe Chef::Provider::Group::Pw do
end
it "should set the -d option with the members joined by ','" do
- expect(@provider.set_members_options).to eql([ " -d all,your,base" ])
+ expect(@provider.set_members_options).to eql([ ["-d", "all,your,base"] ])
end
end
describe "with supplied members array in the new resource and an empty members array in the current resource" do
before do
- allow(@new_resource).to receive(:members).and_return(["all", "your", "base"])
+ allow(@new_resource).to receive(:members).and_return(%w{all your base})
allow(@current_resource).to receive(:members).and_return([])
end
@@ -114,24 +114,24 @@ describe Chef::Provider::Group::Pw do
end
it "should set the -m option with the members joined by ','" do
- expect(@provider.set_members_options).to eql([ " -m all,your,base" ])
+ expect(@provider.set_members_options).to eql([[ "-m", "all,your,base" ]])
end
end
end
- describe"load_current_resource" do
- before (:each) do
+ describe "load_current_resource" do
+ before(:each) do
@provider.action = :create
@provider.load_current_resource
@provider.define_resource_requirements
end
it "should raise an error if the required binary /usr/sbin/pw doesn't exist" do
- expect(File).to receive(:exists?).with("/usr/sbin/pw").and_return(false)
+ expect(File).to receive(:exist?).with("/usr/sbin/pw").and_return(false)
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
end
it "shouldn't raise an error if /usr/sbin/pw exists" do
- allow(File).to receive(:exists?).and_return(true)
+ allow(File).to receive(:exist?).and_return(true)
expect { @provider.process_resource_requirements }.not_to raise_error
end
end
diff --git a/spec/unit/provider/group/suse_spec.rb b/spec/unit/provider/group/suse_spec.rb
new file mode 100644
index 0000000000..e61d865b6d
--- /dev/null
+++ b/spec/unit/provider/group/suse_spec.rb
@@ -0,0 +1,90 @@
+#
+# Author:: Tom Duffield (<tom@chef.io>)
+# Copyright:: Copyright 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::Group::Suse do
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:new_members) { %w{root new_user} }
+ let(:new_resource) do
+ Chef::Resource::Group.new("new_group").tap do |r|
+ r.gid 50
+ r.members new_members
+ r.system false
+ r.non_unique false
+ end
+ end
+ let(:current_resource) do
+ Chef::Resource::Group.new("new_group").tap do |r|
+ r.gid 50
+ r.members %w{root}
+ r.system false
+ r.non_unique false
+ end
+ end
+ let(:provider) do
+ described_class.new(new_resource, run_context).tap do |p|
+ p.current_resource = current_resource
+ end
+ end
+
+ describe "when determining the current group state" do
+ before(:each) do
+ allow(File).to receive(:exist?).and_return(true)
+ provider.action = :create
+ provider.define_resource_requirements
+ end
+
+ # Checking for required binaries is already done in the spec
+ # for Chef::Provider::Group - no need to repeat it here. We'll
+ # include only what's specific to this provider.
+ it "should raise an error if the required binary /usr/sbin/groupmod doesn't exist" do
+ expect(File).to receive(:exist?).with("/usr/sbin/groupmod").and_return(false)
+ expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
+ end
+
+ it "should raise error if one of the member users does not exist" do
+ expect(Etc).to receive(:getpwnam).with("new_user").and_raise ArgumentError
+ expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
+ end
+ end
+
+ describe "#set_members" do
+ it "should add missing members and remove deleted members" do
+ expect(provider).not_to receive(:remove_member)
+ expect(provider).to receive(:add_member).with("new_user")
+ provider.set_members(new_members)
+ end
+ end
+
+ describe "#add_member" do
+ it "should call out to groupmod to add user" do
+ expect(provider).to receive(:shell_out!).with("groupmod", "-A", "new_user", "new_group")
+ provider.add_member("new_user")
+ end
+ end
+
+ describe "#remove_member" do
+ it "should call out to groupmod to remove user" do
+ expect(provider).to receive(:shell_out!).with("groupmod", "-R", "new_user", "new_group")
+ provider.remove_member("new_user")
+ end
+ end
+end
diff --git a/spec/unit/provider/group/usermod_spec.rb b/spec/unit/provider/group/usermod_spec.rb
index 3f06e9ebf1..c6422b12c9 100644
--- a/spec/unit/provider/group/usermod_spec.rb
+++ b/spec/unit/provider/group/usermod_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Group::Usermod do
before do
@@ -24,7 +24,7 @@ describe Chef::Provider::Group::Usermod do
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@new_resource = Chef::Resource::Group.new("wheel")
- @new_resource.members [ "all", "your", "base" ]
+ @new_resource.members %w{all your base}
@new_resource.excluded_members [ ]
@provider = Chef::Provider::Group::Usermod.new(@new_resource, @run_context)
allow(@provider).to receive(:run_command)
@@ -46,18 +46,18 @@ describe Chef::Provider::Group::Usermod do
describe "with supplied members" do
platforms = {
- "openbsd" => "-G",
- "netbsd" => "-G",
- "solaris" => "-a -G",
- "suse" => "-a -G",
- "opensuse" => "-a -G",
- "smartos" => "-G",
- "omnios" => "-G"
+ "openbsd" => [ "-G" ],
+ "netbsd" => [ "-G" ],
+ "solaris" => [ "-a", "-G" ],
+ "suse" => [ "-a", "-G" ],
+ "opensuse" => [ "-a", "-G" ],
+ "smartos" => [ "-G" ],
+ "omnios" => [ "-G" ],
}
before do
- allow(@new_resource).to receive(:members).and_return(["all", "your", "base"])
- allow(File).to receive(:exists?).and_return(true)
+ allow(@new_resource).to receive(:members).and_return(%w{all your base})
+ allow(File).to receive(:exist?).and_return(true)
end
it "should raise an error when setting the entire group directly" do
@@ -65,7 +65,7 @@ describe Chef::Provider::Group::Usermod do
@provider.load_current_resource
@provider.instance_variable_set("@group_exists", true)
@provider.action = :modify
- expect { @provider.run_action(@provider.process_resource_requirements) }.to raise_error(Chef::Exceptions::Group, "setting group members directly is not supported by #{@provider.to_s}, must set append true in group")
+ expect { @provider.run_action(@provider.process_resource_requirements) }.to raise_error(Chef::Exceptions::Group, "setting group members directly is not supported by #{@provider}, must set append true in group")
end
it "should raise an error when excluded_members are set" do
@@ -75,7 +75,7 @@ describe Chef::Provider::Group::Usermod do
@provider.action = :modify
allow(@new_resource).to receive(:append).and_return(true)
allow(@new_resource).to receive(:excluded_members).and_return(["someone"])
- expect { @provider.run_action(@provider.process_resource_requirements) }.to raise_error(Chef::Exceptions::Group, "excluded_members is not supported by #{@provider.to_s}")
+ expect { @provider.run_action(@provider.process_resource_requirements) }.to raise_error(Chef::Exceptions::Group, "excluded_members is not supported by #{@provider}")
end
platforms.each do |platform, flags|
@@ -85,9 +85,9 @@ describe Chef::Provider::Group::Usermod do
@provider.current_resource = current_resource
@node.automatic_attrs[:platform] = platform
allow(@new_resource).to receive(:append).and_return(true)
- expect(@provider).to receive(:shell_out!).with("usermod #{flags} wheel all")
- expect(@provider).to receive(:shell_out!).with("usermod #{flags} wheel your")
- expect(@provider).to receive(:shell_out!).with("usermod #{flags} wheel base")
+ expect(@provider).to receive(:shell_out!).with("usermod", *flags, "wheel", "all")
+ expect(@provider).to receive(:shell_out!).with("usermod", *flags, "wheel", "your")
+ expect(@provider).to receive(:shell_out!).with("usermod", *flags, "wheel", "base")
@provider.modify_group_members
end
end
@@ -96,19 +96,19 @@ describe Chef::Provider::Group::Usermod do
describe "when loading the current resource" do
before(:each) do
- allow(File).to receive(:exists?).and_return(false)
+ allow(File).to receive(:exist?).and_return(false)
@provider.action = :create
@provider.define_resource_requirements
end
it "should raise an error if the required binary /usr/sbin/usermod doesn't exist" do
- allow(File).to receive(:exists?).and_return(true)
- expect(File).to receive(:exists?).with("/usr/sbin/usermod").and_return(false)
+ allow(File).to receive(:exist?).and_return(true)
+ expect(File).to receive(:exist?).with("/usr/sbin/usermod").and_return(false)
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
end
it "shouldn't raise an error if the required binaries exist" do
- allow(File).to receive(:exists?).and_return(true)
+ allow(File).to receive(:exist?).and_return(true)
expect { @provider.process_resource_requirements }.not_to raise_error
end
end
diff --git a/spec/unit/provider/group/windows_spec.rb b/spec/unit/provider/group/windows_spec.rb
index 23dfa8315f..f059f2e717 100644
--- a/spec/unit/provider/group/windows_spec.rb
+++ b/spec/unit/provider/group/windows_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
class Chef
class Util
@@ -50,12 +50,14 @@ describe Chef::Provider::Group::Windows do
before do
@new_resource.members([ "us" ])
@current_resource = Chef::Resource::Group.new("staff")
- @current_resource.members [ "all", "your", "base" ]
+ @current_resource.members %w{all your base}
+ @new_resource.excluded_members %w{all}
allow(Chef::Util::Windows::NetGroup).to receive(:new).and_return(@net_group)
allow(@net_group).to receive(:local_add_members)
allow(@net_group).to receive(:local_set_members)
- allow(@provider).to receive(:local_group_name_to_sid)
+ allow(@provider).to receive(:lookup_account_name)
+ allow(@provider).to receive(:validate_member!).and_return(true)
@provider.current_resource = @current_resource
end
@@ -71,6 +73,12 @@ describe Chef::Provider::Group::Windows do
@provider.manage_group
end
+ it "should call @net_group.local_delete_members" do
+ allow(@new_resource).to receive(:append).and_return(true)
+ allow(@provider).to receive(:lookup_account_name).with("all").and_return("all")
+ expect(@net_group).to receive(:local_delete_members).with(@new_resource.excluded_members)
+ @provider.manage_group
+ end
end
describe "remove_group" do
@@ -94,7 +102,7 @@ describe Chef::Provider::Group::Windows, "NetGroup" do
@new_resource = Chef::Resource::Group.new("Creating a new group")
@new_resource.group_name "Remote Desktop Users"
end
- it 'sets group_name correctly' do
+ it "sets group_name correctly" do
expect(Chef::Util::Windows::NetGroup).to receive(:new).with("Remote Desktop Users")
Chef::Provider::Group::Windows.new(@new_resource, @run_context)
end
diff --git a/spec/unit/provider/group_spec.rb b/spec/unit/provider/group_spec.rb
index b36bfe364b..1d354ea32e 100644
--- a/spec/unit/provider/group_spec.rb
+++ b/spec/unit/provider/group_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::User do
@@ -39,9 +39,9 @@ describe Chef::Provider::User do
@pw_group = double("Struct::Group",
:name => "wheel",
:gid => 20,
- :mem => [ "root", "aj" ]
+ :mem => %w{root aj}
)
- allow(Etc).to receive(:getgrnam).with('wheel').and_return(@pw_group)
+ allow(Etc).to receive(:getgrnam).with("wheel").and_return(@pw_group)
end
it "assumes the group exists by default" do
@@ -52,7 +52,7 @@ describe Chef::Provider::User do
it "sets the group name of the current resource to the group name of the new resource" do
@provider.load_current_resource
- expect(@provider.current_resource.group_name).to eq('wheel')
+ expect(@provider.current_resource.group_name).to eq("wheel")
end
it "does not modify the desired gid if set" do
@@ -120,7 +120,7 @@ describe Chef::Provider::User do
end
it "should return true if the append is true and excluded_members include an existing user" do
- @new_resource.members.each {|m| @new_resource.excluded_members << m }
+ @new_resource.members.each { |m| @new_resource.excluded_members << m }
@new_resource.members.clear
allow(@new_resource).to receive(:append).and_return(true)
expect(@provider.compare_group).to be_truthy
@@ -256,18 +256,18 @@ describe Chef::Provider::User do
describe "when determining the reason for a change" do
it "should report which group members are missing if members are missing and appending to the group" do
- @new_resource.members << "user1"
- @new_resource.members << "user2"
- allow(@new_resource).to receive(:append).and_return true
- expect(@provider.compare_group).to be_truthy
- expect(@provider.change_desc).to eq([ "add missing member(s): user1, user2" ])
+ @new_resource.members << "user1"
+ @new_resource.members << "user2"
+ allow(@new_resource).to receive(:append).and_return true
+ expect(@provider.compare_group).to be_truthy
+ expect(@provider.change_desc).to eq([ "add missing member(s): user1, user2" ])
end
it "should report that the group members will be overwritten if not appending" do
- @new_resource.members << "user1"
- allow(@new_resource).to receive(:append).and_return false
- expect(@provider.compare_group).to be_truthy
- expect(@provider.change_desc).to eq([ "replace group members with new list of members" ])
+ @new_resource.members << "user1"
+ allow(@new_resource).to receive(:append).and_return false
+ expect(@provider.compare_group).to be_truthy
+ expect(@provider.change_desc).to eq([ "replace group members with new list of members" ])
end
it "should report the gid will be changed when it does not match" do
diff --git a/spec/unit/provider/http_request_spec.rb b/spec/unit/provider/http_request_spec.rb
index a84dd5e2a0..9a3519a95a 100644
--- a/spec/unit/provider/http_request_spec.rb
+++ b/spec/unit/provider/http_request_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::HttpRequest do
before(:each) do
@@ -24,7 +24,7 @@ describe Chef::Provider::HttpRequest do
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::HttpRequest.new('adam')
+ @new_resource = Chef::Resource::HttpRequest.new("adam")
@new_resource.name "adam"
@new_resource.url "http://www.opscode.com/"
@new_resource.message "is cool"
@@ -34,7 +34,7 @@ describe Chef::Provider::HttpRequest do
describe "load_current_resource" do
- it "should set up a Chef::REST client, with no authentication" do
+ it "should set up a Chef::ServerAPI client, with no authentication" do
expect(Chef::HTTP::Simple).to receive(:new).with(@new_resource.url)
@provider.load_current_resource
end
@@ -45,7 +45,7 @@ describe Chef::Provider::HttpRequest do
# run_action(x) forces load_current_resource to run;
# that would overwrite our supplied mock Chef::Rest # object
allow(@provider).to receive(:load_current_resource).and_return(true)
- @http = double("Chef::REST")
+ @http = double("Chef::ServerAPI")
@provider.http = @http
end
@@ -138,7 +138,7 @@ describe Chef::Provider::HttpRequest do
it "should not update a HEAD request if a not modified response (CHEF-4762)" do
if_modified_since = File.mtime(__FILE__).httpdate
@new_resource.headers "If-Modified-Since" => if_modified_since
- expect(@http).to receive(:head).with("http://www.opscode.com/", {"If-Modified-Since" => if_modified_since}).and_return(false)
+ expect(@http).to receive(:head).with("http://www.opscode.com/", { "If-Modified-Since" => if_modified_since }).and_return(false)
@provider.run_action(:head)
expect(@new_resource).not_to be_updated
end
diff --git a/spec/unit/provider/ifconfig/aix_spec.rb b/spec/unit/provider/ifconfig/aix_spec.rb
index 0b6fa33614..7f316c952b 100644
--- a/spec/unit/provider/ifconfig/aix_spec.rb
+++ b/spec/unit/provider/ifconfig/aix_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/exceptions'
+require "spec_helper"
+require "chef/exceptions"
describe Chef::Provider::Ifconfig::Aix do
@@ -35,7 +35,6 @@ lo0: flags=e08084b,c0<UP,BROADCAST,LOOPBACK,RUNNING,SIMPLEX,MULTICAST,GROUPRT,64
IFCONFIG
end
-
before(:each) do
@node = Chef::Node.new
@cookbook_collection = Chef::CookbookCollection.new([])
@@ -49,7 +48,7 @@ IFCONFIG
describe "#load_current_resource" do
before do
- @status = double(:stdout => @ifconfig_output, :exitstatus => 0)
+ @status = double(stdout: @ifconfig_output, exitstatus: 0)
allow(@provider).to receive(:shell_out).and_return(@status)
@new_resource.device "en0"
end
@@ -69,11 +68,11 @@ IFCONFIG
it "should add an interface if it does not exist" do
@new_resource.device "en10"
allow(@provider).to receive(:load_current_resource) do
- @provider.instance_variable_set("@status", double("Status", :exitstatus => 0))
+ @provider.instance_variable_set("@status", double("Status", exitstatus: 0))
@provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context))
end
command = "chdev -l #{@new_resource.device} -a netaddr=#{@new_resource.name}"
- expect(@provider).to receive(:run_command).with(:command => command)
+ expect(@provider).to receive(:shell_out!).with(*command.split(" "))
@provider.run_action(:add)
expect(@new_resource).to be_updated
@@ -83,11 +82,11 @@ IFCONFIG
@new_resource.device "en0"
@new_resource.metric "1"
allow(@provider).to receive(:load_current_resource) do
- @provider.instance_variable_set("@status", double("Status", :exitstatus => 0))
+ @provider.instance_variable_set("@status", double("Status", exitstatus: 0))
@provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context))
end
- expect{@provider.run_action(:add)}.to raise_error(Chef::Exceptions::Ifconfig, "interface metric attribute cannot be set for :add action")
+ expect { @provider.run_action(:add) }.to raise_error(Chef::Exceptions::Ifconfig, "interface metric attribute cannot be set for :add action")
end
end
@@ -95,11 +94,11 @@ IFCONFIG
it "should enable an interface if it does not exist" do
@new_resource.device "en10"
allow(@provider).to receive(:load_current_resource) do
- @provider.instance_variable_set("@status", double("Status", :exitstatus => 0))
+ @provider.instance_variable_set("@status", double("Status", exitstatus: 0))
@provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context))
end
command = "ifconfig #{@new_resource.device} #{@new_resource.name}"
- expect(@provider).to receive(:run_command).with(:command => command)
+ expect(@provider).to receive(:shell_out!).with(*command.split(" "))
@provider.run_action(:enable)
expect(@new_resource).to be_updated
@@ -111,11 +110,11 @@ IFCONFIG
it "should not disable an interface if it does not exist" do
@new_resource.device "en10"
allow(@provider).to receive(:load_current_resource) do
- @provider.instance_variable_set("@status", double("Status", :exitstatus => 0))
+ @provider.instance_variable_set("@status", double("Status", exitstatus: 0))
@provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context))
end
- expect(@provider).not_to receive(:run_command)
+ expect(@provider).not_to receive(:shell_out!)
@provider.run_action(:disable)
expect(@new_resource).not_to be_updated
@@ -125,7 +124,7 @@ IFCONFIG
before do
@new_resource.device "en10"
allow(@provider).to receive(:load_current_resource) do
- @provider.instance_variable_set("@status", double("Status", :exitstatus => 0))
+ @provider.instance_variable_set("@status", double("Status", exitstatus: 0))
current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)
current_resource.device @new_resource.device
@provider.instance_variable_set("@current_resource", current_resource)
@@ -134,7 +133,7 @@ IFCONFIG
it "should disable an interface if it exists" do
command = "ifconfig #{@new_resource.device} down"
- expect(@provider).to receive(:run_command).with(:command => command)
+ expect(@provider).to receive(:shell_out!).with(*command.split(" "))
@provider.run_action(:disable)
expect(@new_resource).to be_updated
@@ -148,11 +147,11 @@ IFCONFIG
it "should not delete an interface if it does not exist" do
@new_resource.device "en10"
allow(@provider).to receive(:load_current_resource) do
- @provider.instance_variable_set("@status", double("Status", :exitstatus => 0))
+ @provider.instance_variable_set("@status", double("Status", exitstatus: 0))
@provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context))
end
- expect(@provider).not_to receive(:run_command)
+ expect(@provider).not_to receive(:shell_out!)
@provider.run_action(:delete)
expect(@new_resource).not_to be_updated
@@ -162,7 +161,7 @@ IFCONFIG
before do
@new_resource.device "en10"
allow(@provider).to receive(:load_current_resource) do
- @provider.instance_variable_set("@status", double("Status", :exitstatus => 0))
+ @provider.instance_variable_set("@status", double("Status", exitstatus: 0))
current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)
current_resource.device @new_resource.device
@provider.instance_variable_set("@current_resource", current_resource)
@@ -171,7 +170,7 @@ IFCONFIG
it "should delete an interface if it exists" do
command = "chdev -l #{@new_resource.device} -a state=down"
- expect(@provider).to receive(:run_command).with(:command => command)
+ expect(@provider).to receive(:shell_out!).with(*command.split(" "))
@provider.run_action(:delete)
expect(@new_resource).to be_updated
diff --git a/spec/unit/provider/ifconfig/debian_spec.rb b/spec/unit/provider/ifconfig/debian_spec.rb
index 0c02ae9cd4..9a90dc1e0a 100644
--- a/spec/unit/provider/ifconfig/debian_spec.rb
+++ b/spec/unit/provider/ifconfig/debian_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Xabier de Zuazo (xabier@onddo.com)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/exceptions'
+require "spec_helper"
+require "chef/exceptions"
describe Chef::Provider::Ifconfig::Debian do
@@ -37,15 +37,15 @@ describe Chef::Provider::Ifconfig::Debian do
new_resource
end
- let(:current_resource) { Chef::Resource::Ifconfig.new("10.0.0.1", run_context) }
+ let(:current_resource) { Chef::Resource::Ifconfig.new("10.0.0.1", run_context) }
let(:provider) do
- status = double("Status", :exitstatus => 0)
+ status = double("Status", exitstatus: 0)
provider = Chef::Provider::Ifconfig::Debian.new(new_resource, run_context)
provider.instance_variable_set("@status", status)
provider.current_resource = current_resource
allow(provider).to receive(:load_current_resource)
- allow(provider).to receive(:run_command)
+ allow(provider).to receive(:shell_out!)
provider
end
@@ -77,12 +77,12 @@ describe Chef::Provider::Ifconfig::Debian do
context "when the interface_dot_d directory does not exist" do
before do
FileUtils.rmdir tempdir_path
- expect(File.exists?(tempdir_path)).to be_falsey
+ expect(File.exist?(tempdir_path)).to be_falsey
end
it "should create the /etc/network/interfaces.d directory" do
provider.run_action(:add)
- expect(File.exists?(tempdir_path)).to be_truthy
+ expect(File.exist?(tempdir_path)).to be_truthy
expect(File.directory?(tempdir_path)).to be_truthy
end
@@ -94,7 +94,7 @@ describe Chef::Provider::Ifconfig::Debian do
context "when the interface_dot_d directory exists" do
before do
- expect(File.exists?(tempdir_path)).to be_truthy
+ expect(File.exist?(tempdir_path)).to be_truthy
end
it "should still mark the resource as updated (we still write a file to it)" do
@@ -114,13 +114,7 @@ describe Chef::Provider::Ifconfig::Debian do
before do
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path)
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path)
- config_file_ifcfg = StringIO.new(<<-EOF
-iface eth0 inet static
- address 10.0.0.1
- netmask 255.255.254.0
-EOF
- )
- expect(File.exists?(tempdir_path)).to be_truthy # since the file exists, the enclosing dir must also exist
+ expect(File.exist?(tempdir_path)).to be_truthy # since the file exists, the enclosing dir must also exist
end
context "when the /etc/network/interfaces file has the source line" do
@@ -210,12 +204,12 @@ EOF
context "when the interface_dot_d directory does not exist" do
before do
FileUtils.rmdir tempdir_path
- expect(File.exists?(tempdir_path)).to be_falsey
+ expect(File.exist?(tempdir_path)).to be_falsey
end
it "should not create the /etc/network/interfaces.d directory" do
provider.run_action(:add)
- expect(File.exists?(tempdir_path)).not_to be_truthy
+ expect(File.exist?(tempdir_path)).not_to be_truthy
end
it "should mark the resource as updated" do
@@ -226,7 +220,7 @@ EOF
context "when the interface_dot_d directory exists" do
before do
- expect(File.exists?(tempdir_path)).to be_truthy
+ expect(File.exist?(tempdir_path)).to be_truthy
end
it "should still mark the resource as updated (we still write a file to it)" do
@@ -246,14 +240,8 @@ EOF
before do
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path)
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path)
- config_file_ifcfg = StringIO.new(<<-EOF
-iface eth0 inet static
- address 10.0.0.1
- netmask 255.255.254.0
- EOF
- )
expect(File).not_to receive(:new).with(config_filename_ifcfg, "w")
- expect(File.exists?(tempdir_path)).to be_truthy # since the file exists, the enclosing dir must also exist
+ expect(File.exist?(tempdir_path)).to be_truthy # since the file exists, the enclosing dir must also exist
end
context "when the /etc/network/interfaces file has the source line" do
diff --git a/spec/unit/provider/ifconfig/redhat_spec.rb b/spec/unit/provider/ifconfig/redhat_spec.rb
index 620fd341d7..2111de02fb 100644
--- a/spec/unit/provider/ifconfig/redhat_spec.rb
+++ b/spec/unit/provider/ifconfig/redhat_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Xabier de Zuazo (xabier@onddo.com)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/exceptions'
+require "spec_helper"
+require "chef/exceptions"
describe Chef::Provider::Ifconfig::Redhat do
before do
@@ -25,7 +25,7 @@ describe Chef::Provider::Ifconfig::Redhat do
@cookbook_collection = Chef::CookbookCollection.new([])
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
- #This new_resource can be called anything --> it is not the same as in ifconfig.rb
+ # This new_resource can be called anything --> it is not the same as in ifconfig.rb
@new_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)
@new_resource.mask "255.255.254.0"
@new_resource.metric "1"
@@ -34,7 +34,7 @@ describe Chef::Provider::Ifconfig::Redhat do
@provider = Chef::Provider::Ifconfig::Redhat.new(@new_resource, @run_context)
@current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)
- status = double("Status", :exitstatus => 0)
+ status = double("Status", exitstatus: 0)
@provider.instance_variable_set("@status", status)
@provider.current_resource = @current_resource
@@ -47,7 +47,7 @@ describe Chef::Provider::Ifconfig::Redhat do
it "should write network-script for centos" do
allow(@provider).to receive(:load_current_resource)
- allow(@provider).to receive(:run_command)
+ allow(@provider).to receive(:shell_out!)
expect(@config).to receive(:content) do |arg|
expect(arg).to match(/^\s*DEVICE=eth0\s*$/)
expect(arg).to match(/^\s*IPADDR=10\.0\.0\.1\s*$/)
@@ -64,7 +64,7 @@ describe Chef::Provider::Ifconfig::Redhat do
it "should delete network-script if it exists for centos" do
@current_resource.device @new_resource.device
allow(@provider).to receive(:load_current_resource)
- allow(@provider).to receive(:run_command)
+ allow(@provider).to receive(:shell_out!)
expect(@config).to receive(:run_action).with(:delete)
expect(@config).to receive(:updated?).and_return(true)
@provider.run_action(:delete)
diff --git a/spec/unit/provider/ifconfig_spec.rb b/spec/unit/provider/ifconfig_spec.rb
index 4940f19a45..da27d647ee 100644
--- a/spec/unit/provider/ifconfig_spec.rb
+++ b/spec/unit/provider/ifconfig_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Prajakta Purohit (prajakta@opscode.com)
-# Copyright:: Copyright (c) 2008 Opscode Inc.
+# Author:: Prajakta Purohit (prajakta@chef.io)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-#require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
-require 'spec_helper'
-require 'chef/exceptions'
+# require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
+require "spec_helper"
+require "chef/exceptions"
describe Chef::Provider::Ifconfig do
before do
@@ -26,7 +26,7 @@ describe Chef::Provider::Ifconfig do
@cookbook_collection = Chef::CookbookCollection.new([])
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
- #This new_resource can be called anything --> it is not the same as in ifconfig.rb
+ # This new_resource can be called anything --> it is not the same as in ifconfig.rb
@new_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)
@new_resource.mask "255.255.254.0"
@new_resource.metric "1"
@@ -35,14 +35,14 @@ describe Chef::Provider::Ifconfig do
@provider = Chef::Provider::Ifconfig.new(@new_resource, @run_context)
@current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)
- status = double("Status", :exitstatus => 0)
+ status = double("Status", exitstatus: 0)
@provider.instance_variable_set("@status", status)
@provider.current_resource = @current_resource
- end
+ end
describe Chef::Provider::Ifconfig, "load_current_resource" do
before do
- @status = double(:stdout => "", :exitstatus => 1)
+ @status = double(stdout: "", exitstatus: 1)
allow(@provider).to receive(:shell_out).and_return(@status)
@provider.load_current_resource
end
@@ -57,11 +57,10 @@ describe Chef::Provider::Ifconfig do
describe Chef::Provider::Ifconfig, "action_add" do
it "should add an interface if it does not exist" do
- #@provider.stub(:run_command).and_return(true)
allow(@provider).to receive(:load_current_resource)
@current_resource.inet_addr nil
command = "ifconfig eth0 10.0.0.1 netmask 255.255.254.0 metric 1 mtu 1500"
- expect(@provider).to receive(:run_command).with(:command => command)
+ expect(@provider).to receive(:shell_out!).with(*command.split(" "))
expect(@provider).to receive(:generate_config)
@provider.run_action(:add)
@@ -72,7 +71,7 @@ describe Chef::Provider::Ifconfig do
allow(@provider).to receive(:load_current_resource)
@new_resource.target "172.16.32.2"
command = "ifconfig eth0 172.16.32.2 netmask 255.255.254.0 metric 1 mtu 1500"
- expect(@provider).to receive(:run_command).with(:command => command)
+ expect(@provider).to receive(:shell_out!).with(*command.split(" "))
@provider.run_action(:add)
expect(@new_resource).to be_updated
@@ -80,7 +79,7 @@ describe Chef::Provider::Ifconfig do
it "should not add an interface if it already exists" do
allow(@provider).to receive(:load_current_resource)
- expect(@provider).not_to receive(:run_command)
+ expect(@provider).not_to receive(:shell_out!)
@current_resource.inet_addr "10.0.0.1"
expect(@provider).to receive(:generate_config)
@@ -88,9 +87,9 @@ describe Chef::Provider::Ifconfig do
expect(@new_resource).not_to be_updated
end
- #We are not testing this case with the assumption that anyone writing the cookbook would not make a typo == lo
- #it "should add a blank command if the #{@new_resource.device} == lo" do
- #end
+ # We are not testing this case with the assumption that anyone writing the cookbook would not make a typo == lo
+ # it "should add a blank command if the #{@new_resource.device} == lo" do
+ # end
end
describe Chef::Provider::Ifconfig, "action_enable" do
@@ -99,7 +98,7 @@ describe Chef::Provider::Ifconfig do
allow(@provider).to receive(:load_current_resource)
@current_resource.inet_addr nil
command = "ifconfig eth0 10.0.0.1 netmask 255.255.254.0 metric 1 mtu 1500"
- expect(@provider).to receive(:run_command).with(:command => command)
+ expect(@provider).to receive(:shell_out!).with(*command.split(" "))
expect(@provider).not_to receive(:generate_config)
@provider.run_action(:enable)
@@ -110,7 +109,7 @@ describe Chef::Provider::Ifconfig do
allow(@provider).to receive(:load_current_resource)
@new_resource.target "172.16.32.2"
command = "ifconfig eth0 172.16.32.2 netmask 255.255.254.0 metric 1 mtu 1500"
- expect(@provider).to receive(:run_command).with(:command => command)
+ expect(@provider).to receive(:shell_out!).with(*command.split(" "))
@provider.run_action(:enable)
expect(@new_resource).to be_updated
@@ -133,7 +132,7 @@ describe Chef::Provider::Ifconfig do
allow(@provider).to receive(:load_current_resource)
@current_resource.device "eth0"
command = "ifconfig #{@new_resource.device} down"
- expect(@provider).to receive(:run_command).with(:command => command)
+ expect(@provider).to receive(:shell_out!).with(*command.split(" "))
expect(@provider).to receive(:delete_config)
@provider.run_action(:delete)
@@ -142,7 +141,7 @@ describe Chef::Provider::Ifconfig do
it "should not delete interface if it does not exist" do
allow(@provider).to receive(:load_current_resource)
- expect(@provider).not_to receive(:run_command)
+ expect(@provider).not_to receive(:shell_out!)
expect(@provider).to receive(:delete_config)
@provider.run_action(:delete)
@@ -156,7 +155,7 @@ describe Chef::Provider::Ifconfig do
allow(@provider).to receive(:load_current_resource)
@current_resource.device "eth0"
command = "ifconfig #{@new_resource.device} down"
- expect(@provider).to receive(:run_command).with(:command => command)
+ expect(@provider).to receive(:shell_out!).with(*command.split(" "))
expect(@provider).not_to receive(:delete_config)
@provider.run_action(:disable)
@@ -165,7 +164,7 @@ describe Chef::Provider::Ifconfig do
it "should not delete interface if it does not exist" do
allow(@provider).to receive(:load_current_resource)
- expect(@provider).not_to receive(:run_command)
+ expect(@provider).not_to receive(:shell_out!)
expect(@provider).not_to receive(:delete_config)
@provider.run_action(:disable)
@@ -179,7 +178,7 @@ describe Chef::Provider::Ifconfig do
allow(@provider).to receive(:load_current_resource)
@current_resource.device "eth0"
command = "ifconfig #{@new_resource.device} down"
- expect(@provider).to receive(:run_command).with(:command => command)
+ expect(@provider).to receive(:shell_out!).with(*command.split(" "))
expect(@provider).to receive(:delete_config)
@provider.run_action(:delete)
@@ -190,7 +189,7 @@ describe Chef::Provider::Ifconfig do
# This is so that our fake values do not get overwritten
allow(@provider).to receive(:load_current_resource)
# This is so that nothing actually runs
- expect(@provider).not_to receive(:run_command)
+ expect(@provider).not_to receive(:shell_out!)
expect(@provider).to receive(:delete_config)
@provider.run_action(:delete)
diff --git a/spec/unit/provider/launchd_spec.rb b/spec/unit/provider/launchd_spec.rb
new file mode 100644
index 0000000000..693801f99b
--- /dev/null
+++ b/spec/unit/provider/launchd_spec.rb
@@ -0,0 +1,268 @@
+#
+# Author:: Mike Dodge (<mikedodge04@gmail.com>)
+# Copyright:: Copyright (c) 2015 Facebook, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::Launchd do
+
+ context "When launchd manages call.mom.weekly" do
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:provider) { Chef::Provider::Launchd.new(new_resource, run_context) }
+
+ let(:label) { "call.mom.weekly" }
+ let(:new_resource) { Chef::Resource::Launchd.new(label) }
+ let!(:current_resource) { Chef::Resource::Launchd.new(label) }
+ let(:test_plist) { String.new <<-XML }
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+\t<key>Label</key>
+\t<string>call.mom.weekly</string>
+\t<key>Program</key>
+\t<string>/Library/scripts/call_mom.sh</string>
+\t<key>StartCalendarInterval</key>
+\t<dict>
+\t\t<key>Hour</key>
+\t\t<integer>10</integer>
+\t\t<key>Weekday</key>
+\t\t<integer>7</integer>
+\t</dict>
+\t<key>TimeOut</key>
+\t<integer>300</integer>
+</dict>
+</plist>
+XML
+ let(:test_plist_multiple_intervals) { String.new <<-XML }
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+\t<key>Label</key>
+\t<string>call.mom.weekly</string>
+\t<key>Program</key>
+\t<string>/Library/scripts/call_mom.sh</string>
+\t<key>StartCalendarInterval</key>
+\t<array>
+\t\t<dict>
+\t\t\t<key>Hour</key>
+\t\t\t<integer>11</integer>
+\t\t\t<key>Weekday</key>
+\t\t\t<integer>1</integer>
+\t\t</dict>
+\t\t<dict>
+\t\t\t<key>Hour</key>
+\t\t\t<integer>12</integer>
+\t\t\t<key>Weekday</key>
+\t\t\t<integer>2</integer>
+\t\t</dict>
+\t</array>
+\t<key>TimeOut</key>
+\t<integer>300</integer>
+</dict>
+</plist>
+XML
+
+ let(:test_hash) do
+ {
+ "Label" => "call.mom.weekly",
+ "Program" => "/Library/scripts/call_mom.sh",
+ "StartCalendarInterval" => {
+ "Hour" => 10,
+ "Weekday" => 7,
+ },
+ "TimeOut" => 300,
+ } end
+
+ before(:each) do
+ provider.load_current_resource
+ end
+
+ it "resource name and label should be call.mom.weekly" do
+ expect(new_resource.name).to eql(label)
+ expect(new_resource.label).to eql(label)
+ end
+
+ def run_resource_setup_for_action(action)
+ new_resource.action(action)
+ provider.action = action
+ provider.load_current_resource
+ provider.define_resource_requirements
+ provider.process_resource_requirements
+ end
+
+ describe "with type is set to" do
+ describe "agent" do
+ it "path should be /Library/LaunchAgents/call.mom.weekly.plist" do
+ new_resource.type "agent"
+ expect(provider.gen_path_from_type).
+ to eq("/Library/LaunchAgents/call.mom.weekly.plist")
+ end
+ end
+ describe "daemon" do
+ it "path should be /Library/LaunchDaemons/call.mom.weekly.plist" do
+ expect(provider.gen_path_from_type).
+ to eq("/Library/LaunchDaemons/call.mom.weekly.plist")
+ end
+ end
+ end
+
+ describe "with a :create action and" do
+ describe "program is passed" do
+ it "should produce the test_plist from properties" do
+ new_resource.program "/Library/scripts/call_mom.sh"
+ new_resource.time_out 300
+ new_resource.start_calendar_interval "Hour" => 10, "Weekday" => 7
+ expect(provider.content?).to be_truthy
+ expect(provider.content).to eql(test_plist)
+ end
+ end
+
+ describe "start_calendar_interval is passed" do
+ it "should allow array of Hashes" do
+ allowed = (1..2).collect do |num|
+ {
+ "Hour" => 10 + num,
+ "Weekday" => num,
+ }
+ end
+ new_resource.program "/Library/scripts/call_mom.sh"
+ new_resource.time_out 300
+ new_resource.start_calendar_interval allowed
+ expect(provider.content?).to be_truthy
+ expect(provider.content).to eql(test_plist_multiple_intervals)
+ end
+
+ it "should allow all StartCalendarInterval keys" do
+ allowed = {
+ "Minute" => 1,
+ "Hour" => 1,
+ "Day" => 1,
+ "Weekday" => 1,
+ "Month" => 1,
+ }
+ new_resource.program "/Library/scripts/call_mom.sh"
+ new_resource.time_out 300
+ new_resource.start_calendar_interval allowed
+ expect(provider.content?).to be_truthy
+ %w{Minute Hour Day Weekday Month}.each do |key|
+ expect(provider.content).to include("<key>#{key}</key>")
+ end
+ end
+
+ it "should not allow invalid ShowCalendarInterval keys" do
+ new_resource.program "/Library/scripts/call_mom.sh"
+ new_resource.time_out 300
+ expect do
+ new_resource.start_calendar_interval "Hourly" => 1
+ end.to raise_error(/Hourly are invalid/)
+ end
+
+ it "should not allow non-integer values" do
+ new_resource.program "/Library/scripts/call_mom.sh"
+ new_resource.time_out 300
+ expect do
+ new_resource.start_calendar_interval "Weekday" => "1-2"
+ end.to raise_error(/Invalid value.*\(1-2\)/)
+ end
+ end
+
+ describe "hash is passed" do
+ it "should produce the test_plist content from the plist_hash property" do
+ new_resource.plist_hash test_hash
+ expect(provider.content?).to be_truthy
+ expect(provider.content).to eql(test_plist)
+ end
+ end
+ end
+
+ describe "with an :enable action" do
+ describe "and the file has been updated" do
+ before(:each) do
+ allow(provider).to receive(
+ :manage_plist).with(:create).and_return(true)
+ allow(provider).to receive(
+ :manage_service).with(:restart).and_return(true)
+ end
+
+ it "should call manage_service with a :restart action" do
+ expect(provider.manage_service(:restart)).to be_truthy
+ end
+
+ it "works with action enable" do
+ expect(run_resource_setup_for_action(:enable)).to be_truthy
+ provider.action_enable
+ end
+ end
+
+ describe "and the file has not been updated" do
+ before(:each) do
+ allow(provider).to receive(
+ :manage_plist).with(:create).and_return(nil)
+ allow(provider).to receive(
+ :manage_service).with(:enable).and_return(true)
+ end
+
+ it "should call manage_service with a :enable action" do
+ expect(provider.manage_service(:enable)).to be_truthy
+ end
+
+ it "works with action enable" do
+ expect(run_resource_setup_for_action(:enable)).to be_truthy
+ provider.action_enable
+ end
+ end
+ end
+
+ describe "with an :delete action" do
+ describe "and the ld file is present" do
+ before(:each) do
+ allow(File).to receive(:exists?).and_return(true)
+ allow(provider).to receive(
+ :manage_service).with(:disable).and_return(true)
+ allow(provider).to receive(
+ :manage_plist).with(:delete).and_return(true)
+ end
+
+ it "should call manage_service with a :disable action" do
+ expect(provider.manage_service(:disable)).to be_truthy
+ end
+
+ it "works with action :delete" do
+ expect(run_resource_setup_for_action(:delete)).to be_truthy
+ provider.action_delete
+ end
+ end
+
+ describe "and the ld file is not present" do
+ before(:each) do
+ allow(File).to receive(:exists?).and_return(false)
+ allow(provider).to receive(
+ :manage_plist).with(:delete).and_return(true)
+ end
+
+ it "works with action :delete" do
+ expect(run_resource_setup_for_action(:delete)).to be_truthy
+ provider.action_delete
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/provider/link_spec.rb b/spec/unit/provider/link_spec.rb
index 0f95ce997e..9426cf41dc 100644
--- a/spec/unit/provider/link_spec.rb
+++ b/spec/unit/provider/link_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: AJ Christensen (<aj@junglist.gen.nz>)
-# Author:: John Keiser (<jkeiser@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: John Keiser (<jkeiser@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,12 +17,12 @@
# limitations under the License.
#
-require 'ostruct'
+require "ostruct"
-require 'spec_helper'
+require "spec_helper"
if Chef::Platform.windows?
- require 'chef/win32/file' #probably need this in spec_helper
+ require "chef/win32/file" #probably need this in spec_helper
end
describe Chef::Resource::Link, :not_supported_on_win2k3 do
@@ -39,7 +39,7 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
end
def canonicalize(path)
- Chef::Platform.windows? ? path.gsub('/', '\\') : path
+ Chef::Platform.windows? ? path.tr("/", '\\') : path
end
describe "when the target is a symlink" do
@@ -80,13 +80,13 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
# We test create in unit tests because there is no other way to ensure
# it does no work. Other create and delete scenarios are covered in
# the functional tests for links.
- context 'when the desired state is identical' do
+ context "when the desired state is identical" do
let(:new_resource) do
result = Chef::Resource::Link.new("#{CHEF_SPEC_DATA}/fofile-link")
result.to "#{CHEF_SPEC_DATA}/fofile"
result
end
- it 'create does no work' do
+ it "create does no work" do
expect(provider.access_controls).not_to receive(:set_all)
provider.run_action(:create)
end
@@ -164,7 +164,7 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
expect(provider.current_resource.target_file).to eq("#{CHEF_SPEC_DATA}/fofile-link")
end
it "should update the current source of the existing link with an empty string" do
- expect(provider.current_resource.to).to eq('')
+ expect(provider.current_resource.to).to eq("")
end
it "should not set the owner" do
expect(provider.current_resource.owner).to eq(nil)
@@ -191,7 +191,7 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
expect(provider.current_resource.target_file).to eq("#{CHEF_SPEC_DATA}/fofile-link")
end
it "should update the current source of the existing link with an empty string" do
- expect(provider.current_resource.to).to eq('')
+ expect(provider.current_resource.to).to eq("")
end
it "should not set the owner" do
expect(provider.current_resource.owner).to eq(nil)
@@ -233,14 +233,14 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
# We test create in unit tests because there is no other way to ensure
# it does no work. Other create and delete scenarios are covered in
# the functional tests for links.
- context 'when the desired state is identical' do
+ context "when the desired state is identical" do
let(:new_resource) do
result = Chef::Resource::Link.new("#{CHEF_SPEC_DATA}/fofile-link")
result.to "#{CHEF_SPEC_DATA}/fofile"
result.link_type :hard
result
end
- it 'create does no work' do
+ it "create does no work" do
expect(provider.file_class).not_to receive(:symlink)
expect(provider.file_class).not_to receive(:link)
expect(provider.access_controls).not_to receive(:set_all)
@@ -249,4 +249,159 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
end
end
end
+
+ describe "action_delete" do
+ before(:each) do
+ stat = double("stats", :ino => 5)
+ allow(stat).to receive(:uid).and_return(501)
+ allow(stat).to receive(:gid).and_return(501)
+ allow(stat).to receive(:mode).and_return(0755)
+ allow(provider.file_class).to receive(:stat).with(
+ "#{CHEF_SPEC_DATA}/fofile-link").and_return(stat)
+
+ provider.load_current_resource
+ end
+
+ shared_context "delete link to directories on Windows" do
+ before do
+ allow(::File).to receive(:directory?).with(
+ "#{CHEF_SPEC_DATA}/fofile-link").and_return(true)
+ end
+
+ it "invokes Dir.delete method to delete the link" do
+ expect(::Dir).to receive(:delete).with(provider.new_resource.target_file)
+ expect(Chef::Log).to receive(:info).with("#{provider.new_resource} deleted")
+ provider.run_action(:delete)
+ end
+ end
+
+ shared_context "delete link to directories on Linux" do
+ before do
+ allow(::File).to receive(:directory?).with(
+ "#{CHEF_SPEC_DATA}/fofile-link").and_return(true)
+ end
+
+ it "invokes File.delete method to delete the link" do
+ expect(::File).to receive(:delete).with(provider.new_resource.target_file)
+ expect(Chef::Log).to receive(:info).with("#{provider.new_resource} deleted")
+ provider.run_action(:delete)
+ end
+ end
+
+ shared_context "delete link to files" do
+ before do
+ allow(::File).to receive(:directory?).with(
+ "#{CHEF_SPEC_DATA}/fofile-link").and_return(false)
+ end
+
+ it "invokes File.delete method to delete the link" do
+ expect(::File).to receive(:delete).with(provider.new_resource.target_file)
+ expect(Chef::Log).to receive(:info).with("#{provider.new_resource} deleted")
+ provider.run_action(:delete)
+ end
+ end
+
+ shared_context "soft links prerequisites" do
+ before(:each) do
+ allow(provider.file_class).to receive(:symlink?).with(
+ "#{CHEF_SPEC_DATA}/fofile-link").and_return(true)
+ allow(provider.file_class).to receive(:readlink).with(
+ "#{CHEF_SPEC_DATA}/fofile-link").and_return("#{CHEF_SPEC_DATA}/fofile")
+ end
+ end
+
+ shared_context "hard links prerequisites" do
+ let(:new_resource) do
+ result = Chef::Resource::Link.new("#{CHEF_SPEC_DATA}/fofile-link")
+ result.to "#{CHEF_SPEC_DATA}/fofile"
+ result.link_type :hard
+ result
+ end
+
+ before(:each) do
+ stat = double("stats", :ino => 5)
+ allow(stat).to receive(:uid).and_return(502)
+ allow(stat).to receive(:gid).and_return(502)
+ allow(stat).to receive(:mode).and_return(0644)
+
+ allow(provider.file_class).to receive(:symlink?).with(
+ "#{CHEF_SPEC_DATA}/fofile-link").and_return(false)
+
+ allow(File).to receive(:exists?).with(
+ "#{CHEF_SPEC_DATA}/fofile-link").and_return(true)
+ allow(File).to receive(:exists?).with(
+ "#{CHEF_SPEC_DATA}/fofile").and_return(true)
+
+ allow(provider.file_class).to receive(:stat).with(
+ "#{CHEF_SPEC_DATA}/fofile").and_return(stat)
+ end
+ end
+
+ context "on Windows platform" do
+ let(:resource_link) do
+ Chef::Resource::Link.new(provider.new_resource.name)
+ end
+
+ before(:each) do
+ allow(Chef::Resource::Link).to receive(:new).with(
+ provider.new_resource.name).and_return(resource_link)
+ allow(resource_link).to receive(:verify_links_supported!)
+ allow(Chef::Platform).to receive(:windows?).and_return(true)
+ end
+
+ context "soft links" do
+ include_context "soft links prerequisites"
+
+ context "to directories" do
+ include_context "delete link to directories on Windows"
+ end
+
+ context "to files" do
+ include_context "delete link to files"
+ end
+ end
+
+ context "hard links" do
+ include_context "hard links prerequisites"
+
+ context "to directories" do
+ include_context "delete link to directories on Windows"
+ end
+
+ context "to files" do
+ include_context "delete link to files"
+ end
+ end
+ end
+
+ context "on Linux platform" do
+ before(:each) do
+ allow(Chef::Platform).to receive(:windows?).and_return(false)
+ end
+
+ context "soft links" do
+ include_context "soft links prerequisites"
+
+ context "to directories" do
+ include_context "delete link to directories on Linux"
+ end
+
+ context "to files" do
+ include_context "delete link to files"
+ end
+ end
+
+ context "hard links" do
+ include_context "hard links prerequisites"
+
+ context "to directories" do
+ include_context "delete link to directories on Linux"
+ end
+
+ context "to files" do
+ include_context "delete link to files"
+ end
+ end
+ end
+ end
end
diff --git a/spec/unit/provider/log_spec.rb b/spec/unit/provider/log_spec.rb
index 1ecc633ce1..ce7b1af55a 100644
--- a/spec/unit/provider/log_spec.rb
+++ b/spec/unit/provider/log_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Cary Penniman (<cary@rightscale.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Log::ChefLog do
@@ -72,4 +72,18 @@ describe Chef::Provider::Log::ChefLog do
expect(Chef::Log).to receive(:info).with(log_str).and_return(true)
provider.run_action(:write)
end
+
+ context "when count_log_resource_updates is passed in knife.rb" do
+ it "updates the resource count if count_log_resource_updates=true" do
+ Chef::Config[:count_log_resource_updates] = true
+ expect(new_resource).to receive(:updated_by_last_action)
+ provider.run_action(:write)
+ end
+
+ it "doesn't update the resource count if count_log_resource_updates=false" do
+ Chef::Config[:count_log_resource_updates] = false
+ expect(new_resource).not_to receive(:updated_by_last_action)
+ provider.run_action(:write)
+ end
+ end
end
diff --git a/spec/unit/provider/mdadm_spec.rb b/spec/unit/provider/mdadm_spec.rb
index 77ed5798a8..8ef884e131 100644
--- a/spec/unit/provider/mdadm_spec.rb
+++ b/spec/unit/provider/mdadm_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Provider::Mdadm do
@@ -25,8 +25,8 @@ describe Chef::Provider::Mdadm do
@node = Chef::Node.new
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Mdadm.new('/dev/md1')
- @new_resource.devices ["/dev/sdz1","/dev/sdz2","/dev/sdz3"]
+ @new_resource = Chef::Resource::Mdadm.new("/dev/md1")
+ @new_resource.devices ["/dev/sdz1", "/dev/sdz2", "/dev/sdz3"]
@provider = Chef::Provider::Mdadm.new(@new_resource, @run_context)
end
@@ -34,18 +34,18 @@ describe Chef::Provider::Mdadm do
it "should set the current resources mount point to the new resources mount point" do
allow(@provider).to receive(:shell_out!).and_return(OpenStruct.new(:status => 0))
@provider.load_current_resource
- expect(@provider.current_resource.name).to eq('/dev/md1')
- expect(@provider.current_resource.raid_device).to eq('/dev/md1')
+ expect(@provider.current_resource.name).to eq("/dev/md1")
+ expect(@provider.current_resource.raid_device).to eq("/dev/md1")
end
it "determines that the metadevice exists when mdadm exit code is zero" do
- allow(@provider).to receive(:shell_out!).with("mdadm --detail --test /dev/md1", :returns => [0,4]).and_return(OpenStruct.new(:status => 0))
+ allow(@provider).to receive(:shell_out!).with("mdadm --detail --test /dev/md1", :returns => [0, 4]).and_return(OpenStruct.new(:status => 0))
@provider.load_current_resource
expect(@provider.current_resource.exists).to be_truthy
end
it "determines that the metadevice does not exist when mdadm exit code is 4" do
- allow(@provider).to receive(:shell_out!).with("mdadm --detail --test /dev/md1", :returns => [0,4]).and_return(OpenStruct.new(:status => 4))
+ allow(@provider).to receive(:shell_out!).with("mdadm --detail --test /dev/md1", :returns => [0, 4]).and_return(OpenStruct.new(:status => 4))
@provider.load_current_resource
expect(@provider.current_resource.exists).to be_falsey
end
@@ -53,7 +53,7 @@ describe Chef::Provider::Mdadm do
describe "after the metadevice status is known" do
before(:each) do
- @current_resource = Chef::Resource::Mdadm.new('/dev/md1')
+ @current_resource = Chef::Resource::Mdadm.new("/dev/md1")
@new_resource.level 5
allow(@provider).to receive(:load_current_resource).and_return(true)
@provider.current_resource = @current_resource
@@ -69,13 +69,22 @@ describe Chef::Provider::Mdadm do
it "should specify a bitmap only if set" do
@current_resource.exists(false)
- @new_resource.bitmap('grow')
+ @new_resource.bitmap("grow")
expected_command = "yes | mdadm --create /dev/md1 --level 5 --chunk=16 --metadata=0.90 --bitmap=grow --raid-devices 3 /dev/sdz1 /dev/sdz2 /dev/sdz3"
expect(@provider).to receive(:shell_out!).with(expected_command)
@provider.run_action(:create)
expect(@new_resource).to be_updated_by_last_action
end
+ it "should specify a layout only if set" do
+ @current_resource.exists(false)
+ @new_resource.layout("rs")
+ expected_command = "yes | mdadm --create /dev/md1 --level 5 --chunk=16 --metadata=0.90 --layout=rs --raid-devices 3 /dev/sdz1 /dev/sdz2 /dev/sdz3"
+ expect(@provider).to receive(:shell_out!).with(expected_command)
+ @provider.run_action(:create)
+ expect(@new_resource).to be_updated_by_last_action
+ end
+
it "should not specify a chunksize if raid level 1" do
@current_resource.exists(false)
@new_resource.level 1
@@ -102,7 +111,7 @@ describe Chef::Provider::Mdadm do
expect(@new_resource).to be_updated_by_last_action
end
- it "should not assemble the raid device if it doesnt exist" do
+ it "should not assemble the raid device if it doesnt exist" do
@current_resource.exists(true)
expect(@provider).not_to receive(:shell_out!)
@provider.run_action(:assemble)
diff --git a/spec/unit/provider/mount/aix_spec.rb b/spec/unit/provider/mount/aix_spec.rb
index e232592275..3371c270c5 100644
--- a/spec/unit/provider/mount/aix_spec.rb
+++ b/spec/unit/provider/mount/aix_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2013 OpsCode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Provider::Mount::Aix do
@@ -40,7 +40,7 @@ UNMOUNTED
/dev/sdz3 /tmp/foo jfs2 Jul 17 13:22 rw,log=/dev/hd8
MOUNT
- @enabled_output = <<-ENABLED
+ @enabled_output = <<-ENABLED
#MountPoint:Device:Vfs:Nodename:Type:Size:Options:AutoMount:Acct
/tmp/foo:/dev/sdz1:jfs2::bootfs:10485760:rw:yes:no
ENABLED
@@ -114,7 +114,7 @@ ENABLED
expect(@provider.current_resource.mounted).to be_truthy
expect(@provider.current_resource.mount_point).to eql(@new_resource.mount_point)
expect(@provider.current_resource.fstype).to eql("jfs2")
- expect(@provider.current_resource.options).to eql(['rw'])
+ expect(@provider.current_resource.options).to eql(["rw"])
end
describe "mount_fs" do
@@ -126,10 +126,9 @@ ENABLED
@provider.run_action(:mount)
end
- it "should not mount resource if it is already mounted and the options have not changed" do
+ it "should not mount resource if it is already mounted" do
stub_mounted_enabled(@provider, @mounted_output, "")
- allow(@provider).to receive(:mount_options_unchanged?).and_return(true)
expect(@provider).not_to receive(:mount_fs)
@provider.run_action(:mount)
@@ -156,7 +155,7 @@ ENABLED
describe "remount_fs" do
it "should remount resource if it is already mounted and it supports remounting" do
- @new_resource.supports({:remount => true})
+ @new_resource.supports({ :remount => true })
stub_mounted_enabled(@provider, @mounted_output, "")
expect(@provider).to receive(:shell_out!).with("mount -o remount #{@new_resource.device} #{@new_resource.mount_point}")
@@ -165,7 +164,7 @@ ENABLED
end
it "should remount with new mount options if it is already mounted and it supports remounting" do
- @new_resource.supports({:remount => true})
+ @new_resource.supports({ :remount => true })
@new_resource.options("nodev,rw")
stub_mounted_enabled(@provider, @mounted_output, "")
diff --git a/spec/unit/provider/mount/mount_spec.rb b/spec/unit/provider/mount/mount_spec.rb
index dd13a62796..20a4fd88dd 100644
--- a/spec/unit/provider/mount/mount_spec.rb
+++ b/spec/unit/provider/mount/mount_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Joshua Timberman (<joshua@opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: Joshua Timberman (<joshua@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Provider::Mount::Mount do
before(:each) do
@@ -42,15 +42,15 @@ describe Chef::Provider::Mount::Mount do
describe "when discovering the current fs state" do
before do
- allow(@provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => ''))
+ allow(@provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => ""))
allow(::File).to receive(:foreach).with("/etc/fstab")
end
it "should create a current resource with the same mount point and device" do
@provider.load_current_resource
- expect(@provider.current_resource.name).to eq('/tmp/foo')
- expect(@provider.current_resource.mount_point).to eq('/tmp/foo')
- expect(@provider.current_resource.device).to eq('/dev/sdz1')
+ expect(@provider.current_resource.name).to eq("/tmp/foo")
+ expect(@provider.current_resource.mount_point).to eq("/tmp/foo")
+ expect(@provider.current_resource.device).to eq("/dev/sdz1")
end
it "should accecpt device_type :uuid", :not_supported_on_solaris do
@@ -82,7 +82,7 @@ describe Chef::Provider::Mount::Mount do
it "should raise an error if the mount device does not exist" do
allow(::File).to receive(:exists?).with("/dev/sdz1").and_return false
- expect { @provider.load_current_resource();@provider.mountable? }.to raise_error(Chef::Exceptions::Mount)
+ expect { @provider.load_current_resource(); @provider.mountable? }.to raise_error(Chef::Exceptions::Mount)
end
it "should not call mountable? with load_current_resource - CHEF-1565" do
@@ -99,25 +99,25 @@ describe Chef::Provider::Mount::Mount do
@new_resource.device "d21afe51-a0fe-4dc6-9152-ac733763ae0a"
expect(@provider).to receive(:shell_out).with("/sbin/findfs UUID=d21afe51-a0fe-4dc6-9152-ac733763ae0a").and_return(status)
expect(::File).to receive(:exists?).with("").and_return(false)
- expect { @provider.load_current_resource();@provider.mountable? }.to raise_error(Chef::Exceptions::Mount)
+ expect { @provider.load_current_resource(); @provider.mountable? }.to raise_error(Chef::Exceptions::Mount)
end
it "should raise an error if the mount point does not exist" do
allow(::File).to receive(:exists?).with("/tmp/foo").and_return false
- expect { @provider.load_current_resource();@provider.mountable? }.to raise_error(Chef::Exceptions::Mount)
+ expect { @provider.load_current_resource(); @provider.mountable? }.to raise_error(Chef::Exceptions::Mount)
end
- [ "tmpfs", "fuse", "cgroup" ].each do |fstype|
+ %w{tmpfs fuse cgroup vboxsf zfs}.each do |fstype|
it "does not expect the device to exist for #{fstype}" do
@new_resource.fstype(fstype)
@new_resource.device("whatever")
- expect { @provider.load_current_resource();@provider.mountable? }.not_to raise_error
+ expect { @provider.load_current_resource(); @provider.mountable? }.not_to raise_error
end
end
it "does not expect the device to exist if it's none" do
@new_resource.device("none")
- expect { @provider.load_current_resource();@provider.mountable? }.not_to raise_error
+ expect { @provider.load_current_resource(); @provider.mountable? }.not_to raise_error
end
it "should set mounted true if the mount point is found in the mounts list" do
@@ -134,7 +134,7 @@ describe Chef::Provider::Mount::Mount do
it "should set mounted true if the symlink target of the device is found in the mounts list" do
# expand the target path to correct specs on Windows
- target = ::File.expand_path('/dev/mapper/target')
+ target = ::File.expand_path("/dev/mapper/target")
allow(::File).to receive(:symlink?).with("#{@new_resource.device}").and_return(true)
allow(::File).to receive(:readlink).with("#{@new_resource.device}").and_return(target)
@@ -239,12 +239,12 @@ describe Chef::Provider::Mount::Mount do
end
it "should ignore commented lines in fstab " do
- fstab = "\# #{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n"
- allow(::File).to receive(:foreach).with("/etc/fstab").and_yield fstab
+ fstab = "\# #{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n"
+ allow(::File).to receive(:foreach).with("/etc/fstab").and_yield fstab
- @provider.load_current_resource
- expect(@provider.current_resource.enabled).to be_falsey
- end
+ @provider.load_current_resource
+ expect(@provider.current_resource.enabled).to be_falsey
+ end
it "should set enabled to false if the mount point is not last in fstab" do
line_1 = "#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n"
@@ -266,7 +266,7 @@ describe Chef::Provider::Mount::Mount do
fstab = "#{@new_resource.device} #{@new_resource.mount_point} #{@new_resource.fstype} #{options} 1 2\n"
allow(::File).to receive(:foreach).with("/etc/fstab").and_yield fstab
@provider.load_current_resource
- expect(@provider.current_resource.options).to eq(options.split(','))
+ expect(@provider.current_resource.options).to eq(options.split(","))
end
it "should not mangle the mount options if the symlink target is in fstab" do
@@ -279,7 +279,7 @@ describe Chef::Provider::Mount::Mount do
fstab = "#{target} #{@new_resource.mount_point} #{@new_resource.fstype} #{options} 1 2\n"
allow(::File).to receive(:foreach).with("/etc/fstab").and_yield fstab
@provider.load_current_resource
- expect(@provider.current_resource.options).to eq(options.split(','))
+ expect(@provider.current_resource.options).to eq(options.split(","))
end
end
@@ -311,7 +311,7 @@ describe Chef::Provider::Mount::Mount do
@new_resource.device "d21afe51-a0fe-4dc6-9152-ac733763ae0a"
@new_resource.device_type :uuid
allow(@provider).to receive(:shell_out).with("/sbin/findfs UUID=d21afe51-a0fe-4dc6-9152-ac733763ae0a").and_return(status)
- @stdout_mock = double('stdout mock')
+ @stdout_mock = double("stdout mock")
allow(@stdout_mock).to receive(:each).and_yield("#{@new_resource.device} on #{@new_resource.mount_point}")
expect(@provider).to receive(:shell_out!).with("mount -t #{@new_resource.fstype} -o defaults -U #{@new_resource.device} #{@new_resource.mount_point}").and_return(@stdout_mock)
@provider.mount_fs()
@@ -323,12 +323,6 @@ describe Chef::Provider::Mount::Mount do
@provider.mount_fs()
end
- it "should not mount the filesystem if it is mounted and the options have not changed" do
- allow(@current_resource).to receive(:mounted).and_return(true)
- expect(@provider).to_not receive(:shell_out!)
- @provider.mount_fs()
- end
-
end
describe "umount_fs" do
@@ -347,14 +341,14 @@ describe Chef::Provider::Mount::Mount do
describe "remount_fs" do
it "should use mount -o remount if remount is supported" do
- @new_resource.supports({:remount => true})
+ @new_resource.supports({ :remount => true })
@current_resource.mounted(true)
expect(@provider).to receive(:shell_out!).with("mount -o remount,defaults #{@new_resource.mount_point}")
@provider.remount_fs
end
it "should use mount -o remount with new mount options if remount is supported" do
- @new_resource.supports({:remount => true})
+ @new_resource.supports({ :remount => true })
options = "rw,noexec,noauto"
@new_resource.options(%w{rw noexec noauto})
@current_resource.mounted(true)
@@ -363,7 +357,7 @@ describe Chef::Provider::Mount::Mount do
end
it "should umount and mount if remount is not supported" do
- @new_resource.supports({:remount => false})
+ @new_resource.supports({ :remount => false })
@current_resource.mounted(true)
expect(@provider).to receive(:umount_fs)
expect(@provider).to receive(:sleep).with(1)
diff --git a/spec/unit/provider/mount/solaris_spec.rb b/spec/unit/provider/mount/solaris_spec.rb
index 9a9b09b531..264c8b9b36 100644
--- a/spec/unit/provider/mount/solaris_spec.rb
+++ b/spec/unit/provider/mount/solaris_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@getchef.com>)
-# Copyright:: Copyright (c) 2008-2014 Chef Software, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
# Do not run these tests on windows because some path handling
# code is not implemented to handle windows paths.
@@ -41,7 +41,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
let(:options) { nil }
- let(:new_resource) {
+ let(:new_resource) do
new_resource = Chef::Resource::Mount.new(mountpoint)
new_resource.device device
new_resource.device_type device_type
@@ -50,14 +50,14 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
new_resource.options options
new_resource.supports :remount => false
new_resource
- }
+ end
- let(:provider) {
+ let(:provider) do
Chef::Provider::Mount::Solaris.new(new_resource, run_context)
- }
+ end
- let(:vfstab_file_contents) {
- <<-EOF.gsub /^\s*/, ''
+ let(:vfstab_file_contents) do
+ <<-EOF.gsub /^\s*/, ""
#device device mount FS fsck mount mount
#to mount to fsck point type pass at boot options
#
@@ -74,21 +74,21 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
# ufs
/dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -
EOF
- }
+ end
- let(:vfstab_file) {
+ let(:vfstab_file) do
t = Tempfile.new("rspec-vfstab")
t.write(vfstab_file_contents)
t.close
t
- }
+ end
- let(:mount_output) {
- <<-EOF.gsub /^\s*/, ''
+ let(:mount_output) do
+ <<-EOF.gsub /^\s*/, ""
/dev/dsk/c0t0d0s0 on / type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200000 on Tue Jul 31 22:34:46 2012
/dev/dsk/c0t2d0s7 on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
EOF
- }
+ end
before do
stub_const("Chef::Provider::Mount::Solaris::VFSTAB", vfstab_file.path )
@@ -103,7 +103,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
describe "#define_resource_requirements" do
before do
# we're not testing the actual actions so stub them all out
- [:mount_fs, :umount_fs, :remount_fs, :enable_fs, :disable_fs].each {|m| allow(provider).to receive(m) }
+ [:mount_fs, :umount_fs, :remount_fs, :enable_fs, :disable_fs].each { |m| allow(provider).to receive(m) }
end
it "run_action(:mount) should raise an error if the device does not exist" do
@@ -214,8 +214,8 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
describe "#load_current_resource" do
context "when loading a normal UFS filesystem with noauto, don't mount at boot" do
- let(:vfstab_file_contents) {
- <<-EOF.gsub /^\s*/, ''
+ let(:vfstab_file_contents) do
+ <<-EOF.gsub /^\s*/, ""
#device device mount FS fsck mount mount
#to mount to fsck point type pass at boot options
#
@@ -232,7 +232,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
# ufs
/dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 no -
EOF
- }
+ end
before do
provider.load_current_resource
@@ -244,16 +244,16 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
context "when the device is an smbfs mount" do
- let(:mount_output) {
- <<-EOF.gsub /^\s*/, ''
+ let(:mount_output) do
+ <<-EOF.gsub /^\s*/, ""
//solarsystem/tmp on /mnt type smbfs read/write/setuid/devices/dev=5080000 on Tue Mar 29 11:40:18 2011
EOF
- }
- let(:vfstab_file_contents) {
- <<-EOF.gsub /^\s*/, ''
+ end
+ let(:vfstab_file_contents) do
+ <<-EOF.gsub /^\s*/, ""
//WORKGROUP;username:password@host/share - /mountpoint smbfs - no fileperms=0777,dirperms=0777
EOF
- }
+ end
let(:fsck_device) { "-" }
@@ -263,17 +263,17 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
context "when the device is an NFS mount" do
- let(:mount_output) {
- <<-EOF.gsub /^\s*/, ''
+ let(:mount_output) do
+ <<-EOF.gsub /^\s*/, ""
cartman:/share2 on /cartman type nfs rsize=32768,wsize=32768,NFSv4,dev=4000004 on Tue Mar 29 11:40:18 2011
EOF
- }
+ end
- let(:vfstab_file_contents) {
- <<-EOF.gsub /^\s*/, ''
+ let(:vfstab_file_contents) do
+ <<-EOF.gsub /^\s*/, ""
cartman:/share2 - /cartman nfs - yes rw,soft
EOF
- }
+ end
let(:fsck_device) { "-" }
@@ -316,7 +316,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
it "should set the options field on the current_resource" do
- expect(provider.current_resource.options).to eql(["rw", "soft"])
+ expect(provider.current_resource.options).to eql(%w{rw soft})
end
it "should set the pass field on the current_resource" do
@@ -334,17 +334,17 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
let(:target) { "/dev/mapper/target" }
- let(:mount_output) {
- <<-EOF.gsub /^\s*/, ''
+ let(:mount_output) do
+ <<-EOF.gsub /^\s*/, ""
#{target} on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
EOF
- }
+ end
- let(:vfstab_file_contents) {
- <<-EOF.gsub /^\s*/, ''
+ let(:vfstab_file_contents) do
+ <<-EOF.gsub /^\s*/, ""
#{target} /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -
EOF
- }
+ end
before do
expect(File).to receive(:symlink?).with(device).at_least(:once).and_return(true)
@@ -371,17 +371,17 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
let(:absolute_target) { File.expand_path(target, File.dirname(device)) }
- let(:mount_output) {
- <<-EOF.gsub /^\s*/, ''
+ let(:mount_output) do
+ <<-EOF.gsub /^\s*/, ""
#{absolute_target} on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
EOF
- }
+ end
- let(:vfstab_file_contents) {
- <<-EOF.gsub /^\s*/, ''
+ let(:vfstab_file_contents) do
+ <<-EOF.gsub /^\s*/, ""
#{absolute_target} /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -
EOF
- }
+ end
before do
expect(File).to receive(:symlink?).with(device).at_least(:once).and_return(true)
@@ -404,12 +404,12 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
context "when the matching mount point is last in the mounts list" do
- let(:mount_output) {
- <<-EOF.gsub /^\s*/, ''
+ let(:mount_output) do
+ <<-EOF.gsub /^\s*/, ""
/dev/dsk/c0t0d0s0 on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200000 on Tue Jul 31 22:34:46 2012
/dev/dsk/c0t2d0s7 on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
EOF
- }
+ end
it "should set mounted true" do
provider.load_current_resource()
expect(provider.current_resource.mounted).to be_truthy
@@ -417,12 +417,12 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
context "when the matching mount point is not last in the mounts list" do
- let(:mount_output) {
- <<-EOF.gsub /^\s*/, ''
+ let(:mount_output) do
+ <<-EOF.gsub /^\s*/, ""
/dev/dsk/c0t2d0s7 on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
/dev/dsk/c0t0d0s0 on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200000 on Tue Jul 31 22:34:46 2012
EOF
- }
+ end
it "should set mounted false" do
provider.load_current_resource()
expect(provider.current_resource.mounted).to be_falsey
@@ -430,11 +430,11 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
context "when the matching mount point is not in the mounts list (mountpoint wrong)" do
- let(:mount_output) {
- <<-EOF.gsub /^\s*/, ''
+ let(:mount_output) do
+ <<-EOF.gsub /^\s*/, ""
/dev/dsk/c0t2d0s7 on /mnt/foob type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
EOF
- }
+ end
it "should set mounted false" do
provider.load_current_resource()
expect(provider.current_resource.mounted).to be_falsey
@@ -442,11 +442,11 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
context "when the matching mount point is not in the mounts list (raw device wrong)" do
- let(:mount_output) {
- <<-EOF.gsub /^\s*/, ''
+ let(:mount_output) do
+ <<-EOF.gsub /^\s*/, ""
/dev/dsk/c0t2d0s72 on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
EOF
- }
+ end
it "should set mounted false" do
provider.load_current_resource()
expect(provider.current_resource.mounted).to be_falsey
@@ -454,12 +454,12 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
context "when the mount point is last in fstab" do
- let(:vfstab_file_contents) {
- <<-EOF.gsub /^\s*/, ''
+ let(:vfstab_file_contents) do
+ <<-EOF.gsub /^\s*/, ""
/dev/dsk/c0t2d0s72 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -
/dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -
EOF
- }
+ end
it "should set enabled to true" do
provider.load_current_resource
@@ -468,12 +468,12 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
context "when the mount point is not last in fstab and is a substring of another mount" do
- let(:vfstab_file_contents) {
- <<-EOF.gsub /^\s*/, ''
+ let(:vfstab_file_contents) do
+ <<-EOF.gsub /^\s*/, ""
/dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -
/dev/dsk/c0t2d0s72 /dev/rdsk/c0t2d0s7 /mnt/foo/bar ufs 2 yes -
EOF
- }
+ end
it "should set enabled to true" do
provider.load_current_resource
@@ -482,12 +482,12 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
context "when the mount point is not last in fstab" do
- let(:vfstab_file_contents) {
- <<-EOF.gsub /^\s*/, ''
+ let(:vfstab_file_contents) do
+ <<-EOF.gsub /^\s*/, ""
/dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -
/dev/dsk/c0t2d0s72 /dev/rdsk/c0t2d0s72 /mnt/foo ufs 2 yes -
EOF
- }
+ end
it "should set enabled to false" do
provider.load_current_resource
@@ -496,11 +496,11 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
context "when the mount point is not in fstab, but the mountpoint is a substring of one that is" do
- let(:vfstab_file_contents) {
- <<-EOF.gsub /^\s*/, ''
+ let(:vfstab_file_contents) do
+ <<-EOF.gsub /^\s*/, ""
/dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foob ufs 2 yes -
EOF
- }
+ end
it "should set enabled to false" do
provider.load_current_resource
@@ -509,11 +509,11 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
context "when the mount point is not in fstab, but the device is a substring of one that is" do
- let(:vfstab_file_contents) {
- <<-EOF.gsub /^\s*/, ''
+ let(:vfstab_file_contents) do
+ <<-EOF.gsub /^\s*/, ""
/dev/dsk/c0t2d0s72 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -
EOF
- }
+ end
it "should set enabled to false" do
provider.load_current_resource
@@ -522,11 +522,11 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
end
context "when the mountpoint line is commented out" do
- let(:vfstab_file_contents) {
- <<-EOF.gsub /^\s*/, ''
+ let(:vfstab_file_contents) do
+ <<-EOF.gsub /^\s*/, ""
#/dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -
EOF
- }
+ end
it "should set enabled to false" do
provider.load_current_resource
diff --git a/spec/unit/provider/mount/windows_spec.rb b/spec/unit/provider/mount/windows_spec.rb
index 2de6f11d43..fdb44836b5 100644
--- a/spec/unit/provider/mount/windows_spec.rb
+++ b/spec/unit/provider/mount/windows_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
class Chef
class Util
@@ -100,9 +100,9 @@ describe Chef::Provider::Mount::Windows do
it "should mount the filesystem if it is not mounted" do
expect(@vol).to receive(:add).with(:remote => @new_resource.device,
- :username => @new_resource.username,
- :domainname => @new_resource.domain,
- :password => @new_resource.password)
+ :username => @new_resource.username,
+ :domainname => @new_resource.domain,
+ :password => @new_resource.password)
@provider.mount_fs
end
@@ -112,18 +112,16 @@ describe Chef::Provider::Mount::Windows do
@provider.mount_fs
end
- it "should remount the filesystem if it is mounted and the options have changed" do
- expect(@vol).to receive(:add).with(:remote => @new_resource.device,
- :username => @new_resource.username,
- :domainname => @new_resource.domain,
- :password => @new_resource.password)
- @provider.mount_fs
- end
+ context "mount_options_unchanged?" do
+ it "should return true if mounted device is the same" do
+ allow(@current_resource).to receive(:device).and_return(GUID)
+ expect(@provider.send :mount_options_unchanged?).to be true
+ end
- it "should not mount the filesystem if it is mounted and the options have not changed" do
- expect(@vol).to_not receive(:add)
- allow(@current_resource).to receive(:mounted).and_return(true)
- @provider.mount_fs
+ it "should return false if mounted device has changed" do
+ allow(@current_resource).to receive(:device).and_return("XXXX")
+ expect(@provider.send :mount_options_unchanged?).to be false
+ end
end
end
diff --git a/spec/unit/provider/mount_spec.rb b/spec/unit/provider/mount_spec.rb
index cc2a456440..b2497cf1b2 100644
--- a/spec/unit/provider/mount_spec.rb
+++ b/spec/unit/provider/mount_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Joshua Timberman (<joshua@getchef.com>)
-# Author:: Lamont Granquist (<lamont@getchef.com>)
-# Copyright:: Copyright (c) 2008-2014 Chef Software, Inc.
+# Author:: Joshua Timberman (<joshua@chef.io>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Mount do
@@ -28,7 +28,7 @@ describe Chef::Provider::Mount do
let(:run_context) { Chef::RunContext.new(node, {}, events) }
let(:new_resource) do
- new_resource = Chef::Resource::Mount.new('/tmp/foo')
+ new_resource = Chef::Resource::Mount.new("/tmp/foo")
new_resource.device "/dev/sdz1"
new_resource.name "/tmp/foo"
new_resource.mount_point "/tmp/foo"
@@ -38,7 +38,7 @@ describe Chef::Provider::Mount do
let(:current_resource) do
# this abstract superclass has no load_current_resource to call
- current_resource = Chef::Resource::Mount.new('/tmp/foo')
+ current_resource = Chef::Resource::Mount.new("/tmp/foo")
current_resource.device "/dev/sdz1"
current_resource.name "/tmp/foo"
current_resource.mount_point "/tmp/foo"
@@ -60,32 +60,20 @@ describe Chef::Provider::Mount do
provider.run_action(:mount)
expect(new_resource).to be_updated_by_last_action
end
+ end
- it "should remount the filesystem if it is mounted and the options have changed" do
+ describe "when the target state is an unmounted filesystem" do
+ it "should umount the filesystem if it is mounted" do
allow(current_resource).to receive(:mounted).and_return(true)
- allow(provider).to receive(:mount_options_unchanged?).and_return(false)
expect(provider).to receive(:umount_fs).and_return(true)
- expect(provider).to receive(:wait_until_unmounted)
- expect(provider).to receive(:mount_fs).and_return(true)
- provider.run_action(:mount)
+ provider.run_action(:umount)
expect(new_resource).to be_updated_by_last_action
end
- it "should not mount the filesystem if it is mounted and the options have not changed" do
- allow(current_resource).to receive(:mounted).and_return(true)
- expect(provider).to receive(:mount_options_unchanged?).and_return(true)
- expect(provider).not_to receive(:mount_fs)
- provider.run_action(:mount)
- expect(new_resource).not_to be_updated_by_last_action
- end
-
- end
-
- describe "when the target state is an unmounted filesystem" do
- it "should umount the filesystem if it is mounted" do
+ it "should unmount the filesystem if it is mounted" do
allow(current_resource).to receive(:mounted).and_return(true)
expect(provider).to receive(:umount_fs).and_return(true)
- provider.run_action(:umount)
+ provider.run_action(:unmount)
expect(new_resource).to be_updated_by_last_action
end
@@ -135,7 +123,7 @@ describe Chef::Provider::Mount do
provider.unmount_retries = 1
expect(provider).to receive(:umount_fs)
expect(provider).to receive(:mounted?).and_return(true, true)
- expect{ provider.run_action(:remount) }.to raise_error(Chef::Exceptions::Mount)
+ expect { provider.run_action(:remount) }.to raise_error(Chef::Exceptions::Mount)
end
end
@@ -181,7 +169,6 @@ describe Chef::Provider::Mount do
end
end
-
it "should delegates the mount implementation to subclasses" do
expect { provider.mount_fs }.to raise_error(Chef::Exceptions::UnsupportedAction)
end
diff --git a/spec/unit/provider/ohai_spec.rb b/spec/unit/provider/ohai_spec.rb
index 45688cedb7..fad08ba589 100644
--- a/spec/unit/provider/ohai_spec.rb
+++ b/spec/unit/provider/ohai_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Michael Leinartas (<mleinartas@gmail.com>)
-# Copyright:: Copyright (c) 2010 Michael Leinartas
+# Copyright:: Copyright 2010-2016, Michael Leinartas
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/run_context'
+require "chef/run_context"
describe Chef::Provider::Ohai do
before(:each) do
@@ -34,19 +34,19 @@ describe Chef::Provider::Ohai do
:platform => @platform,
:platform_version => @platform_version,
:data => {
- :origdata => "somevalue"
+ :origdata => "somevalue",
},
:data2 => {
:origdata => "somevalue",
- :newdata => "somevalue"
- }
+ :newdata => "somevalue",
+ },
}
allow(mock_ohai).to receive(:all_plugins).and_return(true)
allow(mock_ohai).to receive(:data).and_return(mock_ohai[:data],
mock_ohai[:data2])
allow(Ohai::System).to receive(:new).and_return(mock_ohai)
allow(Chef::Platform).to receive(:find_platform_and_version).and_return({ "platform" => @platform,
- "platform_version" => @platform_version})
+ "platform_version" => @platform_version })
# Fake node with a dummy save
@node = Chef::Node.new
@node.name(@fqdn)
@@ -56,29 +56,29 @@ describe Chef::Provider::Ohai do
@new_resource = Chef::Resource::Ohai.new("ohai_reload")
ohai = Ohai::System.new
ohai.all_plugins
- @node.consume_external_attrs(ohai.data,{})
+ @node.consume_external_attrs(ohai.data, {})
@provider = Chef::Provider::Ohai.new(@new_resource, @run_context)
end
describe "when reloading ohai" do
before do
- @node.automatic_attrs[:origdata] = 'somevalue'
+ @node.automatic_attrs[:origdata] = "somevalue"
end
it "applies updated ohai data to the node" do
- expect(@node[:origdata]).to eq('somevalue')
+ expect(@node[:origdata]).to eq("somevalue")
expect(@node[:newdata]).to be_nil
@provider.run_action(:reload)
- expect(@node[:origdata]).to eq('somevalue')
- expect(@node[:newdata]).to eq('somevalue')
+ expect(@node[:origdata]).to eq("somevalue")
+ expect(@node[:newdata]).to eq("somevalue")
end
it "should reload a specific plugin and cause node to pick up new values" do
@new_resource.plugin "someplugin"
@provider.run_action(:reload)
- expect(@node[:origdata]).to eq('somevalue')
- expect(@node[:newdata]).to eq('somevalue')
+ expect(@node[:origdata]).to eq("somevalue")
+ expect(@node[:newdata]).to eq("somevalue")
end
end
end
diff --git a/spec/unit/provider/osx_profile_spec.rb b/spec/unit/provider/osx_profile_spec.rb
new file mode 100644
index 0000000000..a1dcf3ecd6
--- /dev/null
+++ b/spec/unit/provider/osx_profile_spec.rb
@@ -0,0 +1,255 @@
+#
+# Author:: Nate Walck (<nate.walck@gmail.com>)
+# Copyright:: Copyright 2015-2016, Chef, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::OsxProfile do
+ let(:shell_out_success) do
+ double("shell_out", :exitstatus => 0, :error? => false)
+ end
+ describe "action_create" do
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:new_resource) { Chef::Resource::OsxProfile.new("Profile Test", run_context) }
+ let(:provider) { Chef::Provider::OsxProfile.new(new_resource, run_context) }
+ let(:all_profiles) do
+ { "_computerlevel" => [{ "ProfileDisplayName" => "Finder Settings",
+ "ProfileIdentifier" => "com.apple.finder",
+ "ProfileInstallDate" => "2015-11-08 23:15:21 +0000",
+ "ProfileItems" => [{ "PayloadContent" => { "PayloadContentManagedPreferences" => { "com.apple.finder" => { "Forced" => [{ "mcx_preference_settings" => { "ShowExternalHardDrivesOnDesktop" => false } }] } } },
+ "PayloadDisplayName" => "Custom: (com.apple.finder)",
+ "PayloadIdentifier" => "com.apple.finder",
+ "PayloadType" => "com.apple.ManagedClient.preferences",
+ "PayloadUUID" => "a017048f-684b-4e81-baa3-43afe316d739",
+ "PayloadVersion" => 1 }],
+ "ProfileOrganization" => "Chef",
+ "ProfileRemovalDisallowed" => "false",
+ "ProfileType" => "Configuration",
+ "ProfileUUID" => "e2e09bef-e673-44a6-bcbe-ecb5f1c1b740",
+ "ProfileVerificationState" => "unsigned",
+ "ProfileVersion" => 1 },
+ { "ProfileDisplayName" => "ScreenSaver Settings",
+ "ProfileIdentifier" => "com.testprofile.screensaver",
+ "ProfileInstallDate" => "2015-10-05 23:15:21 +0000",
+ "ProfileItems" => [{ "PayloadContent" => { "PayloadContentManagedPreferences" => { "com.apple.screensaver" => { "Forced" => [{ "mcx_preference_settings" => { "idleTime" => 0 } }] } } },
+ "PayloadDisplayName" => "Custom: (com.apple.screensaver)",
+ "PayloadIdentifier" => "com.apple.screensaver",
+ "PayloadType" => "com.apple.ManagedClient.preferences",
+ "PayloadUUID" => "73fc30e0-1e57-0131-c32d-000c2944c110",
+ "PayloadVersion" => 1 }],
+ "ProfileOrganization" => "Chef",
+ "ProfileRemovalDisallowed" => "false",
+ "ProfileType" => "Configuration",
+ "ProfileUUID" => "6e95927c-f200-54b4-85c7-52ab99b61c47",
+ "ProfileVerificationState" => "unsigned",
+ "ProfileVersion" => 1 }],
+ }
+ end
+ # If anything is changed within this profile, be sure to update the
+ # ProfileUUID in all_profiles to match the new config specific UUID
+ let(:test_profile) do
+ {
+ "PayloadIdentifier" => "com.testprofile.screensaver",
+ "PayloadRemovalDisallowed" => false,
+ "PayloadScope" => "System",
+ "PayloadType" => "Configuration",
+ "PayloadUUID" => "1781fbec-3325-565f-9022-8aa28135c3cc",
+ "PayloadOrganization" => "Chef",
+ "PayloadVersion" => 1,
+ "PayloadDisplayName" => "Screensaver Settings",
+ "PayloadContent" => [
+ {
+ "PayloadType" => "com.apple.ManagedClient.preferences",
+ "PayloadVersion" => 1,
+ "PayloadIdentifier" => "com.testprofile.screensaver",
+ "PayloadUUID" => "73fc30e0-1e57-0131-c32d-000c2944c108",
+ "PayloadEnabled" => true,
+ "PayloadDisplayName" => "com.apple.screensaver",
+ "PayloadContent" => {
+ "com.apple.screensaver" => {
+ "Forced" => [
+ {
+ "mcx_preference_settings" => {
+ "idleTime" => 0,
+ },
+ },
+ ],
+ },
+ },
+ },
+ ],
+ }
+ end
+ let(:no_profiles) do
+ {}
+ end
+
+ before(:each) do
+ allow(provider).to receive(:cookbook_file_available?).and_return(true)
+ allow(provider).to receive(:cache_cookbook_profile).and_return("/tmp/test.mobileconfig.remote")
+ allow(provider).to receive(:get_new_profile_hash).and_return(test_profile)
+ allow(provider).to receive(:get_installed_profiles).and_return(all_profiles)
+ allow(provider).to receive(:read_plist).and_return(all_profiles)
+ allow(::File).to receive(:unlink).and_return(true)
+ end
+
+ it "should build the get all profiles shellout command correctly" do
+ profile_name = "com.testprofile.screensaver.mobileconfig"
+ tempfile = "/tmp/allprofiles.plist"
+ new_resource.profile_name profile_name
+ allow(provider).to receive(:generate_tempfile).and_return(tempfile)
+ allow(provider).to receive(:get_installed_profiles).and_call_original
+ allow(provider).to receive(:read_plist).and_return(all_profiles)
+ expect(provider).to receive(:shell_out!).with("profiles -P -o '/tmp/allprofiles.plist'")
+ provider.load_current_resource
+ end
+
+ it "should use profile name as profile when no profile is set" do
+ profile_name = "com.testprofile.screensaver.mobileconfig"
+ new_resource.profile_name profile_name
+ provider.load_current_resource
+ expect(new_resource.profile_name).to eql(profile_name)
+ end
+
+ it "should use identifier from specified profile" do
+ new_resource.profile test_profile
+ provider.load_current_resource
+ expect(
+ provider.instance_variable_get(:@new_profile_identifier)
+ ).to eql(test_profile["PayloadIdentifier"])
+ end
+
+ it "should install when not installed" do
+ new_resource.profile test_profile
+ allow(provider).to receive(:get_installed_profiles).and_return(no_profiles)
+ provider.load_current_resource
+ expect { provider.run_action(:install) }.to_not raise_error
+ end
+
+ it "does not install if the profile is already installed" do
+ new_resource.profile test_profile
+ allow(provider).to receive(:get_installed_profiles).and_return(all_profiles)
+ provider.load_current_resource
+ expect(provider).to_not receive(:install_profile)
+ expect { provider.action_install }.to_not raise_error
+ end
+
+ it "should install when installed but uuid differs" do
+ new_resource.profile test_profile
+ all_profiles["_computerlevel"][1]["ProfileUUID"] = "1781fbec-3325-565f-9022-9bb39245d4dd"
+ provider.load_current_resource
+ expect { provider.run_action(:install) }.to_not raise_error
+ end
+
+ it "should build the shellout install command correctly" do
+ profile_path = "/tmp/test.mobileconfig"
+ new_resource.profile test_profile
+ # Change the profile so it triggers an install
+ all_profiles["_computerlevel"][1]["ProfileUUID"] = "1781fbec-3325-565f-9022-9bb39245d4dd"
+ provider.load_current_resource
+ allow(provider).to receive(:write_profile_to_disk).and_return(profile_path)
+ expect(provider).to receive(:shell_out).with("profiles -I -F '#{profile_path}'").and_return(shell_out_success)
+ provider.action_install()
+ end
+
+ it "should fail if there is no identifier inside the profile" do
+ test_profile.delete("PayloadIdentifier")
+ new_resource.profile test_profile
+ error_message = "The specified profile does not seem to be valid"
+ expect { provider.run_action(:install) }.to raise_error(RuntimeError, error_message)
+ end
+
+ end
+
+ describe "action_remove" do
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:new_resource) { Chef::Resource::OsxProfile.new("Profile Test", run_context) }
+ let(:provider) { Chef::Provider::OsxProfile.new(new_resource, run_context) }
+ let(:current_resource) { Chef::Resource::OsxProfile.new("Profile Test") }
+ let(:all_profiles) do
+ { "_computerlevel" => [{ "ProfileDisplayName" => "ScreenSaver Settings",
+ "ProfileIdentifier" => "com.apple.screensaver",
+ "ProfileInstallDate" => "2015-10-05 23:15:21 +0000",
+ "ProfileItems" => [{ "PayloadContent" => { "PayloadContentManagedPreferences" => { "com.apple.screensaver" => { "Forced" => [{ "mcx_preference_settings" => { "idleTime" => 0 } }] } } },
+ "PayloadDisplayName" => "Custom: (com.apple.screensaver)",
+ "PayloadIdentifier" => "com.apple.screensaver",
+ "PayloadType" => "com.apple.ManagedClient.preferences",
+ "PayloadUUID" => "73fc30e0-1e57-0131-c32d-000c2944c108",
+ "PayloadVersion" => 1 }],
+ "ProfileOrganization" => "Chef",
+ "ProfileRemovalDisallowed" => "false",
+ "ProfileType" => "Configuration",
+ "ProfileUUID" => "1781fbec-3325-565f-9022-8aa28135c3cc",
+ "ProfileVerificationState" => "unsigned",
+ "ProfileVersion" => 1 },
+ { "ProfileDisplayName" => "ScreenSaver Settings",
+ "ProfileIdentifier" => "com.testprofile.screensaver",
+ "ProfileInstallDate" => "2015-10-05 23:15:21 +0000",
+ "ProfileItems" => [{ "PayloadContent" => { "PayloadContentManagedPreferences" => { "com.apple.screensaver" => { "Forced" => [{ "mcx_preference_settings" => { "idleTime" => 0 } }] } } },
+ "PayloadDisplayName" => "Custom: (com.apple.screensaver)",
+ "PayloadIdentifier" => "com.apple.screensaver",
+ "PayloadType" => "com.apple.ManagedClient.preferences",
+ "PayloadUUID" => "73fc30e0-1e57-0131-c32d-000c2944c110",
+ "PayloadVersion" => 1 }],
+ "ProfileOrganization" => "Chef",
+ "ProfileRemovalDisallowed" => "false",
+ "ProfileType" => "Configuration",
+ "ProfileUUID" => "1781fbec-3325-565f-9022-8aa28135c3cc",
+ "ProfileVerificationState" => "unsigned",
+ "ProfileVersion" => 1 }],
+ }
+ end
+ before(:each) do
+ provider.current_resource = current_resource
+ allow(provider).to receive(:get_installed_profiles).and_return(all_profiles)
+ end
+
+ it "should use resource name for identifier when not specified" do
+ new_resource.profile_name "com.testprofile.screensaver"
+ new_resource.action(:remove)
+ provider.load_current_resource
+ expect(provider.instance_variable_get(:@new_profile_identifier)
+ ).to eql(new_resource.profile_name)
+ end
+
+ it "should use specified identifier" do
+ new_resource.identifier "com.testprofile.screensaver"
+ new_resource.action(:remove)
+ provider.load_current_resource
+ expect(provider.instance_variable_get(:@new_profile_identifier)
+ ).to eql(new_resource.identifier)
+ end
+
+ it "should work with spaces in the identifier" do
+ provider.action = :remove
+ provider.define_resource_requirements
+ expect { provider.process_resource_requirements }.not_to raise_error
+ end
+
+ it "should build the shellout remove command correctly" do
+ new_resource.identifier "com.testprofile.screensaver"
+ new_resource.action(:remove)
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out).with("profiles -R -p '#{new_resource.identifier}'").and_return(shell_out_success)
+ provider.action_remove()
+ end
+ end
+end
diff --git a/spec/unit/provider/package/aix_spec.rb b/spec/unit/provider/package/aix_spec.rb
index 13992cb8d1..3e3853af28 100644
--- a/spec/unit/provider/package/aix_spec.rb
+++ b/spec/unit/provider/package/aix_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Deepali Jagtap (deepali.jagtap@clogeny.com)
# Author:: Prabhu Das (prabhu.das@clogeny.com)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Package::Aix do
before(:each) do
@@ -28,36 +28,36 @@ describe Chef::Provider::Package::Aix do
@new_resource.source("/tmp/samba.base")
@provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context)
- allow(::File).to receive(:exists?).and_return(true)
+ allow(::File).to receive(:exist?).with(@new_resource.source).and_return(true)
end
describe "assessing the current package status" do
before do
- @bffinfo ="/usr/lib/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:
- /etc/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:"
+ @bffinfo = "/usr/lib/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:
+ /etc/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:"
- @empty_status = double("Status", :stdout => "", :exitstatus => 0)
+ @empty_status = double("Status", :stdout => "", :exitstatus => 0)
end
it "should create a current resource with the name of new_resource" do
status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
- expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
- expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
+ expect(@provider).to receive(:shell_out).with("installp", "-L", "-d", "/tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("lslpp", "-lcq", "samba.base", timeout: 900).and_return(@empty_status)
@provider.load_current_resource
expect(@provider.current_resource.name).to eq("samba.base")
end
it "should set the current resource bff package name to the new resource bff package name" do
status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
- expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
- expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
+ expect(@provider).to receive(:shell_out).with("installp", "-L", "-d", "/tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("lslpp", "-lcq", "samba.base", timeout: 900).and_return(@empty_status)
@provider.load_current_resource
expect(@provider.current_resource.package_name).to eq("samba.base")
end
it "should raise an exception if a source is supplied but not found" do
allow(@provider).to receive(:shell_out).and_return(@empty_status)
- allow(::File).to receive(:exists?).and_return(false)
+ allow(::File).to receive(:exist?).with(@new_resource.source).and_return(false)
@provider.load_current_resource
@provider.define_resource_requirements
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Package)
@@ -65,8 +65,21 @@ describe Chef::Provider::Package::Aix do
it "should get the source package version from lslpp if provided" do
status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
- expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
- expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
+ expect(@provider).to receive(:shell_out).with("installp", "-L", "-d", "/tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("lslpp", "-lcq", "samba.base", timeout: 900).and_return(@empty_status)
+ @provider.load_current_resource
+
+ expect(@provider.current_resource.package_name).to eq("samba.base")
+ expect(@new_resource.version).to eq("3.3.12.0")
+ end
+
+ it "should warn if the package is not a fileset" do
+ info = "samba.base:samba.base.samples:3.3.12.0::COMMITTED:I:Samba for AIX:
+ /etc/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:"
+ status = double("Status", :stdout => info, :exitstatus => 0)
+ expect(@provider).to receive(:shell_out).with("installp", "-L", "-d", "/tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("lslpp", "-lcq", "samba.base", timeout: 900).and_return(@empty_status)
+ expect(Chef::Log).to receive(:warn).once.with(%r{bff package by product name})
@provider.load_current_resource
expect(@provider.current_resource.package_name).to eq("samba.base")
@@ -77,8 +90,8 @@ describe Chef::Provider::Package::Aix do
status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
@stdout = StringIO.new(@bffinfo)
@stdin, @stderr = StringIO.new, StringIO.new
- expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
- expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("installp", "-L", "-d", "/tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("lslpp", "-lcq", "samba.base", timeout: 900).and_return(status)
@provider.load_current_resource
expect(@provider.current_resource.version).to eq("3.3.12.0")
end
@@ -99,8 +112,8 @@ describe Chef::Provider::Package::Aix do
it "should return a current resource with a nil version if the package is not found" do
status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
- expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
- expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
+ expect(@provider).to receive(:shell_out).with("installp", "-L", "-d", "/tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("lslpp", "-lcq", "samba.base", timeout: 900).and_return(@empty_status)
@provider.load_current_resource
expect(@provider.current_resource.version).to be_nil
end
@@ -109,7 +122,7 @@ describe Chef::Provider::Package::Aix do
wrongbffinfo = "/usr/lib/objrepos:openssl.base:0.9.8.2400::COMMITTED:I:Open Secure Socket Layer:
/etc/objrepos:openssl.base:0.9.8.2400::COMMITTED:I:Open Secure Socket Layer:"
status = double("Status", :stdout => wrongbffinfo, :exitstatus => 0)
- expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("installp", "-L", "-d", "/tmp/samba.base", timeout: 900).and_return(status)
expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Package)
end
end
@@ -117,7 +130,7 @@ describe Chef::Provider::Package::Aix do
describe "candidate_version" do
it "should return the candidate_version variable if already setup" do
@provider.candidate_version = "3.3.12.0"
- expect(@provider).not_to receive(:shell_out )
+ expect(@provider).not_to receive(:shell_out)
@provider.candidate_version
end
@@ -137,34 +150,34 @@ describe Chef::Provider::Package::Aix do
describe "install and upgrade" do
it "should run installp -aYF -d with the package source to install" do
- expect(@provider).to receive(:shell_out!).with("installp -aYF -d /tmp/samba.base samba.base", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("installp", "-aYF", "-d", "/tmp/samba.base", "samba.base", timeout: 900)
@provider.install_package("samba.base", "3.3.12.0")
end
- it "should run when the package is a path to install" do
+ it "should run installp -aYF -d when the package is a path to install" do
@new_resource = Chef::Resource::Package.new("/tmp/samba.base")
@provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context)
expect(@new_resource.source).to eq("/tmp/samba.base")
- expect(@provider).to receive(:shell_out!).with("installp -aYF -d /tmp/samba.base /tmp/samba.base", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("installp", "-aYF", "-d", "/tmp/samba.base", "/tmp/samba.base", timeout: 900)
@provider.install_package("/tmp/samba.base", "3.3.12.0")
end
it "should run installp with -eLogfile option." do
allow(@new_resource).to receive(:options).and_return("-e/tmp/installp.log")
- expect(@provider).to receive(:shell_out!).with("installp -aYF -e/tmp/installp.log -d /tmp/samba.base samba.base", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("installp", "-aYF", "-e/tmp/installp.log", "-d", "/tmp/samba.base", "samba.base", timeout: 900)
@provider.install_package("samba.base", "3.3.12.0")
end
end
describe "remove" do
it "should run installp -u samba.base to remove the package" do
- expect(@provider).to receive(:shell_out!).with("installp -u samba.base", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("installp", "-u", "samba.base", timeout: 900)
@provider.remove_package("samba.base", "3.3.12.0")
end
it "should run installp -u -e/tmp/installp.log with options -e/tmp/installp.log" do
allow(@new_resource).to receive(:options).and_return("-e/tmp/installp.log")
- expect(@provider).to receive(:shell_out!).with("installp -u -e/tmp/installp.log samba.base", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("installp", "-u", "-e/tmp/installp.log", "samba.base", timeout: 900)
@provider.remove_package("samba.base", "3.3.12.0")
end
diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb
index 8528480689..a077b2a2a3 100644
--- a/spec/unit/provider/package/apt_spec.rb
+++ b/spec/unit/provider/package/apt_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Provider::Package::Apt do
# XXX: sorry this is ugly and was done quickly to get 12.0.2 out, this file needs a rewrite to use
@@ -34,7 +34,7 @@ describe Chef::Provider::Package::Apt do
@status = double("Status", :exitstatus => 0)
@provider = Chef::Provider::Package::Apt.new(@new_resource, @run_context)
@stdin = StringIO.new
- @stdout =<<-PKG_STATUS
+ @stdout = <<-PKG_STATUS
irssi:
Installed: (none)
Candidate: 0.8.14-1ubuntu4
@@ -43,7 +43,7 @@ irssi:
500 http://us.archive.ubuntu.com/ubuntu/ lucid/main Packages
PKG_STATUS
@stderr = ""
- @shell_out = OpenStruct.new(:stdout => @stdout,:stdin => @stdin,:stderr => @stderr,:status => @status,:exitstatus => 0)
+ @shell_out = OpenStruct.new(:stdout => @stdout, :stdin => @stdin, :stderr => @stderr, :status => @status, :exitstatus => 0)
@timeout = 900
end
@@ -51,7 +51,8 @@ irssi:
it "should create a current resource with the name of the new_resource" do
expect(@provider).to receive(:shell_out!).with(
- "apt-cache policy #{@new_resource.package_name}",
+ "apt-cache", "policy", @new_resource.package_name,
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
).and_return(@shell_out)
@provider.load_current_resource
@@ -60,7 +61,7 @@ irssi:
expect(current_resource).to be_a(Chef::Resource::Package)
expect(current_resource.name).to eq("irssi")
expect(current_resource.package_name).to eq("irssi")
- expect(current_resource.version).to be_nil
+ expect(current_resource.version).to eql([nil])
end
it "should set the installed version if package has one" do
@@ -78,26 +79,51 @@ sudo:
INSTALLED
expect(@provider).to receive(:shell_out!).and_return(@shell_out)
@provider.load_current_resource
- expect(@provider.current_resource.version).to eq("1.7.2p1-1ubuntu5.3")
- expect(@provider.candidate_version).to eql("1.7.2p1-1ubuntu5.3")
+ expect(@provider.current_resource.version).to eq(["1.7.2p1-1ubuntu5.3"])
+ expect(@provider.candidate_version).to eql(["1.7.2p1-1ubuntu5.3"])
+ end
+
+ # it is the superclasses responsibility to throw most exceptions
+ it "if the package does not exist in the cache sets installed + candidate version to nil" do
+ @new_resource.package_name("conic-smarms")
+ policy_out = <<-POLICY_STDOUT
+N: Unable to locate package conic-smarms
+ POLICY_STDOUT
+ policy = double(:stdout => policy_out, :exitstatus => 0)
+ expect(@provider).to receive(:shell_out!).with(
+ "apt-cache", "policy", "conic-smarms",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
+ :timeout => @timeout
+ ).and_return(policy)
+ showpkg_out = <<-SHOWPKG_STDOUT
+N: Unable to locate package conic-smarms
+ SHOWPKG_STDOUT
+ showpkg = double(:stdout => showpkg_out, :exitstatus => 0)
+ expect(@provider).to receive(:shell_out!).with(
+ "apt-cache", "showpkg", "conic-smarms",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
+ :timeout => @timeout
+ ).and_return(showpkg)
+ @provider.load_current_resource
end
# libmysqlclient-dev is a real package in newer versions of debian + ubuntu
# list of virtual packages: http://www.debian.org/doc/packaging-manuals/virtual-package-names-list.txt
it "should not install the virtual package there is a single provider package and it is installed" do
@new_resource.package_name("libmysqlclient15-dev")
- virtual_package_out=<<-VPKG_STDOUT
+ virtual_package_out = <<-VPKG_STDOUT
libmysqlclient15-dev:
Installed: (none)
Candidate: (none)
Version table:
VPKG_STDOUT
- virtual_package = double(:stdout => virtual_package_out,:exitstatus => 0)
+ virtual_package = double(:stdout => virtual_package_out, :exitstatus => 0)
expect(@provider).to receive(:shell_out!).with(
- "apt-cache policy libmysqlclient15-dev",
+ "apt-cache", "policy", "libmysqlclient15-dev",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
).and_return(virtual_package)
- showpkg_out =<<-SHOWPKG_STDOUT
+ showpkg_out = <<-SHOWPKG_STDOUT
Package: libmysqlclient15-dev
Versions:
@@ -115,12 +141,13 @@ libmysqlclient-dev 5.1.41-3ubuntu12.7
libmysqlclient-dev 5.1.41-3ubuntu12.10
libmysqlclient-dev 5.1.41-3ubuntu12
SHOWPKG_STDOUT
- showpkg = double(:stdout => showpkg_out,:exitstatus => 0)
+ showpkg = double(:stdout => showpkg_out, :exitstatus => 0)
expect(@provider).to receive(:shell_out!).with(
- "apt-cache showpkg libmysqlclient15-dev",
+ "apt-cache", "showpkg", "libmysqlclient15-dev",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
).and_return(showpkg)
- real_package_out=<<-RPKG_STDOUT
+ real_package_out = <<-RPKG_STDOUT
libmysqlclient-dev:
Installed: 5.1.41-3ubuntu12.10
Candidate: 5.1.41-3ubuntu12.10
@@ -133,9 +160,10 @@ libmysqlclient-dev:
5.1.41-3ubuntu12 0
500 http://us.archive.ubuntu.com/ubuntu/ lucid/main Packages
RPKG_STDOUT
- real_package = double(:stdout => real_package_out,:exitstatus => 0)
+ real_package = double(:stdout => real_package_out, :exitstatus => 0)
expect(@provider).to receive(:shell_out!).with(
- "apt-cache policy libmysqlclient-dev",
+ "apt-cache", "policy", "libmysqlclient-dev",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
).and_return(real_package)
@provider.load_current_resource
@@ -143,18 +171,19 @@ libmysqlclient-dev:
it "should raise an exception if you specify a virtual package with multiple provider packages" do
@new_resource.package_name("mp3-decoder")
- virtual_package_out=<<-VPKG_STDOUT
+ virtual_package_out = <<-VPKG_STDOUT
mp3-decoder:
Installed: (none)
Candidate: (none)
Version table:
VPKG_STDOUT
- virtual_package = double(:stdout => virtual_package_out,:exitstatus => 0)
+ virtual_package = double(:stdout => virtual_package_out, :exitstatus => 0)
expect(@provider).to receive(:shell_out!).with(
- "apt-cache policy mp3-decoder",
+ "apt-cache", "policy", "mp3-decoder",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
).and_return(virtual_package)
- showpkg_out=<<-SHOWPKG_STDOUT
+ showpkg_out = <<-SHOWPKG_STDOUT
Package: mp3-decoder
Versions:
@@ -175,9 +204,10 @@ opencubicplayer 1:0.1.17-2
mpg321 0.2.10.6
mpg123 1.12.1-0ubuntu1
SHOWPKG_STDOUT
- showpkg = double(:stdout => showpkg_out,:exitstatus => 0)
+ showpkg = double(:stdout => showpkg_out, :exitstatus => 0)
expect(@provider).to receive(:shell_out!).with(
- "apt-cache showpkg mp3-decoder",
+ "apt-cache", "showpkg", "mp3-decoder",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
).and_return(showpkg)
expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Package)
@@ -190,7 +220,8 @@ mpg123 1.12.1-0ubuntu1
allow(@new_resource).to receive(:default_release).and_return("lenny-backports")
allow(@new_resource).to receive(:provider).and_return(nil)
expect(@provider).to receive(:shell_out!).with(
- "apt-cache -o APT::Default-Release=lenny-backports policy irssi",
+ "apt-cache", "-o", "APT::Default-Release=lenny-backports", "policy", "irssi",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
).and_return(@shell_out)
@provider.load_current_resource
@@ -199,12 +230,10 @@ mpg123 1.12.1-0ubuntu1
it "raises an exception if a source is specified (CHEF-5113)" do
@new_resource.source "pluto"
expect(@provider).to receive(:shell_out!).with(
- "apt-cache policy #{@new_resource.package_name}",
+ "apt-cache", "policy", @new_resource.package_name,
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" } ,
:timeout => @timeout
).and_return(@shell_out)
- @provider.load_current_resource
- @provider.define_resource_requirements
- expect(@provider).to receive(:shell_out!).with("apt-cache policy irssi", {:timeout=>900}).and_return(@shell_out)
expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
end
end
@@ -213,26 +242,38 @@ mpg123 1.12.1-0ubuntu1
before do
@current_resource = resource_klass.new("irssi", @run_context)
@provider.current_resource = @current_resource
+ allow(@provider).to receive(:package_data).and_return({
+ "irssi" => {
+ virtual: false,
+ candidate_version: "0.8.12-7",
+ installed_version: nil,
+ },
+ "libmysqlclient15-dev" => {
+ virtual: true,
+ candidate_version: nil,
+ installed_version: nil,
+ },
+ })
end
describe "install_package" do
it "should run apt-get install with the package name and version" do
expect(@provider).to receive(:shell_out!). with(
- "apt-get -q -y install irssi=0.8.12-7",
- :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil},
+ "apt-get", "-q", "-y", "install", "irssi=0.8.12-7",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
)
- @provider.install_package("irssi", "0.8.12-7")
+ @provider.install_package(["irssi"], ["0.8.12-7"])
end
it "should run apt-get install with the package name and version and options if specified" do
expect(@provider).to receive(:shell_out!).with(
- "apt-get -q -y --force-yes install irssi=0.8.12-7",
- :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+ "apt-get", "-q", "-y", "--force-yes", "install", "irssi=0.8.12-7",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
)
@new_resource.options("--force-yes")
- @provider.install_package("irssi", "0.8.12-7")
+ @provider.install_package(["irssi"], ["0.8.12-7"])
end
it "should run apt-get install with the package name and version and default_release if there is one and provider is explicitly defined" do
@@ -243,20 +284,30 @@ mpg123 1.12.1-0ubuntu1
@provider.new_resource = @new_resource
expect(@provider).to receive(:shell_out!).with(
- "apt-get -q -y -o APT::Default-Release=lenny-backports install irssi=0.8.12-7",
- :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+ "apt-get", "-q", "-y", "-o", "APT::Default-Release=lenny-backports", "install", "irssi=0.8.12-7",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
)
- @provider.install_package("irssi", "0.8.12-7")
+ @provider.install_package(["irssi"], ["0.8.12-7"])
+ end
+
+ it "should run apt-get install with the package name and quotes options if specified" do
+ expect(@provider).to receive(:shell_out!).with(
+ "apt-get", "-q", "-y", "--force-yes", "-o", "Dpkg::Options::=--force-confdef", "-o", "Dpkg::Options::=--force-confnew", "install", "irssi=0.8.12-7",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
+ :timeout => @timeout
+ )
+ @new_resource.options('--force-yes -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew"')
+ @provider.install_package(["irssi"], ["0.8.12-7"])
end
end
describe resource_klass, "upgrade_package" do
it "should run install_package with the name and version" do
- expect(@provider).to receive(:install_package).with("irssi", "0.8.12-7")
- @provider.upgrade_package("irssi", "0.8.12-7")
+ expect(@provider).to receive(:install_package).with(["irssi"], ["0.8.12-7"])
+ @provider.upgrade_package(["irssi"], ["0.8.12-7"])
end
end
@@ -264,22 +315,22 @@ mpg123 1.12.1-0ubuntu1
it "should run apt-get remove with the package name" do
expect(@provider).to receive(:shell_out!).with(
- "apt-get -q -y remove irssi",
- :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil},
+ "apt-get", "-q", "-y", "remove", "irssi",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
)
- @provider.remove_package("irssi", "0.8.12-7")
+ @provider.remove_package(["irssi"], ["0.8.12-7"])
end
it "should run apt-get remove with the package name and options if specified" do
expect(@provider).to receive(:shell_out!).with(
- "apt-get -q -y --force-yes remove irssi",
- :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+ "apt-get", "-q", "-y", "--force-yes", "remove", "irssi",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
)
@new_resource.options("--force-yes")
- @provider.remove_package("irssi", "0.8.12-7")
+ @provider.remove_package(["irssi"], ["0.8.12-7"])
end
end
@@ -287,22 +338,22 @@ mpg123 1.12.1-0ubuntu1
it "should run apt-get purge with the package name" do
expect(@provider).to receive(:shell_out!).with(
- "apt-get -q -y purge irssi",
- :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+ "apt-get", "-q", "-y", "purge", "irssi",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
)
- @provider.purge_package("irssi", "0.8.12-7")
+ @provider.purge_package(["irssi"], ["0.8.12-7"])
end
it "should run apt-get purge with the package name and options if specified" do
expect(@provider).to receive(:shell_out!).with(
- "apt-get -q -y --force-yes purge irssi",
- :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+ "apt-get", "-q", "-y", "--force-yes", "purge", "irssi",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
)
@new_resource.options("--force-yes")
- @provider.purge_package("irssi", "0.8.12-7")
+ @provider.purge_package(["irssi"], ["0.8.12-7"])
end
end
@@ -315,8 +366,8 @@ mpg123 1.12.1-0ubuntu1
file = "/tmp/irssi-0.8.12-7.seed"
expect(@provider).to receive(:shell_out!).with(
- "debconf-set-selections /tmp/irssi-0.8.12-7.seed",
- :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil},
+ "debconf-set-selections", "/tmp/irssi-0.8.12-7.seed",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
)
@@ -325,8 +376,8 @@ mpg123 1.12.1-0ubuntu1
it "should run debconf-set-selections on the preseed file if it has changed" do
expect(@provider).to receive(:shell_out!).with(
- "debconf-set-selections /tmp/irssi-0.8.12-7.seed",
- :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil},
+ "debconf-set-selections", "/tmp/irssi-0.8.12-7.seed",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
)
file = @provider.get_preseed_file("irssi", "0.8.12-7")
@@ -346,37 +397,81 @@ mpg123 1.12.1-0ubuntu1
describe "when reconfiguring a package" do
it "should run dpkg-reconfigure package" do
expect(@provider).to receive(:shell_out!).with(
- "dpkg-reconfigure irssi",
- :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+ "dpkg-reconfigure", "irssi",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
)
@provider.reconfig_package("irssi", "0.8.12-7")
end
end
+ describe "when locking a package" do
+ it "should run apt-mark hold package" do
+ expect(@provider).to receive(:shell_out!).with(
+ "apt-mark", "hold", "irssi",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
+ :timeout => @timeout
+ )
+ @provider.lock_package("irssi", "0.8.12-7")
+ end
+ end
+
+ describe "when unlocking a package" do
+ it "should run apt-mark unhold package" do
+ expect(@provider).to receive(:shell_out!).with(
+ "apt-mark", "unhold", "irssi",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
+ :timeout => @timeout
+ )
+ @provider.unlock_package("irssi", "0.8.12-7")
+ end
+ end
+
describe "when installing a virtual package" do
it "should install the package without specifying a version" do
- @provider.is_virtual_package['libmysqlclient-dev'] = true
+ @provider.package_data["libmysqlclient15-dev"][:virtual] = true
+ expect(@provider).to receive(:shell_out!).with(
+ "apt-get", "-q", "-y", "install", "libmysqlclient15-dev",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
+ :timeout => @timeout
+ )
+ @provider.install_package(["libmysqlclient15-dev"], ["not_a_real_version"])
+ end
+ end
+
+ describe "when removing a virtual package" do
+ it "should remove the resolved name instead of the virtual package name" do
+ expect(@provider).to receive(:resolve_virtual_package_name).with("libmysqlclient15-dev").and_return("libmysqlclient-dev")
+ expect(@provider).to receive(:shell_out!).with(
+ "apt-get", "-q", "-y", "remove", "libmysqlclient-dev",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
+ :timeout => @timeout
+ )
+ @provider.remove_package(["libmysqlclient15-dev"], ["not_a_real_version"])
+ end
+ end
+
+ describe "when purging a virtual package" do
+ it "should purge the resolved name instead of the virtual package name" do
+ expect(@provider).to receive(:resolve_virtual_package_name).with("libmysqlclient15-dev").and_return("libmysqlclient-dev")
expect(@provider).to receive(:shell_out!).with(
- "apt-get -q -y install libmysqlclient-dev",
- :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+ "apt-get", "-q", "-y", "purge", "libmysqlclient-dev",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
)
- @provider.install_package("libmysqlclient-dev", "not_a_real_version")
+ @provider.purge_package(["libmysqlclient15-dev"], ["not_a_real_version"])
end
end
describe "when installing multiple packages" do
it "can install a virtual package followed by a non-virtual package" do
# https://github.com/chef/chef/issues/2914
- @provider.is_virtual_package['libmysqlclient-dev'] = true
- @provider.is_virtual_package['irssi'] = false
expect(@provider).to receive(:shell_out!).with(
- "apt-get -q -y install libmysqlclient-dev irssi=0.8.12-7",
- :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+ "apt-get", "-q", "-y", "install", "libmysqlclient15-dev", "irssi=0.8.12-7",
+ :env => { "DEBIAN_FRONTEND" => "noninteractive" },
:timeout => @timeout
)
- @provider.install_package(["libmysqlclient-dev", "irssi"], ["not_a_real_version", "0.8.12-7"])
+ @provider.install_package(["libmysqlclient15-dev", "irssi"], ["not_a_real_version", "0.8.12-7"])
end
end
diff --git a/spec/unit/provider/package/cab_spec.rb b/spec/unit/provider/package/cab_spec.rb
new file mode 100644
index 0000000000..5c86f781f3
--- /dev/null
+++ b/spec/unit/provider/package/cab_spec.rb
@@ -0,0 +1,272 @@
+#
+# Author:: Vasundhara Jagdale (<vasundhara.jagdale@msystechnologies.com>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::Package::Cab do
+ let(:timeout) {}
+
+ let(:new_resource) { Chef::Resource::CabPackage.new("windows_test_pkg") }
+
+ let(:provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::Package::Cab.new(new_resource, run_context)
+ end
+
+ let(:installed_package_list_stdout) do
+ <<-EOF
+Packages listing:
+Package Identity : Package_for_KB2999486~31bf3856ad364e35~amd64~~6.1.9768.0
+Package Identity : Package_for_KB2994825~31bf3856ad364e35~amd64~~6.1.7601.0
+ EOF
+ end
+
+ let(:package_version_stdout) do
+ <<-EOF
+Package information:
+Package Identity : Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0
+State : Installed
+Dependency : Language Pack
+The operation completed successfully
+ EOF
+ end
+
+ before do
+ new_resource.source = File.join("#{ENV['TEMP']}", "test6.1-kb2664825-v3-x64.cab")
+ installed_package_list_obj = double(stdout: installed_package_list_stdout)
+ allow(provider).to receive(:dism_command).with("/Get-Packages").and_return(installed_package_list_obj)
+ package_version_obj = double(stdout: package_version_stdout)
+ allow(provider).to receive(:dism_command).with("/Get-PackageInfo /PackagePath:\"#{new_resource.source}\"").and_return(package_version_obj)
+ end
+
+ def allow_package_info(package_path = nil, package_name = nil)
+ get_package_info_stdout = <<-EOF
+Deployment Image Servicing and Management tool
+Version: 6.1.7600.16385
+
+Image Version: 6.1.7600.16385
+
+Package information:
+Package Identity : Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0
+Applicable : Yes
+Copyright : Microsoft Corporation
+Company : Microsoft Corporation
+State : Installed
+Dependency : Language Pack
+The operation completed successfully
+ EOF
+ get_package_info_obj = double(stdout: get_package_info_stdout)
+ if package_path
+ allow(provider).to receive(:dism_command).with("/Get-PackageInfo /PackagePath:\"#{package_path}\"").and_return(get_package_info_obj)
+ else
+ allow(provider).to receive(:dism_command).with("/Get-PackageInfo /PackageName:\"#{package_name}\"").and_return(get_package_info_obj)
+ end
+ end
+
+ def allow_get_packages
+ get_packages_stdout = <<-EOF
+Deployment Image Servicing and Management tool
+Version: 6.1.7600.16385
+
+Image Version: 6.1.7600.16385
+
+Packages listing:
+
+Package Identity : Package_for_KB2999486~31bf3856ad364e35~amd64~~6.1.9768.0
+State : Installed
+Release Type : Language Pack
+Install Time : 2/11/2015 11:33 PM
+
+Package Identity : Package_for_KB2994825~31bf3856ad364e35~amd64~~6.1.7601.0
+State : Installed
+Release Type : Language Pack
+Install Time : 2/11/2015 11:33 PM
+
+Package Identity : Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0
+State : Installed
+Release Type : Feature Pack
+Install Time : 11/21/2010 3:40 AM
+
+The operation completed successfully.
+ EOF
+ get_packages_obj = double(stdout: get_packages_stdout)
+ allow(provider).to receive(:dism_command).with("/Get-Packages").and_return(get_packages_obj)
+ end
+
+ describe "#load_current_resource" do
+ it "returns a current_resource" do
+ expect(provider.load_current_resource).to be_kind_of(Chef::Resource::CabPackage)
+ end
+
+ it "sets the current_resource.version to nil when the package is not installed" do
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql(nil)
+ end
+
+ it "sets the new resource package version" do
+ provider.load_current_resource
+ expect(provider.new_resource.version).to eql("6.1.3.0")
+ end
+ end
+
+ describe "#source_resource" do
+ before do
+ new_resource.source = "https://www.something.com/Test6.1-KB2664825-v3-x64.cab"
+ new_resource.cookbook_name = "cab_package"
+ end
+
+ it "sets the desired parameters of downloades cab file" do
+ allow(provider).to receive(:default_download_cache_path).and_return("C:\\chef\\cache\\package")
+ source_resource = provider.source_resource
+ expect(source_resource.path).to be == "C:\\chef\\cache\\package"
+ expect(source_resource.name).to be == "windows_test_pkg"
+ expect(source_resource.source).to be == [new_resource.source]
+ expect(source_resource.cookbook_name).to be == "cab_package"
+ end
+ end
+
+ describe "#default_download_cache_path" do
+ before do
+ new_resource.source = "https://www.something.com/Test6.1-KB2664825-v3-x64.cab"
+ end
+
+ it "returns a clean cache path where the cab file is downloaded" do
+ allow(Chef::FileCache).to receive(:create_cache_path).and_return(ENV["TEMP"])
+ path = provider.default_download_cache_path
+ if windows?
+ expect(path).to be == File.join("#{ENV['TEMP']}", "\\", "Test6.1-KB2664825-v3-x64.cab")
+ else
+ expect(path).to be == File.join("#{ENV['TEMP']}", "Test6.1-KB2664825-v3-x64.cab")
+ end
+ end
+ end
+
+ describe "#cab_file_source" do
+ context "when local file path is set" do
+ it "returns local cab file source path" do
+ new_resource.source = File.join("#{ENV['TEMP']}", "test6.1-kb2664825-v3-x64.cab")
+ path = provider.cab_file_source
+ if windows?
+ expect(path).to be == File.join("#{ENV['TEMP'].downcase}", "\\", "test6.1-kb2664825-v3-x64.cab")
+ else
+ expect(path).to be == File.join("#{ENV['TEMP']}", "test6.1-kb2664825-v3-x64.cab")
+ end
+ end
+ end
+ context "when url is set" do
+ it "calls download_source_file method" do
+ new_resource.source = "https://www.something.com/test6.1-kb2664825-v3-x64.cab"
+ if windows?
+ expect(provider).to receive(:download_source_file).and_return(File.join("#{ENV['TEMP'].downcase}", "\\", "test6.1-kb2664825-v3-x64.cab"))
+ else
+ expect(provider).to receive(:download_source_file).and_return(File.join("#{ENV['TEMP']}", "test6.1-kb2664825-v3-x64.cab"))
+ end
+ provider.cab_file_source
+ end
+ end
+ end
+
+ describe "#initialize" do
+ it "returns the correct class" do
+ expect(provider).to be_kind_of(Chef::Provider::Package::Cab)
+ end
+ end
+
+ describe "#package_version" do
+ it "returns the new package version" do
+ allow_package_info(new_resource.source, nil)
+ expect(provider.package_version).to eql("6.1.3.0")
+ end
+ end
+
+ describe "#installed_version" do
+ it "returns the current installed version of package" do
+ allow_package_info(new_resource.source, nil)
+ allow_get_packages
+ allow_package_info(nil, "Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0")
+ expect(provider.installed_version).to eql("6.1.3.0")
+ end
+ end
+
+ describe "#action_remove" do
+ it "does nothing when the package is already removed" do
+ provider.load_current_resource
+ expect(provider).not_to receive(:remove_package)
+ provider.run_action(:remove)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "removes packages if package is installed" do
+ allow_package_info(new_resource.source, nil)
+ allow_get_packages
+ allow_package_info(nil, "Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0")
+ provider.load_current_resource
+ expect(provider.installed_version).not_to eql(nil)
+ expect(provider).to receive(:remove_package)
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated_by_last_action
+ end
+ end
+
+ describe "#action_install" do
+ it "installs package if already not installed" do
+ provider.load_current_resource
+ expect(provider.installed_version).to eql(nil)
+ expect(provider).to receive(:install_package)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "does not install package if already installed" do
+ allow_package_info(new_resource.source, nil)
+ allow_get_packages
+ allow_package_info(nil, "Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0")
+ provider.load_current_resource
+ expect(provider.installed_version).not_to eql(nil)
+ expect(provider).not_to receive(:install_package)
+ provider.run_action(:install)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+ end
+
+ context "Invalid package source" do
+ def package_version_stdout
+ package_version_stdout = <<-EOF
+Deployment Image Servicing and Management tool
+Version: 6.1.7600.16385
+Image Version: 6.1.7600.16385
+An error occurred trying to open - c:\\temp\\test6.1-KB2664825-v3-x64.cab Error: 0x80070003
+Error: 3
+The system cannot find the path specified.
+The DISM log file can be found at C:\\Windows\\Logs\\DISM\\dism.log.
+ EOF
+ end
+
+ before do
+ new_resource.source = "#{ENV['TEMP']}/test6.1-kb2664825-v3-x64.cab"
+ installed_package_list_obj = double(stdout: installed_package_list_stdout)
+ allow(provider).to receive(:dism_command).with("/Get-Packages").and_return(installed_package_list_obj)
+ end
+
+ it "raises error for invalid source path or file" do
+ expect { provider.load_current_resource }.to raise_error(Chef::Exceptions::Package, "DISM: The system cannot find the path or file specified.")
+ end
+ end
+end
diff --git a/spec/unit/provider/package/chocolatey_spec.rb b/spec/unit/provider/package/chocolatey_spec.rb
new file mode 100644
index 0000000000..68b121960c
--- /dev/null
+++ b/spec/unit/provider/package/chocolatey_spec.rb
@@ -0,0 +1,489 @@
+#
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::Package::Chocolatey do
+ let(:timeout) { 900 }
+
+ let(:new_resource) { Chef::Resource::ChocolateyPackage.new("git") }
+
+ let(:provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::Package::Chocolatey.new(new_resource, run_context)
+ end
+
+ let(:choco_install_path) { "C:\\ProgramData\\chocolatey" }
+ let(:choco_exe) { "#{choco_install_path}\\bin\\choco.exe" }
+
+ # installed packages (ConEmu is upgradable)
+ let(:local_list_stdout) do
+ <<-EOF
+Chocolatey v0.9.9.11
+chocolatey|0.9.9.11
+ConEmu|15.10.25.0
+ EOF
+ end
+
+ before do
+ allow(provider).to receive(:choco_install_path).and_return(choco_install_path)
+ allow(provider).to receive(:choco_exe).and_return(choco_exe)
+ local_list_obj = double(:stdout => local_list_stdout)
+ allow(provider).to receive(:shell_out!).with("#{choco_exe} list -l -r", { :returns => [0], :timeout => timeout }).and_return(local_list_obj)
+ end
+
+ def allow_remote_list(package_names, args = nil)
+ remote_list_stdout = <<-EOF
+Chocolatey v0.9.9.11
+chocolatey|0.9.9.11
+ConEmu|15.10.25.1
+Git|2.6.1
+Git|2.6.2
+munin-node|1.6.1.20130823
+ EOF
+ remote_list_obj = double(stdout: remote_list_stdout)
+ allow(provider).to receive(:shell_out!).with("#{choco_exe} list -r #{package_names.join ' '}#{args}", { :returns => [0], timeout: timeout }).and_return(remote_list_obj)
+ end
+
+ describe "#initialize" do
+ it "should return the correct class" do
+ expect(provider).to be_kind_of(Chef::Provider::Package::Chocolatey)
+ end
+
+ it "should support arrays" do
+ expect(provider.use_multipackage_api?).to be true
+ end
+ end
+
+ describe "#candidate_version" do
+ it "should set the candidate_version to the latest version when not pinning" do
+ allow_remote_list(["git"])
+ expect(provider.candidate_version).to eql(["2.6.2"])
+ end
+
+ it "should set the candidate_version to pinned version if available" do
+ allow_remote_list(["git"])
+ new_resource.version("2.6.1")
+ expect(provider.candidate_version).to eql(["2.6.1"])
+ end
+
+ it "should set the candidate_version to nil if there is no candidate" do
+ allow_remote_list(["vim"])
+ new_resource.package_name("vim")
+ expect(provider.candidate_version).to eql([nil])
+ end
+
+ it "should set the candidate_version correctly when there are two packages to install" do
+ allow_remote_list(%w{ConEmu chocolatey})
+ new_resource.package_name(%w{ConEmu chocolatey})
+ expect(provider.candidate_version).to eql(["15.10.25.1", "0.9.9.11"])
+ end
+
+ it "should set the candidate_version correctly when only the first is installable" do
+ allow_remote_list(%w{ConEmu vim})
+ new_resource.package_name(%w{ConEmu vim})
+ expect(provider.candidate_version).to eql(["15.10.25.1", nil])
+ end
+
+ it "should set the candidate_version correctly when only the last is installable" do
+ allow_remote_list(%w{vim chocolatey})
+ new_resource.package_name(%w{vim chocolatey})
+ expect(provider.candidate_version).to eql([nil, "0.9.9.11"])
+ end
+
+ it "should set the candidate_version correctly when neither are is installable" do
+ allow_remote_list(%w{vim ruby})
+ new_resource.package_name(%w{vim ruby})
+ expect(provider.candidate_version).to eql([nil, nil])
+ end
+ end
+
+ describe "#load_current_resource" do
+ it "should return a current_resource" do
+ expect(provider.load_current_resource).to be_kind_of(Chef::Resource::ChocolateyPackage)
+ end
+
+ it "should set the current_resource#package_name" do
+ provider.load_current_resource
+ expect(provider.current_resource.package_name).to eql(["git"])
+ end
+
+ it "should load and downcase names in the installed_packages hash" do
+ provider.load_current_resource
+ expect(provider.send(:installed_packages)).to eql(
+ { "chocolatey" => "0.9.9.11", "conemu" => "15.10.25.0" }
+ )
+ end
+
+ it "should load and downcase names in the available_packages hash" do
+ allow_remote_list(["git"])
+ provider.load_current_resource
+ expect(provider.send(:available_packages)).to eql(
+ { "chocolatey" => "0.9.9.11", "conemu" => "15.10.25.1", "git" => "2.6.2", "munin-node" => "1.6.1.20130823" }
+ )
+ end
+
+ it "should set the current_resource.version to nil when the package is not installed" do
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql([nil])
+ end
+
+ it "should set the current_resource.version to the installed version when the package is installed" do
+ new_resource.package_name("ConEmu")
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql(["15.10.25.0"])
+ end
+
+ it "should set the current_resource.version when there are two packages that are installed" do
+ new_resource.package_name(%w{ConEmu chocolatey})
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql(["15.10.25.0", "0.9.9.11"])
+ end
+
+ it "should set the current_resource.version correctly when only the first is installed" do
+ new_resource.package_name(%w{ConEmu git})
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql(["15.10.25.0", nil])
+ end
+
+ it "should set the current_resource.version correctly when only the last is installed" do
+ new_resource.package_name(%w{git chocolatey})
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql([nil, "0.9.9.11"])
+ end
+
+ it "should set the current_resource.version correctly when none are installed" do
+ new_resource.package_name(%w{git vim})
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql([nil, nil])
+ end
+ end
+
+ describe "#action_install" do
+ it "should install a single package" do
+ allow_remote_list(["git"])
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ context "when changing the timeout to 3600" do
+ let(:timeout) { 3600 }
+ it "sets the timeout on shell_out commands" do
+ allow_remote_list(["git"])
+ new_resource.timeout(timeout)
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+ end
+
+ it "should not install packages that are up-to-date" do
+ allow_remote_list(["chocolatey"])
+ new_resource.package_name("chocolatey")
+ provider.load_current_resource
+ expect(provider).not_to receive(:install_package)
+ provider.run_action(:install)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "should not upgrade packages" do
+ allow_remote_list(["ConEmu"])
+ new_resource.package_name("ConEmu")
+ provider.load_current_resource
+ expect(provider).not_to receive(:install_package)
+ provider.run_action(:install)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "should upgrade packages when given a version pin" do
+ allow_remote_list(["ConEmu"])
+ new_resource.package_name("ConEmu")
+ new_resource.version("15.10.25.1")
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y --version 15.10.25.1 conemu", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "should handle complicated cases when the name/version array is pruned" do
+ # chocolatey will be pruned by the superclass out of the args to install_package and we
+ # implicitly test that we correctly pick up new_resource.version[1] instead of
+ # new_version.resource[0]
+ allow_remote_list(%w{chocolatey ConEmu})
+ new_resource.package_name(%w{chocolatey ConEmu})
+ new_resource.version([nil, "15.10.25.1"])
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y --version 15.10.25.1 conemu", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "should be case-insensitive" do
+ allow_remote_list(["conemu"])
+ new_resource.package_name("conemu")
+ new_resource.version("15.10.25.1")
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y --version 15.10.25.1 conemu", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "should split up commands when given two packages, one with a version pin" do
+ allow_remote_list(%w{ConEmu git})
+ new_resource.package_name(%w{ConEmu git})
+ new_resource.version(["15.10.25.1", nil])
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y --version 15.10.25.1 conemu", { :returns => [0], :timeout => timeout }).and_return(double)
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "should do multipackage installs when given two packages without constraints" do
+ allow_remote_list(["git", "munin-node"])
+ new_resource.package_name(["git", "munin-node"])
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git munin-node", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ context "when passing a source argument" do
+ it "should pass options into the install command" do
+ allow_remote_list(["git"], " -source localpackages")
+ new_resource.source("localpackages")
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y -source localpackages git", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+ end
+
+ it "should pass options into the install command" do
+ allow_remote_list(["git"])
+ new_resource.options("-force")
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y -force git", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "installing a package that does not exist throws an error" do
+ allow_remote_list(["package-does-not-exist"])
+ new_resource.package_name("package-does-not-exist")
+ provider.load_current_resource
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ it "installing multiple packages with a package that does not exist throws an error" do
+ allow_remote_list(["git", "package-does-not-exist"])
+ new_resource.package_name(["git", "package-does-not-exist"])
+ provider.load_current_resource
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ context "alternate source" do
+ it "installing a package that does not exist throws an error" do
+ allow_remote_list(["package-does-not-exist"], " -source alternate_source")
+ new_resource.package_name("package-does-not-exist")
+ new_resource.source("alternate_source")
+ provider.load_current_resource
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ end
+ end
+ end
+
+ describe "#action_upgrade" do
+ it "should install a package that is not installed" do
+ allow_remote_list(["git"])
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y git", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "should upgrade a package that is installed but upgradable" do
+ allow_remote_list(["ConEmu"])
+ new_resource.package_name("ConEmu")
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y conemu", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "should be case insensitive" do
+ allow_remote_list(["conemu"])
+ new_resource.package_name("conemu")
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y conemu", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "should not install a package that is up-to-date" do
+ allow_remote_list(["chocolatey"])
+ new_resource.package_name("chocolatey")
+ provider.load_current_resource
+ expect(provider).not_to receive(:shell_out!).with("#{choco_exe} upgrade -y chocolatey", { :returns => [0], :timeout => timeout })
+ provider.run_action(:upgrade)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "version pins work as well" do
+ allow_remote_list(["git"])
+ new_resource.version("2.6.2")
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y --version 2.6.2 git", { :returns => [0], :timeout => timeout })
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "upgrading multiple packages uses a single command" do
+ allow_remote_list(%w{conemu git})
+ new_resource.package_name(%w{conemu git})
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y conemu git", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "upgrading a package that does not exist throws an error" do
+ allow_remote_list(["package-does-not-exist"])
+ new_resource.package_name("package-does-not-exist")
+ provider.load_current_resource
+ expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ it "upgrading multiple packages with a package that does not exist throws an error" do
+ allow_remote_list(["git", "package-does-not-exist"])
+ new_resource.package_name(["git", "package-does-not-exist"])
+ provider.load_current_resource
+ expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ context "alternate source" do
+ it "installing a package that does not exist throws an error" do
+ allow_remote_list(["package-does-not-exist"], " -source alternate_source")
+ new_resource.package_name("package-does-not-exist")
+ new_resource.source("alternate_source")
+ provider.load_current_resource
+ expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+ end
+ end
+ end
+
+ describe "#action_remove" do
+ it "does nothing when the package is already removed" do
+ allow_remote_list(["git"])
+ provider.load_current_resource
+ expect(provider).not_to receive(:remove_package)
+ provider.run_action(:remove)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "does nothing when all the packages are already removed" do
+ allow_remote_list(["git", "package-does-not-exist"])
+ new_resource.package_name(["git", "package-does-not-exist"])
+ provider.load_current_resource
+ expect(provider).not_to receive(:remove_package)
+ provider.run_action(:remove)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "removes a package" do
+ allow_remote_list(["ConEmu"])
+ new_resource.package_name("ConEmu")
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} uninstall -y ConEmu", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "is case-insensitive" do
+ allow_remote_list(["conemu"])
+ new_resource.package_name("conemu")
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} uninstall -y conemu", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "removes a single package when its the only one installed" do
+ pending "this is a bug in the superclass"
+ allow_remote_list(%w{git conemu})
+ new_resource.package_name(%w{git conemu})
+ provider.load_current_resource
+ expect(provider).to receive(:shell_out!).with("#{choco_exe} uninstall -y conemu", { :returns => [0], :timeout => timeout }).and_return(double)
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated_by_last_action
+ end
+ end
+
+ describe "#action_uninstall" do
+ it "should call :remove with a deprecation warning" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(Chef::Log).to receive(:deprecation).with(/please use :remove/)
+ allow_remote_list(["ConEmu"])
+ new_resource.package_name("ConEmu")
+ provider.load_current_resource
+ expect(provider).to receive(:remove_package)
+ provider.run_action(:uninstall)
+ expect(new_resource).to be_updated_by_last_action
+ end
+ end
+end
+
+describe "behavior when Chocolatey is not installed" do
+ let(:new_resource) { Chef::Resource::ChocolateyPackage.new("git") }
+
+ let(:provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::Package::Chocolatey.new(new_resource, run_context)
+ end
+
+ before do
+ # the shellout sometimes returns "", but test nil to be safe.
+ allow(provider).to receive(:choco_install_path).and_return(nil)
+ provider.instance_variable_set("@choco_install_path", nil)
+
+ # we don't care what this returns, but we have to let it be called.
+ allow(provider).to receive(:shell_out!).and_return(double(:stdout => ""))
+ end
+
+ let(:error_regex) do
+ /Could not locate.*install.*cookbook.*PowerShell.*GetEnvironmentVariable/m
+ end
+
+ context "#choco_exe" do
+ it "triggers a MissingLibrary exception when Chocolatey is not installed" do
+ expect { provider.send(:choco_exe) }.to raise_error(Chef::Exceptions::MissingLibrary, error_regex)
+ end
+ end
+
+ context "#load_current_resource" do
+ it "triggers a MissingLibrary exception when Chocolatey is not installed" do
+ expect { provider.load_current_resource }.to raise_error(Chef::Exceptions::MissingLibrary, error_regex)
+ end
+ end
+end
diff --git a/spec/unit/provider/package/dnf/python_helper_spec.rb b/spec/unit/provider/package/dnf/python_helper_spec.rb
new file mode 100644
index 0000000000..505217bf90
--- /dev/null
+++ b/spec/unit/provider/package/dnf/python_helper_spec.rb
@@ -0,0 +1,29 @@
+#
+# Copyright:: Copyright 2017-2017, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+# NOTE: most of the tests of this functionality are baked into the func tests for the dnf package provider
+
+describe Chef::Provider::Package::Dnf::PythonHelper do
+ let(:helper) { Chef::Provider::Package::Dnf::PythonHelper.instance }
+
+ it "propagates stacktraces on stderr from the forked subprocess" do
+ allow(helper).to receive(:dnf_command).and_return("ruby -e 'raise \"your hands in the air\"'")
+ expect { helper.query(:whatprovides, "tcpdump") }.to raise_error(/your hands in the air/)
+ end
+end
diff --git a/spec/unit/provider/package/dpkg_spec.rb b/spec/unit/provider/package/dpkg_spec.rb
index b868128147..e01e1d9cce 100644
--- a/spec/unit/provider/package/dpkg_spec.rb
+++ b/spec/unit/provider/package/dpkg_spec.rb
@@ -1,6 +1,5 @@
-#
# Author:: Bryan McLellan (btm@loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,187 +15,273 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Package::Dpkg do
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:package) { "wget" }
+ let(:source) { "/tmp/wget_1.11.4-1ubuntu1_amd64.deb" }
+ let(:new_resource) do
+ new_resource = Chef::Resource::DpkgPackage.new(package)
+ new_resource.source source
+ new_resource
+ end
+ let(:provider) { Chef::Provider::Package::Dpkg.new(new_resource, run_context) }
+
+ let(:dpkg_deb_version) { "1.11.4" }
+ let(:dpkg_deb_status) { status = double(:stdout => "#{package}\t#{dpkg_deb_version}", :exitstatus => 0) }
+ let(:dpkg_s_version) { "1.11.4-1ubuntu1" }
+ let(:dpkg_s_status) do
+ stdout = <<-DPKG_S
+Package: #{package}
+Status: install ok installed
+Priority: important
+Section: web
+Installed-Size: 1944
+Maintainer: Ubuntu Core developers <ubuntu-devel-discuss@lists.ubuntu.com>
+Architecture: amd64
+Version: #{dpkg_s_version}
+Config-Version: #{dpkg_s_version}
+Depends: libc6 (>= 2.8~20080505), libssl0.9.8 (>= 0.9.8f-5)
+Conflicts: wget-ssl
+ DPKG_S
+ status = double(:stdout => stdout, :exitstatus => 1)
+ end
+
before(:each) do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Package.new("wget")
- @new_resource.source "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+ allow(provider).to receive(:shell_out!).with("dpkg-deb", "-W", source, timeout: 900).and_return(dpkg_deb_status)
+ allow(provider).to receive(:shell_out!).with("dpkg", "-s", package, timeout: 900, returns: [0, 1]).and_return(double(stdout: "", exitstatus: 1))
+ allow(::File).to receive(:exist?).with(source).and_return(true)
+ end
- @provider = Chef::Provider::Package::Dpkg.new(@new_resource, @run_context)
+ describe "#define_resource_requirements" do
+ it "should raise an exception if a source is supplied but not found when :install" do
+ allow(::File).to receive(:exist?).with(source).and_return(false)
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ it "should raise an exception if a source is supplied but not found when :upgrade" do
+ allow(::File).to receive(:exist?).with(source).and_return(false)
+ expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ # FIXME? we're saying we ignore source, but should supplying source on :remove or :purge be an actual error?
+ it "should not raise an exception if a source is supplied but not found when :remove" do
+ allow(::File).to receive(:exist?).with(source).and_return(false)
+ expect(provider).to receive(:action_remove)
+ expect { provider.run_action(:remove) }.not_to raise_error
+ end
+
+ it "should not raise an exception if a source is supplied but not found when :purge" do
+ allow(::File).to receive(:exist?).with(source).and_return(false)
+ expect(provider).to receive(:action_purge)
+ expect { provider.run_action(:purge) }.not_to raise_error
+ end
- @status = double(:stdout => "", :exitstatus => 0)
- allow(@provider).to receive(:shell_out).and_return(@status)
+ context "when source is nil" do
+ let(:source) { nil }
- allow(::File).to receive(:exists?).and_return(true)
+ it "should raise an exception if a source is nil when :install" do
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ it "should raise an exception if a source is nil when :upgrade" do
+ expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ it "should not raise an exception if a source is nil when :remove" do
+ expect(provider).to receive(:action_remove)
+ expect { provider.run_action(:remove) }.not_to raise_error
+ end
+
+ it "should not raise an exception if a source is nil when :purge" do
+ expect(provider).to receive(:action_purge)
+ expect { provider.run_action(:purge) }.not_to raise_error
+ end
+ end
end
describe "when loading the current resource state" do
it "should create a current resource with the name of the new_resource" do
- @provider.load_current_resource
- expect(@provider.current_resource.package_name).to eq("wget")
- end
-
- it "should raise an exception if a source is supplied but not found" do
- @provider.load_current_resource
- @provider.define_resource_requirements
- allow(::File).to receive(:exists?).and_return(false)
- expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ provider.load_current_resource
+ expect(provider.current_resource.package_name).to eq(["wget"])
end
- describe 'gets the source package version from dpkg-deb' do
+ describe "gets the source package version from dpkg-deb" do
def check_version(version)
- @status = double(:stdout => "wget\t#{version}", :exitstatus => 0)
- allow(@provider).to receive(:shell_out).with("dpkg-deb -W #{@new_resource.source}", timeout: 900).and_return(@status)
- @provider.load_current_resource
- expect(@provider.current_resource.package_name).to eq("wget")
- expect(@provider.candidate_version).to eq(version)
+ status = double(:stdout => "wget\t#{version}", :exitstatus => 0)
+ expect(provider).to receive(:shell_out!).with("dpkg-deb", "-W", source, timeout: 900).and_return(status)
+ provider.load_current_resource
+ expect(provider.current_resource.package_name).to eq(["wget"])
+ expect(provider.candidate_version).to eq([version])
end
- it 'if short version provided' do
- check_version('1.11.4')
+ it "if short version provided" do
+ check_version("1.11.4")
end
- it 'if extended version provided' do
- check_version('1.11.4-1ubuntu1')
+ it "if extended version provided" do
+ check_version("1.11.4-1ubuntu1")
end
- it 'if distro-specific version provided' do
- check_version('1.11.4-1ubuntu1~lucid')
+ it "if distro-specific version provided" do
+ check_version("1.11.4-1ubuntu1~lucid")
end
- it 'returns the version if an epoch is used' do
- check_version('1:1.8.3-2')
+ it "returns the version if an epoch is used" do
+ check_version("1:1.8.3-2")
end
end
- it "gets the source package name from dpkg-deb correctly when the package name has `-', `+' or `.' characters" do
- stdout = "f.o.o-pkg++2\t1.11.4-1ubuntu1"
- status = double(:stdout => stdout, :exitstatus => 1)
- allow(@provider).to receive(:shell_out).and_return(status)
- @provider.load_current_resource
- expect(@provider.current_resource.package_name).to eq("f.o.o-pkg++2")
+ describe "when the package name has `-', `+' or `.' characters" do
+ let(:package) { "f.o.o-pkg++2" }
+
+ it "gets the source package name from dpkg-deb correctly" do
+ provider.load_current_resource
+ expect(provider.current_resource.package_name).to eq(["f.o.o-pkg++2"])
+ end
end
- it "gets the source package version from dpkg-deb correctly when the package version has `~', `-', `+' or `.' characters" do
- stdout = "b.a.r-pkg++1\t1.2.3+3141592-1ubuntu1~lucid"
- status = double(:stdout => stdout, :exitstatus => 1)
- allow(@provider).to receive(:shell_out).and_return(status)
- @provider.load_current_resource
- expect(@provider.candidate_version).to eq('1.2.3+3141592-1ubuntu1~lucid')
+ describe "when the package version has `~', `-', `+' or `.' characters" do
+ let(:package) { "b.a.r-pkg++1" }
+ let(:dpkg_deb_version) { "1.2.3+3141592-1ubuntu1~lucid" }
+ let(:dpkg_s_version) { "1.2.3+3141592-1ubuntu1~lucid" }
+
+ it "gets the source package version from dpkg-deb correctly when the package version has `~', `-', `+' or `.' characters" do
+ provider.load_current_resource
+ expect(provider.candidate_version).to eq(["1.2.3+3141592-1ubuntu1~lucid"])
+ end
end
- it "should raise an exception if the source is not set but we are installing" do
- @new_resource = Chef::Resource::Package.new("wget")
- @provider.new_resource = @new_resource
- @provider.load_current_resource
- @provider.define_resource_requirements
- expect { @provider.run_action(:install)}.to raise_error(Chef::Exceptions::Package)
+ describe "when the source is not set" do
+ let(:source) { nil }
+
+ it "should raise an exception if the source is not set but we are installing" do
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ end
end
it "should return the current version installed if found by dpkg" do
- stdout = <<-DPKG_S
-Package: wget
-Status: install ok installed
-Priority: important
-Section: web
-Installed-Size: 1944
-Maintainer: Ubuntu Core developers <ubuntu-devel-discuss@lists.ubuntu.com>
-Architecture: amd64
-Version: 1.11.4-1ubuntu1
-Config-Version: 1.11.4-1ubuntu1
-Depends: libc6 (>= 2.8~20080505), libssl0.9.8 (>= 0.9.8f-5)
-Conflicts: wget-ssl
-DPKG_S
- status = double(:stdout => stdout, :exitstatus => 1)
- allow(@provider).to receive(:shell_out).with("dpkg -s wget", timeout: 900).and_return(status)
+ allow(provider).to receive(:shell_out!).with("dpkg", "-s", package, timeout: 900, returns: [0, 1]).and_return(dpkg_s_status)
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eq(["1.11.4-1ubuntu1"])
+ end
- @provider.load_current_resource
- expect(@provider.current_resource.version).to eq("1.11.4-1ubuntu1")
+ it "on new debian/ubuntu we get an exit(1) and no stdout from dpkg -s for uninstalled" do
+ dpkg_s_status = double(
+ exitstatus: 1, stdout: "", stderr: <<-EOF
+dpkg-query: package '#{package}' is not installed and no information is available
+Use dpkg --info (= dpkg-deb --info) to examine archive files,
+and dpkg --contents (= dpkg-deb --contents) to list their contents.
+ EOF
+ )
+ expect(provider).to receive(:shell_out!).with("dpkg", "-s", package, returns: [0, 1], timeout: 900).and_return(dpkg_s_status)
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eq([nil])
end
- it "should raise an exception if dpkg fails to run" do
+ it "on old debian/ubuntu we get an exit(0) and we get info on stdout from dpkg -s for uninstalled" do
+ dpkg_s_status = double(
+ exitstatus: 0, stderr: "", stdout: <<-EOF
+Package: #{package}
+Status: unknown ok not-installed
+Priority: extra
+Section: ruby
+ EOF
+ )
+ expect(provider).to receive(:shell_out!).with("dpkg", "-s", package, returns: [0, 1], timeout: 900).and_return(dpkg_s_status)
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eq([nil])
+ end
+
+ it "and we should raise if we get any other exit codes from dpkg -s" do
+ dpkg_s_status = double(
+ exitstatus: 3, stderr: "i am very, very angry with you. i'm very, very cross. go to your room.", stdout: ""
+ )
+ expect(provider).to receive(:shell_out!).with("dpkg", "-s", package, returns: [0, 1], timeout: 900).and_raise(Mixlib::ShellOut::ShellCommandFailed)
+ expect { provider.load_current_resource }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
+ end
+
+ it "should raise an exception if dpkg-deb -W fails to run" do
status = double(:stdout => "", :exitstatus => -1)
- allow(@provider).to receive(:shell_out).and_return(status)
- expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Package)
+ expect(provider).to receive(:shell_out_compact_timeout!).with("dpkg-deb", "-W", "/tmp/wget_1.11.4-1ubuntu1_amd64.deb").and_raise(Mixlib::ShellOut::ShellCommandFailed)
+ expect { provider.load_current_resource }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
end
end
describe Chef::Provider::Package::Dpkg, "install and upgrade" do
it "should run dpkg -i with the package source" do
- expect(@provider).to receive(:run_noninteractive).with(
- "dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+ expect(provider).to receive(:run_noninteractive).with(
+ "dpkg", "-i", "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
)
- @provider.install_package("wget", "1.11.4-1ubuntu1")
+ provider.load_current_resource
+ provider.run_action(:install)
end
it "should run dpkg -i if the package is a path and the source is nil" do
- @new_resource = Chef::Resource::Package.new("/tmp/wget_1.11.4-1ubuntu1_amd64.deb")
- @provider = Chef::Provider::Package::Dpkg.new(@new_resource, @run_context)
- expect(@provider).to receive(:run_noninteractive).with(
- "dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+ new_resource.name "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+ expect(provider).to receive(:run_noninteractive).with(
+ "dpkg", "-i", "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
)
- @provider.install_package("/tmp/wget_1.11.4-1ubuntu1_amd64.deb", "1.11.4-1ubuntu1")
+ provider.run_action(:install)
end
it "should run dpkg -i if the package is a path and the source is nil for an upgrade" do
- @new_resource = Chef::Resource::Package.new("/tmp/wget_1.11.4-1ubuntu1_amd64.deb")
- @provider = Chef::Provider::Package::Dpkg.new(@new_resource, @run_context)
- expect(@provider).to receive(:run_noninteractive).with(
- "dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+ new_resource.name "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+ expect(provider).to receive(:run_noninteractive).with(
+ "dpkg", "-i", "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
)
- @provider.upgrade_package("/tmp/wget_1.11.4-1ubuntu1_amd64.deb", "1.11.4-1ubuntu1")
+ provider.run_action(:upgrade)
end
it "should run dpkg -i with the package source and options if specified" do
- expect(@provider).to receive(:run_noninteractive).with(
- "dpkg -i --force-yes /tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+ new_resource.options "--force-yes"
+ expect(provider).to receive(:run_noninteractive).with(
+ "dpkg", "-i", "--force-yes", "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
)
- allow(@new_resource).to receive(:options).and_return("--force-yes")
-
- @provider.install_package("wget", "1.11.4-1ubuntu1")
+ provider.run_action(:install)
end
+
it "should upgrade by running install_package" do
- expect(@provider).to receive(:install_package).with("wget", "1.11.4-1ubuntu1")
- @provider.upgrade_package("wget", "1.11.4-1ubuntu1")
+ expect(provider).to receive(:install_package).with(["wget"], ["1.11.4-1ubuntu1"])
+ provider.upgrade_package(["wget"], ["1.11.4-1ubuntu1"])
end
end
describe Chef::Provider::Package::Dpkg, "remove and purge" do
it "should run dpkg -r to remove the package" do
- expect(@provider).to receive(:run_noninteractive).with(
- "dpkg -r wget"
+ expect(provider).to receive(:run_noninteractive).with(
+ "dpkg", "-r", "wget"
)
- @provider.remove_package("wget", "1.11.4-1ubuntu1")
+ provider.remove_package(["wget"], ["1.11.4-1ubuntu1"])
end
it "should run dpkg -r to remove the package with options if specified" do
- expect(@provider).to receive(:run_noninteractive).with(
- "dpkg -r --force-yes wget"
+ expect(provider).to receive(:run_noninteractive).with(
+ "dpkg", "-r", "--force-yes", "wget"
)
- allow(@new_resource).to receive(:options).and_return("--force-yes")
+ allow(new_resource).to receive(:options).and_return("--force-yes")
- @provider.remove_package("wget", "1.11.4-1ubuntu1")
+ provider.remove_package(["wget"], ["1.11.4-1ubuntu1"])
end
it "should run dpkg -P to purge the package" do
- expect(@provider).to receive(:run_noninteractive).with(
- "dpkg -P wget"
+ expect(provider).to receive(:run_noninteractive).with(
+ "dpkg", "-P", "wget"
)
- @provider.purge_package("wget", "1.11.4-1ubuntu1")
+ provider.purge_package(["wget"], ["1.11.4-1ubuntu1"])
end
it "should run dpkg -P to purge the package with options if specified" do
- expect(@provider).to receive(:run_noninteractive).with(
- "dpkg -P --force-yes wget"
+ expect(provider).to receive(:run_noninteractive).with(
+ "dpkg", "-P", "--force-yes", "wget"
)
- allow(@new_resource).to receive(:options).and_return("--force-yes")
+ allow(new_resource).to receive(:options).and_return("--force-yes")
- @provider.purge_package("wget", "1.11.4-1ubuntu1")
+ provider.purge_package(["wget"], ["1.11.4-1ubuntu1"])
end
end
end
diff --git a/spec/unit/provider/package/easy_install_spec.rb b/spec/unit/provider/package/easy_install_spec.rb
index 221ec8fdfc..910f01bfeb 100644
--- a/spec/unit/provider/package/easy_install_spec.rb
+++ b/spec/unit/provider/package/easy_install_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,17 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Package::EasyInstall do
before(:each) do
@node = Chef::Node.new
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::EasyInstallPackage.new('boto')
- @new_resource.version('1.8d')
-
- @current_resource = Chef::Resource::EasyInstallPackage.new('boto')
- @current_resource.version('1.8d')
+ @new_resource = Chef::Resource::EasyInstallPackage.new("boto")
+ @new_resource.version("1.8d")
@provider = Chef::Provider::Package::EasyInstall.new(@new_resource, @run_context)
- allow(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
@stdin = StringIO.new
@stdout = StringIO.new
@@ -48,8 +44,8 @@ describe Chef::Provider::Package::EasyInstall do
it "should set the current resources package name to the new resources package name" do
allow($stdout).to receive(:write)
- expect(@current_resource).to receive(:package_name).with(@new_resource.package_name)
@provider.load_current_resource
+ expect(@provider.current_resource.package_name).to eq(@new_resource.package_name)
end
it "should return a relative path to easy_install if no easy_install_binary is given" do
@@ -65,46 +61,52 @@ describe Chef::Provider::Package::EasyInstall do
describe "actions_on_package" do
it "should run easy_install with the package name and version" do
- expect(@provider).to receive(:run_command).with({
- :command => "easy_install \"boto==1.8d\""
- })
+ expect(Chef).to receive(:deprecated).with(:easy_install, /easy_install package provider is deprecated/)
+ expect(@provider).to receive(:shell_out!).with(
+ "easy_install", "boto==1.8d", { timeout: 900 }
+ )
@provider.install_package("boto", "1.8d")
end
it "should run easy_install with the package name and version and specified options" do
- expect(@provider).to receive(:run_command).with({
- :command => "easy_install --always-unzip \"boto==1.8d\""
- })
+ expect(Chef).to receive(:deprecated).with(:easy_install, /easy_install package provider is deprecated/)
+ expect(@provider).to receive(:shell_out!).with(
+ "easy_install", "--always-unzip", "boto==1.8d", { timeout: 900 }
+ )
allow(@new_resource).to receive(:options).and_return("--always-unzip")
@provider.install_package("boto", "1.8d")
end
it "should run easy_install with the package name and version" do
- expect(@provider).to receive(:run_command).with({
- :command => "easy_install \"boto==1.8d\""
- })
+ expect(Chef).to receive(:deprecated).with(:easy_install, /easy_install package provider is deprecated/)
+ expect(@provider).to receive(:shell_out!).with(
+ "easy_install", "boto==1.8d", { timeout: 900 }
+ )
@provider.upgrade_package("boto", "1.8d")
end
it "should run easy_install -m with the package name and version" do
- expect(@provider).to receive(:run_command).with({
- :command => "easy_install -m boto"
- })
+ expect(Chef).to receive(:deprecated).with(:easy_install, /easy_install package provider is deprecated/)
+ expect(@provider).to receive(:shell_out!).with(
+ "easy_install", "-m", "boto", { timeout: 900 }
+ )
@provider.remove_package("boto", "1.8d")
end
it "should run easy_install -m with the package name and version and specified options" do
- expect(@provider).to receive(:run_command).with({
- :command => "easy_install -x -m boto"
- })
+ expect(Chef).to receive(:deprecated).with(:easy_install, /easy_install package provider is deprecated/)
+ expect(@provider).to receive(:shell_out!).with(
+ "easy_install", "-x", "-m", "boto", { timeout: 900 }
+ )
allow(@new_resource).to receive(:options).and_return("-x")
@provider.remove_package("boto", "1.8d")
end
it "should run easy_install -m with the package name and version" do
- expect(@provider).to receive(:run_command).with({
- :command => "easy_install -m boto"
- })
+ expect(Chef).to receive(:deprecated).with(:easy_install, /easy_install package provider is deprecated/)
+ expect(@provider).to receive(:shell_out!).with(
+ "easy_install", "-m", "boto", { timeout: 900 }
+ )
@provider.purge_package("boto", "1.8d")
end
diff --git a/spec/unit/provider/package/freebsd/pkg_spec.rb b/spec/unit/provider/package/freebsd/pkg_spec.rb
index d1f5a649bc..4b3a94aa33 100644
--- a/spec/unit/provider/package/freebsd/pkg_spec.rb
+++ b/spec/unit/provider/package/freebsd/pkg_spec.rb
@@ -1,7 +1,7 @@
#
# Authors:: Bryan McLellan (btm@loftninjas.org)
# Matthew Landauer (matthew@openaustralia.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer
+# Copyright:: Copyright 2009-2016, Bryan McLellan, Matthew Landauer
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
before(:each) do
@@ -30,7 +30,9 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
@provider = Chef::Provider::Package::Freebsd::Pkg.new(@new_resource, @run_context)
@provider.current_resource = @current_resource
- allow(::File).to receive(:exist?).with('/usr/ports/Makefile').and_return(false)
+ allow(::File).to receive(:exist?).with("/usr/ports/Makefile").and_return(false)
+ allow(::File).to receive(:exist?).with("/usr/ports/www/wordpress").and_return(false)
+ allow(::File).to receive(:exist?).with("www/wordpress").and_return(false)
end
describe "when determining the current package state" do
@@ -77,23 +79,21 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
it "should return the version number when it is installed" do
pkg_info = OpenStruct.new(:stdout => "zsh-4.3.6_7")
- expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', env: nil, returns: [0,1], timeout: 900).and_return(pkg_info)
- #@provider.should_receive(:popen4).with('pkg_info -E "zsh*"').and_yield(@pid, @stdin, ["zsh-4.3.6_7"], @stderr).and_return(@status)
+ expect(@provider).to receive(:shell_out!).with("pkg_info", "-E", "zsh*", env: nil, returns: [0, 1], timeout: 900).and_return(pkg_info)
allow(@provider).to receive(:package_name).and_return("zsh")
expect(@provider.current_installed_version).to eq("4.3.6_7")
end
it "does not set the current version number when the package is not installed" do
pkg_info = OpenStruct.new(:stdout => "")
- expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', env: nil, returns: [0,1], timeout: 900).and_return(pkg_info)
+ expect(@provider).to receive(:shell_out!).with("pkg_info", "-E", "zsh*", env: nil, returns: [0, 1], timeout: 900).and_return(pkg_info)
allow(@provider).to receive(:package_name).and_return("zsh")
expect(@provider.current_installed_version).to be_nil
end
it "should return the port path for a valid port name" do
whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh")
- expect(@provider).to receive(:shell_out!).with("whereis -s zsh", env: nil, timeout: 900).and_return(whereis)
- #@provider.should_receive(:popen4).with("whereis -s zsh").and_yield(@pid, @stdin, ["zsh: /usr/ports/shells/zsh"], @stderr).and_return(@status)
+ expect(@provider).to receive(:shell_out!).with("whereis", "-s", "zsh", env: nil, timeout: 900).and_return(whereis)
allow(@provider).to receive(:port_name).and_return("zsh")
expect(@provider.port_path).to eq("/usr/ports/shells/zsh")
end
@@ -102,15 +102,15 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
it "should return the ports candidate version when given a valid port path" do
allow(@provider).to receive(:port_path).and_return("/usr/ports/shells/zsh")
make_v = OpenStruct.new(:stdout => "4.3.6\n", :exitstatus => 0)
- expect(@provider).to receive(:shell_out!).with("make -V PORTVERSION", {cwd: "/usr/ports/shells/zsh", returns: [0, 1], env: nil, timeout: 900}).and_return(make_v)
+ expect(@provider).to receive(:shell_out!).with("make", "-V", "PORTVERSION", { cwd: "/usr/ports/shells/zsh", returns: [0, 1], env: nil, timeout: 900 }).and_return(make_v)
expect(@provider.ports_candidate_version).to eq("4.3.6")
end
it "should figure out the package name when we have ports" do
- allow(::File).to receive(:exist?).with('/usr/ports/Makefile').and_return(true)
+ allow(::File).to receive(:exist?).with("/usr/ports/Makefile").and_return(true)
allow(@provider).to receive(:port_path).and_return("/usr/ports/shells/zsh")
make_v = OpenStruct.new(:stdout => "zsh-4.3.6_7\n", :exitstatus => 0)
- expect(@provider).to receive(:shell_out!).with("make -V PKGNAME", {cwd: "/usr/ports/shells/zsh", env: nil, returns: [0, 1], timeout: 900}).and_return(make_v)
+ expect(@provider).to receive(:shell_out!).with("make", "-V", "PKGNAME", { cwd: "/usr/ports/shells/zsh", env: nil, returns: [0, 1], timeout: 900 }).and_return(make_v)
#@provider.should_receive(:ports_makefile_variable_value).with("PKGNAME").and_return("zsh-4.3.6_7")
expect(@provider.package_name).to eq("zsh")
end
@@ -127,7 +127,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
end
it "should run pkg_add -r with the package name" do
- expect(@provider).to receive(:shell_out!).with("pkg_add -r zsh", env: nil, timeout: 900).and_return(@cmd_result)
+ expect(@provider).to receive(:shell_out!).with("pkg_add", "-r", "zsh", env: nil, timeout: 900).and_return(@cmd_result)
@provider.install_package("zsh", "4.3.6_7")
end
end
@@ -142,7 +142,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
it "should figure out the port path from the package_name using whereis" do
whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh")
- expect(@provider).to receive(:shell_out!).with("whereis -s zsh", env: nil, timeout: 900).and_return(whereis)
+ expect(@provider).to receive(:shell_out!).with("whereis", "-s", "zsh", env: nil, timeout: 900).and_return(whereis)
expect(@provider.port_path).to eq("/usr/ports/shells/zsh")
end
@@ -178,7 +178,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
end
it "should run pkg_add -r with the package name" do
- expect(@provider).to receive(:shell_out!).with("pkg_add -r ruby18-iconv", env: nil, timeout: 900).and_return(@install_result)
+ expect(@provider).to receive(:shell_out!).with("pkg_add", "-r", "ruby18-iconv", env: nil, timeout: 900).and_return(@install_result)
@provider.install_package("ruby-iconv", "1.0")
end
end
@@ -193,7 +193,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
end
it "should run pkg_delete with the package name and version" do
- expect(@provider).to receive(:shell_out!).with("pkg_delete zsh-4.3.6_7", env: nil, timeout: 900).and_return(@pkg_delete)
+ expect(@provider).to receive(:shell_out!).with("pkg_delete", "zsh-4.3.6_7", env: nil, timeout: 900).and_return(@pkg_delete)
@provider.remove_package("zsh", "4.3.6_7")
end
end
@@ -213,14 +213,14 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
it "should return the port path for a valid port name" do
whereis = OpenStruct.new(:stdout => "bonnie++: /usr/ports/benchmarks/bonnie++")
- expect(@provider).to receive(:shell_out!).with("whereis -s bonnie++", env: nil, timeout: 900).and_return(whereis)
+ expect(@provider).to receive(:shell_out!).with("whereis", "-s", "bonnie++", env: nil, timeout: 900).and_return(whereis)
allow(@provider).to receive(:port_name).and_return("bonnie++")
expect(@provider.port_path).to eq("/usr/ports/benchmarks/bonnie++")
end
it "should return the version number when it is installed" do
pkg_info = OpenStruct.new(:stdout => "bonnie++-1.96")
- expect(@provider).to receive(:shell_out!).with('pkg_info -E "bonnie++*"', env: nil, returns: [0,1], timeout: 900).and_return(pkg_info)
+ expect(@provider).to receive(:shell_out!).with("pkg_info", "-E", "bonnie++*", env: nil, returns: [0, 1], timeout: 900).and_return(pkg_info)
allow(@provider).to receive(:package_name).and_return("bonnie++")
expect(@provider.current_installed_version).to eq("1.96")
end
@@ -253,7 +253,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
allow(@provider).to receive(:latest_link_name).and_return("perl")
cmd = OpenStruct.new(:status => true)
- expect(@provider).to receive(:shell_out!).with("pkg_add -r perl", env: nil, timeout: 900).and_return(cmd)
+ expect(@provider).to receive(:shell_out!).with("pkg_add", "-r", "perl", env: nil, timeout: 900).and_return(cmd)
@provider.install_package("perl5.8", "5.8.8_1")
end
@@ -267,7 +267,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
allow(@provider).to receive(:latest_link_name).and_return("mysql50-server")
cmd = OpenStruct.new(:status => true)
- expect(@provider).to receive(:shell_out!).with("pkg_add -r mysql50-server", env: nil, timeout: 900).and_return(cmd)
+ expect(@provider).to receive(:shell_out!).with("pkg_add", "-r", "mysql50-server", env: nil, timeout: 900).and_return(cmd)
@provider.install_package("mysql50-server", "5.0.45_1")
end
end
diff --git a/spec/unit/provider/package/freebsd/pkgng_spec.rb b/spec/unit/provider/package/freebsd/pkgng_spec.rb
index 59215f855b..098052a057 100644
--- a/spec/unit/provider/package/freebsd/pkgng_spec.rb
+++ b/spec/unit/provider/package/freebsd/pkgng_spec.rb
@@ -1,6 +1,6 @@
#
# Authors:: Richard Manyanza (liseki@nyikacraftsmen.com)
-# Copyright:: Copyright (c) 2014 Richard Manyanza
+# Copyright:: Copyright 2014-2016, Richard Manyanza
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,8 @@
# limitations under the License.
#
-
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Provider::Package::Freebsd::Port do
before(:each) do
@@ -30,15 +29,13 @@ describe Chef::Provider::Package::Freebsd::Port do
@provider = Chef::Provider::Package::Freebsd::Pkgng.new(@new_resource, @run_context)
end
-
describe "initialization" do
it "should create a current resource with the name of the new resource" do
expect(@provider.current_resource.is_a?(Chef::Resource::Package)).to be_truthy
- expect(@provider.current_resource.name).to eq('zsh')
+ expect(@provider.current_resource.name).to eq("zsh")
end
end
-
describe "loading current resource" do
before(:each) do
allow(@provider).to receive(:current_installed_version)
@@ -63,7 +60,6 @@ describe Chef::Provider::Package::Freebsd::Port do
end
end
-
describe "determining current installed version" do
before(:each) do
allow(@provider).to receive(:supports_pkgng?)
@@ -71,23 +67,22 @@ describe Chef::Provider::Package::Freebsd::Port do
end
it "should query pkg database" do
- expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', env: nil, returns: [0,70], timeout: 900).and_return(@pkg_info)
+ expect(@provider).to receive(:shell_out!).with("pkg", "info", "zsh", env: nil, returns: [0, 70], timeout: 900).and_return(@pkg_info)
expect(@provider.current_installed_version).to eq("3.1.7")
end
end
-
describe "determining candidate version" do
it "should query repository" do
pkg_query = OpenStruct.new(:stdout => "5.0.5\n", :exitstatus => 0)
- expect(@provider).to receive(:shell_out!).with("pkg rquery '%v' zsh", env: nil, timeout: 900).and_return(pkg_query)
+ expect(@provider).to receive(:shell_out!).with("pkg", "rquery", "%v", "zsh", env: nil, timeout: 900).and_return(pkg_query)
expect(@provider.candidate_version).to eq("5.0.5")
end
it "should query specified repository when given option" do
- @provider.new_resource.options('-r LocalMirror') # This requires LocalMirror repo configuration.
+ @provider.new_resource.options("-r LocalMirror") # This requires LocalMirror repo configuration.
pkg_query = OpenStruct.new(:stdout => "5.0.3\n", :exitstatus => 0)
- expect(@provider).to receive(:shell_out!).with("pkg rquery -r LocalMirror '%v' zsh", env: nil, timeout: 900).and_return(pkg_query)
+ expect(@provider).to receive(:shell_out!).with("pkg", "rquery", "-r", "LocalMirror", "%v", "zsh", env: nil, timeout: 900).and_return(pkg_query)
expect(@provider.candidate_version).to eq("5.0.3")
end
@@ -97,7 +92,6 @@ describe Chef::Provider::Package::Freebsd::Port do
end
end
-
describe "installing a binary package" do
before(:each) do
@install_result = OpenStruct.new(:status => true)
@@ -106,7 +100,7 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should handle package source from file" do
@provider.new_resource.source("/nas/pkg/repo/zsh-5.0.1.txz")
expect(@provider).to receive(:shell_out!).
- with("pkg add /nas/pkg/repo/zsh-5.0.1.txz", env: { 'LC_ALL' => nil }, timeout: 900).
+ with("pkg", "add", "/nas/pkg/repo/zsh-5.0.1.txz", env: { "LC_ALL" => nil }, timeout: 900).
and_return(@install_result)
@provider.install_package("zsh", "5.0.1")
end
@@ -114,26 +108,25 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should handle package source over ftp or http" do
@provider.new_resource.source("http://repo.example.com/zsh-5.0.1.txz")
expect(@provider).to receive(:shell_out!).
- with("pkg add http://repo.example.com/zsh-5.0.1.txz", env: { 'LC_ALL' => nil }, timeout: 900).
+ with("pkg", "add", "http://repo.example.com/zsh-5.0.1.txz", env: { "LC_ALL" => nil }, timeout: 900).
and_return(@install_result)
@provider.install_package("zsh", "5.0.1")
end
it "should handle a package name" do
expect(@provider).to receive(:shell_out!).
- with("pkg install -y zsh", env: { 'LC_ALL' => nil }, timeout: 900).and_return(@install_result)
+ with("pkg", "install", "-y", "zsh", env: { "LC_ALL" => nil }, timeout: 900).and_return(@install_result)
@provider.install_package("zsh", "5.0.1")
end
it "should handle a package name with a specified repo" do
- @provider.new_resource.options('-r LocalMirror') # This requires LocalMirror repo configuration.
+ @provider.new_resource.options("-r LocalMirror") # This requires LocalMirror repo configuration.
expect(@provider).to receive(:shell_out!).
- with("pkg install -y -r LocalMirror zsh", env: { 'LC_ALL' => nil }, timeout: 900).and_return(@install_result)
+ with("pkg", "install", "-y", "-r", "LocalMirror", "zsh", env: { "LC_ALL" => nil }, timeout: 900).and_return(@install_result)
@provider.install_package("zsh", "5.0.1")
end
end
-
describe "removing a binary package" do
before(:each) do
@install_result = OpenStruct.new(:status => true)
@@ -141,14 +134,14 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should call pkg delete" do
expect(@provider).to receive(:shell_out!).
- with("pkg delete -y zsh-5.0.1", env: nil, timeout: 900).and_return(@install_result)
+ with("pkg", "delete", "-y", "zsh-5.0.1", env: nil, timeout: 900).and_return(@install_result)
@provider.remove_package("zsh", "5.0.1")
end
it "should not include repo option in pkg delete" do
- @provider.new_resource.options('-r LocalMirror') # This requires LocalMirror repo configuration.
+ @provider.new_resource.options("-r LocalMirror") # This requires LocalMirror repo configuration.
expect(@provider).to receive(:shell_out!).
- with("pkg delete -y zsh-5.0.1", env: nil, timeout: 900).and_return(@install_result)
+ with("pkg", "delete", "-y", "zsh-5.0.1", env: nil, timeout: 900).and_return(@install_result)
@provider.remove_package("zsh", "5.0.1")
end
end
diff --git a/spec/unit/provider/package/freebsd/port_spec.rb b/spec/unit/provider/package/freebsd/port_spec.rb
index 4b23575740..5c87483fa6 100644
--- a/spec/unit/provider/package/freebsd/port_spec.rb
+++ b/spec/unit/provider/package/freebsd/port_spec.rb
@@ -1,6 +1,6 @@
#
# Authors:: Richard Manyanza (liseki@nyikacraftsmen.com)
-# Copyright:: Copyright (c) 2014 Richard Manyanza
+# Copyright:: Copyright 2014-2016, Richard Manyanza
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,8 @@
# limitations under the License.
#
-
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Provider::Package::Freebsd::Port do
before(:each) do
@@ -30,15 +29,13 @@ describe Chef::Provider::Package::Freebsd::Port do
@provider = Chef::Provider::Package::Freebsd::Port.new(@new_resource, @run_context)
end
-
describe "initialization" do
it "should create a current resource with the name of the new resource" do
expect(@provider.current_resource.is_a?(Chef::Resource::Package)).to be_truthy
- expect(@provider.current_resource.name).to eq('zsh')
+ expect(@provider.current_resource.name).to eq("zsh")
end
end
-
describe "loading current resource" do
before(:each) do
allow(@provider).to receive(:current_installed_version)
@@ -63,7 +60,6 @@ describe Chef::Provider::Package::Freebsd::Port do
end
end
-
describe "determining current installed version" do
before(:each) do
@pkg_info = OpenStruct.new(:stdout => "zsh-3.1.7\n")
@@ -72,24 +68,24 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should check 'pkg_info' if system uses pkg_* tools" do
allow(@new_resource).to receive(:supports_pkgng?)
expect(@new_resource).to receive(:supports_pkgng?).and_return(false)
- expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', env: nil, returns: [0,1], timeout: 900).and_return(@pkg_info)
+ expect(@provider).to receive(:shell_out!).with("pkg_info", "-E", "zsh*", env: nil, returns: [0, 1], timeout: 900).and_return(@pkg_info)
expect(@provider.current_installed_version).to eq("3.1.7")
end
it "should check 'pkg info' if make supports WITH_PKGNG if freebsd version is < 1000017" do
pkg_enabled = OpenStruct.new(:stdout => "yes\n")
- [1000016, 1000000, 901503, 902506, 802511].each do |__freebsd_version|
- @node.automatic_attrs[:os_version] = __freebsd_version
- expect(@new_resource).to receive(:shell_out!).with('make -V WITH_PKGNG', env: nil).and_return(pkg_enabled)
- expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', env: nil, returns: [0,70], timeout: 900).and_return(@pkg_info)
+ [1000016, 1000000, 901503, 902506, 802511].each do |freebsd_version|
+ @node.automatic_attrs[:os_version] = freebsd_version
+ expect(@new_resource).to receive(:shell_out!).with("make", "-V", "WITH_PKGNG", env: nil).and_return(pkg_enabled)
+ expect(@provider).to receive(:shell_out!).with("pkg", "info", "zsh", env: nil, returns: [0, 70], timeout: 900).and_return(@pkg_info)
expect(@provider.current_installed_version).to eq("3.1.7")
end
end
it "should check 'pkg info' if the freebsd version is greater than or equal to 1000017" do
- __freebsd_version = 1000017
- @node.automatic_attrs[:os_version] = __freebsd_version
- expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', env: nil, returns: [0,70], timeout: 900).and_return(@pkg_info)
+ freebsd_version = 1000017
+ @node.automatic_attrs[:os_version] = freebsd_version
+ expect(@provider).to receive(:shell_out!).with("pkg", "info", "zsh", env: nil, returns: [0, 70], timeout: 900).and_return(@pkg_info)
expect(@provider.current_installed_version).to eq("3.1.7")
end
end
@@ -100,20 +96,19 @@ describe Chef::Provider::Package::Freebsd::Port do
end
it "should return candidate version if port exists" do
- allow(::File).to receive(:exist?).with('/usr/ports/Makefile').and_return(true)
- allow(@provider).to receive(:port_dir).and_return('/usr/ports/shells/zsh')
- expect(@provider).to receive(:shell_out!).with("make -V PORTVERSION", cwd: "/usr/ports/shells/zsh", env: nil, returns: [0,1], timeout: 900).
+ allow(::File).to receive(:exist?).with("/usr/ports/Makefile").and_return(true)
+ allow(@provider).to receive(:port_dir).and_return("/usr/ports/shells/zsh")
+ expect(@provider).to receive(:shell_out!).with("make", "-V", "PORTVERSION", cwd: "/usr/ports/shells/zsh", env: nil, returns: [0, 1], timeout: 900).
and_return(@port_version)
expect(@provider.candidate_version).to eq("5.0.5")
end
it "should raise exception if ports tree not found" do
- allow(::File).to receive(:exist?).with('/usr/ports/Makefile').and_return(false)
+ allow(::File).to receive(:exist?).with("/usr/ports/Makefile").and_return(false)
expect { @provider.candidate_version }.to raise_error(Chef::Exceptions::Package, "Ports collection could not be found")
end
end
-
describe "determining port directory" do
it "should return name if package name is absolute path" do
allow(@provider.new_resource).to receive(:package_name).and_return("/var/ports/shells/zsh")
@@ -127,18 +122,17 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should query system for path given just a name" do
whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh\n")
- expect(@provider).to receive(:shell_out!).with("whereis -s zsh", env: nil, timeout: 900).and_return(whereis)
+ expect(@provider).to receive(:shell_out!).with("whereis", "-s", "zsh", env: nil, timeout: 900).and_return(whereis)
expect(@provider.port_dir).to eq("/usr/ports/shells/zsh")
end
it "should raise exception if not found" do
whereis = OpenStruct.new(:stdout => "zsh:\n")
- expect(@provider).to receive(:shell_out!).with("whereis -s zsh", env: nil, timeout: 900).and_return(whereis)
+ expect(@provider).to receive(:shell_out!).with("whereis", "-s", "zsh", env: nil, timeout: 900).and_return(whereis)
expect { @provider.port_dir }.to raise_error(Chef::Exceptions::Package, "Could not find port with the name zsh")
end
end
-
describe "building a binary package" do
before(:each) do
@install_result = OpenStruct.new(:status => true)
@@ -147,13 +141,12 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should run make install in port directory" do
allow(@provider).to receive(:port_dir).and_return("/usr/ports/shells/zsh")
expect(@provider).to receive(:shell_out!).
- with("make -DBATCH install clean", :timeout => 1800, :cwd => "/usr/ports/shells/zsh", :env => nil).
+ with("make", "-DBATCH", "install", "clean", :timeout => 1800, :cwd => "/usr/ports/shells/zsh", :env => nil).
and_return(@install_result)
@provider.install_package("zsh", "5.0.5")
end
end
-
describe "removing a binary package" do
before(:each) do
@install_result = OpenStruct.new(:status => true)
@@ -162,7 +155,7 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should run make deinstall in port directory" do
allow(@provider).to receive(:port_dir).and_return("/usr/ports/shells/zsh")
expect(@provider).to receive(:shell_out!).
- with("make deinstall", :timeout => 300, :cwd => "/usr/ports/shells/zsh", :env => nil).
+ with("make", "deinstall", :timeout => 300, :cwd => "/usr/ports/shells/zsh", :env => nil).
and_return(@install_result)
@provider.remove_package("zsh", "5.0.5")
end
diff --git a/spec/unit/provider/package/homebrew_spec.rb b/spec/unit/provider/package/homebrew_spec.rb
index d01d455b09..572c54e83d 100644
--- a/spec/unit/provider/package/homebrew_spec.rb
+++ b/spec/unit/provider/package/homebrew_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Joshua Timberman (<joshua@getchef.com>)
-# Copyright (c) 2014, Chef Software, Inc. <legal@getchef.com>
+# Author:: Joshua Timberman (<joshua@chef.io>)
+# Copyright 2014-2016, Chef Software, Inc. <legal@chef.io>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,14 +15,14 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Package::Homebrew do
let(:node) { Chef::Node.new }
- let(:events) { double('Chef::Events').as_null_object }
- let(:run_context) { double('Chef::RunContext', node: node, events: events) }
- let(:new_resource) { Chef::Resource::HomebrewPackage.new('emacs') }
- let(:current_resource) { Chef::Resource::HomebrewPackage.new('emacs')}
+ let(:events) { double("Chef::Events").as_null_object }
+ let(:run_context) { double("Chef::RunContext", node: node, events: events) }
+ let(:new_resource) { Chef::Resource::HomebrewPackage.new("emacs") }
+ let(:current_resource) { Chef::Resource::HomebrewPackage.new("emacs") }
let(:provider) do
Chef::Provider::Package::Homebrew.new(new_resource, run_context)
@@ -32,85 +32,85 @@ describe Chef::Provider::Package::Homebrew do
let(:uninstalled_brew_info) do
{
- 'name' => 'emacs',
- 'homepage' => 'http://www.gnu.org/software/emacs',
- 'versions' => {
- 'stable' => '24.3',
- 'bottle' => false,
- 'devel' => nil,
- 'head' => nil
+ "name" => "emacs",
+ "homepage" => "http://www.gnu.org/software/emacs",
+ "versions" => {
+ "stable" => "24.3",
+ "bottle" => false,
+ "devel" => nil,
+ "head" => nil,
},
- 'revision' => 0,
- 'installed' => [],
- 'linked_keg' => nil,
- 'keg_only' => nil,
- 'dependencies' => [],
- 'conflicts_with' => [],
- 'caveats' => nil,
- 'options' => []
+ "revision" => 0,
+ "installed" => [],
+ "linked_keg" => nil,
+ "keg_only" => nil,
+ "dependencies" => [],
+ "conflicts_with" => [],
+ "caveats" => nil,
+ "options" => [],
}
end
let(:installed_brew_info) do
{
- 'name' => 'emacs',
- 'homepage' => 'http://www.gnu.org/software/emacs/',
- 'versions' => {
- 'stable' => '24.3',
- 'bottle' => false,
- 'devel' => nil,
- 'head' => 'HEAD'
+ "name" => "emacs",
+ "homepage" => "http://www.gnu.org/software/emacs/",
+ "versions" => {
+ "stable" => "24.3",
+ "bottle" => false,
+ "devel" => nil,
+ "head" => "HEAD",
},
- 'revision' => 0,
- 'installed' => [{ 'version' => '24.3' }],
- 'linked_keg' => '24.3',
- 'keg_only' => nil,
- 'dependencies' => [],
- 'conflicts_with' => [],
- 'caveats' => '',
- 'options' => []
+ "revision" => 0,
+ "installed" => [{ "version" => "24.3" }],
+ "linked_keg" => "24.3",
+ "keg_only" => nil,
+ "dependencies" => [],
+ "conflicts_with" => [],
+ "caveats" => "",
+ "options" => [],
}
end
let(:keg_only_brew_info) do
{
- 'name' => 'emacs-kegger',
- 'homepage' => 'http://www.gnu.org/software/emacs/',
- 'versions' => {
- 'stable' => '24.3-keggy',
- 'bottle' => false,
- 'devel' => nil,
- 'head' => 'HEAD'
+ "name" => "emacs-kegger",
+ "homepage" => "http://www.gnu.org/software/emacs/",
+ "versions" => {
+ "stable" => "24.3-keggy",
+ "bottle" => false,
+ "devel" => nil,
+ "head" => "HEAD",
},
- 'revision' => 0,
- 'installed' => [{ 'version' => '24.3-keggy' }],
- 'linked_keg' => nil,
- 'keg_only' => true,
- 'dependencies' => [],
- 'conflicts_with' => [],
- 'caveats' => '',
- 'options' => []
+ "revision" => 0,
+ "installed" => [{ "version" => "24.3-keggy" }],
+ "linked_keg" => nil,
+ "keg_only" => true,
+ "dependencies" => [],
+ "conflicts_with" => [],
+ "caveats" => "",
+ "options" => [],
}
end
let(:keg_only_uninstalled_brew_info) do
{
- 'name' => 'emacs-kegger',
- 'homepage' => 'http://www.gnu.org/software/emacs/',
- 'versions' => {
- 'stable' => '24.3-keggy',
- 'bottle' => false,
- 'devel' => nil,
- 'head' => 'HEAD'
+ "name" => "emacs-kegger",
+ "homepage" => "http://www.gnu.org/software/emacs/",
+ "versions" => {
+ "stable" => "24.3-keggy",
+ "bottle" => false,
+ "devel" => nil,
+ "head" => "HEAD",
},
- 'revision' => 0,
- 'installed' => [],
- 'linked_keg' => nil,
- 'keg_only' => true,
- 'dependencies' => [],
- 'conflicts_with' => [],
- 'caveats' => '',
- 'options' => []
+ "revision" => 0,
+ "installed" => [],
+ "linked_keg" => nil,
+ "keg_only" => true,
+ "dependencies" => [],
+ "conflicts_with" => [],
+ "caveats" => "",
+ "options" => [],
}
end
@@ -118,174 +118,174 @@ describe Chef::Provider::Package::Homebrew do
end
- describe 'load_current_resource' do
+ describe "load_current_resource" do
before(:each) do
allow(provider).to receive(:current_installed_version).and_return(nil)
- allow(provider).to receive(:candidate_version).and_return('24.3')
+ allow(provider).to receive(:candidate_version).and_return("24.3")
end
- it 'creates a current resource with the name of the new resource' do
+ it "creates a current resource with the name of the new resource" do
provider.load_current_resource
expect(provider.current_resource).to be_a(Chef::Resource::Package)
- expect(provider.current_resource.name).to eql('emacs')
+ expect(provider.current_resource.name).to eql("emacs")
end
- it 'creates a current resource with the version if the package is installed' do
- expect(provider).to receive(:current_installed_version).and_return('24.3')
+ it "creates a current resource with the version if the package is installed" do
+ expect(provider).to receive(:current_installed_version).and_return("24.3")
provider.load_current_resource
- expect(provider.current_resource.version).to eql('24.3')
+ expect(provider.current_resource.version).to eql("24.3")
end
- it 'creates a current resource with a nil version if the package is not installed' do
+ it "creates a current resource with a nil version if the package is not installed" do
provider.load_current_resource
expect(provider.current_resource.version).to be_nil
end
- it 'sets a candidate version if one exists' do
+ it "sets a candidate version if one exists" do
provider.load_current_resource
- expect(provider.candidate_version).to eql('24.3')
+ expect(provider.candidate_version).to eql("24.3")
end
end
- describe 'current_installed_version' do
- it 'returns the latest version from brew info if the package is keg only' do
+ describe "current_installed_version" do
+ it "returns the latest version from brew info if the package is keg only" do
allow(provider).to receive(:brew_info).and_return(keg_only_brew_info)
- expect(provider.current_installed_version).to eql('24.3-keggy')
+ expect(provider.current_installed_version).to eql("24.3-keggy")
end
- it 'returns the linked keg version if the package is not keg only' do
+ it "returns the linked keg version if the package is not keg only" do
allow(provider).to receive(:brew_info).and_return(installed_brew_info)
- expect(provider.current_installed_version).to eql('24.3')
+ expect(provider.current_installed_version).to eql("24.3")
end
- it 'returns nil if the package is not installed' do
+ it "returns nil if the package is not installed" do
allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
expect(provider.current_installed_version).to be_nil
end
- it 'returns nil if the package is keg only and not installed' do
+ it "returns nil if the package is keg only and not installed" do
allow(provider).to receive(:brew_info).and_return(keg_only_uninstalled_brew_info)
expect(provider.current_installed_version).to be_nil
end
end
- describe 'brew' do
+ describe "brew" do
before do
expect(provider).to receive(:find_homebrew_uid).and_return(homebrew_uid)
expect(Etc).to receive(:getpwuid).with(homebrew_uid).and_return(OpenStruct.new(:name => "name", :dir => "/"))
end
- it 'passes a single to the brew command and return stdout' do
- allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => 'zombo'))
- expect(provider.brew).to eql('zombo')
+ it "passes a single to the brew command and return stdout" do
+ allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => "zombo"))
+ expect(provider.brew).to eql("zombo")
end
- it 'takes multiple arguments as an array' do
- allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => 'homestarrunner'))
- expect(provider.brew('info', 'opts', 'bananas')).to eql('homestarrunner')
+ it "takes multiple arguments as an array" do
+ allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => "homestarrunner"))
+ expect(provider.brew("info", "opts", "bananas")).to eql("homestarrunner")
end
context "when new_resource is Package" do
- let(:new_resource) { Chef::Resource::Package.new('emacs') }
+ let(:new_resource) { Chef::Resource::Package.new("emacs") }
it "does not try to read homebrew_user from Package, which does not have it" do
- allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => 'zombo'))
- expect(provider.brew).to eql('zombo')
+ allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => "zombo"))
+ expect(provider.brew).to eql("zombo")
end
end
end
- context 'when testing actions' do
+ context "when testing actions" do
before(:each) do
provider.current_resource = current_resource
end
- describe 'install_package' do
+ describe "install_package" do
before(:each) do
- allow(provider).to receive(:candidate_version).and_return('24.3')
+ allow(provider).to receive(:candidate_version).and_return("24.3")
end
- it 'installs the named package with brew install' do
- allow(provider.new_resource).to receive(:version).and_return('24.3')
+ it "installs the named package with brew install" do
+ allow(provider.new_resource).to receive(:version).and_return("24.3")
allow(provider.current_resource).to receive(:version).and_return(nil)
allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
- expect(provider).to receive(:get_response_from_command).with('brew install emacs')
- provider.install_package('emacs', '24.3')
+ expect(provider).to receive(:get_response_from_command).with("brew", "install", nil, "emacs")
+ provider.install_package("emacs", "24.3")
end
- it 'does not do anything if the package is installed' do
- allow(provider.current_resource).to receive(:version).and_return('24.3')
+ it "does not do anything if the package is installed" do
+ allow(provider.current_resource).to receive(:version).and_return("24.3")
allow(provider).to receive(:brew_info).and_return(installed_brew_info)
expect(provider).not_to receive(:get_response_from_command)
- provider.install_package('emacs', '24.3')
+ provider.install_package("emacs", "24.3")
end
- it 'uses options to the brew command if specified' do
- allow(provider.new_resource).to receive(:options).and_return('--cocoa')
- allow(provider.current_resource).to receive(:version).and_return('24.3')
- allow(provider).to receive(:get_response_from_command).with('brew install --cocoa emacs')
- provider.install_package('emacs', '24.3')
+ it "uses options to the brew command if specified" do
+ new_resource.options "--cocoa"
+ allow(provider.current_resource).to receive(:version).and_return("24.3")
+ allow(provider).to receive(:get_response_from_command).with("brew", "install", "--cocoa", "emacs")
+ provider.install_package("emacs", "24.3")
end
end
- describe 'upgrade_package' do
- it 'uses brew upgrade to upgrade the package if it is installed' do
- allow(provider.current_resource).to receive(:version).and_return('24')
+ describe "upgrade_package" do
+ it "uses brew upgrade to upgrade the package if it is installed" do
+ allow(provider.current_resource).to receive(:version).and_return("24")
allow(provider).to receive(:brew_info).and_return(installed_brew_info)
- expect(provider).to receive(:get_response_from_command).with('brew upgrade emacs')
- provider.upgrade_package('emacs', '24.3')
+ expect(provider).to receive(:get_response_from_command).with("brew", "upgrade", nil, "emacs")
+ provider.upgrade_package("emacs", "24.3")
end
- it 'does not do anything if the package version is already installed' do
- allow(provider.current_resource).to receive(:version).and_return('24.3')
+ it "does not do anything if the package version is already installed" do
+ allow(provider.current_resource).to receive(:version).and_return("24.3")
allow(provider).to receive(:brew_info).and_return(installed_brew_info)
expect(provider).not_to receive(:get_response_from_command)
- provider.install_package('emacs', '24.3')
+ provider.install_package("emacs", "24.3")
end
- it 'uses brew install to install the package if it is not installed' do
+ it "uses brew install to install the package if it is not installed" do
allow(provider.current_resource).to receive(:version).and_return(nil)
allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
- expect(provider).to receive(:get_response_from_command).with('brew install emacs')
- provider.upgrade_package('emacs', '24.3')
+ expect(provider).to receive(:get_response_from_command).with("brew", "install", nil, "emacs")
+ provider.upgrade_package("emacs", "24.3")
end
- it 'uses options to the brew command if specified' do
- allow(provider.current_resource).to receive(:version).and_return('24')
+ it "uses options to the brew command if specified" do
+ allow(provider.current_resource).to receive(:version).and_return("24")
allow(provider).to receive(:brew_info).and_return(installed_brew_info)
- allow(provider.new_resource).to receive(:options).and_return('--cocoa')
- expect(provider).to receive(:get_response_from_command).with('brew upgrade --cocoa emacs')
- provider.upgrade_package('emacs', '24.3')
+ new_resource.options "--cocoa"
+ expect(provider).to receive(:get_response_from_command).with("brew", "upgrade", [ "--cocoa" ], "emacs")
+ provider.upgrade_package("emacs", "24.3")
end
end
- describe 'remove_package' do
- it 'uninstalls the package with brew uninstall' do
- allow(provider.current_resource).to receive(:version).and_return('24.3')
+ describe "remove_package" do
+ it "uninstalls the package with brew uninstall" do
+ allow(provider.current_resource).to receive(:version).and_return("24.3")
allow(provider).to receive(:brew_info).and_return(installed_brew_info)
- expect(provider).to receive(:get_response_from_command).with('brew uninstall emacs')
- provider.remove_package('emacs', '24.3')
+ expect(provider).to receive(:get_response_from_command).with("brew", "uninstall", nil, "emacs")
+ provider.remove_package("emacs", "24.3")
end
- it 'does not do anything if the package is not installed' do
+ it "does not do anything if the package is not installed" do
allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
expect(provider).not_to receive(:get_response_from_command)
- provider.remove_package('emacs', '24.3')
+ provider.remove_package("emacs", "24.3")
end
end
- describe 'purge_package' do
- it 'uninstalls the package with brew uninstall --force' do
- allow(provider.current_resource).to receive(:version).and_return('24.3')
+ describe "purge_package" do
+ it "uninstalls the package with brew uninstall --force" do
+ allow(provider.current_resource).to receive(:version).and_return("24.3")
allow(provider).to receive(:brew_info).and_return(installed_brew_info)
- expect(provider).to receive(:get_response_from_command).with('brew uninstall --force emacs')
- provider.purge_package('emacs', '24.3')
+ expect(provider).to receive(:get_response_from_command).with("brew", "uninstall", "--force", nil, "emacs")
+ provider.purge_package("emacs", "24.3")
end
- it 'does not do anything if the package is not installed' do
+ it "does not do anything if the package is not installed" do
allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
expect(provider).not_to receive(:get_response_from_command)
- provider.purge_package('emacs', '24.3')
+ provider.purge_package("emacs", "24.3")
end
end
end
diff --git a/spec/unit/provider/package/ips_spec.rb b/spec/unit/provider/package/ips_spec.rb
index ad69dffb10..3bbdd26ce3 100644
--- a/spec/unit/provider/package/ips_spec.rb
+++ b/spec/unit/provider/package/ips_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Bryan McLellan <btm@opscode.com>
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Bryan McLellan <btm@chef.io>
+# Copyright:: Copyright 2012-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
# based on the apt specs
@@ -26,26 +26,25 @@ describe Chef::Provider::Package::Ips do
@node = Chef::Node.new
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Package.new("crypto/gnupg", @run_context)
- @current_resource = Chef::Resource::Package.new("crypto/gnupg", @run_context)
- allow(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
+ @new_resource = Chef::Resource::IpsPackage.new("crypto/gnupg", @run_context)
+ @current_resource = Chef::Resource::IpsPackage.new("crypto/gnupg", @run_context)
+ allow(Chef::Resource::IpsPackage).to receive(:new).and_return(@current_resource)
@provider = Chef::Provider::Package::Ips.new(@new_resource, @run_context)
end
def local_output
stdin = StringIO.new
- stdout = ''
- stderr =<<-PKG_STATUS
+ stdout = ""
+ stderr = <<-PKG_STATUS
pkg: info: no packages matching the following patterns you specified are
installed on the system. Try specifying -r to query remotely:
crypto/gnupg
PKG_STATUS
- return OpenStruct.new(:stdout => stdout,:stdin => stdin,:stderr => stderr,:status => @status,:exitstatus => 1)
+ OpenStruct.new(:stdout => stdout, :stdin => stdin, :stderr => stderr, :status => @status, :exitstatus => 1)
end
def remote_output
-
stdout = <<-PKG_STATUS
Name: security/sudo
Summary: sudo - authority delegation tool
@@ -58,35 +57,35 @@ Packaging Date: April 1, 2012 05:55:52 PM
Size: 2.57 MB
FMRI: pkg://omnios/security/sudo@1.8.4.1,5.11-0.151002:20120401T175552Z
PKG_STATUS
- stdin = StringIO.new
- stderr = ''
- return OpenStruct.new(:stdout => stdout,:stdin => stdin,:stderr => stderr,:status => @status,:exitstatus => 0)
+ stdin = StringIO.new
+ stderr = ""
+ OpenStruct.new(:stdout => stdout, :stdin => stdin, :stderr => stderr, :status => @status, :exitstatus => 0)
end
context "when loading current resource" do
it "should create a current resource with the name of the new_resource" do
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
- expect(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
+ expect(@provider).to receive(:shell_out).with("pkg", "info", @new_resource.package_name, timeout: 900).and_return(local_output)
+ expect(@provider).to receive(:shell_out!).with("pkg", "info", "-r", @new_resource.package_name, timeout: 900).and_return(remote_output)
+ expect(Chef::Resource::IpsPackage).to receive(:new).and_return(@current_resource)
@provider.load_current_resource
end
it "should set the current resources package name to the new resources package name" do
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
+ expect(@provider).to receive(:shell_out).with("pkg", "info", @new_resource.package_name, timeout: 900).and_return(local_output)
+ expect(@provider).to receive(:shell_out!).with("pkg", "info", "-r", @new_resource.package_name, timeout: 900).and_return(remote_output)
@provider.load_current_resource
expect(@current_resource.package_name).to eq(@new_resource.package_name)
end
it "should run pkg info with the package name" do
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
+ expect(@provider).to receive(:shell_out).with("pkg", "info", @new_resource.package_name, timeout: 900).and_return(local_output)
+ expect(@provider).to receive(:shell_out!).with("pkg", "info", "-r", @new_resource.package_name, timeout: 900).and_return(remote_output)
@provider.load_current_resource
end
it "should set the installed version to nil on the current resource if package state is not installed" do
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
+ expect(@provider).to receive(:shell_out).with("pkg", "info", @new_resource.package_name, timeout: 900).and_return(local_output)
+ expect(@provider).to receive(:shell_out!).with("pkg", "info", "-r", @new_resource.package_name, timeout: 900).and_return(remote_output)
@provider.load_current_resource
expect(@current_resource.version).to be_nil
end
@@ -108,31 +107,37 @@ Packaging Date: October 19, 2011 09:14:50 AM
Size: 8.07 MB
FMRI: pkg://solaris/crypto/gnupg@2.0.17,5.11-0.175.0.0.0.2.537:20111019T091450Z
INSTALLED
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
+ expect(@provider).to receive(:shell_out).with("pkg", "info", @new_resource.package_name, timeout: 900).and_return(local)
+ expect(@provider).to receive(:shell_out!).with("pkg", "info", "-r", @new_resource.package_name, timeout: 900).and_return(remote_output)
@provider.load_current_resource
expect(@current_resource.version).to eq("2.0.17")
end
it "should return the current resource" do
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
+ expect(@provider).to receive(:shell_out).with("pkg", "info", @new_resource.package_name, timeout: 900).and_return(local_output)
+ expect(@provider).to receive(:shell_out!).with("pkg", "info", "-r", @new_resource.package_name, timeout: 900).and_return(remote_output)
expect(@provider.load_current_resource).to eql(@current_resource)
end
end
context "when installing a package" do
it "should run pkg install with the package name and version" do
- expect(@provider).to receive(:shell_out).with("pkg install -q crypto/gnupg@2.0.17", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("pkg", "install", "-q", "crypto/gnupg@2.0.17", timeout: 900)
@provider.install_package("crypto/gnupg", "2.0.17")
end
it "should run pkg install with the package name and version and options if specified" do
- expect(@provider).to receive(:shell_out).with("pkg --no-refresh install -q crypto/gnupg@2.0.17", timeout: 900)
- allow(@new_resource).to receive(:options).and_return("--no-refresh")
+ expect(@provider).to receive(:shell_out!).with("pkg", "--no-refresh", "install", "-q", "crypto/gnupg@2.0.17", timeout: 900)
+ @new_resource.options "--no-refresh"
@provider.install_package("crypto/gnupg", "2.0.17")
end
+ it "raises an error if package fails to install" do
+ expect(@provider).to receive(:shell_out!).with("pkg", "--no-refresh", "install", "-q", "crypto/gnupg@2.0.17", timeout: 900).and_raise(Mixlib::ShellOut::ShellCommandFailed)
+ allow(@new_resource).to receive(:options).and_return("--no-refresh")
+ expect { @provider.install_package("crypto/gnupg", "2.0.17") }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
+ end
+
it "should not include the human-readable version in the candidate_version" do
remote = remote_output
remote.stdout = <<-PKG_STATUS
@@ -147,8 +152,8 @@ Packaging Date: April 1, 2012 05:55:52 PM
Size: 2.57 MB
FMRI: pkg://omnios/security/sudo@1.8.4.1,5.11-0.151002:20120401T175552Z
PKG_STATUS
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote)
+ expect(@provider).to receive(:shell_out).with("pkg", "info", @new_resource.package_name, timeout: 900).and_return(local_output)
+ expect(@provider).to receive(:shell_out!).with("pkg", "info", "-r", @new_resource.package_name, timeout: 900).and_return(remote)
@provider.load_current_resource
expect(@current_resource.version).to be_nil
expect(@provider.candidate_version).to eql("1.8.4.1")
@@ -188,8 +193,8 @@ Packaging Date: October 19, 2011 09:14:50 AM
FMRI: pkg://solaris/crypto/gnupg@2.0.18,5.11-0.175.0.0.0.2.537:20111019T091450Z
REMOTE
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote)
+ expect(@provider).to receive(:shell_out).with("pkg", "info", @new_resource.package_name, timeout: 900).and_return(local)
+ expect(@provider).to receive(:shell_out!).with("pkg", "info", "-r", @new_resource.package_name, timeout: 900).and_return(remote)
expect(@provider).to receive(:install_package).exactly(0).times
@provider.run_action(:install)
end
@@ -200,7 +205,7 @@ REMOTE
end
it "should run pkg install with the --accept flag" do
- expect(@provider).to receive(:shell_out).with("pkg install -q --accept crypto/gnupg@2.0.17", timeout: 900)
+ expect(@provider).to receive(:shell_out).with("pkg", "install", "-q", "--accept", "crypto/gnupg@2.0.17", timeout: 900).and_return(local_output)
@provider.install_package("crypto/gnupg", "2.0.17")
end
end
@@ -208,20 +213,20 @@ REMOTE
context "when upgrading a package" do
it "should run pkg install with the package name and version" do
- expect(@provider).to receive(:shell_out).with("pkg install -q crypto/gnupg@2.0.17", timeout: 900)
+ expect(@provider).to receive(:shell_out).with("pkg", "install", "-q", "crypto/gnupg@2.0.17", timeout: 900).and_return(local_output)
@provider.upgrade_package("crypto/gnupg", "2.0.17")
end
end
context "when uninstalling a package" do
it "should run pkg uninstall with the package name and version" do
- expect(@provider).to receive(:shell_out!).with("pkg uninstall -q crypto/gnupg@2.0.17", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("pkg", "uninstall", "-q", "crypto/gnupg@2.0.17", timeout: 900)
@provider.remove_package("crypto/gnupg", "2.0.17")
end
it "should run pkg uninstall with the package name and version and options if specified" do
- expect(@provider).to receive(:shell_out!).with("pkg --no-refresh uninstall -q crypto/gnupg@2.0.17", timeout: 900)
- allow(@new_resource).to receive(:options).and_return("--no-refresh")
+ expect(@provider).to receive(:shell_out!).with("pkg", "--no-refresh", "uninstall", "-q", "crypto/gnupg@2.0.17", timeout: 900)
+ @new_resource.options "--no-refresh"
@provider.remove_package("crypto/gnupg", "2.0.17")
end
end
diff --git a/spec/unit/provider/package/macports_spec.rb b/spec/unit/provider/package/macports_spec.rb
index eef84113b4..d690791d16 100644
--- a/spec/unit/provider/package/macports_spec.rb
+++ b/spec/unit/provider/package/macports_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: David Balatero (<dbalatero@gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Package::Macports do
before(:each) do
@@ -70,7 +70,7 @@ describe Chef::Provider::Package::Macports do
describe "current_installed_version" do
it "should return the current version if the package is installed" do
- stdout = <<EOF
+ stdout = <<EOF
The following ports are currently installed:
openssl @0.9.8k_0 (active)
EOF
@@ -105,7 +105,7 @@ EOF
it "should run the port install command with the correct version" do
expect(@current_resource).to receive(:version).and_return("4.1.6")
@provider.current_resource = @current_resource
- expect(@provider).to receive(:shell_out!).with("port install zsh @4.2.7", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("port", "install", "zsh", "@4.2.7", timeout: 900)
@provider.install_package("zsh", "4.2.7")
end
@@ -122,7 +122,7 @@ EOF
expect(@current_resource).to receive(:version).and_return("4.1.6")
@provider.current_resource = @current_resource
allow(@new_resource).to receive(:options).and_return("-f")
- expect(@provider).to receive(:shell_out!).with("port -f install zsh @4.2.7", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("port", "-f", "install", "zsh", "@4.2.7", timeout: 900)
@provider.install_package("zsh", "4.2.7")
end
@@ -130,36 +130,36 @@ EOF
describe "purge_package" do
it "should run the port uninstall command with the correct version" do
- expect(@provider).to receive(:shell_out!).with("port uninstall zsh @4.2.7", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("port", "uninstall", "zsh", "@4.2.7", timeout: 900)
@provider.purge_package("zsh", "4.2.7")
end
it "should purge the currently active version if no explicit version is passed in" do
- expect(@provider).to receive(:shell_out!).with("port uninstall zsh", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("port", "uninstall", "zsh", timeout: 900)
@provider.purge_package("zsh", nil)
end
it "should add options to the port command when specified" do
allow(@new_resource).to receive(:options).and_return("-f")
- expect(@provider).to receive(:shell_out!).with("port -f uninstall zsh @4.2.7", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("port", "-f", "uninstall", "zsh", "@4.2.7", timeout: 900)
@provider.purge_package("zsh", "4.2.7")
end
end
describe "remove_package" do
it "should run the port deactivate command with the correct version" do
- expect(@provider).to receive(:shell_out!).with("port deactivate zsh @4.2.7", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("port", "deactivate", "zsh", "@4.2.7", timeout: 900)
@provider.remove_package("zsh", "4.2.7")
end
it "should remove the currently active version if no explicit version is passed in" do
- expect(@provider).to receive(:shell_out!).with("port deactivate zsh", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("port", "deactivate", "zsh", timeout: 900)
@provider.remove_package("zsh", nil)
end
it "should add options to the port command when specified" do
allow(@new_resource).to receive(:options).and_return("-f")
- expect(@provider).to receive(:shell_out!).with("port -f deactivate zsh @4.2.7", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("port", "-f", "deactivate", "zsh", "@4.2.7", timeout: 900)
@provider.remove_package("zsh", "4.2.7")
end
end
@@ -169,7 +169,7 @@ EOF
expect(@current_resource).to receive(:version).at_least(:once).and_return("4.1.6")
@provider.current_resource = @current_resource
- expect(@provider).to receive(:shell_out!).with("port upgrade zsh @4.2.7", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("port", "upgrade", "zsh", "@4.2.7", timeout: 900)
@provider.upgrade_package("zsh", "4.2.7")
end
@@ -195,7 +195,7 @@ EOF
expect(@current_resource).to receive(:version).at_least(:once).and_return("4.1.6")
@provider.current_resource = @current_resource
- expect(@provider).to receive(:shell_out!).with("port -f upgrade zsh @4.2.7", timeout: 900)
+ expect(@provider).to receive(:shell_out!).with("port", "-f", "upgrade", "zsh", "@4.2.7", timeout: 900)
@provider.upgrade_package("zsh", "4.2.7")
end
diff --git a/spec/unit/provider/package/msu_spec.rb b/spec/unit/provider/package/msu_spec.rb
new file mode 100644
index 0000000000..b9091d757a
--- /dev/null
+++ b/spec/unit/provider/package/msu_spec.rb
@@ -0,0 +1,283 @@
+#
+# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::Package::Msu, :windows_only do
+ let(:timeout) {}
+
+ let(:new_resource) { Chef::Resource::MsuPackage.new("windows_test_pkg") }
+
+ let(:provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::Package::Msu.new(new_resource, run_context)
+ end
+
+ let(:installed_package_list_stdout) do
+ <<-EOF
+Packages listing:
+Package Identity : Package_for_KB2999486~31bf3856ad364e35~amd64~~6.1.9768.0
+Package Identity : Package_for_KB2994825~31bf3856ad364e35~amd64~~6.1.7601.0
+ EOF
+ end
+
+ let(:package_version_stdout) do
+ <<-EOF
+Package information:
+Package Identity : Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0
+State : Installed
+Dependency : Language Pack
+The operation completed successfully
+ EOF
+ end
+
+ let(:get_package_info_stdout) do
+ <<-EOF
+Deployment Image Servicing and Management tool
+Version: 6.1.7600.16385
+
+Image Version: 6.1.7600.16385
+
+Package information:
+Package Identity : Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0
+Applicable : Yes
+Copyright : Microsoft Corporation
+Company : Microsoft Corporation
+State : Installed
+Dependency : Language Pack
+The operation completed successfully
+ EOF
+ end
+
+ def allow_get_packages
+ get_packages_stdout = <<-EOF
+Deployment Image Servicing and Management tool
+Version: 6.1.7600.16385
+
+Image Version: 6.1.7600.16385
+
+Packages listing:
+
+Package Identity : Package_for_KB2999486~31bf3856ad364e35~amd64~~6.1.9768.0
+State : Installed
+Release Type : Language Pack
+Install Time : 2/11/2015 11:33 PM
+
+Package Identity : Package_for_KB2994825~31bf3856ad364e35~amd64~~6.1.7601.0
+State : Installed
+Release Type : Language Pack
+Install Time : 2/11/2015 11:33 PM
+
+Package Identity : Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0
+State : Installed
+Release Type : Feature Pack
+Install Time : 11/21/2010 3:40 AM
+
+The operation completed successfully.
+ EOF
+ get_packages_obj = double(stdout: get_packages_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-Packages").and_return(get_packages_obj)
+ end
+
+ before do
+ allow(Dir).to receive(:mktmpdir)
+ allow(provider).to receive(:cleanup_after_converge)
+ end
+
+ describe "#initialize" do
+ it "returns the correct class" do
+ expect(provider).to be_kind_of(Chef::Provider::Package::Msu)
+ end
+ end
+
+ describe "#load_current_resource" do
+ before do
+ new_resource.source = "C:\\Temp\\Test6.1-KB2664825-v3-x64.msu"
+ cab_file = "c:\\temp\\test6.1-kb2664825-v3-x64.cab"
+ allow(provider).to receive(:extract_msu_contents)
+ allow(provider).to receive(:read_cab_files_from_xml).and_return([cab_file])
+ installed_package_list_obj = double(stdout: installed_package_list_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-Packages").and_return(installed_package_list_obj)
+ package_version_obj = double(stdout: package_version_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-PackageInfo /PackagePath:\"#{cab_file}\"").and_return(package_version_obj)
+ end
+
+ it "returns a current_resource" do
+ expect(provider.load_current_resource).to be_kind_of(Chef::Resource::MsuPackage)
+ end
+
+ it "sets the current_resource.version to nil when the package is not installed" do
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql([nil])
+ end
+
+ it "calls download_source_file method if source is a URL" do
+ new_resource.source = "https://www.something.com/Test6.1-KB2664825-v3-x64.msu"
+ expect(provider).to receive(:download_source_file)
+ provider.load_current_resource
+ end
+ end
+
+ describe "#source_resource" do
+ before do
+ new_resource.source = "C:\\Temp\\Test6.1-KB2664825-v3-x64.msu"
+ new_resource.cookbook_name = "Msu_package"
+ end
+
+ it "sets the desired parameters of downloades msu file" do
+ allow(provider).to receive(:default_download_cache_path).and_return("C:\\chef\\cache\\package")
+ source_resource = provider.source_resource
+ expect(source_resource.path).to be == "C:\\chef\\cache\\package"
+ expect(source_resource.name).to be == "windows_test_pkg"
+ expect(source_resource.source).to be == [new_resource.source]
+ expect(source_resource.cookbook_name).to be == "Msu_package"
+ expect(source_resource.checksum).to be nil
+ end
+ end
+
+ describe "#default_download_cache_path" do
+ before do
+ new_resource.source = "https://www.something.com/Test6.1-KB2664825-v3-x64.msu"
+ end
+
+ it "returns a clean cache path where the msu file is downloaded" do
+ allow(Chef::FileCache).to receive(:create_cache_path).and_return("C:\\chef\\abc\\package")
+ path = provider.default_download_cache_path
+ expect(path).to be == "C:\\chef\\abc\\package\\Test6.1-KB2664825-v3-x64.msu"
+ end
+ end
+
+ describe "action specs" do
+ before do
+ new_resource.source = "C:\\Temp\\Test6.1-KB2664825-v3-x64.msu"
+ cab_file = "c:\\temp\\test6.1-kb2664825-v3-x64.cab"
+ allow(provider).to receive(:extract_msu_contents)
+ allow(provider).to receive(:read_cab_files_from_xml).and_return([cab_file])
+ installed_package_list_obj = double(stdout: installed_package_list_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-Packages").and_return(installed_package_list_obj)
+ package_version_obj = double(stdout: package_version_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-PackageInfo /PackagePath:\"#{cab_file}\"").and_return(package_version_obj)
+ end
+
+ describe "#action_install" do
+ it "installs package if not already installed" do
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql([nil])
+ expect(provider).to receive(:install_package)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "does not install package if already installed" do
+ get_package_info_obj = double(stdout: get_package_info_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-PackageInfo /PackagePath:\"#{new_resource.source}\"").and_return(get_package_info_obj)
+ allow_get_packages
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-PackageInfo /PackageName:\"Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0\"").and_return(get_package_info_obj)
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql(["6.1.3.0"])
+ expect(provider).not_to receive(:install_package)
+ provider.run_action(:install)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+ end
+
+ describe "#action_remove" do
+ it "does nothing when the package is not present" do
+ provider.load_current_resource
+ expect(provider).not_to receive(:remove_package)
+ provider.run_action(:remove)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "removes packages if package is installed" do
+ get_package_info_obj = double(stdout: get_package_info_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-PackageInfo /PackagePath:\"#{new_resource.source}\"").and_return(get_package_info_obj)
+ allow_get_packages
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-PackageInfo /PackageName:\"Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0\"").and_return(get_package_info_obj)
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql(["6.1.3.0"])
+ expect(provider).to receive(:remove_package)
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated_by_last_action
+ end
+ end
+
+ context "Invalid package source" do
+ def package_version_stdout
+ package_version_stdout = <<-EOF
+
+ Deployment Image Servicing and Management tool
+ Version: 6.1.7600.16385
+
+ Image Version: 6.1.7600.16385
+
+ An error occurred trying to open - c:\\temp\\test6.1-KB2664825-v3-x64.cab Error: 0x80070003
+ Error: 3
+ The system cannot find the path specified.
+ The DISM log file can be found at C:\\Windows\\Logs\\DISM\\dism.log.
+ EOF
+ end
+
+ it "raises error for invalid source path or file" do
+ expect { provider.load_current_resource }.to raise_error(Chef::Exceptions::Package, "DISM: The system cannot find the path or file specified.")
+ end
+ end
+ end
+
+ describe "#extract_msu_contents" do
+ it "extracts the msu contents by using mixlib shellout" do
+ expect(provider).to receive(:shell_out_with_timeout!).with("#{ENV['SYSTEMROOT']}\\system32\\expand.exe -f:* msu_file destination")
+ provider.extract_msu_contents("msu_file", "destination")
+ end
+ end
+
+ describe "#read_cab_files_from_xml" do
+ it "raises error if the xml file is not present" do
+ allow(Dir).to receive(:glob).and_return([])
+ expect { provider.read_cab_files_from_xml("msu_dir") }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ it "parses xml file with single cab file" do
+ xml_file = File.join(CHEF_SPEC_DATA, "sample_msu1.xml")
+ allow(Dir).to receive(:glob).and_return([xml_file])
+ cab_files = provider.read_cab_files_from_xml("msu_dir")
+ expect(cab_files).to eql(["msu_dir/IE10-Windows6.1-KB2859903-x86.CAB"])
+ end
+
+# We couldn't find any msu file with multiple cab files in it.
+# So we are not 100% sure about the structure of XML file in this case
+# The specs below cover 2 possible XML formats
+ context "handles different xml formats for multiple cab files in the msu package" do
+ it "parses xml file with multiple <package> tags" do
+ xml_file = File.join(CHEF_SPEC_DATA, "sample_msu2.xml")
+ allow(Dir).to receive(:glob).and_return([xml_file])
+ cab_files = provider.read_cab_files_from_xml("msu_dir")
+ expect(cab_files).to eql(["msu_dir/IE10-Windows6.1-KB2859903-x86.CAB", "msu_dir/abc.CAB"])
+ end
+
+ it "parses xml file with multiple <servicing> tags" do
+ xml_file = File.join(CHEF_SPEC_DATA, "sample_msu3.xml")
+ allow(Dir).to receive(:glob).and_return([xml_file])
+ cab_files = provider.read_cab_files_from_xml("msu_dir")
+ expect(cab_files).to eql(["msu_dir/IE10-Windows6.1-KB2859903-x86.CAB", "msu_dir/abc.CAB"])
+ end
+ end
+ end
+end
diff --git a/spec/unit/provider/package/openbsd_spec.rb b/spec/unit/provider/package/openbsd_spec.rb
index 8407f83785..20eb85dfcf 100644
--- a/spec/unit/provider/package/openbsd_spec.rb
+++ b/spec/unit/provider/package/openbsd_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Scott Bonds (scott@ggr.com)
-# Copyright:: Copyright (c) 2014 Scott Bonds
+# Copyright:: Copyright 2014-2016, Scott Bonds
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Provider::Package::Openbsd do
let(:node) do
node = Chef::Node.new
- node.default['kernel'] = {'name' => 'OpenBSD', 'release' => '5.5', 'machine' => 'amd64'}
+ node.default["kernel"] = { "name" => "OpenBSD", "release" => "5.5", "machine" => "amd64" }
node
end
@@ -33,79 +33,79 @@ describe Chef::Provider::Package::Openbsd do
Chef::Provider::Package::Openbsd.new(new_resource, run_context)
end
- let(:new_resource) { Chef::Resource::Package.new(name)}
+ let(:new_resource) { Chef::Resource::Package.new(name) }
before(:each) do
- ENV['PKG_PATH'] = nil
+ ENV["PKG_PATH"] = nil
end
describe "install a package" do
- let(:name) { 'ihavetoes' }
- let(:version) {'0.0'}
+ let(:name) { "ihavetoes" }
+ let(:version) { "0.0" }
- context 'when not already installed' do
+ context "when not already installed" do
before do
- allow(provider).to receive(:shell_out!).with("pkg_info -e \"#{name}->0\"", anything()).and_return(instance_double('shellout', :stdout => ''))
+ allow(provider).to receive(:shell_out!).with("pkg_info", "-e", "#{name}->0", anything()).and_return(instance_double("shellout", :stdout => ""))
end
- context 'when there is a single candidate' do
+ context "when there is a single candidate" do
- context 'when source is not provided' do
- it 'should run the installation command' do
- expect(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}\"", anything()).and_return(
- instance_double('shellout', :stdout => "#{name}-#{version}\n"))
+ context "when source is not provided" do
+ it "should run the installation command" do
+ expect(provider).to receive(:shell_out!).with("pkg_info", "-I", name, anything()).and_return(
+ instance_double("shellout", :stdout => "#{name}-#{version}\n"))
expect(provider).to receive(:shell_out!).with(
- "pkg_add -r #{name}-#{version}",
- {:env => {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}, timeout: 900}
- ) {OpenStruct.new :status => true}
+ "pkg_add", "-r", "#{name}-#{version}",
+ { :env => { "PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/" }, timeout: 900 }
+ ) { OpenStruct.new :status => true }
provider.run_action(:install)
end
end
end
- context 'when there are multiple candidates' do
- let(:flavor_a) { 'flavora' }
- let(:flavor_b) { 'flavorb' }
+ context "when there are multiple candidates" do
+ let(:flavor_a) { "flavora" }
+ let(:flavor_b) { "flavorb" }
- context 'if no version is specified' do
- it 'should raise an exception' do
- expect(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}\"", anything()).and_return(
- instance_double('shellout', :stdout => "#{name}-#{version}-#{flavor_a}\n#{name}-#{version}-#{flavor_b}\n"))
+ context "if no version is specified" do
+ it "should raise an exception" do
+ expect(provider).to receive(:shell_out!).with("pkg_info", "-I", name, anything()).and_return(
+ instance_double("shellout", :stdout => "#{name}-#{version}-#{flavor_a}\n#{name}-#{version}-#{flavor_b}\n"))
expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /multiple matching candidates/)
end
end
- context 'if a flavor is specified' do
+ context "if a flavor is specified" do
- let(:flavor) { 'flavora' }
- let(:package_name) {'ihavetoes' }
+ let(:flavor) { "flavora" }
+ let(:package_name) { "ihavetoes" }
let(:name) { "#{package_name}--#{flavor}" }
- context 'if no version is specified' do
- it 'should run the installation command' do
- expect(provider).to receive(:shell_out!).with("pkg_info -e \"#{package_name}->0\"", anything()).and_return(instance_double('shellout', :stdout => ''))
- expect(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}\"", anything()).and_return(
- instance_double('shellout', :stdout => "#{name}-#{version}-#{flavor}\n"))
+ context "if no version is specified" do
+ it "should run the installation command" do
+ expect(provider).to receive(:shell_out!).with("pkg_info", "-e", "#{package_name}->0", anything()).and_return(instance_double("shellout", :stdout => ""))
+ expect(provider).to receive(:shell_out!).with("pkg_info", "-I", name, anything()).and_return(
+ instance_double("shellout", :stdout => "#{name}-#{version}-#{flavor}\n"))
expect(provider).to receive(:shell_out!).with(
- "pkg_add -r #{name}-#{version}-#{flavor}",
- {env: {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}, timeout: 900}
- ) {OpenStruct.new :status => true}
+ "pkg_add", "-r", "#{name}-#{version}-#{flavor}",
+ { env: { "PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/" }, timeout: 900 }
+ ) { OpenStruct.new :status => true }
provider.run_action(:install)
end
end
end
- context 'if a version is specified' do
- it 'should use the flavor from the version' do
- expect(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}-#{version}-#{flavor_b}\"", anything()).and_return(
- instance_double('shellout', :stdout => "#{name}-#{version}-#{flavor_a}\n"))
+ context "if a version is specified" do
+ it "should use the flavor from the version" do
+ expect(provider).to receive(:shell_out!).with("pkg_info", "-I", "#{name}-#{version}-#{flavor_b}", anything()).and_return(
+ instance_double("shellout", :stdout => "#{name}-#{version}-#{flavor_a}\n"))
new_resource.version("#{version}-#{flavor_b}")
expect(provider).to receive(:shell_out!).with(
- "pkg_add -r #{name}-#{version}-#{flavor_b}",
- {env: {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}, timeout: 900}
- ) {OpenStruct.new :status => true}
+ "pkg_add", "-r", "#{name}-#{version}-#{flavor_b}",
+ { env: { "PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/" }, timeout: 900 }
+ ) { OpenStruct.new :status => true }
provider.run_action(:install)
end
end
@@ -115,7 +115,7 @@ describe Chef::Provider::Package::Openbsd do
describe "delete a package" do
before do
- @name = 'ihavetoes'
+ @name = "ihavetoes"
@new_resource = Chef::Resource::Package.new(@name)
@current_resource = Chef::Resource::Package.new(@name)
@provider = Chef::Provider::Package::Openbsd.new(@new_resource, @run_context)
@@ -123,8 +123,8 @@ describe Chef::Provider::Package::Openbsd do
end
it "should run the command to delete the installed package" do
expect(@provider).to receive(:shell_out!).with(
- "pkg_delete #{@name}", env: nil, timeout: 900
- ) {OpenStruct.new :status => true}
+ "pkg_delete", @name, env: nil, timeout: 900
+ ) { OpenStruct.new :status => true }
@provider.remove_package(@name, nil)
end
end
diff --git a/spec/unit/provider/package/pacman_spec.rb b/spec/unit/provider/package/pacman_spec.rb
index fcb9f8a86c..32af9e4bd2 100644
--- a/spec/unit/provider/package/pacman_spec.rb
+++ b/spec/unit/provider/package/pacman_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Jan Zimmek (<jan.zimmek@web.de>)
-# Copyright:: Copyright (c) 2010 Jan Zimmek
+# Copyright:: Copyright 2010-2016, Jan Zimmek
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Package::Pacman do
before(:each) do
@@ -51,7 +51,7 @@ ERR
end
it "should run pacman query with the package name" do
- expect(@provider).to receive(:shell_out).with("pacman -Qi #{@new_resource.package_name}", {timeout: 900}).and_return(@status)
+ expect(@provider).to receive(:shell_out).with("pacman", "-Qi", @new_resource.package_name, { timeout: 900 }).and_return(@status)
@provider.load_current_resource
end
@@ -62,7 +62,6 @@ ERR
it "should set the installed version to nil on the current resource if pacman installed version not exists" do
allow(@provider).to receive(:shell_out).and_return(@status)
- expect(@current_resource).to receive(:version).with(nil).and_return(true)
@provider.load_current_resource
end
@@ -103,7 +102,7 @@ PACMAN
end
it "should use pacman.conf to determine valid repo names for package versions" do
- @pacman_conf = <<-PACMAN_CONF
+ @pacman_conf = <<-PACMAN_CONF
[options]
HoldPkg = pacman glibc
Architecture = auto
@@ -122,7 +121,7 @@ Include = /etc/pacman.d/mirrorlist
PACMAN_CONF
status = double(:stdout => "customrepo nano 1.2.3-4", :exitstatus => 0)
- allow(::File).to receive(:exists?).with("/etc/pacman.conf").and_return(true)
+ allow(::File).to receive(:exist?).with("/etc/pacman.conf").and_return(true)
allow(::File).to receive(:read).with("/etc/pacman.conf").and_return(@pacman_conf)
allow(@provider).to receive(:shell_out).and_return(status)
@@ -152,12 +151,12 @@ PACMAN_CONF
describe Chef::Provider::Package::Pacman, "install_package" do
it "should run pacman install with the package name and version" do
- expect(@provider).to receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar nano", {timeout: 900})
+ expect(@provider).to receive(:shell_out!).with("pacman", "--sync", "--noconfirm", "--noprogressbar", "nano", { timeout: 900 })
@provider.install_package("nano", "1.0")
end
it "should run pacman install with the package name and version and options if specified" do
- expect(@provider).to receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar --debug nano", {timeout: 900})
+ expect(@provider).to receive(:shell_out!).with("pacman", "--sync", "--noconfirm", "--noprogressbar", "--debug", "nano", { timeout: 900 })
allow(@new_resource).to receive(:options).and_return("--debug")
@provider.install_package("nano", "1.0")
@@ -173,12 +172,12 @@ PACMAN_CONF
describe Chef::Provider::Package::Pacman, "remove_package" do
it "should run pacman remove with the package name" do
- expect(@provider).to receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar nano", {timeout: 900})
+ expect(@provider).to receive(:shell_out!).with("pacman", "--remove", "--noconfirm", "--noprogressbar", "nano", { timeout: 900 })
@provider.remove_package("nano", "1.0")
end
it "should run pacman remove with the package name and options if specified" do
- expect(@provider).to receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar --debug nano", {timeout: 900})
+ expect(@provider).to receive(:shell_out!).with("pacman", "--remove", "--noconfirm", "--noprogressbar", "--debug", "nano", { timeout: 900 })
allow(@new_resource).to receive(:options).and_return("--debug")
@provider.remove_package("nano", "1.0")
diff --git a/spec/unit/provider/package/paludis_spec.rb b/spec/unit/provider/package/paludis_spec.rb
index 4ed5dfc003..df0150c8c0 100644
--- a/spec/unit/provider/package/paludis_spec.rb
+++ b/spec/unit/provider/package/paludis_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Vasiliy Tolstov <v.tolstov@selfip.ru>
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
# based on the ips specs
@@ -33,7 +33,7 @@ describe Chef::Provider::Package::Paludis do
@stdin = StringIO.new
@stderr = StringIO.new
- @stdout =<<-PKG_STATUS
+ @stdout = <<-PKG_STATUS
group/ntp 0 accounts
group/ntp 0 installed-accounts
net/ntp 4.2.6_p5-r2 arbor
@@ -42,7 +42,7 @@ user/ntp 0 installed-accounts
net/ntp 4.2.6_p5-r1 installed
PKG_STATUS
@pid = 12345
- @shell_out = OpenStruct.new(:stdout => @stdout,:stdin => @stdin,:stderr => @stderr,:status => @status,:exitstatus => 0)
+ @shell_out = OpenStruct.new(:stdout => @stdout, :stdin => @stdin, :stderr => @stderr, :status => @status, :exitstatus => 0)
end
context "when loading current resource" do
@@ -59,7 +59,7 @@ PKG_STATUS
end
it "should run pkg info with the package name" do
- expect(@provider).to receive(:shell_out!).with("cave -L warning print-ids -M none -m \"#{@new_resource.package_name}\" -f \"%c/%p %v %r\n\"").and_return(@shell_out)
+ expect(@provider).to receive(:shell_out!).with("cave", "-L", "warning", "print-ids", "-M", "none", "-m", @new_resource.package_name, "-f", "%c/%p %v %r\n").and_return(@shell_out)
@provider.load_current_resource
end
@@ -86,14 +86,13 @@ INSTALLED
context "when installing a package" do
it "should run pkg install with the package name and version" do
- expect(@provider).to receive(:shell_out!).with("cave -L warning resolve -x \"=net/ntp-4.2.6_p5-r2\"", {:timeout=>@new_resource.timeout})
+ expect(@provider).to receive(:shell_out!).with("cave", "-L", "warning", "resolve", "-x", "=net/ntp-4.2.6_p5-r2", { :timeout => @new_resource.timeout || 900 })
@provider.install_package("net/ntp", "4.2.6_p5-r2")
end
-
it "should run pkg install with the package name and version and options if specified" do
- expect(@provider).to receive(:shell_out!).with("cave -L warning resolve -x --preserve-world \"=net/ntp-4.2.6_p5-r2\"", {:timeout=>@new_resource.timeout})
- allow(@new_resource).to receive(:options).and_return("--preserve-world")
+ expect(@provider).to receive(:shell_out!).with("cave", "-L", "warning", "resolve", "-x", "--preserve-world", "=net/ntp-4.2.6_p5-r2", { :timeout => @new_resource.timeout || 900 })
+ @new_resource.options "--preserve-world"
@provider.install_package("net/ntp", "4.2.6_p5-r2")
end
@@ -102,7 +101,7 @@ INSTALLED
sys-process/lsof 4.87 arbor
sys-process/lsof 4.87 x86_64
PKG_STATUS
- expect(@provider).to receive(:shell_out!).with("cave -L warning resolve -x \"=sys-process/lsof-4.87\"", {:timeout=>@new_resource.timeout})
+ expect(@provider).to receive(:shell_out!).with("cave", "-L", "warning", "resolve", "-x", "=sys-process/lsof-4.87", { :timeout => @new_resource.timeout || 900 })
@provider.install_package("sys-process/lsof", "4.87")
end
@@ -120,14 +119,14 @@ PKG_STATUS
context "when upgrading a package" do
it "should run pkg install with the package name and version" do
- expect(@provider).to receive(:shell_out!).with("cave -L warning resolve -x \"=net/ntp-4.2.6_p5-r2\"", {:timeout=>@new_resource.timeout})
+ expect(@provider).to receive(:shell_out!).with("cave", "-L", "warning", "resolve", "-x", "=net/ntp-4.2.6_p5-r2", { :timeout => @new_resource.timeout || 900 })
@provider.upgrade_package("net/ntp", "4.2.6_p5-r2")
end
end
context "when uninstalling a package" do
it "should run pkg uninstall with the package name and version" do
- expect(@provider).to receive(:shell_out!).with("cave -L warning uninstall -x \"=net/ntp-4.2.6_p5-r2\"")
+ expect(@provider).to receive(:shell_out!).with("cave", "-L", "warning", "uninstall", "-x", "=net/ntp-4.2.6_p5-r2")
@provider.remove_package("net/ntp", "4.2.6_p5-r2")
end
diff --git a/spec/unit/provider/package/portage_spec.rb b/spec/unit/provider/package/portage_spec.rb
index 55743dbeaf..d77e180181 100644
--- a/spec/unit/provider/package/portage_spec.rb
+++ b/spec/unit/provider/package/portage_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Caleb Tennis (<caleb.tennis@gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Package::Portage, "load_current_resource" do
before(:each) do
@@ -56,6 +56,12 @@ describe Chef::Provider::Package::Portage, "load_current_resource" do
expect(@provider.current_resource.version).to eq("1.0.0-r1")
end
+ it "should return a current resource with the correct version if the package is found with version with character" do
+ allow(::Dir).to receive(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0d"])
+ @provider.load_current_resource
+ expect(@provider.current_resource.version).to eq("1.0.0d")
+ end
+
it "should return a current resource with a nil version if the package is not found" do
allow(::Dir).to receive(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/notgit-1.0.0"])
@provider.load_current_resource
@@ -278,31 +284,30 @@ EOF
describe Chef::Provider::Package::Portage, "install_package" do
it "should install a normally versioned package using portage" do
- expect(@provider).to receive(:shell_out!).with("emerge -g --color n --nospinner --quiet =dev-util/git-1.0.0")
+ expect(@provider).to receive(:shell_out!).with("emerge", "-g", "--color", "n", "--nospinner", "--quiet", "=dev-util/git-1.0.0")
@provider.install_package("dev-util/git", "1.0.0")
end
it "should install a tilde versioned package using portage" do
- expect(@provider).to receive(:shell_out!).with("emerge -g --color n --nospinner --quiet ~dev-util/git-1.0.0")
+ expect(@provider).to receive(:shell_out!).with("emerge", "-g", "--color", "n", "--nospinner", "--quiet", "~dev-util/git-1.0.0")
@provider.install_package("dev-util/git", "~1.0.0")
end
it "should add options to the emerge command when specified" do
- expect(@provider).to receive(:shell_out!).with("emerge -g --color n --nospinner --quiet --oneshot =dev-util/git-1.0.0")
- allow(@new_resource).to receive(:options).and_return("--oneshot")
-
+ expect(@provider).to receive(:shell_out!).with("emerge", "-g", "--color", "n", "--nospinner", "--quiet", "--oneshot", "=dev-util/git-1.0.0")
+ @new_resource.options "--oneshot"
@provider.install_package("dev-util/git", "1.0.0")
end
end
describe Chef::Provider::Package::Portage, "remove_package" do
it "should un-emerge the package with no version specified" do
- expect(@provider).to receive(:shell_out!).with("emerge --unmerge --color n --nospinner --quiet dev-util/git")
+ expect(@provider).to receive(:shell_out!).with("emerge", "--unmerge", "--color", "n", "--nospinner", "--quiet", "dev-util/git")
@provider.remove_package("dev-util/git", nil)
end
it "should un-emerge the package with a version specified" do
- expect(@provider).to receive(:shell_out!).with("emerge --unmerge --color n --nospinner --quiet =dev-util/git-1.0.0")
+ expect(@provider).to receive(:shell_out!).with("emerge", "--unmerge", "--color", "n", "--nospinner", "--quiet", "=dev-util/git-1.0.0")
@provider.remove_package("dev-util/git", "1.0.0")
end
end
diff --git a/spec/unit/provider/package/powershell_spec.rb b/spec/unit/provider/package/powershell_spec.rb
new file mode 100644
index 0000000000..4ab100f07f
--- /dev/null
+++ b/spec/unit/provider/package/powershell_spec.rb
@@ -0,0 +1,337 @@
+#
+# Author:: Dheeraj Dubey(<dheeraj.dubey@msystechnologies.com>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/mixin/powershell_out"
+
+describe Chef::Provider::Package::Powershell do
+ include Chef::Mixin::PowershellOut
+ let(:timeout) { 900 }
+
+ let(:new_resource) { Chef::Resource::PowershellPackage.new("windows_test_pkg") }
+
+ let(:provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::Package::Powershell.new(new_resource, run_context)
+ end
+
+ let(:package_xcertificate_installed) do
+ double("powershell_out", :stdout => "2.1.0.0\r\n")
+ end
+
+ let(:package_xcertificate_installed_2_0_0_0) do
+ double("powershell_out", :stdout => "2.0.0.0\r\n")
+ end
+
+ let(:package_xcertificate_available) do
+ double("powershell_out", :stdout => "2.1.0.0\r\n")
+ end
+
+ let(:package_xcertificate_available_2_0_0_0) do
+ double("powershell_out", :stdout => "2.0.0.0\r\n")
+ end
+
+ let(:package_xcertificate_not_installed) do
+ double("powershell_out", :stdout => "")
+ end
+
+ let(:package_xcertificate_not_available) do
+ double("powershell_out", :stdout => "")
+ end
+
+ let(:package_xnetworking_installed) do
+ double("powershell_out", :stdout => "2.12.0.0\r\n")
+ end
+
+ let(:package_xnetworking_installed_2_11_0_0) do
+ double("powershell_out", :stdout => "2.11.0.0\r\n")
+ end
+
+ let(:package_xnetworking_available) do
+ double("powershell_out", :stdout => "2.12.0.0\r\n")
+ end
+
+ let(:package_xnetworking_available_2_11_0_0) do
+ double("powershell_out", :stdout => "2.11.0.0\r\n")
+ end
+
+ let(:package_xnetworking_not_installed) do
+ double("powershell_out", :stdout => "")
+ end
+
+ let(:package_xnetworking_not_available) do
+ double("powershell_out", :stdout => "")
+ end
+
+ let(:package_7zip_available) do
+ double("powershell_out", :stdout => "16.02\r\n")
+ end
+
+ let(:package_7zip_not_installed) do
+ double("powershell_out", :stdout => "")
+ end
+
+ let(:powershell_installed_version) do
+ double("powershell_out", :stdout => "5")
+ end
+
+ describe "#initialize" do
+ it "should return the correct class" do
+ expect(provider).to be_kind_of(Chef::Provider::Package::Powershell)
+ end
+ end
+
+ describe "#candidate_version" do
+
+ it "should set the candidate_version to the latest version when not pinning" do
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available)
+ new_resource.package_name(["xNetworking"])
+ new_resource.version(nil)
+ expect(provider.candidate_version).to eql(["2.12.0.0"])
+ end
+
+ it "should set the candidate_version to the latest version when not pinning and package name is space seperated" do
+ allow(provider).to receive(:powershell_out).with("(Find-Package '7-Zip 16.02 (x64)' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_7zip_available)
+ new_resource.package_name(["7-Zip 16.02 (x64)"])
+ new_resource.version(nil)
+ expect(provider.candidate_version).to eql(["16.02"])
+ end
+
+ it "should set the candidate_version to pinned version if available" do
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -RequiredVersion 2.0.0.0 -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available_2_0_0_0)
+ new_resource.package_name(["xCertificate"])
+ new_resource.version(["2.0.0.0"])
+ expect(provider.candidate_version).to eql(["2.0.0.0"])
+ end
+
+ it "should set the candidate_version to nil if there is no candidate" do
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available)
+ new_resource.package_name(["xCertificate"])
+ expect(provider.candidate_version).to eql([nil])
+ end
+
+ it "should set the candidate_version correctly when there are two packages to install" do
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available)
+ new_resource.package_name(%w{xCertificate xNetworking})
+ new_resource.version(nil)
+ expect(provider.candidate_version).to eql(["2.1.0.0", "2.12.0.0"])
+ end
+
+ it "should set the candidate_version correctly when only the first is installable" do
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available)
+ new_resource.package_name(%w{xCertificate xNetworking})
+ new_resource.version(nil)
+ expect(provider.candidate_version).to eql(["2.1.0.0", nil])
+ end
+
+ it "should set the candidate_version correctly when only the last is installable" do
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available)
+ new_resource.package_name(%w{xCertificate xNetworking})
+ new_resource.version(nil)
+ expect(provider.candidate_version).to eql([nil, "2.12.0.0"])
+ end
+
+ it "should set the candidate_version correctly when neither are is installable and version is passed as nil array" do
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available)
+ new_resource.package_name(%w{xNetworking xCertificate})
+ new_resource.version([nil, nil])
+ expect(provider.candidate_version).to eql([nil, nil])
+ end
+
+ it "should set the candidate_version correctly when neither are is installable and version is not passed" do
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available)
+ new_resource.package_name(%w{xNetworking xCertificate})
+ new_resource.version(nil)
+ expect(provider.candidate_version).to eql([nil, nil])
+ end
+
+ end
+
+ describe "#action_install" do
+ it "should install a single package" do
+ provider.load_current_resource
+ new_resource.package_name(["xCertificate"])
+ new_resource.version(nil)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available)
+ allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version)
+ expect(provider).to receive(:powershell_out).with("Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0", { :timeout => new_resource.timeout })
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "should install a single package when package name has space in between" do
+ provider.load_current_resource
+ new_resource.package_name(["7-Zip 16.02 (x64)"])
+ new_resource.version(nil)
+ allow(provider).to receive(:powershell_out).with("(Find-Package '7-Zip 16.02 (x64)' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_7zip_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name '7-Zip 16.02 (x64)' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_7zip_not_installed)
+ allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version)
+ expect(provider).to receive(:powershell_out).with("Install-Package '7-Zip 16.02 (x64)' -Force -ForceBootstrap -RequiredVersion 16.02", { :timeout => new_resource.timeout })
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ context "when changing the timeout to 3600" do
+ let(:timeout) { 3600 }
+ it "sets the timeout on shell_out commands" do
+ new_resource.timeout(timeout)
+ provider.load_current_resource
+ new_resource.package_name(["xCertificate"])
+ new_resource.version(nil)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available)
+ allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version)
+ expect(provider).to receive(:powershell_out).with("Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0", { :timeout => new_resource.timeout })
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+ end
+
+ it "should not install packages that are up-to-date" do
+ new_resource.package_name(["xCertificate"])
+ new_resource.version(nil)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version)
+ provider.load_current_resource
+ expect(provider).not_to receive(:install_package)
+ provider.run_action(:install)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "should not install packages that are up-to-date" do
+ new_resource.package_name(["xNetworking"])
+ new_resource.version(["2.11.0.0"])
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -RequiredVersion 2.11.0.0 -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xNetworking' -RequiredVersion 2.11.0.0 -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available_2_11_0_0)
+ allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version)
+ provider.load_current_resource
+ expect(provider).not_to receive(:install_package)
+ provider.run_action(:install)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "should handle complicated cases when the name/version array is pruned" do
+ # implicitly test that we correctly pick up new_resource.version[1] instead of
+ # new_version.resource[0]
+ new_resource.package_name(%w{xCertificate xNetworking})
+ new_resource.version([nil, "2.11.0.0"])
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -RequiredVersion 2.11.0.0 -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available_2_11_0_0)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xNetworking' -RequiredVersion 2.11.0.0 -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available)
+ allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version)
+ expect(provider).to receive(:powershell_out).with("Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0", { :timeout => new_resource.timeout })
+ expect(provider).to receive(:powershell_out).with("Install-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.11.0.0", { :timeout => new_resource.timeout })
+ provider.load_current_resource
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "should split up commands when given two packages, one with a version pin" do
+ new_resource.package_name(%w{xCertificate xNetworking})
+ new_resource.version(["2.1.0.0", nil])
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -RequiredVersion 2.1.0.0 -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -RequiredVersion 2.1.0.0 -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xNetworking' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available)
+ allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version)
+ expect(provider).to receive(:powershell_out).with("Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0", { :timeout => new_resource.timeout })
+ expect(provider).to receive(:powershell_out).with("Install-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.12.0.0", { :timeout => new_resource.timeout })
+
+ provider.load_current_resource
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "should do multipackage installs when given two packages without constraints" do
+ new_resource.package_name(%w{xCertificate xNetworking})
+ new_resource.version(nil)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xNetworking' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available)
+ allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version)
+ expect(provider).to receive(:powershell_out).with("Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0", { :timeout => new_resource.timeout })
+ expect(provider).to receive(:powershell_out).with("Install-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.12.0.0", { :timeout => new_resource.timeout })
+ provider.load_current_resource
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+ end
+
+ describe "#action_remove" do
+ it "does nothing when the package is already removed" do
+ provider.load_current_resource
+ new_resource.package_name(["xCertificate"])
+ new_resource.version(["2.1.0.0"])
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -RequiredVersion 2.1.0.0 -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -RequiredVersion 2.1.0.0 -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available)
+ allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version)
+ expect(provider).not_to receive(:remove_package)
+ provider.run_action(:remove)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "does nothing when all the packages are already removed" do
+ new_resource.package_name(%w{xCertificate xNetworking})
+ new_resource.version(nil)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xNetworking' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available)
+ allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version)
+ provider.load_current_resource
+ expect(provider).not_to receive(:remove_package)
+ provider.run_action(:remove)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "removes a package when version is specified" do
+ new_resource.package_name(["xCertificate"])
+ new_resource.version(["2.1.0.0"])
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -RequiredVersion 2.1.0.0 -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -RequiredVersion 2.1.0.0 -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version)
+ provider.load_current_resource
+ expect(provider).to receive(:powershell_out).with("Uninstall-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0", { :timeout => new_resource.timeout })
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "removes a package when version is not specified" do
+ new_resource.package_name(["xCertificate"])
+ new_resource.version(nil)
+ allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available)
+ allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version)
+ provider.load_current_resource
+ expect(provider).to receive(:powershell_out).with("(Uninstall-Package 'xCertificate' -Force -ForceBootstrap | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available)
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated_by_last_action
+ end
+ end
+end
diff --git a/spec/unit/provider/package/rpm_spec.rb b/spec/unit/provider/package/rpm_spec.rb
index ad9d694e34..3730878026 100644
--- a/spec/unit/provider/package/rpm_spec.rb
+++ b/spec/unit/provider/package/rpm_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Joshua Timberman (<joshua@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Joshua Timberman (<joshua@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Package::Rpm do
let(:provider) { Chef::Provider::Package::Rpm.new(new_resource, run_context) }
@@ -35,13 +35,13 @@ describe Chef::Provider::Package::Rpm do
end
# `rpm -qp [stuff] $source`
- let(:rpm_qp_status) { instance_double('Mixlib::ShellOut', exitstatus: rpm_qp_exitstatus, stdout: rpm_qp_stdout) }
+ let(:rpm_qp_status) { instance_double("Mixlib::ShellOut", exitstatus: rpm_qp_exitstatus, stdout: rpm_qp_stdout) }
# `rpm -q [stuff] $package_name`
- let(:rpm_q_status) { instance_double('Mixlib::ShellOut', exitstatus: rpm_q_exitstatus, stdout: rpm_q_stdout) }
+ let(:rpm_q_status) { instance_double("Mixlib::ShellOut", exitstatus: rpm_q_exitstatus, stdout: rpm_q_stdout) }
before(:each) do
- allow(::File).to receive(:exists?).with("PLEASE STUB File.exists? EXACTLY").and_return(true)
+ allow(::File).to receive(:exist?).with("PLEASE STUB File.exists? EXACTLY").and_return(true)
# Ensure all shell out usage is stubbed with exact arguments
allow(provider).to receive(:shell_out!).with("PLEASE STUB YOUR SHELLOUT CALLS").and_return(nil)
@@ -61,7 +61,7 @@ describe Chef::Provider::Package::Rpm do
context "when the source is a file that doesn't exist" do
it "should raise an exception when attempting any action" do
- allow(::File).to receive(:exists?).with(package_source).and_return(false)
+ allow(::File).to receive(:exist?).with(package_source).and_return(false)
expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
end
end
@@ -71,7 +71,7 @@ describe Chef::Provider::Package::Rpm do
let(:package_source) { "foobar://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" }
it "should raise an exception if an uri formed source is non-supported scheme" do
- allow(::File).to receive(:exists?).with(package_source).and_return(false)
+ allow(::File).to receive(:exist?).with(package_source).and_return(false)
# verify let bindings are as we expect
expect(new_resource.source).to eq("foobar://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
@@ -86,18 +86,18 @@ describe Chef::Provider::Package::Rpm do
before do
expect(provider).to receive(:shell_out!).
- with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{package_source}", timeout: 900).
+ with("rpm", "-qp", "--queryformat", "%{NAME} %{VERSION}-%{RELEASE}\n", package_source, timeout: 900).
and_return(rpm_qp_status)
expect(provider).to receive(:shell_out).
- with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{package_name}", timeout: 900).
+ with("rpm", "-q", "--queryformat", "%{NAME} %{VERSION}-%{RELEASE}\n", package_name, timeout: 900).
and_return(rpm_q_status)
end
context "when rpm fails when querying package installed state" do
before do
- allow(::File).to receive(:exists?).with(package_source).and_return(true)
+ allow(::File).to receive(:exist?).with(package_source).and_return(true)
end
let(:rpm_qp_stdout) { "ImageMagick-c++ 6.5.4.7-7.el6_5" }
@@ -116,7 +116,6 @@ describe Chef::Provider::Package::Rpm do
end
end
-
context "when the package is installed" do
let(:rpm_qp_stdout) { "ImageMagick-c++ 6.5.4.7-7.el6_5" }
@@ -130,7 +129,7 @@ describe Chef::Provider::Package::Rpm do
context "when the source is a file system path" do
before do
- allow(::File).to receive(:exists?).with(package_source).and_return(true)
+ allow(::File).to receive(:exist?).with(package_source).and_return(true)
provider.action = action
@@ -152,7 +151,7 @@ describe Chef::Provider::Package::Rpm do
context "when at the desired version already" do
it "does nothing when the correct version is installed" do
- expect(provider).to_not receive(:shell_out!).with("rpm -i /tmp/imagemagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ expect(provider).to_not receive(:shell_out!).with("rpm", "-i", "/tmp/imagemagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
provider.action_install
end
@@ -163,7 +162,7 @@ describe Chef::Provider::Package::Rpm do
let(:rpm_q_stdout) { "imagemagick-c++ 0.5.4.7-7.el6_5" }
it "runs rpm -u with the package source to upgrade" do
- expect(provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ expect(provider).to receive(:shell_out!).with("rpm", "-U", "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
provider.action_install
end
end
@@ -179,7 +178,7 @@ describe Chef::Provider::Package::Rpm do
let(:rpm_q_stdout) { "imagemagick-c++ 21.4-19.el6_5" }
it "should run rpm -u --oldpackage with the package source to downgrade" do
- expect(provider).to receive(:shell_out!).with("rpm -U --oldpackage /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ expect(provider).to receive(:shell_out!).with("rpm", "-U", "--oldpackage", "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
provider.action_install
end
@@ -193,7 +192,7 @@ describe Chef::Provider::Package::Rpm do
context "when at the desired version already" do
it "does nothing when the correct version is installed" do
- expect(provider).to_not receive(:shell_out!).with("rpm -i /tmp/imagemagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ expect(provider).to_not receive(:shell_out!).with("rpm", "-i", "/tmp/imagemagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
provider.action_upgrade
end
@@ -204,7 +203,7 @@ describe Chef::Provider::Package::Rpm do
let(:rpm_q_stdout) { "imagemagick-c++ 0.5.4.7-7.el6_5" }
it "runs rpm -u with the package source to upgrade" do
- expect(provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ expect(provider).to receive(:shell_out!).with("rpm", "-U", "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
provider.action_upgrade
end
end
@@ -220,7 +219,7 @@ describe Chef::Provider::Package::Rpm do
let(:rpm_q_stdout) { "imagemagick-c++ 21.4-19.el6_5" }
it "should run rpm -u --oldpackage with the package source to downgrade" do
- expect(provider).to receive(:shell_out!).with("rpm -U --oldpackage /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ expect(provider).to receive(:shell_out!).with("rpm", "-U", "--oldpackage", "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
provider.action_upgrade
end
@@ -232,12 +231,11 @@ describe Chef::Provider::Package::Rpm do
let(:action) { :remove }
it "should remove the package" do
- expect(provider).to receive(:shell_out!).with("rpm -e ImageMagick-c++-6.5.4.7-7.el6_5", timeout: 900)
+ expect(provider).to receive(:shell_out!).with("rpm", "-e", "ImageMagick-c++-6.5.4.7-7.el6_5", timeout: 900)
provider.action_remove
end
end
-
context "when the package name contains a tilde (chef#3503)" do
let(:package_name) { "supermarket" }
@@ -278,7 +276,7 @@ describe Chef::Provider::Package::Rpm do
context "when the source is given as an URI" do
before(:each) do
- allow(::File).to receive(:exists?).with(package_source).and_return(false)
+ allow(::File).to receive(:exist?).with(package_source).and_return(false)
provider.action = action
@@ -287,7 +285,7 @@ describe Chef::Provider::Package::Rpm do
provider.process_resource_requirements
end
- %w(http HTTP https HTTPS ftp FTP file FILE).each do |scheme|
+ %w{http HTTP https HTTPS ftp FTP file FILE}.each do |scheme|
context "when the source URI uses protocol scheme '#{scheme}'" do
@@ -324,7 +322,7 @@ describe Chef::Provider::Package::Rpm do
let(:action) { :install }
before do
- allow(File).to receive(:exists?).with(package_source).and_return(true)
+ allow(File).to receive(:exist?).with(package_source).and_return(true)
provider.action = action
@@ -359,7 +357,7 @@ describe Chef::Provider::Package::Rpm do
describe "action install" do
it "installs the package" do
- expect(provider).to receive(:shell_out!).with("rpm -i #{package_source}", timeout: 900)
+ expect(provider).to receive(:shell_out!).with("rpm", "-i", package_source, timeout: 900)
provider.action_install
end
@@ -367,7 +365,7 @@ describe Chef::Provider::Package::Rpm do
context "when custom resource options are given" do
it "installs with custom options specified in the resource" do
new_resource.options("--dbpath /var/lib/rpm")
- expect(provider).to receive(:shell_out!).with("rpm --dbpath /var/lib/rpm -i #{package_source}", timeout: 900)
+ expect(provider).to receive(:shell_out!).with("rpm", "--dbpath", "/var/lib/rpm", "-i", package_source, timeout: 900)
provider.action_install
end
end
@@ -378,7 +376,7 @@ describe Chef::Provider::Package::Rpm do
let(:action) { :upgrade }
it "installs the package" do
- expect(provider).to receive(:shell_out!).with("rpm -i #{package_source}", timeout: 900)
+ expect(provider).to receive(:shell_out!).with("rpm", "-i", package_source, timeout: 900)
provider.action_upgrade
end
@@ -389,14 +387,13 @@ describe Chef::Provider::Package::Rpm do
let(:action) { :remove }
it "should do nothing" do
- expect(provider).to_not receive(:shell_out!).with("rpm -e ImageMagick-c++-6.5.4.7-7.el6_5", timeout: 900)
+ expect(provider).to_not receive(:shell_out!).with("rpm", "-e", "ImageMagick-c++-6.5.4.7-7.el6_5", timeout: 900)
provider.action_remove
end
end
end
-
end
end
@@ -407,7 +404,7 @@ describe Chef::Provider::Package::Rpm do
# provider will call File.exists?. Because of the ordering in our
# let() bindings and such, we have to set the stub here and not in a
# before block.
- allow(::File).to receive(:exists?).with(package_source).and_return(true)
+ allow(::File).to receive(:exist?).with(package_source).and_return(true)
Chef::Resource::Package.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
end
@@ -416,7 +413,7 @@ describe Chef::Provider::Package::Rpm do
it "should install from a path when the package is a path and the source is nil" do
expect(new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
provider.current_resource = current_resource
- expect(provider).to receive(:shell_out!).with("rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ expect(provider).to receive(:shell_out!).with("rpm", "-i", "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
provider.install_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5")
end
@@ -424,10 +421,9 @@ describe Chef::Provider::Package::Rpm do
expect(new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
current_resource.version("21.4-19.el5")
provider.current_resource = current_resource
- expect(provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ expect(provider).to receive(:shell_out!).with("rpm", "-U", "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
provider.upgrade_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5")
end
end
-
end
diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb
index f790bdb1ce..53c82f2f70 100644
--- a/spec/unit/provider/package/rubygems_spec.rb
+++ b/spec/unit/provider/package/rubygems_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: David Balatero (dbalatero@gmail.com)
#
-# Copyright:: Copyright (c) 2009 David Balatero
+# Copyright:: Copyright 2009-2016, David Balatero
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'pp'
module GemspecBackcompatCreator
def gemspec(name, version)
@@ -28,8 +27,8 @@ module GemspecBackcompatCreator
end
end
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do
include GemspecBackcompatCreator
@@ -43,18 +42,18 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do
end
it "determines the installed versions of gems from Gem.source_index" do
- gems = [gemspec('rspec-core', Gem::Version.new('1.2.9')), gemspec('rspec-core', Gem::Version.new('1.3.0'))]
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0')
- expect(Gem::Specification).to receive(:find_all_by_name).with('rspec-core', Gem::Dependency.new('rspec-core').requirement).and_return(gems)
+ gems = [gemspec("rspec-core", Gem::Version.new("1.2.9")), gemspec("rspec-core", Gem::Version.new("1.3.0"))]
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("1.8.0")
+ expect(Gem::Specification).to receive(:find_all_by_name).with("rspec-core", Gem::Dependency.new("rspec-core").requirement).and_return(gems)
else
- expect(Gem.source_index).to receive(:search).with(Gem::Dependency.new('rspec-core', nil)).and_return(gems)
+ expect(Gem.source_index).to receive(:search).with(Gem::Dependency.new("rspec-core", nil)).and_return(gems)
end
- expect(@gem_env.installed_versions(Gem::Dependency.new('rspec-core', nil))).to eq(gems)
+ expect(@gem_env.installed_versions(Gem::Dependency.new("rspec-core", nil))).to eq(gems)
end
it "determines the installed versions of gems from the source index (part2: the unmockening)" do
- expected = ['rspec-core', Gem::Version.new(RSpec::Core::Version::STRING)]
- actual = @gem_env.installed_versions(Gem::Dependency.new('rspec-core', nil)).map { |spec| [spec.name, spec.version] }
+ expected = ["rspec-core", Gem::Version.new(RSpec::Core::Version::STRING)]
+ actual = @gem_env.installed_versions(Gem::Dependency.new("rspec-core", nil)).map { |spec| [spec.name, spec.version] }
expect(actual).to include(expected)
end
@@ -64,7 +63,7 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do
begin
@gem_env.with_gem_sources("http://gems.example.org") do
sources_in_block = Gem.sources
- raise RuntimeError, "sources should be reset even in case of an error"
+ raise "sources should be reset even in case of an error"
end
rescue RuntimeError
end
@@ -78,7 +77,7 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do
begin
@gem_env.with_gem_sources(nil) do
sources_in_block = Gem.sources
- raise RuntimeError, "sources should be reset even in case of an error"
+ raise "sources should be reset even in case of an error"
end
rescue RuntimeError
end
@@ -86,80 +85,90 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do
expect(Gem.sources).to eq(normal_sources)
end
- it "finds a matching gem candidate version" do
- dep = Gem::Dependency.new('rspec', '>= 0')
- dep_installer = Gem::DependencyInstaller.new
- allow(@gem_env).to receive(:dependency_installer).and_return(dep_installer)
- latest = [[gemspec("rspec", Gem::Version.new("1.3.0")), "https://rubygems.org/"]]
- expect(dep_installer).to receive(:find_gems_with_sources).with(dep).and_return(latest)
- expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0'))).to eq(Gem::Version.new('1.3.0'))
- end
+ context "new default rubygems behavior" do
+ before do
+ Chef::Config[:rubygems_cache_enabled] = false
+ end
- it "finds a matching gem candidate version on rubygems 2.0.0+" do
- dep = Gem::Dependency.new('rspec', '>= 0')
- dep_installer = Gem::DependencyInstaller.new
- allow(@gem_env).to receive(:dependency_installer).and_return(dep_installer)
- best_gem = double("best gem match", :spec => gemspec("rspec", Gem::Version.new("1.3.0")), :source => "https://rubygems.org")
- available_set = double("Gem::AvailableSet test double")
- expect(available_set).to receive(:pick_best!)
- expect(available_set).to receive(:set).and_return([best_gem])
- expect(dep_installer).to receive(:find_gems_with_sources).with(dep).and_return(available_set)
- expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0'))).to eq(Gem::Version.new('1.3.0'))
- end
+ it "finds a matching gem candidate version on rubygems 2.0.0+" do
+ dep = Gem::Dependency.new("rspec", ">= 0")
+ dep_installer = Gem::DependencyInstaller.new
+ allow(@gem_env).to receive(:dependency_installer).and_return(dep_installer)
+ expect(dep_installer).not_to receive(:find_gems_with_sources).with(dep).and_call_original
+ expect(@gem_env.candidate_version_from_remote(dep)).to be_kind_of(Gem::Version)
+ end
- it "gives the candidate version as nil if none is found" do
- dep = Gem::Dependency.new('rspec', '>= 0')
- latest = []
- dep_installer = Gem::DependencyInstaller.new
- allow(@gem_env).to receive(:dependency_installer).and_return(dep_installer)
- expect(dep_installer).to receive(:find_gems_with_sources).with(dep).and_return(latest)
- expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0'))).to be_nil
- end
+ it "gives the candidate version as nil if none is found" do
+ dep = Gem::Dependency.new("lksdjflksdjflsdkfj", ">= 0")
+ dep_installer = Gem::DependencyInstaller.new
+ allow(@gem_env).to receive(:dependency_installer).and_return(dep_installer)
+ expect(dep_installer).not_to receive(:find_gems_with_sources).with(dep).and_call_original
+ expect(@gem_env.candidate_version_from_remote(dep)).to be_nil
+ end
- it "finds a matching candidate version from a .gem file when the path to the gem is supplied" do
- location = CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem'
- expect(@gem_env.candidate_version_from_file(Gem::Dependency.new('chef-integration-test', '>= 0'), location)).to eq(Gem::Version.new('0.1.0'))
- expect(@gem_env.candidate_version_from_file(Gem::Dependency.new('chef-integration-test', '>= 0.2.0'), location)).to be_nil
+ it "finds a matching gem from a specific gemserver when explicit sources are given (to a server that doesn't respond to api requests)" do
+ dep = Gem::Dependency.new("rspec", ">= 0")
+ dep_installer = Gem::DependencyInstaller.new
+ allow(@gem_env).to receive(:dependency_installer).and_return(dep_installer)
+ expect(dep_installer).not_to receive(:find_gems_with_sources).with(dep).and_call_original
+ expect(@gem_env.candidate_version_from_remote(dep, "http://production.cf.rubygems.org")).to be_kind_of(Gem::Version)
+ end
end
- it "finds a matching gem from a specific gemserver when explicit sources are given" do
- dep = Gem::Dependency.new('rspec', '>= 0')
- latest = [[gemspec("rspec", Gem::Version.new("1.3.0")), "https://rubygems.org/"]]
+ context "old rubygems caching behavior" do
+ before do
+ Chef::Config[:rubygems_cache_enabled] = true
+ end
- expect(@gem_env).to receive(:with_gem_sources).with('http://gems.example.com').and_yield
- dep_installer = Gem::DependencyInstaller.new
- allow(@gem_env).to receive(:dependency_installer).and_return(dep_installer)
- expect(dep_installer).to receive(:find_gems_with_sources).with(dep).and_return(latest)
- expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>=0'), 'http://gems.example.com')).to eq(Gem::Version.new('1.3.0'))
+ it "finds a matching gem candidate version on rubygems 2.0.0+" do
+ dep = Gem::Dependency.new("rspec", ">= 0")
+ expect(@gem_env.candidate_version_from_remote(dep)).to be_kind_of(Gem::Version)
+ end
+
+ it "gives the candidate version as nil if none is found" do
+ dep = Gem::Dependency.new("lksdjflksdjflsdkfj", ">= 0")
+ expect(@gem_env.candidate_version_from_remote(dep)).to be_nil
+ end
+
+ it "finds a matching gem from a specific gemserver when explicit sources are given" do
+ dep = Gem::Dependency.new("rspec", ">= 0")
+ expect(@gem_env.candidate_version_from_remote(dep, "http://production.cf.rubygems.org")).to be_kind_of(Gem::Version)
+ end
+ end
+
+ it "finds a matching candidate version from a .gem file when the path to the gem is supplied" do
+ location = CHEF_SPEC_DATA + "/gems/chef-integration-test-0.1.0.gem"
+ expect(@gem_env.candidate_version_from_file(Gem::Dependency.new("chef-integration-test", ">= 0"), location)).to eq(Gem::Version.new("0.1.0"))
+ expect(@gem_env.candidate_version_from_file(Gem::Dependency.new("chef-integration-test", ">= 0.2.0"), location)).to be_nil
end
it "installs a gem with a hash of options for the dependency installer" do
dep_installer = Gem::DependencyInstaller.new
- expect(@gem_env).to receive(:dependency_installer).with(:install_dir => '/foo/bar').and_return(dep_installer)
- expect(@gem_env).to receive(:with_gem_sources).with('http://gems.example.com').and_yield
- expect(dep_installer).to receive(:install).with(Gem::Dependency.new('rspec', '>= 0'))
- @gem_env.install(Gem::Dependency.new('rspec', '>= 0'), :install_dir => '/foo/bar', :sources => ['http://gems.example.com'])
+ expect(@gem_env).to receive(:dependency_installer).with(install_dir: "/foo/bar").and_return(dep_installer)
+ expect(@gem_env).to receive(:with_gem_sources).with("http://gems.example.com").and_yield
+ expect(dep_installer).to receive(:install).with(Gem::Dependency.new("rspec", ">= 0"))
+ @gem_env.install(Gem::Dependency.new("rspec", ">= 0"), install_dir: "/foo/bar", sources: ["http://gems.example.com"])
end
it "builds an uninstaller for a gem with options set to avoid requiring user input" do
# default options for uninstaller should be:
# :ignore => true, :executables => true
- expect(Gem::Uninstaller).to receive(:new).with('rspec', :ignore => true, :executables => true)
- @gem_env.uninstaller('rspec')
+ expect(Gem::Uninstaller).to receive(:new).with("rspec", ignore: true, executables: true)
+ @gem_env.uninstaller("rspec")
end
it "uninstalls all versions of a gem" do
- uninstaller = double('gem uninstaller')
+ uninstaller = double("gem uninstaller")
expect(uninstaller).to receive(:uninstall)
- expect(@gem_env).to receive(:uninstaller).with('rspec', :all => true).and_return(uninstaller)
- @gem_env.uninstall('rspec')
+ expect(@gem_env).to receive(:uninstaller).with("rspec", all: true).and_return(uninstaller)
+ @gem_env.uninstall("rspec")
end
it "uninstalls a specific version of a gem" do
- uninstaller = double('gem uninstaller')
+ uninstaller = double("gem uninstaller")
expect(uninstaller).to receive(:uninstall)
- expect(@gem_env).to receive(:uninstaller).with('rspec', :version => '1.2.3').and_return(uninstaller)
- @gem_env.uninstall('rspec', '1.2.3')
+ expect(@gem_env).to receive(:uninstaller).with("rspec", version: "1.2.3").and_return(uninstaller)
+ @gem_env.uninstall("rspec", "1.2.3")
end
end
@@ -170,72 +179,72 @@ describe Chef::Provider::Package::Rubygems::AlternateGemEnvironment do
before do
Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache.clear
Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache.clear
- @gem_env = Chef::Provider::Package::Rubygems::AlternateGemEnvironment.new('/usr/weird/bin/gem')
+ @gem_env = Chef::Provider::Package::Rubygems::AlternateGemEnvironment.new("/usr/weird/bin/gem")
end
it "determines the gem paths from shelling out to gem env" do
- gem_env_output = ['/path/to/gems', '/another/path/to/gems'].join(File::PATH_SEPARATOR)
- shell_out_result = OpenStruct.new(:stdout => gem_env_output)
- expect(@gem_env).to receive(:shell_out!).with('/usr/weird/bin/gem env gempath').and_return(shell_out_result)
- expect(@gem_env.gem_paths).to eq(['/path/to/gems', '/another/path/to/gems'])
+ gem_env_output = ["/path/to/gems", "/another/path/to/gems"].join(File::PATH_SEPARATOR)
+ shell_out_result = OpenStruct.new(stdout: gem_env_output)
+ expect(@gem_env).to receive(:shell_out!).with("/usr/weird/bin/gem env gempath").and_return(shell_out_result)
+ expect(@gem_env.gem_paths).to eq(["/path/to/gems", "/another/path/to/gems"])
end
it "caches the gempaths by gem_binary" do
- gem_env_output = ['/path/to/gems', '/another/path/to/gems'].join(File::PATH_SEPARATOR)
- shell_out_result = OpenStruct.new(:stdout => gem_env_output)
- expect(@gem_env).to receive(:shell_out!).with('/usr/weird/bin/gem env gempath').and_return(shell_out_result)
- expected = ['/path/to/gems', '/another/path/to/gems']
- expect(@gem_env.gem_paths).to eq(['/path/to/gems', '/another/path/to/gems'])
- expect(Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache['/usr/weird/bin/gem']).to eq(expected)
+ gem_env_output = ["/path/to/gems", "/another/path/to/gems"].join(File::PATH_SEPARATOR)
+ shell_out_result = OpenStruct.new(stdout: gem_env_output)
+ expect(@gem_env).to receive(:shell_out!).with("/usr/weird/bin/gem env gempath").and_return(shell_out_result)
+ expected = ["/path/to/gems", "/another/path/to/gems"]
+ expect(@gem_env.gem_paths).to eq(["/path/to/gems", "/another/path/to/gems"])
+ expect(Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache["/usr/weird/bin/gem"]).to eq(expected)
end
it "uses the cached result for gem paths when available" do
expect(@gem_env).not_to receive(:shell_out!)
- expected = ['/path/to/gems', '/another/path/to/gems']
- Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache['/usr/weird/bin/gem']= expected
- expect(@gem_env.gem_paths).to eq(['/path/to/gems', '/another/path/to/gems'])
+ expected = ["/path/to/gems", "/another/path/to/gems"]
+ Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache["/usr/weird/bin/gem"] = expected
+ expect(@gem_env.gem_paths).to eq(["/path/to/gems", "/another/path/to/gems"])
end
it "builds the gems source index from the gem paths" do
- allow(@gem_env).to receive(:gem_paths).and_return(['/path/to/gems', '/another/path/to/gems'])
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0')
+ allow(@gem_env).to receive(:gem_paths).and_return(["/path/to/gems", "/another/path/to/gems"])
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("1.8.0")
@gem_env.gem_specification
- expect(Gem::Specification.dirs).to eq([ '/path/to/gems/specifications', '/another/path/to/gems/specifications' ])
+ expect(Gem::Specification.dirs).to eq([ "/path/to/gems/specifications", "/another/path/to/gems/specifications" ])
else
- expect(Gem::SourceIndex).to receive(:from_gems_in).with('/path/to/gems/specifications', '/another/path/to/gems/specifications')
+ expect(Gem::SourceIndex).to receive(:from_gems_in).with("/path/to/gems/specifications", "/another/path/to/gems/specifications")
@gem_env.gem_source_index
end
end
it "determines the installed versions of gems from the source index" do
- gems = [gemspec('rspec', Gem::Version.new('1.2.9')), gemspec('rspec', Gem::Version.new('1.3.0'))]
- rspec_dep = Gem::Dependency.new('rspec', nil)
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0')
+ gems = [gemspec("rspec", Gem::Version.new("1.2.9")), gemspec("rspec", Gem::Version.new("1.3.0"))]
+ rspec_dep = Gem::Dependency.new("rspec", nil)
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("1.8.0")
allow(@gem_env).to receive(:gem_specification).and_return(Gem::Specification)
expect(@gem_env.gem_specification).to receive(:find_all_by_name).with(rspec_dep.name, rspec_dep.requirement).and_return(gems)
else
allow(@gem_env).to receive(:gem_source_index).and_return(Gem.source_index)
expect(@gem_env.gem_source_index).to receive(:search).with(rspec_dep).and_return(gems)
end
- expect(@gem_env.installed_versions(Gem::Dependency.new('rspec', nil))).to eq(gems)
+ expect(@gem_env.installed_versions(Gem::Dependency.new("rspec", nil))).to eq(gems)
end
it "determines the installed versions of gems from the source index (part2: the unmockening)" do
allow($stdout).to receive(:write)
path_to_gem = if windows?
- `where gem`.split[1]
- else
- `which gem`.strip
- end
+ `where gem`.split[1]
+ else
+ `which gem`.strip
+ end
skip("cant find your gem executable") if path_to_gem.empty?
gem_env = Chef::Provider::Package::Rubygems::AlternateGemEnvironment.new(path_to_gem)
- expected = ['rspec-core', Gem::Version.new(RSpec::Core::Version::STRING)]
- actual = gem_env.installed_versions(Gem::Dependency.new('rspec-core', nil)).map { |s| [s.name, s.version] }
+ expected = ["rspec-core", Gem::Version.new(RSpec::Core::Version::STRING)]
+ actual = gem_env.installed_versions(Gem::Dependency.new("rspec-core", nil)).map { |s| [s.name, s.version] }
expect(actual).to include(expected)
end
it "detects when the target gem environment is the jruby platform" do
- gem_env_out=<<-JRUBY_GEM_ENV
+ gem_env_out = <<-JRUBY_GEM_ENV
RubyGems Environment:
- RUBYGEMS VERSION: 1.3.6
- RUBY VERSION: 1.8.7 (2010-05-12 patchlevel 249) [java]
@@ -261,23 +270,23 @@ RubyGems Environment:
- REMOTE SOURCES:
- https://rubygems.org/
- http://gems.github.com/
-JRUBY_GEM_ENV
- expect(@gem_env).to receive(:shell_out!).with('/usr/weird/bin/gem env').and_return(double('jruby_gem_env', :stdout => gem_env_out))
- expected = ['ruby', Gem::Platform.new('universal-java-1.6')]
+ JRUBY_GEM_ENV
+ expect(@gem_env).to receive(:shell_out!).with("/usr/weird/bin/gem env").and_return(double("jruby_gem_env", stdout: gem_env_out))
+ expected = ["ruby", Gem::Platform.new("universal-java-1.6")]
expect(@gem_env.gem_platforms).to eq(expected)
# it should also cache the result
- expect(Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache['/usr/weird/bin/gem']).to eq(expected)
+ expect(Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache["/usr/weird/bin/gem"]).to eq(expected)
end
it "uses the cached result for gem platforms if available" do
expect(@gem_env).not_to receive(:shell_out!)
- expected = ['ruby', Gem::Platform.new('universal-java-1.6')]
- Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache['/usr/weird/bin/gem']= expected
+ expected = ["ruby", Gem::Platform.new("universal-java-1.6")]
+ Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache["/usr/weird/bin/gem"] = expected
expect(@gem_env.gem_platforms).to eq(expected)
end
it "uses the current gem platforms when the target env is not jruby" do
- gem_env_out=<<-RBX_GEM_ENV
+ gem_env_out = <<-RBX_GEM_ENV
RubyGems Environment:
- RUBYGEMS VERSION: 1.3.6
- RUBY VERSION: 1.8.7 (2010-05-14 patchlevel 174) [x86_64-apple-darwin10.3.0]
@@ -303,23 +312,23 @@ RubyGems Environment:
- REMOTE SOURCES:
- https://rubygems.org/
- http://gems.github.com/
-RBX_GEM_ENV
- expect(@gem_env).to receive(:shell_out!).with('/usr/weird/bin/gem env').and_return(double('rbx_gem_env', :stdout => gem_env_out))
+ RBX_GEM_ENV
+ expect(@gem_env).to receive(:shell_out!).with("/usr/weird/bin/gem env").and_return(double("rbx_gem_env", stdout: gem_env_out))
expect(@gem_env.gem_platforms).to eq(Gem.platforms)
- expect(Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache['/usr/weird/bin/gem']).to eq(Gem.platforms)
+ expect(Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache["/usr/weird/bin/gem"]).to eq(Gem.platforms)
end
it "yields to a block while masquerading as a different gems platform" do
original_platforms = Gem.platforms
platforms_in_block = nil
begin
- @gem_env.with_gem_platforms(['ruby', Gem::Platform.new('sparc64-java-1.7')]) do
+ @gem_env.with_gem_platforms(["ruby", Gem::Platform.new("sparc64-java-1.7")]) do
platforms_in_block = Gem.platforms
raise "gem platforms should get set to the correct value even when an error occurs"
end
rescue RuntimeError
end
- expect(platforms_in_block).to eq(['ruby', Gem::Platform.new('sparc64-java-1.7')])
+ expect(platforms_in_block).to eq(["ruby", Gem::Platform.new("sparc64-java-1.7")])
expect(Gem.platforms).to eq(original_platforms)
end
@@ -327,357 +336,487 @@ end
describe Chef::Provider::Package::Rubygems do
let(:target_version) { nil }
+ let(:gem_name) { "rspec-core" }
+ let(:gem_binary) { nil }
+ let(:bindir) { "/usr/bin/ruby" }
+ let(:options) { nil }
+ let(:source) { nil }
+
+ let(:new_resource) do
+ new_resource = Chef::Resource::GemPackage.new(gem_name)
+ new_resource.version(target_version)
+ new_resource.gem_binary(gem_binary) if gem_binary
+ new_resource.options(options) if options
+ new_resource.source(source) if source
+ new_resource
+ end
- before(:each) do
- @node = Chef::Node.new
- @new_resource = Chef::Resource::GemPackage.new("rspec-core")
- @spec_version = @new_resource.version(target_version)
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
+ let(:current_resource) { nil }
+ let(:provider) do
+ run_context = Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new)
+ provider = Chef::Provider::Package::Rubygems.new(new_resource, run_context)
+ if current_resource
+ allow(provider).to receive(:load_current_resource)
+ provider.current_resource = current_resource
+ end
+ provider
+ end
+
+ let(:gem_dep) { Gem::Dependency.new(gem_name, target_version) }
+
+ before(:each) do
# We choose detect omnibus via RbConfig::CONFIG['bindir'] in Chef::Provider::Package::Rubygems.new
- allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("/usr/bin/ruby")
+ allow(RbConfig::CONFIG).to receive(:[]).with("bindir").and_return(bindir)
# Rubygems uses this interally
- allow(RbConfig::CONFIG).to receive(:[]).with('arch').and_call_original
- @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
+ allow(RbConfig::CONFIG).to receive(:[]).with("arch").and_call_original
end
describe "when new_resource version is nil" do
let(:target_version) { nil }
it "target_version_already_installed? should return false so that we can search for candidates" do
- @provider.load_current_resource
- expect(@provider.target_version_already_installed?(@provider.current_resource.version, @new_resource.version)).to be_falsey
+ provider.load_current_resource
+ expect(provider.target_version_already_installed?(provider.current_resource.version, new_resource.version)).to be_falsey
end
end
- describe "when new_resource version is current rspec version" do
- let(:target_version) { RSpec::Core::Version::STRING }
+ describe "when new_resource version is an rspec version" do
+ let(:current_version) { RSpec::Core::Version::STRING }
+ let(:target_version) { current_version }
it "triggers a gem configuration load so a later one will not stomp its config values" do
+ _ = provider
# ugly, is there a better way?
expect(Gem.instance_variable_get(:@configuration)).not_to be_nil
end
it "uses the CurrentGemEnvironment implementation when no gem_binary_path is provided" do
- expect(@provider.gem_env).to be_a_kind_of(Chef::Provider::Package::Rubygems::CurrentGemEnvironment)
+ expect(provider.gem_env).to be_a_kind_of(Chef::Provider::Package::Rubygems::CurrentGemEnvironment)
end
- it "uses the AlternateGemEnvironment implementation when a gem_binary_path is provided" do
- @new_resource.gem_binary('/usr/weird/bin/gem')
- provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
- expect(provider.gem_env.gem_binary_location).to eq('/usr/weird/bin/gem')
- end
+ context "when a gem_binary_path is provided" do
+ let(:gem_binary) { "/usr/weird/bin/gem" }
- it "recognizes chef as omnibus" do
- allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("/opt/chef/embedded/bin")
- provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
- expect(provider.is_omnibus?).to be true
- end
+ it "uses the AlternateGemEnvironment implementation when a gem_binary_path is provided" do
+ expect(provider.gem_env.gem_binary_location).to eq(gem_binary)
+ end
- it "recognizes opscode as omnibus" do
- allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("/opt/opscode/embedded/bin")
- provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
- expect(provider.is_omnibus?).to be true
- end
+ context "when you try to use a hash of install options" do
+ let(:options) { { fail: :burger } }
- it "recognizes chefdk as omnibus" do
- allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("/opt/chefdk/embedded/bin")
- provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
- expect(provider.is_omnibus?).to be true
+ it "smites you" do
+ expect { provider }.to raise_error(ArgumentError)
+ end
+ end
end
- it "searches for a gem binary when running on Omnibus on Unix" do
- platform_mock :unix do
- allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("/opt/chef/embedded/bin")
- allow(ENV).to receive(:[]).with('PATH').and_return("/usr/bin:/usr/sbin:/opt/chef/embedded/bin")
- allow(File).to receive(:exists?).with('/usr/bin/gem').and_return(false)
- allow(File).to receive(:exists?).with('/usr/sbin/gem').and_return(true)
- allow(File).to receive(:exists?).with('/opt/chef/embedded/bin/gem').and_return(true) # should not get here
- provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
- expect(provider.gem_env.gem_binary_location).to eq('/usr/sbin/gem')
+ context "when in omnibus opscode" do
+ let(:bindir) { "/opt/opscode/embedded/bin" }
+
+ it "recognizes opscode as omnibus" do
+ expect(provider.is_omnibus?).to be true
end
end
- it "searches for a gem binary when running on Omnibus on Windows" do
- platform_mock :windows do
- allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("d:/opscode/chef/embedded/bin")
- allow(ENV).to receive(:[]).with('PATH').and_return('C:\windows\system32;C:\windows;C:\Ruby186\bin;d:\opscode\chef\embedded\bin')
- allow(File).to receive(:exists?).with('C:\\windows\\system32\\gem').and_return(false)
- allow(File).to receive(:exists?).with('C:\\windows\\gem').and_return(false)
- allow(File).to receive(:exists?).with('C:\\Ruby186\\bin\\gem').and_return(true)
- allow(File).to receive(:exists?).with('d:\\opscode\\chef\\bin\\gem').and_return(false) # should not get here
- allow(File).to receive(:exists?).with('d:\\opscode\\chef\\embedded\\bin\\gem').and_return(false) # should not get here
- provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
- expect(provider.gem_env.gem_binary_location).to eq('C:\Ruby186\bin\gem')
+ context "when in omnibus chefdk" do
+ let(:bindir) { "/opt/chefdk/embedded/bin" }
+
+ it "recognizes chefdk as omnibus" do
+ expect(provider.is_omnibus?).to be true
end
end
- it "smites you when you try to use a hash of install options with an explicit gem binary" do
- @new_resource.gem_binary('/foo/bar')
- @new_resource.options(:fail => :burger)
- expect {Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)}.to raise_error(ArgumentError)
+ context "when in omnibus chef" do
+ let(:bindir) { "/opt/chef/embedded/bin" }
+
+ it "recognizes chef as omnibus" do
+ expect(provider.is_omnibus?).to be true
+ end
+
+ it "searches for a gem binary when running on Omnibus on Unix" do
+ platform_mock :unix do
+ allow(ENV).to receive(:[]).with("PATH").and_return("/usr/bin:/usr/sbin:/opt/chef/embedded/bin")
+ allow(File).to receive(:exist?).with("/usr/bin/gem").and_return(false)
+ allow(File).to receive(:exist?).with("/usr/sbin/gem").and_return(true)
+ allow(File).to receive(:exist?).with("/opt/chef/embedded/bin/gem").and_return(true) # should not get here
+ expect(provider.gem_env.gem_binary_location).to eq("/usr/sbin/gem")
+ end
+ end
+
+ context "when on Windows" do
+ let(:bindir) { "d:/opscode/chef/embedded/bin" }
+
+ it "searches for a gem binary when running on Omnibus on Windows" do
+ platform_mock :windows do
+ allow(ENV).to receive(:[]).with("PATH").and_return('C:\windows\system32;C:\windows;C:\Ruby186\bin;d:\opscode\chef\embedded\bin')
+ allow(File).to receive(:exist?).with('C:\\windows\\system32\\gem').and_return(false)
+ allow(File).to receive(:exist?).with('C:\\windows\\gem').and_return(false)
+ allow(File).to receive(:exist?).with('C:\\Ruby186\\bin\\gem').and_return(true)
+ allow(File).to receive(:exist?).with('d:\\opscode\\chef\\bin\\gem').and_return(false) # should not get here
+ allow(File).to receive(:exist?).with('d:\\opscode\\chef\\embedded\\bin\\gem').and_return(false) # should not get here
+ expect(provider.gem_env.gem_binary_location).to eq('C:\Ruby186\bin\gem')
+ end
+ end
+ end
end
it "converts the new resource into a gem dependency" do
- expect(@provider.gem_dependency).to eq(Gem::Dependency.new('rspec-core', @spec_version))
- @new_resource.version('~> 1.2.0')
- expect(@provider.gem_dependency).to eq(Gem::Dependency.new('rspec-core', '~> 1.2.0'))
+ expect(provider.gem_dependency).to eq(gem_dep)
+ end
+
+ context "when the new resource is not the current version" do
+ let(:target_version) { "~> 9000.0.2" }
+
+ it "converts the new resource into a gem dependency" do
+ expect(provider.gem_dependency).to eq(gem_dep)
+ end
end
describe "when determining the currently installed version" do
+ before do
+ provider.load_current_resource
+ end
it "sets the current version to the version specified by the new resource if that version is installed" do
- @provider.load_current_resource
- expect(@provider.current_resource.version).to eq(@spec_version)
+ expect(provider.current_resource.version).to eq(current_version)
end
- it "sets the current version to the highest installed version if the requested version is not installed" do
- @new_resource.version('9000.0.2')
- @provider.load_current_resource
- expect(@provider.current_resource.version).to eq(@spec_version)
+ context "if the requested version is not installed" do
+ let(:target_version) { "9000.0.2" }
+
+ it "sets the current version to the highest installed version if the requested version is not installed" do
+ expect(provider.current_resource.version).to eq(current_version)
+ end
end
- it "leaves the current version at nil if the package is not installed" do
- @new_resource.package_name("no-such-gem-should-exist-with-this-name")
- @provider.load_current_resource
- expect(@provider.current_resource.version).to be_nil
+ context "if the package is not currently installed" do
+ let(:gem_name) { "no-such-gem-should-exist-with-this-name" }
+
+ it "leaves the current version at nil" do
+ expect(provider.current_resource.version).to be_nil
+ end
end
end
describe "when determining the candidate version to install" do
+ before do
+ provider.load_current_resource
+ end
- it "does not query for available versions when the current version is the target version" do
- @provider.current_resource = @new_resource.dup
- expect(@provider.candidate_version).to be_nil
+ context "when the current version is the target version" do
+ it "does not query for available versions" do
+ # NOTE: odd use case -- we've equality pinned a version, but are calling :upgrade
+ expect(provider.gem_env).not_to receive(:candidate_version_from_remote)
+ expect(provider.gem_env).not_to receive(:install)
+ provider.run_action(:upgrade)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
end
- it "determines the candidate version by querying the remote gem servers" do
- @new_resource.source('http://mygems.example.com')
- @provider.load_current_resource
- @provider.current_resource.version('0.0.1')
- version = Gem::Version.new(@spec_version)
- expect(@provider.gem_env).to receive(:candidate_version_from_remote).
- with(Gem::Dependency.new('rspec-core', @spec_version), "http://mygems.example.com").
- and_return(version)
- expect(@provider.candidate_version).to eq(@spec_version)
+ context "when the current version satisfies the target version requirement" do
+ let(:target_version) { ">= 0" }
+
+ it "does not query for available versions on install" do
+ expect(provider.gem_env).not_to receive(:candidate_version_from_remote)
+ expect(provider.gem_env).not_to receive(:install)
+ provider.run_action(:install)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "queries for available versions on upgrade" do
+ expect(provider.gem_env).to receive(:candidate_version_from_remote)
+ .and_return(Gem::Version.new("9000.0.2"))
+ expect(provider.gem_env).to receive(:install)
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated_by_last_action
+ end
end
- it "parses the gem's specification if the requested source is a file" do
- @new_resource.package_name('chef-integration-test')
- @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @new_resource.version('>= 0')
- @provider.load_current_resource
- expect(@provider.candidate_version).to eq('0.1.0')
+ context "when the requested source is a remote server" do
+ let(:source) { "http://mygems.example.com" }
+
+ it "determines the candidate version by querying the remote gem servers" do
+ expect(provider.gem_env).to receive(:candidate_version_from_remote)
+ .with(gem_dep, source)
+ .and_return(Gem::Version.new(target_version))
+ expect(provider.candidate_version).to eq(target_version)
+ end
end
+ context "when the requested source is a file" do
+ let(:gem_name) { "chef-integration-test" }
+ let(:source) { CHEF_SPEC_DATA + "/gems/chef-integration-test-0.1.0.gem" }
+ let(:target_version) { ">= 0" }
+
+ it "parses the gem's specification" do
+ expect(provider.candidate_version).to eq("0.1.0")
+ end
+ end
end
describe "when installing a gem" do
+ let(:target_version) { "9000.0.2" }
+ let(:current_version) { nil }
+ let(:candidate_version) { "9000.0.2" }
+ let(:current_resource) do
+ current_resource = Chef::Resource::GemPackage.new(gem_name)
+ current_resource.version(current_version)
+ current_resource
+ end
+
before do
- @current_resource = Chef::Resource::GemPackage.new('rspec-core')
- @provider.current_resource = @current_resource
- @gem_dep = Gem::Dependency.new('rspec-core', @spec_version)
- allow(@provider).to receive(:load_current_resource)
+ version = Gem::Version.new(candidate_version)
+ args = [gem_dep]
+ args << source if source
+ allow(provider.gem_env).to receive(:candidate_version_from_remote)
+ .with(*args)
+ .and_return(version)
end
describe "in the current gem environment" do
it "installs the gem via the gems api when no explicit options are used" do
- expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => nil)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ expect(provider.gem_env).to receive(:install).with(gem_dep, sources: nil)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
end
- it "installs the gem via the gems api when a remote source is provided" do
- @new_resource.source('http://gems.example.org')
- sources = ['http://gems.example.org']
- expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => sources)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ context "when a remote source is provided" do
+ let(:source) { "http://gems.example.org" }
+
+ it "installs the gem via the gems api" do
+ expect(provider.gem_env).to receive(:install).with(gem_dep, sources: [source])
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
end
- it "installs the gem from file via the gems api when no explicit options are used" do
- @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- expect(@provider.gem_env).to receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ context "when source is a path" do
+ let(:source) { CHEF_SPEC_DATA + "/gems/chef-integration-test-0.1.0.gem" }
+
+ it "installs the gem from file via the gems api" do
+ expect(provider.gem_env).to receive(:install).with(source)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
end
- it "installs the gem from file via the gems api when the package is a path and the source is nil" do
- @new_resource = Chef::Resource::GemPackage.new(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
- @provider.current_resource = @current_resource
- expect(@new_resource.source).to eq(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- expect(@provider.gem_env).to receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ context "when the gem name is a file path and source is nil" do
+ let(:gem_name) { CHEF_SPEC_DATA + "/gems/chef-integration-test-0.1.0.gem" }
+
+ it "installs the gem from file via the gems api" do
+ expect(new_resource.source).to eq(gem_name)
+ expect(provider.gem_env).to receive(:install).with(gem_name)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
end
# this catches 'gem_package "foo"' when "./foo" is a file in the cwd, and instead of installing './foo' it fetches the remote gem
it "installs the gem via the gems api, when the package has no file separator characters in it, but a matching file exists in cwd" do
- allow(::File).to receive(:exists?).and_return(true)
- @new_resource.package_name('rspec-core')
- expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => nil)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ allow(::File).to receive(:exist?).and_return(true)
+ new_resource.package_name("rspec-core")
+ expect(provider.gem_env).to receive(:install).with(gem_dep, sources: nil)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
end
- it "installs the gem by shelling out when options are provided as a String" do
- @new_resource.options('-i /alt/install/location')
- expected ="gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" -i /alt/install/location"
- expect(@provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ context "when options are provided as a String" do
+ let(:options) { "-i /alt/install/location" }
+
+ it "installs the gem by shelling out when options are provided as a String" do
+ expected = "gem install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" #{options}"
+ expect(provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
end
- it "installs the gem with rubygems.org as an added source" do
- @new_resource.gem_binary('/foo/bar')
- @new_resource.source('http://mirror.ops.rhcloud.com/mirror/ruby')
- expected ="/foo/bar install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" --source=#{@new_resource.source} --source=https://rubygems.org"
- expect(@provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ context "when another source and binary are provided" do
+ let(:source) { "http://mirror.ops.rhcloud.com/mirror/ruby" }
+ let(:gem_binary) { "/foo/bar" }
+
+ it "installs the gem with rubygems.org as an added source" do
+ expected = "#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" --source=#{source} --source=https://rubygems.org"
+ expect(provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
end
- it "installs the gem with cleared sources and explict source when specified" do
- @new_resource.gem_binary('/foo/bar')
- @new_resource.source('http://mirror.ops.rhcloud.com/mirror/ruby')
- @new_resource.clear_sources(true)
- expected ="/foo/bar install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" --clear-sources --source=#{@new_resource.source}"
- expect(@provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ context "when we have cleared sources and an explict source is specified" do
+ let(:gem_binary) { "/foo/bar" }
+ let(:source) { "http://mirror.ops.rhcloud.com/mirror/ruby" }
+
+ it "installs the gem" do
+ new_resource.clear_sources(true)
+ expected = "#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" --clear-sources --source=#{source}"
+ expect(provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
end
context "when no version is given" do
let(:target_version) { nil }
+ let(:options) { "-i /alt/install/location" }
it "installs the gem by shelling out when options are provided but no version is given" do
- @new_resource.options('-i /alt/install/location')
- expected ="gem install rspec-core -q --no-rdoc --no-ri -v \"#{@provider.candidate_version}\" -i /alt/install/location"
- expect(@provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ expected = "gem install rspec-core -q --no-rdoc --no-ri -v \"#{candidate_version}\" #{options}"
+ expect(provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
end
end
- it "installs the gem via the gems api when options are given as a Hash" do
- @new_resource.options(:install_dir => '/alt/install/location')
- expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => nil, :install_dir => '/alt/install/location')
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ context "when options are given as a Hash" do
+ let(:options) { { install_dir: "/alt/install/location" } }
+
+ it "installs the gem via the gems api when options are given as a Hash" do
+ expect(provider.gem_env).to receive(:install).with(gem_dep, { sources: nil }.merge(options))
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
end
describe "at a specific version" do
- before do
- @gem_dep = Gem::Dependency.new('rspec-core', @spec_version)
- end
+ let(:target_version) { "9000.0.2" }
it "installs the gem via the gems api" do
- expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => nil)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ expect(provider.gem_env).to receive(:install).with(gem_dep, sources: nil)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
end
end
- describe "at version specified with comparison operator" do
- it "skips install if current version satisifies requested version" do
- @current_resource.version("2.3.3")
- @new_resource.version(">=2.3.0")
- expect(@provider.gem_env).not_to receive(:install)
- @provider.run_action(:install)
+ describe "at version specified with comparison operator" do
+ context "if current version satisifies requested version" do
+ let(:target_version) { ">=2.3.0" }
+ let(:current_version) { "2.3.3" }
+
+ it "skips the install" do
+ expect(provider.gem_env).not_to receive(:install)
+ provider.run_action(:install)
+ end
+
+ it "performs the upgrade" do
+ expect(provider.gem_env).to receive(:install)
+ provider.run_action(:upgrade)
+ end
end
- it "allows user to specify gem version with fuzzy operator" do
- @current_resource.version("2.3.3")
- @new_resource.version("~>2.3.0")
+ context "if the fuzzy operator is used" do
+ let(:target_version) { "~>2.3.0" }
+ let(:current_version) { "2.3.3" }
- expect(@provider.gem_env).not_to receive(:install)
- @provider.run_action(:install)
+ it "it matches an existing gem" do
+ expect(provider.gem_env).not_to receive(:install)
+ provider.run_action(:install)
+ end
+
+ it "it upgrades an existing gem" do
+ expect(provider.gem_env).to receive(:install)
+ provider.run_action(:upgrade)
+ end
end
end
end
describe "in an alternate gem environment" do
+ let(:gem_binary) { "/usr/weird/bin/gem" }
+
it "installs the gem by shelling out to gem install" do
- @new_resource.gem_binary('/usr/weird/bin/gem')
- expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\"", env: nil, timeout: 900)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ expect(provider).to receive(:shell_out!).with("#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\"", env: nil, timeout: 900)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
end
- it "installs the gem from file by shelling out to gem install" do
- @new_resource.gem_binary('/usr/weird/bin/gem')
- @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @new_resource.version('>= 0')
- expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", env: nil, timeout: 900)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ context "when source is a path" do
+ let(:source) { CHEF_SPEC_DATA + "/gems/chef-integration-test-0.1.0.gem" }
+ let(:target_version) { ">= 0" }
+
+ it "installs the gem by shelling out to gem install" do
+ expect(provider).to receive(:shell_out!).with("#{gem_binary} install #{source} -q --no-rdoc --no-ri -v \"#{target_version}\"", env: nil, timeout: 900)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
end
- it "installs the gem from file by shelling out to gem install when the package is a path and the source is nil" do
- @new_resource = Chef::Resource::GemPackage.new(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
- @provider.current_resource = @current_resource
- @new_resource.gem_binary('/usr/weird/bin/gem')
- @new_resource.version('>= 0')
- expect(@new_resource.source).to eq(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", env: nil, timeout: 900)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ context "when the package is a path and source is nil" do
+ let(:gem_name) { CHEF_SPEC_DATA + "/gems/chef-integration-test-0.1.0.gem" }
+ let(:target_version) { ">= 0" }
+
+ it "installs the gem from file by shelling out to gem install when the package is a path and the source is nil" do
+ expect(new_resource.source).to eq(gem_name)
+ expect(provider).to receive(:shell_out!).with("#{gem_binary} install #{gem_name} -q --no-rdoc --no-ri -v \"#{target_version}\"", env: nil, timeout: 900)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
end
end
end
describe "when uninstalling a gem" do
- before do
- @new_resource = Chef::Resource::GemPackage.new("rspec")
- @current_resource = @new_resource.dup
- @current_resource.version('1.2.3')
- @provider.new_resource = @new_resource
- @provider.current_resource = @current_resource
+ let(:gem_name) { "rspec" }
+ let(:current_version) { "1.2.3" }
+ let(:target_version) { nil }
+
+ let(:current_resource) do
+ current_resource = Chef::Resource::GemPackage.new(gem_name)
+ current_resource.version(current_version)
+ current_resource
end
describe "in the current gem environment" do
it "uninstalls via the api when no explicit options are used" do
# pre-reqs for action_remove to actually remove the package:
- expect(@provider.new_resource.version).to be_nil
- expect(@provider.current_resource.version).not_to be_nil
+ expect(provider.new_resource.version).to be_nil
+ expect(provider.current_resource.version).not_to be_nil
# the behavior we're testing:
- expect(@provider.gem_env).to receive(:uninstall).with('rspec', nil)
- @provider.action_remove
+ expect(provider.gem_env).to receive(:uninstall).with("rspec", nil)
+ provider.action_remove
end
- it "uninstalls via the api when options are given as a Hash" do
- # pre-reqs for action_remove to actually remove the package:
- expect(@provider.new_resource.version).to be_nil
- expect(@provider.current_resource.version).not_to be_nil
- # the behavior we're testing:
- @new_resource.options(:install_dir => '/alt/install/location')
- expect(@provider.gem_env).to receive(:uninstall).with('rspec', nil, :install_dir => '/alt/install/location')
- @provider.action_remove
+ context "when options are given as a Hash" do
+ let(:options) { { install_dir: "/alt/install/location" } }
+
+ it "uninstalls via the api" do
+ # pre-reqs for action_remove to actually remove the package:
+ expect(provider.new_resource.version).to be_nil
+ expect(provider.current_resource.version).not_to be_nil
+ # the behavior we're testing:
+ expect(provider.gem_env).to receive(:uninstall).with("rspec", nil, options)
+ provider.action_remove
+ end
end
- it "uninstalls via the gem command when options are given as a String" do
- @new_resource.options('-i /alt/install/location')
- expect(@provider).to receive(:shell_out!).with("gem uninstall rspec -q -x -I -a -i /alt/install/location", env: nil, timeout: 900)
- @provider.action_remove
+ context "when options are given as a String" do
+ let(:options) { "-i /alt/install/location" }
+
+ it "uninstalls via the gem command" do
+ expect(provider).to receive(:shell_out!).with("gem uninstall rspec -q -x -I -a #{options}", env: nil, timeout: 900)
+ provider.action_remove
+ end
end
- it "uninstalls a specific version of a gem when a version is provided" do
- @new_resource.version('1.2.3')
- expect(@provider.gem_env).to receive(:uninstall).with('rspec', '1.2.3')
- @provider.action_remove
+ context "when a version is provided" do
+ let(:target_version) { "1.2.3" }
+
+ it "uninstalls a specific version of a gem" do
+ expect(provider.gem_env).to receive(:uninstall).with("rspec", "1.2.3")
+ provider.action_remove
+ end
end
end
describe "in an alternate gem environment" do
+ let(:gem_binary) { "/usr/weird/bin/gem" }
+
it "uninstalls via the gem command" do
- @new_resource.gem_binary('/usr/weird/bin/gem')
- expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem uninstall rspec -q -x -I -a", env: nil, timeout: 900)
- @provider.action_remove
+ expect(provider).to receive(:shell_out!).with("#{gem_binary} uninstall rspec -q -x -I -a", env: nil, timeout: 900)
+ provider.action_remove
end
end
end
diff --git a/spec/unit/provider/package/smartos_spec.rb b/spec/unit/provider/package/smartos_spec.rb
index 8f2d2bb8ea..51bffa17b6 100644
--- a/spec/unit/provider/package/smartos_spec.rb
+++ b/spec/unit/provider/package/smartos_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Trevor O (trevoro@joyent.com)
# Author:: Yukihiko Sawanobori (sawanoboriyu@higanworks.com)
-# Copyright:: Copyright (c) 2012 Opscode
+# Copyright:: Copyright 2012-2016, Opscode
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
#
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper"))
-require 'ostruct'
+require "ostruct"
describe Chef::Provider::Package::SmartOS, "load_current_resource" do
before(:each) do
@@ -28,7 +28,6 @@ describe Chef::Provider::Package::SmartOS, "load_current_resource" do
@new_resource = Chef::Resource::Package.new("varnish")
@current_resource = Chef::Resource::Package.new("varnish")
-
@status = double("Status", :exitstatus => 0)
@provider = Chef::Provider::Package::SmartOS.new(@new_resource, @run_context)
allow(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
@@ -66,7 +65,6 @@ describe Chef::Provider::Package::SmartOS, "load_current_resource" do
expect(@current_resource.version).to eq(nil)
end
-
end
describe "candidate_version" do
@@ -81,8 +79,8 @@ describe Chef::Provider::Package::SmartOS, "load_current_resource" do
expect(search).to receive(:each_line).
and_yield("something-varnish-1.1.1 something varnish like\n").
and_yield("varnish-2.3.4 actual varnish\n")
- @shell_out = double('shell_out!', :stdout => search)
- expect(@provider).to receive(:shell_out!).with('/opt/local/bin/pkgin', 'se', 'varnish', :env => nil, :returns => [0,1], :timeout=>900).and_return(@shell_out)
+ @shell_out = double("shell_out!", :stdout => search)
+ expect(@provider).to receive(:shell_out!).with("/opt/local/bin/pkgin", "se", "varnish", :env => nil, :returns => [0, 1], :timeout => 900).and_return(@shell_out)
expect(@provider.candidate_version).to eq("2.3.4")
end
@@ -91,8 +89,8 @@ describe Chef::Provider::Package::SmartOS, "load_current_resource" do
expect(search).to receive(:each_line).
and_yield("something-varnish-1.1.1;;something varnish like\n").
and_yield("varnish-2.3.4;;actual varnish\n")
- @shell_out = double('shell_out!', :stdout => search)
- expect(@provider).to receive(:shell_out!).with('/opt/local/bin/pkgin', 'se', 'varnish', :env => nil, :returns => [0,1], :timeout=>900).and_return(@shell_out)
+ @shell_out = double("shell_out!", :stdout => search)
+ expect(@provider).to receive(:shell_out!).with("/opt/local/bin/pkgin", "se", "varnish", :env => nil, :returns => [0, 1], :timeout => 900).and_return(@shell_out)
expect(@provider.candidate_version).to eq("2.3.4")
end
end
@@ -101,8 +99,8 @@ describe Chef::Provider::Package::SmartOS, "load_current_resource" do
it "run pkgin and install the package" do
out = OpenStruct.new(:stdout => nil)
- expect(@provider).to receive(:shell_out!).with("/opt/local/sbin/pkg_info", "-E", "varnish*", {:env => nil, :returns=>[0,1], :timeout=>900}).and_return(@shell_out)
- expect(@provider).to receive(:shell_out!).with("/opt/local/bin/pkgin", "-y", "install", "varnish-2.1.5nb2", {:env=>nil, :timeout=>900}).and_return(out)
+ expect(@provider).to receive(:shell_out!).with("/opt/local/sbin/pkg_info", "-E", "varnish*", { :env => nil, :returns => [0, 1], :timeout => 900 }).and_return(@shell_out)
+ expect(@provider).to receive(:shell_out!).with("/opt/local/bin/pkgin", "-y", "install", "varnish-2.1.5nb2", { :env => nil, :timeout => 900 }).and_return(out)
@provider.load_current_resource
@provider.install_package("varnish", "2.1.5nb2")
end
diff --git a/spec/unit/provider/package/solaris_spec.rb b/spec/unit/provider/package/solaris_spec.rb
index ae6c96da00..2fba2e3a08 100644
--- a/spec/unit/provider/package/solaris_spec.rb
+++ b/spec/unit/provider/package/solaris_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Toomas Pelberg (<toomasp@gmx.net>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Package::Solaris do
before(:each) do
@@ -27,12 +27,12 @@ describe Chef::Provider::Package::Solaris do
@new_resource.source("/tmp/bash.pkg")
@provider = Chef::Provider::Package::Solaris.new(@new_resource, @run_context)
- allow(::File).to receive(:exists?).and_return(true)
+ allow(::File).to receive(:exist?).and_return(true)
end
describe "assessing the current package status" do
before do
- @pkginfo =<<-PKGINFO
+ @pkginfo = <<-PKGINFO
PKGINST: SUNWbash
NAME: GNU Bourne-Again shell (bash)
CATEGORY: system
@@ -46,7 +46,7 @@ INSTDATE: Nov 04 2009 01:02
HOTLINE: Please contact your local service provider
PKGINFO
- @status = double("Status",:stdout => "", :exitstatus => 0)
+ @status = double("Status", :stdout => "", :exitstatus => 0)
end
it "should create a current resource with the name of new_resource" do
@@ -63,7 +63,7 @@ PKGINFO
it "should raise an exception if a source is supplied but not found" do
allow(@provider).to receive(:shell_out).and_return(@status)
- allow(::File).to receive(:exists?).and_return(false)
+ allow(::File).to receive(:exist?).and_return(false)
@provider.load_current_resource
@provider.define_resource_requirements
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Package)
@@ -71,8 +71,8 @@ PKGINFO
it "should get the source package version from pkginfo if provided" do
status = double(:stdout => @pkginfo, :exitstatus => 0)
- expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash", { timeout: 900 }).and_return(status)
- expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash", { timeout: 900 }).and_return(@status)
+ expect(@provider).to receive(:shell_out).with("pkginfo", "-l", "-d", "/tmp/bash.pkg", "SUNWbash", { timeout: 900 }).and_return(status)
+ expect(@provider).to receive(:shell_out).with("pkginfo", "-l", "SUNWbash", { timeout: 900 }).and_return(@status)
@provider.load_current_resource
expect(@provider.current_resource.package_name).to eq("SUNWbash")
@@ -81,8 +81,8 @@ PKGINFO
it "should return the current version installed if found by pkginfo" do
status = double(:stdout => @pkginfo, :exitstatus => 0)
- expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash", { timeout: 900 }).and_return(@status)
- expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash", { timeout: 900 }).and_return(status)
+ expect(@provider).to receive(:shell_out).with("pkginfo", "-l", "-d", "/tmp/bash.pkg", "SUNWbash", { timeout: 900 }).and_return(@status)
+ expect(@provider).to receive(:shell_out).with("pkginfo", "-l", "SUNWbash", { timeout: 900 }).and_return(status)
@provider.load_current_resource
expect(@provider.current_resource.version).to eq("11.10.0,REV=2005.01.08.05.16")
end
@@ -101,8 +101,8 @@ PKGINFO
end
it "should return a current resource with a nil version if the package is not found" do
- expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash", { timeout: 900 }).and_return(@status)
- expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash", { timeout: 900 }).and_return(@status)
+ expect(@provider).to receive(:shell_out).with("pkginfo", "-l", "-d", "/tmp/bash.pkg", "SUNWbash", { timeout: 900 }).and_return(@status)
+ expect(@provider).to receive(:shell_out).with("pkginfo", "-l", "SUNWbash", { timeout: 900 }).and_return(@status)
@provider.load_current_resource
expect(@provider.current_resource.version).to be_nil
end
@@ -132,7 +132,7 @@ PKGINFO
describe "install and upgrade" do
it "should run pkgadd -n -d with the package source to install" do
- expect(@provider).to receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all", { timeout: 900 })
+ expect(@provider).to receive(:shell_out!).with("pkgadd", "-n", "-d", "/tmp/bash.pkg", "all", { timeout: 900 })
@provider.install_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
end
@@ -140,26 +140,26 @@ PKGINFO
@new_resource = Chef::Resource::Package.new("/tmp/bash.pkg")
@provider = Chef::Provider::Package::Solaris.new(@new_resource, @run_context)
expect(@new_resource.source).to eq("/tmp/bash.pkg")
- expect(@provider).to receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all", { timeout: 900 })
+ expect(@provider).to receive(:shell_out!).with("pkgadd", "-n", "-d", "/tmp/bash.pkg", "all", { timeout: 900 })
@provider.install_package("/tmp/bash.pkg", "11.10.0,REV=2005.01.08.05.16")
end
it "should run pkgadd -n -a /tmp/myadmin -d with the package options -a /tmp/myadmin" do
- allow(@new_resource).to receive(:options).and_return("-a /tmp/myadmin")
- expect(@provider).to receive(:shell_out!).with("pkgadd -n -a /tmp/myadmin -d /tmp/bash.pkg all", { timeout: 900 })
+ @new_resource.options "-a /tmp/myadmin"
+ expect(@provider).to receive(:shell_out!).with("pkgadd", "-n", "-a", "/tmp/myadmin", "-d", "/tmp/bash.pkg", "all", { timeout: 900 })
@provider.install_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
end
end
describe "remove" do
it "should run pkgrm -n to remove the package" do
- expect(@provider).to receive(:shell_out!).with("pkgrm -n SUNWbash", { timeout: 900 })
+ expect(@provider).to receive(:shell_out!).with("pkgrm", "-n", "SUNWbash", { timeout: 900 })
@provider.remove_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
end
it "should run pkgrm -n -a /tmp/myadmin with options -a /tmp/myadmin" do
- allow(@new_resource).to receive(:options).and_return("-a /tmp/myadmin")
- expect(@provider).to receive(:shell_out!).with("pkgrm -n -a /tmp/myadmin SUNWbash", { timeout: 900 })
+ @new_resource.options "-a /tmp/myadmin"
+ expect(@provider).to receive(:shell_out!).with("pkgrm", "-n", "-a", "/tmp/myadmin", "SUNWbash", { timeout: 900 })
@provider.remove_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
end
diff --git a/spec/unit/provider/package/windows/exe_spec.rb b/spec/unit/provider/package/windows/exe_spec.rb
new file mode 100644
index 0000000000..f18cbf3dca
--- /dev/null
+++ b/spec/unit/provider/package/windows/exe_spec.rb
@@ -0,0 +1,201 @@
+#
+# Author:: Matt Wrock <matt@mattwrock.com>
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/provider/package/windows/exe"
+
+unless Chef::Platform.windows?
+ class Chef
+ module ReservedNames::Win32
+ class File
+ def version_info
+ nil
+ end
+ end
+ end
+ end
+end
+
+describe Chef::Provider::Package::Windows::Exe do
+ let(:package_name) { "calculator" }
+ let(:resource_source) { "calculator.exe" }
+ let(:new_resource) do
+ new_resource = Chef::Resource::WindowsPackage.new(package_name)
+ new_resource.source(resource_source)
+ new_resource
+ end
+ let(:uninstall_hash) do
+ [{
+ "DisplayVersion" => "outdated",
+ "UninstallString" => File.join("uninst_dir", "uninst_file"),
+ }]
+ end
+ let(:uninstall_entry) do
+ entries = []
+ uninstall_hash.each do |entry|
+ entries.push(Chef::Provider::Package::Windows::RegistryUninstallEntry.new("hive", "key", entry))
+ end
+ entries
+ end
+ let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :nsis, uninstall_entry) }
+
+ before(:each) do
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(true)
+ end
+
+ it "responds to shell_out!" do
+ expect(provider).to respond_to(:shell_out!)
+ end
+
+ describe "expand_options" do
+ it "returns an empty string if passed no options" do
+ expect(provider.expand_options(nil)).to eql ""
+ end
+
+ it "returns a string with a leading space if passed options" do
+ expect(provider.expand_options("--train nope --town no_way")).to eql(" --train nope --town no_way")
+ end
+ end
+
+ describe "installed_version" do
+ it "returns the installed version" do
+ expect(provider.installed_version).to eql(["outdated"])
+ end
+
+ context "no versions installed" do
+ let(:uninstall_hash) { [] }
+
+ it "returns the installed version" do
+ expect(provider.installed_version).to eql(nil)
+ end
+ end
+ end
+
+ describe "package_version" do
+ before { new_resource.version(nil) }
+
+ context "source file does not exist" do
+ before do
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
+ end
+
+ it "returns nil" do
+ expect(provider.package_version).to eql(nil)
+ end
+ end
+
+ it "returns the version attribute if given" do
+ new_resource.version("v55555")
+ expect(provider.package_version).to eql("v55555")
+ end
+
+ it "returns nil if no version given" do
+ expect(provider.package_version).to eql(nil)
+ end
+ end
+
+ describe "remove_package" do
+ before do
+ allow(::File).to receive(:exist?).and_return(false)
+ end
+
+ context "no version given and one package installed with unquoted uninstall string" do
+ it "removes installed package and quotes uninstall string" do
+ allow(::File).to receive(:exist?).with("uninst_dir/uninst_file").and_return(true)
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"uninst_dir\/uninst_file\" \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+ provider.remove_package
+ end
+ end
+
+ context "When timeout value is passed" do
+ it "removes installed package and quotes uninstall string" do
+ new_resource.timeout = 300
+ allow(::File).to receive(:exist?).with("uninst_dir/uninst_file").and_return(true)
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"uninst_dir\/uninst_file\" \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, :timeout => 300, :returns => [0])
+ provider.remove_package
+ end
+ end
+
+ context "several packages installed with quoted uninstall strings" do
+ let(:uninstall_hash) do
+ [
+ {
+ "DisplayVersion" => "v1",
+ "UninstallString" => "\"#{File.join("uninst_dir1", "uninst_file1")}\"",
+ },
+ {
+ "DisplayVersion" => "v2",
+ "UninstallString" => "\"#{File.join("uninst_dir2", "uninst_file2")}\"",
+ },
+ ]
+ end
+
+ context "version given and installed" do
+ it "removes given version" do
+ new_resource.version("v2")
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"uninst_dir2\/uninst_file2\" \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+ provider.remove_package
+ end
+ end
+
+ context "no version given" do
+ it "removes both versions" do
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"uninst_dir1\/uninst_file1\" \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"uninst_dir2\/uninst_file2\" \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+ provider.remove_package
+ end
+ end
+ end
+ end
+
+ context "installs nsis installer" do
+ let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :nsis, uninstall_entry) }
+
+ it "calls installer with the correct flags" do
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"#{Regexp.quote(new_resource.source)}\" \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+ provider.install_package
+ end
+ end
+
+ context "installs installshield installer" do
+ let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :installshield, uninstall_entry) }
+
+ it "calls installer with the correct flags" do
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"#{Regexp.quote(new_resource.source)}\" \/s \/sms & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+ provider.install_package
+ end
+ end
+
+ context "installs inno installer" do
+ let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :inno, uninstall_entry) }
+
+ it "calls installer with the correct flags" do
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"#{Regexp.quote(new_resource.source)}\" \/VERYSILENT \/SUPPRESSMSGBOXES \/NORESTART & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+ provider.install_package
+ end
+ end
+
+ context "installs wise installer" do
+ let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :wise, uninstall_entry) }
+
+ it "calls installer with the correct flags" do
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"#{Regexp.quote(new_resource.source)}\" \/s & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+ provider.install_package
+ end
+ end
+end
diff --git a/spec/unit/provider/package/windows/msi_spec.rb b/spec/unit/provider/package/windows/msi_spec.rb
index bef202847f..c8099c38d0 100644
--- a/spec/unit/provider/package/windows/msi_spec.rb
+++ b/spec/unit/provider/package/windows/msi_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,38 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
+require "chef/provider/package/windows/msi"
describe Chef::Provider::Package::Windows::MSI do
- let(:node) { double('Chef::Node') }
- let(:events) { double('Chef::Events').as_null_object } # mock all the methods
- let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
- let(:new_resource) { Chef::Resource::WindowsPackage.new("calculator.msi") }
- let(:provider) { Chef::Provider::Package::Windows::MSI.new(new_resource) }
-
- before(:each) do
- stub_const("File::ALT_SEPARATOR", "\\")
- allow(::File).to receive(:absolute_path).with("calculator.msi").and_return("calculator.msi")
+ let(:node) { double("Chef::Node") }
+ let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+ let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
+ let(:package_name) { "calculator" }
+ let(:resource_source) { "calculator.msi" }
+ let(:resource_version) { nil }
+ let(:new_resource) do
+ new_resource = Chef::Resource::WindowsPackage.new(package_name)
+ new_resource.source(resource_source)
+ new_resource.version(resource_version)
+ new_resource
+ end
+ let(:uninstall_hash) do
+ [{
+ "DisplayVersion" => "outdated",
+ "UninstallString" => "MsiExec.exe /X{guid}",
+ }]
+ end
+ let(:uninstall_entry) do
+ entries = []
+ uninstall_hash.each do |entry|
+ entries.push(Chef::Provider::Package::Windows::RegistryUninstallEntry.new("hive", "key", entry))
+ end
+ entries
+ end
+ let(:provider) { Chef::Provider::Package::Windows::MSI.new(new_resource, uninstall_entry) }
+ before do
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(true)
end
it "responds to shell_out!" do
@@ -50,6 +70,11 @@ describe Chef::Provider::Package::Windows::MSI do
allow(provider).to receive(:get_installed_version).with("{23170F69-40C1-2702-0920-000001000000}").and_return("3.14159.1337.42")
expect(provider.installed_version).to eql("3.14159.1337.42")
end
+
+ it "returns the installed version in the registry when install file not present" do
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
+ expect(provider.installed_version).to eql(["outdated"])
+ end
end
describe "package_version" do
@@ -57,19 +82,87 @@ describe Chef::Provider::Package::Windows::MSI do
allow(provider).to receive(:get_product_property).with(/calculator.msi$/, "ProductVersion").and_return(42)
expect(provider.package_version).to eql(42)
end
+
+ context "version is explicitly provided" do
+ let(:resource_version) { "given_version" }
+
+ it "returns the given version" do
+ expect(provider.package_version).to eql("given_version")
+ end
+ end
+
+ context "no source or version is given" do
+ before do
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
+ end
+
+ it "returns nil" do
+ expect(provider.package_version).to eql(nil)
+ end
+ end
end
describe "install_package" do
it "calls msiexec /qn /i" do
- expect(provider).to receive(:shell_out!).with(/msiexec \/qn \/i \"calculator.msi\"/, kind_of(Hash))
- provider.install_package("unused", "unused")
+ expect(provider).to receive(:shell_out!).with(/msiexec \/qn \/i \"#{Regexp.quote(new_resource.source)}\"/, kind_of(Hash))
+ provider.install_package
end
end
describe "remove_package" do
it "calls msiexec /qn /x" do
- expect(provider).to receive(:shell_out!).with(/msiexec \/qn \/x \"calculator.msi\"/, kind_of(Hash))
- provider.remove_package("unused", "unused")
+ expect(provider).to receive(:shell_out!).with(/msiexec \/qn \/x \"#{Regexp.quote(new_resource.source)}\"/, kind_of(Hash))
+ provider.remove_package
+ end
+
+ context "no source is provided" do
+ before do
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
+ end
+
+ it "removes installed package" do
+ expect(provider).to receive(:shell_out!).with(/msiexec \/x {guid} \/q/, kind_of(Hash))
+ provider.remove_package
+ end
+
+ context "there are multiple installs" do
+ let(:uninstall_hash) do
+ [
+ {
+ "DisplayVersion" => "outdated",
+ "UninstallString" => "MsiExec.exe /X{guid}",
+ },
+ {
+ "DisplayVersion" => "really_outdated",
+ "UninstallString" => "MsiExec.exe /X{guid2}",
+ },
+ ]
+ end
+
+ it "removes both installed package" do
+ expect(provider).to receive(:shell_out!).with(/msiexec \/x {guid} \/q/, kind_of(Hash))
+ expect(provider).to receive(:shell_out!).with(/msiexec \/x {guid2} \/q/, kind_of(Hash))
+ provider.remove_package
+ end
+ end
+
+ context "custom options includes /Q" do
+ before { new_resource.options("/Q") }
+
+ it "does not duplicate quiet switch" do
+ expect(provider).to receive(:shell_out!).with(/msiexec \/x {guid} \/Q/, kind_of(Hash))
+ provider.remove_package
+ end
+ end
+
+ context "custom options includes /qn" do
+ before { new_resource.options("/qn") }
+
+ it "does not duplicate quiet switch" do
+ expect(provider).to receive(:shell_out!).with(/msiexec \/x {guid} \/qn/, kind_of(Hash))
+ provider.remove_package
+ end
+ end
end
end
end
diff --git a/spec/unit/provider/package/windows_spec.rb b/spec/unit/provider/package/windows_spec.rb
index e5acc87694..4b258a078f 100644
--- a/spec/unit/provider/package/windows_spec.rb
+++ b/spec/unit/provider/package/windows_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
+require "chef/provider/package/windows/exe"
+require "chef/provider/package/windows/msi"
describe Chef::Provider::Package::Windows, :windows_only do
before(:each) do
@@ -24,26 +26,37 @@ describe Chef::Provider::Package::Windows, :windows_only do
allow(Chef::FileCache).to receive(:create_cache_path).with("package/").and_return(cache_path)
end
- let(:node) { double('Chef::Node') }
- let(:events) { double('Chef::Events').as_null_object } # mock all the methods
- let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
- let(:resource_source) { 'calculator.msi' }
- let(:new_resource) { Chef::Resource::WindowsPackage.new(resource_source) }
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:resource_source) { "calculator.msi" }
+ let(:resource_name) { "calculator" }
+ let(:installer_type) { nil }
+ let(:new_resource) do
+ new_resource = Chef::Resource::WindowsPackage.new(resource_name)
+ new_resource.source(resource_source) if resource_source
+ new_resource.installer_type(installer_type) if installer_type
+ new_resource
+ end
let(:provider) { Chef::Provider::Package::Windows.new(new_resource, run_context) }
let(:cache_path) { 'c:\\cache\\' }
+ before(:each) do
+ allow(::File).to receive(:exist?).with(provider.new_resource.source).and_return(true)
+ end
+
describe "load_current_resource" do
shared_examples "a local file" do
before(:each) do
allow(Chef::Util::PathHelper).to receive(:validate_path)
- allow(provider).to receive(:package_provider).and_return(double('package_provider',
+ allow(provider).to receive(:package_provider).and_return(double("package_provider",
:installed_version => "1.0", :package_version => "2.0"))
end
it "creates a current resource with the name of the new resource" do
provider.load_current_resource
expect(provider.current_resource).to be_a(Chef::Resource::WindowsPackage)
- expect(provider.current_resource.name).to eql(resource_source)
+ expect(provider.current_resource.name).to eql(resource_name)
end
it "sets the current version if the package is installed" do
@@ -58,7 +71,7 @@ describe Chef::Provider::Package::Windows, :windows_only do
end
context "when the source is a uri" do
- let(:resource_source) { 'https://foo.bar/calculator.msi' }
+ let(:resource_source) { "https://foo.bar/calculator.msi" }
context "when the source has not been downloaded" do
before(:each) do
@@ -76,19 +89,6 @@ describe Chef::Provider::Package::Windows, :windows_only do
end
it_behaves_like "a local file"
end
-
- context "when remote_file_attributes are provided" do
- let (:remote_file_attributes) { {:path => 'C:\\foobar.msi'} }
- before(:each) do
- new_resource.remote_file_attributes(remote_file_attributes)
- end
-
- it 'should override the attributes of the remote file resource used' do
- expect(::File).to receive(:exists?).with(remote_file_attributes[:path])
- provider.load_current_resource
- end
-
- end
end
context "when source is a local file" do
@@ -98,8 +98,9 @@ describe Chef::Provider::Package::Windows, :windows_only do
describe "package_provider" do
shared_examples "a local file" do
+
it "checks that the source path is valid" do
- expect(Chef::Util::PathHelper).to receive(:validate_path)
+ expect(Chef::Util::PathHelper).to receive(:validate_path).and_call_original
provider.package_provider
end
@@ -108,14 +109,34 @@ describe Chef::Provider::Package::Windows, :windows_only do
expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::MSI)
end
- it "raises an error if the installer_type is unknown" do
- allow(provider).to receive(:installer_type).and_return(:apt_for_windows)
- expect { provider.package_provider }.to raise_error
+ it "sets the package provider to Exe if the the installer type is :inno" do
+ allow(provider).to receive(:installer_type).and_return(:inno)
+ expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
+ end
+
+ it "sets the package provider to Exe if the the installer type is :nsis" do
+ allow(provider).to receive(:installer_type).and_return(:nsis)
+ expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
+ end
+
+ it "sets the package provider to Exe if the the installer type is :wise" do
+ allow(provider).to receive(:installer_type).and_return(:wise)
+ expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
+ end
+
+ it "sets the package provider to Exe if the the installer type is :installshield" do
+ allow(provider).to receive(:installer_type).and_return(:installshield)
+ expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
+ end
+
+ it "defaults to exe if the installer_type is unknown" do
+ allow(provider).to receive(:installer_type).and_return(nil)
+ expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
end
end
context "when the source is a uri" do
- let(:resource_source) { 'https://foo.bar/calculator.msi' }
+ let(:resource_source) { "https://foo.bar/calculator.msi" }
context "when the source has not been downloaded" do
before(:each) do
@@ -146,20 +167,277 @@ describe Chef::Provider::Package::Windows, :windows_only do
end
describe "installer_type" do
- it "it returns @installer_type if it is set" do
+ let(:resource_source) { "microsoft_installer.exe" }
+
+ context "there is no source" do
+ let(:uninstall_hash) do
+ [{
+ "DisplayVersion" => "outdated",
+ "UninstallString" => "blah blah",
+ }]
+ end
+ let(:uninstall_key) { "blah" }
+ let(:uninstall_entry) do
+ entries = []
+ uninstall_hash.each do |entry|
+ entries.push(Chef::Provider::Package::Windows::RegistryUninstallEntry.new("hive", uninstall_key, entry))
+ end
+ entries
+ end
+
+ before do
+ allow(Chef::Provider::Package::Windows::RegistryUninstallEntry).to receive(:find_entries).and_return(uninstall_entry)
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
+ end
+
+ context "uninstall string contains MsiExec.exe" do
+ let(:uninstall_hash) do
+ [{
+ "DisplayVersion" => "outdated",
+ "UninstallString" => "MsiExec.exe /X{guid}",
+ }]
+ end
+
+ it "sets installer_type to MSI" do
+ expect(provider.installer_type).to eql(:msi)
+ end
+ end
+
+ context "uninstall string ends with uninst.exe" do
+ let(:uninstall_hash) do
+ [{
+ "DisplayVersion" => "outdated",
+ "UninstallString" => %q{"c:/hfhfheru/uninst.exe"},
+ }]
+ end
+
+ it "sets installer_type to NSIS" do
+ expect(provider.installer_type).to eql(:nsis)
+ end
+ end
+
+ context "uninstall key ends in _is1" do
+ let(:uninstall_key) { "blah_is1" }
+
+ it "sets installer_type to inno" do
+ expect(provider.installer_type).to eql(:inno)
+ end
+ end
+
+ context "eninstall entries is empty" do
+ before { allow(Chef::Provider::Package::Windows::RegistryUninstallEntry).to receive(:find_entries).and_return([]) }
+
+ it "returns nil" do
+ expect(provider.installer_type).to eql(nil)
+ end
+ end
+ end
+
+ it "returns @installer_type if it is set" do
provider.new_resource.installer_type(:downeaster)
expect(provider.installer_type).to eql(:downeaster)
end
- it "sets installer_type to msi if the source ends in .msi" do
- provider.new_resource.source("microsoft_installer.msi")
- expect(provider.installer_type).to eql(:msi)
+ it "sets installer_type to inno if the source contains inno" do
+ allow(::Kernel).to receive(:open).and_yield(StringIO.new("blah blah inno blah"))
+ expect(provider.installer_type).to eql(:inno)
+ end
+
+ it "sets installer_type to wise if the source contains wise" do
+ allow(::Kernel).to receive(:open).and_yield(StringIO.new("blah blah wise blah"))
+ expect(provider.installer_type).to eql(:wise)
end
- it "raises an error if it cannot determine the installer type" do
- provider.new_resource.installer_type(nil)
- provider.new_resource.source("tomfoolery.now")
- expect { provider.installer_type }.to raise_error(ArgumentError)
+ it "sets installer_type to nsis if the source contains nsis" do
+ allow(::Kernel).to receive(:open).and_yield(StringIO.new("blah blah nullsoft blah"))
+ expect(provider.installer_type).to eql(:nsis)
+ end
+
+ context "source ends in .msi" do
+ let(:resource_source) { "microsoft_installer.msi" }
+
+ it "sets installer_type to msi" do
+ expect(provider.installer_type).to eql(:msi)
+ end
+ end
+
+ context "the source is setup.exe" do
+ let(:resource_source) { "setup.exe" }
+
+ it "sets installer_type to installshield" do
+ allow(::Kernel).to receive(:open).and_yield(StringIO.new(""))
+ expect(provider.installer_type).to eql(:installshield)
+ end
+ end
+
+ context "cannot determine the installer type" do
+ let(:resource_source) { "tomfoolery.now" }
+
+ it "raises an error" do
+ allow(::Kernel).to receive(:open).and_yield(StringIO.new(""))
+ provider.new_resource.installer_type(nil)
+ expect { provider.installer_type }.to raise_error(Chef::Exceptions::CannotDetermineWindowsInstallerType)
+ end
+ end
+ end
+
+ describe "action_install" do
+ let(:resource_name) { "blah" }
+ let(:resource_source) { "blah.exe" }
+ let(:installer_type) { :inno }
+
+ before do
+ allow_any_instance_of(Chef::Provider::Package::Windows::Exe).to receive(:package_version).and_return(new_resource.version)
+ end
+
+ context "no source given" do
+ let(:resource_source) { nil }
+
+ it "raises a NoWindowsPackageSource error" do
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::NoWindowsPackageSource)
+ end
+
+ context "msi installer_type" do
+ let(:installer_type) { :msi }
+
+ it "does not raise a NoWindowsPackageSource error" do
+ expect(provider).to receive(:install_package)
+ provider.run_action(:install)
+ end
+ end
+ end
+
+ context "http source given and no type given explicitly" do
+ let(:installer_type) { nil }
+ let(:resource_source) { "https://foo.bar/calculator.exe" }
+
+ it "downloads the http resource" do
+ allow(File).to receive(:exist?).with('c:\cache\calculator.exe').and_return(false)
+ expect(provider).to receive(:download_source_file)
+ provider.run_action(:install)
+ end
+ end
+
+ context "no version given, discovered or installed" do
+ it "installs latest" do
+ expect(provider).to receive(:install_package).with("blah", "latest")
+ provider.run_action(:install)
+ end
+ end
+
+ context "no version given or discovered but package is installed" do
+ before { allow(provider).to receive(:current_version_array).and_return(["5.5.5"]) }
+
+ it "does not install" do
+ expect(provider).not_to receive(:install_package)
+ provider.run_action(:install)
+ end
+ end
+
+ context "a version is given and none is installed" do
+ before { new_resource.version("5.5.5") }
+
+ it "installs given version" do
+ expect(provider).to receive(:install_package).with("blah", "5.5.5")
+ provider.run_action(:install)
+ end
+ end
+
+ context "a version is given and several are installed" do
+ context "given version matches an installed version" do
+ before do
+ new_resource.version("5.5.5")
+ allow(provider).to receive(:current_version_array).and_return([ ["5.5.5", "4.3.0", "1.1.1"] ])
+ end
+
+ it "does not install" do
+ expect(provider).not_to receive(:install_package)
+ provider.run_action(:install)
+ end
+ end
+
+ context "given version does not match an installed version" do
+ before do
+ new_resource.version("5.5.5")
+ allow(provider).to receive(:current_version_array).and_return([ ["5.5.0", "4.3.0", "1.1.1"] ])
+ end
+
+ it "installs given version" do
+ expect(provider).to receive(:install_package).with("blah", "5.5.5")
+ provider.run_action(:install)
+ end
+ end
+ end
+
+ context "a version is given and one is installed" do
+ context "given version matches installed version" do
+ before do
+ new_resource.version("5.5.5")
+ allow(provider).to receive(:current_version_array).and_return(["5.5.5"])
+ end
+
+ it "does not install" do
+ expect(provider).not_to receive(:install_package)
+ provider.run_action(:install)
+ end
+ end
+
+ context "given version does not match installed version" do
+ before do
+ new_resource.version("5.5.5")
+ allow(provider).to receive(:current_version_array).and_return(["5.5.0"])
+ end
+
+ it "installs given version" do
+ expect(provider).to receive(:install_package).with("blah", "5.5.5")
+ provider.run_action(:install)
+ end
+ end
+ end
+ end
+
+ shared_context "valid checksum" do
+ context "checksum is valid" do
+ before do
+ allow(provider).to receive(:checksum).and_return("jiie00u3bbs92vsbhvgvklb2lasgh20ah")
+ end
+
+ it "does not raise the checksum mismatch exception" do
+ expect { provider.send(:validate_content!) }.to_not raise_error
+ end
+ end
+ end
+
+ shared_context "invalid checksum" do
+ context "checksum is invalid" do
+ before do
+ allow(provider).to receive(:checksum).and_return("kiie30u3bbs92vsbhvgvklb2lasgh20ah")
+ end
+
+ it "raises the checksum mismatch exception" do
+ expect { provider.send(:validate_content!) }.to raise_error(
+ Chef::Exceptions::ChecksumMismatch)
+ end
+ end
+ end
+
+ describe "validate_content!" do
+ before(:each) do
+ new_resource.checksum("jiie00u3bbs92vsbhvgvklb2lasgh20ah")
+ end
+
+ context "checksum is in lowercase" do
+ include_context "valid checksum"
+ include_context "invalid checksum"
+ end
+
+ context "checksum is in uppercase" do
+ before do
+ new_resource.checksum = new_resource.checksum.upcase
+ end
+
+ include_context "valid checksum"
+ include_context "invalid checksum"
end
end
end
diff --git a/spec/unit/provider/package/yum/yum_cache_spec.rb b/spec/unit/provider/package/yum/yum_cache_spec.rb
new file mode 100644
index 0000000000..e9d615d734
--- /dev/null
+++ b/spec/unit/provider/package/yum/yum_cache_spec.rb
@@ -0,0 +1,27 @@
+#
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::Package::Yum::YumCache do
+
+ it "can find yum-dump.py" do
+ expect(File.exist?(Chef::Provider::Package::Yum::YumCache.instance.yum_dump_path)).to be true
+ end
+
+end
diff --git a/spec/unit/provider/package/yum_spec.rb b/spec/unit/provider/package/yum_spec.rb
index 3fc0b807c9..e0a5f8c862 100644
--- a/spec/unit/provider/package/yum_spec.rb
+++ b/spec/unit/provider/package/yum_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,18 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'securerandom'
+require "spec_helper"
+require "securerandom"
describe Chef::Provider::Package::Yum do
before(:each) do
@node = Chef::Node.new
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::YumPackage.new('cups')
+ @new_resource = Chef::Resource::YumPackage.new("cups")
@status = double("Status", :exitstatus => 0)
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_installed => true,
:reset => true,
:installed_version => "1.2.4-11.18.el5",
@@ -40,6 +40,7 @@ describe Chef::Provider::Package::Yum do
)
allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
allow(@yum_cache).to receive(:yum_binary=).with("yum")
+ allow(::File).to receive(:exist?).with("/usr/bin/yum-deprecated").and_return(false)
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@pid = double("PID")
end
@@ -77,15 +78,16 @@ describe Chef::Provider::Package::Yum do
describe "when source is provided" do
it "should set the candidate version" do
- @new_resource = Chef::Resource::YumPackage.new('testing.source')
+ @new_resource = Chef::Resource::YumPackage.new("testing.source")
@new_resource.source "chef-server-core-12.0.5-1.rpm"
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
- allow(File).to receive(:exists?).with(@new_resource.source).and_return(true)
+ allow(File).to receive(:exist?).with(@new_resource.source).and_return(true)
allow(@yum_cache).to receive(:installed_version).and_return(nil)
- shellout_double = double(:stdout => 'chef-server-core 12.0.5-1')
+ shellout_double = double(:stdout => "chef-server-core 12.0.5-1 i386")
allow(@provider).to receive(:shell_out!).and_return(shellout_double)
@provider.load_current_resource
- expect(@provider.candidate_version).to eql('12.0.5-1')
+ expect(@provider.candidate_version).to eql("12.0.5-1")
+ expect(@provider.new_resource.arch).to eql("i386")
end
end
@@ -94,14 +96,14 @@ describe Chef::Provider::Package::Yum do
expect(File).to receive(:exist?).with("/usr/bin/yum-deprecated").and_return(true)
expect(@yum_cache).to receive(:yum_binary=).with("yum-deprecated")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
- expect(@provider.yum_binary).to eql("yum-deprecated")
+ expect(@provider.send(:yum_binary)).to eql("yum-deprecated")
end
it "when yum-deprecated does not exist" do
expect(File).to receive(:exist?).with("/usr/bin/yum-deprecated").and_return(false)
expect(@yum_cache).to receive(:yum_binary=).with("yum")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
- expect(@provider.yum_binary).to eql("yum")
+ expect(@provider.send(:yum_binary)).to eql("yum")
end
it "when the yum_binary is set on the resource" do
@@ -109,31 +111,31 @@ describe Chef::Provider::Package::Yum do
expect(File).not_to receive(:exist?)
expect(@yum_cache).to receive(:yum_binary=).with("/usr/bin/yum-something")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
- expect(@provider.yum_binary).to eql("/usr/bin/yum-something")
+ expect(@provider.send(:yum_binary)).to eql("/usr/bin/yum-something")
end
it "when the new_resource is a vanilla package class and yum-deprecated exists" do
- @new_resource = Chef::Resource::Package.new('cups')
+ @new_resource = Chef::Resource::YumPackage.new("cups")
expect(File).to receive(:exist?).with("/usr/bin/yum-deprecated").and_return(true)
expect(@yum_cache).to receive(:yum_binary=).with("yum-deprecated")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
- expect(@provider.yum_binary).to eql("yum-deprecated")
+ expect(@provider.send(:yum_binary)).to eql("yum-deprecated")
end
it "when the new_resource is a vanilla package class and yum-deprecated does not exist" do
- @new_resource = Chef::Resource::Package.new('cups')
+ @new_resource = Chef::Resource::YumPackage.new("cups")
expect(File).to receive(:exist?).with("/usr/bin/yum-deprecated").and_return(false)
expect(@yum_cache).to receive(:yum_binary=).with("yum")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
- expect(@provider.yum_binary).to eql("yum")
+ expect(@provider.send(:yum_binary)).to eql("yum")
end
end
describe "when arch in package_name" do
it "should set the arch if no existing package_name is found and new_package_name+new_arch is available" do
- @new_resource = Chef::Resource::YumPackage.new('testing.noarch')
+ @new_resource = Chef::Resource::YumPackage.new("testing.noarch")
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache'
+ "Chef::Provider::Yum::YumCache"
)
allow(@yum_cache).to receive(:installed_version) do |package_name, arch|
# nothing installed for package_name/new_package_name
@@ -155,24 +157,22 @@ describe Chef::Provider::Package::Yum do
@provider.load_current_resource
expect(@provider.new_resource.package_name).to eq("testing")
expect(@provider.new_resource.arch).to eq("noarch")
- expect(@provider.arch).to eq("noarch")
- @new_resource = Chef::Resource::YumPackage.new('testing.more.noarch')
+ @new_resource = Chef::Resource::YumPackage.new("testing.more.noarch")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@provider.load_current_resource
expect(@provider.new_resource.package_name).to eq("testing.more")
expect(@provider.new_resource.arch).to eq("noarch")
- expect(@provider.arch).to eq("noarch")
end
describe "when version constraint in package_name" do
it "should set package_version if no existing package_name is found and new_package_name is available" do
- @new_resource = Chef::Resource::Package.new('cups = 1.2.4-11.18.el5_2.3')
+ @new_resource = Chef::Resource::YumPackage.new("cups = 1.2.4-11.18.el5_2.3")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
- allow(@yum_cache).to receive(:package_available?) { |pkg| pkg == 'cups' ? true : false }
+ allow(@yum_cache).to receive(:package_available?) { |pkg| pkg == "cups" ? true : false }
allow(@yum_cache).to receive(:packages_from_require) do |pkg|
[Chef::Provider::Package::Yum::RPMDbPackage.new("cups", "1.2.4-11.18.el5_2.3", "noarch", [], false, true, "base"),
- Chef::Provider::Package::Yum::RPMDbPackage.new("cups", "1.2.4-11.18.el5_2.2", "noarch", [], false, true, "base"),]
+ Chef::Provider::Package::Yum::RPMDbPackage.new("cups", "1.2.4-11.18.el5_2.2", "noarch", [], false, true, "base")]
end
expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{checking yum info})
expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{installed version})
@@ -186,9 +186,9 @@ describe Chef::Provider::Package::Yum do
end
it "should not set the arch when an existing package_name is found" do
- @new_resource = Chef::Resource::YumPackage.new('testing.beta3')
+ @new_resource = Chef::Resource::YumPackage.new("testing.beta3")
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache'
+ "Chef::Provider::Yum::YumCache"
)
allow(@yum_cache).to receive(:installed_version) do |package_name, arch|
# installed for package_name
@@ -211,20 +211,18 @@ describe Chef::Provider::Package::Yum do
@provider.load_current_resource
expect(@provider.new_resource.package_name).to eq("testing.beta3")
expect(@provider.new_resource.arch).to eq(nil)
- expect(@provider.arch).to eq(nil)
- @new_resource = Chef::Resource::YumPackage.new('testing.beta3.more')
+ @new_resource = Chef::Resource::YumPackage.new("testing.beta3.more")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@provider.load_current_resource
expect(@provider.new_resource.package_name).to eq("testing.beta3.more")
expect(@provider.new_resource.arch).to eq(nil)
- expect(@provider.arch).to eq(nil)
end
it "should not set the arch when no existing package_name or new_package_name+new_arch is found" do
- @new_resource = Chef::Resource::YumPackage.new('testing.beta3')
+ @new_resource = Chef::Resource::YumPackage.new("testing.beta3")
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache'
+ "Chef::Provider::Yum::YumCache"
)
allow(@yum_cache).to receive(:installed_version) do |package_name, arch|
# nothing installed for package_name/new_package_name
@@ -242,25 +240,23 @@ describe Chef::Provider::Package::Yum do
@provider.load_current_resource
expect(@provider.new_resource.package_name).to eq("testing.beta3")
expect(@provider.new_resource.arch).to eq(nil)
- expect(@provider.arch).to eq(nil)
- @new_resource = Chef::Resource::YumPackage.new('testing.beta3.more')
+ @new_resource = Chef::Resource::YumPackage.new("testing.beta3.more")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@provider.load_current_resource
expect(@provider.new_resource.package_name).to eq("testing.beta3.more")
expect(@provider.new_resource.arch).to eq(nil)
- expect(@provider.arch).to eq(nil)
end
it "should ensure it doesn't clobber an existing arch if passed" do
- @new_resource = Chef::Resource::YumPackage.new('testing.i386')
+ @new_resource = Chef::Resource::YumPackage.new("testing.i386")
@new_resource.arch("x86_64")
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache'
+ "Chef::Provider::Yum::YumCache"
)
- allow(@yum_cache).to receive(:installed_version) do |package_name, arch|
- # nothing installed for package_name/new_package_name
- nil
+ allow(@yum_cache).to receive(:installed_version) do |package_name, arch|
+ # nothing installed for package_name/new_package_name
+ nil
end
allow(@yum_cache).to receive(:candidate_version) do |package_name, arch|
if package_name == "testing.noarch"
@@ -282,13 +278,13 @@ describe Chef::Provider::Package::Yum do
end
it "should flush the cache if :before is true" do
- allow(@new_resource).to receive(:flush_cache).and_return({:after => false, :before => true})
+ allow(@new_resource).to receive(:flush_cache).and_return({ :after => false, :before => true })
expect(@yum_cache).to receive(:reload).once
@provider.load_current_resource
end
it "should flush the cache if :before is false" do
- allow(@new_resource).to receive(:flush_cache).and_return({:after => false, :before => false})
+ allow(@new_resource).to receive(:flush_cache).and_return({ :after => false, :before => false })
expect(@yum_cache).not_to receive(:reload)
@provider.load_current_resource
end
@@ -312,8 +308,9 @@ describe Chef::Provider::Package::Yum do
end
context "when the package name isn't found" do
- let(:yum_cache) { double(
- 'Chef::Provider::Yum::YumCache',
+ let(:yum_cache) do
+ double(
+ "Chef::Provider::Yum::YumCache",
:reload_installed => true,
:reset => true,
:installed_version => "1.0.1.el5",
@@ -322,7 +319,7 @@ describe Chef::Provider::Package::Yum do
:version_available? => true,
:disable_extra_repo_control => true
)
- }
+ end
before do
allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(yum_cache)
@@ -334,61 +331,59 @@ describe Chef::Provider::Package::Yum do
it "should search provides then set package_name to match" do
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@provider.load_current_resource
- expect(@new_resource.package_name).to eq('test-package')
+ expect(@new_resource.package_name).to eq("test-package")
expect(@new_resource.version).to eq(nil)
end
it "should search provides then set version to match if a requirement was passed in the package name" do
- @new_resource = Chef::Resource::YumPackage.new('test-package = 2.0.1.el5')
+ @new_resource = Chef::Resource::YumPackage.new("test-package = 2.0.1.el5")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@provider.load_current_resource
- expect(@new_resource.package_name).to eq('test-package')
- expect(@new_resource.version).to eq('2.0.1.el5')
+ expect(@new_resource.package_name).to eq("test-package")
+ expect(@new_resource.version).to eq("2.0.1.el5")
end
-
it "should search provides then set version to match if a requirement was passed in the version" do
- @new_resource = Chef::Resource::YumPackage.new('test-package')
- @new_resource.version('= 2.0.1.el5')
+ @new_resource = Chef::Resource::YumPackage.new("test-package")
+ @new_resource.version("= 2.0.1.el5")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@provider.load_current_resource
- expect(@new_resource.package_name).to eq('test-package')
- expect(@new_resource.version).to eq('2.0.1.el5')
+ expect(@new_resource.package_name).to eq("test-package")
+ expect(@new_resource.version).to eq("2.0.1.el5")
end
-
it "should search provides and not set the version to match if a specific version was requested" do
- @new_resource = Chef::Resource::YumPackage.new('test-package')
- @new_resource.version('3.0.1.el5')
+ @new_resource = Chef::Resource::YumPackage.new("test-package")
+ @new_resource.version("3.0.1.el5")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@provider.load_current_resource
- expect(@new_resource.package_name).to eq('test-package')
- expect(@new_resource.version).to eq('3.0.1.el5')
+ expect(@new_resource.package_name).to eq("test-package")
+ expect(@new_resource.version).to eq("3.0.1.el5")
end
it "should search provides then set versions to match if requirements were passed in the package name as an array" do
- @new_resource = Chef::Resource::YumPackage.new(['test-package = 2.0.1.el5'])
+ @new_resource = Chef::Resource::YumPackage.new(["test-package = 2.0.1.el5"])
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@provider.load_current_resource
- expect(@new_resource.package_name).to eq(['test-package'])
- expect(@new_resource.version).to eq(['2.0.1.el5'])
+ expect(@new_resource.package_name).to eq(["test-package"])
+ expect(@new_resource.version).to eq(["2.0.1.el5"])
end
it "should search provides and not set the versions to match if specific versions were requested in an array" do
- @new_resource = Chef::Resource::YumPackage.new(['test-package'])
- @new_resource.version(['3.0.1.el5'])
+ @new_resource = Chef::Resource::YumPackage.new(["test-package"])
+ @new_resource.version(["3.0.1.el5"])
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@provider.load_current_resource
- expect(@new_resource.package_name).to eq(['test-package'])
- expect(@new_resource.version).to eq(['3.0.1.el5'])
+ expect(@new_resource.package_name).to eq(["test-package"])
+ expect(@new_resource.version).to eq(["3.0.1.el5"])
end
end
it "should not return an error if no version number is specified in the resource" do
- @new_resource = Chef::Resource::YumPackage.new('test-package')
+ @new_resource = Chef::Resource::YumPackage.new("test-package")
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_installed => true,
:reset => true,
:installed_version => "1.0.1.el5",
@@ -398,7 +393,7 @@ describe Chef::Provider::Package::Yum do
:disable_extra_repo_control => true
)
allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
- allow(@yum_cache).to receive(:yum_binary=).with("yum")
+ allow(@yum_cache).to receive(:yum_binary=).with("yum")
pkg = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "2.0.1.el5", "x86_64", [])
expect(@yum_cache).to receive(:packages_from_require).and_return([pkg])
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@@ -408,9 +403,9 @@ describe Chef::Provider::Package::Yum do
end
it "should give precedence to the version attribute when both a requirement in the resource name and a version attribute are specified" do
- @new_resource = Chef::Resource::YumPackage.new('test-package')
+ @new_resource = Chef::Resource::YumPackage.new("test-package")
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_installed => true,
:reset => true,
:installed_version => "1.2.4-11.18.el5",
@@ -420,20 +415,20 @@ describe Chef::Provider::Package::Yum do
:disable_extra_repo_control => true
)
allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
- allow(@yum_cache).to receive(:yum_binary=).with("yum")
+ allow(@yum_cache).to receive(:yum_binary=).with("yum")
pkg = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "2.0.1.el5", "x86_64", [])
expect(@yum_cache).to receive(:packages_from_require).and_return([pkg])
- @new_resource = Chef::Resource::YumPackage.new('test-package = 2.0.1.el5')
- @new_resource.version('3.0.1.el5')
+ @new_resource = Chef::Resource::YumPackage.new("test-package = 2.0.1.el5")
+ @new_resource.version("3.0.1.el5")
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@provider.load_current_resource
- expect(@new_resource.package_name).to eq('test-package')
- expect(@new_resource.version).to eq('3.0.1.el5')
+ expect(@new_resource.package_name).to eq("test-package")
+ expect(@new_resource.version).to eq("3.0.1.el5")
end
it "should correctly detect the installed states of an array of package names and version numbers" do
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_installed => true,
:reset => true,
:installed_version => "1.0.1.el5",
@@ -448,17 +443,17 @@ describe Chef::Provider::Package::Yum do
expect(@yum_cache).to receive(:packages_from_require).exactly(4).times.and_return([])
expect(@yum_cache).to receive(:reload_provides).twice
- @new_resource = Chef::Resource::YumPackage.new(['test-package','test-package2'])
- @new_resource.version(['2.0.1.el5','3.0.1.el5'])
+ @new_resource = Chef::Resource::YumPackage.new(["test-package", "test-package2"])
+ @new_resource.version(["2.0.1.el5", "3.0.1.el5"])
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@provider.load_current_resource
- expect(@new_resource.package_name).to eq(['test-package','test-package2'])
- expect(@new_resource.version).to eq(['2.0.1.el5','3.0.1.el5'])
+ expect(@new_resource.package_name).to eq(["test-package", "test-package2"])
+ expect(@new_resource.version).to eq(["2.0.1.el5", "3.0.1.el5"])
end
it "should search provides if no package is available - if no match in installed provides then load the complete set" do
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_installed => true,
:reset => true,
:installed_version => "1.2.4-11.18.el5",
@@ -478,7 +473,7 @@ describe Chef::Provider::Package::Yum do
it "should search provides if no package is available and not load the complete set if action is :remove or :purge" do
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_installed => true,
:reset => true,
:installed_version => "1.2.4-11.18.el5",
@@ -502,7 +497,7 @@ describe Chef::Provider::Package::Yum do
it "should search provides if no package is available - if no match in provides leave the name intact" do
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_provides => true,
:reload_installed => true,
:reset => true,
@@ -540,8 +535,8 @@ describe Chef::Provider::Package::Yum do
end
it "should run yum localinstall if given a path to an rpm as the package" do
- @new_resource = Chef::Resource::Package.new("/tmp/emacs-21.4-20.el5.i386.rpm")
- allow(::File).to receive(:exists?).and_return(true)
+ @new_resource = Chef::Resource::YumPackage.new("/tmp/emacs-21.4-20.el5.i386.rpm")
+ allow(::File).to receive(:exist?).with("/tmp/emacs-21.4-20.el5.i386.rpm").and_return(true)
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
expect(@new_resource.source).to eq("/tmp/emacs-21.4-20.el5.i386.rpm")
expect(@provider).to receive(:yum_command).with(
@@ -551,9 +546,9 @@ describe Chef::Provider::Package::Yum do
end
it "should run yum install with the package name, version and arch" do
- @provider.load_current_resource
allow(@new_resource).to receive(:arch).and_return("i386")
allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
+ @provider.load_current_resource
expect(@provider).to receive(:yum_command).with(
"-d0 -e0 -y install cups-1.2.4-11.19.el5.i386"
)
@@ -562,7 +557,7 @@ describe Chef::Provider::Package::Yum do
it "installs the package with the options given in the resource" do
@provider.load_current_resource
- allow(@provider).to receive(:candidate_version).and_return('11')
+ allow(@provider).to receive(:candidate_version).and_return("11")
allow(@new_resource).to receive(:options).and_return("--disablerepo epmd")
allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
expect(@provider).to receive(:yum_command).with(
@@ -573,7 +568,7 @@ describe Chef::Provider::Package::Yum do
it "should raise an exception if the package is not available" do
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_from_cache => true,
:reset => true,
:installed_version => "1.2.4-11.18.el5",
@@ -591,7 +586,7 @@ describe Chef::Provider::Package::Yum do
it "should raise an exception if candidate version is older than the installed version and allow_downgrade is false" do
allow(@new_resource).to receive(:allow_downgrade).and_return(false)
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_installed => true,
:reset => true,
:installed_version => "1.2.4-11.18.el5",
@@ -610,7 +605,7 @@ describe Chef::Provider::Package::Yum do
it "should not raise an exception if candidate version is older than the installed version and the package is list in yum's installonlypkg option" do
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_installed => true,
:reset => true,
:installed_version => "1.2.4-11.18.el5",
@@ -634,7 +629,7 @@ describe Chef::Provider::Package::Yum do
it "should run yum downgrade if candidate version is older than the installed version and allow_downgrade is true" do
allow(@new_resource).to receive(:allow_downgrade).and_return(true)
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_installed => true,
:reset => true,
:installed_version => "1.2.4-11.18.el5",
@@ -656,7 +651,7 @@ describe Chef::Provider::Package::Yum do
end
it "should run yum install then flush the cache if :after is true" do
- allow(@new_resource).to receive(:flush_cache).and_return({:after => true, :before => false})
+ allow(@new_resource).to receive(:flush_cache).and_return({ :after => true, :before => false })
@provider.load_current_resource
allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
expect(@provider).to receive(:yum_command).with(
@@ -667,7 +662,7 @@ describe Chef::Provider::Package::Yum do
end
it "should run yum install then not flush the cache if :after is false" do
- allow(@new_resource).to receive(:flush_cache).and_return({:after => false, :before => false})
+ allow(@new_resource).to receive(:flush_cache).and_return({ :after => false, :before => false })
@provider.load_current_resource
allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
expect(@provider).to receive(:yum_command).with(
@@ -681,7 +676,7 @@ describe Chef::Provider::Package::Yum do
describe "when upgrading a package" do
it "should run yum install if the package is installed and a version is given" do
@provider.load_current_resource
- allow(@provider).to receive(:candidate_version).and_return('11')
+ allow(@provider).to receive(:candidate_version).and_return("11")
allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
expect(@provider).to receive(:yum_command).with(
"-d0 -e0 -y install cups-11"
@@ -691,8 +686,8 @@ describe Chef::Provider::Package::Yum do
it "should run yum install if the package is not installed" do
@provider.load_current_resource
- @current_resource = Chef::Resource::Package.new('cups')
- allow(@provider).to receive(:candidate_version).and_return('11')
+ @current_resource = Chef::Resource::YumPackage.new("cups")
+ allow(@provider).to receive(:candidate_version).and_return("11")
allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
expect(@provider).to receive(:yum_command).with(
"-d0 -e0 -y install cups-11"
@@ -702,7 +697,7 @@ describe Chef::Provider::Package::Yum do
it "should raise an exception if candidate version is older than the installed version" do
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_installed => true,
:reset => true,
:installed_version => "1.2.4-11.18.el5",
@@ -722,18 +717,15 @@ describe Chef::Provider::Package::Yum do
# Test our little workaround, some crossover into Chef::Provider::Package territory
it "should call action_upgrade in the parent if the current resource version is nil" do
allow(@yum_cache).to receive(:installed_version).and_return(nil)
- @current_resource = Chef::Resource::Package.new('cups')
- allow(@provider).to receive(:candidate_version).and_return('11')
- expect(@provider).to receive(:upgrade_package).with(
- "cups",
- "11"
- )
+ @current_resource = Chef::Resource::YumPackage.new("cups")
+ allow(@provider).to receive(:candidate_version).and_return("11")
+ expect(@provider).to receive(:upgrade_package).with(["cups"], ["11"])
@provider.run_action(:upgrade)
end
it "should call action_upgrade in the parent if the candidate version is nil" do
@provider.load_current_resource
- @current_resource = Chef::Resource::Package.new('cups')
+ @current_resource = Chef::Resource::YumPackage.new("cups")
allow(@provider).to receive(:candidate_version).and_return(nil)
expect(@provider).not_to receive(:upgrade_package)
@provider.run_action(:upgrade)
@@ -741,20 +733,17 @@ describe Chef::Provider::Package::Yum do
it "should call action_upgrade in the parent if the candidate is newer" do
@provider.load_current_resource
- @current_resource = Chef::Resource::Package.new('cups')
- allow(@provider).to receive(:candidate_version).and_return('11')
- expect(@provider).to receive(:upgrade_package).with(
- "cups",
- "11"
- )
+ @current_resource = Chef::Resource::YumPackage.new("cups")
+ allow(@provider).to receive(:candidate_version).and_return("11")
+ expect(@provider).to receive(:upgrade_package).with(["cups"], ["11"])
@provider.run_action(:upgrade)
end
it "should not call action_upgrade in the parent if the candidate is older" do
allow(@yum_cache).to receive(:installed_version).and_return("12")
@provider.load_current_resource
- @current_resource = Chef::Resource::Package.new('cups')
- allow(@provider).to receive(:candidate_version).and_return('11')
+ @current_resource = Chef::Resource::YumPackage.new("cups")
+ allow(@provider).to receive(:candidate_version).and_return("11")
expect(@provider).not_to receive(:upgrade_package)
@provider.run_action(:upgrade)
end
@@ -786,15 +775,33 @@ describe Chef::Provider::Package::Yum do
end
end
+ describe "when locking a package" do
+ it "should run yum versionlock add with the package name" do
+ expect(@provider).to receive(:yum_command).with(
+ "-d0 -e0 -y versionlock add emacs"
+ )
+ @provider.lock_package("emacs", nil)
+ end
+ end
+
+ describe "when unlocking a package" do
+ it "should run yum versionlock delete with the package name" do
+ expect(@provider).to receive(:yum_command).with(
+ "-d0 -e0 -y versionlock delete emacs"
+ )
+ @provider.unlock_package("emacs", nil)
+ end
+ end
+
describe "when running yum" do
it "should run yum once if it exits with a return code of 0" do
@status = double("Status", :exitstatus => 0, :stdout => "", :stderr => "")
allow(@provider).to receive(:shell_out).and_return(@status)
expect(@provider).to receive(:shell_out).once.with(
"yum -d0 -e0 -y install emacs-1.0",
- {:timeout => Chef::Config[:yum_timeout]}
+ { :timeout => Chef::Config[:yum_timeout] }
)
- @provider.yum_command("-d0 -e0 -y install emacs-1.0")
+ @provider.send(:yum_command, "-d0 -e0 -y install emacs-1.0")
end
it "should run yum once if it exits with a return code > 0 and no scriptlet failures" do
@@ -802,33 +809,33 @@ describe Chef::Provider::Package::Yum do
allow(@provider).to receive(:shell_out).and_return(@status)
expect(@provider).to receive(:shell_out).once.with(
"yum -d0 -e0 -y install emacs-1.0",
- {:timeout => Chef::Config[:yum_timeout]}
+ { :timeout => Chef::Config[:yum_timeout] }
)
- expect { @provider.yum_command("-d0 -e0 -y install emacs-1.0") }.to raise_error(Chef::Exceptions::Exec)
+ expect { @provider.send(:yum_command, "-d0 -e0 -y install emacs-1.0") }.to raise_error(Chef::Exceptions::Exec)
end
it "should run yum once if it exits with a return code of 1 and %pre scriptlet failures" do
@status = double("Status", :exitstatus => 1, :stdout => "error: %pre(demo-1-1.el5.centos.x86_64) scriptlet failed, exit status 2",
- :stderr => "")
+ :stderr => "")
allow(@provider).to receive(:shell_out).and_return(@status)
expect(@provider).to receive(:shell_out).once.with(
"yum -d0 -e0 -y install emacs-1.0",
- {:timeout => Chef::Config[:yum_timeout]}
+ { :timeout => Chef::Config[:yum_timeout] }
)
# will still raise an exception, can't stub out the subsequent call
- expect { @provider.yum_command("-d0 -e0 -y install emacs-1.0") }.to raise_error(Chef::Exceptions::Exec)
+ expect { @provider.send(:yum_command, "-d0 -e0 -y install emacs-1.0") }.to raise_error(Chef::Exceptions::Exec)
end
it "should run yum twice if it exits with a return code of 1 and %post scriptlet failures" do
@status = double("Status", :exitstatus => 1, :stdout => "error: %post(demo-1-1.el5.centos.x86_64) scriptlet failed, exit status 2",
- :stderr => "")
+ :stderr => "")
allow(@provider).to receive(:shell_out).and_return(@status)
expect(@provider).to receive(:shell_out).twice.with(
"yum -d0 -e0 -y install emacs-1.0",
- {:timeout => Chef::Config[:yum_timeout]}
+ { :timeout => Chef::Config[:yum_timeout] }
)
# will still raise an exception, can't stub out the subsequent call
- expect { @provider.yum_command("-d0 -e0 -y install emacs-1.0") }.to raise_error(Chef::Exceptions::Exec)
+ expect { @provider.send(:yum_command, "-d0 -e0 -y install emacs-1.0") }.to raise_error(Chef::Exceptions::Exec)
end
it "should pass the yum_binary to the command if its specified" do
@@ -839,9 +846,9 @@ describe Chef::Provider::Package::Yum do
allow(@provider).to receive(:shell_out).and_return(@status)
expect(@provider).to receive(:shell_out).once.with(
"yum-deprecated -d0 -e0 -y install emacs-1.0",
- {:timeout => Chef::Config[:yum_timeout]}
+ { :timeout => Chef::Config[:yum_timeout] }
)
- @provider.yum_command("-d0 -e0 -y install emacs-1.0")
+ @provider.send(:yum_command, "-d0 -e0 -y install emacs-1.0")
end
end
end
@@ -856,7 +863,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
[
[ "0:3.3", [ 0, "3.3", nil ] ],
[ "9:1.7.3", [ 9, "1.7.3", nil ] ],
- [ "15:20020927", [ 15, "20020927", nil ] ]
+ [ "15:20020927", [ 15, "20020927", nil ] ],
].each do |x, y|
expect(@rpmutils.version_parse(x)).to eq(y)
end
@@ -866,7 +873,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
[
[ ":3.3", [ 0, "3.3", nil ] ],
[ "-1:1.7.3", [ nil, nil, "1:1.7.3" ] ],
- [ "-:20020927", [ nil, nil, ":20020927" ] ]
+ [ "-:20020927", [ nil, nil, ":20020927" ] ],
].each do |x, y|
expect(@rpmutils.version_parse(x)).to eq(y)
end
@@ -876,7 +883,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
[
[ "3.3", [ nil, "3.3", nil ] ],
[ "1.7.3", [ nil, "1.7.3", nil ] ],
- [ "20020927", [ nil, "20020927", nil ] ]
+ [ "20020927", [ nil, "20020927", nil ] ],
].each do |x, y|
expect(@rpmutils.version_parse(x)).to eq(y)
end
@@ -886,7 +893,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
[
[ "3..3", [ nil, "3..3", nil ] ],
[ "0001.7.3", [ nil, "0001.7.3", nil ] ],
- [ "20020927,3", [ nil, "20020927,3", nil ] ]
+ [ "20020927,3", [ nil, "20020927,3", nil ] ],
].each do |x, y|
expect(@rpmutils.version_parse(x)).to eq(y)
end
@@ -896,7 +903,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
[
[ "3.3-0.pre3.1.60.el5_5.1", [ nil, "3.3", "0.pre3.1.60.el5_5.1" ] ],
[ "1.7.3-1jpp.2.el5", [ nil, "1.7.3", "1jpp.2.el5" ] ],
- [ "20020927-46.el5", [ nil, "20020927", "46.el5" ] ]
+ [ "20020927-46.el5", [ nil, "20020927", "46.el5" ] ],
].each do |x, y|
expect(@rpmutils.version_parse(x)).to eq(y)
end
@@ -906,7 +913,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
[
[ "3.3-", [ nil, "3.3", nil ] ],
[ "-1jpp.2.el5", [ nil, nil, "1jpp.2.el5" ] ],
- [ "-0020020927-46.el5", [ nil, "-0020020927", "46.el5" ] ]
+ [ "-0020020927-46.el5", [ nil, "-0020020927", "46.el5" ] ],
].each do |x, y|
expect(@rpmutils.version_parse(x)).to eq(y)
end
@@ -965,7 +972,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
[ "0.0.1aa", "0.0.1aa", 0 ],
[ "0.0.1a", "0.0.1aa", -1 ],
].each do |x, y, result|
- expect(@rpmutils.rpmvercmp(x,y)).to eq(result)
+ expect(@rpmutils.rpmvercmp(x, y)).to eq(result)
end
end
@@ -982,44 +989,44 @@ describe Chef::Provider::Package::Yum::RPMUtils do
[ nil, "1.0.1", -1 ],
[ "1.0.1", "", 1 ],
[ "", "", 0 ],
- [ "", "1.0.1", -1 ]
+ [ "", "1.0.1", -1 ],
].each do |x, y, result|
- expect(@rpmutils.rpmvercmp(x,y)).to eq(result)
+ expect(@rpmutils.rpmvercmp(x, y)).to eq(result)
end
end
it "tests isalnum good input" do
- [ 'a', 'z', 'A', 'Z', '0', '9' ].each do |t|
+ %w{a z A Z 0 9}.each do |t|
expect(@rpmutils.isalnum(t)).to eq(true)
end
end
it "tests isalnum bad input" do
- [ '-', '.', '!', '^', ':', '_' ].each do |t|
+ [ "-", ".", "!", "^", ":", "_" ].each do |t|
expect(@rpmutils.isalnum(t)).to eq(false)
end
end
it "tests isalpha good input" do
- [ 'a', 'z', 'A', 'Z', ].each do |t|
+ %w{a z A Z}.each do |t|
expect(@rpmutils.isalpha(t)).to eq(true)
end
end
it "tests isalpha bad input" do
- [ '0', '9', '-', '.', '!', '^', ':', '_' ].each do |t|
+ [ "0", "9", "-", ".", "!", "^", ":", "_" ].each do |t|
expect(@rpmutils.isalpha(t)).to eq(false)
end
end
it "tests isdigit good input" do
- [ '0', '9', ].each do |t|
+ %w{0 9}.each do |t|
expect(@rpmutils.isdigit(t)).to eq(true)
end
end
it "tests isdigit bad input" do
- [ 'A', 'z', '-', '.', '!', '^', ':', '_' ].each do |t|
+ [ "A", "z", "-", ".", "!", "^", ":", "_" ].each do |t|
expect(@rpmutils.isdigit(t)).to eq(false)
end
end
@@ -1065,21 +1072,21 @@ describe Chef::Provider::Package::Yum::RPMVersion do
end
it "should raise an error unless passed 1 or 3 args" do
- expect {
+ expect do
Chef::Provider::Package::Yum::RPMVersion.new()
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
Chef::Provider::Package::Yum::RPMVersion.new("1:1.6.5-9.36.el5")
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
Chef::Provider::Package::Yum::RPMVersion.new("1:1.6.5-9.36.el5", "extra")
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
Chef::Provider::Package::Yum::RPMVersion.new("1", "1.6.5", "9.36.el5")
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
Chef::Provider::Package::Yum::RPMVersion.new("1", "1.6.5", "9.36.el5", "extra")
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
# thanks version_class_spec.rb!
@@ -1102,7 +1109,7 @@ describe Chef::Provider::Package::Yum::RPMVersion do
[ "0:1.4.10-7.20090624svn.el5",
"0:1.4.10-7.20090625svn.el5" ],
[ "0:2.3.4-2.el5",
- "0:2.3.4-2.el6" ]
+ "0:2.3.4-2.el6" ],
].each do |smaller, larger|
sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller)
lg = Chef::Provider::Package::Yum::RPMVersion.new(larger)
@@ -1121,14 +1128,14 @@ describe Chef::Provider::Package::Yum::RPMVersion do
"3.3-15.el5" ],
[ "alpha9.8",
"beta9.8" ],
- [ "14jpp",
- "15jpp" ],
+ %w{14jpp
+15jpp},
[ "0.9.0-0.6",
"0.9.0-0.7" ],
[ "0:1.9",
"3:1.9" ],
[ "2.3-2.el5",
- "2.3-2.el6" ]
+ "2.3-2.el6" ],
].each do |smaller, larger|
sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller)
lg = Chef::Provider::Package::Yum::RPMVersion.new(larger)
@@ -1145,7 +1152,7 @@ describe Chef::Provider::Package::Yum::RPMVersion do
[ "0:2.3-15.el5",
"0:2.3-15.el5" ],
[ "0:alpha9.8-27.2",
- "0:alpha9.8-27.2" ]
+ "0:alpha9.8-27.2" ],
].each do |smaller, larger|
sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller)
lg = Chef::Provider::Package::Yum::RPMVersion.new(larger)
@@ -1160,7 +1167,7 @@ describe Chef::Provider::Package::Yum::RPMVersion do
[ "2.3-15.el5",
"2.3-15.el5" ],
[ "alpha9.8-3",
- "alpha9.8-3" ]
+ "alpha9.8-3" ],
].each do |smaller, larger|
sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller)
lg = Chef::Provider::Package::Yum::RPMVersion.new(larger)
@@ -1231,9 +1238,9 @@ describe Chef::Provider::Package::Yum::RPMPackage do
it "should always have at least one provide, itself" do
expect(@rpm.provides.size).to eq(1)
- @rpm.provides[0].name == "testing"
- @rpm.provides[0].version.evr == "1:1.6.5-9.36.el5"
- @rpm.provides[0].flag == :==
+ expect(@rpm.provides[0].name).to eql("testing")
+ expect(@rpm.provides[0].version.evr).to eql("1:1.6.5-9.36.el5")
+ expect(@rpm.provides[0].flag).to eql(:==)
end
end
@@ -1255,37 +1262,37 @@ describe Chef::Provider::Package::Yum::RPMPackage do
it "should always have at least one provide, itself" do
expect(@rpm.provides.size).to eq(1)
- @rpm.provides[0].name == "testing"
- @rpm.provides[0].version.evr == "1:1.6.5-9.36.el5"
- @rpm.provides[0].flag == :==
+ expect(@rpm.provides[0].name).to eql("testing")
+ expect(@rpm.provides[0].version.evr).to eql("1:1.6.5-9.36.el5")
+ expect(@rpm.provides[0].flag).to eql(:==)
end
end
it "should raise an error unless passed 4 or 6 args" do
- expect {
+ expect do
Chef::Provider::Package::Yum::RPMPackage.new()
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
Chef::Provider::Package::Yum::RPMPackage.new("testing")
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
Chef::Provider::Package::Yum::RPMPackage.new("testing", "1:1.6.5-9.36.el5")
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
Chef::Provider::Package::Yum::RPMPackage.new("testing", "1:1.6.5-9.36.el5", "x86_64")
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
Chef::Provider::Package::Yum::RPMPackage.new("testing", "1:1.6.5-9.36.el5", "x86_64", [])
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
Chef::Provider::Package::Yum::RPMPackage.new("testing", "1", "1.6.5", "9.36.el5", "x86_64")
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
Chef::Provider::Package::Yum::RPMPackage.new("testing", "1", "1.6.5", "9.36.el5", "x86_64", [])
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
Chef::Provider::Package::Yum::RPMPackage.new("testing", "1", "1.6.5", "9.36.el5", "x86_64", [], "extra")
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
describe "<=>" do
@@ -1299,8 +1306,8 @@ describe Chef::Provider::Package::Yum::RPMPackage do
"B-test" ],
[ "Aa-test",
"aA-test" ],
- [ "1test",
- "2test" ],
+ %w{1test
+2test},
].each do |smaller, larger|
sm = Chef::Provider::Package::Yum::RPMPackage.new(smaller, "0:0.0.1-1", "x86_64", [])
lg = Chef::Provider::Package::Yum::RPMPackage.new(larger, "0:0.0.1-1", "x86_64", [])
@@ -1312,12 +1319,12 @@ describe Chef::Provider::Package::Yum::RPMPackage do
it "should sort alphabetically based on package arch" do
[
- [ "i386",
- "x86_64" ],
- [ "i386",
- "noarch" ],
- [ "noarch",
- "x86_64" ],
+ %w{i386
+x86_64},
+ %w{i386
+noarch},
+ %w{noarch
+x86_64},
].each do |smaller, larger|
sm = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "0:0.0.1-1", smaller, [])
lg = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "0:0.0.1-1", larger, [])
@@ -1399,27 +1406,27 @@ describe Chef::Provider::Package::Yum::RPMDependency do
end
it "should raise an error unless passed 3 or 5 args" do
- expect {
+ expect do
Chef::Provider::Package::Yum::RPMDependency.new()
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
Chef::Provider::Package::Yum::RPMDependency.new("testing")
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5")
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==)
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==, "extra")
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
Chef::Provider::Package::Yum::RPMDependency.new("testing", "1", "1.6.5", "9.36.el5", :==)
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
Chef::Provider::Package::Yum::RPMDependency.new("testing", "1", "1.6.5", "9.36.el5", :==, "extra")
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
describe "parse" do
@@ -1460,7 +1467,7 @@ describe Chef::Provider::Package::Yum::RPMDependency do
[ "=", :== ],
[ "==", :== ],
[ "<=", :<= ],
- [ "<", :< ]
+ [ "<", :< ],
].each do |before, after|
@rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing #{before} 1:1.1-1")
expect(@rpmdep.flag).to eq(after)
@@ -1474,7 +1481,7 @@ describe Chef::Provider::Package::Yum::RPMDependency do
[ ">>", :== ],
[ "<<", :== ],
[ "!", :== ],
- [ "~", :== ]
+ [ "~", :== ],
].each do |before, after|
@rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing #{before} 1:1.1-1")
expect(@rpmdep.name).to eq("testing #{before} 1:1.1-1")
@@ -1487,12 +1494,12 @@ describe Chef::Provider::Package::Yum::RPMDependency do
it "should raise an error unless a RPMDependency is passed" do
@rpmprovide = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==)
@rpmrequire = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :>=)
- expect {
+ expect do
@rpmprovide.satisfy?("hi")
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
@rpmprovide.satisfy?(@rpmrequire)
- }.not_to raise_error
+ end.not_to raise_error
end
it "should validate dependency satisfaction logic for standard examples" do
@@ -1549,12 +1556,12 @@ describe Chef::Provider::Package::Yum::RPMDb do
# name, version, arch, installed, available
deps_v = [
Chef::Provider::Package::Yum::RPMDependency.parse("libz.so.1()(64bit)"),
- Chef::Provider::Package::Yum::RPMDependency.parse("test-package-a = 0:1.6.5-9.36.el5")
+ Chef::Provider::Package::Yum::RPMDependency.parse("test-package-a = 0:1.6.5-9.36.el5"),
]
deps_z = [
Chef::Provider::Package::Yum::RPMDependency.parse("libz.so.1()(64bit)"),
Chef::Provider::Package::Yum::RPMDependency.parse("config(test) = 0:1.6.5-9.36.el5"),
- Chef::Provider::Package::Yum::RPMDependency.parse("test-package-c = 0:1.6.5-9.36.el5")
+ Chef::Provider::Package::Yum::RPMDependency.parse("test-package-c = 0:1.6.5-9.36.el5"),
]
@rpm_v = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-a", "0:1.6.5-9.36.el5", "i386", deps_v, true, false, "base")
@rpm_w = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "0:1.6.5-9.36.el5", "i386", [], true, true, "extras")
@@ -1580,7 +1587,7 @@ describe Chef::Provider::Package::Yum::RPMDb do
end
it "should only accept an RPMDbPackage object" do
- expect { @rpmdb.push("string") }.to raise_error
+ expect { @rpmdb.push("string") }.to raise_error(ArgumentError)
end
it "should add the package to the package db" do
@@ -1714,12 +1721,12 @@ describe Chef::Provider::Package::Yum::RPMDb do
it "should raise an error unless a RPMDependency is passed" do
@rpmprovide = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==)
@rpmrequire = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :>=)
- expect {
+ expect do
@rpmdb.whatprovides("hi")
- }.to raise_error(ArgumentError)
- expect {
+ end.to raise_error(ArgumentError)
+ expect do
@rpmdb.whatprovides(@rpmrequire)
- }.not_to raise_error
+ end.not_to raise_error
end
it "should return an Array of packages statisfying a RPMDependency" do
@@ -1750,13 +1757,13 @@ describe Chef::Provider::Package::Yum::YumCache do
end
end
- let(:yum_exe) {
+ let(:yum_exe) do
StringIO.new("#!/usr/bin/python\n\naldsjfa\ldsajflkdsjf\lajsdfj")
- }
+ end
- let(:bin_exe) {
+ let(:bin_exe) do
StringIO.new(SecureRandom.random_bytes)
- }
+ end
before(:each) do
@stdin = double("STDIN", :nil_object => true)
@@ -1840,13 +1847,19 @@ EOF
end
it "should return the default python if the yum-executable doesn't start with #!" do
- allow(::File).to receive(:open).with("/usr/bin/yum", "r") { |&b| r = b.call(bin_exe); bin_exe.rewind; r}
+ allow(::File).to receive(:open).with("/usr/bin/yum", "r") { |&b| r = b.call(bin_exe); bin_exe.rewind; r }
+ expect(@yc.python_bin).to eq("/usr/bin/python")
+ end
+
+ it "should return /usr/bin/python if the interpreter is /bin/bash" do
+ other = StringIO.new("#!/bin/bash\n# The yum executable redirecting to dnf from dnf-yum compatible package.")
+ allow(::File).to receive(:open).with("/usr/bin/yum", "r") { |&b| r = b.call(other); other.rewind; r }
expect(@yc.python_bin).to eq("/usr/bin/python")
end
it "should return the interpreter for yum" do
other = StringIO.new("#!/usr/bin/super_python\n\nlasjdfdsaljf\nlasdjfs")
- allow(::File).to receive(:open).with("/usr/bin/yum", "r") { |&b| r = b.call(other); other.rewind; r}
+ allow(::File).to receive(:open).with("/usr/bin/yum", "r") { |&b| r = b.call(other); other.rewind; r }
expect(@yc.python_bin).to eq("/usr/bin/super_python")
end
end
@@ -1861,32 +1874,32 @@ EOF
it "should run yum-dump.py using the system python when next_refresh is for :all" do
@yc.reload
- expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --yum-lock-timeout 30$}, :timeout=>Chef::Config[:yum_timeout])
+ expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --yum-lock-timeout 30$}, :timeout => Chef::Config[:yum_timeout])
@yc.refresh
end
it "should run yum-dump.py with the installed flag when next_refresh is for :installed" do
@yc.reload_installed
- expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --installed --yum-lock-timeout 30$}, :timeout=>Chef::Config[:yum_timeout])
+ expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --installed --yum-lock-timeout 30$}, :timeout => Chef::Config[:yum_timeout])
@yc.refresh
end
it "should run yum-dump.py with the all-provides flag when next_refresh is for :provides" do
@yc.reload_provides
- expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --all-provides --yum-lock-timeout 30$}, :timeout=>Chef::Config[:yum_timeout])
+ expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --all-provides --yum-lock-timeout 30$}, :timeout => Chef::Config[:yum_timeout])
@yc.refresh
end
it "should pass extra_repo_control args to yum-dump.py" do
@yc.enable_extra_repo_control("--enablerepo=foo --disablerepo=bar")
- expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --enablerepo=foo --disablerepo=bar --yum-lock-timeout 30$}, :timeout=>Chef::Config[:yum_timeout])
+ expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --enablerepo=foo --disablerepo=bar --yum-lock-timeout 30$}, :timeout => Chef::Config[:yum_timeout])
@yc.refresh
end
it "should pass extra_repo_control args and configured yum lock timeout to yum-dump.py" do
Chef::Config[:yum_lock_timeout] = 999
@yc.enable_extra_repo_control("--enablerepo=foo --disablerepo=bar")
- expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --enablerepo=foo --disablerepo=bar --yum-lock-timeout 999$}, :timeout=>Chef::Config[:yum_timeout])
+ expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --enablerepo=foo --disablerepo=bar --yum-lock-timeout 999$}, :timeout => Chef::Config[:yum_timeout])
@yc.refresh
end
@@ -1914,7 +1927,7 @@ EOF
it "should raise exception yum-dump.py exits with a non zero status" do
@status = double("Status", :exitstatus => 1, :stdin => @stdin, :stdout => @stdout_no_output, :stderr => @stderr)
allow(@yc).to receive(:shell_out!).and_return(@status)
- expect { @yc.refresh}.to raise_error(Chef::Exceptions::Package, %r{CentOS-Base.repo, line: 12})
+ expect { @yc.refresh }.to raise_error(Chef::Exceptions::Package, %r{CentOS-Base.repo, line: 12})
end
it "should parse type 'i' into an installed state for a package" do
@@ -2109,18 +2122,18 @@ describe "Chef::Provider::Package::Yum - Multi" do
@node = Chef::Node.new
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Package.new(['cups', 'vim'])
+ @new_resource = Chef::Resource::YumPackage.new(%w{cups vim})
@status = double("Status", :exitstatus => 0)
@yum_cache = double(
- 'Chef::Provider::Yum::YumCache',
+ "Chef::Provider::Yum::YumCache",
:reload_installed => true,
:reset => true,
- :installed_version => 'XXXX',
- :candidate_version => 'YYYY',
+ :installed_version => "XXXX",
+ :candidate_version => "YYYY",
:package_available? => true,
:version_available? => true,
- :allow_multi_install => [ 'kernel' ],
- :package_repository => 'base',
+ :allow_multi_install => [ "kernel" ],
+ :package_repository => "base",
:disable_extra_repo_control => true
)
allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
@@ -2130,15 +2143,23 @@ describe "Chef::Provider::Package::Yum - Multi" do
@pid = double("PID")
end
+ describe "when evaluating the correctness of the resource" do
+ it "raises an error if the array lengths of package name, arch, and version do not match up" do
+ allow(@new_resource).to receive(:version).and_return(["1.1"])
+ allow(@new_resource).to receive(:arch).and_return(%w{x86_64 i386 i686})
+ expect { @provider.check_resource_semantics! }.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
+ end
+ end
+
describe "when loading the current system state" do
it "should create a current resource with the name of the new_resource" do
@provider.load_current_resource
- expect(@provider.current_resource.name).to eq('cups, vim')
+ expect(@provider.current_resource.name).to eq("cups, vim")
end
it "should set the current resources package name to the new resources package name" do
@provider.load_current_resource
- expect(@provider.current_resource.package_name).to eq(['cups', 'vim'])
+ expect(@provider.current_resource.package_name).to eq(%w{cups vim})
end
it "should set the installed version to nil on the current resource if no installed package" do
@@ -2148,21 +2169,21 @@ describe "Chef::Provider::Package::Yum - Multi" do
end
it "should set the installed version if yum has one" do
- allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5')
- allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('1.0')
- allow(@yum_cache).to receive(:candidate_version).with('cups', nil).and_return('1.2.4-11.18.el5_2.3')
- allow(@yum_cache).to receive(:candidate_version).with('vim', nil).and_return('1.5')
+ allow(@yum_cache).to receive(:installed_version).with("cups", nil).and_return("1.2.4-11.18.el5")
+ allow(@yum_cache).to receive(:installed_version).with("vim", nil).and_return("1.0")
+ allow(@yum_cache).to receive(:candidate_version).with("cups", nil).and_return("1.2.4-11.18.el5_2.3")
+ allow(@yum_cache).to receive(:candidate_version).with("vim", nil).and_return("1.5")
@provider.load_current_resource
- expect(@provider.current_resource.version).to eq(['1.2.4-11.18.el5', '1.0'])
+ expect(@provider.current_resource.version).to eq(["1.2.4-11.18.el5", "1.0"])
end
it "should set the candidate version if yum info has one" do
- allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5')
- allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('1.0')
- allow(@yum_cache).to receive(:candidate_version).with('cups', nil).and_return('1.2.4-11.18.el5_2.3')
- allow(@yum_cache).to receive(:candidate_version).with('vim', nil).and_return('1.5')
+ allow(@yum_cache).to receive(:installed_version).with("cups", nil).and_return("1.2.4-11.18.el5")
+ allow(@yum_cache).to receive(:installed_version).with("vim", nil).and_return("1.0")
+ allow(@yum_cache).to receive(:candidate_version).with("cups", nil).and_return("1.2.4-11.18.el5_2.3")
+ allow(@yum_cache).to receive(:candidate_version).with("vim", nil).and_return("1.5")
@provider.load_current_resource
- expect(@provider.candidate_version).to eql(['1.2.4-11.18.el5_2.3', '1.5'])
+ expect(@provider.candidate_version).to eql(["1.2.4-11.18.el5_2.3", "1.5"])
end
it "should return the current resouce" do
@@ -2171,30 +2192,31 @@ describe "Chef::Provider::Package::Yum - Multi" do
describe "when version constraint in package_name" do
it "should set package_version if no existing package_name is found and new_package_name is available" do
- @new_resource = Chef::Resource::Package.new(['cups = 1.2.4-11.18.el5_2.3', 'emacs = 24.4'])
+ @new_resource = Chef::Resource::YumPackage.new(["cups = 1.2.4-11.18.el5_2.3", "emacs = 24.4"])
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
- allow(@yum_cache).to receive(:package_available?) { |pkg| %w(cups emacs).include?(pkg) ? true : false }
+ allow(@yum_cache).to receive(:package_available?) { |pkg| %w{cups emacs}.include?(pkg) ? true : false }
allow(@yum_cache).to receive(:candidate_version) do |pkg|
- if pkg == 'cups'
+ if pkg == "cups"
"1.2.4-11.18.el5_2.3"
- elsif pkg == 'emacs'
+ elsif pkg == "emacs"
"24.4"
end
end
allow(@yum_cache).to receive(:packages_from_require) do |pkg|
- if pkg.name == 'cups'
+ if pkg.name == "cups"
[Chef::Provider::Package::Yum::RPMDbPackage.new("cups", "1.2.4-11.18.el5_2.3", "noarch", [], false, true, "base")]
- elsif pkg.name == 'emacs'
+ elsif pkg.name == "emacs"
[Chef::Provider::Package::Yum::RPMDbPackage.new("emacs", "24.4", "noarch", [], false, true, "base")]
end
end
expect(Chef::Log).to receive(:debug).exactly(2).times.with(%r{matched 1 package,})
- expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{candidate version: \["1.2.4-11.18.el5_2.3", "24.4"\]})
+ expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{candidate version: 1.2.4-11.18.el5_2.3})
+ expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{candidate version: 24.4})
expect(Chef::Log).to receive(:debug).at_least(2).times.with(%r{checking yum info})
@provider.load_current_resource
- expect(@provider.new_resource.package_name).to eq(["cups", "emacs"])
+ expect(@provider.new_resource.package_name).to eq(%w{cups emacs})
expect(@provider.new_resource.version).to eq(["1.2.4-11.18.el5_2.3", "24.4"])
- expect(@provider.send(:package_name_array)).to eq(["cups", "emacs"])
+ expect(@provider.send(:package_name_array)).to eq(%w{cups emacs})
expect(@provider.send(:new_version_array)).to eq(["1.2.4-11.18.el5_2.3", "24.4"])
end
end
@@ -2204,38 +2226,47 @@ describe "Chef::Provider::Package::Yum - Multi" do
it "should run yum install with the package name and version" do
@provider.load_current_resource
allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
- allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5')
- allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('0.9')
+ allow(@yum_cache).to receive(:installed_version).with("cups", nil).and_return("1.2.4-11.18.el5")
+ allow(@yum_cache).to receive(:installed_version).with("vim", nil).and_return("0.9")
expect(@provider).to receive(:yum_command).with(
"-d0 -e0 -y install cups-1.2.4-11.19.el5 vim-1.0"
)
- @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", '1.0'])
+ @provider.install_package(%w{cups vim}, ["1.2.4-11.19.el5", "1.0"])
+ end
+
+ it "should not run yum install with nil package name" do
+ @provider.load_current_resource
+ allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
+ expect(@provider).to receive(:yum_command).with(
+ "-d0 -e0 -y install cups-1.2.4-11.19.el5"
+ )
+ @provider.install_package(["cups", nil], ["1.2.4-11.19.el5", nil])
end
it "should run yum install with the package name, version and arch" do
@provider.load_current_resource
- allow(@new_resource).to receive(:arch).and_return("i386")
+ allow(@new_resource).to receive(:arch).and_return(%w{i386 i386})
allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
expect(@provider).to receive(:yum_command).with(
"-d0 -e0 -y install cups-1.2.4-11.19.el5.i386 vim-1.0.i386"
)
- @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", "1.0"])
+ @provider.install_package(%w{cups vim}, ["1.2.4-11.19.el5", "1.0"])
end
it "installs the package with the options given in the resource" do
@provider.load_current_resource
allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
- allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5')
- allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('0.9')
+ allow(@yum_cache).to receive(:installed_version).with("cups", nil).and_return("1.2.4-11.18.el5")
+ allow(@yum_cache).to receive(:installed_version).with("vim", nil).and_return("0.9")
expect(@provider).to receive(:yum_command).with(
"-d0 -e0 -y --disablerepo epmd install cups-1.2.4-11.19.el5 vim-1.0"
)
allow(@new_resource).to receive(:options).and_return("--disablerepo epmd")
- @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", '1.0'])
+ @provider.install_package(%w{cups vim}, ["1.2.4-11.19.el5", "1.0"])
end
it "should run yum install with the package name and version when name has arch" do
- @new_resource = Chef::Resource::Package.new(['cups.x86_64', 'vim'])
+ @new_resource = Chef::Resource::YumPackage.new(["cups.x86_64", "vim"])
@provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
@@ -2243,20 +2274,20 @@ describe "Chef::Provider::Package::Yum - Multi" do
# and we need to craft the right response. The default mock setup above
# will just return valid versions all the time which won't work for this
# test.
- allow(@yum_cache).to receive(:installed_version).with('cups', 'x86_64').and_return('XXXX')
- allow(@yum_cache).to receive(:candidate_version).with('cups', 'x86_64').and_return('1.2.4-11.18.el5')
- allow(@yum_cache).to receive(:installed_version).with('cups.x86_64').and_return(nil)
- allow(@yum_cache).to receive(:candidate_version).with('cups.x86_64').and_return(nil)
+ allow(@yum_cache).to receive(:installed_version).with("cups", "x86_64").and_return("XXXX")
+ allow(@yum_cache).to receive(:candidate_version).with("cups", "x86_64").and_return("1.2.4-11.18.el5")
+ allow(@yum_cache).to receive(:installed_version).with("cups.x86_64").and_return(nil)
+ allow(@yum_cache).to receive(:candidate_version).with("cups.x86_64").and_return(nil)
# Normal mock's for the idempotency check
- allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5')
- allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('0.9')
+ allow(@yum_cache).to receive(:installed_version).with("cups", nil).and_return("1.2.4-11.18.el5")
+ allow(@yum_cache).to receive(:installed_version).with("vim", nil).and_return("0.9")
@provider.load_current_resource
expect(@provider).to receive(:yum_command).with(
"-d0 -e0 -y install cups-1.2.4-11.19.el5.x86_64 vim-1.0"
)
- @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", '1.0'])
+ @provider.install_package(%w{cups vim}, ["1.2.4-11.19.el5", "1.0"])
end
end
diff --git a/spec/unit/provider/package/zypper_spec.rb b/spec/unit/provider/package/zypper_spec.rb
index 18ff739bc6..7e6f204b64 100644
--- a/spec/unit/provider/package/zypper_spec.rb
+++ b/spec/unit/provider/package/zypper_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Package::Zypper do
let!(:new_resource) { Chef::Resource::ZypperPackage.new("cups") }
@@ -34,18 +34,18 @@ describe Chef::Provider::Package::Zypper do
before(:each) do
allow(Chef::Resource::Package).to receive(:new).and_return(current_resource)
- allow(provider).to receive(:shell_out).and_return(status)
+ allow(provider).to receive(:shell_out!).and_return(status)
allow(provider).to receive(:`).and_return("2.0")
end
- def shell_out_expectation(command, options=nil)
- options ||= { timeout: 900 }
- expect(provider).to receive(:shell_out).with(command, options)
+ def shell_out_expectation(*command, **options)
+ options[:timeout] ||= 900
+ expect(provider).to receive(:shell_out).with(*command, **options)
end
- def shell_out_expectation!(command, options=nil)
- options ||= { timeout: 900 }
- expect(provider).to receive(:shell_out!).with(command, options)
+ def shell_out_expectation!(*command, **options)
+ options[:timeout] ||= 900
+ expect(provider).to receive(:shell_out!).with(*command, **options)
end
describe "when loading the current package state" do
@@ -60,42 +60,48 @@ describe Chef::Provider::Package::Zypper do
end
it "should run zypper info with the package name" do
- shell_out_expectation(
- "zypper --non-interactive info #{new_resource.package_name}"
+ shell_out_expectation!(
+ "zypper", "--non-interactive", "info", new_resource.package_name
).and_return(status)
provider.load_current_resource
end
it "should set the installed version to nil on the current resource if zypper info installed version is (none)" do
allow(provider).to receive(:shell_out).and_return(status)
- expect(current_resource).to receive(:version).with(nil).and_return(true)
+ expect(current_resource).to receive(:version).with([nil]).and_return(true)
provider.load_current_resource
end
- it "should set the installed version if zypper info has one" do
+ it "should set the installed version if zypper info has one (zypper version < 1.13.0)" do
status = double(:stdout => "Version: 1.0\nInstalled: Yes\n", :exitstatus => 0)
- allow(provider).to receive(:shell_out).and_return(status)
- expect(current_resource).to receive(:version).with("1.0").and_return(true)
+ allow(provider).to receive(:shell_out!).and_return(status)
+ expect(current_resource).to receive(:version).with(["1.0"]).and_return(true)
provider.load_current_resource
end
- it "should set the candidate version if zypper info has one" do
- status = double(:stdout => "Version: 1.0\nInstalled: No\nStatus: out-of-date (version 0.9 installed)", :exitstatus => 0)
+ it "should set the installed version if zypper info has one (zypper version >= 1.13.0)" do
+ status = double(:stdout => "Version : 1.0 \nInstalled : Yes \n", :exitstatus => 0)
- allow(provider).to receive(:shell_out).and_return(status)
+ allow(provider).to receive(:shell_out!).and_return(status)
+ expect(current_resource).to receive(:version).with(["1.0"]).and_return(true)
provider.load_current_resource
- expect(provider.candidate_version).to eql("1.0")
end
- it "should raise an exception if zypper info fails" do
- expect(status).to receive(:exitstatus).and_return(1)
- expect { provider.load_current_resource }.to raise_error(Chef::Exceptions::Package)
+ it "should set the candidate version if zypper info has one (zypper version < 1.13.0)" do
+ status = double(:stdout => "Version: 1.0\nInstalled: No\nStatus: out-of-date (version 0.9 installed)", :exitstatus => 0)
+
+ allow(provider).to receive(:shell_out!).and_return(status)
+ provider.load_current_resource
+ expect(provider.candidate_version).to eql(["1.0"])
end
- it "should not raise an exception if zypper info succeeds" do
- expect(status).to receive(:exitstatus).and_return(0)
- expect { provider.load_current_resource }.not_to raise_error
+ it "should set the candidate version if zypper info has one (zypper version >= 1.13.0)" do
+ status = double(:stdout => "Version : 1.0 \nInstalled : No \nStatus : out-of-date (version 0.9 installed)", :exitstatus => 0)
+
+ allow(provider).to receive(:shell_out!).and_return(status)
+ provider.load_current_resource
+ expect(provider.candidate_version).to eql(["1.0"])
end
it "should return the current resouce" do
@@ -107,27 +113,25 @@ describe Chef::Provider::Package::Zypper do
it "should run zypper install with the package name and version" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
shell_out_expectation!(
- "zypper --non-interactive install --auto-agree-with-licenses emacs=1.0"
+ "zypper", "--non-interactive", "install", "--auto-agree-with-licenses", "emacs=1.0"
)
- provider.install_package("emacs", "1.0")
+ provider.install_package(["emacs"], ["1.0"])
end
it "should run zypper install without gpg checks" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
shell_out_expectation!(
- "zypper --non-interactive --no-gpg-checks install "+
- "--auto-agree-with-licenses emacs=1.0"
+ "zypper", "--non-interactive", "--no-gpg-checks", "install", "--auto-agree-with-licenses", "emacs=1.0"
)
- provider.install_package("emacs", "1.0")
+ provider.install_package(["emacs"], ["1.0"])
end
it "should warn about gpg checks on zypper install" do
expect(Chef::Log).to receive(:warn).with(
/All packages will be installed without gpg signature checks/
)
shell_out_expectation!(
- "zypper --non-interactive --no-gpg-checks install "+
- "--auto-agree-with-licenses emacs=1.0"
+ "zypper", "--non-interactive", "--no-gpg-checks", "install", "--auto-agree-with-licenses", "emacs=1.0"
)
- provider.install_package("emacs", "1.0")
+ provider.install_package(["emacs"], ["1.0"])
end
end
@@ -135,34 +139,31 @@ describe Chef::Provider::Package::Zypper do
it "should run zypper update with the package name and version" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
shell_out_expectation!(
- "zypper --non-interactive install --auto-agree-with-licenses emacs=1.0"
+ "zypper", "--non-interactive", "install", "--auto-agree-with-licenses", "emacs=1.0"
)
- provider.upgrade_package("emacs", "1.0")
+ provider.upgrade_package(["emacs"], ["1.0"])
end
it "should run zypper update without gpg checks" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
shell_out_expectation!(
- "zypper --non-interactive --no-gpg-checks install "+
- "--auto-agree-with-licenses emacs=1.0"
+ "zypper", "--non-interactive", "--no-gpg-checks", "install", "--auto-agree-with-licenses", "emacs=1.0"
)
- provider.upgrade_package("emacs", "1.0")
+ provider.upgrade_package(["emacs"], ["1.0"])
end
it "should warn about gpg checks on zypper upgrade" do
expect(Chef::Log).to receive(:warn).with(
/All packages will be installed without gpg signature checks/
)
shell_out_expectation!(
- "zypper --non-interactive --no-gpg-checks install "+
- "--auto-agree-with-licenses emacs=1.0"
+ "zypper", "--non-interactive", "--no-gpg-checks", "install", "--auto-agree-with-licenses", "emacs=1.0"
)
- provider.upgrade_package("emacs", "1.0")
+ provider.upgrade_package(["emacs"], ["1.0"])
end
it "should run zypper upgrade without gpg checks" do
shell_out_expectation!(
- "zypper --non-interactive --no-gpg-checks install "+
- "--auto-agree-with-licenses emacs=1.0"
+ "zypper", "--non-interactive", "--no-gpg-checks", "install", "--auto-agree-with-licenses", "emacs=1.0"
)
- provider.upgrade_package("emacs", "1.0")
+ provider.upgrade_package(["emacs"], ["1.0"])
end
end
@@ -172,9 +173,9 @@ describe Chef::Provider::Package::Zypper do
it "should run zypper remove with the package name" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
shell_out_expectation!(
- "zypper --non-interactive remove emacs"
+ "zypper", "--non-interactive", "remove", "emacs"
)
- provider.remove_package("emacs", nil)
+ provider.remove_package(["emacs"], [nil])
end
end
@@ -182,51 +183,115 @@ describe Chef::Provider::Package::Zypper do
it "should run zypper remove with the package name" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
shell_out_expectation!(
- "zypper --non-interactive remove emacs=1.0"
+ "zypper", "--non-interactive", "remove", "emacs=1.0"
)
- provider.remove_package("emacs", "1.0")
+ provider.remove_package(["emacs"], ["1.0"])
end
it "should run zypper remove without gpg checks" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
shell_out_expectation!(
- "zypper --non-interactive --no-gpg-checks remove emacs=1.0"
+ "zypper", "--non-interactive", "--no-gpg-checks", "remove", "emacs=1.0"
)
- provider.remove_package("emacs", "1.0")
+ provider.remove_package(["emacs"], ["1.0"])
end
it "should warn about gpg checks on zypper remove" do
expect(Chef::Log).to receive(:warn).with(
/All packages will be installed without gpg signature checks/
)
shell_out_expectation!(
- "zypper --non-interactive --no-gpg-checks remove emacs=1.0"
+ "zypper", "--non-interactive", "--no-gpg-checks", "remove", "emacs=1.0"
)
- provider.remove_package("emacs", "1.0")
+ provider.remove_package(["emacs"], ["1.0"])
end
end
end
describe "purge_package" do
- it "should run remove_package with the name and version" do
+ it "should run remove with the name and version and --clean-deps" do
shell_out_expectation!(
- "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0"
+ "zypper", "--non-interactive", "--no-gpg-checks", "remove", "--clean-deps", "emacs=1.0"
)
- provider.purge_package("emacs", "1.0")
+ provider.purge_package(["emacs"], ["1.0"])
end
it "should run zypper purge without gpg checks" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
shell_out_expectation!(
- "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0"
+ "zypper", "--non-interactive", "--no-gpg-checks", "remove", "--clean-deps", "emacs=1.0"
)
- provider.purge_package("emacs", "1.0")
+ provider.purge_package(["emacs"], ["1.0"])
end
it "should warn about gpg checks on zypper purge" do
expect(Chef::Log).to receive(:warn).with(
/All packages will be installed without gpg signature checks/
)
shell_out_expectation!(
- "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0"
+ "zypper", "--non-interactive", "--no-gpg-checks", "remove", "--clean-deps", "emacs=1.0"
+ )
+ provider.purge_package(["emacs"], ["1.0"])
+ end
+ end
+
+ describe "lock_package" do
+ it "should run zypper addlock with the package name" do
+ allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
+ shell_out_expectation!(
+ "zypper", "--non-interactive", "addlock", "emacs"
+ )
+ provider.lock_package(["emacs"], [nil])
+ end
+ it "should run zypper addlock without gpg checks" do
+ allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
+ shell_out_expectation!(
+ "zypper", "--non-interactive", "--no-gpg-checks", "addlock", "emacs"
+ )
+ provider.lock_package(["emacs"], [nil])
+ end
+ it "should warn about gpg checks on zypper addlock" do
+ expect(Chef::Log).to receive(:warn).with(
+ /All packages will be installed without gpg signature checks/
+ )
+ shell_out_expectation!(
+ "zypper", "--non-interactive", "--no-gpg-checks", "addlock", "emacs"
+ )
+ provider.lock_package(["emacs"], [nil])
+ end
+ it "should run zypper addlock without gpg checks" do
+ shell_out_expectation!(
+ "zypper", "--non-interactive", "--no-gpg-checks", "addlock", "emacs"
+ )
+ provider.lock_package(["emacs"], [nil])
+ end
+ end
+
+ describe "unlock_package" do
+ it "should run zypper removelock with the package name" do
+ allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
+ shell_out_expectation!(
+ "zypper", "--non-interactive", "removelock", "emacs"
+ )
+ provider.unlock_package(["emacs"], [nil])
+ end
+ it "should run zypper removelock without gpg checks" do
+ allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
+ shell_out_expectation!(
+ "zypper", "--non-interactive", "--no-gpg-checks", "removelock", "emacs"
+ )
+ provider.unlock_package(["emacs"], [nil])
+ end
+ it "should warn about gpg checks on zypper removelock" do
+ expect(Chef::Log).to receive(:warn).with(
+ /All packages will be installed without gpg signature checks/
+ )
+ shell_out_expectation!(
+ "zypper", "--non-interactive", "--no-gpg-checks", "removelock", "emacs"
)
- provider.purge_package("emacs", "1.0")
+ provider.unlock_package(["emacs"], [nil])
+ end
+ it "should run zypper removelock without gpg checks" do
+ shell_out_expectation!(
+ "zypper", "--non-interactive", "--no-gpg-checks", "removelock", "emacs"
+ )
+ provider.unlock_package(["emacs"], [nil])
end
end
@@ -238,28 +303,46 @@ describe Chef::Provider::Package::Zypper do
describe "install_package" do
it "should run zypper install with the package name and version" do
shell_out_expectation!(
- "zypper --no-gpg-checks install --auto-agree-with-licenses -y emacs"
+ "zypper", "--no-gpg-checks", "install", "--auto-agree-with-licenses", "-y", "emacs"
)
- provider.install_package("emacs", "1.0")
+ provider.install_package(["emacs"], ["1.0"])
end
end
describe "upgrade_package" do
it "should run zypper update with the package name and version" do
shell_out_expectation!(
- "zypper --no-gpg-checks install --auto-agree-with-licenses -y emacs"
+ "zypper", "--no-gpg-checks", "install", "--auto-agree-with-licenses", "-y", "emacs"
)
- provider.upgrade_package("emacs", "1.0")
+ provider.upgrade_package(["emacs"], ["1.0"])
end
end
describe "remove_package" do
it "should run zypper remove with the package name" do
shell_out_expectation!(
- "zypper --no-gpg-checks remove -y emacs"
+ "zypper", "--no-gpg-checks", "remove", "-y", "emacs"
)
- provider.remove_package("emacs", "1.0")
+ provider.remove_package(["emacs"], ["1.0"])
end
end
end
+
+ describe "when installing multiple packages" do # https://github.com/chef/chef/issues/3570
+ it "should install an array of package names and versions" do
+ allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
+ shell_out_expectation!(
+ "zypper", "--non-interactive", "--no-gpg-checks", "install", "--auto-agree-with-licenses", "emacs=1.0", "vim=2.0"
+ )
+ provider.install_package(%w{emacs vim}, ["1.0", "2.0"])
+ end
+
+ it "should remove an array of package names and versions" do
+ allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
+ shell_out_expectation!(
+ "zypper", "--non-interactive", "--no-gpg-checks", "remove", "emacs=1.0", "vim=2.0"
+ )
+ provider.remove_package(%w{emacs vim}, ["1.0", "2.0"])
+ end
+ end
end
diff --git a/spec/unit/provider/package_spec.rb b/spec/unit/provider/package_spec.rb
index 432d968906..122e58efb7 100644
--- a/spec/unit/provider/package_spec.rb
+++ b/spec/unit/provider/package_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,415 +16,475 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Package do
- before do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Package.new('emacs')
- @current_resource = Chef::Resource::Package.new('emacs')
- @provider = Chef::Provider::Package.new(@new_resource, @run_context)
- @provider.current_resource = @current_resource
-
- @provider.candidate_version = "1.0"
+ let(:node) do
+ node = Chef::Node.new
+ node.automatic_attrs[:platform] = :just_testing
+ node.automatic_attrs[:platform_version] = :just_testing
+ node
+ end
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:new_resource) { Chef::Resource::Package.new("emacs") }
+ let(:current_resource) { Chef::Resource::Package.new("emacs") }
+ let(:candidate_version) { "1.0" }
+ let(:provider) do
+ provider = Chef::Provider::Package.new(new_resource, run_context)
+ provider.current_resource = current_resource
+ provider.candidate_version = candidate_version
+ provider
end
describe "when installing a package" do
before(:each) do
- @provider.current_resource = @current_resource
- allow(@provider).to receive(:install_package).and_return(true)
+ provider.current_resource = current_resource
+ allow(provider).to receive(:install_package).and_return(true)
end
it "raises a Chef::Exceptions::InvalidResourceSpecification if both multipackage and source are provided" do
- @new_resource.package_name(['a', 'b'])
- @new_resource.source('foo')
- expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
+ new_resource.package_name(%w{a b})
+ new_resource.source("foo")
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
end
it "should raise a Chef::Exceptions::Package if no version is specified, and no candidate is available" do
- @provider.candidate_version = nil
- expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ provider.candidate_version = nil
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
end
it "should call preseed_package if a response_file is given" do
- @new_resource.response_file("foo")
- expect(@provider).to receive(:get_preseed_file).with(
- @new_resource.name,
- @provider.candidate_version
+ new_resource.response_file("foo")
+ expect(provider).to receive(:get_preseed_file).with(
+ new_resource.name,
+ provider.candidate_version
).and_return("/var/cache/preseed-test")
- expect(@provider).to receive(:preseed_package).with(
+ expect(provider).to receive(:preseed_package).with(
"/var/cache/preseed-test"
).and_return(true)
- @provider.run_action(:install)
+ provider.run_action(:install)
end
it "should not call preseed_package if a response_file is not given" do
- expect(@provider).not_to receive(:preseed_package)
- @provider.run_action(:install)
+ expect(provider).not_to receive(:preseed_package)
+ provider.run_action(:install)
end
it "should install the package at the candidate_version if it is not already installed" do
- expect(@provider).to receive(:install_package).with(
- @new_resource.name,
- @provider.candidate_version
+ expect(provider).to receive(:install_package).with(
+ new_resource.name,
+ provider.candidate_version
).and_return(true)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
end
it "should install the package at the version specified if it is not already installed" do
- @new_resource.version("1.0")
- expect(@provider).to receive(:install_package).with(
- @new_resource.name,
- @new_resource.version
+ new_resource.version("1.0")
+ expect(provider).to receive(:install_package).with(
+ new_resource.name,
+ new_resource.version
).and_return(true)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
end
it "should install the package at the version specified if a different version is installed" do
- @new_resource.version("1.0")
- allow(@current_resource).to receive(:version).and_return("0.99")
- expect(@provider).to receive(:install_package).with(
- @new_resource.name,
- @new_resource.version
+ new_resource.version("1.0")
+ allow(current_resource).to receive(:version).and_return("0.99")
+ expect(provider).to receive(:install_package).with(
+ new_resource.name,
+ new_resource.version
).and_return(true)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated_by_last_action
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
end
it "should not install the package if it is already installed and no version is specified" do
- @current_resource.version("1.0")
- expect(@provider).not_to receive(:install_package)
- @provider.run_action(:install)
- expect(@new_resource).not_to be_updated_by_last_action
+ current_resource.version("1.0")
+ expect(provider).not_to receive(:install_package)
+ provider.run_action(:install)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "should not install the package if it is already installed at the version specified" do
- @current_resource.version("1.0")
- @new_resource.version("1.0")
- expect(@provider).not_to receive(:install_package)
- @provider.run_action(:install)
- expect(@new_resource).not_to be_updated_by_last_action
+ current_resource.version("1.0")
+ new_resource.version("1.0")
+ expect(provider).not_to receive(:install_package)
+ provider.run_action(:install)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "should call the candidate_version accessor only once if the package is already installed and no version is specified" do
- @current_resource.version("1.0")
- allow(@provider).to receive(:candidate_version).and_return("1.0")
- @provider.run_action(:install)
+ current_resource.version("1.0")
+ allow(provider).to receive(:candidate_version).and_return("1.0")
+ provider.run_action(:install)
end
it "should call the candidate_version accessor only once if the package is already installed at the version specified" do
- @current_resource.version("1.0")
- @new_resource.version("1.0")
- @provider.run_action(:install)
+ current_resource.version("1.0")
+ new_resource.version("1.0")
+ provider.run_action(:install)
end
it "should set the resource to updated if it installs the package" do
- @provider.run_action(:install)
- expect(@new_resource).to be_updated
+ provider.run_action(:install)
+ expect(new_resource).to be_updated
end
end
describe "when upgrading the package" do
before(:each) do
- allow(@provider).to receive(:upgrade_package).and_return(true)
+ allow(provider).to receive(:upgrade_package).and_return(true)
end
it "should upgrade the package if the current version is not the candidate version" do
- expect(@provider).to receive(:upgrade_package).with(
- @new_resource.name,
- @provider.candidate_version
+ expect(provider).to receive(:upgrade_package).with(
+ new_resource.name,
+ provider.candidate_version
).and_return(true)
- @provider.run_action(:upgrade)
- expect(@new_resource).to be_updated_by_last_action
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated_by_last_action
end
it "should set the resource to updated if it installs the package" do
- @provider.run_action(:upgrade)
- expect(@new_resource).to be_updated
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated
end
it "should not install the package if the current version is the candidate version" do
- @current_resource.version "1.0"
- expect(@provider).not_to receive(:upgrade_package)
- @provider.run_action(:upgrade)
- expect(@new_resource).not_to be_updated_by_last_action
+ current_resource.version "1.0"
+ expect(provider).not_to receive(:upgrade_package)
+ provider.run_action(:upgrade)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "should print the word 'uninstalled' if there was no original version" do
- allow(@current_resource).to receive(:version).and_return(nil)
+ allow(current_resource).to receive(:version).and_return(nil)
expect(Chef::Log).to receive(:info).with("package[emacs] upgraded emacs to 1.0")
- @provider.run_action(:upgrade)
- expect(@new_resource).to be_updated_by_last_action
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated_by_last_action
end
it "should raise a Chef::Exceptions::Package if current version and candidate are nil" do
- allow(@current_resource).to receive(:version).and_return(nil)
- @provider.candidate_version = nil
- expect { @provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+ allow(current_resource).to receive(:version).and_return(nil)
+ provider.candidate_version = nil
+ expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
end
it "should not install the package if candidate version is nil" do
- @current_resource.version "1.0"
- @provider.candidate_version = nil
- expect(@provider).not_to receive(:upgrade_package)
- @provider.run_action(:upgrade)
- expect(@new_resource).not_to be_updated_by_last_action
+ current_resource.version "1.0"
+ provider.candidate_version = nil
+ expect(provider).not_to receive(:upgrade_package)
+ provider.run_action(:upgrade)
+ expect(new_resource).not_to be_updated_by_last_action
end
end
describe "When removing the package" do
before(:each) do
- allow(@provider).to receive(:remove_package).and_return(true)
- @current_resource.version '1.4.2'
+ allow(provider).to receive(:remove_package).and_return(true)
+ current_resource.version "1.4.2"
end
it "should remove the package if it is installed" do
- expect(@provider).to be_removing_package
- expect(@provider).to receive(:remove_package).with('emacs', nil)
- @provider.run_action(:remove)
- expect(@new_resource).to be_updated
- expect(@new_resource).to be_updated_by_last_action
+ expect(provider).to be_removing_package
+ expect(provider).to receive(:remove_package).with("emacs", nil)
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated
+ expect(new_resource).to be_updated_by_last_action
end
it "should remove the package at a specific version if it is installed at that version" do
- @new_resource.version "1.4.2"
- expect(@provider).to be_removing_package
- expect(@provider).to receive(:remove_package).with('emacs', '1.4.2')
- @provider.run_action(:remove)
- expect(@new_resource).to be_updated_by_last_action
+ new_resource.version "1.4.2"
+ expect(provider).to be_removing_package
+ expect(provider).to receive(:remove_package).with("emacs", "1.4.2")
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated_by_last_action
end
it "should not remove the package at a specific version if it is not installed at that version" do
- @new_resource.version "1.0"
- expect(@provider).not_to be_removing_package
- expect(@provider).not_to receive(:remove_package)
- @provider.run_action(:remove)
- expect(@new_resource).not_to be_updated_by_last_action
+ new_resource.version "1.0"
+ expect(provider).not_to be_removing_package
+ expect(provider).not_to receive(:remove_package)
+ provider.run_action(:remove)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "should not remove the package if it is not installed" do
- expect(@provider).not_to receive(:remove_package)
- allow(@current_resource).to receive(:version).and_return(nil)
- @provider.run_action(:remove)
- expect(@new_resource).not_to be_updated_by_last_action
+ expect(provider).not_to receive(:remove_package)
+ allow(current_resource).to receive(:version).and_return(nil)
+ provider.run_action(:remove)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "should set the resource to updated if it removes the package" do
- @provider.run_action(:remove)
- expect(@new_resource).to be_updated
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated
end
end
describe "When purging the package" do
before(:each) do
- allow(@provider).to receive(:purge_package).and_return(true)
- @current_resource.version '1.4.2'
+ allow(provider).to receive(:purge_package).and_return(true)
+ current_resource.version "1.4.2"
end
it "should purge the package if it is installed" do
- expect(@provider).to be_removing_package
- expect(@provider).to receive(:purge_package).with('emacs', nil)
- @provider.run_action(:purge)
- expect(@new_resource).to be_updated
- expect(@new_resource).to be_updated_by_last_action
+ expect(provider).to be_removing_package
+ expect(provider).to receive(:purge_package).with("emacs", nil)
+ provider.run_action(:purge)
+ expect(new_resource).to be_updated
+ expect(new_resource).to be_updated_by_last_action
end
it "should purge the package at a specific version if it is installed at that version" do
- @new_resource.version "1.4.2"
- expect(@provider).to be_removing_package
- expect(@provider).to receive(:purge_package).with('emacs', '1.4.2')
- @provider.run_action(:purge)
- expect(@new_resource).to be_updated_by_last_action
+ new_resource.version "1.4.2"
+ expect(provider).to be_removing_package
+ expect(provider).to receive(:purge_package).with("emacs", "1.4.2")
+ provider.run_action(:purge)
+ expect(new_resource).to be_updated_by_last_action
end
it "should not purge the package at a specific version if it is not installed at that version" do
- @new_resource.version "1.0"
- expect(@provider).not_to be_removing_package
- expect(@provider).not_to receive(:purge_package)
- @provider.run_action(:purge)
- expect(@new_resource).not_to be_updated_by_last_action
+ new_resource.version "1.0"
+ expect(provider).not_to be_removing_package
+ expect(provider).not_to receive(:purge_package)
+ provider.run_action(:purge)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "should not purge the package if it is not installed" do
- @current_resource.instance_variable_set(:@version, nil)
- expect(@provider).not_to be_removing_package
+ current_resource.instance_variable_set(:@version, nil)
+ expect(provider).not_to be_removing_package
- expect(@provider).not_to receive(:purge_package)
- @provider.run_action(:purge)
- expect(@new_resource).not_to be_updated_by_last_action
+ expect(provider).not_to receive(:purge_package)
+ provider.run_action(:purge)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "should set the resource to updated if it purges the package" do
- @provider.run_action(:purge)
- expect(@new_resource).to be_updated
+ provider.run_action(:purge)
+ expect(new_resource).to be_updated
end
end
describe "when reconfiguring the package" do
before(:each) do
- allow(@provider).to receive(:reconfig_package).and_return(true)
+ allow(provider).to receive(:reconfig_package).and_return(true)
end
it "should info log, reconfigure the package and update the resource" do
- allow(@current_resource).to receive(:version).and_return('1.0')
- allow(@new_resource).to receive(:response_file).and_return(true)
- expect(@provider).to receive(:get_preseed_file).and_return('/var/cache/preseed-test')
- allow(@provider).to receive(:preseed_package).and_return(true)
- allow(@provider).to receive(:reconfig_package).and_return(true)
+ allow(current_resource).to receive(:version).and_return("1.0")
+ allow(new_resource).to receive(:response_file).and_return(true)
+ expect(provider).to receive(:get_preseed_file).and_return("/var/cache/preseed-test")
+ allow(provider).to receive(:preseed_package).and_return(true)
+ allow(provider).to receive(:reconfig_package).and_return(true)
expect(Chef::Log).to receive(:info).with("package[emacs] reconfigured")
- expect(@provider).to receive(:reconfig_package)
- @provider.run_action(:reconfig)
- expect(@new_resource).to be_updated
- expect(@new_resource).to be_updated_by_last_action
+ expect(provider).to receive(:reconfig_package)
+ provider.run_action(:reconfig)
+ expect(new_resource).to be_updated
+ expect(new_resource).to be_updated_by_last_action
end
it "should debug log and not reconfigure the package if the package is not installed" do
- allow(@current_resource).to receive(:version).and_return(nil)
+ allow(current_resource).to receive(:version).and_return(nil)
expect(Chef::Log).to receive(:debug).with("package[emacs] is NOT installed - nothing to do")
- expect(@provider).not_to receive(:reconfig_package)
- @provider.run_action(:reconfig)
- expect(@new_resource).not_to be_updated_by_last_action
+ expect(provider).not_to receive(:reconfig_package)
+ provider.run_action(:reconfig)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "should debug log and not reconfigure the package if no response_file is given" do
- allow(@current_resource).to receive(:version).and_return('1.0')
- allow(@new_resource).to receive(:response_file).and_return(nil)
+ allow(current_resource).to receive(:version).and_return("1.0")
+ allow(new_resource).to receive(:response_file).and_return(nil)
expect(Chef::Log).to receive(:debug).with("package[emacs] no response_file provided - nothing to do")
- expect(@provider).not_to receive(:reconfig_package)
- @provider.run_action(:reconfig)
- expect(@new_resource).not_to be_updated_by_last_action
+ expect(provider).not_to receive(:reconfig_package)
+ provider.run_action(:reconfig)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "should debug log and not reconfigure the package if the response_file has not changed" do
- allow(@current_resource).to receive(:version).and_return('1.0')
- allow(@new_resource).to receive(:response_file).and_return(true)
- expect(@provider).to receive(:get_preseed_file).and_return(false)
- allow(@provider).to receive(:preseed_package).and_return(false)
+ allow(current_resource).to receive(:version).and_return("1.0")
+ allow(new_resource).to receive(:response_file).and_return(true)
+ expect(provider).to receive(:get_preseed_file).and_return(false)
+ allow(provider).to receive(:preseed_package).and_return(false)
expect(Chef::Log).to receive(:debug).with("package[emacs] preseeding has not changed - nothing to do")
- expect(@provider).not_to receive(:reconfig_package)
- @provider.run_action(:reconfig)
- expect(@new_resource).not_to be_updated_by_last_action
+ expect(provider).not_to receive(:reconfig_package)
+ provider.run_action(:reconfig)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+ end
+
+ describe "When locking the package" do
+ before(:each) do
+ allow(provider).to receive(:lock_package).and_return(true)
+ end
+
+ it "should lock the package if it is unlocked" do
+ allow(provider).to receive(:package_locked).and_return(false)
+ expect(provider).to receive(:lock_package)
+ provider.run_action(:lock)
+ end
+
+ it "should not lock the package if it is already locked" do
+ allow(provider).to receive(:package_locked).and_return(true)
+ expect(provider).not_to receive(:lock_package)
+ provider.run_action(:lock)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "should set the resource to updated if it locks the package" do
+ allow(provider).to receive(:package_locked).and_return(false)
+ provider.run_action(:lock)
+ expect(new_resource).to be_updated
+ end
+ end
+
+ describe "When unlocking the package" do
+ before(:each) do
+ allow(provider).to receive(:unlock_package).and_return(true)
+ end
+
+ it "should unlock the package if it is locked" do
+ allow(provider).to receive(:package_locked).and_return(true)
+ expect(provider).to receive(:unlock_package)
+ provider.run_action(:unlock)
+ end
+
+ it "should not unlock the package if it is already unlocked" do
+ allow(provider).to receive(:package_locked).and_return(false)
+ expect(provider).not_to receive(:unlock_package)
+ provider.run_action(:unlock)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "should set the resource to updated if it unlocks the package" do
+ allow(provider).to receive(:package_locked).and_return(true)
+ provider.run_action(:unlock)
+ expect(new_resource).to be_updated
end
end
describe "when running commands to be implemented by subclasses" do
it "should raises UnsupportedAction for install" do
- expect { @provider.install_package('emacs', '1.4.2') }.to raise_error(Chef::Exceptions::UnsupportedAction)
+ expect { provider.install_package("emacs", "1.4.2") }.to raise_error(Chef::Exceptions::UnsupportedAction)
end
it "should raises UnsupportedAction for upgrade" do
- expect { @provider.upgrade_package('emacs', '1.4.2') }.to raise_error(Chef::Exceptions::UnsupportedAction)
+ expect { provider.upgrade_package("emacs", "1.4.2") }.to raise_error(Chef::Exceptions::UnsupportedAction)
end
it "should raises UnsupportedAction for remove" do
- expect { @provider.remove_package('emacs', '1.4.2') }.to raise_error(Chef::Exceptions::UnsupportedAction)
+ expect { provider.remove_package("emacs", "1.4.2") }.to raise_error(Chef::Exceptions::UnsupportedAction)
end
it "should raises UnsupportedAction for purge" do
- expect { @provider.purge_package('emacs', '1.4.2') }.to raise_error(Chef::Exceptions::UnsupportedAction)
+ expect { provider.purge_package("emacs", "1.4.2") }.to raise_error(Chef::Exceptions::UnsupportedAction)
end
it "should raise UnsupportedAction for preseed_package" do
preseed_file = "/tmp/sun-jdk-package-preseed-file.seed"
- expect { @provider.preseed_package(preseed_file) }.to raise_error(Chef::Exceptions::UnsupportedAction)
+ expect { provider.preseed_package(preseed_file) }.to raise_error(Chef::Exceptions::UnsupportedAction)
end
it "should raise UnsupportedAction for reconfig" do
- expect { @provider.reconfig_package('emacs', '1.4.2') }.to raise_error(Chef::Exceptions::UnsupportedAction)
+ expect { provider.reconfig_package("emacs", "1.4.2") }.to raise_error(Chef::Exceptions::UnsupportedAction)
end
- end
-
- describe "when given a response file" do
- before(:each) do
- @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.fetch_from_disk(@cookbook_repo)
-
- @node = Chef::Node.new
- cl = Chef::CookbookLoader.new(@cookbook_repo)
- cl.load_cookbooks
- @cookbook_collection = Chef::CookbookCollection.new(cl)
- @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
- @provider.run_context = @run_context
+ it "should raise UnsupportedAction for lock" do
+ expect { provider.lock_package("emacs", nil) }.to raise_error(Chef::Exceptions::UnsupportedAction)
+ end
- @node.automatic_attrs[:platform] = 'PLATFORM: just testing'
- @node.automatic_attrs[:platform_version] = 'PLATFORM VERSION: just testing'
+ it "should raise UnsupportedAction for unlock" do
+ expect { provider.unlock_package("emacs", nil) }.to raise_error(Chef::Exceptions::UnsupportedAction)
+ end
+ end
- @new_resource.response_file('java.response')
- @new_resource.cookbook_name = 'java'
+ describe "when given a response file" do
+ let(:cookbook_repo) { File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) }
+ let(:cookbook_loader) do
+ Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
+ Chef::CookbookLoader.new(cookbook_repo)
+ end
+ let(:cookbook_collection) do
+ cookbook_loader.load_cookbooks
+ Chef::CookbookCollection.new(cookbook_loader)
+ end
+ let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) }
+ let(:new_resource) do
+ new_resource = Chef::Resource::Package.new("emacs")
+ new_resource.response_file("java.response")
+ new_resource.cookbook_name = "java"
+ new_resource
end
describe "creating the cookbook file resource to fetch the response file" do
before do
- expect(Chef::FileCache).to receive(:create_cache_path).with('preseed/java').and_return("/tmp/preseed/java")
+ expect(Chef::FileCache).to receive(:create_cache_path).with("preseed/java").and_return("/tmp/preseed/java")
end
it "sets the preseed resource's runcontext to its own run context" do
allow(Chef::FileCache).to receive(:create_cache_path).and_return("/tmp/preseed/java")
- expect(@provider.preseed_resource('java', '6').run_context).not_to be_nil
- expect(@provider.preseed_resource('java', '6').run_context).to equal(@provider.run_context)
+ expect(provider.preseed_resource("java", "6").run_context).not_to be_nil
+ expect(provider.preseed_resource("java", "6").run_context).to equal(provider.run_context)
end
it "should set the cookbook name of the remote file to the new resources cookbook name" do
- expect(@provider.preseed_resource('java', '6').cookbook_name).to eq('java')
+ expect(provider.preseed_resource("java", "6").cookbook_name).to eq("java")
end
it "should set remote files source to the new resources response file" do
- expect(@provider.preseed_resource('java', '6').source).to eq('java.response')
+ expect(provider.preseed_resource("java", "6").source).to eq("java.response")
end
it "should never back up the cached response file" do
- expect(@provider.preseed_resource('java', '6').backup).to be_falsey
+ expect(provider.preseed_resource("java", "6").backup).to be_falsey
end
it "sets the install path of the resource to $file_cache/$cookbook/$pkg_name-$pkg_version.seed" do
- expect(@provider.preseed_resource('java', '6').path).to eq('/tmp/preseed/java/java-6.seed')
+ expect(provider.preseed_resource("java", "6").path).to eq("/tmp/preseed/java/java-6.seed")
end
end
describe "when installing the preseed file to the cache location" do
- before do
- @node.automatic_attrs[:platform] = :just_testing
- @node.automatic_attrs[:platform_version] = :just_testing
-
- @response_file_destination = Dir.tmpdir + '/preseed--java--java-6.seed'
-
- @response_file_resource = Chef::Resource::CookbookFile.new(@response_file_destination, @run_context)
- @response_file_resource.cookbook_name = 'java'
- @response_file_resource.backup(false)
- @response_file_resource.source('java.response')
-
+ let(:response_file_destination) { Dir.tmpdir + "/preseed--java--java-6.seed" }
+ let(:response_file_resource) do
+ response_file_resource = Chef::Resource::CookbookFile.new(response_file_destination, run_context)
+ response_file_resource.cookbook_name = "java"
+ response_file_resource.backup(false)
+ response_file_resource.source("java.response")
+ response_file_resource
+ end
- expect(@provider).to receive(:preseed_resource).with('java', '6').and_return(@response_file_resource)
+ before do
+ expect(provider).to receive(:preseed_resource).with("java", "6").and_return(response_file_resource)
end
after do
- FileUtils.rm(@response_file_destination) if ::File.exist?(@response_file_destination)
+ FileUtils.rm(response_file_destination) if ::File.exist?(response_file_destination)
end
it "creates the preseed file in the cache" do
- expect(@response_file_resource).to receive(:run_action).with(:create)
- @provider.get_preseed_file("java", "6")
+ expect(response_file_resource).to receive(:run_action).with(:create)
+ provider.get_preseed_file("java", "6")
end
it "returns the path to the response file if the response file was updated" do
- expect(@provider.get_preseed_file("java", "6")).to eq(@response_file_destination)
+ expect(provider.get_preseed_file("java", "6")).to eq(response_file_destination)
end
it "should return false if the response file has not been updated" do
- @response_file_resource.updated_by_last_action(false)
- expect(@response_file_resource).not_to be_updated_by_last_action
+ response_file_resource.updated_by_last_action(false)
+ expect(response_file_resource).not_to be_updated_by_last_action
# don't let the response_file_resource set updated to true
- expect(@response_file_resource).to receive(:run_action).with(:create)
- expect(@provider.get_preseed_file("java", "6")).to be(false)
+ expect(response_file_resource).to receive(:run_action).with(:create)
+ expect(provider.get_preseed_file("java", "6")).to be(false)
end
end
@@ -432,308 +492,456 @@ describe Chef::Provider::Package do
end
end
+describe "Subclass with use_multipackage_api" do
+ class MyPackageResource < Chef::Resource::Package
+ end
+
+ class MyPackageProvider < Chef::Provider::Package
+ use_multipackage_api
+ end
+
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:new_resource) { MyPackageResource.new("installs the packages") }
+ let(:current_resource) { MyPackageResource.new("installs the packages") }
+ let(:provider) do
+ provider = MyPackageProvider.new(new_resource, run_context)
+ provider.current_resource = current_resource
+ provider
+ end
+
+ it "has use_multipackage_api? methods on the class and instance" do
+ expect(MyPackageProvider.use_multipackage_api?).to be true
+ expect(provider.use_multipackage_api?).to be true
+ end
+
+ context "#a_to_s utility for subclasses" do
+ before(:each) do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ end
+
+ it "converts varargs of strings to a single string" do
+ expect(provider.send(:a_to_s, "a", nil, "b", "", "c", " ", "d e", "f-g")).to eq("a b c d e f-g")
+ end
+
+ it "converts an array of strings to a single string" do
+ expect(provider.send(:a_to_s, ["a", nil, "b", "", "c", " ", "d e", "f-g"])).to eq("a b c d e f-g")
+ end
+
+ it "converts a mishmash of array args to a single string" do
+ expect(provider.send(:a_to_s, "a", [ nil, "b", "", [ "c" ] ], " ", [ "d e", "f-g" ])).to eq("a b c d e f-g")
+ end
+ end
+
+ it "when user passes string to package_name, passes arrays to install_package" do
+ new_resource.package_name "vim"
+ new_resource.version nil
+ provider.candidate_version = [ "1.0" ]
+ expect(provider).to receive(:install_package).with(
+ [ "vim" ],
+ [ "1.0" ]
+ ).and_return(true)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ expect(new_resource.version).to eql(nil)
+ end
+
+ it "when user pases string to package_name and version, passes arrays to install_package" do
+ new_resource.package_name "vim"
+ new_resource.version "1.0"
+ provider.candidate_version = [ "1.0" ]
+ expect(provider).to receive(:install_package).with(
+ [ "vim" ],
+ [ "1.0" ]
+ ).and_return(true)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ expect(new_resource.version).to eql("1.0")
+ end
+
+ it "when user passes string to package_name, passes arrays to upgrade_package" do
+ new_resource.package_name "vim"
+ new_resource.version nil
+ provider.candidate_version = [ "1.0" ]
+ expect(provider).to receive(:upgrade_package).with(
+ [ "vim" ],
+ [ "1.0" ]
+ ).and_return(true)
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated_by_last_action
+ expect(new_resource.version).to eql(nil)
+ end
+
+ it "when user pases string to package_name and version, passes arrays to upgrade_package" do
+ new_resource.package_name "vim"
+ new_resource.version "1.0"
+ provider.candidate_version = [ "1.0" ]
+ expect(provider).to receive(:upgrade_package).with(
+ [ "vim" ],
+ [ "1.0" ]
+ ).and_return(true)
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated_by_last_action
+ expect(new_resource.version).to eql("1.0")
+ end
+
+ it "when user passes string to package_name, passes arrays to remove_package" do
+ new_resource.package_name "vim"
+ current_resource.package_name "vim"
+ current_resource.version [ "1.0" ]
+ provider.candidate_version = [ "1.0" ]
+ expect(provider).to receive(:remove_package).with(
+ [ "vim" ],
+ [ nil ]
+ ).and_return(true)
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated_by_last_action
+ expect(new_resource.version).to eql(nil)
+ end
+
+ it "when user passes string to package_name, passes arrays to purge_package" do
+ new_resource.package_name "vim"
+ current_resource.package_name "vim"
+ current_resource.version [ "1.0" ]
+ provider.candidate_version = [ "1.0" ]
+ expect(provider).to receive(:purge_package).with(
+ [ "vim" ],
+ [ nil ]
+ ).and_return(true)
+ provider.run_action(:purge)
+ expect(new_resource).to be_updated_by_last_action
+ expect(new_resource.version).to eql(nil)
+ end
+
+ it "when user passes string to package_name, passes arrays to reconfig_package" do
+ new_resource.package_name "vim"
+ current_resource.package_name "vim"
+ current_resource.version [ "1.0" ]
+ allow(new_resource).to receive(:response_file).and_return(true)
+ expect(provider).to receive(:get_preseed_file).and_return("/var/cache/preseed-test")
+ allow(provider).to receive(:preseed_package).and_return(true)
+ allow(provider).to receive(:reconfig_package).and_return(true)
+ expect(provider).to receive(:reconfig_package).with(
+ [ "vim" ],
+ [ "1.0" ]
+ ).and_return(true)
+ provider.run_action(:reconfig)
+ expect(new_resource).to be_updated_by_last_action
+ end
+end
+
describe "Chef::Provider::Package - Multi" do
- before do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Package.new(['emacs', 'vi'])
- @current_resource = Chef::Resource::Package.new(['emacs', 'vi'])
- @provider = Chef::Provider::Package.new(@new_resource, @run_context)
- @provider.current_resource = @current_resource
- @provider.candidate_version = ['1.0', '6.2']
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:new_resource) { Chef::Resource::Package.new(%w{emacs vi}) }
+ let(:current_resource) { Chef::Resource::Package.new(%w{emacs vi}) }
+ let(:candidate_version) { [ "1.0", "6.2" ] }
+ class MyPackageProvider < Chef::Provider::Package
+ use_multipackage_api
+ end
+ let(:provider) do
+ provider = MyPackageProvider.new(new_resource, run_context)
+ provider.current_resource = current_resource
+ provider.candidate_version = candidate_version
+ provider
end
describe "when installing multiple packages" do
before(:each) do
- @provider.current_resource = @current_resource
- allow(@provider).to receive(:install_package).and_return(true)
+ provider.current_resource = current_resource
+ allow(provider).to receive(:install_package).and_return(true)
end
it "installs the candidate versions when none are installed" do
- expect(@provider).to receive(:install_package).with(
- ["emacs", "vi"],
+ expect(provider).to receive(:install_package).with(
+ %w{emacs vi},
["1.0", "6.2"]
).and_return(true)
- @provider.run_action(:install)
- expect(@new_resource).to be_updated
+ provider.run_action(:install)
+ expect(new_resource).to be_updated
end
it "installs the candidate versions when some are installed" do
- expect(@provider).to receive(:install_package).with(
- [ 'vi' ],
- [ '6.2' ]
+ expect(provider).to receive(:install_package).with(
+ [ "vi" ],
+ [ "6.2" ]
).and_return(true)
- @current_resource.version(['1.0', nil])
- @provider.run_action(:install)
- expect(@new_resource).to be_updated
+ current_resource.version(["1.0", nil])
+ provider.run_action(:install)
+ expect(new_resource).to be_updated
end
it "installs the specified version when some are out of date" do
- @current_resource.version(['1.0', '6.2'])
- @new_resource.version(['1.0', '6.1'])
- @provider.run_action(:install)
- expect(@new_resource).to be_updated
+ current_resource.version(["1.0", "6.2"])
+ new_resource.version(["1.0", "6.1"])
+ provider.run_action(:install)
+ expect(new_resource).to be_updated
end
it "does not install any version if all are installed at the right version" do
- @current_resource.version(['1.0', '6.2'])
- @new_resource.version(['1.0', '6.2'])
- @provider.run_action(:install)
- expect(@new_resource).not_to be_updated_by_last_action
+ current_resource.version(["1.0", "6.2"])
+ new_resource.version(["1.0", "6.2"])
+ provider.run_action(:install)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "does not install any version if all are installed, and no version was specified" do
- @current_resource.version(['1.0', '6.2'])
- @provider.run_action(:install)
- expect(@new_resource).not_to be_updated_by_last_action
+ current_resource.version(["1.0", "6.2"])
+ provider.run_action(:install)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "raises an exception if both are not installed and no caondidates are available" do
- @current_resource.version([nil, nil])
- @provider.candidate_version = [nil, nil]
- expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ current_resource.version([nil, nil])
+ provider.candidate_version = [nil, nil]
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
end
it "raises an exception if one is not installed and no candidates are available" do
- @current_resource.version(['1.0', nil])
- @provider.candidate_version = ['1.0', nil]
- expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ current_resource.version(["1.0", nil])
+ provider.candidate_version = ["1.0", nil]
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
end
it "does not raise an exception if the packages are installed or have a candidate" do
- @current_resource.version(['1.0', nil])
- @provider.candidate_version = [nil, '6.2']
- expect { @provider.run_action(:install) }.not_to raise_error
+ current_resource.version(["1.0", nil])
+ provider.candidate_version = [nil, "6.2"]
+ expect { provider.run_action(:install) }.not_to raise_error
end
it "raises an exception if an explicit version is asked for, an old version is installed, but no candidate" do
- @new_resource.version ['1.0', '6.2']
- @current_resource.version(['1.0', '6.1'])
- @provider.candidate_version = ['1.0', nil]
- expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ new_resource.version ["1.0", "6.2"]
+ current_resource.version(["1.0", "6.1"])
+ provider.candidate_version = ["1.0", nil]
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
end
it "does not raise an exception if an explicit version is asked for, and is installed, but no candidate" do
- @new_resource.version ['1.0', '6.2']
- @current_resource.version(['1.0', '6.2'])
- @provider.candidate_version = ['1.0', nil]
- expect { @provider.run_action(:install) }.not_to raise_error
+ new_resource.version ["1.0", "6.2"]
+ current_resource.version(["1.0", "6.2"])
+ provider.candidate_version = ["1.0", nil]
+ expect { provider.run_action(:install) }.not_to raise_error
end
it "raise an exception if an explicit version is asked for, and is not installed, and no candidate" do
- @new_resource.version ['1.0', '6.2']
- @current_resource.version(['1.0', nil])
- @provider.candidate_version = ['1.0', nil]
- expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ new_resource.version ["1.0", "6.2"]
+ current_resource.version(["1.0", nil])
+ provider.candidate_version = ["1.0", nil]
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
end
it "does not raise an exception if an explicit version is asked for, and is not installed, and there is a candidate" do
- @new_resource.version ['1.0', '6.2']
- @current_resource.version(['1.0', nil])
- @provider.candidate_version = ['1.0', '6.2']
- expect { @provider.run_action(:install) }.not_to raise_error
+ new_resource.version ["1.0", "6.2"]
+ current_resource.version(["1.0", nil])
+ provider.candidate_version = ["1.0", "6.2"]
+ expect { provider.run_action(:install) }.not_to raise_error
end
end
describe "when upgrading multiple packages" do
before(:each) do
- @provider.current_resource = @current_resource
- allow(@provider).to receive(:upgrade_package).and_return(true)
+ provider.current_resource = current_resource
+ allow(provider).to receive(:upgrade_package).and_return(true)
end
it "should upgrade the package if the current versions are not the candidate version" do
- @current_resource.version ['0.9', '6.1']
- expect(@provider).to receive(:upgrade_package).with(
- @new_resource.package_name,
- @provider.candidate_version
+ current_resource.version ["0.9", "6.1"]
+ expect(provider).to receive(:upgrade_package).with(
+ new_resource.package_name,
+ provider.candidate_version
).and_return(true)
- @provider.run_action(:upgrade)
- expect(@new_resource).to be_updated_by_last_action
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated_by_last_action
end
it "should upgrade the package if some of current versions are not the candidate versions" do
- @current_resource.version ['1.0', '6.1']
- expect(@provider).to receive(:upgrade_package).with(
+ current_resource.version ["1.0", "6.1"]
+ expect(provider).to receive(:upgrade_package).with(
["vi"],
["6.2"]
).and_return(true)
- @provider.run_action(:upgrade)
- expect(@new_resource).to be_updated_by_last_action
+ provider.run_action(:upgrade)
+ expect(new_resource).to be_updated_by_last_action
end
it "should not install the package if the current versions are the candidate version" do
- @current_resource.version ['1.0', '6.2']
- expect(@provider).not_to receive(:upgrade_package)
- @provider.run_action(:upgrade)
- expect(@new_resource).not_to be_updated_by_last_action
+ current_resource.version ["1.0", "6.2"]
+ expect(provider).not_to receive(:upgrade_package)
+ provider.run_action(:upgrade)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "should raise an exception if both are not installed and no caondidates are available" do
- @current_resource.version([nil, nil])
- @provider.candidate_version = [nil, nil]
- expect { @provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+ current_resource.version([nil, nil])
+ provider.candidate_version = [nil, nil]
+ expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
end
it "should raise an exception if one is not installed and no candidates are available" do
- @current_resource.version(['1.0', nil])
- @provider.candidate_version = ['1.0', nil]
- expect { @provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+ current_resource.version(["1.0", nil])
+ provider.candidate_version = ["1.0", nil]
+ expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
end
it "should not raise an exception if the packages are installed or have a candidate" do
- @current_resource.version(['1.0', nil])
- @provider.candidate_version = [nil, '6.2']
- expect { @provider.run_action(:upgrade) }.not_to raise_error
+ current_resource.version(["1.0", nil])
+ provider.candidate_version = [nil, "6.2"]
+ expect { provider.run_action(:upgrade) }.not_to raise_error
end
it "should not raise an exception if the packages are installed or have a candidate" do
- @current_resource.version(['1.0', nil])
- @provider.candidate_version = [nil, '6.2']
- expect { @provider.run_action(:upgrade) }.not_to raise_error
+ current_resource.version(["1.0", nil])
+ provider.candidate_version = [nil, "6.2"]
+ expect { provider.run_action(:upgrade) }.not_to raise_error
end
end
describe "When removing multiple packages " do
before(:each) do
- allow(@provider).to receive(:remove_package).and_return(true)
- @current_resource.version ['1.0', '6.2']
+ allow(provider).to receive(:remove_package).and_return(true)
+ current_resource.version ["1.0", "6.2"]
end
it "should remove the packages if all are installed" do
- expect(@provider).to be_removing_package
- expect(@provider).to receive(:remove_package).with(['emacs', 'vi'], nil)
- @provider.run_action(:remove)
- expect(@new_resource).to be_updated
- expect(@new_resource).to be_updated_by_last_action
+ expect(provider).to be_removing_package
+ expect(provider).to receive(:remove_package).with(%w{emacs vi}, [nil])
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated
+ expect(new_resource).to be_updated_by_last_action
end
it "should remove the packages if some are installed" do
- @current_resource.version ['1.0', nil]
- expect(@provider).to be_removing_package
- expect(@provider).to receive(:remove_package).with(['emacs', 'vi'], nil)
- @provider.run_action(:remove)
- expect(@new_resource).to be_updated
- expect(@new_resource).to be_updated_by_last_action
+ current_resource.version ["1.0", nil]
+ expect(provider).to be_removing_package
+ expect(provider).to receive(:remove_package).with(%w{emacs vi}, [nil])
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated
+ expect(new_resource).to be_updated_by_last_action
end
it "should remove the packages at a specific version if they are installed at that version" do
- @new_resource.version ['1.0', '6.2']
- expect(@provider).to be_removing_package
- expect(@provider).to receive(:remove_package).with(['emacs', 'vi'], ['1.0', '6.2'])
- @provider.run_action(:remove)
- expect(@new_resource).to be_updated_by_last_action
+ new_resource.version ["1.0", "6.2"]
+ expect(provider).to be_removing_package
+ expect(provider).to receive(:remove_package).with(%w{emacs vi}, ["1.0", "6.2"])
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated_by_last_action
end
it "should remove the packages at a specific version any are is installed at that version" do
- @new_resource.version ['0.5', '6.2']
- expect(@provider).to be_removing_package
- expect(@provider).to receive(:remove_package).with(['emacs', 'vi'], ['0.5', '6.2'])
- @provider.run_action(:remove)
- expect(@new_resource).to be_updated_by_last_action
+ new_resource.version ["0.5", "6.2"]
+ expect(provider).to be_removing_package
+ expect(provider).to receive(:remove_package).with(%w{emacs vi}, ["0.5", "6.2"])
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated_by_last_action
end
it "should not remove the packages at a specific version if they are not installed at that version" do
- @new_resource.version ['0.5', '6.0']
- expect(@provider).not_to be_removing_package
- expect(@provider).not_to receive(:remove_package)
- @provider.run_action(:remove)
- expect(@new_resource).not_to be_updated_by_last_action
+ new_resource.version ["0.5", "6.0"]
+ expect(provider).not_to be_removing_package
+ expect(provider).not_to receive(:remove_package)
+ provider.run_action(:remove)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "should not remove the packages if they are not installed" do
- expect(@provider).not_to receive(:remove_package)
- allow(@current_resource).to receive(:version).and_return(nil)
- @provider.run_action(:remove)
- expect(@new_resource).not_to be_updated_by_last_action
+ expect(provider).not_to receive(:remove_package)
+ allow(current_resource).to receive(:version).and_return(nil)
+ provider.run_action(:remove)
+ expect(new_resource).not_to be_updated_by_last_action
end
end
describe "When purging multiple packages " do
before(:each) do
- allow(@provider).to receive(:purge_package).and_return(true)
- @current_resource.version ['1.0', '6.2']
+ allow(provider).to receive(:purge_package).and_return(true)
+ current_resource.version ["1.0", "6.2"]
end
it "should purge the packages if all are installed" do
- expect(@provider).to be_removing_package
- expect(@provider).to receive(:purge_package).with(['emacs', 'vi'], nil)
- @provider.run_action(:purge)
- expect(@new_resource).to be_updated
- expect(@new_resource).to be_updated_by_last_action
+ expect(provider).to be_removing_package
+ expect(provider).to receive(:purge_package).with(%w{emacs vi}, [nil])
+ provider.run_action(:purge)
+ expect(new_resource).to be_updated
+ expect(new_resource).to be_updated_by_last_action
end
it "should purge the packages if some are installed" do
- @current_resource.version ['1.0', nil]
- expect(@provider).to be_removing_package
- expect(@provider).to receive(:purge_package).with(['emacs', 'vi'], nil)
- @provider.run_action(:purge)
- expect(@new_resource).to be_updated
- expect(@new_resource).to be_updated_by_last_action
+ current_resource.version ["1.0", nil]
+ expect(provider).to be_removing_package
+ expect(provider).to receive(:purge_package).with(%w{emacs vi}, [nil])
+ provider.run_action(:purge)
+ expect(new_resource).to be_updated
+ expect(new_resource).to be_updated_by_last_action
end
it "should purge the packages at a specific version if they are installed at that version" do
- @new_resource.version ['1.0', '6.2']
- expect(@provider).to be_removing_package
- expect(@provider).to receive(:purge_package).with(['emacs', 'vi'], ['1.0', '6.2'])
- @provider.run_action(:purge)
- expect(@new_resource).to be_updated_by_last_action
+ new_resource.version ["1.0", "6.2"]
+ expect(provider).to be_removing_package
+ expect(provider).to receive(:purge_package).with(%w{emacs vi}, ["1.0", "6.2"])
+ provider.run_action(:purge)
+ expect(new_resource).to be_updated_by_last_action
end
it "should purge the packages at a specific version any are is installed at that version" do
- @new_resource.version ['0.5', '6.2']
- expect(@provider).to be_removing_package
- expect(@provider).to receive(:purge_package).with(['emacs', 'vi'], ['0.5', '6.2'])
- @provider.run_action(:purge)
- expect(@new_resource).to be_updated_by_last_action
+ new_resource.version ["0.5", "6.2"]
+ expect(provider).to be_removing_package
+ expect(provider).to receive(:purge_package).with(%w{emacs vi}, ["0.5", "6.2"])
+ provider.run_action(:purge)
+ expect(new_resource).to be_updated_by_last_action
end
it "should not purge the packages at a specific version if they are not installed at that version" do
- @new_resource.version ['0.5', '6.0']
- expect(@provider).not_to be_removing_package
- expect(@provider).not_to receive(:purge_package)
- @provider.run_action(:purge)
- expect(@new_resource).not_to be_updated_by_last_action
+ new_resource.version ["0.5", "6.0"]
+ expect(provider).not_to be_removing_package
+ expect(provider).not_to receive(:purge_package)
+ provider.run_action(:purge)
+ expect(new_resource).not_to be_updated_by_last_action
end
it "should not purge the packages if they are not installed" do
- expect(@provider).not_to receive(:purge_package)
- allow(@current_resource).to receive(:version).and_return(nil)
- @provider.run_action(:purge)
- expect(@new_resource).not_to be_updated_by_last_action
+ expect(provider).not_to receive(:purge_package)
+ allow(current_resource).to receive(:version).and_return(nil)
+ provider.run_action(:purge)
+ expect(new_resource).not_to be_updated_by_last_action
end
end
describe "shell_out helpers" do
+ before(:each) do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ end
+
[ :shell_out_with_timeout, :shell_out_with_timeout! ].each do |method|
stubbed_method = method == :shell_out_with_timeout! ? :shell_out! : :shell_out
[ %w{command arg1 arg2}, "command arg1 arg2" ].each do |command|
it "#{method} defaults to 900 seconds" do
- expect(@provider).to receive(stubbed_method).with(*command, timeout: 900)
- @provider.send(method, *command)
+ expect(provider).to receive(stubbed_method).with(*command, timeout: 900)
+ provider.send(method, *command)
end
it "#{method} overrides the default timeout with its options" do
- expect(@provider).to receive(stubbed_method).with(*command, timeout: 1)
- @provider.send(method, *command, timeout: 1)
+ expect(provider).to receive(stubbed_method).with(*command, timeout: 1)
+ provider.send(method, *command, timeout: 1)
end
it "#{method} overrides both timeouts with the new_resource.timeout" do
- @new_resource.timeout(99)
- expect(@provider).to receive(stubbed_method).with(*command, timeout: 99)
- @provider.send(method, *command, timeout: 1)
+ new_resource.timeout(99)
+ expect(provider).to receive(stubbed_method).with(*command, timeout: 99)
+ provider.send(method, *command, timeout: 1)
end
it "#{method} defaults to 900 seconds and preserves options" do
- expect(@provider).to receive(stubbed_method).with(*command, env: nil, timeout: 900)
- @provider.send(method, *command, env: nil)
+ expect(provider).to receive(stubbed_method).with(*command, env: nil, timeout: 900)
+ provider.send(method, *command, env: nil)
end
it "#{method} overrides the default timeout with its options and preserves options" do
- expect(@provider).to receive(stubbed_method).with(*command, timeout: 1, env: nil)
- @provider.send(method, *command, timeout: 1, env: nil)
+ expect(provider).to receive(stubbed_method).with(*command, timeout: 1, env: nil)
+ provider.send(method, *command, timeout: 1, env: nil)
end
it "#{method} overrides both timeouts with the new_resource.timeout and preseves options" do
- @new_resource.timeout(99)
- expect(@provider).to receive(stubbed_method).with(*command, timeout: 99, env: nil)
- @provider.send(method, *command, timeout: 1, env: nil)
+ new_resource.timeout(99)
+ expect(provider).to receive(stubbed_method).with(*command, timeout: 99, env: nil)
+ provider.send(method, *command, timeout: 1, env: nil)
end
end
end
diff --git a/spec/unit/provider/powershell_script_spec.rb b/spec/unit/provider/powershell_script_spec.rb
index 121973763d..4fd3f3534d 100644
--- a/spec/unit/provider/powershell_script_spec.rb
+++ b/spec/unit/provider/powershell_script_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::PowershellScript, "action_run" do
let(:powershell_version) { nil }
- let(:node) {
+ let(:node) do
node = Chef::Node.new
node.default["kernel"] = Hash.new
node.default["kernel"][:machine] = :x86_64.to_s
@@ -28,71 +28,71 @@ describe Chef::Provider::PowershellScript, "action_run" do
node.default[:languages] = { :powershell => { :version => powershell_version } }
end
node
- }
+ end
- let(:provider) {
+ let(:provider) do
empty_events = Chef::EventDispatch::Dispatcher.new
run_context = Chef::RunContext.new(node, {}, empty_events)
- new_resource = Chef::Resource::PowershellScript.new('run some powershell code', run_context)
+ new_resource = Chef::Resource::PowershellScript.new("run some powershell code", run_context)
Chef::Provider::PowershellScript.new(new_resource, run_context)
- }
+ end
- context 'when setting interpreter flags' do
- context 'on nano' do
+ context "when setting interpreter flags" do
+ context "on nano" do
before(:each) do
allow(Chef::Platform).to receive(:windows_nano_server?).and_return(true)
allow(provider).to receive(:is_forced_32bit).and_return(false)
os_info_double = double("os_info")
- allow(provider.run_context.node.kernel).to receive(:os_info).and_return(os_info_double)
- allow(os_info_double).to receive(:system_directory).and_return("C:\\Windows\\system32")
+ allow(provider.run_context.node["kernel"]).to receive(:[]).with("os_info").and_return(os_info_double)
+ allow(os_info_double).to receive(:[]).with("system_directory").and_return("C:\\Windows\\system32")
end
it "sets the -Command flag as the last flag" do
- flags = provider.command.split(' ').keep_if { |flag| flag =~ /^-/ }
+ flags = provider.command.split(" ").keep_if { |flag| flag =~ /^-/ }
expect(flags.pop).to eq("-Command")
end
end
- context 'not on nano' do
+ context "not on nano" do
before(:each) do
allow(Chef::Platform).to receive(:windows_nano_server?).and_return(false)
allow(provider).to receive(:is_forced_32bit).and_return(false)
os_info_double = double("os_info")
- allow(provider.run_context.node.kernel).to receive(:os_info).and_return(os_info_double)
- allow(os_info_double).to receive(:system_directory).and_return("C:\\Windows\\system32")
+ allow(provider.run_context.node["kernel"]).to receive(:[]).with("os_info").and_return(os_info_double)
+ allow(os_info_double).to receive(:[]).with("system_directory").and_return("C:\\Windows\\system32")
end
it "sets the -File flag as the last flag" do
- flags = provider.command.split(' ').keep_if { |flag| flag =~ /^-/ }
+ flags = provider.command.split(" ").keep_if { |flag| flag =~ /^-/ }
expect(flags.pop).to eq("-File")
end
let(:execution_policy_flag) do
execution_policy_index = 0
- provider_flags = provider.flags.split(' ')
+ provider_flags = provider.flags.split(" ")
execution_policy_specified = false
- provider_flags.find do | value |
+ provider_flags.find do |value|
execution_policy_index += 1
- execution_policy_specified = value.downcase == '-ExecutionPolicy'.downcase
+ execution_policy_specified = value.casecmp("-ExecutionPolicy".downcase).zero?
end
execution_policy = execution_policy_specified ? provider_flags[execution_policy_index] : nil
end
- context 'when running with an unspecified PowerShell version' do
+ context "when running with an unspecified PowerShell version" do
let(:powershell_version) { nil }
it "sets the -ExecutionPolicy flag to 'Unrestricted' by default" do
- expect(execution_policy_flag.downcase).to eq('unrestricted'.downcase)
+ expect(execution_policy_flag.downcase).to eq("unrestricted".downcase)
end
end
- { '2.0' => 'Unrestricted',
- '2.5' => 'Unrestricted',
- '3.0' => 'Bypass',
- '3.6' => 'Bypass',
- '4.0' => 'Bypass',
- '5.0' => 'Bypass' }.each do | version_policy |
+ { "2.0" => "Unrestricted",
+ "2.5" => "Unrestricted",
+ "3.0" => "Bypass",
+ "3.6" => "Bypass",
+ "4.0" => "Bypass",
+ "5.0" => "Bypass" }.each do |version_policy|
let(:powershell_version) { version_policy[0].to_f }
context "when running PowerShell version #{version_policy[0]}" do
let(:powershell_version) { version_policy[0].to_f }
diff --git a/spec/unit/provider/registry_key_spec.rb b/spec/unit/provider/registry_key_spec.rb
index 47543ffe39..3fb9468f5d 100644
--- a/spec/unit/provider/registry_key_spec.rb
+++ b/spec/unit/provider/registry_key_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (lamont@opscode.com)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Lamont Granquist (lamont@chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,26 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
shared_examples_for "a registry key" do
- before(:each) do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
-
- @new_resource = Chef::Resource::RegistryKey.new("windows is fun", @run_context)
- @new_resource.key keyname
- @new_resource.values( testval1 )
- @new_resource.recursive false
-
- @provider = Chef::Provider::RegistryKey.new(@new_resource, @run_context)
-
- allow(@provider).to receive(:running_on_windows!).and_return(true)
- @double_registry = double(Chef::Win32::Registry)
- allow(@provider).to receive(:registry).and_return(@double_registry)
- end
-
describe "when first created" do
end
@@ -273,6 +256,23 @@ shared_examples_for "a registry key" do
end
describe Chef::Provider::RegistryKey do
+ before(:each) do
+ @node = Chef::Node.new
+ @events = Chef::EventDispatch::Dispatcher.new
+ @run_context = Chef::RunContext.new(@node, {}, @events)
+
+ @new_resource = Chef::Resource::RegistryKey.new("windows is fun", @run_context)
+ @new_resource.key keyname
+ @new_resource.values( testval1 )
+ @new_resource.recursive false
+
+ @provider = Chef::Provider::RegistryKey.new(@new_resource, @run_context)
+
+ allow(@provider).to receive(:running_on_windows!).and_return(true)
+ @double_registry = double(Chef::Win32::Registry)
+ allow(@provider).to receive(:registry).and_return(@double_registry)
+ end
+
context "when the key data is safe" do
let(:keyname) { 'HKLM\Software\Opscode\Testing\Safe' }
let(:testval1) { { :name => "one", :type => :string, :data => "1" } }
@@ -292,4 +292,116 @@ describe Chef::Provider::RegistryKey do
it_should_behave_like "a registry key"
end
+
+ describe "action_create" do
+ context "when key exists and type matches" do
+ let(:keyname) { 'hklm\\software\\opscode\\testing\\dword' }
+ let(:dword_passed_as_integer) { { :name => "one", :type => :dword, :data => 12345 } }
+ let(:testval1) { { :name => "one", :type => :dword, :data => "12345" } }
+ before do
+ expect(@double_registry).to receive(:key_exists?).twice.with(keyname).and_return(true)
+ end
+
+ it "does not make a change for datatype of data value differing" do
+ expect(@double_registry).to receive(:get_values).with(keyname).and_return( dword_passed_as_integer )
+ expect(@double_registry).not_to receive(:set_value)
+ @provider.load_current_resource
+ @provider.action_create
+ end
+ end
+ end
+end
+
+describe Chef::Provider::RegistryKey, "key_missing?" do
+ let(:provider) { Chef::Provider::RegistryKey.new(nil, nil) }
+ let(:all_keys_present_in_all_hash) do
+ [ { :name => "input1_value1", :type => :string, :data => "my_value1" },
+ { :name => "input1_value2", :type => :string, :data => "my_value2" },
+ ]
+ end
+ let(:type_key_not_present_in_any_hash) do
+ [ { :name => "input2_value1", :data => "my_value1" },
+ { :name => "input2_value2", :data => "my_value2" },
+ ]
+ end
+ let(:type_key_not_present_in_some_hash) do
+ [ { :name => "input3_value1", :data => "my_value1" },
+ { :name => "input3_value2", :type => :string, :data => "my_value2" },
+ ]
+ end
+ let(:data_key_not_present_in_any_hash) do
+ [ { :name => "input4_value1", :type => :string },
+ { :name => "input4_value2", :type => :string },
+ ]
+ end
+ let(:data_key_not_present_in_some_hash) do
+ [ { :name => "input5_value1", :type => :string, :data => "my_value1" },
+ { :name => "input5_value2", :type => :string },
+ ]
+ end
+ let(:only_name_key_present_in_all_hash) do
+ [ { :name => "input6_value1" },
+ { :name => "input6_value2" },
+ ]
+ end
+
+ context "type key" do
+ context "when type key is present in all the values hash of registry_key resource" do
+ it "returns false" do
+ response = provider.key_missing?(all_keys_present_in_all_hash, :type)
+ expect(response).to be == false
+ end
+ end
+
+ context "when type key is not present in any of the values hash of registry_key resource" do
+ it "returns true" do
+ response = provider.key_missing?(type_key_not_present_in_any_hash, :type)
+ expect(response).to be == true
+ end
+ end
+
+ context "when type key is not present only in some of the values hash of registry_key resource" do
+ it "returns true" do
+ response = provider.key_missing?(type_key_not_present_in_some_hash, :type)
+ expect(response).to be == true
+ end
+ end
+
+ context "when only name key is present in all the values hash of registry_key resource" do
+ it "returns true" do
+ response = provider.key_missing?(only_name_key_present_in_all_hash, :type)
+ expect(response).to be == true
+ end
+ end
+ end
+
+ context "data key" do
+ context "when data key is present in all the values hash of registry_key resource" do
+ it "returns false" do
+ response = provider.key_missing?(all_keys_present_in_all_hash, :data)
+ expect(response).to be == false
+ end
+ end
+
+ context "when data key is not present in any of the values hash of registry_key resource" do
+ it "returns true" do
+ response = provider.key_missing?(data_key_not_present_in_any_hash, :data)
+ expect(response).to be == true
+ end
+ end
+
+ context "when data key is not present only in some of the values hash of registry_key resource" do
+ it "returns true" do
+ response = provider.key_missing?(data_key_not_present_in_some_hash, :data)
+ expect(response).to be == true
+ end
+ end
+
+ context "when only name key is present in all the values hash of registry_key resource" do
+ it "returns true" do
+ response = provider.key_missing?(only_name_key_present_in_all_hash, :data)
+ expect(response).to be == true
+ end
+ end
+ end
end
diff --git a/spec/unit/provider/remote_directory_spec.rb b/spec/unit/provider/remote_directory_spec.rb
index 6426dafd79..cb1b6e3cd8 100644
--- a/spec/unit/provider/remote_directory_spec.rb
+++ b/spec/unit/provider/remote_directory_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2010 Daniel DeLeo
+# Copyright:: Copyright 2010-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'digest/md5'
-require 'tmpdir'
-require 'chef/mixin/file_class'
+require "spec_helper"
+require "digest/md5"
+require "tmpdir"
+require "chef/mixin/file_class"
class Chef::CFCCheck
include Chef::Mixin::FileClass
@@ -32,7 +32,7 @@ describe Chef::Provider::RemoteDirectory do
@resource = Chef::Resource::RemoteDirectory.new(File.join(Dir.tmpdir, "tafty"))
# in CHEF_SPEC_DATA/cookbooks/openldap/files/default/remotedir
@resource.source "remotedir"
- @resource.cookbook('openldap')
+ @resource.cookbook("openldap")
@cookbook_repo = ::File.expand_path(::File.join(CHEF_SPEC_DATA, "cookbooks"))
Chef::Cookbook::FileVendor.fetch_from_disk(@cookbook_repo)
@@ -99,6 +99,21 @@ describe Chef::Provider::RemoteDirectory do
expect(cookbook_file.owner).to eq("toor")
expect(cookbook_file.backup).to eq(23)
end
+
+ it "respects sensitive flag" do
+ @resource.cookbook "gondola_rides"
+ @resource.sensitive true
+ cookbook_file = @provider.send(:cookbook_file_resource,
+ "/target/destination/path.txt",
+ "relative/source/path.txt")
+ expect(cookbook_file.sensitive).to eq(true)
+
+ @resource.sensitive false
+ cookbook_file = @provider.send(:cookbook_file_resource,
+ "/target/destination/path.txt",
+ "relative/source/path.txt")
+ expect(cookbook_file.sensitive).to eq(false)
+ end
end
describe "when creating the remote directory" do
@@ -106,11 +121,11 @@ describe Chef::Provider::RemoteDirectory do
@node.automatic_attrs[:platform] = :just_testing
@node.automatic_attrs[:platform_version] = :just_testing
- @destination_dir = Dir.mktmpdir << "/remote_directory_test"
+ @destination_dir = make_canonical_temp_directory << "/remote_directory_test"
@resource.path(@destination_dir)
end
- after {FileUtils.rm_rf(@destination_dir)}
+ after { FileUtils.rm_rf(@destination_dir) }
# CHEF-3552
it "creates the toplevel directory without error " do
@@ -121,12 +136,12 @@ describe Chef::Provider::RemoteDirectory do
it "transfers the directory with all contents" do
@provider.run_action(:create)
- expect(::File.exist?(@destination_dir + '/remote_dir_file1.txt')).to be_truthy
- expect(::File.exist?(@destination_dir + '/remote_dir_file2.txt')).to be_truthy
- expect(::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file1.txt')).to be_truthy
- expect(::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file2.txt')).to be_truthy
- expect(::File.exist?(@destination_dir + '/remotesubdir/.a_dotfile')).to be_truthy
- expect(::File.exist?(@destination_dir + '/.a_dotdir/.a_dotfile_in_a_dotdir')).to be_truthy
+ expect(::File.exist?(@destination_dir + "/remote_dir_file1.txt")).to be_truthy
+ expect(::File.exist?(@destination_dir + "/remote_dir_file2.txt")).to be_truthy
+ expect(::File.exist?(@destination_dir + "/remotesubdir/remote_subdir_file1.txt")).to be_truthy
+ expect(::File.exist?(@destination_dir + "/remotesubdir/remote_subdir_file2.txt")).to be_truthy
+ expect(::File.exist?(@destination_dir + "/remotesubdir/.a_dotfile")).to be_truthy
+ expect(::File.exist?(@destination_dir + "/.a_dotdir/.a_dotfile_in_a_dotdir")).to be_truthy
end
describe "only if it is missing" do
@@ -134,52 +149,52 @@ describe Chef::Provider::RemoteDirectory do
@resource.overwrite(true)
@provider.run_action(:create)
- File.open(@destination_dir + '/remote_dir_file1.txt', 'a') {|f| f.puts "blah blah blah" }
- File.open(@destination_dir + '/remotesubdir/remote_subdir_file1.txt', 'a') {|f| f.puts "blah blah blah" }
- file1md5 = Digest::MD5.hexdigest(File.read(@destination_dir + '/remote_dir_file1.txt'))
- subdirfile1md5 = Digest::MD5.hexdigest(File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt'))
+ File.open(@destination_dir + "/remote_dir_file1.txt", "a") { |f| f.puts "blah blah blah" }
+ File.open(@destination_dir + "/remotesubdir/remote_subdir_file1.txt", "a") { |f| f.puts "blah blah blah" }
+ file1md5 = Digest::MD5.hexdigest(File.read(@destination_dir + "/remote_dir_file1.txt"))
+ subdirfile1md5 = Digest::MD5.hexdigest(File.read(@destination_dir + "/remotesubdir/remote_subdir_file1.txt"))
@provider.run_action(:create_if_missing)
- expect(file1md5.eql?(Digest::MD5.hexdigest(File.read(@destination_dir + '/remote_dir_file1.txt')))).to be_truthy
- expect(subdirfile1md5.eql?(Digest::MD5.hexdigest(File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt')))).to be_truthy
+ expect(file1md5.eql?(Digest::MD5.hexdigest(File.read(@destination_dir + "/remote_dir_file1.txt")))).to be_truthy
+ expect(subdirfile1md5.eql?(Digest::MD5.hexdigest(File.read(@destination_dir + "/remotesubdir/remote_subdir_file1.txt")))).to be_truthy
end
end
describe "with purging enabled" do
- before {@resource.purge(true)}
+ before { @resource.purge(true) }
it "removes existing files if purge is true" do
@provider.run_action(:create)
- FileUtils.touch(@destination_dir + '/marked_for_death.txt')
- FileUtils.touch(@destination_dir + '/remotesubdir/marked_for_death_again.txt')
+ FileUtils.touch(@destination_dir + "/marked_for_death.txt")
+ FileUtils.touch(@destination_dir + "/remotesubdir/marked_for_death_again.txt")
@provider.run_action(:create)
- expect(::File.exist?(@destination_dir + '/remote_dir_file1.txt')).to be_truthy
- expect(::File.exist?(@destination_dir + '/remote_dir_file2.txt')).to be_truthy
- expect(::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file1.txt')).to be_truthy
- expect(::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file2.txt')).to be_truthy
+ expect(::File.exist?(@destination_dir + "/remote_dir_file1.txt")).to be_truthy
+ expect(::File.exist?(@destination_dir + "/remote_dir_file2.txt")).to be_truthy
+ expect(::File.exist?(@destination_dir + "/remotesubdir/remote_subdir_file1.txt")).to be_truthy
+ expect(::File.exist?(@destination_dir + "/remotesubdir/remote_subdir_file2.txt")).to be_truthy
- expect(::File.exist?(@destination_dir + '/marked_for_death.txt')).to be_falsey
- expect(::File.exist?(@destination_dir + '/remotesubdir/marked_for_death_again.txt')).to be_falsey
+ expect(::File.exist?(@destination_dir + "/marked_for_death.txt")).to be_falsey
+ expect(::File.exist?(@destination_dir + "/remotesubdir/marked_for_death_again.txt")).to be_falsey
end
it "removes files in subdirectories before files above" do
@provider.run_action(:create)
- FileUtils.mkdir_p(@destination_dir + '/a/multiply/nested/directory/')
- FileUtils.touch(@destination_dir + '/a/foo.txt')
- FileUtils.touch(@destination_dir + '/a/multiply/bar.txt')
- FileUtils.touch(@destination_dir + '/a/multiply/nested/baz.txt')
- FileUtils.touch(@destination_dir + '/a/multiply/nested/directory/qux.txt')
+ FileUtils.mkdir_p(@destination_dir + "/a/multiply/nested/directory/")
+ FileUtils.touch(@destination_dir + "/a/foo.txt")
+ FileUtils.touch(@destination_dir + "/a/multiply/bar.txt")
+ FileUtils.touch(@destination_dir + "/a/multiply/nested/baz.txt")
+ FileUtils.touch(@destination_dir + "/a/multiply/nested/directory/qux.txt")
@provider.run_action(:create)
- expect(::File.exist?(@destination_dir + '/a/foo.txt')).to be_falsey
- expect(::File.exist?(@destination_dir + '/a/multiply/bar.txt')).to be_falsey
- expect(::File.exist?(@destination_dir + '/a/multiply/nested/baz.txt')).to be_falsey
- expect(::File.exist?(@destination_dir + '/a/multiply/nested/directory/qux.txt')).to be_falsey
+ expect(::File.exist?(@destination_dir + "/a/foo.txt")).to be_falsey
+ expect(::File.exist?(@destination_dir + "/a/multiply/bar.txt")).to be_falsey
+ expect(::File.exist?(@destination_dir + "/a/multiply/nested/baz.txt")).to be_falsey
+ expect(::File.exist?(@destination_dir + "/a/multiply/nested/directory/qux.txt")).to be_falsey
end
it "removes directory symlinks properly", :not_supported_on_win2k3 do
- symlinked_dir_path = @destination_dir + '/symlinked_dir'
+ symlinked_dir_path = @destination_dir + "/symlinked_dir"
@provider.action = :create
@provider.run_action
@@ -202,18 +217,18 @@ describe Chef::Provider::RemoteDirectory do
end
describe "with overwrite disabled" do
- before {@resource.purge(false)}
- before {@resource.overwrite(false)}
+ before { @resource.purge(false) }
+ before { @resource.overwrite(false) }
it "leaves modifications alone" do
@provider.run_action(:create)
- ::File.open(@destination_dir + '/remote_dir_file1.txt', 'a') {|f| f.puts "blah blah blah" }
- ::File.open(@destination_dir + '/remotesubdir/remote_subdir_file1.txt', 'a') {|f| f.puts "blah blah blah" }
- file1md5 = Digest::MD5.hexdigest(::File.read(@destination_dir + '/remote_dir_file1.txt'))
- subdirfile1md5 = Digest::MD5.hexdigest(::File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt'))
+ ::File.open(@destination_dir + "/remote_dir_file1.txt", "a") { |f| f.puts "blah blah blah" }
+ ::File.open(@destination_dir + "/remotesubdir/remote_subdir_file1.txt", "a") { |f| f.puts "blah blah blah" }
+ file1md5 = Digest::MD5.hexdigest(::File.read(@destination_dir + "/remote_dir_file1.txt"))
+ subdirfile1md5 = Digest::MD5.hexdigest(::File.read(@destination_dir + "/remotesubdir/remote_subdir_file1.txt"))
@provider.run_action(:create)
- expect(file1md5.eql?(Digest::MD5.hexdigest(::File.read(@destination_dir + '/remote_dir_file1.txt')))).to be_truthy
- expect(subdirfile1md5.eql?(Digest::MD5.hexdigest(::File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt')))).to be_truthy
+ expect(file1md5.eql?(Digest::MD5.hexdigest(::File.read(@destination_dir + "/remote_dir_file1.txt")))).to be_truthy
+ expect(subdirfile1md5.eql?(Digest::MD5.hexdigest(::File.read(@destination_dir + "/remotesubdir/remote_subdir_file1.txt")))).to be_truthy
end
end
diff --git a/spec/unit/provider/remote_file/cache_control_data_spec.rb b/spec/unit/provider/remote_file/cache_control_data_spec.rb
index 11f2af3edc..a80aa38e77 100644
--- a/spec/unit/provider/remote_file/cache_control_data_spec.rb
+++ b/spec/unit/provider/remote_file/cache_control_data_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'uri'
+require "spec_helper"
+require "uri"
CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH = 64
-CACHE_FILE_MD5_HEX_LENGTH = 32
+CACHE_FILE_CHECKSUM_HEX_LENGTH = 32
CACHE_FILE_JSON_FILE_EXTENSION_LENGTH = 5
CACHE_FILE_PATH_LIMIT =
CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH +
1 +
- CACHE_FILE_MD5_HEX_LENGTH +
+ CACHE_FILE_CHECKSUM_HEX_LENGTH +
CACHE_FILE_JSON_FILE_EXTENSION_LENGTH # {friendly}-{md5hex}.json == 102
describe Chef::Provider::RemoteFile::CacheControlData do
@@ -36,7 +36,8 @@ describe Chef::Provider::RemoteFile::CacheControlData do
Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, current_file_checksum)
end
- let(:cache_path) { "remote_file/http___www_google_com_robots_txt-9839677abeeadf0691026e0cabca2339.json" }
+ let(:cache_path) { "remote_file/http___www_google_com_robots_txt-6dc1b24315d0cff764d30344199c6f7b.json" }
+ let(:old_cache_path) { "remote_file/http___www_google_com_robots_txt-9839677abeeadf0691026e0cabca2339.json" }
# the checksum of the file we have on disk already
let(:current_file_checksum) { "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }
@@ -44,7 +45,8 @@ describe Chef::Provider::RemoteFile::CacheControlData do
context "when loading data for an unknown URI" do
before do
- expect(Chef::FileCache).to receive(:load).with(cache_path).and_raise(Chef::Exceptions::FileNotFound, "nope")
+ expect(Chef::FileCache).to receive(:has_key?).with(cache_path).and_return(false)
+ expect(Chef::FileCache).to receive(:has_key?).with(old_cache_path).and_return(false)
end
context "and there is no current copy of the file" do
@@ -64,7 +66,8 @@ describe Chef::Provider::RemoteFile::CacheControlData do
context "and the URI contains a password" do
let(:uri) { URI.parse("http://bob:password@example.org/") }
- let(:cache_path) { "remote_file/http___bob_XXXX_example_org_-f121caacb74c05a35bcefdf578ed5fc9.json" }
+ let(:cache_path) { "remote_file/http___bob_XXXX_example_org_-44be109aa176a165ef599c12d97af792.json" }
+ let(:old_cache_path) { "remote_file/http___bob_XXXX_example_org_-f121caacb74c05a35bcefdf578ed5fc9.json" }
it "loads the cache data from a path based on a sanitized URI" do
Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, current_file_checksum)
@@ -88,51 +91,73 @@ describe Chef::Provider::RemoteFile::CacheControlData do
Chef::JSONCompat.to_json(cache)
end
- before do
- expect(Chef::FileCache).to receive(:load).with(cache_path).and_return(cache_json_data)
- end
-
- context "and there is no on-disk copy of the file" do
- let(:current_file_checksum) { nil }
-
- it "returns empty cache control data" do
- expect(cache_control_data.etag).to be_nil
- expect(cache_control_data.mtime).to be_nil
+ context "when the cache control data uses sha256 for its name" do
+ before do
+ expect(Chef::FileCache).to receive(:has_key?).with(cache_path).and_return(true)
+ expect(Chef::FileCache).to receive(:load).with(cache_path).and_return(cache_json_data)
end
- end
- context "and the cached checksum does not match the on-disk copy" do
- let(:current_file_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" }
+ context "and there is no on-disk copy of the file" do
+ let(:current_file_checksum) { nil }
- it "returns empty cache control data" do
- expect(cache_control_data.etag).to be_nil
- expect(cache_control_data.mtime).to be_nil
+ it "returns empty cache control data" do
+ expect(cache_control_data.etag).to be_nil
+ expect(cache_control_data.mtime).to be_nil
+ end
end
- end
- context "and the cached checksum matches the on-disk copy" do
+ context "and the cached checksum does not match the on-disk copy" do
+ let(:current_file_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" }
- it "populates the cache control data" do
- expect(cache_control_data.etag).to eq(etag)
- expect(cache_control_data.mtime).to eq(mtime)
+ it "returns empty cache control data" do
+ expect(cache_control_data.etag).to be_nil
+ expect(cache_control_data.mtime).to be_nil
+ end
end
- end
-
- context "and the cached checksum data is corrupted" do
- let(:cache_json_data) { '{"foo",,"bar" []}' }
- it "returns empty cache control data" do
- expect(cache_control_data.etag).to be_nil
- expect(cache_control_data.mtime).to be_nil
+ context "and the cached checksum matches the on-disk copy" do
+ context "when the filename uses sha256" do
+ before do
+ expect(Chef::FileCache).not_to receive(:has_key?).with(old_cache_path)
+ end
+ it "populates the cache control data" do
+ expect(cache_control_data.etag).to eq(etag)
+ expect(cache_control_data.mtime).to eq(mtime)
+ end
+ end
end
- context "and it still is valid JSON" do
- let(:cache_json_data) { '' }
+ context "and the cached checksum data is corrupted" do
+ let(:cache_json_data) { '{"foo",,"bar" []}' }
it "returns empty cache control data" do
expect(cache_control_data.etag).to be_nil
expect(cache_control_data.mtime).to be_nil
end
+
+ context "and it still is valid JSON" do
+ let(:cache_json_data) { "" }
+
+ it "returns empty cache control data" do
+ expect(cache_control_data.etag).to be_nil
+ expect(cache_control_data.mtime).to be_nil
+ end
+ end
+ end
+ end
+
+ context "when the filename uses md5" do
+ before do
+ expect(Chef::FileCache).to receive(:has_key?).with(cache_path).and_return(false)
+ expect(Chef::FileCache).to receive(:has_key?).with(old_cache_path).and_return(true)
+ expect(Chef::FileCache).to receive(:load).with(old_cache_path).and_return(cache_json_data)
+ end
+
+ it "populates the cache control data and creates the cache control data file with the correct path" do
+ expect(Chef::FileCache).to receive(:store).with(cache_path, cache_json_data)
+ expect(Chef::FileCache).to receive(:delete).with(old_cache_path)
+ expect(cache_control_data.etag).to eq(etag)
+ expect(cache_control_data.mtime).to eq(mtime)
end
end
end
@@ -174,7 +199,8 @@ describe Chef::Provider::RemoteFile::CacheControlData do
context "and the URI contains a password" do
let(:uri) { URI.parse("http://bob:password@example.org/") }
- let(:cache_path) { "remote_file/http___bob_XXXX_example_org_-f121caacb74c05a35bcefdf578ed5fc9.json" }
+ let(:cache_path) { "remote_file/http___bob_XXXX_example_org_-44be109aa176a165ef599c12d97af792.json" }
+ let(:old_cache_path) { "remote_file/http___bob_XXXX_example_org_-f121caacb74c05a35bcefdf578ed5fc9.json" }
it "writes the data to the cache with a sanitized path name" do
json_data = cache_control_data.json_data
@@ -188,16 +214,16 @@ describe Chef::Provider::RemoteFile::CacheControlData do
# local file system path limits resulting in exceptions from
# file system API's on both Windows and Unix systems.
context "and the URI results in a file cache path that exceeds #{CACHE_FILE_PATH_LIMIT} characters in length" do
- let(:long_remote_path) { "http://www.bing.com/" + ('0' * (CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH * 2 )) }
+ let(:long_remote_path) { "http://www.bing.com/" + ("0" * (CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH * 2 )) }
let(:uri) { URI.parse(long_remote_path) }
let(:truncated_remote_uri) { URI.parse(long_remote_path[0...CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH]) }
let(:truncated_file_cache_path) do
cache_control_data_truncated = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(truncated_remote_uri, current_file_checksum)
- cache_control_data_truncated.send('sanitized_cache_file_basename')[0...CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH]
+ cache_control_data_truncated.send("sanitized_cache_file_basename")[0...CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH]
end
it "truncates the file cache path to 102 characters" do
- normalized_cache_path = cache_control_data.send('sanitized_cache_file_basename')
+ normalized_cache_path = cache_control_data.send("sanitized_cache_file_basename")
expect(Chef::FileCache).to receive(:store).with("remote_file/" + normalized_cache_path, cache_control_data.json_data)
@@ -207,7 +233,7 @@ describe Chef::Provider::RemoteFile::CacheControlData do
end
it "uses a file cache path that starts with the first #{CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH} characters of the URI" do
- normalized_cache_path = cache_control_data.send('sanitized_cache_file_basename')
+ normalized_cache_path = cache_control_data.send("sanitized_cache_file_basename")
expect(truncated_file_cache_path.length).to eq(CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH)
expect(normalized_cache_path.start_with?(truncated_file_cache_path)).to eq(true)
@@ -217,4 +243,3 @@ describe Chef::Provider::RemoteFile::CacheControlData do
end
end
-
diff --git a/spec/unit/provider/remote_file/content_spec.rb b/spec/unit/provider/remote_file/content_spec.rb
index ce18d23a09..307eb98187 100644
--- a/spec/unit/provider/remote_file/content_spec.rb
+++ b/spec/unit/provider/remote_file/content_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::RemoteFile::Content do
@@ -141,7 +141,6 @@ describe Chef::Provider::RemoteFile::Content do
it_behaves_like "the resource needs fetching"
end
-
describe "when the fetcher throws an exception" do
before do
allow(new_resource).to receive(:checksum).and_return(nil)
@@ -160,10 +159,10 @@ describe Chef::Provider::RemoteFile::Content do
describe "when there is an array of sources and the first fails" do
- # https://github.com/opscode/chef/pull/1358#issuecomment-40853299
+ # https://github.com/chef/chef/pull/1358#issuecomment-40853299
def create_exception(exception_class)
if [ Net::HTTPServerException, Net::HTTPFatalError ].include? exception_class
- exception_class.new("message", {"something" => 1})
+ exception_class.new("message", { "something" => 1 })
else
exception_class.new
end
@@ -180,7 +179,8 @@ describe Chef::Provider::RemoteFile::Content do
Timeout::Error,
Net::HTTPServerException,
Net::HTTPFatalError,
- Net::FTPError
+ Net::FTPError,
+ Errno::ETIMEDOUT,
].each do |exception|
describe "with an exception of #{exception}" do
before do
diff --git a/spec/unit/provider/remote_file/fetcher_spec.rb b/spec/unit/provider/remote_file/fetcher_spec.rb
index 8bd3b7c625..0fa213cdb2 100644
--- a/spec/unit/provider/remote_file/fetcher_spec.rb
+++ b/spec/unit/provider/remote_file/fetcher_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::RemoteFile::Fetcher do
diff --git a/spec/unit/provider/remote_file/ftp_spec.rb b/spec/unit/provider/remote_file/ftp_spec.rb
index dbbddd8e84..b2fbb7300c 100644
--- a/spec/unit/provider/remote_file/ftp_spec.rb
+++ b/spec/unit/provider/remote_file/ftp_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Jesse Campbell (<hikeit@gmail.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
+# Copyright:: Copyright 2013-2016, Jesse Campbell
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::RemoteFile::FTP do
- let(:enclosing_directory) {
+ let(:enclosing_directory) do
canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
- }
- let(:resource_path) {
+ end
+ let(:resource_path) do
canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt")))
- }
+ end
let(:new_resource) do
r = Chef::Resource::RemoteFile.new("remote file ftp backend test (new resource)")
@@ -38,7 +38,7 @@ describe Chef::Provider::RemoteFile::FTP do
end
let(:ftp) do
- ftp = double(Net::FTP, { })
+ ftp = double(Net::FTP, {})
allow(ftp).to receive(:connect)
allow(ftp).to receive(:login)
allow(ftp).to receive(:voidcmd)
@@ -200,9 +200,7 @@ describe Chef::Provider::RemoteFile::FTP do
context "and proxying is enabled" do
before do
- Chef::Config[:ftp_proxy] = "socks5://socks.example.com:5000"
- Chef::Config[:ftp_proxy_user] = "bill"
- Chef::Config[:ftp_proxy_pass] = "ted"
+ stub_const("ENV", "ftp_proxy" => "socks5://bill:ted@socks.example.com:5000")
end
it "fetches the file via the proxy" do
diff --git a/spec/unit/provider/remote_file/http_spec.rb b/spec/unit/provider/remote_file/http_spec.rb
index d9cfaa15eb..f58a3d3c14 100644
--- a/spec/unit/provider/remote_file/http_spec.rb
+++ b/spec/unit/provider/remote_file/http_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Lamont Granquist
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Lamont Granquist
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::RemoteFile::HTTP do
@@ -61,7 +61,7 @@ describe Chef::Provider::RemoteFile::HTTP do
end
it "has the user-specified custom headers" do
- expect(fetcher.headers).to eq({"x-myapp-header" => "custom-header-value"})
+ expect(fetcher.headers).to eq({ "x-myapp-header" => "custom-header-value" })
end
end
@@ -163,6 +163,12 @@ describe Chef::Provider::RemoteFile::HTTP do
let(:last_response) { {} }
+ let(:event_dispatcher) do
+ event_dispatcher = double(Chef::EventDispatch::Dispatcher)
+ allow(event_dispatcher).to receive(:formatter?).and_return(false)
+ event_dispatcher
+ end
+
let(:rest) do
rest = double(Chef::HTTP::Simple)
allow(rest).to receive(:streaming_request).and_return(tempfile)
@@ -173,12 +179,12 @@ describe Chef::Provider::RemoteFile::HTTP do
before do
new_resource.headers({})
new_resource.use_last_modified(false)
+ allow(new_resource).to receive(:events).and_return(event_dispatcher)
expect(Chef::Provider::RemoteFile::CacheControlData).to receive(:load_and_validate).with(uri, current_resource_checksum).and_return(cache_control_data)
expect(Chef::HTTP::Simple).to receive(:new).with(*expected_http_args).and_return(rest)
end
-
describe "and the request does not return new content" do
it "should return a nil tempfile for a 304 HTTPNotModifed" do
@@ -206,8 +212,22 @@ describe Chef::Provider::RemoteFile::HTTP do
expect(cache_control_data.checksum).to eq(fetched_content_checksum)
end
+ context "with progress reports" do
+ before do
+ Chef::Config[:show_download_progress] = true
+ end
+
+ it "should yield its progress" do
+ allow(rest).to receive(:streaming_request_with_progress).and_yield(50, 100).and_yield(70, 100).and_return(tempfile)
+ expect(event_dispatcher).to receive(:formatter?).and_return(true)
+ expect(event_dispatcher).to receive(:resource_update_progress).with(new_resource, 50, 100, 10).ordered
+ expect(event_dispatcher).to receive(:resource_update_progress).with(new_resource, 70, 100, 10).ordered
+ fetcher.fetch
+ end
+ end
+
context "and the response does not contain an etag" do
- let(:last_response) { {"etag" => nil} }
+ let(:last_response) { { "etag" => nil } }
it "does not include an etag in the result" do
fetcher.fetch
expect(cache_control_data.etag).to be_nil
@@ -217,7 +237,7 @@ describe Chef::Provider::RemoteFile::HTTP do
end
context "and the response has an etag header" do
- let(:last_response) { {"etag" => "abc123"} }
+ let(:last_response) { { "etag" => "abc123" } }
it "includes the etag value in the response" do
fetcher.fetch
@@ -229,7 +249,7 @@ describe Chef::Provider::RemoteFile::HTTP do
end
context "and the response has no Date or Last-Modified header" do
- let(:last_response) { {"date" => nil, "last_modified" => nil} }
+ let(:last_response) { { "date" => nil, "last_modified" => nil } }
it "does not set an mtime in the result" do
# RFC 2616 suggests that servers that do not set a Date header do not
# have a reliable clock, so no use in making them deal with dates.
@@ -243,7 +263,7 @@ describe Chef::Provider::RemoteFile::HTTP do
context "and the response has a Last-Modified header" do
let(:last_response) do
# Last-Modified should be preferred to Date if both are set
- {"date" => "Fri, 17 May 2013 23:23:23 GMT", "last_modified" => "Fri, 17 May 2013 11:11:11 GMT"}
+ { "date" => "Fri, 17 May 2013 23:23:23 GMT", "last_modified" => "Fri, 17 May 2013 11:11:11 GMT" }
end
it "sets the mtime to the Last-Modified time in the response" do
@@ -255,7 +275,7 @@ describe Chef::Provider::RemoteFile::HTTP do
context "and the response has a Date header but no Last-Modified header" do
let(:last_response) do
- {"date" => "Fri, 17 May 2013 23:23:23 GMT", "last_modified" => nil}
+ { "date" => "Fri, 17 May 2013 23:23:23 GMT", "last_modified" => nil }
end
it "sets the mtime to the Date in the response" do
@@ -270,7 +290,7 @@ describe Chef::Provider::RemoteFile::HTTP do
context "and the target file is a tarball [CHEF-3140]" do
let(:uri) { URI.parse("http://opscode.com/tarball.tgz") }
- let(:expected_http_opts) { {:disable_gzip => true} }
+ let(:expected_http_opts) { { :disable_gzip => true } }
# CHEF-3140
# Some servers return tarballs as content type tar and encoding gzip, which
@@ -300,4 +320,3 @@ describe Chef::Provider::RemoteFile::HTTP do
end
end
-
diff --git a/spec/unit/provider/remote_file/local_file_spec.rb b/spec/unit/provider/remote_file/local_file_spec.rb
index 575996a540..6f345cadd1 100644
--- a/spec/unit/provider/remote_file/local_file_spec.rb
+++ b/spec/unit/provider/remote_file/local_file_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Jesse Campbell (<hikeit@gmail.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
+# Copyright:: Copyright 2013-2016, Jesse Campbell
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,9 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
+require "uri"
+require "addressable/uri"
describe Chef::Provider::RemoteFile::LocalFile do
@@ -47,7 +49,7 @@ describe Chef::Provider::RemoteFile::LocalFile do
end
describe "when given local windows path with spaces" do
- let(:uri) { URI.parse(URI.escape("file:///z:/windows/path/foo & bar.txt")) }
+ let(:uri) { URI.parse(Addressable::URI.encode("file:///z:/windows/path/foo & bar.txt")) }
it "returns a valid windows local path" do
expect(fetcher.source_path).to eq("z:/windows/path/foo & bar.txt")
end
@@ -61,7 +63,7 @@ describe Chef::Provider::RemoteFile::LocalFile do
end
describe "when given unc windows path with spaces" do
- let(:uri) { URI.parse(URI.escape("file:////server/share/windows/path/foo & bar.txt")) }
+ let(:uri) { URI.parse(Addressable::URI.encode("file:////server/share/windows/path/foo & bar.txt")) }
it "returns a valid windows unc path" do
expect(fetcher.source_path).to eq("//server/share/windows/path/foo & bar.txt")
end
diff --git a/spec/unit/provider/remote_file/network_file_spec.rb b/spec/unit/provider/remote_file/network_file_spec.rb
index 3666a47468..de065c83e2 100644
--- a/spec/unit/provider/remote_file/network_file_spec.rb
+++ b/spec/unit/provider/remote_file/network_file_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala (<jdm@chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software
+# Copyright:: Copyright 2015-2016, Chef Software
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::RemoteFile::NetworkFile do
diff --git a/spec/unit/provider/remote_file/sftp_spec.rb b/spec/unit/provider/remote_file/sftp_spec.rb
new file mode 100644
index 0000000000..ddab1605f0
--- /dev/null
+++ b/spec/unit/provider/remote_file/sftp_spec.rb
@@ -0,0 +1,150 @@
+#
+# Author:: John Kerry (<john@kerryhouse.net>)
+# Copyright:: Copyright 2013-2016, John Kerry
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::RemoteFile::SFTP do
+ #built out dependencies
+ let(:enclosing_directory) do
+ canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
+ end
+ let(:resource_path) do
+ canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt")))
+ end
+
+ let(:new_resource) do
+ r = Chef::Resource::RemoteFile.new("remote file sftp backend test (new resource)")
+ r.path(resource_path)
+ r
+ end
+
+ let(:current_resource) do
+ Chef::Resource::RemoteFile.new("remote file sftp backend test (current resource)'")
+ end
+
+ let(:uri) { URI.parse("sftp://conan:cthu1hu@opscode.com/seattle.txt") }
+
+ let(:sftp) do
+ sftp = double(Net::SFTP, {})
+ allow(sftp).to receive(:download!)
+ sftp
+ end
+
+ let(:tempfile_path) { "/tmp/somedir/remote-file-sftp-backend-spec-test" }
+
+ let(:tempfile) do
+ t = StringIO.new
+ allow(t).to receive(:path).and_return(tempfile_path)
+ t
+ end
+
+ before(:each) do
+ allow(Net::SFTP).to receive(:start).with(any_args).and_return(sftp)
+ allow(Tempfile).to receive(:new).and_return(tempfile)
+ end
+ describe "on initialization without user and password provided in the URI" do
+ it "throws an argument exception with no userinfo is given" do
+ uri.userinfo = nil
+ uri.password = nil
+ uri.user = nil
+ expect { Chef::Provider::RemoteFile::SFTP.new(uri, new_resource, current_resource) }.to raise_error(ArgumentError)
+ end
+
+ it "throws an argument exception with no user name is given" do
+ uri.userinfo = ":cthu1hu"
+ uri.password = "cthu1hu"
+ uri.user = nil
+ expect { Chef::Provider::RemoteFile::SFTP.new(uri, new_resource, current_resource) }.to raise_error(ArgumentError)
+ end
+
+ it "throws an argument exception with no password is given" do
+ uri.userinfo = "conan:"
+ uri.password = nil
+ uri.user = "conan"
+ expect { Chef::Provider::RemoteFile::SFTP.new(uri, new_resource, current_resource) }.to raise_error(ArgumentError)
+ end
+
+ end
+
+ describe "on initialization with user and password provided in the URI" do
+
+ it "throws an argument exception when no path is given" do
+ uri.path = ""
+ expect { Chef::Provider::RemoteFile::SFTP.new(uri, new_resource, current_resource) }.to raise_error(ArgumentError)
+ end
+
+ it "throws an argument exception when only a / is given" do
+ uri.path = "/"
+ expect { Chef::Provider::RemoteFile::SFTP.new(uri, new_resource, current_resource) }.to raise_error(ArgumentError)
+ end
+
+ it "throws an argument exception when no filename is given" do
+ uri.path = "/the/whole/path/"
+ expect { Chef::Provider::RemoteFile::SFTP.new(uri, new_resource, current_resource) }.to raise_error(ArgumentError)
+ end
+
+ end
+
+ describe "when fetching the object" do
+
+ let(:cache_control_data) { Chef::Provider::RemoteFile::CacheControlData.new(uri) }
+ let(:current_resource_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" }
+
+ subject(:fetcher) { Chef::Provider::RemoteFile::SFTP.new(uri, new_resource, current_resource) }
+
+ before do
+ current_resource.checksum(current_resource_checksum)
+ end
+
+ it "should attempt to download a file from the provided url and path" do
+ expect(sftp).to receive(:download!).with("/seattle.txt", "/tmp/somedir/remote-file-sftp-backend-spec-test")
+ fetcher.fetch
+ end
+
+ context "and the URI specifies an alternate port" do
+ let(:uri) { URI.parse("sftp://conan:cthu1hu@opscode.com:8021/seattle.txt") }
+
+ it "should connect on an alternate port when one is provided" do
+ expect(Net::SFTP).to receive(:start).with("opscode.com:8021", "conan", :password => "cthu1hu")
+ fetcher.fetch
+ end
+
+ end
+
+ context "and the uri specifies a nested path" do
+ let(:uri) { URI.parse("sftp://conan:cthu1hu@opscode.com/the/whole/path/seattle.txt") }
+
+ it "should fetch the file from the correct path" do
+ expect(sftp).to receive(:download!).with("/the/whole/path/seattle.txt", "/tmp/somedir/remote-file-sftp-backend-spec-test")
+ fetcher.fetch
+ end
+ end
+
+ context "when not using last modified based conditional fetching" do
+ before do
+ new_resource.use_last_modified(false)
+ end
+
+ it "should return a tempfile in the result" do
+ result = fetcher.fetch
+ expect(result).to equal(tempfile)
+ end
+
+ end
+ end
+end
diff --git a/spec/unit/provider/remote_file_spec.rb b/spec/unit/provider/remote_file_spec.rb
index de4a897847..6ceb1d450d 100644
--- a/spec/unit/provider/remote_file_spec.rb
+++ b/spec/unit/provider/remote_file_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2008-2013 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,9 @@
# limitations under the License.
#
-require 'spec_helper'
-
-require 'support/shared/unit/provider/file'
+require "spec_helper"
+require "support/shared/unit/provider/file"
describe Chef::Provider::RemoteFile do
let(:resource) do
@@ -32,18 +31,18 @@ describe Chef::Provider::RemoteFile do
end
let(:content) do
- content = double('Chef::Provider::File::Content::RemoteFile')
+ content = double("Chef::Provider::File::Content::RemoteFile")
end
- let(:node) { double('Chef::Node') }
- let(:events) { double('Chef::Events').as_null_object } # mock all the methods
- let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
- let(:enclosing_directory) {
+ let(:node) { double("Chef::Node") }
+ let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+ let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
+ let(:enclosing_directory) do
canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
- }
- let(:resource_path) {
+ end
+ let(:resource_path) do
canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt")))
- }
+ end
subject(:provider) do
provider = described_class.new(resource, run_context)
@@ -60,4 +59,3 @@ describe Chef::Provider::RemoteFile do
it_behaves_like "a file provider with source field"
end
-
diff --git a/spec/unit/provider/route_spec.rb b/spec/unit/provider/route_spec.rb
index ff68eea895..03d1ad2477 100644
--- a/spec/unit/provider/route_spec.rb
+++ b/spec/unit/provider/route_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Route do
before do
@@ -25,9 +25,9 @@ describe Chef::Provider::Route do
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
- @new_resource = Chef::Resource::Route.new('10.0.0.10')
+ @new_resource = Chef::Resource::Route.new("10.0.0.10")
@new_resource.gateway "10.0.0.9"
- @current_resource = Chef::Resource::Route.new('10.0.0.10')
+ @current_resource = Chef::Resource::Route.new("10.0.0.10")
@current_resource.gateway "10.0.0.9"
@provider = Chef::Provider::Route.new(@new_resource, @run_context)
@@ -36,30 +36,29 @@ describe Chef::Provider::Route do
describe Chef::Provider::Route, "hex2ip" do
it "should return nil if ip address is invalid" do
- expect(@provider.hex2ip('foo')).to be_nil # does not even look like an ip
- expect(@provider.hex2ip('ABCDEFGH')).to be_nil # 8 chars, but invalid
+ expect(@provider.hex2ip("foo")).to be_nil # does not even look like an ip
+ expect(@provider.hex2ip("ABCDEFGH")).to be_nil # 8 chars, but invalid
end
it "should return quad-dotted notation for a valid IP" do
- expect(@provider.hex2ip('01234567')).to eq('103.69.35.1')
- expect(@provider.hex2ip('0064a8c0')).to eq('192.168.100.0')
- expect(@provider.hex2ip('00FFFFFF')).to eq('255.255.255.0')
+ expect(@provider.hex2ip("01234567")).to eq("103.69.35.1")
+ expect(@provider.hex2ip("0064a8c0")).to eq("192.168.100.0")
+ expect(@provider.hex2ip("00FFFFFF")).to eq("255.255.255.0")
end
end
-
describe Chef::Provider::Route, "load_current_resource" do
context "on linux" do
before do
- @node.automatic_attrs[:os] = 'linux'
- routing_table = "Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT\n" +
- "eth0 0064A8C0 0984A8C0 0003 0 0 0 00FFFFFF 0 0 0\n"
+ @node.automatic_attrs[:os] = "linux"
+ routing_table = "Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT\n" \
+ "eth0 0064A8C0 0984A8C0 0003 0 0 0 00FFFFFF 0 0 0\n"
route_file = StringIO.new(routing_table)
allow(File).to receive(:open).with("/proc/net/route", "r").and_return(route_file)
end
it "should set is_running to false when a route is not detected" do
- resource = Chef::Resource::Route.new('10.10.10.0/24')
+ resource = Chef::Resource::Route.new("10.10.10.0/24")
allow(resource).to receive(:gateway).and_return("10.0.0.1")
allow(resource).to receive(:device).and_return("eth0")
provider = Chef::Provider::Route.new(resource, @run_context)
@@ -69,7 +68,7 @@ describe Chef::Provider::Route do
end
it "should detect existing routes and set is_running attribute correctly" do
- resource = Chef::Resource::Route.new('192.168.100.0/24')
+ resource = Chef::Resource::Route.new("192.168.100.0/24")
allow(resource).to receive(:gateway).and_return("192.168.132.9")
allow(resource).to receive(:device).and_return("eth0")
provider = Chef::Provider::Route.new(resource, @run_context)
@@ -79,7 +78,7 @@ describe Chef::Provider::Route do
end
it "should use gateway value when matching routes" do
- resource = Chef::Resource::Route.new('192.168.100.0/24')
+ resource = Chef::Resource::Route.new("192.168.100.0/24")
allow(resource).to receive(:gateway).and_return("10.10.10.10")
allow(resource).to receive(:device).and_return("eth0")
provider = Chef::Provider::Route.new(resource, @run_context)
@@ -92,16 +91,16 @@ describe Chef::Provider::Route do
describe Chef::Provider::Route, "action_add" do
it "should add the route if it does not exist" do
- allow(@provider).to receive(:run_command).and_return(true)
+ allow(@provider).to receive(:shell_out!)
allow(@current_resource).to receive(:gateway).and_return(nil)
- expect(@provider).to receive(:generate_command).once.with(:add)
+ expect(@provider).to receive(:generate_command).with(:add).and_return(["command"])
expect(@provider).to receive(:generate_config)
@provider.run_action(:add)
expect(@new_resource).to be_updated
end
it "should not add the route if it exists" do
- allow(@provider).to receive(:run_command).and_return(true)
+ allow(@provider).to receive(:shell_out!)
allow(@provider).to receive(:is_running).and_return(true)
expect(@provider).not_to receive(:generate_command).with(:add)
expect(@provider).to receive(:generate_config)
@@ -110,13 +109,13 @@ describe Chef::Provider::Route do
end
it "should not delete config file for :add action (CHEF-3332)" do
- @node.automatic_attrs[:platform] = 'centos'
+ @node.automatic_attrs[:platform] = "centos"
route_file = StringIO.new
expect(File).to receive(:new).and_return(route_file)
- @resource_add = Chef::Resource::Route.new('192.168.1.0/24 via 192.168.0.1')
+ @resource_add = Chef::Resource::Route.new("192.168.1.0/24 via 192.168.0.1")
@run_context.resource_collection << @resource_add
- allow(@provider).to receive(:run_command).and_return(true)
+ allow(@provider).to receive(:shell_out!).and_return(true)
@resource_add.action(:add)
@provider.run_action(:add)
@@ -127,8 +126,8 @@ describe Chef::Provider::Route do
describe Chef::Provider::Route, "action_delete" do
it "should delete the route if it exists" do
- allow(@provider).to receive(:run_command).and_return(true)
- expect(@provider).to receive(:generate_command).once.with(:delete)
+ allow(@provider).to receive(:shell_out!).and_return(true)
+ expect(@provider).to receive(:generate_command).with(:delete).and_return(["command"])
allow(@provider).to receive(:is_running).and_return(true)
@provider.run_action(:delete)
expect(@new_resource).to be_updated
@@ -136,7 +135,7 @@ describe Chef::Provider::Route do
it "should not delete the route if it does not exist" do
allow(@current_resource).to receive(:gateway).and_return(nil)
- allow(@provider).to receive(:run_command).and_return(true)
+ allow(@provider).to receive(:shell_out!).and_return(true)
expect(@provider).not_to receive(:generate_command).with(:add)
@provider.run_action(:delete)
expect(@new_resource).not_to be_updated
@@ -145,62 +144,62 @@ describe Chef::Provider::Route do
describe Chef::Provider::Route, "generate_command for action_add" do
it "should include a netmask when a one is specified" do
- allow(@new_resource).to receive(:netmask).and_return('255.255.0.0')
- expect(@provider.generate_command(:add)).to match(/\/\d{1,2}\s/)
+ allow(@new_resource).to receive(:netmask).and_return("255.255.0.0")
+ expect(@provider.generate_command(:add).join(" ")).to match(/\/\d{1,2}/)
end
it "should not include a netmask when a one is specified" do
allow(@new_resource).to receive(:netmask).and_return(nil)
- expect(@provider.generate_command(:add)).not_to match(/\/\d{1,2}\s/)
+ expect(@provider.generate_command(:add).join(" ")).not_to match(/\/\d{1,2}/)
end
it "should include ' via $gateway ' when a gateway is specified" do
- expect(@provider.generate_command(:add)).to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\s/)
+ expect(@provider.generate_command(:add).join(" ")).to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}/)
end
it "should not include ' via $gateway ' when a gateway is not specified" do
allow(@new_resource).to receive(:gateway).and_return(nil)
- expect(@provider.generate_command(:add)).not_to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\s/)
+ expect(@provider.generate_command(:add).join(" ")).not_to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}/)
end
end
describe Chef::Provider::Route, "generate_command for action_delete" do
it "should include a netmask when a one is specified" do
- allow(@new_resource).to receive(:netmask).and_return('255.255.0.0')
- expect(@provider.generate_command(:delete)).to match(/\/\d{1,2}\s/)
+ allow(@new_resource).to receive(:netmask).and_return("255.255.0.0")
+ expect(@provider.generate_command(:delete).join(" ")).to match(/\/\d{1,2}/)
end
it "should not include a netmask when a one is specified" do
allow(@new_resource).to receive(:netmask).and_return(nil)
- expect(@provider.generate_command(:delete)).not_to match(/\/\d{1,2}\s/)
+ expect(@provider.generate_command(:delete).join(" ")).not_to match(/\/\d{1,2}/)
end
it "should include ' via $gateway ' when a gateway is specified" do
- expect(@provider.generate_command(:delete)).to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\s/)
+ expect(@provider.generate_command(:delete).join(" ")).to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}/)
end
it "should not include ' via $gateway ' when a gateway is not specified" do
allow(@new_resource).to receive(:gateway).and_return(nil)
- expect(@provider.generate_command(:delete)).not_to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\s/)
+ expect(@provider.generate_command(:delete).join(" ")).not_to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}/)
end
end
describe Chef::Provider::Route, "config_file_contents for action_add" do
it "should include a netmask when a one is specified" do
- allow(@new_resource).to receive(:netmask).and_return('255.255.0.0')
- expect(@provider.config_file_contents(:add, { :target => @new_resource.target, :netmask => @new_resource.netmask})).to match(/\/\d{1,2}.*\n$/)
+ allow(@new_resource).to receive(:netmask).and_return("255.255.0.0")
+ expect(@provider.config_file_contents(:add, target: @new_resource.target, netmask: @new_resource.netmask)).to match(/\/\d{1,2}.*\n$/)
end
it "should not include a netmask when a one is specified" do
- expect(@provider.config_file_contents(:add, { :target => @new_resource.target})).not_to match(/\/\d{1,2}.*\n$/)
+ expect(@provider.config_file_contents(:add, target: @new_resource.target)).not_to match(/\/\d{1,2}.*\n$/)
end
it "should include ' via $gateway ' when a gateway is specified" do
- expect(@provider.config_file_contents(:add, { :target => @new_resource.target, :gateway => @new_resource.gateway})).to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\n/)
+ expect(@provider.config_file_contents(:add, target: @new_resource.target, gateway: @new_resource.gateway)).to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\n/)
end
it "should not include ' via $gateway ' when a gateway is not specified" do
- expect(@provider.generate_command(:add)).not_to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\n/)
+ expect(@provider.generate_command(:add).join(" ")).not_to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\n/)
end
end
@@ -211,33 +210,39 @@ describe Chef::Provider::Route do
end
describe Chef::Provider::Route, "generate_config method" do
- %w[ centos redhat fedora ].each do |platform|
+ %w{ centos redhat fedora }.each do |platform|
it "should write a route file on #{platform} platform" do
@node.automatic_attrs[:platform] = platform
route_file = StringIO.new
expect(File).to receive(:new).with("/etc/sysconfig/network-scripts/route-eth0", "w").and_return(route_file)
- #Chef::Log.should_receive(:debug).with("route[10.0.0.10] writing route.eth0\n10.0.0.10 via 10.0.0.9\n")
+ # Chef::Log.should_receive(:debug).with("route[10.0.0.10] writing route.eth0\n10.0.0.10 via 10.0.0.9\n")
@run_context.resource_collection << @new_resource
@provider.generate_config
end
end
it "should put all routes for a device in a route config file" do
- @node.automatic_attrs[:platform] = 'centos'
+ @node.automatic_attrs[:platform] = "centos"
route_file = StringIO.new
expect(File).to receive(:new).and_return(route_file)
- @run_context.resource_collection << Chef::Resource::Route.new('192.168.1.0/24 via 192.168.0.1')
- @run_context.resource_collection << Chef::Resource::Route.new('192.168.2.0/24 via 192.168.0.1')
- @run_context.resource_collection << Chef::Resource::Route.new('192.168.3.0/24 via 192.168.0.1')
+ @run_context.resource_collection << Chef::Resource::Route.new("192.168.1.0/24 via 192.168.0.1")
+ @run_context.resource_collection << Chef::Resource::Route.new("192.168.2.0/24 via 192.168.0.1")
+ @run_context.resource_collection << Chef::Resource::Route.new("192.168.3.0/24 via 192.168.0.1")
+ @run_context.resource_collection << Chef::Resource::Route.new("Complex Route").tap do |r|
+ r.target "192.168.4.0"
+ r.gateway "192.168.0.1"
+ r.netmask "255.255.255.0"
+ end
@provider.action = :add
@provider.generate_config
- expect(route_file.string.split("\n").size).to eq(3)
+ expect(route_file.string.split("\n").size).to eq(4)
expect(route_file.string).to match(/^192\.168\.1\.0\/24 via 192\.168\.0\.1$/)
expect(route_file.string).to match(/^192\.168\.2\.0\/24 via 192\.168\.0\.1$/)
expect(route_file.string).to match(/^192\.168\.3\.0\/24 via 192\.168\.0\.1$/)
+ expect(route_file.string).to match(/^192\.168\.4\.0\/24 via 192\.168\.0\.1$/)
end
end
end
diff --git a/spec/unit/provider/ruby_block_spec.rb b/spec/unit/provider/ruby_block_spec.rb
index 266c943367..b49aef9243 100644
--- a/spec/unit/provider/ruby_block_spec.rb
+++ b/spec/unit/provider/ruby_block_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2009-2016, Opscode
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::RubyBlock, "initialize" do
before(:each) do
@@ -25,7 +25,7 @@ describe Chef::Provider::RubyBlock, "initialize" do
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@new_resource = Chef::Resource::RubyBlock.new("bloc party")
- @new_resource.block { $evil_global_evil_laugh = :mwahahaha}
+ @new_resource.block { $evil_global_evil_laugh = :mwahahaha }
@provider = Chef::Provider::RubyBlock.new(@new_resource, @run_context)
end
@@ -43,4 +43,3 @@ describe Chef::Provider::RubyBlock, "initialize" do
expect(@new_resource).to be_updated
end
end
-
diff --git a/spec/unit/provider/script_spec.rb b/spec/unit/provider/script_spec.rb
index d1759981aa..2f024c4c29 100644
--- a/spec/unit/provider/script_spec.rb
+++ b/spec/unit/provider/script_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (adam@opscode.com)
-# Copyright:: Copyright (c) 2009 Opscode
+# Author:: Adam Jacob (adam@chef.io)
+# Copyright:: Copyright 2009-2016, Opscode
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Script, "action_run" do
let(:node) { Chef::Node.new }
@@ -25,12 +25,12 @@ describe Chef::Provider::Script, "action_run" do
let(:run_context) { Chef::RunContext.new(node, {}, events) }
- let(:new_resource) {
- new_resource = Chef::Resource::Script.new('run some perl code')
+ let(:new_resource) do
+ new_resource = Chef::Resource::Script.new("run some perl code")
new_resource.code "$| = 1; print 'i like beans'"
- new_resource.interpreter 'perl'
+ new_resource.interpreter "perl"
new_resource
- }
+ end
let(:provider) { Chef::Provider::Script.new(new_resource, run_context) }
@@ -56,12 +56,55 @@ describe Chef::Provider::Script, "action_run" do
end
end
- context "#set_owner_and_group" do
- it "sets the owner and group for the script file" do
- new_resource.user 'toor'
- new_resource.group 'wheel'
- expect(FileUtils).to receive(:chown).with('toor', 'wheel', tempfile.path)
- provider.set_owner_and_group
+ context "when configuring the script file's security" do
+ context "when not running on Windows" do
+ before do
+ allow(::Chef::Platform).to receive(:windows?).and_return(false)
+ end
+ context "#set_owner_and_group" do
+ it "sets the owner and group for the script file" do
+ new_resource.user "toor"
+ new_resource.group "wheel"
+ expect(FileUtils).to receive(:chown).with("toor", "wheel", tempfile.path)
+ provider.set_owner_and_group
+ end
+ end
+ end
+
+ context "when running on Windows" do
+ before do
+ allow(::Chef::Platform).to receive(:windows?).and_return(true)
+ expect(new_resource.user).to eq(nil)
+ stub_const("Chef::ReservedNames::Win32::API::Security::GENERIC_READ", 1)
+ stub_const("Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE", 4)
+ stub_const("Chef::ReservedNames::Win32::Security", Class.new)
+ stub_const("Chef::ReservedNames::Win32::Security::SecurableObject", Class.new)
+ stub_const("Chef::ReservedNames::Win32::Security::SID", Class.new)
+ stub_const("Chef::ReservedNames::Win32::Security::ACE", Class.new)
+ stub_const("Chef::ReservedNames::Win32::Security::ACL", Class.new)
+ end
+
+ context "when an alternate user is not specified" do
+ it "does not attempt to set the script file's security descriptor" do
+ expect(provider).to receive(:grant_alternate_user_read_access)
+ expect(Chef::ReservedNames::Win32::Security::SecurableObject).not_to receive(:new)
+ provider.set_owner_and_group
+ end
+ end
+
+ context "when an alternate user is specified" do
+ let(:security_descriptor) { instance_double("Chef::ReservedNames::Win32::Security::SecurityDescriptor", :dacl => []) }
+ let(:securable_object) { instance_double("Chef::ReservedNames::Win32::Security::SecurableObject", :security_descriptor => security_descriptor, :dacl= => nil) }
+ it "sets the script file's security descriptor" do
+ new_resource.user("toor")
+ expect(Chef::ReservedNames::Win32::Security::SecurableObject).to receive(:new).and_return(securable_object)
+ expect(Chef::ReservedNames::Win32::Security::SID).to receive(:from_account).and_return(nil)
+ expect(Chef::ReservedNames::Win32::Security::ACE).to receive(:access_allowed).and_return(nil)
+ expect(Chef::ReservedNames::Win32::Security::ACL).to receive(:create).and_return(nil)
+ expect(securable_object).to receive(:dacl=)
+ provider.set_owner_and_group
+ end
+ end
end
end
@@ -72,7 +115,7 @@ describe Chef::Provider::Script, "action_run" do
describe "when writing the script to the file" do
it "should put the contents of the script in the temp file" do
- allow(provider).to receive(:unlink_script_file) # stub to avoid remove
+ allow(provider).to receive(:unlink_script_file) # stub to avoid remove
provider.action_run
expect(IO.read(tempfile.path)).to eq("$| = 1; print 'i like beans'\n")
provider.unlink_script_file
@@ -87,25 +130,25 @@ describe Chef::Provider::Script, "action_run" do
end
describe "when running the script" do
- let (:default_opts) {
- {timeout: 3600, returns: 0, log_level: :info, log_tag: "script[run some perl code]", live_stream: STDOUT}
- }
+ let (:default_opts) do
+ { timeout: 3600, returns: 0, log_level: :info, log_tag: "script[run some perl code]" }
+ end
before do
- allow(STDOUT).to receive(:tty?).and_return(true)
+ allow(STDOUT).to receive(:tty?).and_return(false)
end
it 'should set the command to "interpreter" "tempfile"' do
expect(provider.command).to eq(%Q{"perl" "#{tempfile.path}"})
end
- it 'should call shell_out! with the command' do
+ it "should call shell_out! with the command" do
expect(provider).to receive(:shell_out!).with(provider.command, default_opts).and_return(true)
provider.action_run
end
it "should set the command to 'interpreter flags tempfile'" do
- new_resource.flags '-f'
+ new_resource.flags "-f"
expect(provider.command).to eq(%Q{"perl" -f "#{tempfile.path}"})
end
end
diff --git a/spec/unit/provider/service/aix_service_spec.rb b/spec/unit/provider/service/aix_service_spec.rb
index 5cca7d6f0a..802ccee2c7 100644
--- a/spec/unit/provider/service/aix_service_spec.rb
+++ b/spec/unit/provider/service/aix_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Kaustubh <kaustubh@clogeny.com>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service::Aix do
before(:each) do
@@ -133,7 +133,7 @@ describe Chef::Provider::Service::Aix do
end
it "should call the start command for groups" do
- @provider.instance_eval('@is_resource_group = true')
+ @provider.instance_eval("@is_resource_group = true")
expect(@provider).to receive(:shell_out!).with("startsrc -g #{@new_resource.service_name}")
@provider.start_service
@@ -152,7 +152,7 @@ describe Chef::Provider::Service::Aix do
end
it "should call the stop command for groups" do
- @provider.instance_eval('@is_resource_group = true')
+ @provider.instance_eval("@is_resource_group = true")
expect(@provider).to receive(:shell_out!).with("stopsrc -g #{@new_resource.service_name}")
@provider.stop_service
@@ -171,7 +171,7 @@ describe Chef::Provider::Service::Aix do
end
it "should call the reload command for groups" do
- @provider.instance_eval('@is_resource_group = true')
+ @provider.instance_eval("@is_resource_group = true")
expect(@provider).to receive(:shell_out!).with("refresh -g #{@new_resource.service_name}")
@provider.reload_service
@@ -193,4 +193,3 @@ describe Chef::Provider::Service::Aix do
end
end
end
-
diff --git a/spec/unit/provider/service/aixinit_service_spec.rb b/spec/unit/provider/service/aixinit_service_spec.rb
index e4c9faa8b4..09c177903b 100644
--- a/spec/unit/provider/service/aixinit_service_spec.rb
+++ b/spec/unit/provider/service/aixinit_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: kaustubh (<kaustubh@clogeny.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service::AixInit do
before(:each) do
@node = Chef::Node.new
- @node.automatic_attrs[:command] = {:ps => 'fuuuu'}
+ @node.automatic_attrs[:command] = { :ps => "fuuuu" }
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@@ -102,7 +102,7 @@ describe Chef::Provider::Service::AixInit do
context "when the service doesn't set a priority" do
it "creates symlink with status S" do
- expect(@provider).to receive(:create_symlink).with(2,'S','')
+ expect(@provider).to receive(:create_symlink).with(2, "S", "")
@provider.enable_service
end
@@ -114,7 +114,7 @@ describe Chef::Provider::Service::AixInit do
end
it "creates a symlink with status S and a priority" do
- expect(@provider).to receive(:create_symlink).with(2,'S',75)
+ expect(@provider).to receive(:create_symlink).with(2, "S", 75)
@provider.enable_service
end
@@ -122,13 +122,13 @@ describe Chef::Provider::Service::AixInit do
context "when the service sets complex priorities (hash)" do
before do
- priority = {2 => [:start, 20], 3 => [:stop, 10]}
+ priority = { 2 => [:start, 20], 3 => [:stop, 10] }
@new_resource.priority(priority)
end
it "create symlink with status start (S) or stop (K) and a priority " do
- expect(@provider).to receive(:create_symlink).with(2,'S',20)
- expect(@provider).to receive(:create_symlink).with(3,'K',10)
+ expect(@provider).to receive(:create_symlink).with(2, "S", 20)
+ expect(@provider).to receive(:create_symlink).with(3, "K", 10)
@provider.enable_service
end
@@ -142,7 +142,7 @@ describe Chef::Provider::Service::AixInit do
context "when the service doesn't set a priority" do
it "creates symlinks with status stop (K)" do
- expect(@provider).to receive(:create_symlink).with(2,'K','')
+ expect(@provider).to receive(:create_symlink).with(2, "K", "")
@provider.disable_service
end
@@ -154,7 +154,7 @@ describe Chef::Provider::Service::AixInit do
end
it "create symlink with status stop (k) and a priority " do
- expect(@provider).to receive(:create_symlink).with(2,'K',25)
+ expect(@provider).to receive(:create_symlink).with(2, "K", 25)
@provider.disable_service
end
@@ -162,12 +162,12 @@ describe Chef::Provider::Service::AixInit do
context "when the service sets complex priorities (hash)" do
before do
- @priority = {2 => [:start, 20], 3 => [:stop, 10]}
+ @priority = { 2 => [:start, 20], 3 => [:stop, 10] }
@new_resource.priority(@priority)
end
it "create symlink with status stop (k) and a priority " do
- expect(@provider).to receive(:create_symlink).with(3,'K',90)
+ expect(@provider).to receive(:create_symlink).with(3, "K", 90)
@provider.disable_service
end
@@ -183,17 +183,17 @@ describe Chef::Provider::Service::AixInit do
end
it "the service is enabled" do
- expect(@provider.current_resource).to receive(:enabled).with(true)
- expect(@provider.current_resource).to receive(:priority).with(20)
+ expect(@provider.current_resource).to receive(:enabled).with(true)
+ expect(@provider.current_resource).to receive(:priority).with(20)
- @provider.set_current_resource_attributes
+ @provider.set_current_resource_attributes
end
end
context "when rc2.d contains only stop script" do
before do
files = ["/etc/rc.d/rc2.d/K20apache"]
- @priority = {2 => [:stop, 20]}
+ @priority = { 2 => [:stop, 20] }
allow(Dir).to receive(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]chef"]).and_return(files)
end
@@ -208,7 +208,9 @@ describe Chef::Provider::Service::AixInit do
context "when rc2.d contains both start and stop scripts" do
before do
@files = ["/etc/rc.d/rc2.d/S20apache", "/etc/rc.d/rc2.d/K80apache"]
- @priority = {2 => [:start, 20], 2 => [:stop, 80]}
+ # FIXME: this is clearly buggy the duplicated keys do not work
+ #@priority = {2 => [:start, 20], 2 => [:stop, 80]}
+ @priority = { 2 => [:stop, 80] }
allow(Dir).to receive(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]chef"]).and_return(@files)
end
@@ -228,17 +230,17 @@ describe Chef::Provider::Service::AixInit do
end
it "the service is enabled" do
- expect(@provider.current_resource).to receive(:enabled).with(true)
- expect(@provider.current_resource).to receive(:priority).with('')
+ expect(@provider.current_resource).to receive(:enabled).with(true)
+ expect(@provider.current_resource).to receive(:priority).with("")
- @provider.set_current_resource_attributes
+ @provider.set_current_resource_attributes
end
end
context "when rc2.d contains only stop script (without priority)" do
before do
files = ["/etc/rc.d/rc2.d/Kapache"]
- @priority = {2 => [:stop, '']}
+ @priority = { 2 => [:stop, ""] }
allow(Dir).to receive(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).and_return(files)
end
@@ -253,7 +255,9 @@ describe Chef::Provider::Service::AixInit do
context "when rc2.d contains both start and stop scripts" do
before do
files = ["/etc/rc.d/rc2.d/Sapache", "/etc/rc.d/rc2.d/Kapache"]
- @priority = {2 => [:start, ''], 2 => [:stop, '']}
+ # FIXME: this is clearly buggy the duplicated keys do not work
+ #@priority = {2 => [:start, ''], 2 => [:stop, '']}
+ @priority = { 2 => [:stop, ""] }
allow(Dir).to receive(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).and_return(files)
end
@@ -266,4 +270,3 @@ describe Chef::Provider::Service::AixInit do
end
end
end
-
diff --git a/spec/unit/provider/service/arch_service_spec.rb b/spec/unit/provider/service/arch_service_spec.rb
index 49be0e274c..506a1616c5 100644
--- a/spec/unit/provider/service/arch_service_spec.rb
+++ b/spec/unit/provider/service/arch_service_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Jan Zimmek (<jan.zimmek@web.de>)
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
# most of this code has been ripped from init_service_spec.rb
# and is only slightly modified to match "arch" needs.
@@ -26,14 +26,14 @@ require 'ostruct'
describe Chef::Provider::Service::Arch, "load_current_resource" do
before(:each) do
@node = Chef::Node.new
- @node.automatic_attrs[:command] = {:ps => "ps -ef"}
+ @node.automatic_attrs[:command] = { :ps => "ps -ef" }
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@new_resource = Chef::Resource::Service.new("chef")
@new_resource.pattern("chef")
- @new_resource.supports({:status => false})
+ @new_resource.supports({ :status => false })
@provider = Chef::Provider::Service::Arch.new(@new_resource, @run_context)
@@ -45,13 +45,13 @@ describe Chef::Provider::Service::Arch, "load_current_resource" do
it "should set the current resources service name to the new resources service name" do
allow(@provider).to receive(:shell_out).and_return(OpenStruct.new(:exitstatus => 0, :stdout => ""))
@provider.load_current_resource
- expect(@provider.current_resource.service_name).to eq('chef')
+ expect(@provider.current_resource.service_name).to eq("chef")
end
end
describe "when the service supports status" do
before do
- @new_resource.supports({:status => true})
+ @new_resource.supports({ :status => true })
end
it "should run '/etc/rc.d/service_name status'" do
@@ -92,14 +92,14 @@ describe Chef::Provider::Service::Arch, "load_current_resource" do
end
it "should raise error if the node has a nil ps attribute and no other means to get status" do
- @node.automatic_attrs[:command] = {:ps => nil}
+ @node.automatic_attrs[:command] = { :ps => nil }
@provider.define_resource_requirements
@provider.action = :start
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
end
it "should raise error if the node has an empty ps attribute and no other means to get status" do
- @node.automatic_attrs[:command] = {:ps => ""}
+ @node.automatic_attrs[:command] = { :ps => "" }
@provider.define_resource_requirements
@provider.action = :start
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
@@ -125,7 +125,7 @@ DEFAULT_PS
@status = double("Status", :exitstatus => 0, :stdout => @stdout)
allow(@provider).to receive(:shell_out!).and_return(@status)
- @node.automatic_attrs[:command] = {:ps => "ps -ef"}
+ @node.automatic_attrs[:command] = { :ps => "ps -ef" }
end
it "determines the service is running when it appears in ps" do
@@ -155,7 +155,7 @@ RUNNING_PS
it "should return existing entries in DAEMONS array" do
allow(::File).to receive(:read).with("/etc/rc.conf").and_return("DAEMONS=(network !apache ssh)")
- expect(@provider.daemons).to eq(['network', '!apache', 'ssh'])
+ expect(@provider.daemons).to eq(["network", "!apache", "ssh"])
end
context "when the current service status is known" do
@@ -180,7 +180,7 @@ RUNNING_PS
it "should add chef to DAEMONS array" do
allow(::File).to receive(:read).with("/etc/rc.conf").and_return("DAEMONS=(network)")
- expect(@provider).to receive(:update_daemons).with(['network', 'chef'])
+ expect(@provider).to receive(:update_daemons).with(%w{network chef})
@provider.enable_service()
end
end
@@ -201,7 +201,7 @@ RUNNING_PS
it "should remove chef from DAEMONS array" do
allow(::File).to receive(:read).with("/etc/rc.conf").and_return("DAEMONS=(network chef)")
- expect(@provider).to receive(:update_daemons).with(['network', '!chef'])
+ expect(@provider).to receive(:update_daemons).with(["network", "!chef"])
@provider.disable_service()
end
end
@@ -274,7 +274,7 @@ RUNNING_PS
# end
it "should call 'restart' on the service_name if the resource supports it" do
- allow(@new_resource).to receive(:supports).and_return({:restart => true})
+ allow(@new_resource).to receive(:supports).and_return({ :restart => true })
expect(@provider).to receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} restart")
@provider.restart_service()
end
@@ -309,7 +309,7 @@ RUNNING_PS
# end
it "should call 'reload' on the service if it supports it" do
- allow(@new_resource).to receive(:supports).and_return({:reload => true})
+ allow(@new_resource).to receive(:supports).and_return({ :reload => true })
expect(@provider).to receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} reload")
@provider.reload_service()
end
diff --git a/spec/unit/provider/service/debian_service_spec.rb b/spec/unit/provider/service/debian_service_spec.rb
index a4667e8ce8..799ed991a3 100644
--- a/spec/unit/provider/service/debian_service_spec.rb
+++ b/spec/unit/provider/service/debian_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 HJK Solutions, LLC
+# Copyright:: Copyright 2008-2016, HJK Solutions, LLC
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service::Debian do
before(:each) do
@node = Chef::Node.new
- @node.automatic_attrs[:command] = {:ps => 'fuuuu'}
+ @node.automatic_attrs[:command] = { :ps => "fuuuu" }
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@@ -39,9 +39,9 @@ describe Chef::Provider::Service::Debian do
expect(File).to receive(:exists?).with("/usr/sbin/update-rc.d") .and_return(false)
@provider.define_resource_requirements
- expect {
+ expect do
@provider.process_resource_requirements
- }.to raise_error(Chef::Exceptions::Service)
+ end.to raise_error(Chef::Exceptions::Service)
end
context "when update-rc.d shows init linked to rc*.d/" do
@@ -108,13 +108,13 @@ describe Chef::Provider::Service::Debian do
it "raises an error" do
@provider.define_resource_requirements
- expect {
+ expect do
@provider.process_resource_requirements
- }.to raise_error(Chef::Exceptions::Service)
+ end.to raise_error(Chef::Exceptions::Service)
end
end
- {"Debian/Lenny and older" => {
+ { "Debian/Lenny and older" => {
"linked" => {
"stdout" => <<-STDOUT,
Removing any system startup links for /etc/init.d/chef ...
@@ -128,18 +128,18 @@ describe Chef::Provider::Service::Debian do
STDOUT
"stderr" => "",
"priorities" => {
- "0"=>[:stop, "20"],
- "1"=>[:stop, "20"],
- "2"=>[:start, "20"],
- "3"=>[:start, "20"],
- "4"=>[:start, "20"],
- "5"=>[:start, "20"],
- "6"=>[:stop, "20"]
- }
+ "0" => [:stop, "20"],
+ "1" => [:stop, "20"],
+ "2" => [:start, "20"],
+ "3" => [:start, "20"],
+ "4" => [:start, "20"],
+ "5" => [:start, "20"],
+ "6" => [:stop, "20"],
+ },
},
"not linked" => {
"stdout" => " Removing any system startup links for /etc/init.d/chef ...",
- "stderr" => ""
+ "stderr" => "",
},
},
"Debian/Squeeze and earlier" => {
@@ -156,19 +156,19 @@ insserv: remove service /etc/init.d/../rc0.d/K20chef-client
insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
STDERR
"priorities" => {
- "0"=>[:stop, "20"],
- "1"=>[:stop, "20"],
- "2"=>[:start, "20"],
- "3"=>[:start, "20"],
- "4"=>[:start, "20"],
- "5"=>[:start, "20"],
- "6"=>[:stop, "20"]
- }
+ "0" => [:stop, "20"],
+ "1" => [:stop, "20"],
+ "2" => [:start, "20"],
+ "3" => [:start, "20"],
+ "4" => [:start, "20"],
+ "5" => [:start, "20"],
+ "6" => [:stop, "20"],
+ },
},
"not linked" => {
"stdout" => "update-rc.d: using dependency based boot sequencing",
- "stderr" => ""
- }
+ "stderr" => "",
+ },
},
"Debian/Wheezy and earlier, a service only starting at run level S" => {
"linked" => {
@@ -181,17 +181,17 @@ insserv: remove service /etc/init.d/../rcS.d/S13rpcbind
insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
STDERR
"priorities" => {
- "0"=>[:stop, "06"],
- "1"=>[:stop, "06"],
- "6"=>[:stop, "06"],
- "S"=>[:start, "13"]
- }
+ "0" => [:stop, "06"],
+ "1" => [:stop, "06"],
+ "6" => [:stop, "06"],
+ "S" => [:start, "13"],
+ },
},
"not linked" => {
"stdout" => "",
- "stderr" => "insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop"
- }
- }
+ "stderr" => "insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop",
+ },
+ },
}.each do |model, expected_results|
context "on #{model}" do
context "when update-rc.d shows init linked to rc*.d/" do
@@ -276,7 +276,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
context "when the service is enabled" do
before do
@current_resource.enabled(true)
- @current_resource.priority(80)
+ @current_resource.priority(80)
end
context "and the service sets no priority" do
@@ -311,7 +311,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
it "calls update-rc.d 'service_name' defaults" do
expect_commands(@provider, [
"/usr/sbin/update-rc.d -f #{service_name} remove",
- "/usr/sbin/update-rc.d #{service_name} defaults"
+ "/usr/sbin/update-rc.d #{service_name} defaults",
])
@provider.enable_service
end
@@ -325,7 +325,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
it "calls update-rc.d 'service_name' defaults" do
expect_commands(@provider, [
"/usr/sbin/update-rc.d -f #{service_name} remove",
- "/usr/sbin/update-rc.d #{service_name} defaults 75 25"
+ "/usr/sbin/update-rc.d #{service_name} defaults 75 25",
])
@provider.enable_service
end
@@ -339,7 +339,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
it "calls update-rc.d 'service_name' with those priorities" do
expect_commands(@provider, [
"/usr/sbin/update-rc.d -f #{service_name} remove",
- "/usr/sbin/update-rc.d #{service_name} start 20 2 . stop 55 3 . "
+ "/usr/sbin/update-rc.d #{service_name} start 20 2 . stop 55 3 . ",
])
@provider.enable_service
end
@@ -352,7 +352,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
it "calls update-rc.d -f 'service_name' remove + stop with default priority" do
expect_commands(@provider, [
"/usr/sbin/update-rc.d -f #{service_name} remove",
- "/usr/sbin/update-rc.d -f #{service_name} stop 80 2 3 4 5 ."
+ "/usr/sbin/update-rc.d -f #{service_name} stop 80 2 3 4 5 .",
])
@provider.disable_service
end
@@ -366,7 +366,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
it "calls update-rc.d -f 'service_name' remove + stop with the specified priority" do
expect_commands(@provider, [
"/usr/sbin/update-rc.d -f #{service_name} remove",
- "/usr/sbin/update-rc.d -f #{service_name} stop #{100 - @new_resource.priority} 2 3 4 5 ."
+ "/usr/sbin/update-rc.d -f #{service_name} stop #{100 - @new_resource.priority} 2 3 4 5 .",
])
@provider.disable_service
end
diff --git a/spec/unit/provider/service/freebsd_service_spec.rb b/spec/unit/provider/service/freebsd_service_spec.rb
index cfc28c94d5..10eb3c1a14 100644
--- a/spec/unit/provider/service/freebsd_service_spec.rb
+++ b/spec/unit/provider/service/freebsd_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
class Chef::Provider::Service::Freebsd
public :service_enable_variable_name
@@ -27,14 +27,14 @@ end
describe Chef::Provider::Service::Freebsd do
let(:node) do
node = Chef::Node.new
- node.automatic_attrs[:command] = {:ps => "ps -ax"}
+ node.automatic_attrs[:command] = { :ps => "ps -ax" }
node
end
let(:new_resource) do
new_resource = Chef::Resource::Service.new("apache22")
new_resource.pattern("httpd")
- new_resource.supports({:status => false})
+ new_resource.supports({ :status => false })
new_resource
end
@@ -46,7 +46,7 @@ describe Chef::Provider::Service::Freebsd do
let(:provider) do
events = Chef::EventDispatch::Dispatcher.new
run_context = Chef::RunContext.new(node, {}, events)
- provider = Chef::Provider::Service::Freebsd.new(new_resource,run_context)
+ provider = Chef::Provider::Service::Freebsd.new(new_resource, run_context)
provider.action = :start
provider
end
@@ -115,7 +115,7 @@ describe Chef::Provider::Service::Freebsd do
let(:status) { double(:stdout => "", :exitstatus => 0) }
before do
- new_resource.supports({:status => true})
+ new_resource.supports({ :status => true })
end
it "should run '/etc/init.d/service_name status'" do
@@ -147,7 +147,7 @@ PS_SAMPLE
let(:status) { double(:stdout => stdout, :exitstatus => 0) }
before do
- node.automatic_attrs[:command] = {:ps => "ps -ax"}
+ node.automatic_attrs[:command] = { :ps => "ps -ax" }
end
it "should shell_out! the node's ps command" do
@@ -191,7 +191,7 @@ PS_SAMPLE
context "when ps is empty string" do
before do
- node.automatic_attrs[:command] = {:ps => ""}
+ node.automatic_attrs[:command] = { :ps => "" }
end
it "should set running to nil" do
@@ -257,10 +257,11 @@ PS_SAMPLE
end
context "when the enable variable partial matches (left) some other service and we are disabled" do
- let(:lines) { [
+ let(:lines) do
+ [
%Q{thing_#{new_resource.service_name}_enable="YES"},
%Q{#{new_resource.service_name}_enable="NO"},
- ] }
+ ] end
it "sets enabled based on the exact match (false)" do
provider.determine_enabled_status!
expect(current_resource.enabled).to be false
@@ -268,10 +269,11 @@ PS_SAMPLE
end
context "when the enable variable partial matches (right) some other service and we are disabled" do
- let(:lines) { [
+ let(:lines) do
+ [
%Q{#{new_resource.service_name}_thing_enable="YES"},
%Q{#{new_resource.service_name}_enable="NO"},
- ] }
+ ] end
it "sets enabled based on the exact match (false)" do
provider.determine_enabled_status!
expect(current_resource.enabled).to be false
@@ -279,10 +281,11 @@ PS_SAMPLE
end
context "when the enable variable partial matches (left) some other disabled service and we are enabled" do
- let(:lines) { [
+ let(:lines) do
+ [
%Q{thing_#{new_resource.service_name}_enable="NO"},
%Q{#{new_resource.service_name}_enable="YES"},
- ] }
+ ] end
it "sets enabled based on the exact match (true)" do
provider.determine_enabled_status!
expect(current_resource.enabled).to be true
@@ -290,10 +293,11 @@ PS_SAMPLE
end
context "when the enable variable partial matches (right) some other disabled service and we are enabled" do
- let(:lines) { [
+ let(:lines) do
+ [
%Q{#{new_resource.service_name}_thing_enable="NO"},
%Q{#{new_resource.service_name}_enable="YES"},
- ] }
+ ] end
it "sets enabled based on the exact match (true)" do
provider.determine_enabled_status!
expect(current_resource.enabled).to be true
@@ -465,7 +469,7 @@ EOF
describe Chef::Provider::Service::Freebsd, "restart_service" do
it "should call 'restart' on the service_name if the resource supports it" do
- new_resource.supports({:restart => true})
+ new_resource.supports({ :restart => true })
expect(provider).to receive(:shell_out_with_systems_locale!).with("/usr/local/etc/rc.d/#{new_resource.service_name} fastrestart")
provider.restart_service()
end
@@ -495,7 +499,7 @@ EOF
allow(provider).to receive(:service_enable_variable_name).and_return("#{new_resource.service_name}_enable")
end
- [ "start", "reload", "restart", "enable" ].each do |action|
+ %w{start reload restart enable}.each do |action|
it "should raise an exception when the action is #{action}" do
provider.define_resource_requirements
provider.action = action
@@ -503,7 +507,7 @@ EOF
end
end
- [ "stop", "disable" ].each do |action|
+ %w{stop disable}.each do |action|
it "should not raise an error when the action is #{action}" do
provider.define_resource_requirements
provider.action = action
@@ -518,7 +522,7 @@ EOF
allow(provider).to receive(:service_enable_variable_name).and_return(nil)
end
- [ "start", "reload", "restart", "enable" ].each do |action|
+ %w{start reload restart enable}.each do |action|
it "should raise an exception when the action is #{action}" do
provider.action = action
provider.define_resource_requirements
@@ -526,7 +530,7 @@ EOF
end
end
- [ "stop", "disable" ].each do |action|
+ %w{stop disable}.each do |action|
it "should not raise an error when the action is #{action}" do
provider.action = action
provider.define_resource_requirements
@@ -558,7 +562,7 @@ EOF
it "should enable the service if it is not enabled and not already specified in the rc.conf file" do
allow(current_resource).to receive(:enabled).and_return(false)
- expect(provider).to receive(:read_rc_conf).and_return([ "foo", "bar" ])
+ expect(provider).to receive(:read_rc_conf).and_return(%w{foo bar})
expect(provider).to receive(:write_rc_conf).with(["foo", "bar", "#{new_resource.service_name}_enable=\"YES\""])
provider.enable_service()
end
diff --git a/spec/unit/provider/service/gentoo_service_spec.rb b/spec/unit/provider/service/gentoo_service_spec.rb
index 0aa7bf4529..a00ca7aadd 100644
--- a/spec/unit/provider/service/gentoo_service_spec.rb
+++ b/spec/unit/provider/service/gentoo_service_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Lee Jensen (<ljensen@engineyard.com>)
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service::Gentoo do
before(:each) do
@@ -100,7 +100,7 @@ describe Chef::Provider::Service::Gentoo do
end
end
- end
+ end
it "should return the current_resource" do
expect(@provider.load_current_resource).to eq(@current_resource)
diff --git a/spec/unit/provider/service/init_service_spec.rb b/spec/unit/provider/service/init_service_spec.rb
index 827a4261e1..4b31e9c399 100644
--- a/spec/unit/provider/service/init_service_spec.rb
+++ b/spec/unit/provider/service/init_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service::Init, "load_current_resource" do
before(:each) do
@node = Chef::Node.new
- @node.automatic_attrs[:command] = {:ps => "ps -ef"}
+ @node.automatic_attrs[:command] = { :ps => "ps -ef" }
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@@ -48,12 +48,12 @@ PS
it "should set the current resources service name to the new resources service name" do
@provider.load_current_resource
- expect(@current_resource.service_name).to eq('chef')
+ expect(@current_resource.service_name).to eq("chef")
end
describe "when the service supports status" do
before do
- @new_resource.supports({:status => true})
+ @new_resource.supports({ :status => true })
end
it "should run '/etc/init.d/service_name status'" do
@@ -109,7 +109,7 @@ PS
describe "when the node has not specified a ps command" do
it "should raise an error if the node has a nil ps attribute" do
- @node.automatic_attrs[:command] = {:ps => nil}
+ @node.automatic_attrs[:command] = { :ps => nil }
@provider.load_current_resource
@provider.action = :start
@provider.define_resource_requirements
@@ -117,7 +117,7 @@ PS
end
it "should raise an error if the node has an empty ps attribute" do
- @node.automatic_attrs[:command] = {:ps => ""}
+ @node.automatic_attrs[:command] = { :ps => "" }
@provider.load_current_resource
@provider.action = :start
@provider.define_resource_requirements
@@ -189,7 +189,7 @@ RUNNING_PS
describe "when restarting a service" do
it "should call 'restart' on the service_name if the resource supports it" do
- @new_resource.supports({:restart => true})
+ @new_resource.supports({ :restart => true })
expect(@provider).to receive(:shell_out_with_systems_locale!).with("/etc/init.d/#{@new_resource.service_name} restart")
@provider.restart_service()
end
@@ -210,7 +210,7 @@ RUNNING_PS
describe "when reloading a service" do
it "should call 'reload' on the service if it supports it" do
- @new_resource.supports({:reload => true})
+ @new_resource.supports({ :reload => true })
expect(@provider).to receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef reload")
@provider.reload_service()
end
diff --git a/spec/unit/provider/service/insserv_service_spec.rb b/spec/unit/provider/service/insserv_service_spec.rb
index 3799daebb4..3b2b19c432 100644
--- a/spec/unit/provider/service/insserv_service_spec.rb
+++ b/spec/unit/provider/service/insserv_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service::Insserv do
before(:each) do
@node = Chef::Node.new
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @node.automatic_attrs[:command] = {:ps => "ps -ax"}
+ @node.automatic_attrs[:command] = { :ps => "ps -ax" }
@new_resource = Chef::Resource::Service.new("initgrediant")
@current_resource = Chef::Resource::Service.new("initgrediant")
diff --git a/spec/unit/provider/service/invokercd_service_spec.rb b/spec/unit/provider/service/invokercd_service_spec.rb
index 81588c80e5..57b13d0c51 100644
--- a/spec/unit/provider/service/invokercd_service_spec.rb
+++ b/spec/unit/provider/service/invokercd_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service::Invokercd, "load_current_resource" do
before(:each) do
@node = Chef::Node.new
- @node.automatic_attrs[:command] = {:ps => "ps -ef"}
+ @node.automatic_attrs[:command] = { :ps => "ps -ef" }
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@@ -48,12 +48,12 @@ PS
it "should set the current resources service name to the new resources service name" do
@provider.load_current_resource
- expect(@current_resource.service_name).to eq('chef')
+ expect(@current_resource.service_name).to eq("chef")
end
describe "when the service supports status" do
before do
- @new_resource.supports({:status => true})
+ @new_resource.supports({ :status => true })
end
it "should run '/usr/sbin/invoke-rc.d service_name status'" do
@@ -95,14 +95,14 @@ PS
describe "when the node has not specified a ps command" do
it "should raise error if the node has a nil ps attribute and no other means to get status" do
- @node.automatic_attrs[:command] = {:ps => nil}
+ @node.automatic_attrs[:command] = { :ps => nil }
@provider.action = :start
@provider.define_resource_requirements
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
end
it "should raise error if the node has an empty ps attribute and no other means to get status" do
- @node.automatic_attrs[:command] = {:ps => ""}
+ @node.automatic_attrs[:command] = { :ps => "" }
@provider.action = :start
@provider.define_resource_requirements
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
@@ -176,7 +176,7 @@ RUNNING_PS
describe "when restarting a service" do
it "should call 'restart' on the service_name if the resource supports it" do
- @new_resource.supports({:restart => true})
+ @new_resource.supports({ :restart => true })
expect(@provider).to receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} restart")
@provider.restart_service()
end
@@ -197,7 +197,7 @@ RUNNING_PS
describe "when reloading a service" do
it "should call 'reload' on the service if it supports it" do
- @new_resource.supports({:reload => true})
+ @new_resource.supports({ :reload => true })
expect(@provider).to receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d chef reload")
@provider.reload_service()
end
diff --git a/spec/unit/provider/service/macosx_spec.rb b/spec/unit/provider/service/macosx_spec.rb
index 54183bdc3d..c9dd629187 100644
--- a/spec/unit/provider/service/macosx_spec.rb
+++ b/spec/unit/provider/service/macosx_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Igor Afonov <afonov@gmail.com>
-# Copyright:: Copyright (c) 2011 Igor Afonov
+# Copyright:: Copyright 2011-2016, Igor Afonov
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service::Macosx do
describe ".gather_plist_dirs" do
context "when HOME directory is set" do
before do
- allow(Chef::Util::PathHelper).to receive(:home).with('Library', 'LaunchAgents').and_yield('/Users/someuser/Library/LaunchAgents')
+ allow(Chef::Util::PathHelper).to receive(:home).with("Library", "LaunchAgents").and_yield("/Users/someuser/Library/LaunchAgents")
end
it "includes users's LaunchAgents folder" do
@@ -32,7 +32,7 @@ describe Chef::Provider::Service::Macosx do
context "when HOME directory is not set" do
before do
- allow(Chef::Util::PathHelper).to receive(:home).with('Library', 'LaunchAgents').and_return(nil)
+ allow(Chef::Util::PathHelper).to receive(:home).with("Library", "LaunchAgents").and_return(nil)
end
it "doesn't include user's LaunchAgents folder" do
@@ -43,7 +43,7 @@ describe Chef::Provider::Service::Macosx do
context "when service name is given as" do
let(:node) { Chef::Node.new }
- let(:events) {Chef::EventDispatch::Dispatcher.new}
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
let(:run_context) { Chef::RunContext.new(node, {}, events) }
let(:provider) { described_class.new(new_resource, run_context) }
let(:launchctl_stdout) { StringIO.new }
@@ -58,33 +58,33 @@ describe Chef::Provider::Service::Macosx do
</plist>
XML
- ["Daemon", "Agent"].each do |service_type|
+ %w{Daemon Agent}.each do |service_type|
["redis-server", "io.redis.redis-server"].each do |service_name|
["10.9", "10.10", "10.11"].each do |platform_version|
- let(:plist) {'/Library/LaunchDaemons/io.redis.redis-server.plist'}
+ let(:plist) { "/Library/LaunchDaemons/io.redis.redis-server.plist" }
let(:session) { StringIO.new }
- if service_type == 'Agent'
- let(:plist) {'/Library/LaunchAgents/io.redis.redis-server.plist'}
- let(:session) {'-S Aqua '}
- let(:su_cmd) {'su -l igor -c'}
+ if service_type == "Agent"
+ let(:plist) { "/Library/LaunchAgents/io.redis.redis-server.plist" }
+ let(:session) { "-S Aqua " }
+ let(:su_cmd) { "su -l igor -c" }
if platform_version == "10.9"
- let(:su_cmd) {'su igor -c'}
+ let(:su_cmd) { "su igor -c" }
end
end
- let(:service_label) {'io.redis.redis-server'}
+ let(:service_label) { "io.redis.redis-server" }
before do
allow(Dir).to receive(:glob).and_return([plist], [])
- allow(Etc).to receive(:getlogin).and_return('igor')
+ allow(Etc).to receive(:getlogin).and_return("igor")
allow(node).to receive(:[]).with("platform_version").and_return(platform_version)
cmd = "launchctl list #{service_label}"
allow(provider).to receive(:shell_out_with_systems_locale).
- with(/(#{su_cmd} '#{cmd}'|#{cmd})/).
- and_return(double("Status",
+ with(/(#{su_cmd} '#{cmd}'|#{cmd})/).
+ and_return(double("Status",
:stdout => launchctl_stdout, :exitstatus => 0))
allow(File).to receive(:exists?).and_return([true], [])
allow(provider).to receive(:shell_out_with_systems_locale!).
- with(/plutil -convert xml1 -o/).
- and_return(double("Status", :stdout => plutil_stdout))
+ with(/plutil -convert xml1 -o/).
+ and_return(double("Status", :stdout => plutil_stdout))
end
context "#{service_name} that is a #{service_type} running Osx #{platform_version}" do
@@ -109,8 +109,8 @@ XML
allow(Dir).to receive(:glob).and_return([])
allow(File).to receive(:exists?).and_return([true], [])
allow(provider).to receive(:shell_out!).
- with(/plutil -convert xml1 -o/).
- and_raise(Mixlib::ShellOut::ShellCommandFailed)
+ with(/plutil -convert xml1 -o/).
+ and_raise(Mixlib::ShellOut::ShellCommandFailed)
end
it "works for action :nothing" do
@@ -166,7 +166,7 @@ SVC_LIST
allow(File).to receive(:exists?).and_return([true], [])
end
it "should throw an exception when reload action is attempted" do
- expect {provider.run_action(:reload)}.to raise_error(Chef::Exceptions::UnsupportedAction)
+ expect { provider.run_action(:reload) }.to raise_error(Chef::Exceptions::UnsupportedAction)
end
end
context "when launchctl returns empty service pid" do
@@ -263,10 +263,10 @@ SVC_LIST
end
it "starts service via launchctl if service found" do
- cmd = 'launchctl load -w ' + session + plist
+ cmd = "launchctl load -w " + session + plist
expect(provider).to receive(:shell_out_with_systems_locale).
- with(/(#{su_cmd} .#{cmd}.|#{cmd})/).
- and_return(0)
+ with(/(#{su_cmd} .#{cmd}.|#{cmd})/).
+ and_return(0)
provider.start_service
end
@@ -295,10 +295,10 @@ SVC_LIST
end
it "stops the service via launchctl if service found" do
- cmd = 'launchctl unload -w '+ plist
+ cmd = "launchctl unload -w " + plist
expect(provider).to receive(:shell_out_with_systems_locale).
- with(/(#{su_cmd} .#{cmd}.|#{cmd})/).
- and_return(0)
+ with(/(#{su_cmd} .#{cmd}.|#{cmd})/).
+ and_return(0)
provider.stop_service
end
@@ -322,7 +322,7 @@ SVC_LIST
it "stops and then starts service" do
expect(provider).to receive(:unload_service)
- expect(provider).to receive(:load_service);
+ expect(provider).to receive(:load_service)
provider.restart_service
end
diff --git a/spec/unit/provider/service/openbsd_service_spec.rb b/spec/unit/provider/service/openbsd_service_spec.rb
index d3c150a14b..872a3bc400 100644
--- a/spec/unit/provider/service/openbsd_service_spec.rb
+++ b/spec/unit/provider/service/openbsd_service_spec.rb
@@ -1,8 +1,8 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
# Author:: Scott Bonds (scott@ggr.com)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
-# Copyright:: Copyright (c) 2014 Scott Bonds
+# Copyright:: Copyright 2009-2016, Bryan McLellan
+# Copyright:: Copyright 2014-2016, Scott Bonds
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
class Chef::Provider::Service::Openbsd
public :builtin_service_enable_variable_name
@@ -31,11 +31,11 @@ end
describe Chef::Provider::Service::Openbsd do
let(:node) do
node = Chef::Node.new
- node.automatic_attrs[:command] = {:ps => "ps -ax"}
+ node.automatic_attrs[:command] = { :ps => "ps -ax" }
node
end
- let(:supports) { {:status => false} }
+ let(:supports) { { :status => false } }
let(:new_resource) do
new_resource = Chef::Resource::Service.new("sndiod")
@@ -52,9 +52,9 @@ describe Chef::Provider::Service::Openbsd do
let(:provider) do
events = Chef::EventDispatch::Dispatcher.new
run_context = Chef::RunContext.new(node, {}, events)
- allow(::File).to receive(:read).with('/etc/rc.conf').and_return('')
- allow(::File).to receive(:read).with('/etc/rc.conf.local').and_return('')
- provider = Chef::Provider::Service::Openbsd.new(new_resource,run_context)
+ allow(::File).to receive(:read).with("/etc/rc.conf").and_return("")
+ allow(::File).to receive(:read).with("/etc/rc.conf.local").and_return("")
+ provider = Chef::Provider::Service::Openbsd.new(new_resource, run_context)
provider.action = :start
provider
end
@@ -80,7 +80,7 @@ describe Chef::Provider::Service::Openbsd do
end
it "should set init_command to nil if it can't find anything" do
- expect(::File).to receive(:exist?).with('/etc/rc.d/sndiod').and_return(false)
+ expect(::File).to receive(:exist?).with("/etc/rc.d/sndiod").and_return(false)
expect(provider.init_command).to be nil
end
end
@@ -174,10 +174,11 @@ describe Chef::Provider::Service::Openbsd do
end
context "when the enable variable partial matches (left) some other service and we are disabled" do
- let(:lines) { [
+ let(:lines) do
+ [
%Q{thing_#{provider.builtin_service_enable_variable_name}="YES"},
%Q{#{provider.builtin_service_enable_variable_name}="NO"},
- ] }
+ ] end
it "sets enabled based on the exact match (false)" do
provider.determine_enabled_status!
expect(current_resource.enabled).to be false
@@ -185,10 +186,11 @@ describe Chef::Provider::Service::Openbsd do
end
context "when the enable variable partial matches (right) some other service and we are disabled" do
- let(:lines) { [
+ let(:lines) do
+ [
%Q{#{provider.builtin_service_enable_variable_name}_thing="YES"},
%Q{#{provider.builtin_service_enable_variable_name}},
- ] }
+ ] end
it "sets enabled based on the exact match (false)" do
provider.determine_enabled_status!
expect(current_resource.enabled).to be false
@@ -196,10 +198,11 @@ describe Chef::Provider::Service::Openbsd do
end
context "when the enable variable partial matches (left) some other disabled service and we are enabled" do
- let(:lines) { [
+ let(:lines) do
+ [
%Q{thing_#{provider.builtin_service_enable_variable_name}="NO"},
%Q{#{provider.builtin_service_enable_variable_name}="YES"},
- ] }
+ ] end
it "sets enabled based on the exact match (true)" do
provider.determine_enabled_status!
expect(current_resource.enabled).to be true
@@ -207,10 +210,11 @@ describe Chef::Provider::Service::Openbsd do
end
context "when the enable variable partial matches (right) some other disabled service and we are enabled" do
- let(:lines) { [
+ let(:lines) do
+ [
%Q{#{provider.builtin_service_enable_variable_name}_thing="NO"},
%Q{#{provider.builtin_service_enable_variable_name}="YES"},
- ] }
+ ] end
it "sets enabled based on the exact match (true)" do
provider.determine_enabled_status!
expect(current_resource.enabled).to be true
@@ -250,7 +254,7 @@ describe Chef::Provider::Service::Openbsd do
current_resource.running(false)
allow(provider).to receive(:service_enable_variable_name).and_return "#{new_resource.service_name}_enable"
expect(::File).to receive(:open).with("/etc/rc.d/#{new_resource.service_name}")
- end
+ end
it "should create a current resource with the name of the new resource" do
expect(Chef::Resource::Service).to receive(:new).and_return(current_resource)
@@ -338,7 +342,7 @@ describe Chef::Provider::Service::Openbsd do
allow(provider).to receive(:builtin_service_enable_variable_name).and_return("#{new_resource.service_name}_enable")
end
- [ "start", "reload", "restart", "enable" ].each do |action|
+ %w{start reload restart enable}.each do |action|
it "should raise an exception when the action is #{action}" do
provider.define_resource_requirements
provider.action = action
@@ -346,7 +350,7 @@ describe Chef::Provider::Service::Openbsd do
end
end
- [ "stop", "disable" ].each do |action|
+ %w{stop disable}.each do |action|
it "should not raise an error when the action is #{action}" do
provider.define_resource_requirements
provider.action = action
@@ -360,7 +364,7 @@ describe Chef::Provider::Service::Openbsd do
allow(provider).to receive(:builtin_service_enable_variable_name).and_return(nil)
end
- [ "start", "reload", "restart", "enable" ].each do |action|
+ %w{start reload restart enable}.each do |action|
it "should raise an exception when the action is #{action}" do
provider.action = action
provider.define_resource_requirements
@@ -368,7 +372,7 @@ describe Chef::Provider::Service::Openbsd do
end
end
- [ "stop", "disable" ].each do |action|
+ %w{stop disable}.each do |action|
it "should not raise an error when the action is #{action}" do
provider.action = action
provider.define_resource_requirements
@@ -381,7 +385,7 @@ describe Chef::Provider::Service::Openbsd do
describe Chef::Provider::Service::Openbsd, "enable_service" do
before do
provider.current_resource = current_resource
- allow(FileUtils).to receive(:touch).with('/etc/rc.conf.local')
+ allow(FileUtils).to receive(:touch).with("/etc/rc.conf.local")
end
context "is builtin and disabled by default" do
before do
@@ -398,10 +402,10 @@ describe Chef::Provider::Service::Openbsd do
end
context "is disabled" do
before do
- provider.rc_conf_local = ''
+ provider.rc_conf_local = ""
end
it "should enable the service by adding a line to rc.conf.local" do
- expect(::File).to receive(:write).with('/etc/rc.conf.local', include("#{provider.builtin_service_enable_variable_name}=\"\""))
+ expect(::File).to receive(:write).with("/etc/rc.conf.local", include("#{provider.builtin_service_enable_variable_name}=\"\""))
expect(provider.is_enabled?).to be false
provider.enable_service
expect(provider.is_enabled?).to be true
@@ -414,7 +418,7 @@ describe Chef::Provider::Service::Openbsd do
end
context "is enabled" do
before do
- provider.rc_conf_local = ''
+ provider.rc_conf_local = ""
end
it "should not change rc.conf.local since it is already enabled" do
expect(::File).not_to receive(:write)
@@ -426,7 +430,7 @@ describe Chef::Provider::Service::Openbsd do
provider.rc_conf_local = "#{provider.builtin_service_enable_variable_name}=NO"
end
it "should enable the service by removing a line from rc.conf.local" do
- expect(::File).to receive(:write).with('/etc/rc.conf.local', /^(?!#{provider.builtin_service_enable_variable_name})$/)
+ expect(::File).to receive(:write).with("/etc/rc.conf.local", /^(?!#{provider.builtin_service_enable_variable_name})$/)
expect(provider.is_enabled?).to be false
provider.enable_service
expect(provider.is_enabled?).to be true
@@ -435,7 +439,7 @@ describe Chef::Provider::Service::Openbsd do
end
context "is not builtin" do
before do
- provider.rc_conf = ''
+ provider.rc_conf = ""
end
context "is enabled" do
before do
@@ -448,10 +452,10 @@ describe Chef::Provider::Service::Openbsd do
end
context "is disabled" do
before do
- provider.rc_conf_local = ''
+ provider.rc_conf_local = ""
end
it "should enable the service by adding it to the pkg_scripts list" do
- expect(::File).to receive(:write).with('/etc/rc.conf.local', "\npkg_scripts=\"#{new_resource.service_name}\"\n")
+ expect(::File).to receive(:write).with("/etc/rc.conf.local", "\npkg_scripts=\"#{new_resource.service_name}\"\n")
expect(provider.is_enabled?).to be false
provider.enable_service
expect(provider.is_enabled?).to be true
@@ -463,7 +467,7 @@ describe Chef::Provider::Service::Openbsd do
describe Chef::Provider::Service::Openbsd, "disable_service" do
before do
provider.current_resource = current_resource
- allow(FileUtils).to receive(:touch).with('/etc/rc.conf.local')
+ allow(FileUtils).to receive(:touch).with("/etc/rc.conf.local")
end
context "is builtin and disabled by default" do
before do
@@ -474,7 +478,7 @@ describe Chef::Provider::Service::Openbsd do
provider.rc_conf_local = "#{provider.builtin_service_enable_variable_name}=\"\""
end
it "should disable the service by removing its line from rc.conf.local" do
- expect(::File).to receive(:write).with('/etc/rc.conf.local', /^(?!#{provider.builtin_service_enable_variable_name})$/)
+ expect(::File).to receive(:write).with("/etc/rc.conf.local", /^(?!#{provider.builtin_service_enable_variable_name})$/)
expect(provider.is_enabled?).to be true
provider.disable_service
expect(provider.is_enabled?).to be false
@@ -482,7 +486,7 @@ describe Chef::Provider::Service::Openbsd do
end
context "is disabled" do
before do
- provider.rc_conf_local = ''
+ provider.rc_conf_local = ""
end
it "should not change rc.conf.local since it is already disabled" do
expect(::File).not_to receive(:write)
@@ -496,10 +500,10 @@ describe Chef::Provider::Service::Openbsd do
end
context "is enabled" do
before do
- provider.rc_conf_local = ''
+ provider.rc_conf_local = ""
end
it "should disable the service by adding a line to rc.conf.local" do
- expect(::File).to receive(:write).with('/etc/rc.conf.local', include("#{provider.builtin_service_enable_variable_name}=\"NO\""))
+ expect(::File).to receive(:write).with("/etc/rc.conf.local", include("#{provider.builtin_service_enable_variable_name}=\"NO\""))
expect(provider.is_enabled?).to be true
provider.disable_service
expect(provider.is_enabled?).to be false
@@ -517,14 +521,14 @@ describe Chef::Provider::Service::Openbsd do
end
context "is not builtin" do
before do
- provider.rc_conf = ''
+ provider.rc_conf = ""
end
context "is enabled" do
before do
provider.rc_conf_local = "pkg_scripts=\"#{new_resource.service_name}\"\n"
end
it "should disable the service by removing it from the pkg_scripts list" do
- expect(::File).to receive(:write).with('/etc/rc.conf.local', /^(?!#{new_resource.service_name})$/)
+ expect(::File).to receive(:write).with("/etc/rc.conf.local", /^(?!#{new_resource.service_name})$/)
expect(provider.is_enabled?).to be true
provider.disable_service
expect(provider.is_enabled?).to be false
@@ -532,7 +536,7 @@ describe Chef::Provider::Service::Openbsd do
end
context "is disabled" do
before do
- provider.rc_conf_local = ''
+ provider.rc_conf_local = ""
end
it "should not change rc.conf.local since it is already disabled" do
expect(::File).not_to receive(:write)
diff --git a/spec/unit/provider/service/redhat_spec.rb b/spec/unit/provider/service/redhat_spec.rb
index 5aaf54d9f5..40f9bc3a91 100644
--- a/spec/unit/provider/service/redhat_spec.rb
+++ b/spec/unit/provider/service/redhat_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 HJK Solutions, LLC
+# Copyright:: Copyright 2008-2016, HJK Solutions, LLC
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,13 +17,13 @@
#
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper"))
-require 'ostruct'
+require "ostruct"
shared_examples_for "define_resource_requirements_common" do
it "should raise an error if /sbin/chkconfig does not exist" do
allow(File).to receive(:exists?).with("/sbin/chkconfig").and_return(false)
allow(@provider).to receive(:shell_out).with("/sbin/service chef status").and_raise(Errno::ENOENT)
- allow(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_raise(Errno::ENOENT)
+ allow(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_raise(Errno::ENOENT)
@provider.load_current_resource
@provider.define_resource_requirements
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
@@ -33,7 +33,7 @@ shared_examples_for "define_resource_requirements_common" do
status = double("Status", :exitstatus => 0, :stdout => "" , :stderr => "")
expect(@provider).to receive(:shell_out).with("/sbin/service chef status").and_return(status)
chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "", :stderr => "service chef supports chkconfig, but is not referenced in any runlevel (run 'chkconfig --add chef')")
- expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+ expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
@provider.load_current_resource
@provider.define_resource_requirements
expect { @provider.process_resource_requirements }.not_to raise_error
@@ -44,7 +44,7 @@ describe "Chef::Provider::Service::Redhat" do
before(:each) do
@node = Chef::Node.new
- @node.automatic_attrs[:command] = {:ps => 'foo'}
+ @node.automatic_attrs[:command] = { :ps => "foo" }
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@@ -71,7 +71,7 @@ describe "Chef::Provider::Service::Redhat" do
it "sets supports[:status] to true by default" do
chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef 0:off 1:off 2:off 3:off 4:off 5:on 6:off", :stderr => "")
- expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+ expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
expect(@provider.service_missing).to be false
@provider.load_current_resource
expect(@provider.supports[:status]).to be true
@@ -81,7 +81,7 @@ describe "Chef::Provider::Service::Redhat" do
@new_resource.supports( { status: false } )
@new_resource.pattern "myservice"
chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef 0:off 1:off 2:off 3:off 4:off 5:on 6:off", :stderr => "")
- expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+ expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
foo_out = double("ps_command", :exitstatus => 0, :stdout => "a line that matches myservice", :stderr => "")
expect(@provider).to receive(:shell_out!).with("foo").and_return(foo_out)
expect(@provider.service_missing).to be false
@@ -92,7 +92,7 @@ describe "Chef::Provider::Service::Redhat" do
it "sets the current enabled status to true if the service is enabled for any run level" do
chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef 0:off 1:off 2:off 3:off 4:off 5:on 6:off", :stderr => "")
- expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+ expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
expect(@provider.service_missing).to be false
@provider.load_current_resource
expect(@current_resource.enabled).to be true
@@ -100,7 +100,7 @@ describe "Chef::Provider::Service::Redhat" do
it "sets the current enabled status to false if the regex does not match" do
chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef 0:off 1:off 2:off 3:off 4:off 5:off 6:off", :stderr => "")
- expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+ expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
expect(@provider.service_missing).to be false
expect(@provider.load_current_resource).to eql(@current_resource)
expect(@current_resource.enabled).to be false
@@ -109,7 +109,7 @@ describe "Chef::Provider::Service::Redhat" do
it "sets the current enabled status to true if the service is enabled at specified run levels" do
@new_resource.run_levels([1, 2])
chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef 0:off 1:on 2:on 3:off 4:off 5:off 6:off", :stderr => "")
- expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+ expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
expect(@provider.service_missing).to be false
@provider.load_current_resource
expect(@current_resource.enabled).to be true
@@ -119,7 +119,7 @@ describe "Chef::Provider::Service::Redhat" do
it "sets the current enabled status to false if the service is enabled at a run level it should not" do
@new_resource.run_levels([1, 2])
chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef 0:off 1:on 2:on 3:on 4:off 5:off 6:off", :stderr => "")
- expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+ expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
expect(@provider.service_missing).to be false
@provider.load_current_resource
expect(@current_resource.enabled).to be false
@@ -129,7 +129,7 @@ describe "Chef::Provider::Service::Redhat" do
it "sets the current enabled status to false if the service is not enabled at specified run levels" do
@new_resource.run_levels([ 2 ])
chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef 0:off 1:on 2:off 3:off 4:off 5:off 6:off", :stderr => "")
- expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+ expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
expect(@provider.service_missing).to be false
@provider.load_current_resource
expect(@current_resource.enabled).to be false
@@ -144,20 +144,34 @@ describe "Chef::Provider::Service::Redhat" do
before do
status = double("Status", :exitstatus => 1, :stdout => "", :stderr => "chef: unrecognized service")
expect(@provider).to receive(:shell_out).with("/sbin/service chef status").and_return(status)
- chkconfig = double("Chkconfig", :existatus=> 1, :stdout => "", :stderr => "error reading information on service chef: No such file or directory")
- expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+ chkconfig = double("Chkconfig", :existatus => 1, :stdout => "", :stderr => "error reading information on service chef: No such file or directory")
+ expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
@provider.load_current_resource
@provider.define_resource_requirements
end
- [ "start", "reload", "restart", "enable" ].each do |action|
+ %w{start reload restart enable}.each do |action|
it "should raise an error when the action is #{action}" do
@provider.action = action
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
end
end
- [ "stop", "disable" ].each do |action|
+ %w{start reload restart}.each do |action|
+ it "should not raise an error when the action is #{action} and init_command is set" do
+ @new_resource.init_command("/etc/init.d/chef")
+ @provider.action = action
+ expect { @provider.process_resource_requirements }.not_to raise_error
+ end
+
+ it "should not raise an error when the action is #{action} and #{action}_command is set" do
+ @new_resource.send("#{action}_command", "/etc/init.d/chef #{action}")
+ @provider.action = action
+ expect { @provider.process_resource_requirements }.not_to raise_error
+ end
+ end
+
+ %w{stop disable}.each do |action|
it "should not raise an error when the action is #{action}" do
@provider.action = action
expect { @provider.process_resource_requirements }.not_to raise_error
@@ -182,8 +196,8 @@ describe "Chef::Provider::Service::Redhat" do
it "should not raise an error if the service does not exist" do
status = double("Status", :exitstatus => 1, :stdout => "", :stderr => "chef: unrecognized service")
expect(@provider).to receive(:shell_out).with("/sbin/service chef status").and_return(status)
- chkconfig = double("Chkconfig", :existatus=> 1, :stdout => "", :stderr => "error reading information on service chef: No such file or directory")
- expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+ chkconfig = double("Chkconfig", :existatus => 1, :stdout => "", :stderr => "error reading information on service chef: No such file or directory")
+ expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
@provider.load_current_resource
@provider.define_resource_requirements
expect { @provider.process_resource_requirements }.not_to raise_error
diff --git a/spec/unit/provider/service/simple_service_spec.rb b/spec/unit/provider/service/simple_service_spec.rb
index 895c559dff..499e0cc2d3 100644
--- a/spec/unit/provider/service/simple_service_spec.rb
+++ b/spec/unit/provider/service/simple_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Mathieu Sauve-Frankel <msf@kisoku.net>
-# Copyright:: Copyright (c) 2009, Mathieu Sauve Frankel
+# Copyright:: Copyright 2009-2016, Mathieu Sauve Frankel
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service::Simple, "load_current_resource" do
before(:each) do
@node = Chef::Node.new
- @node.automatic_attrs[:command] = {:ps => "ps -ef"}
+ @node.automatic_attrs[:command] = { :ps => "ps -ef" }
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@@ -51,13 +51,13 @@ NOMOCKINGSTRINGSPLZ
end
it "should raise error if the node has a nil ps attribute and no other means to get status" do
- @node.automatic_attrs[:command] = {:ps => nil}
+ @node.automatic_attrs[:command] = { :ps => nil }
@provider.define_resource_requirements
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
end
it "should raise error if the node has an empty ps attribute and no other means to get status" do
- @node.automatic_attrs[:command] = {:ps => ""}
+ @node.automatic_attrs[:command] = { :ps => "" }
@provider.define_resource_requirements
expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
end
diff --git a/spec/unit/provider/service/solaris_smf_service_spec.rb b/spec/unit/provider/service/solaris_smf_service_spec.rb
index 62c3ac6c6e..c6835bed64 100644
--- a/spec/unit/provider/service/solaris_smf_service_spec.rb
+++ b/spec/unit/provider/service/solaris_smf_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Toomas Pelberg (<toomasp@gmx.net>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,77 +16,77 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service::Solaris do
before(:each) do
- @node =Chef::Node.new
+ @node = Chef::Node.new
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Service.new('chef')
+ @new_resource = Chef::Resource::Service.new("chef")
- @current_resource = Chef::Resource::Service.new('chef')
+ @current_resource = Chef::Resource::Service.new("chef")
@provider = Chef::Provider::Service::Solaris.new(@new_resource, @run_context)
allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
# enabled / started service (svcs -l chef)
enabled_svc_stdout = [
- 'fmri svc:/application/chef:default',
- 'name chef service',
- 'enabled true',
- 'state online',
- 'next_state none',
- 'state_time April 2, 2015 04:25:19 PM EDT',
- 'logfile /var/svc/log/application-chef:default.log',
- 'restarter svc:/system/svc/restarter:default',
- 'contract_id 1115271',
- 'dependency require_all/error svc:/milestone/multi-user:default (online)'
+ "fmri svc:/application/chef:default",
+ "name chef service",
+ "enabled true",
+ "state online",
+ "next_state none",
+ "state_time April 2, 2015 04:25:19 PM EDT",
+ "logfile /var/svc/log/application-chef:default.log",
+ "restarter svc:/system/svc/restarter:default",
+ "contract_id 1115271",
+ "dependency require_all/error svc:/milestone/multi-user:default (online)",
].join("\n")
# disabled / stopped service (svcs -l chef)
disabled_svc_stdout = [
- 'fmri svc:/application/chef:default',
- 'name chef service',
- 'enabled false',
- 'state disabled',
- 'next_state none',
- 'state_time April 2, 2015 04:25:19 PM EDT',
- 'logfile /var/svc/log/application-chef:default.log',
- 'restarter svc:/system/svc/restarter:default',
- 'contract_id 1115271',
- 'dependency require_all/error svc:/milestone/multi-user:default (online)'
+ "fmri svc:/application/chef:default",
+ "name chef service",
+ "enabled false",
+ "state disabled",
+ "next_state none",
+ "state_time April 2, 2015 04:25:19 PM EDT",
+ "logfile /var/svc/log/application-chef:default.log",
+ "restarter svc:/system/svc/restarter:default",
+ "contract_id 1115271",
+ "dependency require_all/error svc:/milestone/multi-user:default (online)",
].join("\n")
# disabled / stopped service (svcs -l chef)
maintenance_svc_stdout = [
- 'fmri svc:/application/chef:default',
- 'name chef service',
- 'enabled true',
- 'state maintenance',
- 'next_state none',
- 'state_time April 2, 2015 04:25:19 PM EDT',
- 'logfile /var/svc/log/application-chef:default.log',
- 'restarter svc:/system/svc/restarter:default',
- 'contract_id 1115271',
- 'dependency require_all/error svc:/milestone/multi-user:default (online)'
+ "fmri svc:/application/chef:default",
+ "name chef service",
+ "enabled true",
+ "state maintenance",
+ "next_state none",
+ "state_time April 2, 2015 04:25:19 PM EDT",
+ "logfile /var/svc/log/application-chef:default.log",
+ "restarter svc:/system/svc/restarter:default",
+ "contract_id 1115271",
+ "dependency require_all/error svc:/milestone/multi-user:default (online)",
].join("\n")
# shell_out! return value for a service that is running
- @enabled_svc_status = double("Status", :exitstatus => 0, :stdout => enabled_svc_stdout, :stdin => '', :stderr => '')
+ @enabled_svc_status = double("Status", :exitstatus => 0, :stdout => enabled_svc_stdout, :stdin => "", :stderr => "")
# shell_out! return value for a service that is disabled
- @disabled_svc_status = double("Status", :exitstatus => 0, :stdout => disabled_svc_stdout, :stdin => '', :stderr => '')
+ @disabled_svc_status = double("Status", :exitstatus => 0, :stdout => disabled_svc_stdout, :stdin => "", :stderr => "")
# shell_out! return value for a service that is in maintenance mode
- @maintenance_svc_status = double("Status", :exitstatus => 0, :stdout => maintenance_svc_stdout, :stdin => '', :stderr => '')
+ @maintenance_svc_status = double("Status", :exitstatus => 0, :stdout => maintenance_svc_stdout, :stdin => "", :stderr => "")
# shell_out! return value for a service that does not exist
- @no_svc_status = double("Status", :exitstatus => 1, :stdout => '', :stdin => '', :stderr => "svcs: Pattern 'chef' doesn't match any instances\n")
+ @no_svc_status = double("Status", :exitstatus => 1, :stdout => "", :stdin => "", :stderr => "svcs: Pattern 'chef' doesn't match any instances\n")
# shell_out! return value for a successful execution
- @success = double("clear", :exitstatus => 0, :stdout => '', :stdin => '', :stderr => '')
+ @success = double("clear", :exitstatus => 0, :stdout => "", :stdin => "", :stderr => "")
end
it "should raise an error if /bin/svcs and /usr/sbin/svcadm are not executable" do
@@ -116,18 +116,18 @@ describe Chef::Provider::Service::Solaris do
describe "when discovering the current service state" do
it "should create a current resource with the name of the new resource" do
- expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", {:returns=>[0, 1]}).and_return(@enabled_svc_status)
+ expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
expect(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
@provider.load_current_resource
end
it "should return the current resource" do
- expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", {:returns=>[0, 1]}).and_return(@enabled_svc_status)
+ expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
expect(@provider.load_current_resource).to eql(@current_resource)
end
it "should call '/bin/svcs -l service_name'" do
- expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", {:returns=>[0, 1]}).and_return(@enabled_svc_status)
+ expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
@provider.load_current_resource
end
@@ -162,7 +162,7 @@ describe Chef::Provider::Service::Solaris do
end
it "should call svcadm enable -s chef" do
- expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", {:returns=>[0, 1]}).and_return(@enabled_svc_status)
+ expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
expect(@provider).not_to receive(:shell_out!).with("/usr/sbin/svcadm", "clear", @current_resource.service_name)
expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "enable", "-s", @current_resource.service_name).and_return(@success)
@provider.load_current_resource
@@ -172,7 +172,7 @@ describe Chef::Provider::Service::Solaris do
end
it "should call svcadm enable -s chef for start_service" do
- expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", {:returns=>[0, 1]}).and_return(@enabled_svc_status)
+ expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
expect(@provider).not_to receive(:shell_out!).with("/usr/sbin/svcadm", "clear", @current_resource.service_name)
expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "enable", "-s", @current_resource.service_name).and_return(@success)
@provider.load_current_resource
@@ -182,7 +182,7 @@ describe Chef::Provider::Service::Solaris do
it "should call svcadm clear chef for start_service when state maintenance" do
# we are in maint mode
- expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", {:returns=>[0, 1]}).and_return(@maintenance_svc_status)
+ expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@maintenance_svc_status)
expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "clear", @current_resource.service_name).and_return(@success)
expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "enable", "-s", @current_resource.service_name).and_return(@success)
@@ -191,7 +191,7 @@ describe Chef::Provider::Service::Solaris do
expect(@provider.enable_service).to be_truthy
# now we are enabled
- expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", {:returns=>[0, 1]}).and_return(@enabled_svc_status)
+ expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
@provider.load_current_resource
expect(@current_resource.enabled).to be_truthy
@@ -204,7 +204,7 @@ describe Chef::Provider::Service::Solaris do
end
it "should call svcadm disable -s chef" do
- expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", {:returns=>[0, 1]}).and_return(@disabled_svc_status)
+ expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@disabled_svc_status)
expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "disable", "-s", "chef").and_return(@success)
@provider.load_current_resource
expect(@provider.disable_service).to be_truthy
@@ -212,7 +212,7 @@ describe Chef::Provider::Service::Solaris do
end
it "should call svcadm disable -s chef for stop_service" do
- expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", {:returns=>[0, 1]}).and_return(@disabled_svc_status)
+ expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@disabled_svc_status)
expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "disable", "-s", "chef").and_return(@success)
@provider.load_current_resource
expect(@provider.stop_service).to be_truthy
@@ -224,7 +224,7 @@ describe Chef::Provider::Service::Solaris do
describe "when reloading the service" do
before(:each) do
@provider.current_resource = @current_resource
- allow(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", {:returns=>[0, 1]}).and_return(@enabled_svc_status)
+ allow(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
end
it "should call svcadm refresh chef" do
@@ -237,7 +237,7 @@ describe Chef::Provider::Service::Solaris do
describe "when the service doesn't exist" do
before(:each) do
@provider.current_resource = @current_resource
- expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", {:returns=>[0, 1]}).and_return(@no_svc_status)
+ expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@no_svc_status)
end
it "should be marked not running" do
diff --git a/spec/unit/provider/service/systemd_service_spec.rb b/spec/unit/provider/service/systemd_service_spec.rb
index 90b669a459..4e25f499f6 100644
--- a/spec/unit/provider/service/systemd_service_spec.rb
+++ b/spec/unit/provider/service/systemd_service_spec.rb
@@ -1,6 +1,7 @@
#
# Author:: Stephen Haynes (<sh@nomitor.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Davide Cavalca (<dcavalca@fb.com>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +17,20 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service::Systemd do
- let(:node) { Chef::Node.new }
+ let(:node) do
+ node = Chef::Node.new
+ node.default["etc"] = Hash.new
+ node.default["etc"]["passwd"] = {
+ "joe" => {
+ "uid" => 10000,
+ },
+ }
+ node
+ end
let(:events) { Chef::EventDispatch::Dispatcher.new }
@@ -33,11 +43,11 @@ describe Chef::Provider::Service::Systemd do
let(:provider) { Chef::Provider::Service::Systemd.new(new_resource, run_context) }
let(:shell_out_success) do
- double('shell_out_with_systems_locale', :exitstatus => 0, :error? => false)
+ double("shell_out_with_systems_locale", :exitstatus => 0, :error? => false)
end
let(:shell_out_failure) do
- double('shell_out_with_systems_locale', :exitstatus => 1, :error? => true)
+ double("shell_out_with_systems_locale", :exitstatus => 1, :error? => true)
end
let(:current_resource) { Chef::Resource::Service.new(service_name) }
@@ -51,6 +61,7 @@ describe Chef::Provider::Service::Systemd do
before(:each) do
allow(provider).to receive(:is_active?).and_return(false)
allow(provider).to receive(:is_enabled?).and_return(false)
+ allow(provider).to receive(:is_masked?).and_return(false)
end
it "should create a current resource with the name of the new resource" do
@@ -127,6 +138,23 @@ describe Chef::Provider::Service::Systemd do
expect(current_resource.enabled).to be false
end
+ it "should check if the service is masked" do
+ expect(provider).to receive(:is_masked?)
+ provider.load_current_resource
+ end
+
+ it "should set masked to true if the service is masked" do
+ allow(provider).to receive(:is_masked?).and_return(true)
+ provider.load_current_resource
+ expect(current_resource.masked).to be true
+ end
+
+ it "should set masked to false if the service is not masked" do
+ allow(provider).to receive(:is_masked?).and_return(false)
+ provider.load_current_resource
+ expect(current_resource.masked).to be false
+ end
+
it "should return the current resource" do
expect(provider.load_current_resource).to eql(current_resource)
end
@@ -152,15 +180,32 @@ describe Chef::Provider::Service::Systemd do
provider.start_service
end
- it "should call '#{systemctl_path} start service_name' if no start command is specified" do
- expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} start #{service_name}").and_return(shell_out_success)
- provider.start_service
+ context "when a user is not specified" do
+ it "should call '#{systemctl_path} --system start service_name' if no start command is specified" do
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} --system start #{service_name}", {}).and_return(shell_out_success)
+ provider.start_service
+ end
+
+ it "should not call '#{systemctl_path} --system start service_name' if it is already running" do
+ current_resource.running(true)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} --system start #{service_name}", {})
+ provider.start_service
+ end
end
- it "should not call '#{systemctl_path} start service_name' if it is already running" do
- current_resource.running(true)
- expect(provider).not_to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} start #{service_name}")
- provider.start_service
+ context "when a user is specified" do
+ it "should call '#{systemctl_path} --user start service_name' if no start command is specified" do
+ current_resource.user("joe")
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} --user start #{service_name}", { :environment => { "DBUS_SESSION_BUS_ADDRESS" => "unix:path=/run/user/10000/bus" }, :user => "joe" }).and_return(shell_out_success)
+ provider.start_service
+ end
+
+ it "should not call '#{systemctl_path} --user start service_name' if it is already running" do
+ current_resource.running(true)
+ current_resource.user("joe")
+ expect(provider).not_to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} --user start #{service_name}", { :environment => { "DBUS_SESSION_BUS_ADDRESS" => "unix:path=/run/user/10000/bus" }, :user => "joe" })
+ provider.start_service
+ end
end
it "should call the restart command if one is specified" do
@@ -170,9 +215,9 @@ describe Chef::Provider::Service::Systemd do
provider.restart_service
end
- it "should call '#{systemctl_path} restart service_name' if no restart command is specified" do
+ it "should call '#{systemctl_path} --system restart service_name' if no restart command is specified" do
current_resource.running(true)
- expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} restart #{service_name}").and_return(shell_out_success)
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} --system restart #{service_name}", {}).and_return(shell_out_success)
provider.restart_service
end
@@ -187,9 +232,9 @@ describe Chef::Provider::Service::Systemd do
end
context "when a reload command is not specified" do
- it "should call '#{systemctl_path} reload service_name' if the service is running" do
+ it "should call '#{systemctl_path} --system reload service_name' if the service is running" do
current_resource.running(true)
- expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} reload #{service_name}").and_return(shell_out_success)
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} --system reload #{service_name}", {}).and_return(shell_out_success)
provider.reload_service
end
@@ -208,15 +253,15 @@ describe Chef::Provider::Service::Systemd do
provider.stop_service
end
- it "should call '#{systemctl_path} stop service_name' if no stop command is specified" do
+ it "should call '#{systemctl_path} --system stop service_name' if no stop command is specified" do
current_resource.running(true)
- expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} stop #{service_name}").and_return(shell_out_success)
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} --system stop #{service_name}", {}).and_return(shell_out_success)
provider.stop_service
end
- it "should not call '#{systemctl_path} stop service_name' if it is already stopped" do
+ it "should not call '#{systemctl_path} --system stop service_name' if it is already stopped" do
current_resource.running(false)
- expect(provider).not_to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} stop #{service_name}")
+ expect(provider).not_to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} --system stop #{service_name}", {})
provider.stop_service
end
end
@@ -228,17 +273,35 @@ describe Chef::Provider::Service::Systemd do
allow(provider).to receive(:which).with("systemctl").and_return("#{systemctl_path}")
end
- it "should call '#{systemctl_path} enable service_name' to enable the service" do
- expect(provider).to receive(:shell_out!).with("#{systemctl_path} enable #{service_name}").and_return(shell_out_success)
+ it "should call '#{systemctl_path} --system enable service_name' to enable the service" do
+ expect(provider).to receive(:shell_out!).with("#{systemctl_path} --system enable #{service_name}", {}).and_return(shell_out_success)
provider.enable_service
end
- it "should call '#{systemctl_path} disable service_name' to disable the service" do
- expect(provider).to receive(:shell_out!).with("#{systemctl_path} disable #{service_name}").and_return(shell_out_success)
+ it "should call '#{systemctl_path} --system disable service_name' to disable the service" do
+ expect(provider).to receive(:shell_out!).with("#{systemctl_path} --system disable #{service_name}", {}).and_return(shell_out_success)
provider.disable_service
end
end
+ describe "mask and unmask service" do
+ before(:each) do
+ provider.current_resource = current_resource
+ current_resource.service_name(service_name)
+ allow(provider).to receive(:which).with("systemctl").and_return("#{systemctl_path}")
+ end
+
+ it "should call '#{systemctl_path} --system mask service_name' to mask the service" do
+ expect(provider).to receive(:shell_out!).with("#{systemctl_path} --system mask #{service_name}", {}).and_return(shell_out_success)
+ provider.mask_service
+ end
+
+ it "should call '#{systemctl_path} --system unmask service_name' to unmask the service" do
+ expect(provider).to receive(:shell_out!).with("#{systemctl_path} --system unmask #{service_name}", {}).and_return(shell_out_success)
+ provider.unmask_service
+ end
+ end
+
describe "is_active?" do
before(:each) do
provider.current_resource = current_resource
@@ -246,13 +309,13 @@ describe Chef::Provider::Service::Systemd do
allow(provider).to receive(:which).with("systemctl").and_return("#{systemctl_path}")
end
- it "should return true if '#{systemctl_path} is-active service_name' returns 0" do
- expect(provider).to receive(:shell_out).with("#{systemctl_path} is-active #{service_name} --quiet").and_return(shell_out_success)
+ it "should return true if '#{systemctl_path} --system is-active service_name' returns 0" do
+ expect(provider).to receive(:shell_out).with("#{systemctl_path} --system is-active #{service_name} --quiet", {}).and_return(shell_out_success)
expect(provider.is_active?).to be true
end
- it "should return false if '#{systemctl_path} is-active service_name' returns anything except 0" do
- expect(provider).to receive(:shell_out).with("#{systemctl_path} is-active #{service_name} --quiet").and_return(shell_out_failure)
+ it "should return false if '#{systemctl_path} --system is-active service_name' returns anything except 0" do
+ expect(provider).to receive(:shell_out).with("#{systemctl_path} --system is-active #{service_name} --quiet", {}).and_return(shell_out_failure)
expect(provider.is_active?).to be false
end
end
@@ -264,16 +327,44 @@ describe Chef::Provider::Service::Systemd do
allow(provider).to receive(:which).with("systemctl").and_return("#{systemctl_path}")
end
- it "should return true if '#{systemctl_path} is-enabled service_name' returns 0" do
- expect(provider).to receive(:shell_out).with("#{systemctl_path} is-enabled #{service_name} --quiet").and_return(shell_out_success)
+ it "should return true if '#{systemctl_path} --system is-enabled service_name' returns 0" do
+ expect(provider).to receive(:shell_out).with("#{systemctl_path} --system is-enabled #{service_name} --quiet", {}).and_return(shell_out_success)
expect(provider.is_enabled?).to be true
end
- it "should return false if '#{systemctl_path} is-enabled service_name' returns anything except 0" do
- expect(provider).to receive(:shell_out).with("#{systemctl_path} is-enabled #{service_name} --quiet").and_return(shell_out_failure)
+ it "should return false if '#{systemctl_path} --system is-enabled service_name' returns anything except 0" do
+ expect(provider).to receive(:shell_out).with("#{systemctl_path} --system is-enabled #{service_name} --quiet", {}).and_return(shell_out_failure)
expect(provider.is_enabled?).to be false
end
end
+
+ describe "is_masked?" do
+ before(:each) do
+ provider.current_resource = current_resource
+ current_resource.service_name(service_name)
+ allow(provider).to receive(:which).with("systemctl").and_return("#{systemctl_path}")
+ end
+
+ it "should return true if '#{systemctl_path} --system is-enabled service_name' returns 'masked' and returns anything except 0" do
+ expect(provider).to receive(:shell_out).with("#{systemctl_path} --system is-enabled #{service_name}", {}).and_return(double(:stdout => "masked", :exitstatus => shell_out_failure))
+ expect(provider.is_masked?).to be true
+ end
+
+ it "should return true if '#{systemctl_path} --system is-enabled service_name' outputs 'masked-runtime' and returns anything except 0" do
+ expect(provider).to receive(:shell_out).with("#{systemctl_path} --system is-enabled #{service_name}", {}).and_return(double(:stdout => "masked-runtime", :exitstatus => shell_out_failure))
+ expect(provider.is_masked?).to be true
+ end
+
+ it "should return false if '#{systemctl_path} --system is-enabled service_name' returns 0" do
+ expect(provider).to receive(:shell_out).with("#{systemctl_path} --system is-enabled #{service_name}", {}).and_return(double(:stdout => "enabled", :exitstatus => shell_out_success))
+ expect(provider.is_masked?).to be false
+ end
+
+ it "should return false if '#{systemctl_path} --system is-enabled service_name' returns anything except 0 and outputs an error'" do
+ expect(provider).to receive(:shell_out).with("#{systemctl_path} --system is-enabled #{service_name}", {}).and_return(double(:stdout => "Failed to get unit file state for #{service_name}: No such file or directory", :exitstatus => shell_out_failure))
+ expect(provider.is_masked?).to be false
+ end
+ end
end
end
end
diff --git a/spec/unit/provider/service/upstart_service_spec.rb b/spec/unit/provider/service/upstart_service_spec.rb
index 1c8e304cb7..0245dd038c 100644
--- a/spec/unit/provider/service/upstart_service_spec.rb
+++ b/spec/unit/provider/service/upstart_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
-# Copyright:: Copyright (c) 2010 Bryan McLellan
+# Copyright:: Copyright 2010-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,18 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service::Upstart do
let(:shell_out_success) do
- double('shell_out_with_systems_locale', :exitstatus => 0, :error? => false)
+ double("shell_out_with_systems_locale", :exitstatus => 0, :error? => false)
end
before(:each) do
- @node =Chef::Node.new
- @node.name('upstarter')
- @node.automatic_attrs[:platform] = 'ubuntu'
- @node.automatic_attrs[:platform_version] = '9.10'
+ @node = Chef::Node.new
+ @node.name("upstarter")
+ @node.automatic_attrs[:platform] = "ubuntu"
+ @node.automatic_attrs[:platform_version] = "9.10"
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@@ -42,7 +42,7 @@ describe Chef::Provider::Service::Upstart do
end
it "should return /etc/event.d as the upstart job directory when running on Ubuntu 9.04" do
- @node.automatic_attrs[:platform_version] = '9.04'
+ @node.automatic_attrs[:platform_version] = "9.04"
#Chef::Platform.stub(:find_platform_and_version).and_return([ "ubuntu", "9.04" ])
@provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context)
expect(@provider.instance_variable_get(:@upstart_job_dir)).to eq("/etc/event.d")
@@ -50,14 +50,14 @@ describe Chef::Provider::Service::Upstart do
end
it "should return /etc/init as the upstart job directory when running on Ubuntu 9.10" do
- @node.automatic_attrs[:platform_version] = '9.10'
+ @node.automatic_attrs[:platform_version] = "9.10"
@provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context)
expect(@provider.instance_variable_get(:@upstart_job_dir)).to eq("/etc/init")
expect(@provider.instance_variable_get(:@upstart_conf_suffix)).to eq(".conf")
end
it "should return /etc/init as the upstart job directory by default" do
- @node.automatic_attrs[:platform_version] = '9000'
+ @node.automatic_attrs[:platform_version] = "9000"
@provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context)
expect(@provider.instance_variable_get(:@upstart_job_dir)).to eq("/etc/init")
expect(@provider.instance_variable_get(:@upstart_conf_suffix)).to eq(".conf")
@@ -66,7 +66,7 @@ describe Chef::Provider::Service::Upstart do
describe "load_current_resource" do
before(:each) do
- @node.automatic_attrs[:command] = {:ps => "ps -ax"}
+ @node.automatic_attrs[:command] = { :ps => "ps -ax" }
@current_resource = Chef::Resource::Service.new("rsyslog")
allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
@@ -105,17 +105,21 @@ describe Chef::Provider::Service::Upstart do
end
describe "when the status command uses the new format" do
- before do
+ it "should set running to true if the goal state is 'start'" do
+ @stdout = StringIO.new("rsyslog start/running")
+ allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+ @provider.load_current_resource
+ expect(@current_resource.running).to be_truthy
end
- it "should set running to true if the status command returns 0" do
- @stdout = StringIO.new("rsyslog start/running")
+ it "should set running to true if the goal state is 'start' but current state is not 'running'" do
+ @stdout = StringIO.new("rsyslog start/starting")
allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
@provider.load_current_resource
expect(@current_resource.running).to be_truthy
end
- it "should set running to false if the status command returns anything except 0" do
+ it "should set running to false if the goal state is 'stop'" do
@stdout = StringIO.new("rsyslog stop/waiting")
allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
@provider.load_current_resource
@@ -123,15 +127,45 @@ describe Chef::Provider::Service::Upstart do
end
end
+ describe "when the status command uses the new format with an instance" do
+ it "should set running to true if the goal state is 'start'" do
+ @stdout = StringIO.new("rsyslog (test) start/running, process 100")
+ allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+ @provider.load_current_resource
+ expect(@current_resource.running).to be_truthy
+ end
+
+ it "should set running to true if the goal state is 'start' but current state is not 'running'" do
+ @stdout = StringIO.new("rsyslog (test) start/starting, process 100")
+ allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+ @provider.load_current_resource
+ expect(@current_resource.running).to be_truthy
+ end
+
+ it "should set running to false if the goal state is 'stop'" do
+ @stdout = StringIO.new("rsyslog (test) stop/waiting, process 100")
+ allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+ @provider.load_current_resource
+ expect(@current_resource.running).to be_falsey
+ end
+ end
+
describe "when the status command uses the old format" do
- it "should set running to true if the status command returns 0" do
+ it "should set running to true if the goal state is 'start'" do
@stdout = StringIO.new("rsyslog (start) running, process 32225")
allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
@provider.load_current_resource
expect(@current_resource.running).to be_truthy
end
- it "should set running to false if the status command returns anything except 0" do
+ it "should set running to true if the goal state is 'start' but current state is not 'running'" do
+ @stdout = StringIO.new("rsyslog (start) starting, process 32225")
+ allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+ @provider.load_current_resource
+ expect(@current_resource.running).to be_truthy
+ end
+
+ it "should set running to false if the goal state is 'stop'" do
@stdout = StringIO.new("rsyslog (stop) waiting")
allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
@provider.load_current_resource
@@ -195,8 +229,8 @@ describe Chef::Provider::Service::Upstart do
end
end
- it "should track state when we fail to obtain service status via upstart_state" do
- expect(@provider).to receive(:upstart_state).and_raise Chef::Exceptions::Exec
+ it "should track state when we fail to obtain service status via upstart_goal_state" do
+ expect(@provider).to receive(:upstart_goal_state).and_raise Chef::Exceptions::Exec
@provider.load_current_resource
expect(@provider.instance_variable_get("@command_success")).to eq(false)
end
@@ -209,7 +243,7 @@ describe Chef::Provider::Service::Upstart do
describe "enable and disable service" do
before(:each) do
- @current_resource = Chef::Resource::Service.new('rsyslog')
+ @current_resource = Chef::Resource::Service.new("rsyslog")
allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
@provider.current_resource = @current_resource
allow(Chef::Util::FileEdit).to receive(:new)
@@ -237,25 +271,27 @@ describe Chef::Provider::Service::Upstart do
describe "start and stop service" do
before(:each) do
- @current_resource = Chef::Resource::Service.new('rsyslog')
+ @current_resource = Chef::Resource::Service.new("rsyslog")
allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
@provider.current_resource = @current_resource
end
it "should call the start command if one is specified" do
+ @provider.upstart_service_running = false
allow(@new_resource).to receive(:start_command).and_return("/sbin/rsyslog startyousillysally")
expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog startyousillysally")
@provider.start_service()
end
it "should call '/sbin/start service_name' if no start command is specified" do
+ @provider.upstart_service_running = false
expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/start #{@new_resource.service_name}").and_return(shell_out_success)
@provider.start_service()
end
it "should not call '/sbin/start service_name' if it is already running" do
- allow(@current_resource).to receive(:running).and_return(true)
+ @provider.upstart_service_running = true
expect(@provider).not_to receive(:shell_out_with_systems_locale!)
@provider.start_service()
end
@@ -276,13 +312,16 @@ describe Chef::Provider::Service::Upstart do
@provider.restart_service()
end
- it "should call '/sbin/restart service_name' if no restart command is specified" do
- allow(@current_resource).to receive(:running).and_return(true)
- expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/restart #{@new_resource.service_name}").and_return(shell_out_success)
+ it "should call start/sleep/stop if no restart command is specified" do
+ @provider.upstart_service_running = true
+ expect(@provider).to receive(:stop_service)
+ expect(@provider).to receive(:sleep).with(1)
+ expect(@provider).to receive(:start_service)
@provider.restart_service()
end
it "should call '/sbin/start service_name' if restart_service is called for a stopped service" do
+ @provider.upstart_service_running = false
allow(@current_resource).to receive(:running).and_return(false)
expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/start #{@new_resource.service_name}").and_return(shell_out_success)
@provider.restart_service()
@@ -302,22 +341,24 @@ describe Chef::Provider::Service::Upstart do
end
it "should call the stop command if one is specified" do
- allow(@current_resource).to receive(:running).and_return(true)
+ @provider.upstart_service_running = true
allow(@new_resource).to receive(:stop_command).and_return("/sbin/rsyslog stopyousillysally")
expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog stopyousillysally")
@provider.stop_service()
end
it "should call '/sbin/stop service_name' if no stop command is specified" do
- allow(@current_resource).to receive(:running).and_return(true)
+ @provider.upstart_service_running = true
expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/stop #{@new_resource.service_name}").and_return(shell_out_success)
@provider.stop_service()
end
it "should not call '/sbin/stop service_name' if it is already stopped" do
+ @provider.upstart_service_running = false
allow(@current_resource).to receive(:running).and_return(false)
expect(@provider).not_to receive(:shell_out_with_systems_locale!).with("/sbin/stop #{@new_resource.service_name}")
@provider.stop_service()
+ expect(@upstart_service_running).to be_falsey
end
end
end
diff --git a/spec/unit/provider/service/windows_spec.rb b/spec/unit/provider/service/windows_spec.rb
index 4c9f5b3377..d4c451511d 100644
--- a/spec/unit/provider/service/windows_spec.rb
+++ b/spec/unit/provider/service/windows_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Nuo Yan <nuo@opscode.com>
-# Author:: Seth Chisamore <schisamo@opscode.com>
-# Copyright:: Copyright (c) 2010-2011 Opscode, Inc
+# Author:: Nuo Yan <nuo@chef.io>
+# Author:: Seth Chisamore <schisamo@chef.io>
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'mixlib/shellout'
+require "spec_helper"
+require "mixlib/shellout"
describe Chef::Provider::Service::Windows, "load_current_resource" do
include_context "Win32"
@@ -30,6 +30,7 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
prvdr.current_resource = Chef::Resource::WindowsService.new("current-chef")
prvdr
end
+ let(:service_right) { Chef::Provider::Service::Windows::SERVICE_RIGHT }
before(:all) do
Win32::Service = Class.new
@@ -46,17 +47,18 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
double("ConfigStruct", :start_type => "auto start"))
allow(Win32::Service).to receive(:exists?).and_return(true)
allow(Win32::Service).to receive(:configure).and_return(Win32::Service)
+ allow(Chef::ReservedNames::Win32::Security).to receive(:get_account_right).and_return([])
end
after(:each) do
- Win32::Service.send(:remove_const, 'AUTO_START') if defined?(Win32::Service::AUTO_START)
- Win32::Service.send(:remove_const, 'DEMAND_START') if defined?(Win32::Service::DEMAND_START)
- Win32::Service.send(:remove_const, 'DISABLED') if defined?(Win32::Service::DISABLED)
+ Win32::Service.send(:remove_const, "AUTO_START") if defined?(Win32::Service::AUTO_START)
+ Win32::Service.send(:remove_const, "DEMAND_START") if defined?(Win32::Service::DEMAND_START)
+ Win32::Service.send(:remove_const, "DISABLED") if defined?(Win32::Service::DISABLED)
end
it "sets the current resources service name to the new resources service name" do
provider.load_current_resource
- expect(provider.current_resource.service_name).to eq('chef')
+ expect(provider.current_resource.service_name).to eq("chef")
end
it "returns the current resource" do
@@ -149,21 +151,28 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
let(:old_run_as_user) { new_resource.run_as_user }
let(:old_run_as_password) { new_resource.run_as_password }
- before {
+ before do
new_resource.run_as_user(".\\wallace")
new_resource.run_as_password("Wensleydale")
- }
+ end
- after {
+ after do
new_resource.run_as_user(old_run_as_user)
new_resource.run_as_password(old_run_as_password)
- }
+ end
it "calls #grant_service_logon if the :run_as_user and :run_as_password attributes are present" do
expect(Win32::Service).to receive(:start)
expect(provider).to receive(:grant_service_logon).and_return(true)
provider.start_service
end
+
+ it "does not grant user SeServiceLogonRight if it already has it" do
+ expect(Win32::Service).to receive(:start)
+ expect(Chef::ReservedNames::Win32::Security).to receive(:get_account_right).with("wallace").and_return([service_right])
+ expect(Chef::ReservedNames::Win32::Security).not_to receive(:add_account_right).with("wallace", service_right)
+ provider.start_service
+ end
end
end
@@ -360,7 +369,7 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
end
describe Chef::Provider::Service::Windows, "action_configure_startup" do
- { :automatic => "auto start", :manual => "demand start", :disabled => "disabled" }.each do |type,win32|
+ { :automatic => "auto start", :manual => "demand start", :disabled => "disabled" }.each do |type, win32|
it "sets the startup type to #{type} if it is something else" do
new_resource.startup_type(type)
allow(provider).to receive(:current_start_type).and_return("fire")
@@ -400,54 +409,36 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
shared_context "testing private methods" do
- let(:private_methods) {
+ let(:private_methods) do
described_class.private_instance_methods
- }
+ end
- before {
+ before do
described_class.send(:public, *private_methods)
- }
+ end
- after {
+ after do
described_class.send(:private, *private_methods)
- }
+ end
end
describe "grant_service_logon" do
include_context "testing private methods"
let(:username) { "unit_test_user" }
- let(:success_string) { "The task has completed successfully.\r\nSee logfile etc." }
- let(:failure_string) { "Look on my works, ye Mighty, and despair!" }
- let(:command) {
- dbfile = provider.grant_dbfile_name(username)
- policyfile = provider.grant_policyfile_name(username)
- logfile = provider.grant_logfile_name(username)
-
- %Q{secedit.exe /configure /db "#{dbfile}" /cfg "#{policyfile}" /areas USER_RIGHTS SECURITYPOLICY SERVICES /log "#{logfile}"}
- }
- let(:shellout_env) { {:environment=>{"LC_ALL"=>"en_US.UTF-8"}} }
-
- before {
- expect_any_instance_of(described_class).to receive(:shell_out).with(command).and_call_original
- expect_any_instance_of(Mixlib::ShellOut).to receive(:run_command).and_return(nil)
- }
-
- after {
- # only needed for the second test.
- ::File.delete(provider.grant_policyfile_name(username)) rescue nil
- ::File.delete(provider.grant_logfile_name(username)) rescue nil
- ::File.delete(provider.grant_dbfile_name(username)) rescue nil
- }
-
- it "calls Mixlib::Shellout with the correct command string" do
- expect_any_instance_of(Mixlib::ShellOut).to receive(:exitstatus).and_return(0)
+
+ it "calls win32 api to grant user SeServiceLogonRight" do
+ expect(Chef::ReservedNames::Win32::Security).to receive(:add_account_right).with(username, service_right)
expect(provider.grant_service_logon(username)).to equal true
end
- it "raises an exception when the grant command fails" do
- expect_any_instance_of(Mixlib::ShellOut).to receive(:exitstatus).and_return(1)
- expect_any_instance_of(Mixlib::ShellOut).to receive(:stdout).and_return(failure_string)
+ it "strips '.\' from user name when sending to win32 api" do
+ expect(Chef::ReservedNames::Win32::Security).to receive(:add_account_right).with(username, service_right)
+ expect(provider.grant_service_logon(".\\#{username}")).to equal true
+ end
+
+ it "raises an exception when the grant fails" do
+ expect(Chef::ReservedNames::Win32::Security).to receive(:add_account_right).and_raise(Chef::Exceptions::Win32APIError, "barf")
expect { provider.grant_service_logon(username) }.to raise_error(Chef::Exceptions::Service)
end
end
diff --git a/spec/unit/provider/service_spec.rb b/spec/unit/provider/service_spec.rb
index 17bade55b6..d775297658 100644
--- a/spec/unit/provider/service_spec.rb
+++ b/spec/unit/provider/service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Service do
before do
@@ -49,7 +49,6 @@ describe Chef::Provider::Service do
end
end
-
describe "when disabling the service" do
it "should disable the service if enabled and set the resource as updated" do
allow(@current_resource).to receive(:enabled).and_return(true)
diff --git a/spec/unit/provider/subversion_spec.rb b/spec/unit/provider/subversion_spec.rb
index 9d4a8bd218..a4ab4ae42c 100644
--- a/spec/unit/provider/subversion_spec.rb
+++ b/spec/unit/provider/subversion_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Subversion do
@@ -32,12 +32,21 @@ describe Chef::Provider::Subversion do
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@provider = Chef::Provider::Subversion.new(@resource, @run_context)
+ @original_env = ENV.to_hash
+ # Generated command lines would include any environmental proxies
+ ENV.delete("http_proxy")
+ ENV.delete("https_proxy")
+ end
+
+ after do
+ ENV.clear
+ ENV.update(@original_env)
end
it "converts resource attributes to options for run_command and popen4" do
expect(@provider.run_options).to eq({})
- @resource.user 'deployninja'
- expect(@provider.run_options).to eq({:user => "deployninja"})
+ @resource.user "deployninja"
+ expect(@provider.run_options).to eq({ :user => "deployninja" })
end
context "determining the revision of the currently deployed code" do
@@ -54,28 +63,28 @@ describe Chef::Provider::Subversion do
end
it "determines the current revision if there's a checkout with svn data available" do
- example_svn_info = "Path: .\n" +
- "URL: http://svn.example.org/trunk/myapp\n" +
- "Repository Root: http://svn.example.org\n" +
- "Repository UUID: d62ff500-7bbc-012c-85f1-0026b0e37c24\n" +
- "Revision: 11739\nNode Kind: directory\n" +
- "Schedule: normal\n" +
- "Last Changed Author: codeninja\n" +
- "Last Changed Rev: 11410\n" + # Last Changed Rev is preferred to Revision
- "Last Changed Date: 2009-03-25 06:09:56 -0600 (Wed, 25 Mar 2009)\n\n"
+ example_svn_info = "Path: .\n" +
+ "URL: http://svn.example.org/trunk/myapp\n" +
+ "Repository Root: http://svn.example.org\n" +
+ "Repository UUID: d62ff500-7bbc-012c-85f1-0026b0e37c24\n" +
+ "Revision: 11739\nNode Kind: directory\n" +
+ "Schedule: normal\n" +
+ "Last Changed Author: codeninja\n" +
+ "Last Changed Rev: 11410\n" + # Last Changed Rev is preferred to Revision
+ "Last Changed Date: 2009-03-25 06:09:56 -0600 (Wed, 25 Mar 2009)\n\n"
expect(::File).to receive(:exist?).at_least(1).times.with("/my/deploy/dir/.svn").and_return(true)
- expected_command = ["svn info", {:cwd => '/my/deploy/dir', :returns => [0,1]}]
+ expected_command = ["svn info", { :cwd => "/my/deploy/dir", :returns => [0, 1] }]
expect(@provider).to receive(:shell_out!).with(*expected_command).
- and_return(double("ShellOut result", :stdout => example_svn_info, :stderr => ""))
+ and_return(double("ShellOut result", :stdout => example_svn_info, :stderr => ""))
expect(@provider.find_current_revision).to eql("11410")
end
it "gives nil as the current revision if the deploy dir isn't a SVN working copy" do
example_svn_info = "svn: '/tmp/deploydir' is not a working copy\n"
expect(::File).to receive(:exist?).with("/my/deploy/dir/.svn").and_return(true)
- expected_command = ["svn info", {:cwd => '/my/deploy/dir', :returns => [0,1]}]
+ expected_command = ["svn info", { :cwd => "/my/deploy/dir", :returns => [0, 1] }]
expect(@provider).to receive(:shell_out!).with(*expected_command).
- and_return(double("ShellOut result", :stdout => example_svn_info, :stderr => ""))
+ and_return(double("ShellOut result", :stdout => example_svn_info, :stderr => ""))
expect(@provider.find_current_revision).to be_nil
end
@@ -109,29 +118,29 @@ describe Chef::Provider::Subversion do
end
it "queries the server and resolves the revision if it's not an integer (i.e. 'HEAD')" do
- example_svn_info = "Path: .\n" +
- "URL: http://svn.example.org/trunk/myapp\n" +
- "Repository Root: http://svn.example.org\n" +
- "Repository UUID: d62ff500-7bbc-012c-85f1-0026b0e37c24\n" +
- "Revision: 11739\nNode Kind: directory\n" +
- "Schedule: normal\n" +
- "Last Changed Author: codeninja\n" +
- "Last Changed Rev: 11410\n" + # Last Changed Rev is preferred to Revision
- "Last Changed Date: 2009-03-25 06:09:56 -0600 (Wed, 25 Mar 2009)\n\n"
+ example_svn_info = "Path: .\n" +
+ "URL: http://svn.example.org/trunk/myapp\n" +
+ "Repository Root: http://svn.example.org\n" +
+ "Repository UUID: d62ff500-7bbc-012c-85f1-0026b0e37c24\n" +
+ "Revision: 11739\nNode Kind: directory\n" +
+ "Schedule: normal\n" +
+ "Last Changed Author: codeninja\n" +
+ "Last Changed Rev: 11410\n" + # Last Changed Rev is preferred to Revision
+ "Last Changed Date: 2009-03-25 06:09:56 -0600 (Wed, 25 Mar 2009)\n\n"
@resource.revision "HEAD"
- expected_command = ["svn info http://svn.example.org/trunk/ --no-auth-cache -rHEAD", {:cwd => '/my/deploy/dir', :returns => [0,1]}]
+ expected_command = ["svn info http://svn.example.org/trunk/ --no-auth-cache -rHEAD", { :cwd => "/my/deploy/dir", :returns => [0, 1] }]
expect(@provider).to receive(:shell_out!).with(*expected_command).
- and_return(double("ShellOut result", :stdout => example_svn_info, :stderr => ""))
+ and_return(double("ShellOut result", :stdout => example_svn_info, :stderr => ""))
expect(@provider.revision_int).to eql("11410")
end
it "returns a helpful message if data from `svn info` can't be parsed" do
example_svn_info = "some random text from an error message\n"
@resource.revision "HEAD"
- expected_command = ["svn info http://svn.example.org/trunk/ --no-auth-cache -rHEAD", {:cwd => '/my/deploy/dir', :returns => [0,1]}]
+ expected_command = ["svn info http://svn.example.org/trunk/ --no-auth-cache -rHEAD", { :cwd => "/my/deploy/dir", :returns => [0, 1] }]
expect(@provider).to receive(:shell_out!).with(*expected_command).
- and_return(double("ShellOut result", :stdout => example_svn_info, :stderr => ""))
- expect {@provider.revision_int}.to raise_error(RuntimeError, "Could not parse `svn info` data: some random text from an error message\n")
+ and_return(double("ShellOut result", :stdout => example_svn_info, :stderr => ""))
+ expect { @provider.revision_int }.to raise_error(RuntimeError, "Could not parse `svn info` data: some random text from an error message\n")
end
@@ -142,28 +151,27 @@ describe Chef::Provider::Subversion do
end
it "generates a checkout command with default options" do
- expect(@provider.checkout_command).to eql("svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir")
+ expect(@provider.checkout_command).to eql("svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir")
end
it "generates a checkout command with authentication" do
@resource.svn_username "deployNinja"
@resource.svn_password "vanish!"
- expect(@provider.checkout_command).to eql("svn checkout -q --username deployNinja --password vanish! " +
+ expect(@provider.checkout_command).to eql("svn checkout -q --username deployNinja --password vanish! " +
"-r12345 http://svn.example.org/trunk/ /my/deploy/dir")
end
it "generates a checkout command with arbitrary options" do
@resource.svn_arguments "--no-auth-cache"
- expect(@provider.checkout_command).to eql("svn checkout --no-auth-cache -q -r12345 "+
- "http://svn.example.org/trunk/ /my/deploy/dir")
+ expect(@provider.checkout_command).to eql("svn checkout --no-auth-cache -q -r12345 " + "http://svn.example.org/trunk/ /my/deploy/dir")
end
it "generates a sync command with default options" do
- expect(@provider.sync_command).to eql("svn update -q -r12345 /my/deploy/dir")
+ expect(@provider.sync_command).to eql("svn update -q -r12345 /my/deploy/dir")
end
it "generates an export command with default options" do
- expect(@provider.export_command).to eql("svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir")
+ expect(@provider.export_command).to eql("svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir")
end
it "doesn't try to find the current revision when loading the resource if running an export" do
@@ -180,7 +188,7 @@ describe Chef::Provider::Subversion do
it "runs an export with the --force option" do
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
- expected_cmd = "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
+ expected_cmd = "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
expect(@provider).to receive(:shell_out!).with(expected_cmd, {})
@provider.run_action(:force_export)
expect(@resource).to be_updated
@@ -188,21 +196,21 @@ describe Chef::Provider::Subversion do
it "runs the checkout command for action_checkout" do
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
- expected_cmd = "svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
+ expected_cmd = "svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
expect(@provider).to receive(:shell_out!).with(expected_cmd, {})
@provider.run_action(:checkout)
expect(@resource).to be_updated
end
it "raises an error if the svn checkout command would fail because the enclosing directory doesn't exist" do
- expect {@provider.run_action(:sync)}.to raise_error(Chef::Exceptions::MissingParentDirectory)
+ expect { @provider.run_action(:sync) }.to raise_error(Chef::Exceptions::MissingParentDirectory)
end
it "should not checkout if the destination exists or is a non empty directory" do
allow(::File).to receive(:exist?).with("/my/deploy/dir/.svn").and_return(false)
allow(::File).to receive(:exist?).with("/my/deploy/dir").and_return(true)
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
- allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return(['.','..','foo','bar'])
+ allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return([".", "..", "foo", "bar"])
expect(@provider).not_to receive(:checkout_command)
@provider.run_action(:checkout)
expect(@resource).not_to be_updated
@@ -212,8 +220,8 @@ describe Chef::Provider::Subversion do
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
@resource.user "whois"
@resource.group "thisis"
- expected_cmd = "svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
- expect(@provider).to receive(:shell_out!).with(expected_cmd, {user: "whois", group: "thisis"})
+ expected_cmd = "svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
+ expect(@provider).to receive(:shell_out!).with(expected_cmd, { user: "whois", group: "thisis" })
@provider.run_action(:checkout)
expect(@resource).to be_updated
end
@@ -237,7 +245,7 @@ describe Chef::Provider::Subversion do
expect(::File).to receive(:exist?).with("/my/deploy/dir/.svn").and_return(true)
allow(@provider).to receive(:find_current_revision).and_return("11410")
allow(@provider).to receive(:current_revision_matches_target_revision?).and_return(false)
- expected_cmd = "svn update -q -r12345 /my/deploy/dir"
+ expected_cmd = "svn update -q -r12345 /my/deploy/dir"
expect(@provider).to receive(:shell_out!).with(expected_cmd, {})
@provider.run_action(:sync)
expect(@resource).to be_updated
@@ -246,7 +254,7 @@ describe Chef::Provider::Subversion do
it "does not fetch any updates if the remote revision matches the current revision" do
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
expect(::File).to receive(:exist?).with("/my/deploy/dir/.svn").and_return(true)
- allow(@provider).to receive(:find_current_revision).and_return('12345')
+ allow(@provider).to receive(:find_current_revision).and_return("12345")
allow(@provider).to receive(:current_revision_matches_target_revision?).and_return(true)
@provider.run_action(:sync)
expect(@resource).not_to be_updated
@@ -254,7 +262,7 @@ describe Chef::Provider::Subversion do
it "runs the export_command on action_export" do
allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
- expected_cmd = "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
+ expected_cmd = "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
expect(@provider).to receive(:shell_out!).with(expected_cmd, {})
@provider.run_action(:export)
expect(@resource).to be_updated
@@ -267,33 +275,87 @@ describe Chef::Provider::Subversion do
it "selects 'svn' as the binary by default" do
@resource.svn_binary nil
allow(ChefConfig).to receive(:windows?) { false }
- expect(@provider).to receive(:svn_binary).and_return('svn')
+ expect(@provider).to receive(:svn_binary).and_return("svn")
expect(@provider.export_command).to eql(
- 'svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir')
+ "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir")
end
it "selects an svn binary with an exe extension on windows" do
@resource.svn_binary nil
allow(ChefConfig).to receive(:windows?) { true }
- expect(@provider).to receive(:svn_binary).and_return('svn.exe')
+ expect(@provider).to receive(:svn_binary).and_return("svn.exe")
expect(@provider.export_command).to eql(
- 'svn.exe export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir')
+ "svn.exe export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir")
end
it "uses a custom svn binary as part of the svn command" do
- @resource.svn_binary 'teapot'
- expect(@provider).to receive(:svn_binary).and_return('teapot')
+ @resource.svn_binary "teapot"
+ expect(@provider).to receive(:svn_binary).and_return("teapot")
expect(@provider.export_command).to eql(
- 'teapot export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir')
+ "teapot export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir")
end
it "wraps custom svn binary with quotes if it contains whitespace" do
- @resource.svn_binary 'c:/program files (x86)/subversion/svn.exe'
- expect(@provider).to receive(:svn_binary).and_return('c:/program files (x86)/subversion/svn.exe')
+ @resource.svn_binary "c:/program files (x86)/subversion/svn.exe"
+ expect(@provider).to receive(:svn_binary).and_return("c:/program files (x86)/subversion/svn.exe")
expect(@provider.export_command).to eql(
- '"c:/program files (x86)/subversion/svn.exe" export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir')
+ '"c:/program files (x86)/subversion/svn.exe" export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir')
end
end
+ shared_examples_for "proxied configuration" do
+ it "generates a checkout command with a http proxy" do
+ expect(@provider.checkout_command).to eql("svn checkout -q" +
+ " --config-option servers:global:http-proxy-host=somehost --config-option servers:global:http-proxy-port=1" +
+ " -r12345 #{repository_url} /my/deploy/dir" )
+ end
+ end
+
+ describe "when proxy environment variables exist" do
+ let(:http_proxy_uri) { "http://somehost:1" }
+ let(:http_no_proxy) { "svn.example.org" }
+
+ before (:all) do
+ @original_env = ENV.to_hash
+ end
+
+ after (:all) do
+ ENV.clear
+ ENV.update(@original_env)
+ end
+
+ context "http_proxy is specified" do
+ let(:repository_url) { "http://svn.example.org/trunk/" }
+
+ before do
+ ENV["http_proxy"] = http_proxy_uri
+ end
+
+ it_should_behave_like "proxied configuration"
+ end
+
+ context "https_proxy is specified" do
+ let(:repository_url) { "https://svn.example.org/trunk/" }
+
+ before do
+ ENV["http_proxy"] = nil
+ ENV["https_proxy"] = http_proxy_uri
+ @resource.repository "https://svn.example.org/trunk/"
+ end
+
+ it_should_behave_like "proxied configuration"
+ end
+
+ context "when no_proxy is specified" do
+ before do
+ ENV["http_proxy"] = http_proxy_uri
+ ENV["no_proxy"] = http_no_proxy
+ end
+
+ it "generates a checkout command with default options" do
+ expect(@provider.checkout_command).to eql("svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir")
+ end
+ end
+ end
end
diff --git a/spec/unit/provider/systemd_unit_spec.rb b/spec/unit/provider/systemd_unit_spec.rb
new file mode 100644
index 0000000000..7f2907c982
--- /dev/null
+++ b/spec/unit/provider/systemd_unit_spec.rb
@@ -0,0 +1,885 @@
+#
+# Author:: Nathan Williams (<nath.e.will@gmail.com>)
+# Copyright:: Copyright (c), Nathan Williams
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::SystemdUnit do
+ let(:node) do
+ Chef::Node.new.tap do |n|
+ n.default["etc"] = {}
+ n.default["etc"]["passwd"] = {
+ "joe" => {
+ "uid" => 1_000,
+ },
+ }
+ end
+ end
+
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:unit_name) { "sysstat-collect.timer" }
+ let(:user_name) { "joe" }
+ let(:current_resource) { Chef::Resource::SystemdUnit.new(unit_name) }
+ let(:new_resource) { Chef::Resource::SystemdUnit.new(unit_name) }
+ let(:provider) { Chef::Provider::SystemdUnit.new(new_resource, run_context) }
+ let(:unit_path_system) { "/etc/systemd/system/sysstat-collect.timer" }
+ let(:unit_path_user) { "/etc/systemd/user/sysstat-collect.timer" }
+ let(:unit_content_string) { "[Unit]\nDescription = Run system activity accounting tool every 10 minutes\n\n[Timer]\nOnCalendar = *:00/10\n\n[Install]\nWantedBy = sysstat.service\n" }
+ let(:malformed_content_string) { "derp" }
+
+ let(:unit_content_hash) do
+ {
+ "Unit" => {
+ "Description" => "Run system activity accounting tool every 10 minutes",
+ },
+ "Timer" => {
+ "OnCalendar" => "*:00/10",
+ },
+ "Install" => {
+ "WantedBy" => "sysstat.service",
+ },
+ }
+ end
+
+ let(:user_cmd_opts) do
+ {
+ :user => "joe",
+ :environment => {
+ "DBUS_SESSION_BUS_ADDRESS" => "unix:path=/run/user/1000/bus",
+ },
+ }
+ end
+
+ let(:shell_out_success) do
+ double("shell_out_with_systems_locale", :exitstatus => 0, :error? => false)
+ end
+
+ let(:shell_out_failure) do
+ double("shell_out_with_systems_locale", :exitstatus => 1, :error? => true)
+ end
+
+ let(:shell_out_masked) do
+ double("shell_out_with_systems_locale", :exit_status => 0, :error? => false, :stdout => "masked")
+ end
+
+ let(:shell_out_static) do
+ double("shell_out_with_systems_locale", :exit_status => 0, :error? => false, :stdout => "static")
+ end
+
+ before(:each) do
+ allow(Chef::Resource::SystemdUnit).to receive(:new)
+ .with(unit_name)
+ .and_return(current_resource)
+ end
+
+ describe "define_resource_requirements" do
+ before(:each) do
+ provider.action = :create
+ allow(provider).to receive(:active?).and_return(false)
+ allow(provider).to receive(:enabled?).and_return(false)
+ allow(provider).to receive(:masked?).and_return(false)
+ allow(provider).to receive(:static?).and_return(false)
+ end
+
+ it "accepts valid resource requirements" do
+ new_resource.content(unit_content_string)
+ provider.load_current_resource
+ provider.define_resource_requirements
+ expect { provider.process_resource_requirements }.to_not raise_error
+ end
+
+ it "rejects failed resource requirements" do
+ new_resource.content(malformed_content_string)
+ provider.load_current_resource
+ provider.define_resource_requirements
+ expect { provider.process_resource_requirements }.to raise_error(IniParse::ParseError)
+ end
+ end
+
+ describe "load_current_resource" do
+ before(:each) do
+ allow(provider).to receive(:active?).and_return(false)
+ allow(provider).to receive(:enabled?).and_return(false)
+ allow(provider).to receive(:masked?).and_return(false)
+ allow(provider).to receive(:static?).and_return(false)
+ end
+
+ it "should create a current resource with the name of the new resource" do
+ expect(Chef::Resource::SystemdUnit).to receive(:new)
+ .with(unit_name)
+ .and_return(current_resource)
+ provider.load_current_resource
+ end
+
+ it "should check if the unit is active" do
+ expect(provider).to receive(:active?)
+ provider.load_current_resource
+ end
+
+ it "sets the active property to true if the unit is active" do
+ allow(provider).to receive(:active?).and_return(true)
+ provider.load_current_resource
+ expect(current_resource.active).to be true
+ end
+
+ it "sets the active property to false if the unit is not active" do
+ allow(provider).to receive(:active?).and_return(false)
+ provider.load_current_resource
+ expect(current_resource.active).to be false
+ end
+
+ it "should check if the unit is enabled" do
+ expect(provider).to receive(:enabled?)
+ provider.load_current_resource
+ end
+
+ it "sets the enabled property to true if the unit is enabled" do
+ allow(provider).to receive(:enabled?).and_return(true)
+ provider.load_current_resource
+ expect(current_resource.enabled).to be true
+ end
+
+ it "sets the enabled property to false if the unit is not enabled" do
+ allow(provider).to receive(:enabled?).and_return(false)
+ provider.load_current_resource
+ expect(current_resource.enabled).to be false
+ end
+
+ it "should check if the unit is masked" do
+ expect(provider).to receive(:masked?)
+ provider.load_current_resource
+ end
+
+ it "sets the masked property to true if the unit is masked" do
+ allow(provider).to receive(:masked?).and_return(true)
+ provider.load_current_resource
+ expect(current_resource.masked).to be true
+ end
+
+ it "sets the masked property to false if the unit is masked" do
+ allow(provider).to receive(:masked?).and_return(false)
+ provider.load_current_resource
+ expect(current_resource.masked).to be false
+ end
+
+ it "should check if the unit is static" do
+ expect(provider).to receive(:static?)
+ provider.load_current_resource
+ end
+
+ it "sets the static property to true if the unit is static" do
+ allow(provider).to receive(:static?).and_return(true)
+ provider.load_current_resource
+ expect(current_resource.static).to be true
+ end
+
+ it "sets the static property to false if the unit is not static" do
+ allow(provider).to receive(:static?).and_return(false)
+ provider.load_current_resource
+ expect(current_resource.static).to be false
+ end
+
+ it "loads the system unit content if the file exists and user is not set" do
+ allow(File).to receive(:exist?)
+ .with(unit_path_system)
+ .and_return(true)
+ allow(File).to receive(:read)
+ .with(unit_path_system)
+ .and_return(unit_content_string)
+
+ expect(File).to receive(:exist?)
+ .with(unit_path_system)
+ expect(File).to receive(:read)
+ .with(unit_path_system)
+ provider.load_current_resource
+ expect(current_resource.content).to eq(unit_content_string)
+ end
+
+ it "does not load the system unit content if the unit file is not present and the user is not set" do
+ allow(File).to receive(:exist?)
+ .with(unit_path_system)
+ .and_return(false)
+ expect(File).to_not receive(:read)
+ .with(unit_path_system)
+ provider.load_current_resource
+ expect(current_resource.content).to eq(nil)
+ end
+
+ it "loads the user unit content if the file exists and user is set" do
+ new_resource.user("joe")
+ allow(File).to receive(:exist?)
+ .with(unit_path_user)
+ .and_return(true)
+ allow(File).to receive(:read)
+ .with(unit_path_user)
+ .and_return(unit_content_string)
+ expect(File).to receive(:exist?)
+ .with(unit_path_user)
+ expect(File).to receive(:read)
+ .with(unit_path_user)
+ provider.load_current_resource
+ expect(current_resource.content).to eq(unit_content_string)
+ end
+
+ it "does not load the user unit if the file does not exist and user is set" do
+ new_resource.user("joe")
+ allow(File).to receive(:exist?)
+ .with(unit_path_user)
+ .and_return(false)
+ expect(File).to_not receive(:read)
+ .with(unit_path_user)
+ provider.load_current_resource
+ expect(current_resource.content).to eq(nil)
+ end
+ end
+
+ %w{/bin/systemctl /usr/bin/systemctl}.each do |systemctl_path|
+ describe "when systemctl path is #{systemctl_path}" do
+ before(:each) do
+ provider.current_resource = current_resource
+ allow(provider).to receive(:which)
+ .with("systemctl")
+ .and_return(systemctl_path)
+ end
+
+ describe "creates/deletes the unit" do
+ it "creates the unit file when it does not exist" do
+ allow(provider).to receive(:manage_unit_file)
+ .with(:create)
+ .and_return(true)
+ allow(provider).to receive(:daemon_reload)
+ .and_return(true)
+ expect(provider).to receive(:manage_unit_file).with(:create)
+ provider.action_create
+ end
+
+ it "creates the file when the unit content is different" do
+ allow(provider).to receive(:manage_unit_file)
+ .with(:create)
+ .and_return(true)
+ allow(provider).to receive(:daemon_reload)
+ .and_return(true)
+ expect(provider).to receive(:manage_unit_file).with(:create)
+ provider.action_create
+ end
+
+ it "does not create the unit file when the content is the same" do
+ current_resource.content(unit_content_string)
+ allow(provider).to receive(:manage_unit_file).with(:create)
+ allow(provider).to receive(:daemon_reload)
+ .and_return(true)
+ expect(provider).to_not receive(:manage_unit_file)
+ provider.action_create
+ end
+
+ it "triggers a daemon-reload when creating a unit with triggers_reload" do
+ allow(provider).to receive(:manage_unit_file).with(:create)
+ expect(new_resource.triggers_reload).to eq true
+ allow(provider).to receive(:shell_out_with_systems_locale!)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} daemon-reload")
+ provider.action_create
+ end
+
+ it "triggers a daemon-reload when deleting a unit with triggers_reload" do
+ allow(File).to receive(:exist?)
+ .with(unit_path_system)
+ .and_return(true)
+ allow(provider).to receive(:manage_unit_file).with(:delete)
+ expect(new_resource.triggers_reload).to eq true
+ allow(provider).to receive(:shell_out_with_systems_locale!)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} daemon-reload")
+ provider.action_delete
+ end
+
+ it "does not trigger a daemon-reload when creating a unit without triggers_reload" do
+ new_resource.triggers_reload(false)
+ allow(provider).to receive(:manage_unit_file).with(:create)
+ allow(provider).to receive(:shell_out_with_systems_locale!)
+ expect(provider).to_not receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} daemon-reload")
+ provider.action_create
+ end
+
+ it "does not trigger a daemon-reload when deleting a unit without triggers_reload" do
+ new_resource.triggers_reload(false)
+ allow(File).to receive(:exist?)
+ .with(unit_path_system)
+ .and_return(true)
+ allow(provider).to receive(:manage_unit_file).with(:delete)
+ allow(provider).to receive(:shell_out_with_systems_locale!)
+ expect(provider).to_not receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} daemon-reload")
+ provider.action_delete
+ end
+
+ context "when a user is specified" do
+ it "deletes the file when it exists" do
+ new_resource.user("joe")
+ allow(File).to receive(:exist?)
+ .with(unit_path_user)
+ .and_return(true)
+ allow(provider).to receive(:manage_unit_file)
+ .with(:delete)
+ .and_return(true)
+ allow(provider).to receive(:daemon_reload)
+ expect(provider).to receive(:manage_unit_file).with(:delete)
+ provider.action_delete
+ end
+
+ it "does not delete the file when it is absent" do
+ new_resource.user("joe")
+ allow(File).to receive(:exist?)
+ .with(unit_path_user)
+ .and_return(false)
+ allow(provider).to receive(:manage_unit_file).with(:delete)
+ expect(provider).to_not receive(:manage_unit_file)
+ provider.action_delete
+ end
+ end
+
+ context "when no user is specified" do
+ it "deletes the file when it exists" do
+ allow(File).to receive(:exist?)
+ .with(unit_path_system)
+ .and_return(true)
+ allow(provider).to receive(:manage_unit_file)
+ .with(:delete)
+ allow(provider).to receive(:daemon_reload)
+ expect(provider).to receive(:manage_unit_file).with(:delete)
+ provider.action_delete
+ end
+
+ it "does not delete the file when it is absent" do
+ allow(File).to receive(:exist?)
+ .with(unit_path_system)
+ .and_return(false)
+ allow(provider).to receive(:manage_unit_file).with(:delete)
+ allow(provider).to receive(:daemon_reload)
+ expect(provider).to_not receive(:manage_unit_file)
+ provider.action_delete
+ end
+ end
+ end
+
+ describe "enables/disables the unit" do
+ context "when a user is specified" do
+ it "enables the unit when it is disabled" do
+ current_resource.user(user_name)
+ current_resource.enabled(false)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user enable #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_enable
+ end
+
+ it "does not enable the unit when it is enabled" do
+ current_resource.user(user_name)
+ current_resource.enabled(true)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_enable
+ end
+
+ it "does not enable the unit when it is static" do
+ current_resource.user(user_name)
+ current_resource.static(true)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_enable
+ end
+
+ it "disables the unit when it is enabled" do
+ current_resource.user(user_name)
+ current_resource.enabled(true)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user disable #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_disable
+ end
+
+ it "does not disable the unit when it is disabled" do
+ current_resource.user(user_name)
+ current_resource.enabled(false)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_disable
+ end
+
+ it "does not disable the unit when it is static" do
+ current_resource.user(user_name)
+ current_resource.static(true)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_disable
+ end
+ end
+
+ context "when no user is specified" do
+ it "enables the unit when it is disabled" do
+ current_resource.enabled(false)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system enable #{unit_name}", {})
+ .and_return(shell_out_success)
+ provider.action_enable
+ end
+
+ it "does not enable the unit when it is enabled" do
+ current_resource.enabled(true)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_enable
+ end
+
+ it "does not enable the unit when it is static" do
+ current_resource.static(true)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_enable
+ end
+
+ it "disables the unit when it is enabled" do
+ current_resource.enabled(true)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system disable #{unit_name}", {})
+ .and_return(shell_out_success)
+ provider.action_disable
+ end
+
+ it "does not disable the unit when it is disabled" do
+ current_resource.enabled(false)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_disable
+ end
+
+ it "does not disable the unit when it is static" do
+ current_resource.user(user_name)
+ current_resource.static(true)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_disable
+ end
+ end
+ end
+
+ describe "masks/unmasks the unit" do
+ context "when a user is specified" do
+ it "masks the unit when it is unmasked" do
+ current_resource.user(user_name)
+ current_resource.masked(false)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user mask #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_mask
+ end
+
+ it "does not mask the unit when it is masked" do
+ current_resource.user(user_name)
+ current_resource.masked(true)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_mask
+ end
+
+ it "unmasks the unit when it is masked" do
+ current_resource.user(user_name)
+ current_resource.masked(true)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user unmask #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_unmask
+ end
+
+ it "does not unmask the unit when it is unmasked" do
+ current_resource.user(user_name)
+ current_resource.masked(false)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_unmask
+ end
+ end
+
+ context "when no user is specified" do
+ it "masks the unit when it is unmasked" do
+ current_resource.masked(false)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system mask #{unit_name}", {})
+ .and_return(shell_out_success)
+ provider.action_mask
+ end
+
+ it "does not mask the unit when it is masked" do
+ current_resource.masked(true)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_mask
+ end
+
+ it "unmasks the unit when it is masked" do
+ current_resource.masked(true)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system unmask #{unit_name}", {})
+ .and_return(shell_out_success)
+ provider.action_unmask
+ end
+
+ it "does not unmask the unit when it is unmasked" do
+ current_resource.masked(false)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_unmask
+ end
+ end
+ end
+
+ describe "starts/stops the unit" do
+ context "when a user is specified" do
+ it "starts the unit when it is inactive" do
+ current_resource.user(user_name)
+ current_resource.active(false)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user start #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_start
+ end
+
+ it "does not start the unit when it is active" do
+ current_resource.user(user_name)
+ current_resource.active(true)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_start
+ end
+
+ it "stops the unit when it is active" do
+ current_resource.user(user_name)
+ current_resource.active(true)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user stop #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_stop
+ end
+
+ it "does not stop the unit when it is inactive" do
+ current_resource.user(user_name)
+ current_resource.active(false)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_stop
+ end
+ end
+
+ context "when no user is specified" do
+ it "starts the unit when it is inactive" do
+ current_resource.active(false)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system start #{unit_name}", {})
+ .and_return(shell_out_success)
+ provider.action_start
+ end
+
+ it "does not start the unit when it is active" do
+ current_resource.active(true)
+ expect(provider).to_not receive(:shell_out_with_systems_locale!)
+ provider.action_start
+ end
+
+ it "stops the unit when it is active" do
+ current_resource.active(true)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system stop #{unit_name}", {})
+ .and_return(shell_out_success)
+ provider.action_stop
+ end
+
+ it "does not stop the unit when it is inactive" do
+ current_resource.active(false)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_stop
+ end
+ end
+ end
+
+ describe "restarts/reloads the unit" do
+ context "when a user is specified" do
+ it "restarts the unit" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user restart #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_restart
+ end
+
+ it "reloads the unit if active" do
+ current_resource.user(user_name)
+ current_resource.active(true)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user reload #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_reload
+ end
+
+ it "does not reload if the unit is inactive" do
+ current_resource.user(user_name)
+ current_resource.active(false)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_reload
+ end
+ end
+
+ context "when no user is specified" do
+ it "restarts the unit" do
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system restart #{unit_name}", {})
+ .and_return(shell_out_success)
+ provider.action_restart
+ end
+
+ it "reloads the unit if active" do
+ current_resource.active(true)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system reload #{unit_name}", {})
+ .and_return(shell_out_success)
+ provider.action_reload
+ end
+
+ it "does not reload the unit if inactive" do
+ current_resource.active(false)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!)
+ provider.action_reload
+ end
+ end
+ end
+
+ describe "try-restarts the unit" do
+ context "when a user is specified" do
+ it "try-restarts the unit" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user try-restart #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_try_restart
+ end
+ end
+
+ context "when no user is specified" do
+ it "try-restarts the unit" do
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system try-restart #{unit_name}", {})
+ .and_return(shell_out_success)
+ provider.action_try_restart
+ end
+ end
+ end
+
+ describe "reload-or-restarts the unit" do
+ context "when a user is specified" do
+ it "reload-or-restarts the unit" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user reload-or-restart #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_reload_or_restart
+ end
+ end
+
+ context "when no user is specified" do
+ it "reload-or-restarts the unit" do
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system reload-or-restart #{unit_name}", {})
+ .and_return(shell_out_success)
+ provider.action_reload_or_restart
+ end
+ end
+ end
+
+ describe "reload-or-try-restarts the unit" do
+ context "when a user is specified" do
+ it "reload-or-try-restarts the unit" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user reload-or-try-restart #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_reload_or_try_restart
+ end
+ end
+
+ context "when no user is specified" do
+ it "reload-or-try-restarts the unit" do
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system reload-or-try-restart #{unit_name}", {})
+ .and_return(shell_out_success)
+ provider.action_reload_or_try_restart
+ end
+ end
+ end
+
+ describe "#active?" do
+ before(:each) do
+ provider.current_resource = current_resource
+ allow(provider).to receive(:which).with("systemctl").and_return("#{systemctl_path}")
+ end
+
+ context "when a user is specified" do
+ it "returns true when unit is active" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --user is-active #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ expect(provider.active?).to be true
+ end
+
+ it "returns false when unit is inactive" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --user is-active #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_failure)
+ expect(provider.active?).to be false
+ end
+ end
+
+ context "when no user is specified" do
+ it "returns true when unit is active" do
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --system is-active #{unit_name}", {})
+ .and_return(shell_out_success)
+ expect(provider.active?).to be true
+ end
+
+ it "returns false when unit is not active" do
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --system is-active #{unit_name}", {})
+ .and_return(shell_out_failure)
+ expect(provider.active?).to be false
+ end
+ end
+ end
+
+ describe "#enabled?" do
+ before(:each) do
+ provider.current_resource = current_resource
+ allow(provider).to receive(:which).with("systemctl").and_return("#{systemctl_path}")
+ end
+
+ context "when a user is specified" do
+ it "returns true when unit is enabled" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --user is-enabled #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_success)
+ expect(provider.enabled?).to be true
+ end
+
+ it "returns false when unit is not enabled" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --user is-enabled #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_failure)
+ expect(provider.enabled?).to be false
+ end
+ end
+
+ context "when no user is specified" do
+ it "returns true when unit is enabled" do
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --system is-enabled #{unit_name}", {})
+ .and_return(shell_out_success)
+ expect(provider.enabled?).to be true
+ end
+
+ it "returns false when unit is not enabled" do
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --system is-enabled #{unit_name}", {})
+ .and_return(shell_out_failure)
+ expect(provider.enabled?).to be false
+ end
+ end
+ end
+
+ describe "#masked?" do
+ before(:each) do
+ provider.current_resource = current_resource
+ allow(provider).to receive(:which).with("systemctl").and_return("#{systemctl_path}")
+ end
+
+ context "when a user is specified" do
+ it "returns true when the unit is masked" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --user status #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_masked)
+ expect(provider.masked?).to be true
+ end
+
+ it "returns false when the unit is not masked" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --user status #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_static)
+ expect(provider.masked?).to be false
+ end
+ end
+
+ context "when no user is specified" do
+ it "returns true when the unit is masked" do
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --system status #{unit_name}", {})
+ .and_return(shell_out_masked)
+ expect(provider.masked?).to be true
+ end
+
+ it "returns false when the unit is not masked" do
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --system status #{unit_name}", {})
+ .and_return(shell_out_static)
+ expect(provider.masked?).to be false
+ end
+ end
+ end
+
+ describe "#static?" do
+ before(:each) do
+ provider.current_resource = current_resource
+ allow(provider).to receive(:which).with("systemctl").and_return("#{systemctl_path}")
+ end
+
+ context "when a user is specified" do
+ it "returns true when the unit is static" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --user is-enabled #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_static)
+ expect(provider.static?).to be true
+ end
+
+ it "returns false when the unit is not static" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --user is-enabled #{unit_name}", user_cmd_opts)
+ .and_return(shell_out_masked)
+ expect(provider.static?).to be false
+ end
+ end
+
+ context "when no user is specified" do
+ it "returns true when the unit is static" do
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --system is-enabled #{unit_name}", {})
+ .and_return(shell_out_static)
+ expect(provider.static?).to be true
+ end
+
+ it "returns false when the unit is not static" do
+ expect(provider).to receive(:shell_out)
+ .with("#{systemctl_path} --system is-enabled #{unit_name}", {})
+ .and_return(shell_out_masked)
+ expect(provider.static?).to be false
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/provider/template/content_spec.rb b/spec/unit/provider/template/content_spec.rb
index 509c8cf33b..8f30d8f868 100644
--- a/spec/unit/provider/template/content_spec.rb
+++ b/spec/unit/provider/template/content_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,27 +16,27 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::Template::Content do
- let(:enclosing_directory) {
+ let(:enclosing_directory) do
canonicalize_path(Dir.mktmpdir)
- }
+ end
- let(:resource_path) {
+ let(:resource_path) do
canonicalize_path(File.expand_path(File.join(enclosing_directory, "openldap_stuff.conf")))
- }
+ end
let(:new_resource) do
double("Chef::Resource::Template (new)",
- :cookbook_name => 'openldap',
- :recipe_name => 'default',
+ :cookbook_name => "openldap",
+ :recipe_name => "default",
:source_line => "/Users/lamont/solo/cookbooks/openldap/recipes/default.rb:2:in `from_file'",
:source_line_file => "/Users/lamont/solo/cookbooks/openldap/recipes/default.rb",
:source_line_number => "2",
- :source => 'openldap_stuff.conf.erb',
- :name => 'openldap_stuff.conf',
+ :source => "openldap_stuff.conf.erb",
+ :name => "openldap_stuff.conf",
:path => resource_path,
:local => false,
:cookbook => nil,
@@ -46,10 +46,10 @@ describe Chef::Provider::Template::Content do
:helper_modules => [])
end
- let(:rendered_file_locations) {
- [Dir.tmpdir + '/openldap_stuff.conf',
- enclosing_directory + '/openldap_stuff.conf']
- }
+ let(:rendered_file_locations) do
+ [Dir.tmpdir + "/openldap_stuff.conf",
+ enclosing_directory + "/openldap_stuff.conf"]
+ end
let(:run_context) do
cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
@@ -73,25 +73,25 @@ describe Chef::Provider::Template::Content do
end
it "finds the template file in the cookbook cache if it isn't local" do
- expect(content.template_location).to eq(CHEF_SPEC_DATA + '/cookbooks/openldap/templates/default/openldap_stuff.conf.erb')
+ expect(content.template_location).to eq(CHEF_SPEC_DATA + "/cookbooks/openldap/templates/default/openldap_stuff.conf.erb")
end
it "finds the template file locally if it is local" do
allow(new_resource).to receive(:local).and_return(true)
- allow(new_resource).to receive(:source).and_return('/tmp/its_on_disk.erb')
- expect(content.template_location).to eq('/tmp/its_on_disk.erb')
+ allow(new_resource).to receive(:source).and_return("/tmp/its_on_disk.erb")
+ expect(content.template_location).to eq("/tmp/its_on_disk.erb")
end
it "should use the cookbook name if defined in the template resource" do
- allow(new_resource).to receive(:cookbook_name).and_return('apache2')
- allow(new_resource).to receive(:cookbook).and_return('openldap')
+ allow(new_resource).to receive(:cookbook_name).and_return("apache2")
+ allow(new_resource).to receive(:cookbook).and_return("openldap")
allow(new_resource).to receive(:source).and_return("test.erb")
- expect(content.template_location).to eq(CHEF_SPEC_DATA + '/cookbooks/openldap/templates/default/test.erb')
+ expect(content.template_location).to eq(CHEF_SPEC_DATA + "/cookbooks/openldap/templates/default/test.erb")
end
it "returns a tempfile in the tempdir when :file_staging_uses_destdir is not set" do
Chef::Config[:file_staging_uses_destdir] = false
- expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be true
+ expect(content.tempfile.path.start_with?(Dir.tmpdir)).to be true
expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be false
end
@@ -101,23 +101,23 @@ describe Chef::Provider::Template::Content do
end
context "when creating a tempfile in destdir fails" do
- let(:enclosing_directory) {
+ let(:enclosing_directory) do
canonicalize_path("/nonexisting/path")
- }
+ end
it "returns a tempfile in the tempdir when :file_deployment_uses_destdir is set to :auto" do
Chef::Config[:file_staging_uses_destdir] = :auto
- expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be true
+ expect(content.tempfile.path.start_with?(Dir.tmpdir)).to be true
expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be false
end
it "fails when :file_desployment_uses_destdir is set" do
Chef::Config[:file_staging_uses_destdir] = true
- expect{content.tempfile}.to raise_error(Chef::Exceptions::FileContentStagingError)
+ expect { content.tempfile }.to raise_error(Chef::Exceptions::FileContentStagingError)
end
it "returns a tempfile in the tempdir when :file_desployment_uses_destdir is not set" do
- expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be true
+ expect(content.tempfile.path.start_with?(Dir.tmpdir)).to be true
expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be false
end
end
@@ -130,14 +130,14 @@ describe Chef::Provider::Template::Content do
describe "when using location helpers" do
let(:new_resource) do
double("Chef::Resource::Template (new)",
- :cookbook_name => 'openldap',
- :recipe_name => 'default',
+ :cookbook_name => "openldap",
+ :recipe_name => "default",
:source_line => CHEF_SPEC_DATA + "/cookbooks/openldap/recipes/default.rb:2:in `from_file'",
:source_line_file => CHEF_SPEC_DATA + "/cookbooks/openldap/recipes/default.rb",
:source_line_number => "2",
- :source => 'helpers.erb',
- :name => 'helpers.erb',
- :path => CHEF_SPEC_DATA + '/cookbooks/openldap/templates/default/helpers.erb',
+ :source => "helpers.erb",
+ :name => "helpers.erb",
+ :path => CHEF_SPEC_DATA + "/cookbooks/openldap/templates/default/helpers.erb",
:local => false,
:cookbook => nil,
:variables => {},
diff --git a/spec/unit/provider/template_spec.rb b/spec/unit/provider/template_spec.rb
index 713303d818..306fd6ea71 100644
--- a/spec/unit/provider/template_spec.rb
+++ b/spec/unit/provider/template_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2008-2013 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,23 +17,22 @@
# limitations under the License.
#
-require 'stringio'
-require 'spec_helper'
-require 'etc'
-require 'ostruct'
-require 'support/shared/unit/provider/file'
-
+require "stringio"
+require "spec_helper"
+require "etc"
+require "ostruct"
+require "support/shared/unit/provider/file"
describe Chef::Provider::Template do
- let(:node) { double('Chef::Node') }
- let(:events) { double('Chef::Events').as_null_object } # mock all the methods
- let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
- let(:enclosing_directory) {
+ let(:node) { double("Chef::Node") }
+ let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+ let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
+ let(:enclosing_directory) do
canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
- }
- let(:resource_path) {
+ end
+ let(:resource_path) do
canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt")))
- }
+ end
# Subject
@@ -50,7 +49,7 @@ describe Chef::Provider::Template do
end
let(:content) do
- content = double('Chef::Provider::File::Content::Template', :template_location => "/foo/bar/baz")
+ content = double("Chef::Provider::File::Content::Template", :template_location => "/foo/bar/baz")
allow(File).to receive(:exists?).with("/foo/bar/baz").and_return(true)
content
end
@@ -59,15 +58,15 @@ describe Chef::Provider::Template do
context "when creating the template" do
- let(:node) { double('Chef::Node') }
- let(:events) { double('Chef::Events').as_null_object } # mock all the methods
- let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
- let(:enclosing_directory) {
+ let(:node) { double("Chef::Node") }
+ let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+ let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
+ let(:enclosing_directory) do
canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
- }
- let(:resource_path) {
+ end
+ let(:resource_path) do
canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt")))
- }
+ end
# Subject
diff --git a/spec/unit/provider/user/dscl_spec.rb b/spec/unit/provider/user/dscl_spec.rb
index a9407a4d7e..f59709e717 100644
--- a/spec/unit/provider/user/dscl_spec.rb
+++ b/spec/unit/provider/user/dscl_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Dreamcat4 (<dreamcat4@gmail.com>)
-# Copyright:: Copyright (c) 2009 OpsCode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,59 +16,60 @@
# limitations under the License.
#
-ShellCmdResult = Struct.new(:stdout, :stderr, :exitstatus)
-
-require 'spec_helper'
-require 'ostruct'
-require 'mixlib/shellout'
+require "spec_helper"
+require "ostruct"
+require "mixlib/shellout"
describe Chef::Provider::User::Dscl do
before do
allow(ChefConfig).to receive(:windows?) { false }
end
- let(:node) {
+ let(:shellcmdresult) do
+ Struct.new(:stdout, :stderr, :exitstatus)
+ end
+ let(:node) do
node = Chef::Node.new
allow(node).to receive(:[]).with(:platform_version).and_return(mac_version)
allow(node).to receive(:[]).with(:platform).and_return("mac_os_x")
node
- }
+ end
- let(:events) {
+ let(:events) do
Chef::EventDispatch::Dispatcher.new
- }
+ end
- let(:run_context) {
+ let(:run_context) do
Chef::RunContext.new(node, {}, events)
- }
+ end
- let(:new_resource) {
- r = Chef::Resource::User.new("toor")
+ let(:new_resource) do
+ r = Chef::Resource::User::DsclUser.new("toor")
r.password(password)
r.salt(salt)
r.iterations(iterations)
r
- }
+ end
- let(:provider) {
+ let(:provider) do
Chef::Provider::User::Dscl.new(new_resource, run_context)
- }
+ end
- let(:mac_version) {
+ let(:mac_version) do
"10.9.1"
- }
+ end
let(:password) { nil }
let(:salt) { nil }
let(:iterations) { nil }
- let(:salted_sha512_password) {
+ let(:salted_sha512_password) do
"0f543f021c63255e64e121a3585601b8ecfedf6d2\
705ddac69e682a33db5dbcdb9b56a2520bc8fff63a\
2ba6b7984c0737ff0b7949455071581f7affcd536d\
402b6cdb097"
- }
+ end
- let(:salted_sha512_pbkdf2_password) {
+ let(:salted_sha512_pbkdf2_password) do
"c734b6e4787c3727bb35e29fdd92b97c\
1de12df509577a045728255ec7c6c5f5\
c18efa05ed02b682ffa7ebc05119900e\
@@ -77,24 +78,24 @@ b1d4880833aa7a190afc13e2bf0936b8\
9464a8c234f3919082400b4f939bb77b\
c5adbbac718b7eb99463a7b679571e0f\
1c9fef2ef08d0b9e9c2bcf644eed2ffc"
- }
+ end
- let(:salted_sha512_pbkdf2_salt) {
+ let(:salted_sha512_pbkdf2_salt) do
"2d942d8364a9ccf2b8e5cb7ed1ff58f78\
e29dbfee7f9db58859144d061fd0058"
- }
+ end
- let(:salted_sha512_pbkdf2_iterations) {
+ let(:salted_sha512_pbkdf2_iterations) do
25000
- }
+ end
- let(:vagrant_sha_512) {
+ let(:vagrant_sha_512) do
"6f75d7190441facc34291ebbea1fc756b242d4f\
e9bcff141bccb84f1979e27e539539aa31f9f7dcc92c0cea959\
ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
- }
+ end
- let(:vagrant_sha_512_pbkdf2) {
+ let(:vagrant_sha_512_pbkdf2) do
"12601a90db17cbf\
8ba4808e6382fb0d3b9d8a6c1a190477bf680ab21afb\
6065467136e55cc208a6f74156e3daf20fb13369ef4b\
@@ -102,51 +103,51 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
47cca84341a7f93a27147343f89fb843fb46c0017d2\
64afa4976baacf941b915bd1ec1ca24c30b3e759e02\
403e02f59fe7ff5938a7636c"
- }
+ end
- let(:vagrant_sha_512_pbkdf2_salt) {
+ let(:vagrant_sha_512_pbkdf2_salt) do
"ee954be472fdc60ddf89484781433993625f006af6ec810c08f49a7e413946a1"
- }
+ end
- let(:vagrant_sha_512_pbkdf2_iterations) {
+ let(:vagrant_sha_512_pbkdf2_iterations) do
34482
- }
+ end
describe "when shelling out to dscl" do
it "should run dscl with the supplied cmd /Path args" do
- shell_return = ShellCmdResult.new('stdout', 'err', 0)
- expect(provider).to receive(:shell_out).with("dscl . -cmd /Path args").and_return(shell_return)
- expect(provider.run_dscl("cmd /Path args")).to eq('stdout')
+ shell_return = shellcmdresult.new("stdout", "err", 0)
+ expect(provider).to receive(:shell_out).with("dscl", ".", "-cmd", "/Path", "args").and_return(shell_return)
+ expect(provider.run_dscl("cmd", "/Path", "args")).to eq("stdout")
end
it "returns an empty string from delete commands" do
- shell_return = ShellCmdResult.new('out', 'err', 23)
- expect(provider).to receive(:shell_out).with("dscl . -delete /Path args").and_return(shell_return)
- expect(provider.run_dscl("delete /Path args")).to eq("")
+ shell_return = shellcmdresult.new("out", "err", 23)
+ expect(provider).to receive(:shell_out).with("dscl", ".", "-delete", "/Path", "args").and_return(shell_return)
+ expect(provider.run_dscl("delete", "/Path", "args")).to eq("")
end
it "should raise an exception for any other command" do
- shell_return = ShellCmdResult.new('out', 'err', 23)
- expect(provider).to receive(:shell_out).with('dscl . -cmd /Path arguments').and_return(shell_return)
- expect { provider.run_dscl("cmd /Path arguments") }.to raise_error(Chef::Exceptions::DsclCommandFailed)
+ shell_return = shellcmdresult.new("out", "err", 23)
+ expect(provider).to receive(:shell_out).with("dscl", ".", "-cmd", "/Path", "arguments").and_return(shell_return)
+ expect { provider.run_dscl("cmd", "/Path", "arguments") }.to raise_error(Chef::Exceptions::DsclCommandFailed)
end
it "raises an exception when dscl reports 'no such key'" do
- shell_return = ShellCmdResult.new("No such key: ", 'err', 23)
- expect(provider).to receive(:shell_out).with('dscl . -cmd /Path args').and_return(shell_return)
- expect { provider.run_dscl("cmd /Path args") }.to raise_error(Chef::Exceptions::DsclCommandFailed)
+ shell_return = shellcmdresult.new("No such key: ", "err", 23)
+ expect(provider).to receive(:shell_out).with("dscl", ".", "-cmd", "/Path", "args").and_return(shell_return)
+ expect { provider.run_dscl("cmd", "/Path", "args") }.to raise_error(Chef::Exceptions::DsclCommandFailed)
end
it "raises an exception when dscl reports 'eDSRecordNotFound'" do
- shell_return = ShellCmdResult.new("<dscl_cmd> DS Error: -14136 (eDSRecordNotFound)", 'err', -14136)
- expect(provider).to receive(:shell_out).with('dscl . -cmd /Path args').and_return(shell_return)
- expect { provider.run_dscl("cmd /Path args") }.to raise_error(Chef::Exceptions::DsclCommandFailed)
+ shell_return = shellcmdresult.new("<dscl_cmd> DS Error: -14136 (eDSRecordNotFound)", "err", -14136)
+ expect(provider).to receive(:shell_out).with("dscl", ".", "-cmd", "/Path", "args").and_return(shell_return)
+ expect { provider.run_dscl("cmd", "/Path", "args") }.to raise_error(Chef::Exceptions::DsclCommandFailed)
end
end
describe "get_free_uid" do
before do
- expect(provider).to receive(:run_dscl).with("list /Users uid").and_return("\nwheel 200\nstaff 201\nbrahms 500\nchopin 501\n")
+ expect(provider).to receive(:run_dscl).with("list", "/Users", "uid").and_return("\nwheel 200\nstaff 201\nbrahms 500\nchopin 501\n")
end
describe "when resource is configured as system" do
@@ -176,7 +177,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
describe "when called with a user id" do
before do
- expect(provider).to receive(:run_dscl).with("list /Users uid").and_return("\naj 500\n")
+ expect(provider).to receive(:run_dscl).with("list", "/Users", "uid").and_return("\naj 500\n")
end
it "should return true for a used uid number" do
@@ -197,8 +198,8 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
end
it "finds a valid, unused uid when none is specified" do
- expect(provider).to receive(:run_dscl).with("list /Users uid").and_return('')
- expect(provider).to receive(:run_dscl).with("create /Users/toor UniqueID 501")
+ expect(provider).to receive(:run_dscl).with("list", "/Users", "uid").and_return("")
+ expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "UniqueID", 501)
expect(provider).to receive(:get_free_uid).and_return(501)
provider.dscl_set_uid
expect(new_resource.uid).to eq(501)
@@ -206,70 +207,70 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
it "sets the uid specified in the resource" do
new_resource.uid(1000)
- expect(provider).to receive(:run_dscl).with("create /Users/toor UniqueID 1000").and_return(true)
- expect(provider).to receive(:run_dscl).with("list /Users uid").and_return('')
+ expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "UniqueID", 1000).and_return(true)
+ expect(provider).to receive(:run_dscl).with("list", "/Users", "uid").and_return("")
provider.dscl_set_uid
end
end
describe "when modifying the home directory" do
- let(:current_resource) {
+ let(:current_resource) do
new_resource.dup
- }
+ end
before do
- new_resource.supports({ :manage_home => true })
- new_resource.home('/Users/toor')
+ new_resource.manage_home true
+ new_resource.home("/Users/toor")
provider.current_resource = current_resource
end
it "deletes the home directory when resource#home is nil" do
new_resource.instance_variable_set(:@home, nil)
- expect(provider).to receive(:run_dscl).with("delete /Users/toor NFSHomeDirectory").and_return(true)
+ expect(provider).to receive(:run_dscl).with("delete", "/Users/toor", "NFSHomeDirectory").and_return(true)
provider.dscl_set_home
end
-
it "raises InvalidHomeDirectory when the resource's home directory doesn't look right" do
- new_resource.home('epic-fail')
+ new_resource.home("epic-fail")
expect { provider.dscl_set_home }.to raise_error(Chef::Exceptions::InvalidHomeDirectory)
end
it "moves the users home to the new location if it exists and the target location is different" do
- new_resource.supports(:manage_home => true)
+ new_resource.manage_home true
- current_home = CHEF_SPEC_DATA + '/old_home_dir'
- current_home_files = [current_home + '/my-dot-emacs', current_home + '/my-dot-vim']
+ current_home = CHEF_SPEC_DATA + "/old_home_dir"
+ current_home_files = [current_home + "/my-dot-emacs", current_home + "/my-dot-vim"]
current_resource.home(current_home)
new_resource.gid(23)
- allow(::File).to receive(:exists?).with('/old/home/toor').and_return(true)
- allow(::File).to receive(:exists?).with('/Users/toor').and_return(true)
+ allow(::File).to receive(:exist?).with("/old/home/toor").and_return(true)
+ allow(::File).to receive(:exist?).with("/Users/toor").and_return(true)
+ allow(::File).to receive(:exist?).with(current_home).and_return(true)
- expect(FileUtils).to receive(:mkdir_p).with('/Users/toor').and_return(true)
+ expect(FileUtils).to receive(:mkdir_p).with("/Users/toor").and_return(true)
expect(FileUtils).to receive(:rmdir).with(current_home)
- expect(::Dir).to receive(:glob).with("#{CHEF_SPEC_DATA}/old_home_dir/*",::File::FNM_DOTMATCH).and_return(current_home_files)
- expect(FileUtils).to receive(:mv).with(current_home_files, "/Users/toor", :force => true)
- expect(FileUtils).to receive(:chown_R).with('toor','23','/Users/toor')
+ expect(::Dir).to receive(:glob).with("#{CHEF_SPEC_DATA}/old_home_dir/*", ::File::FNM_DOTMATCH).and_return(current_home_files)
+ expect(FileUtils).to receive(:mv).with(current_home_files, "/Users/toor", force: true)
+ expect(FileUtils).to receive(:chown_R).with("toor", "23", "/Users/toor")
- expect(provider).to receive(:run_dscl).with("create /Users/toor NFSHomeDirectory '/Users/toor'")
+ expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "NFSHomeDirectory", "/Users/toor")
provider.dscl_set_home
end
it "should raise an exception when the systems user template dir (skel) cannot be found" do
- allow(::File).to receive(:exists?).and_return(false,false,false)
+ allow(::File).to receive(:exist?).and_return(false, false, false)
expect { provider.dscl_set_home }.to raise_error(Chef::Exceptions::User)
end
it "should run ditto to copy any missing files from skel to the new home dir" do
- expect(::File).to receive(:exists?).with("/System/Library/User\ Template/English.lproj").and_return(true)
- expect(FileUtils).to receive(:chown_R).with('toor', '', '/Users/toor')
- expect(provider).to receive(:shell_out!).with("ditto '/System/Library/User Template/English.lproj' '/Users/toor'")
+ expect(::File).to receive(:exist?).with("/System/Library/User\ Template/English.lproj").and_return(true)
+ expect(FileUtils).to receive(:chown_R).with("toor", "", "/Users/toor")
+ expect(provider).to receive(:shell_out!).with("ditto", "/System/Library/User Template/English.lproj", "/Users/toor")
provider.ditto_home
end
it "creates the user's NFSHomeDirectory and home directory" do
- expect(provider).to receive(:run_dscl).with("create /Users/toor NFSHomeDirectory '/Users/toor'").and_return(true)
+ expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "NFSHomeDirectory", "/Users/toor").and_return(true)
expect(provider).to receive(:ditto_home)
provider.dscl_set_home
end
@@ -280,8 +281,8 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
let(:plutil_exists) { true }
before do
- allow(::File).to receive(:exists?).with("/usr/bin/dscl").and_return(dscl_exists)
- allow(::File).to receive(:exists?).with("/usr/bin/plutil").and_return(plutil_exists)
+ allow(::File).to receive(:exist?).with("/usr/bin/dscl").and_return(dscl_exists)
+ allow(::File).to receive(:exist?).with("/usr/bin/plutil").and_return(plutil_exists)
end
def run_requirements
@@ -294,7 +295,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
let(:dscl_exists) { false }
it "should raise an error" do
- expect { run_requirements }.to raise_error
+ expect { run_requirements }.to raise_error(Chef::Exceptions::User)
end
end
@@ -302,24 +303,24 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
let(:plutil_exists) { false }
it "should raise an error" do
- expect { run_requirements }.to raise_error
+ expect { run_requirements }.to raise_error(Chef::Exceptions::User)
end
end
describe "when on Mac 10.6" do
- let(:mac_version) {
+ let(:mac_version) do
"10.6.5"
- }
+ end
it "should raise an error" do
- expect { run_requirements }.to raise_error
+ expect { run_requirements }.to raise_error(Chef::Exceptions::User)
end
end
describe "when on Mac 10.7" do
- let(:mac_version) {
+ let(:mac_version) do
"10.7.5"
- }
+ end
describe "when password is SALTED-SHA512" do
let(:password) { salted_sha512_password }
@@ -333,22 +334,22 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
let(:password) { salted_sha512_pbkdf2_password }
it "should raise an error" do
- expect { run_requirements }.to raise_error
+ expect { run_requirements }.to raise_error(Chef::Exceptions::User)
end
end
end
[ "10.9", "10.10"].each do |version|
describe "when on Mac #{version}" do
- let(:mac_version) {
+ let(:mac_version) do
"#{version}.2"
- }
+ end
describe "when password is SALTED-SHA512" do
let(:password) { salted_sha512_password }
it "should raise an error" do
- expect { run_requirements }.to raise_error
+ expect { run_requirements }.to raise_error(Chef::Exceptions::User)
end
end
@@ -357,7 +358,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
describe "when salt and iteration is not set" do
it "should raise an error" do
- expect { run_requirements }.to raise_error
+ expect { run_requirements }.to raise_error(Chef::Exceptions::User)
end
end
@@ -379,16 +380,16 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
let(:user_plist_file) { nil }
before do
- expect(provider).to receive(:shell_out).with("dscacheutil '-flushcache'")
- expect(provider).to receive(:shell_out).with("plutil -convert xml1 -o - /var/db/dslocal/nodes/Default/users/toor.plist") do
+ expect(provider).to receive(:shell_out).with("dscacheutil", "-flushcache")
+ expect(provider).to receive(:shell_out).with("plutil", "-convert", "xml1", "-o", "-", "/var/db/dslocal/nodes/Default/users/toor.plist") do
if user_plist_file.nil?
- ShellCmdResult.new('Can not find the file', 'Sorry!!', 1)
+ shellcmdresult.new("Can not find the file", "Sorry!!", 1)
else
- ShellCmdResult.new(File.read(File.join(CHEF_SPEC_DATA, "mac_users/#{user_plist_file}.plist.xml")), "", 0)
+ shellcmdresult.new(File.read(File.join(CHEF_SPEC_DATA, "mac_users/#{user_plist_file}.plist.xml")), "", 0)
end
end
- if !user_plist_file.nil?
+ unless user_plist_file.nil?
expect(provider).to receive(:convert_binary_plist_to_xml).and_return(File.read(File.join(CHEF_SPEC_DATA, "mac_users/#{user_plist_file}.shadow.xml")))
end
end
@@ -413,9 +414,9 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
let(:password) { "something" } # Load password during load_current_resource
describe "on 10.7" do
- let(:mac_version) {
+ let(:mac_version) do
"10.7.5"
- }
+ end
let(:user_plist_file) { "10.7" }
@@ -478,9 +479,9 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
end
describe "on 10.8" do
- let(:mac_version) {
+ let(:mac_version) do
"10.8.3"
- }
+ end
let(:user_plist_file) { "10.8" }
@@ -504,9 +505,9 @@ e68d1f9821b26689312366")
describe "on 10.7 upgraded to 10.8" do
# In this scenario user password is still in 10.7 format
- let(:mac_version) {
+ let(:mac_version) do
"10.8.3"
- }
+ end
let(:user_plist_file) { "10.7-8" }
@@ -542,9 +543,9 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
end
describe "on 10.9" do
- let(:mac_version) {
+ let(:mac_version) do
"10.9.1"
- }
+ end
let(:user_plist_file) { "10.9" }
@@ -646,9 +647,9 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
describe "prepare_password_shadow_info" do
describe "when on Mac 10.7" do
- let(:mac_version) {
+ let(:mac_version) do
"10.7.1"
- }
+ end
describe "when the password is plain text" do
let(:password) { "vagrant" }
@@ -656,7 +657,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
it "password_shadow_info should have salted-sha-512 format" do
shadow_info = provider.prepare_password_shadow_info
expect(shadow_info).to have_key("SALTED-SHA512")
- info = shadow_info["SALTED-SHA512"].string.unpack('H*').first
+ info = shadow_info["SALTED-SHA512"].string.unpack("H*").first
expect(provider.salted_sha512?(info)).to be_truthy
end
end
@@ -667,7 +668,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
it "password_shadow_info should have salted-sha-512 format" do
shadow_info = provider.prepare_password_shadow_info
expect(shadow_info).to have_key("SALTED-SHA512")
- info = shadow_info["SALTED-SHA512"].string.unpack('H*').first
+ info = shadow_info["SALTED-SHA512"].string.unpack("H*").first
expect(provider.salted_sha512?(info)).to be_truthy
expect(info).to eq(vagrant_sha_512)
end
@@ -676,9 +677,9 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
["10.8", "10.9", "10.10"].each do |version|
describe "when on Mac #{version}" do
- let(:mac_version) {
+ let(:mac_version) do
"#{version}.1"
- }
+ end
describe "when the password is plain text" do
let(:password) { "vagrant" }
@@ -689,7 +690,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
expect(shadow_info["SALTED-SHA512-PBKDF2"]).to have_key("entropy")
expect(shadow_info["SALTED-SHA512-PBKDF2"]).to have_key("salt")
expect(shadow_info["SALTED-SHA512-PBKDF2"]).to have_key("iterations")
- info = shadow_info["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack('H*').first
+ info = shadow_info["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack("H*").first
expect(provider.salted_sha512_pbkdf2?(info)).to be_truthy
end
end
@@ -705,7 +706,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
expect(shadow_info["SALTED-SHA512-PBKDF2"]).to have_key("entropy")
expect(shadow_info["SALTED-SHA512-PBKDF2"]).to have_key("salt")
expect(shadow_info["SALTED-SHA512-PBKDF2"]).to have_key("iterations")
- info = shadow_info["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack('H*').first
+ info = shadow_info["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack("H*").first
expect(provider.salted_sha512_pbkdf2?(info)).to be_truthy
expect(info).to eq(vagrant_sha_512_pbkdf2)
end
@@ -720,10 +721,10 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
end
it "should sleep and flush the dscl cache before saving the password" do
- expect(provider).to receive(:prepare_password_shadow_info).and_return({ })
+ expect(provider).to receive(:prepare_password_shadow_info).and_return({})
mock_shellout = double("Mock::Shellout")
allow(mock_shellout).to receive(:run_command)
- expect(Mixlib::ShellOut).to receive(:new).and_return(mock_shellout)
+ expect(provider).to receive(:shell_out).and_return(mock_shellout)
expect(provider).to receive(:read_user_info)
expect(provider).to receive(:dscl_set)
expect(provider).to receive(:sleep).with(3)
@@ -751,29 +752,29 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
end
it "creates the user and sets the comment field" do
- expect(provider).to receive(:run_dscl).with("create /Users/toor").and_return(true)
+ expect(provider).to receive(:run_dscl).with("create", "/Users/toor").and_return(true)
provider.dscl_create_user
end
it "sets the comment field" do
- expect(provider).to receive(:run_dscl).with("create /Users/toor RealName '#mockssuck'").and_return(true)
+ expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "RealName", "#mockssuck").and_return(true)
provider.dscl_create_comment
end
it "sets the comment field to username" do
new_resource.comment nil
- expect(provider).to receive(:run_dscl).with("create /Users/toor RealName '#mockssuck'").and_return(true)
+ expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "RealName", "#mockssuck").and_return(true)
provider.dscl_create_comment
expect(new_resource.comment).to eq("#mockssuck")
end
it "should run run_dscl with create /Users/user PrimaryGroupID to set the users primary group" do
- expect(provider).to receive(:run_dscl).with("create /Users/toor PrimaryGroupID '1001'").and_return(true)
+ expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "PrimaryGroupID", 1001).and_return(true)
provider.dscl_set_gid
end
it "should run run_dscl with create /Users/user UserShell to set the users login shell" do
- expect(provider).to receive(:run_dscl).with("create /Users/toor UserShell '/usr/bin/false'").and_return(true)
+ expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "UserShell", "/usr/bin/false").and_return(true)
provider.dscl_set_shell
end
end
@@ -785,21 +786,21 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
end
it "should map the group name to a numeric ID when the group exists" do
- expect(provider).to receive(:run_dscl).with("read /Groups/newgroup PrimaryGroupID").ordered.and_return("PrimaryGroupID: 1001\n")
- expect(provider).to receive(:run_dscl).with("create /Users/toor PrimaryGroupID '1001'").ordered.and_return(true)
+ expect(provider).to receive(:run_dscl).with("read", "/Groups/newgroup", "PrimaryGroupID").ordered.and_return("PrimaryGroupID: 1001\n")
+ expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "PrimaryGroupID", "1001").ordered.and_return(true)
provider.dscl_set_gid
end
it "should raise an exception when the group does not exist" do
- shell_return = ShellCmdResult.new("<dscl_cmd> DS Error: -14136 (eDSRecordNotFound)", 'err', -14136)
- expect(provider).to receive(:shell_out).with('dscl . -read /Groups/newgroup PrimaryGroupID').and_return(shell_return)
+ shell_return = shellcmdresult.new("<dscl_cmd> DS Error: -14136 (eDSRecordNotFound)", "err", -14136)
+ expect(provider).to receive(:shell_out).with("dscl", ".", "-read", "/Groups/newgroup", "PrimaryGroupID").and_return(shell_return)
expect { provider.dscl_set_gid }.to raise_error(Chef::Exceptions::GroupIDNotFound)
end
end
it "should set group ID to 20 if it's not specified" do
new_resource.gid nil
- expect(provider).to receive(:run_dscl).with("create /Users/toor PrimaryGroupID '20'").ordered.and_return(true)
+ expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "PrimaryGroupID", 20).ordered.and_return(true)
provider.dscl_set_gid
expect(new_resource.gid).to eq(20)
end
@@ -814,8 +815,8 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
new_resource.username "mud"
new_resource.uid 2342
new_resource.gid 2342
- new_resource.home '/Users/death'
- new_resource.password 'goaway'
+ new_resource.home "/Users/death"
+ new_resource.password "goaway"
end
it "sets the user, comment field, uid, gid, moves the home directory, sets the shell, and sets the password" do
@@ -847,22 +848,22 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
describe "when the user exists" do
before do
- expect(provider).to receive(:shell_out).with("dscacheutil '-flushcache'")
- expect(provider).to receive(:shell_out).with("plutil -convert xml1 -o - /var/db/dslocal/nodes/Default/users/toor.plist") do
- ShellCmdResult.new(File.read(File.join(CHEF_SPEC_DATA, "mac_users/10.9.plist.xml")), "", 0)
+ expect(provider).to receive(:shell_out).with("dscacheutil", "-flushcache")
+ expect(provider).to receive(:shell_out).with("plutil", "-convert", "xml1", "-o", "-", "/var/db/dslocal/nodes/Default/users/toor.plist") do
+ shellcmdresult.new(File.read(File.join(CHEF_SPEC_DATA, "mac_users/10.9.plist.xml")), "", 0)
end
provider.load_current_resource
end
describe "when Chef is removing the user" do
it "removes the user from the groups and deletes home directory when the resource is configured to manage home" do
- new_resource.supports({ :manage_home => true })
- expect(provider).to receive(:run_dscl).with("list /Groups").and_return("my_group\nyour_group\nreal_group\n")
- expect(provider).to receive(:run_dscl).with("read /Groups/my_group").and_raise(Chef::Exceptions::DsclCommandFailed) # Empty group
- expect(provider).to receive(:run_dscl).with("read /Groups/your_group").and_return("GroupMembership: not_you")
- expect(provider).to receive(:run_dscl).with("read /Groups/real_group").and_return("GroupMembership: toor")
- expect(provider).to receive(:run_dscl).with("delete /Groups/real_group GroupMembership 'toor'")
- expect(provider).to receive(:run_dscl).with("delete /Users/toor")
+ new_resource.manage_home true
+ expect(provider).to receive(:run_dscl).with("list", "/Groups").and_return("my_group\nyour_group\nreal_group\n")
+ expect(provider).to receive(:run_dscl).with("read", "/Groups/my_group").and_raise(Chef::Exceptions::DsclCommandFailed) # Empty group
+ expect(provider).to receive(:run_dscl).with("read", "/Groups/your_group").and_return("GroupMembership: not_you")
+ expect(provider).to receive(:run_dscl).with("read", "/Groups/real_group").and_return("GroupMembership: toor")
+ expect(provider).to receive(:run_dscl).with("delete", "/Groups/real_group", "GroupMembership", "toor")
+ expect(provider).to receive(:run_dscl).with("delete", "/Users/toor")
expect(FileUtils).to receive(:rm_rf).with("/Users/vagrant")
provider.remove_user
end
@@ -885,7 +886,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
end
it "can unlock the user" do
- expect(provider).to receive(:run_dscl).with("create /Users/toor AuthenticationAuthority ';ShadowHash;HASHLIST:<SALTED-SHA512-PBKDF2>'")
+ expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "AuthenticationAuthority", ";ShadowHash;HASHLIST:<SALTED-SHA512-PBKDF2>")
provider.unlock_user
end
end
@@ -893,7 +894,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
describe "when locking the user" do
it "should run run_dscl with append /Users/user AuthenticationAuthority ;DisabledUser; to lock the user account" do
- expect(provider).to receive(:run_dscl).with("append /Users/toor AuthenticationAuthority ';DisabledUser;'")
+ expect(provider).to receive(:run_dscl).with("append", "/Users/toor", "AuthenticationAuthority", ";DisabledUser;")
provider.lock_user
end
end
diff --git a/spec/unit/provider/user/linux_spec.rb b/spec/unit/provider/user/linux_spec.rb
new file mode 100644
index 0000000000..b04ada2511
--- /dev/null
+++ b/spec/unit/provider/user/linux_spec.rb
@@ -0,0 +1,112 @@
+#
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+#
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/provider/user/useradd"
+
+describe Chef::Provider::User::Linux do
+
+ subject(:provider) do
+ p = described_class.new(@new_resource, @run_context)
+ p.current_resource = @current_resource
+ p
+ end
+
+ supported_useradd_options = {
+ "comment" => "-c",
+ "gid" => "-g",
+ "uid" => "-u",
+ "shell" => "-s",
+ "password" => "-p",
+ }
+
+ include_examples "a useradd-based user provider", supported_useradd_options
+
+ describe "manage_home behavior" do
+ before(:each) do
+ @new_resource = Chef::Resource::User::LinuxUser.new("adam", @run_context)
+ @current_resource = Chef::Resource::User::LinuxUser.new("adam", @run_context)
+ end
+
+ it "supports manage_home does not exist", chef: ">= 13" do
+ expect( @new_resource.supports.key?(:manage_home) ).to be false
+ end
+
+ it "supports non_unique does not exist", chef: ">= 13" do
+ expect( @new_resource.supports.key?(:non_unique) ).to be false
+ end
+
+ # supports is a method on the superclass so can't totally be removed, but we should aggressively NOP it to decisively break it
+ it "disables the supports API", chef: ">= 13" do
+ @new_resource.supports( manage_home: true )
+ expect( @new_resource.supports.key?(:manage_home) ).to be false
+ end
+
+ it "sets supports manage_home to false" do
+ expect( @new_resource.supports[:manage_home] ).to be false
+ end
+
+ it "sets supports non-unique to false" do
+ expect( @new_resource.supports[:non_unique] ).to be false
+ end
+
+ it "throws a deprecation warning on setting supports[:non_unique]" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(Chef).to receive(:deprecated).with(:supports_property, "supports { non_unique: true } on the user resource is deprecated and will be removed in Chef 13, set non_unique true instead")
+ @new_resource.supports( non_unique: true )
+ end
+
+ it "throws a deprecation warning on setting supports[:manage_home]" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(Chef).to receive(:deprecated).with(:supports_property, "supports { manage_home: true } on the user resource is deprecated and will be removed in Chef 13, set manage_home true instead")
+ @new_resource.supports( manage_home: true )
+ end
+
+ it "defaults manage_home to false" do
+ expect( @new_resource.manage_home ).to be false
+ end
+
+ it "supports[:manage_home] (incorectly) acts like manage_home" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ @new_resource.supports(manage_home: true)
+ expect( provider.useradd_options ).to eql(["-m"])
+ end
+
+ it "supports[:manage_home] does not change behavior of manage_home: false", chef: ">= 13" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ @new_resource.supports(manage_home: true)
+ expect( provider.useradd_options ).to eql(["-M"])
+ end
+
+ it "by default manage_home is false and we use -M" do
+ expect( provider.useradd_options ).to eql(["-M"])
+ end
+
+ it "setting manage_home to false includes -M" do
+ @new_resource.manage_home false
+ expect( provider.useradd_options ).to eql(["-M"])
+ end
+
+ it "setting manage_home to true includes -m" do
+ @new_resource.manage_home true
+ expect( provider.useradd_options ).to eql(["-m"])
+ end
+ end
+end
diff --git a/spec/unit/provider/user/pw_spec.rb b/spec/unit/provider/user/pw_spec.rb
index b225972e87..2f44d6f3e3 100644
--- a/spec/unit/provider/user/pw_spec.rb
+++ b/spec/unit/provider/user/pw_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Stephen Haynes (<sh@nomitor.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::User::Pw do
before(:each) do
@@ -24,7 +24,7 @@ describe Chef::Provider::User::Pw do
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::User.new("adam")
+ @new_resource = Chef::Resource::User::PwUser.new("adam")
@new_resource.comment "Adam Jacob"
@new_resource.uid 1000
@new_resource.gid 1000
@@ -32,9 +32,11 @@ describe Chef::Provider::User::Pw do
@new_resource.shell "/usr/bin/zsh"
@new_resource.password "abracadabra"
- @new_resource.supports :manage_home => true
+ # XXX: rip out in Chef-13
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ @new_resource.supports manage_home: true
- @current_resource = Chef::Resource::User.new("adam")
+ @current_resource = Chef::Resource::User::PwUser.new("adam")
@current_resource.comment "Adam Jacob"
@current_resource.uid 1000
@current_resource.gid 1000
@@ -48,11 +50,11 @@ describe Chef::Provider::User::Pw do
describe "setting options to the pw command" do
field_list = {
- 'comment' => "-c",
- 'home' => "-d",
- 'gid' => "-g",
- 'uid' => "-u",
- 'shell' => "-s"
+ "comment" => "-c",
+ "home" => "-d",
+ "gid" => "-g",
+ "uid" => "-u",
+ "shell" => "-s",
}
field_list.each do |attribute, option|
it "should check for differences in #{attribute} between the new and current resources" do
@@ -63,35 +65,36 @@ describe Chef::Provider::User::Pw do
it "should set the option for #{attribute} if the new resources #{attribute} is not null" do
allow(@new_resource).to receive(attribute).and_return("hola")
- expect(@provider.set_options).to eql(" #{@new_resource.username} #{option} '#{@new_resource.send(attribute)}' -m")
+ expect(@provider.set_options).to eql([ @new_resource.username, option, @new_resource.send(attribute), "-m"])
end
it "should set the option for #{attribute} if the new resources #{attribute} is not null, without homedir management" do
- allow(@new_resource).to receive(:supports).and_return({:manage_home => false})
+ allow(@new_resource).to receive(:supports).and_return(manage_home: false)
allow(@new_resource).to receive(attribute).and_return("hola")
- expect(@provider.set_options).to eql(" #{@new_resource.username} #{option} '#{@new_resource.send(attribute)}'")
+ expect(@provider.set_options).to eql([@new_resource.username, option, @new_resource.send(attribute)])
end
end
it "should combine all the possible options" do
- match_string = " adam"
- field_list.sort{ |a,b| a[0] <=> b[0] }.each do |attribute, option|
+ match_array = [ "adam" ]
+ field_list.sort { |a, b| a[0] <=> b[0] }.each do |attribute, option|
allow(@new_resource).to receive(attribute).and_return("hola")
- match_string << " #{option} 'hola'"
+ match_array << option
+ match_array << "hola"
end
- match_string << " -m"
- expect(@provider.set_options).to eql(match_string)
+ match_array << "-m"
+ expect(@provider.set_options).to eql(match_array)
end
end
describe "create_user" do
before(:each) do
- allow(@provider).to receive(:run_command).and_return(true)
+ allow(@provider).to receive(:shell_out!).and_return(true)
allow(@provider).to receive(:modify_password).and_return(true)
end
it "should run pw useradd with the return of set_options" do
- expect(@provider).to receive(:run_command).with({ :command => "pw useradd adam -m" }).and_return(true)
+ expect(@provider).to receive(:shell_out!).with("pw", "useradd", "adam", "-m").and_return(true)
@provider.create_user
end
@@ -103,12 +106,12 @@ describe Chef::Provider::User::Pw do
describe "manage_user" do
before(:each) do
- allow(@provider).to receive(:run_command).and_return(true)
+ allow(@provider).to receive(:shell_out!).and_return(true)
allow(@provider).to receive(:modify_password).and_return(true)
end
it "should run pw usermod with the return of set_options" do
- expect(@provider).to receive(:run_command).with({ :command => "pw usermod adam -m" }).and_return(true)
+ expect(@provider).to receive(:shell_out!).with("pw", "usermod", "adam", "-m").and_return(true)
@provider.manage_user
end
@@ -120,13 +123,13 @@ describe Chef::Provider::User::Pw do
describe "remove_user" do
it "should run pw userdel with the new resources user name" do
- @new_resource.supports :manage_home => false
- expect(@provider).to receive(:run_command).with({ :command => "pw userdel #{@new_resource.username}" }).and_return(true)
+ @new_resource.supports manage_home: false
+ expect(@provider).to receive(:shell_out!).with("pw", "userdel", @new_resource.username).and_return(true)
@provider.remove_user
end
it "should run pw userdel with the new resources user name and -r if manage_home is true" do
- expect(@provider).to receive(:run_command).with({ :command => "pw userdel #{@new_resource.username} -r"}).and_return(true)
+ expect(@provider).to receive(:shell_out!).with("pw", "userdel", @new_resource.username, "-r").and_return(true)
@provider.remove_user
end
end
@@ -145,23 +148,26 @@ describe Chef::Provider::User::Pw do
describe "when locking the user" do
it "should run pw lock with the new resources username" do
- expect(@provider).to receive(:run_command).with({ :command => "pw lock #{@new_resource.username}"})
+ expect(@provider).to receive(:shell_out!).with("pw", "lock", @new_resource.username)
@provider.lock_user
end
end
describe "when unlocking the user" do
it "should run pw unlock with the new resources username" do
- expect(@provider).to receive(:run_command).with({ :command => "pw unlock #{@new_resource.username}"})
+ expect(@provider).to receive(:shell_out!).with("pw", "unlock", @new_resource.username)
@provider.unlock_user
end
end
describe "when modifying the password" do
before(:each) do
- @status = double("Status", :exitstatus => 0)
+ @status = double("Status", exitstatus: 0)
allow(@provider).to receive(:popen4).and_return(@status)
- @pid, @stdin, @stdout, @stderr = nil, nil, nil, nil
+ @pid = nil
+ @stdin = nil
+ @stdout = nil
+ @stderr = nil
end
describe "and the new password has not been specified" do
@@ -170,7 +176,6 @@ describe Chef::Provider::User::Pw do
end
it "logs an appropriate message" do
- expect(Chef::Log).to receive(:debug).with("user[adam] no change needed to password")
@provider.modify_password
end
end
@@ -194,7 +199,6 @@ describe Chef::Provider::User::Pw do
end
it "logs an appropriate message" do
- expect(Chef::Log).to receive(:debug).with("user[adam] no change needed to password")
@provider.modify_password
end
end
@@ -206,12 +210,11 @@ describe Chef::Provider::User::Pw do
end
it "should log an appropriate message" do
- expect(Chef::Log).to receive(:debug).with("user[adam] updating password")
@provider.modify_password
end
it "should run pw usermod with the username and the option -H 0" do
- expect(@provider).to receive(:popen4).with("pw usermod adam -H 0", :waitlast => true).and_return(@status)
+ expect(@provider).to receive(:popen4).with("pw usermod adam -H 0", waitlast: true).and_return(@status)
@provider.modify_password
end
@@ -236,16 +239,16 @@ describe Chef::Provider::User::Pw do
describe "when loading the current state" do
before do
- @provider.new_resource = Chef::Resource::User.new("adam")
+ @provider.new_resource = Chef::Resource::User::PwUser.new("adam")
end
it "should raise an error if the required binary /usr/sbin/pw doesn't exist" do
- expect(File).to receive(:exists?).with("/usr/sbin/pw").and_return(false)
+ expect(File).to receive(:exist?).with("/usr/sbin/pw").and_return(false)
expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::User)
end
it "shouldn't raise an error if /usr/sbin/pw exists" do
- allow(File).to receive(:exists?).and_return(true)
+ allow(File).to receive(:exist?).and_return(true)
expect { @provider.load_current_resource }.not_to raise_error
end
end
diff --git a/spec/unit/provider/user/solaris_spec.rb b/spec/unit/provider/user/solaris_spec.rb
index a3c17a9a56..1935336308 100644
--- a/spec/unit/provider/user/solaris_spec.rb
+++ b/spec/unit/provider/user/solaris_spec.rb
@@ -1,9 +1,9 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
# Author:: Dave Eddy (<dave@daveeddy.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
-# Copyright:: Copyright (c) 2015, Dave Eddy
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2015-2016, Dave Eddy
#
# License:: Apache License, Version 2.0
#
@@ -20,33 +20,40 @@
# limitations under the License.
#
-ShellCmdResult = Struct.new(:stdout, :stderr, :exitstatus)
-
-require 'mixlib/shellout'
-require 'spec_helper'
+require "mixlib/shellout"
+require "spec_helper"
describe Chef::Provider::User::Solaris do
- subject(:provider) do
- p = described_class.new(@new_resource, @run_context)
- p.current_resource = @current_resource
+ let(:shellcmdresult) do
+ Struct.new(:stdout, :stderr, :exitstatus)
+ end
+
+ let(:node) do
+ Chef::Node.new.tap do |node|
+ node.automatic["platform"] = "solaris2"
+ end
+ end
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:new_resource) do
+ Chef::Resource::User::SolarisUser.new("adam", @run_context)
+ end
+ let(:current_resource) do
+ Chef::Resource::User::SolarisUser.new("adam", @run_context)
+ end
- # Prevent the useradd-based provider tests from trying to write /etc/shadow
- allow(p).to receive(:write_shadow_file)
- p
+ subject(:provider) do
+ described_class.new(new_resource, run_context).tap do |p|
+ p.current_resource = current_resource
+ # Prevent the useradd-based provider tests from trying to write /etc/shadow
+ allow(p).to receive(:write_shadow_file)
+ end
end
describe "when we want to set a password" do
before(:each) do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
-
- @new_resource = Chef::Resource::User.new("adam", @run_context)
- @current_resource = Chef::Resource::User.new("adam", @run_context)
-
- @new_resource.password "hocus-pocus"
-
+ new_resource.password "hocus-pocus"
end
it "should use its own shadow file writer to set the password" do
@@ -66,70 +73,104 @@ describe Chef::Provider::User::Solaris do
# may not be able to write to /etc for tests...
temp_file = Tempfile.new("shadow")
allow(Tempfile).to receive(:new).with("shadow", "/etc").and_return(temp_file)
- @new_resource.password "verysecurepassword"
+ new_resource.password "verysecurepassword"
provider.manage_user
expect(::File.open(password_file.path, "r").read).to match(/adam:verysecurepassword:/)
password_file.unlink
end
end
- describe 'when managing user locked status' do
- before(:each) do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
+ describe "#create_user" do
+ context "with a system user" do
+ before { new_resource.system(true) }
+ it "should not pass -r" do
+ expect(provider).to receive(:shell_out!).with("useradd", "adam")
+ provider.create_user
+ end
+ end
- @new_resource = Chef::Resource::User.new('dave')
- @current_resource = @new_resource.dup
+ context "with manage_home" do
+ before { new_resource.manage_home(true) }
+ it "should not pass -r" do
+ expect(provider).to receive(:shell_out!).with("useradd", "-m", "adam")
+ provider.create_user
+ end
+ end
+ end
- @provider = Chef::Provider::User::Solaris.new(@new_resource, @run_context)
- @provider.current_resource = @current_resource
+ describe "when managing user locked status" do
+ let(:user_lock) { "adam:FOO:::::::" }
+ let(:shadow_file_contents) do
+ %W{
+ user1:LK:::::::
+ #{user_lock}
+ user2:NP:::::::
+ }
end
- describe 'when determining if the user is locked' do
+
+ describe "when determining if the user is locked" do
+ before do
+ allow(IO).to receive(:read).and_return(shadow_file_contents.join("\n"))
+ end
+
+ context "when user does not exist" do
+ let(:user_lock) { "other_user:FOO:::::::" }
+
+ it "should raise a sensible error" do
+ expect { provider.check_lock }.to raise_error(Chef::Exceptions::User)
+ end
+ end
# locked shadow lines
[
- 'dave:LK:::::::',
- 'dave:*LK*:::::::',
- 'dave:*LK*foobar:::::::',
- 'dave:*LK*bahamas10:::::::',
- 'dave:*LK*L....:::::::',
+ "adam:*LK*:::::::",
+ "adam:*LK*foobar:::::::",
+ "adam:*LK*bahamas10:::::::",
+ "adam:*LK*goonawaLK:::::::",
+ "adam:*LK*LKgir:::::::",
+ "adam:*LK*L....:::::::",
].each do |shadow|
- it "should return true if user is locked with #{shadow}" do
- shell_return = ShellCmdResult.new(shadow + "\n", '', 0)
- expect(provider).to receive(:shell_out!).with('getent', 'shadow', @new_resource.username).and_return(shell_return)
- expect(provider.check_lock).to eql(true)
+ context "for user 'adam' with entry '#{shadow}'" do
+ let(:user_lock) { shadow }
+
+ it "should return true" do
+ expect(provider.check_lock).to eql(true)
+ end
end
end
# unlocked shadow lines
[
- 'dave:NP:::::::',
- 'dave:*NP*:::::::',
- 'dave:foobar:::::::',
- 'dave:bahamas10:::::::',
- 'dave:L...:::::::',
+ "adam:NP:::::::",
+ "adam:*NP*:::::::",
+ "adam:foobar:::::::",
+ "adam:bahamas10:::::::",
+ "adam:goonawaLK:::::::",
+ "adam:LKgir:::::::",
+ "adam:L...:::::::",
].each do |shadow|
- it "should return false if user is unlocked with #{shadow}" do
- shell_return = ShellCmdResult.new(shadow + "\n", '', 0)
- expect(provider).to receive(:shell_out!).with('getent', 'shadow', @new_resource.username).and_return(shell_return)
- expect(provider.check_lock).to eql(false)
+ context "for user 'adam' with entry '#{shadow}'" do
+ let(:user_lock) { shadow }
+
+ it "should return false" do
+ expect(provider.check_lock).to eql(false)
+ end
end
end
end
- describe 'when locking the user' do
- it 'should run passwd -l with the new resources username' do
- shell_return = ShellCmdResult.new('', '', 0)
- expect(provider).to receive(:shell_out!).with('passwd', '-l', @new_resource.username).and_return(shell_return)
+ describe "when locking the user" do
+ it "should run passwd -l with the new resources username" do
+ shell_return = shellcmdresult.new("", "", 0)
+ expect(provider).to receive(:shell_out!).with("passwd", "-l", "adam").and_return(shell_return)
provider.lock_user
end
end
- describe 'when unlocking the user' do
- it 'should run passwd -u with the new resources username' do
- shell_return = ShellCmdResult.new('', '', 0)
- expect(provider).to receive(:shell_out!).with('passwd', '-u', @new_resource.username).and_return(shell_return)
+ describe "when unlocking the user" do
+ it "should run passwd -u with the new resources username" do
+ shell_return = shellcmdresult.new("", "", 0)
+ expect(provider).to receive(:shell_out!).with("passwd", "-u", "adam").and_return(shell_return)
provider.unlock_user
end
end
diff --git a/spec/unit/provider/user/useradd_spec.rb b/spec/unit/provider/user/useradd_spec.rb
deleted file mode 100644
index b9f6ee0d86..0000000000
--- a/spec/unit/provider/user/useradd_spec.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
-#
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'spec_helper'
-require 'chef/provider/user/useradd'
-
-describe Chef::Provider::User::Useradd do
-
- subject(:provider) do
- p = described_class.new(@new_resource, @run_context)
- p.current_resource = @current_resource
- p
- end
-
- supported_useradd_options = {
- 'comment' => "-c",
- 'gid' => "-g",
- 'uid' => "-u",
- 'shell' => "-s",
- 'password' => "-p"
- }
-
- include_examples "a useradd-based user provider", supported_useradd_options
-
- describe "manage_user" do
- # CHEF-5247: Chef::Provider::User::Solaris subclasses Chef::Provider::User::Useradd, but does not use usermod to change passwords.
- # Thus, a call to Solaris#manage_user calls Solaris#manage_password and Useradd#manage_user, but the latter should be a no-op.
- it "should not run the command if universal_options is an empty array" do
- allow(provider).to receive(:universal_options).and_return([])
- expect(provider).not_to receive(:shell_out!)
- provider.manage_user
- end
- end
-end
diff --git a/spec/unit/provider/user/windows_spec.rb b/spec/unit/provider/user/windows_spec.rb
index 7e08f971a9..82f3c1ab2a 100644
--- a/spec/unit/provider/user/windows_spec.rb
+++ b/spec/unit/provider/user/windows_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
class Chef
class Util
@@ -30,10 +30,10 @@ end
describe Chef::Provider::User::Windows do
before(:each) do
@node = Chef::Node.new
- @new_resource = Chef::Resource::User.new("monkey")
+ @new_resource = Chef::Resource::User::WindowsUser.new("monkey")
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @current_resource = Chef::Resource::User.new("monkey")
+ @current_resource = Chef::Resource::User::WindowsUser.new("monkey")
@net_user = double("Chef::Util::Windows::NetUser")
allow(Chef::Util::Windows::NetUser).to receive(:new).and_return(@net_user)
@@ -89,7 +89,7 @@ describe Chef::Provider::User::Windows do
describe "and the attributes do not match" do
before do
- @current_resource = Chef::Resource::User.new("adam")
+ @current_resource = Chef::Resource::User::WindowsUser.new("adam")
@current_resource.comment "Adam Jacob-foo"
@current_resource.uid 1111
@current_resource.gid 1111
@@ -104,7 +104,7 @@ describe Chef::Provider::User::Windows do
end
it "marks the home_dir attribute to be updated" do
- expect(@provider.set_options[:home_dir]).to eq('/home/adam')
+ expect(@provider.set_options[:home_dir]).to eq("/home/adam")
end
it "ignores the primary_group_id attribute" do
@@ -116,30 +116,30 @@ describe Chef::Provider::User::Windows do
end
it "marks the script_path attribute to be updated" do
- expect(@provider.set_options[:script_path]).to eq('/usr/bin/zsh')
+ expect(@provider.set_options[:script_path]).to eq("/usr/bin/zsh")
end
it "marks the password attribute to be updated" do
- expect(@provider.set_options[:password]).to eq('abracadabra')
+ expect(@provider.set_options[:password]).to eq("abracadabra")
end
end
end
describe "when creating the user" do
it "should call @net_user.add with the return of set_options" do
- allow(@provider).to receive(:set_options).and_return(:name=> "monkey")
- expect(@net_user).to receive(:add).with(:name=> "monkey")
+ allow(@provider).to receive(:set_options).and_return(name: "monkey")
+ expect(@net_user).to receive(:add).with(name: "monkey")
@provider.create_user
end
end
describe "manage_user" do
before(:each) do
- allow(@provider).to receive(:set_options).and_return(:name=> "monkey")
+ allow(@provider).to receive(:set_options).and_return(name: "monkey")
end
it "should call @net_user.update with the return of set_options" do
- expect(@net_user).to receive(:update).with(:name=> "monkey")
+ expect(@net_user).to receive(:update).with(name: "monkey")
@provider.manage_user
end
end
diff --git a/spec/unit/provider/user_spec.rb b/spec/unit/provider/user_spec.rb
index bd24a6a01e..489597445f 100644
--- a/spec/unit/provider/user_spec.rb
+++ b/spec/unit/provider/user_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
EtcPwnamIsh = Struct.new(:name, :passwd, :uid, :gid, :gecos, :dir, :shell, :change, :uclass, :expire)
EtcGrnamIsh = Struct.new(:name, :passwd, :gid, :mem)
@@ -58,7 +58,7 @@ describe Chef::Provider::User do
describe "executing load_current_resource" do
before(:each) do
@node = Chef::Node.new
- #@new_resource = double("Chef::Resource::User",
+ # @new_resource = double("Chef::Resource::User",
# :null_object => true,
# :username => "adam",
# :comment => "Adam Jacob",
@@ -68,7 +68,7 @@ describe Chef::Provider::User do
# :shell => "/usr/bin/zsh",
# :password => nil,
# :updated => nil
- #)
+ # )
allow(Chef::Resource::User).to receive(:new).and_return(@current_resource)
@pw_user = EtcPwnamIsh.new
@pw_user.name = "adam"
@@ -83,7 +83,7 @@ describe Chef::Provider::User do
it "should create a current resource with the same name as the new resource" do
@provider.load_current_resource
- expect(@provider.current_resource.name).to eq('adam')
+ expect(@provider.current_resource.name).to eq("adam")
end
it "should set the username of the current resource to the username of the new resource" do
@@ -92,7 +92,7 @@ describe Chef::Provider::User do
end
it "should change the encoding of gecos to the encoding of the new resource" do
- @pw_user.gecos.force_encoding('ASCII-8BIT')
+ @pw_user.gecos.force_encoding("ASCII-8BIT")
@provider.load_current_resource
expect(@provider.current_resource.comment.encoding).to eq(@new_resource.comment.encoding)
end
@@ -110,11 +110,11 @@ describe Chef::Provider::User do
# The mapping between the Chef::Resource::User and Getpwnam struct
user_attrib_map = {
- :uid => :uid,
- :gid => :gid,
- :comment => :gecos,
- :home => :dir,
- :shell => :shell
+ uid: :uid,
+ gid: :gid,
+ comment: :gecos,
+ home: :dir,
+ shell: :shell,
}
user_attrib_map.each do |user_attrib, getpwnam_attrib|
it "should set the current resources #{user_attrib} based on getpwnam #{getpwnam_attrib}" do
@@ -140,18 +140,16 @@ describe Chef::Provider::User do
describe "and running assertions" do
def self.shadow_lib_unavail?
- begin
- require 'rubygems'
- require 'shadow'
- rescue LoadError
- skip "ruby-shadow gem not installed for dynamic load test"
- true
- else
- false
- end
+ require "rubygems"
+ require "shadow"
+ rescue LoadError
+ skip "ruby-shadow gem not installed for dynamic load test"
+ true
+ else
+ false
end
- before (:each) do
+ before(:each) do
user = @pw_user.dup
user.name = "root"
user.passwd = "x"
@@ -161,15 +159,15 @@ describe Chef::Provider::User do
unless shadow_lib_unavail?
context "and we have the ruby-shadow gem" do
- skip "and we are not root (rerun this again as root)", :requires_unprivileged_user => true
+ skip "and we are not root (rerun this again as root)", requires_unprivileged_user: true
- context "and we are root", :requires_root => true do
+ context "and we are root", requires_root: true do
it "should pass assertions when ruby-shadow can be loaded" do
- @provider.action = 'create'
+ @provider.action = "create"
original_method = @provider.method(:require)
expect(@provider).to receive(:require) { |*args| original_method.call(*args) }
- passwd_info = Struct::PasswdEntry.new(:sp_namp => "adm ", :sp_pwdp => "$1$T0N0Q.lc$nyG6pFI3Dpqa5cxUz/57j0", :sp_lstchg => 14861, :sp_min => 0, :sp_max => 99999,
- :sp_warn => 7, :sp_inact => -1, :sp_expire => -1, :sp_flag => -1)
+ passwd_info = Struct::PasswdEntry.new(sp_namp: "adm ", sp_pwdp: "$1$T0N0Q.lc$nyG6pFI3Dpqa5cxUz/57j0", sp_lstchg: 14861, sp_min: 0, sp_max: 99999,
+ sp_warn: 7, sp_inact: -1, sp_expire: -1, sp_flag: -1)
expect(Shadow::Passwd).to receive(:getspnam).with("adam").and_return(passwd_info)
@provider.load_current_resource
@provider.define_resource_requirements
@@ -183,24 +181,24 @@ describe Chef::Provider::User do
expect(@provider).to receive(:require).with("shadow") { raise LoadError }
@provider.load_current_resource
@provider.define_resource_requirements
- expect {@provider.process_resource_requirements}.to raise_error Chef::Exceptions::MissingLibrary
+ expect { @provider.process_resource_requirements }.to raise_error Chef::Exceptions::MissingLibrary
end
end
end
describe "compare_user" do
- let(:mapping) {
+ let(:mapping) do
{
- 'username' => ["adam", "Adam"],
- 'comment' => ["Adam Jacob", "adam jacob"],
- 'uid' => [1000, 1001],
- 'gid' => [1000, 1001],
- 'home' => ["/home/adam", "/Users/adam"],
- 'shell'=> ["/usr/bin/zsh", "/bin/bash"],
- 'password'=> ["abcd","12345"]
+ "username" => %w{adam Adam},
+ "comment" => ["Adam Jacob", "adam jacob"],
+ "uid" => [1000, 1001],
+ "gid" => [1000, 1001],
+ "home" => ["/home/adam", "/Users/adam"],
+ "shell" => ["/usr/bin/zsh", "/bin/bash"],
+ "password" => %w{abcd 12345},
}
- }
+ end
%w{uid gid comment home shell password}.each do |attribute|
it "should return true if #{attribute} doesn't match" do
@@ -221,6 +219,12 @@ describe Chef::Provider::User do
it "should return false if the objects are identical" do
expect(@provider.compare_user).to eql(false)
end
+
+ it "should ignore differences in trailing slash in home paths" do
+ @new_resource.home "/home/adam"
+ @current_resource.home "/home/adam/"
+ expect(@provider.compare_user).to eql(false)
+ end
end
describe "action_create" do
@@ -380,7 +384,6 @@ describe Chef::Provider::User do
end
end
-
describe "action_lock" do
before(:each) do
allow(@provider).to receive(:load_current_resource)
@@ -441,8 +444,8 @@ describe Chef::Provider::User do
describe "convert_group_name" do
before do
- @new_resource.gid('999')
- @group = EtcGrnamIsh.new('wheel', '*', 999, [])
+ @new_resource.gid("999")
+ @group = EtcGrnamIsh.new("wheel", "*", 999, [])
end
it "should lookup the group name locally" do
diff --git a/spec/unit/provider/whyrun_safe_ruby_block_spec.rb b/spec/unit/provider/whyrun_safe_ruby_block_spec.rb
index 2a4dccdad7..29d49ff90b 100644
--- a/spec/unit/provider/whyrun_safe_ruby_block_spec.rb
+++ b/spec/unit/provider/whyrun_safe_ruby_block_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Phil Dibowitz (<phild@fb.com>)
-# Copyright:: Copyright (c) 2013 Facebook
+# Copyright:: Copyright 2013-2016, Facebook
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Provider::WhyrunSafeRubyBlock, "initialize" do
before(:each) do
@@ -25,7 +25,7 @@ describe Chef::Provider::WhyrunSafeRubyBlock, "initialize" do
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@new_resource = Chef::Resource::WhyrunSafeRubyBlock.new("bloc party")
- @new_resource.block { $evil_global_evil_laugh = :mwahahaha}
+ @new_resource.block { $evil_global_evil_laugh = :mwahahaha }
@provider = Chef::Provider::WhyrunSafeRubyBlock.new(@new_resource, @run_context)
end
@@ -44,4 +44,3 @@ describe Chef::Provider::WhyrunSafeRubyBlock, "initialize" do
end
end
-
diff --git a/spec/unit/provider/yum_repository_spec.rb b/spec/unit/provider/yum_repository_spec.rb
new file mode 100644
index 0000000000..5b019f7d3e
--- /dev/null
+++ b/spec/unit/provider/yum_repository_spec.rb
@@ -0,0 +1,35 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::YumRepository do
+ let(:new_resource) { Chef::Resource::YumRepository.new("multiverse") }
+
+ let(:provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::YumRepository.new(new_resource, run_context)
+ end
+
+ it "responds to load_current_resource" do
+ expect(provider).to respond_to(:load_current_resource)
+ end
+
+end
diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb
index 2fb99f610c..ec102209ab 100644
--- a/spec/unit/provider_resolver_spec.rb
+++ b/spec/unit/provider_resolver_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@getchef.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/mixin/convert_to_class_name'
-require 'chef/provider_resolver'
-require 'chef/platform/service_helpers'
-require 'support/shared/integration/integration_helper'
-require 'tmpdir'
-require 'fileutils'
+require "spec_helper"
+require "chef/mixin/convert_to_class_name"
+require "chef/provider_resolver"
+require "chef/platform/service_helpers"
+require "support/shared/integration/integration_helper"
+require "tmpdir"
+require "fileutils"
include Chef::Mixin::ConvertToClassName
@@ -48,7 +48,7 @@ describe Chef::ProviderResolver do
node.automatic[:platform_family] = platform_family
node.automatic[:platform] = platform
node.automatic[:platform_version] = platform_version
- node.automatic[:kernel] = { machine: 'i386' }
+ node.automatic[:kernel] = { machine: "i386" }
node
end
let(:run_context) { Chef::RunContext.new(node, nil, nil) }
@@ -73,7 +73,7 @@ describe Chef::ProviderResolver do
end
def self.on_platform(platform, *tags,
- platform_version: '11.0.1',
+ platform_version: "11.0.1",
platform_family: nil,
os: nil,
&block)
@@ -135,6 +135,7 @@ describe Chef::ProviderResolver do
end
else
it "'#{name}' fails to resolve (since #{name.inspect} is unsupported on #{platform} #{platform_version})", *tags do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
expect(resolved_provider).to be_nil
end
end
@@ -147,25 +148,17 @@ describe Chef::ProviderResolver do
services.each do |service|
case service
when :debian
- directory 'usr/sbin/update-rc.d'
+ file "usr/sbin/update-rc.d", ""
when :invokercd
- directory 'usr/sbin/invoke-rc.d'
+ file "usr/sbin/invoke-rc.d", ""
when :insserv
- directory 'sbin/insserv'
+ file "sbin/insserv", ""
when :upstart
- directory 'etc/init'
- directory 'sbin/start'
+ file "sbin/initctl", ""
when :redhat
- directory 'sbin/chkconfig'
+ file "sbin/chkconfig", ""
when :systemd
- file 'bin/systemctl', ''
- # Make systemctl executable
- File.chmod(0755, path_to('bin/systemctl'))
- # Windows doesn't respect executable bit, do this to let Windows users see if they've broken the resolver
- allow(::File).to receive(:executable?) { |p| p == path_to('bin/systemctl') } if windows?
- file 'proc/1/comm', "systemd\n"
- mock_shellout_command("/bin/systemctl --all", stdout: "")
- mock_shellout_command("/bin/systemctl list-unit-files", stdout: "")
+ file "proc/1/comm", "systemd\n"
else
raise ArgumentError, service
end
@@ -186,24 +179,8 @@ describe Chef::ProviderResolver do
when :usr_local_etc_rcd
file "usr/local/etc/rc.d/#{service_name}", ""
when :systemd
- file 'bin/systemctl', ''
- # Make systemctl executable
- File.chmod(0755, path_to("bin/systemctl"))
- # Windows doesn't respect executable bit, do this to let Windows users see if they've broken the resolver
- allow(::File).to receive(:executable?) { |p| p == path_to('bin/systemctl') } if windows?
- file 'proc/1/comm', "systemd\n"
- mock_shellout_command("/bin/systemctl --all", stdout: <<-EOM)
- superv loaded
- stinky something-else
- #{service_name} loaded
- blargh not-found
- EOM
- mock_shellout_command("/bin/systemctl list-unit-files", stdout: <<-EOM)
- usuperv loaded
- ustinky something-else
- u#{service_name} loaded
- ublargh not-found
- EOM
+ file "proc/1/comm", "systemd\n"
+ file "etc/systemd/system/#{service_name}.service", ""
else
raise ArgumentError, config
end
@@ -272,7 +249,7 @@ describe Chef::ProviderResolver do
Chef::Provider::Service::Debian,
Chef::Provider::Service::Init,
Chef::Provider::Service::Invokercd,
- Chef::Provider::Service::Upstart,
+ Chef::Provider::Service::Upstart
)
end
@@ -280,10 +257,10 @@ describe Chef::ProviderResolver do
expect(provider_resolver.supported_handlers).to include(
Chef::Provider::Service::Debian,
Chef::Provider::Service::Init,
- Chef::Provider::Service::Invokercd,
+ Chef::Provider::Service::Invokercd
)
expect(provider_resolver.supported_handlers).to_not include(
- Chef::Provider::Service::Upstart,
+ Chef::Provider::Service::Upstart
)
end
@@ -303,7 +280,7 @@ describe Chef::ProviderResolver do
Chef::Provider::Service::Debian,
Chef::Provider::Service::Init,
Chef::Provider::Service::Invokercd,
- Chef::Provider::Service::Upstart,
+ Chef::Provider::Service::Upstart
)
end
@@ -312,7 +289,7 @@ describe Chef::ProviderResolver do
Chef::Provider::Service::Debian,
Chef::Provider::Service::Init,
Chef::Provider::Service::Invokercd,
- Chef::Provider::Service::Upstart,
+ Chef::Provider::Service::Upstart
)
end
@@ -332,18 +309,18 @@ describe Chef::ProviderResolver do
Chef::Provider::Service::Debian,
Chef::Provider::Service::Init,
Chef::Provider::Service::Invokercd,
- Chef::Provider::Service::Upstart,
+ Chef::Provider::Service::Upstart
)
end
it "supports only the upstart handler" do
expect(provider_resolver.supported_handlers).to include(
- Chef::Provider::Service::Upstart,
+ Chef::Provider::Service::Upstart
)
expect(provider_resolver.supported_handlers).to_not include(
Chef::Provider::Service::Debian,
Chef::Provider::Service::Init,
- Chef::Provider::Service::Invokercd,
+ Chef::Provider::Service::Invokercd
)
end
@@ -363,7 +340,7 @@ describe Chef::ProviderResolver do
Chef::Provider::Service::Debian,
Chef::Provider::Service::Init,
Chef::Provider::Service::Invokercd,
- Chef::Provider::Service::Upstart,
+ Chef::Provider::Service::Upstart
)
end
@@ -372,7 +349,7 @@ describe Chef::ProviderResolver do
Chef::Provider::Service::Upstart,
Chef::Provider::Service::Debian,
Chef::Provider::Service::Init,
- Chef::Provider::Service::Invokercd,
+ Chef::Provider::Service::Invokercd
)
end
@@ -504,7 +481,41 @@ describe Chef::ProviderResolver do
end
end
- on_platform %w(freebsd netbsd), platform_version: '3.1.4' do
+ on_platform "freebsd", os: "freebsd", platform_version: "10.3" do
+ it "returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
+ stub_service_providers
+ stub_service_configs(:usr_local_etc_rcd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
+
+ it "returns a Freebsd provider if it finds the /etc/rc.d initscript" do
+ stub_service_providers
+ stub_service_configs(:etc_rcd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
+
+ it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
+ # should only care about :usr_local_etc_rcd stub in the service configs
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:usr_local_etc_rcd, :initd, :upstart, :xinetd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
+
+ it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
+ # should only care about :etc_rcd stub in the service configs
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:etc_rcd, :initd, :upstart, :xinetd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
+
+ it "always returns a freebsd provider by default?" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
+ end
+
+ on_platform "netbsd", os: "netbsd", platform_version: "7.0.1" do
it "returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
stub_service_providers
stub_service_configs(:usr_local_etc_rcd)
@@ -531,7 +542,7 @@ describe Chef::ProviderResolver do
expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
end
- it "foo" do
+ it "always returns a freebsd provider by default?" do
stub_service_providers
stub_service_configs
expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
@@ -541,346 +552,355 @@ describe Chef::ProviderResolver do
end
PROVIDERS =
- {
- bash: [ Chef::Resource::Bash, Chef::Provider::Script ],
- breakpoint: [ Chef::Resource::Breakpoint, Chef::Provider::Breakpoint ],
- chef_gem: [ Chef::Resource::ChefGem, Chef::Provider::Package::Rubygems ],
- cookbook_file: [ Chef::Resource::CookbookFile, Chef::Provider::CookbookFile ],
- csh: [ Chef::Resource::Csh, Chef::Provider::Script ],
- deploy: [ Chef::Resource::Deploy, Chef::Provider::Deploy::Timestamped ],
- deploy_revision: [ Chef::Resource::DeployRevision, Chef::Provider::Deploy::Revision ],
- directory: [ Chef::Resource::Directory, Chef::Provider::Directory ],
- easy_install_package: [ Chef::Resource::EasyInstallPackage, Chef::Provider::Package::EasyInstall ],
- erl_call: [ Chef::Resource::ErlCall, Chef::Provider::ErlCall ],
- execute: [ Chef::Resource::Execute, Chef::Provider::Execute ],
- file: [ Chef::Resource::File, Chef::Provider::File ],
- gem_package: [ Chef::Resource::GemPackage, Chef::Provider::Package::Rubygems ],
- git: [ Chef::Resource::Git, Chef::Provider::Git ],
- group: [ Chef::Resource::Group, Chef::Provider::Group::Gpasswd ],
- homebrew_package: [ Chef::Resource::HomebrewPackage, Chef::Provider::Package::Homebrew ],
- http_request: [ Chef::Resource::HttpRequest, Chef::Provider::HttpRequest ],
- ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
- link: [ Chef::Resource::Link, Chef::Provider::Link ],
- log: [ Chef::Resource::Log, Chef::Provider::Log::ChefLog ],
- macports_package: [ Chef::Resource::MacportsPackage, Chef::Provider::Package::Macports ],
- mdadm: [ Chef::Resource::Mdadm, Chef::Provider::Mdadm ],
- mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Mount ],
- perl: [ Chef::Resource::Perl, Chef::Provider::Script ],
- portage_package: [ Chef::Resource::PortagePackage, Chef::Provider::Package::Portage ],
- python: [ Chef::Resource::Python, Chef::Provider::Script ],
- remote_directory: [ Chef::Resource::RemoteDirectory, Chef::Provider::RemoteDirectory ],
- route: [ Chef::Resource::Route, Chef::Provider::Route ],
- ruby: [ Chef::Resource::Ruby, Chef::Provider::Script ],
- ruby_block: [ Chef::Resource::RubyBlock, Chef::Provider::RubyBlock ],
- script: [ Chef::Resource::Script, Chef::Provider::Script ],
- subversion: [ Chef::Resource::Subversion, Chef::Provider::Subversion ],
- template: [ Chef::Resource::Template, Chef::Provider::Template ],
- timestamped_deploy: [ Chef::Resource::TimestampedDeploy, Chef::Provider::Deploy::Timestamped ],
- user: [ Chef::Resource::User, Chef::Provider::User::Useradd ],
- whyrun_safe_ruby_block: [ Chef::Resource::WhyrunSafeRubyBlock, Chef::Provider::WhyrunSafeRubyBlock ],
-
- # We want to check that these are unsupported:
- apt_package: nil,
- bff_package: nil,
- dpkg_package: nil,
- dsc_script: nil,
- ips_package: nil,
- pacman_package: nil,
- paludis_package: nil,
- rpm_package: nil,
- smartos_package: nil,
- solaris_package: nil,
- yum_package: nil,
- windows_package: nil,
- windows_service: nil,
-
- "linux" => {
- apt_package: [ Chef::Resource::AptPackage, Chef::Provider::Package::Apt ],
- dpkg_package: [ Chef::Resource::DpkgPackage, Chef::Provider::Package::Dpkg ],
- pacman_package: [ Chef::Resource::PacmanPackage, Chef::Provider::Package::Pacman ],
- paludis_package: [ Chef::Resource::PaludisPackage, Chef::Provider::Package::Paludis ],
- rpm_package: [ Chef::Resource::RpmPackage, Chef::Provider::Package::Rpm ],
- yum_package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ],
-
- "debian" => {
- ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Debian ],
- package: [ Chef::Resource::AptPackage, Chef::Provider::Package::Apt ],
- # service: [ Chef::Resource::DebianService, Chef::Provider::Service::Debian ],
+ {
+ bash: [ Chef::Resource::Bash, Chef::Provider::Script ],
+ breakpoint: [ Chef::Resource::Breakpoint, Chef::Provider::Breakpoint ],
+ chef_gem: [ Chef::Resource::ChefGem, Chef::Provider::Package::Rubygems ],
+ cookbook_file: [ Chef::Resource::CookbookFile, Chef::Provider::CookbookFile ],
+ csh: [ Chef::Resource::Csh, Chef::Provider::Script ],
+ deploy: [ Chef::Resource::Deploy, Chef::Provider::Deploy::Timestamped ],
+ deploy_revision: [ Chef::Resource::DeployRevision, Chef::Provider::Deploy::Revision ],
+ directory: [ Chef::Resource::Directory, Chef::Provider::Directory ],
+ easy_install_package: [ Chef::Resource::EasyInstallPackage, Chef::Provider::Package::EasyInstall ],
+ erl_call: [ Chef::Resource::ErlCall, Chef::Provider::ErlCall ],
+ execute: [ Chef::Resource::Execute, Chef::Provider::Execute ],
+ file: [ Chef::Resource::File, Chef::Provider::File ],
+ gem_package: [ Chef::Resource::GemPackage, Chef::Provider::Package::Rubygems ],
+ git: [ Chef::Resource::Git, Chef::Provider::Git ],
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Gpasswd ],
+ homebrew_package: [ Chef::Resource::HomebrewPackage, Chef::Provider::Package::Homebrew ],
+ http_request: [ Chef::Resource::HttpRequest, Chef::Provider::HttpRequest ],
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+ link: [ Chef::Resource::Link, Chef::Provider::Link ],
+ log: [ Chef::Resource::Log, Chef::Provider::Log::ChefLog ],
+ macports_package: [ Chef::Resource::MacportsPackage, Chef::Provider::Package::Macports ],
+ mdadm: [ Chef::Resource::Mdadm, Chef::Provider::Mdadm ],
+ mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Mount ],
+ perl: [ Chef::Resource::Perl, Chef::Provider::Script ],
+ portage_package: [ Chef::Resource::PortagePackage, Chef::Provider::Package::Portage ],
+ python: [ Chef::Resource::Python, Chef::Provider::Script ],
+ remote_directory: [ Chef::Resource::RemoteDirectory, Chef::Provider::RemoteDirectory ],
+ route: [ Chef::Resource::Route, Chef::Provider::Route ],
+ ruby: [ Chef::Resource::Ruby, Chef::Provider::Script ],
+ ruby_block: [ Chef::Resource::RubyBlock, Chef::Provider::RubyBlock ],
+ script: [ Chef::Resource::Script, Chef::Provider::Script ],
+ subversion: [ Chef::Resource::Subversion, Chef::Provider::Subversion ],
+ template: [ Chef::Resource::Template, Chef::Provider::Template ],
+ timestamped_deploy: [ Chef::Resource::TimestampedDeploy, Chef::Provider::Deploy::Timestamped ],
+ aix_user: [ Chef::Resource::User::AixUser, Chef::Provider::User::Aix ],
+ dscl_user: [ Chef::Resource::User::DsclUser, Chef::Provider::User::Dscl ],
+ linux_user: [ Chef::Resource::User::LinuxUser, Chef::Provider::User::Linux ],
+ pw_user: [ Chef::Resource::User::PwUser, Chef::Provider::User::Pw ],
+ solaris_user: [ Chef::Resource::User::SolarisUser, Chef::Provider::User::Solaris ],
+ windows_user: [ Chef::Resource::User::WindowsUser, Chef::Provider::User::Windows ],
+ whyrun_safe_ruby_block: [ Chef::Resource::WhyrunSafeRubyBlock, Chef::Provider::WhyrunSafeRubyBlock ],
+
+ # We want to check that these are unsupported:
+ apt_package: nil,
+ bff_package: nil,
+ dpkg_package: nil,
+ dsc_script: nil,
+ ips_package: nil,
+ pacman_package: nil,
+ paludis_package: nil,
+ rpm_package: nil,
+ smartos_package: nil,
+ solaris_package: nil,
+ yum_package: nil,
+ windows_package: nil,
+ windows_service: nil,
+
+ "linux" => {
+ apt_package: [ Chef::Resource::AptPackage, Chef::Provider::Package::Apt ],
+ dpkg_package: [ Chef::Resource::DpkgPackage, Chef::Provider::Package::Dpkg ],
+ pacman_package: [ Chef::Resource::PacmanPackage, Chef::Provider::Package::Pacman ],
+ paludis_package: [ Chef::Resource::PaludisPackage, Chef::Provider::Package::Paludis ],
+ rpm_package: [ Chef::Resource::RpmPackage, Chef::Provider::Package::Rpm ],
+ yum_package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ],
"debian" => {
- "7.0" => {
- },
- "6.0" => {
- ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
- # service: [ Chef::Resource::InsservService, Chef::Provider::Service::Insserv ],
- },
- "5.0" => {
- ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
- },
- },
- "gcel" => {
- "3.1.4" => {
- ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
- },
- },
- "linaro" => {
- "3.1.4" => {
- ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Debian ],
+ package: [ Chef::Resource::AptPackage, Chef::Provider::Package::Apt ],
+ # service: [ Chef::Resource::DebianService, Chef::Provider::Service::Debian ],
+
+ "debian" => {
+ "7.0" => {
+ },
+ "6.0" => {
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+ # service: [ Chef::Resource::InsservService, Chef::Provider::Service::Insserv ],
+ },
+ "5.0" => {
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+ },
+ },
+ "gcel" => {
+ "3.1.4" => {
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+ },
+ },
+ "linaro" => {
+ "3.1.4" => {
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+ },
+ },
+ "linuxmint" => {
+ "3.1.4" => {
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+ # service: [ Chef::Resource::UpstartService, Chef::Provider::Service::Upstart ],
+ },
+ },
+ "raspbian" => {
+ "3.1.4" => {
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+ },
+ },
+ "ubuntu" => {
+ "11.10" => {
+ },
+ "10.04" => {
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+ },
},
},
- "linuxmint" => {
- "3.1.4" => {
- ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
- # service: [ Chef::Resource::UpstartService, Chef::Provider::Service::Upstart ],
- },
- },
- "raspbian" => {
- "3.1.4" => {
- ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
- },
- },
- "ubuntu" => {
- "11.10" => {
- },
- "10.04" => {
- ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
- },
- },
- },
-
- "arch" => {
- # TODO should be Chef::Resource::PacmanPackage
- package: [ Chef::Resource::Package, Chef::Provider::Package::Pacman ],
"arch" => {
- "3.1.4" => {
- }
- },
- },
-
- "freebsd" => {
- group: [ Chef::Resource::Group, Chef::Provider::Group::Pw ],
- user: [ Chef::Resource::User, Chef::Provider::User::Pw ],
+ # TODO should be Chef::Resource::PacmanPackage
+ package: [ Chef::Resource::Package, Chef::Provider::Package::Pacman ],
- "freebsd" => {
- "3.1.4" => {
+ "arch" => {
+ "3.1.4" => {
+ },
},
},
- },
- "suse" => {
- group: [ Chef::Resource::Group, Chef::Provider::Group::Gpasswd ],
+
"suse" => {
- "12.0" => {
- },
- %w(11.1 11.2 11.3) => {
- group: [ Chef::Resource::Group, Chef::Provider::Group::Suse ],
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Gpasswd ],
+ "suse" => {
+ "12.0" => {
+ },
+ %w{11.1 11.2 11.3} => {
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Suse ],
+ },
+ },
+ "opensuse" => {
+ # service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
+ package: [ Chef::Resource::ZypperPackage, Chef::Provider::Package::Zypper ],
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
+ "12.3" => {
+ },
+ "12.2" => {
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Suse ],
+ },
},
},
- "opensuse" => {
- # service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
- package: [ Chef::Resource::ZypperPackage, Chef::Provider::Package::Zypper ],
- group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
- "12.3" => {
- },
- "12.2" => {
- group: [ Chef::Resource::Group, Chef::Provider::Group::Suse ],
+
+ "gentoo" => {
+ # TODO should be Chef::Resource::PortagePackage
+ package: [ Chef::Resource::Package, Chef::Provider::Package::Portage ],
+ portage_package: [ Chef::Resource::PortagePackage, Chef::Provider::Package::Portage ],
+ # service: [ Chef::Resource::GentooService, Chef::Provider::Service::Gentoo ],
+
+ "gentoo" => {
+ "3.1.4" => {
+ },
},
},
- },
- "gentoo" => {
- # TODO should be Chef::Resource::PortagePackage
- package: [ Chef::Resource::Package, Chef::Provider::Package::Portage ],
- portage_package: [ Chef::Resource::PortagePackage, Chef::Provider::Package::Portage ],
- # service: [ Chef::Resource::GentooService, Chef::Provider::Service::Gentoo ],
-
- "gentoo" => {
- "3.1.4" => {
+ "rhel" => {
+ # service: [ Chef::Resource::SystemdService, Chef::Provider::Service::Systemd ],
+ package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ],
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Redhat ],
+
+ %w{amazon xcp xenserver ibm_powerkvm cloudlinux parallels} => {
+ "3.1.4" => {
+ # service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
+ },
+ },
+ %w{redhat centos scientific oracle} => {
+ "7.0" => {
+ },
+ "6.0" => {
+ # service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
+ },
+ },
+ "fedora" => {
+ "15.0" => {
+ },
+ "14.0" => {
+ # service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
+ },
},
},
+
},
- "rhel" => {
- # service: [ Chef::Resource::SystemdService, Chef::Provider::Service::Systemd ],
- package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ],
- ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Redhat ],
+ "freebsd" => {
+ "freebsd" => {
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Pw ],
+ user: [ Chef::Resource::User::PwUser, Chef::Provider::User::Pw ],
- %w(amazon xcp xenserver ibm_powerkvm cloudlinux parallels) => {
- "3.1.4" => {
- # service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
- },
- },
- %w(redhat centos scientific oracle) => {
- "7.0" => {
- },
- "6.0" => {
- # service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
- },
- },
- "fedora" => {
- "15.0" => {
- },
- "14.0" => {
- # service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
+ "freebsd" => {
+ "10.3" => {
+ },
},
},
},
- },
+ "darwin" => {
+ %w{mac_os_x mac_os_x_server} => {
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Dscl ],
+ package: [ Chef::Resource::HomebrewPackage, Chef::Provider::Package::Homebrew ],
+ osx_profile: [ Chef::Resource::OsxProfile, Chef::Provider::OsxProfile],
+ user: [ Chef::Resource::User::DsclUser, Chef::Provider::User::Dscl ],
- "darwin" => {
- %w(mac_os_x mac_os_x_server) => {
- group: [ Chef::Resource::Group, Chef::Provider::Group::Dscl ],
- package: [ Chef::Resource::HomebrewPackage, Chef::Provider::Package::Homebrew ],
- user: [ Chef::Resource::User, Chef::Provider::User::Dscl ],
-
- "mac_os_x" => {
- "10.9.2" => {
+ "mac_os_x" => {
+ "10.9.2" => {
+ },
},
},
},
- },
-
- "windows" => {
- batch: [ Chef::Resource::Batch, Chef::Provider::Batch ],
- dsc_script: [ Chef::Resource::DscScript, Chef::Provider::DscScript ],
- env: [ Chef::Resource::Env, Chef::Provider::Env::Windows ],
- group: [ Chef::Resource::Group, Chef::Provider::Group::Windows ],
- mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Windows ],
- package: [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ],
- powershell_script: [ Chef::Resource::PowershellScript, Chef::Provider::PowershellScript ],
- service: [ Chef::Resource::WindowsService, Chef::Provider::Service::Windows ],
- user: [ Chef::Resource::User, Chef::Provider::User::Windows ],
- windows_package: [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ],
- windows_service: [ Chef::Resource::WindowsService, Chef::Provider::Service::Windows ],
"windows" => {
- %w(mswin mingw32 windows) => {
- "10.9.2" => {
+ batch: [ Chef::Resource::Batch, Chef::Provider::Batch ],
+ dsc_script: [ Chef::Resource::DscScript, Chef::Provider::DscScript ],
+ env: [ Chef::Resource::Env, Chef::Provider::Env::Windows ],
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Windows ],
+ mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Windows ],
+ package: [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ],
+ powershell_script: [ Chef::Resource::PowershellScript, Chef::Provider::PowershellScript ],
+ service: [ Chef::Resource::WindowsService, Chef::Provider::Service::Windows ],
+ user: [ Chef::Resource::User::WindowsUser, Chef::Provider::User::Windows ],
+ windows_package: [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ],
+ windows_service: [ Chef::Resource::WindowsService, Chef::Provider::Service::Windows ],
+
+ "windows" => {
+ %w{mswin mingw32 windows} => {
+ "10.9.2" => {
+ },
},
},
},
- },
-
- "aix" => {
- bff_package: [ Chef::Resource::BffPackage, Chef::Provider::Package::Aix ],
- cron: [ Chef::Resource::Cron, Chef::Provider::Cron::Aix ],
- group: [ Chef::Resource::Group, Chef::Provider::Group::Aix ],
- ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Aix ],
- mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Aix ],
- # TODO should be Chef::Resource::BffPackage
- package: [ Chef::Resource::Package, Chef::Provider::Package::Aix ],
- rpm_package: [ Chef::Resource::RpmPackage, Chef::Provider::Package::Rpm ],
- user: [ Chef::Resource::User, Chef::Provider::User::Aix ],
- # service: [ Chef::Resource::AixService, Chef::Provider::Service::Aix ],
"aix" => {
+ bff_package: [ Chef::Resource::BffPackage, Chef::Provider::Package::Aix ],
+ cron: [ Chef::Resource::Cron, Chef::Provider::Cron::Aix ],
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Aix ],
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Aix ],
+ mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Aix ],
+ # TODO should be Chef::Resource::BffPackage
+ package: [ Chef::Resource::Package, Chef::Provider::Package::Aix ],
+ rpm_package: [ Chef::Resource::RpmPackage, Chef::Provider::Package::Rpm ],
+ user: [ Chef::Resource::User::AixUser, Chef::Provider::User::Aix ],
+ # service: [ Chef::Resource::AixService, Chef::Provider::Service::Aix ],
+
"aix" => {
- "5.6" => {
+ "aix" => {
+ "5.6" => {
+ },
},
},
},
- },
- "hpux" => {
"hpux" => {
"hpux" => {
- "3.1.4" => {
- group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ]
- }
- }
- }
- },
-
- "netbsd" => {
+ "hpux" => {
+ "3.1.4" => {
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
+ },
+ },
+ },
+ },
+
"netbsd" => {
"netbsd" => {
- "3.1.4" => {
- group: [ Chef::Resource::Group, Chef::Provider::Group::Groupmod ],
+ "netbsd" => {
+ "3.1.4" => {
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Groupmod ],
+ },
},
},
},
- },
-
- "openbsd" => {
- group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
- package: [ Chef::Resource::OpenbsdPackage, Chef::Provider::Package::Openbsd ],
"openbsd" => {
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
+ package: [ Chef::Resource::OpenbsdPackage, Chef::Provider::Package::Openbsd ],
+
"openbsd" => {
- "3.1.4" => {
+ "openbsd" => {
+ "3.1.4" => {
+ },
},
},
},
- },
-
- "solaris2" => {
- group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
- ips_package: [ Chef::Resource::IpsPackage, Chef::Provider::Package::Ips ],
- package: [ Chef::Resource::SolarisPackage, Chef::Provider::Package::Solaris ],
- mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Solaris ],
- solaris_package: [ Chef::Resource::SolarisPackage, Chef::Provider::Package::Solaris ],
- "smartos" => {
- smartos_package: [ Chef::Resource::SmartosPackage, Chef::Provider::Package::SmartOS ],
- package: [ Chef::Resource::SmartosPackage, Chef::Provider::Package::SmartOS ],
+ "solaris2" => {
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
+ ips_package: [ Chef::Resource::IpsPackage, Chef::Provider::Package::Ips ],
+ package: [ Chef::Resource::SolarisPackage, Chef::Provider::Package::Solaris ],
+ mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Solaris ],
+ solaris_package: [ Chef::Resource::SolarisPackage, Chef::Provider::Package::Solaris ],
"smartos" => {
- "3.1.4" => {
- },
- },
- },
+ smartos_package: [ Chef::Resource::SmartosPackage, Chef::Provider::Package::SmartOS ],
+ package: [ Chef::Resource::SmartosPackage, Chef::Provider::Package::SmartOS ],
- "solaris2" => {
- "nexentacore" => {
- "3.1.4" => {
- },
- },
- "omnios" => {
- "3.1.4" => {
- user: [ Chef::Resource::User, Chef::Provider::User::Solaris ],
- }
- },
- "openindiana" => {
- "3.1.4" => {
- },
- },
- "opensolaris" => {
- "3.1.4" => {
+ "smartos" => {
+ "3.1.4" => {
+ },
},
},
+
"solaris2" => {
- user: [ Chef::Resource::User, Chef::Provider::User::Solaris ],
- "5.11" => {
- package: [ Chef::Resource::IpsPackage, Chef::Provider::Package::Ips ],
- },
- "5.9" => {
+ "nexentacore" => {
+ "3.1.4" => {
+ },
+ },
+ "omnios" => {
+ "3.1.4" => {
+ user: [ Chef::Resource::User::SolarisUser, Chef::Provider::User::Solaris ],
+ },
+ },
+ "openindiana" => {
+ "3.1.4" => {
+ },
+ },
+ "opensolaris" => {
+ "3.1.4" => {
+ },
+ },
+ "solaris2" => {
+ user: [ Chef::Resource::User::SolarisUser, Chef::Provider::User::Solaris ],
+ "5.11" => {
+ package: [ Chef::Resource::IpsPackage, Chef::Provider::Package::Ips ],
+ },
+ "5.9" => {
+ },
},
},
- },
- },
+ },
- "solaris" => {
"solaris" => {
"solaris" => {
- "3.1.4" => {
+ "solaris" => {
+ "3.1.4" => {
+ },
},
},
},
- },
- "exherbo" => {
"exherbo" => {
"exherbo" => {
- "3.1.4" => {
- # TODO should be Chef::Resource::PaludisPackage
- package: [ Chef::Resource::Package, Chef::Provider::Package::Paludis ]
- }
- }
- }
+ "exherbo" => {
+ "3.1.4" => {
+ # TODO should be Chef::Resource::PaludisPackage
+ package: [ Chef::Resource::Package, Chef::Provider::Package::Paludis ],
+ },
+ },
+ },
+ },
}
- }
def self.create_provider_tests(providers, test, expected, filter)
expected = expected.merge(providers.select { |key, value| key.is_a?(Symbol) })
diff --git a/spec/unit/provider_spec.rb b/spec/unit/provider_spec.rb
index 97b88b1732..2bc2ae7c88 100644
--- a/spec/unit/provider_spec.rb
+++ b/spec/unit/provider_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,17 @@
# limitations under the License.
#
-require 'spec_helper'
-
+require "spec_helper"
class NoWhyrunDemonstrator < Chef::Provider
attr_reader :system_state_altered
def whyrun_supported?
false
end
- def load_current_resource
+ def load_current_resource
end
+
def action_foo
@system_state_altered = true
end
@@ -55,7 +55,6 @@ class CheckResourceSemanticsDemonstrator < ConvergeActionDemonstrator
end
end
-
describe Chef::Provider do
before(:each) do
@cookbook_collection = Chef::CookbookCollection.new([])
@@ -107,7 +106,7 @@ describe Chef::Provider do
it "evals embedded recipes with a pristine resource collection" do
@provider.run_context.instance_variable_set(:@resource_collection, "doesn't matter what this is")
temporary_collection = nil
- snitch = Proc.new {temporary_collection = @run_context.resource_collection}
+ snitch = Proc.new { temporary_collection = @run_context.resource_collection }
@provider.send(:recipe_eval, &snitch)
expect(temporary_collection).to be_an_instance_of(Chef::ResourceCollection)
expect(@provider.run_context.instance_variable_get(:@resource_collection)).to eq("doesn't matter what this is")
@@ -115,7 +114,7 @@ describe Chef::Provider do
it "does not re-load recipes when creating the temporary run context" do
expect_any_instance_of(Chef::RunContext).not_to receive(:load)
- snitch = Proc.new {temporary_collection = @run_context.resource_collection}
+ snitch = Proc.new { temporary_collection = @run_context.resource_collection }
@provider.send(:recipe_eval, &snitch)
end
diff --git a/spec/unit/pure_application_spec.rb b/spec/unit/pure_application_spec.rb
index 5d879a7b85..a25acc2bba 100644
--- a/spec/unit/pure_application_spec.rb
+++ b/spec/unit/pure_application_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,7 @@
# be able to test only Chef::Application.
# Regression test for CHEF-5169
-require 'chef/application'
+require "chef/application"
describe "Chef::Application" do
let(:app) { Chef::Application.new }
diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb
index ea3ab44c16..e1e3e0ad72 100644
--- a/spec/unit/recipe_spec.rb
+++ b/spec/unit/recipe_spec.rb
@@ -1,9 +1,9 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,30 +19,24 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/platform/resource_priority_map'
+require "spec_helper"
+require "chef/platform/resource_priority_map"
describe Chef::Recipe do
- let(:cookbook_repo) { File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks")) }
-
- let(:cookbook_loader) do
- loader = Chef::CookbookLoader.new(cookbook_repo)
- loader.load_cookbooks
- loader
+ let(:cookbook_collection) do
+ cookbook_repo = File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks"))
+ cookbook_loader = Chef::CookbookLoader.new(cookbook_repo)
+ cookbook_loader.load_cookbooks
+ Chef::CookbookCollection.new(cookbook_loader)
end
- let(:cookbook_collection) { Chef::CookbookCollection.new(cookbook_loader) }
-
let(:node) do
- Chef::Node.new.tap {|n| n.normal[:tags] = [] }
- end
-
- let(:events) do
- Chef::EventDispatch::Dispatcher.new
+ Chef::Node.new
end
let(:run_context) do
+ events = Chef::EventDispatch::Dispatcher.new
Chef::RunContext.new(node, cookbook_collection, events)
end
@@ -81,15 +75,15 @@ describe Chef::Recipe do
end
it "should require a name argument" do
- expect {
+ expect do
recipe.cat
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should allow regular errors (not NameErrors) to pass unchanged" do
- expect {
+ expect do
recipe.cat("felix") { raise ArgumentError, "You Suck" }
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should add our zen_master to the collection" do
@@ -106,7 +100,7 @@ describe Chef::Recipe do
end
end
- expect(run_context.resource_collection.map{|r| r.name}).to eql(["monkey", "dog", "cat"])
+ expect(run_context.resource_collection.map { |r| r.name }).to eql(%w{monkey dog cat})
end
it "should return the new resource after creating it" do
@@ -199,11 +193,41 @@ describe Chef::Recipe do
end
end
+ describe "when resource cloning is disabled" do
+ def not_expect_warning
+ expect(Chef::Log).not_to receive(:warn).with(/3694/)
+ expect(Chef::Log).not_to receive(:warn).with(/Previous/)
+ expect(Chef::Log).not_to receive(:warn).with(/Current/)
+ end
+
+ before do
+ Chef::Config[:resource_cloning] = false
+ end
+
+ it "should emit a 3694 warning when attributes change" do
+ recipe.zen_master "klopp" do
+ something "bvb"
+ end
+ not_expect_warning
+ recipe.zen_master "klopp" do
+ something "vbv"
+ end
+ end
+
+ it "should not copy attributes from a prior resource" do
+ recipe.zen_master "klopp" do
+ something "bvb"
+ end
+ not_expect_warning
+ recipe.zen_master "klopp"
+ expect(run_context.resource_collection.first.something).to eql("bvb")
+ expect(run_context.resource_collection[1].something).to be nil
+ end
+ end
+
describe "when cloning resources" do
def expect_warning
- expect(Chef::Log).to receive(:warn).with(/3694/)
- expect(Chef::Log).to receive(:warn).with(/Previous/)
- expect(Chef::Log).to receive(:warn).with(/Current/)
+ expect(Chef).to receive(:deprecated).with(:resource_cloning, /^Cloning resource attributes for zen_master\[klopp\]/)
end
it "should emit a 3694 warning when attributes change" do
@@ -250,7 +274,7 @@ describe Chef::Recipe do
it "should not emit a 3694 warning for completely trivial resource cloning" do
recipe.zen_master "klopp"
- expect(Chef::Log).to_not receive(:warn)
+ expect(Chef).to_not receive(:deprecated)
recipe.zen_master "klopp"
end
@@ -258,7 +282,7 @@ describe Chef::Recipe do
recipe.zen_master "klopp" do
action :nothing
end
- expect(Chef::Log).to_not receive(:warn)
+ expect(Chef).to_not receive(:deprecated)
recipe.zen_master "klopp" do
action :score
end
@@ -268,21 +292,41 @@ describe Chef::Recipe do
recipe.zen_master "klopp" do
action :score
end
- expect(Chef::Log).to_not receive(:warn)
+ expect(Chef).to_not receive(:deprecated)
recipe.zen_master "klopp" do
action :nothing
end
end
- it "validating resources via build_resource" do
- expect {recipe.build_resource(:remote_file, "klopp") do
- source Chef::DelayedEvaluator.new {"http://chef.io"}
- end}.to_not raise_error
+ class Coerced < Chef::Resource
+ resource_name :coerced
+ provides :coerced
+ default_action :whatever
+ property :package_name, [String, Array], coerce: proc { |x| [x].flatten }, name_property: true
+ def after_created
+ Array(action).each do |action|
+ run_action(action)
+ end
+ end
+ action :whatever do
+ package_name # unlazy the package_name
+ end
end
- end
+ it "does not emit 3694 when the name_property is unlazied by running it at compile_time" do
+ recipe.coerced "string"
+ expect(Chef).to_not receive(:deprecated)
+ recipe.coerced "string"
+ end
+ it "validating resources via build_resource" do
+ expect do
+ recipe.build_resource(:remote_file, "klopp") do
+ source Chef::DelayedEvaluator.new { "http://chef.io" }
+ end end.to_not raise_error
+ end
+ end
describe "creating resources via declare_resource" do
let(:zm_resource) do
@@ -305,6 +349,36 @@ describe Chef::Recipe do
zm_resource # force let binding evaluation
expect(run_context.resource_collection.resources(:zen_master => "klopp")).to eq(zm_resource)
end
+
+ it "will insert another resource if create_if_missing is not set (cloned resource as of Chef-12)" do
+ expect(Chef).to receive(:deprecated).with(:resource_cloning, /^Cloning resource attributes for zen_master\[klopp\]/)
+ zm_resource
+ recipe.declare_resource(:zen_master, "klopp")
+ expect(run_context.resource_collection.count).to eql(2)
+ end
+
+ it "does not insert two resources if create_if_missing is used" do
+ zm_resource
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ recipe.declare_resource(:zen_master, "klopp", create_if_missing: true)
+ expect(run_context.resource_collection.count).to eql(1)
+ end
+
+ context "injecting a different run_context" do
+ let(:run_context2) do
+ events = Chef::EventDispatch::Dispatcher.new
+ Chef::RunContext.new(node, cookbook_collection, events)
+ end
+
+ it "should insert resources into the correct run_context" do
+ zm_resource
+ recipe.declare_resource(:zen_master, "klopp2", run_context: run_context2)
+ run_context2.resource_collection.lookup("zen_master[klopp2]")
+ expect { run_context2.resource_collection.lookup("zen_master[klopp]") }.to raise_error(Chef::Exceptions::ResourceNotFound)
+ expect { run_context.resource_collection.lookup("zen_master[klopp2]") }.to raise_error(Chef::Exceptions::ResourceNotFound)
+ run_context.resource_collection.lookup("zen_master[klopp]")
+ end
+ end
end
describe "creating a resource with short name" do
@@ -333,7 +407,6 @@ describe Chef::Recipe do
end
end
-
it "defines the resource using the declaration name with long name" do
resource_zn_follower
expect(run_context.resource_collection.lookup("zen_follower[srst]")).not_to be_nil
@@ -345,7 +418,7 @@ describe Chef::Recipe do
it "gives a sane error message when using method_missing" do
expect do
recipe.no_such_resource("foo")
- end.to raise_error(NoMethodError, %q[No resource or method named `no_such_resource' for `Chef::Recipe "test"'])
+ end.to raise_error(NoMethodError, %q{No resource or method named `no_such_resource' for `Chef::Recipe "test"'})
end
it "gives a sane error message when using method_missing 'bare'" do
@@ -354,7 +427,7 @@ describe Chef::Recipe do
# Giving an argument will change this from NameError to NoMethodError
no_such_resource
end
- end.to raise_error(NameError, %q[No resource, method, or local variable named `no_such_resource' for `Chef::Recipe "test"'])
+ end.to raise_error(NameError, %q{No resource, method, or local variable named `no_such_resource' for `Chef::Recipe "test"'})
end
it "gives a sane error message when using build_resource" do
@@ -401,15 +474,18 @@ describe Chef::Recipe do
end
it "copies attributes from the first resource" do
+ expect(Chef).to receive(:deprecated).with(:resource_cloning, /^Cloning resource attributes for zen_master\[klopp\]/)
expect(duplicated_resource.something).to eq("bvb09")
end
it "does not copy the action from the first resource" do
+ expect(Chef).to receive(:deprecated).with(:resource_cloning, /^Cloning resource attributes for zen_master\[klopp\]/)
expect(original_resource.action).to eq([:score])
expect(duplicated_resource.action).to eq([:nothing])
end
it "does not copy the source location of the first resource" do
+ expect(Chef).to receive(:deprecated).with(:resource_cloning, /^Cloning resource attributes for zen_master\[klopp\]/)
# sanity check source location:
expect(original_resource.source_line).to include(__FILE__)
expect(duplicated_resource.source_line).to include(__FILE__)
@@ -418,10 +494,12 @@ describe Chef::Recipe do
end
it "sets the cookbook name on the cloned resource to that resource's cookbook" do
+ expect(Chef).to receive(:deprecated).with(:resource_cloning, /^Cloning resource attributes for zen_master\[klopp\]/)
expect(duplicated_resource.cookbook_name).to eq("second_cb")
end
it "sets the recipe name on the cloned resource to that resoure's recipe" do
+ expect(Chef).to receive(:deprecated).with(:resource_cloning, /^Cloning resource attributes for zen_master\[klopp\]/)
expect(duplicated_resource.recipe_name).to eq("second_recipe")
end
@@ -615,21 +693,25 @@ describe Chef::Recipe do
end
end
+ it "should initialize tags to an empty Array" do
+ expect(node.tags).to eql([])
+ end
+
it "should set tags via tag" do
recipe.tag "foo"
- expect(node[:tags]).to include("foo")
+ expect(node.tags).to include("foo")
end
it "should set multiple tags via tag" do
recipe.tag "foo", "bar"
- expect(node[:tags]).to include("foo")
- expect(node[:tags]).to include("bar")
+ expect(node.tags).to include("foo")
+ expect(node.tags).to include("bar")
end
it "should not set the same tag twice via tag" do
recipe.tag "foo"
recipe.tag "foo"
- expect(node[:tags]).to eql([ "foo" ])
+ expect(node.tags).to eql([ "foo" ])
end
it "should return the current list of tags from tag with no arguments" do
@@ -653,13 +735,13 @@ describe Chef::Recipe do
it "should remove a tag from the tag list via untag" do
recipe.tag "foo"
recipe.untag "foo"
- expect(node[:tags]).to eql([])
+ expect(node.tags).to eql([])
end
it "should remove multiple tags from the tag list via untag" do
recipe.tag "foo", "bar"
recipe.untag "bar", "foo"
- expect(node[:tags]).to eql([])
+ expect(node.tags).to eql([])
end
end
diff --git a/spec/unit/resource/apt_package_spec.rb b/spec/unit/resource/apt_package_spec.rb
index 3c31f63dd7..78eccfb444 100644
--- a/spec/unit/resource/apt_package_spec.rb
+++ b/spec/unit/resource/apt_package_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::AptPackage, "initialize" do
@@ -26,7 +26,7 @@ describe Chef::Resource::AptPackage, "initialize" do
provider: Chef::Provider::Package::Apt,
name: :apt_package,
action: :install,
- os: "linux",
+ os: "linux"
)
let(:resource) { Chef::Resource::AptPackage.new("foo") }
diff --git a/spec/unit/resource/apt_repository_spec.rb b/spec/unit/resource/apt_repository_spec.rb
new file mode 100644
index 0000000000..69cf94ae56
--- /dev/null
+++ b/spec/unit/resource/apt_repository_spec.rb
@@ -0,0 +1,50 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::AptRepository do
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:resource) { Chef::Resource::AptRepository.new("multiverse", run_context) }
+
+ it "should create a new Chef::Resource::AptRepository" do
+ expect(resource).to be_a_kind_of(Chef::Resource)
+ expect(resource).to be_a_kind_of(Chef::Resource::AptRepository)
+ end
+
+ it "the default keyserver should be keyserver.ubuntu.com" do
+ expect(resource.keyserver).to eql("keyserver.ubuntu.com")
+ end
+
+ it "the default distribution should be nillable" do
+ expect(resource.distribution(nil)).to eql(nil)
+ expect(resource.distribution).to eql(nil)
+ end
+
+ it "should resolve to a Noop class when apt-get is not found" do
+ expect(Chef::Provider::AptRepository).to receive(:which).with("apt-get").and_return(false)
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop)
+ end
+
+ it "should resolve to a AptRepository class when apt-get is found" do
+ expect(Chef::Provider::AptRepository).to receive(:which).with("apt-get").and_return(true)
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::AptRepository)
+ end
+end
diff --git a/spec/unit/resource/apt_update_spec.rb b/spec/unit/resource/apt_update_spec.rb
new file mode 100644
index 0000000000..dd72b18063
--- /dev/null
+++ b/spec/unit/resource/apt_update_spec.rb
@@ -0,0 +1,50 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::AptUpdate do
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:resource) { Chef::Resource::AptUpdate.new("update", run_context) }
+
+ it "should create a new Chef::Resource::AptUpdate" do
+ expect(resource).to be_a_kind_of(Chef::Resource)
+ expect(resource).to be_a_kind_of(Chef::Resource::AptUpdate)
+ end
+
+ it "the default frequency should be 1 day" do
+ expect(resource.frequency).to eql(86_400)
+ end
+
+ it "the frequency should accept integers" do
+ resource.frequency(400)
+ expect(resource.frequency).to eql(400)
+ end
+
+ it "should resolve to a Noop class when apt-get is not found" do
+ expect(Chef::Provider::AptUpdate).to receive(:which).with("apt-get").and_return(false)
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop)
+ end
+
+ it "should resolve to a AptUpdate class when apt-get is found" do
+ expect(Chef::Provider::AptUpdate).to receive(:which).with("apt-get").and_return(true)
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::AptUpdate)
+ end
+end
diff --git a/spec/unit/resource/bash_spec.rb b/spec/unit/resource/bash_spec.rb
index f313900433..56c36df1ce 100644
--- a/spec/unit/resource/bash_spec.rb
+++ b/spec/unit/resource/bash_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Bash do
diff --git a/spec/unit/resource/batch_spec.rb b/spec/unit/resource/batch_spec.rb
index b8c2897f42..e19ea15585 100644
--- a/spec/unit/resource/batch_spec.rb
+++ b/spec/unit/resource/batch_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Batch do
@@ -25,7 +25,7 @@ describe Chef::Resource::Batch do
node.default["kernel"] = Hash.new
node.default["kernel"][:machine] = :x86_64.to_s
- node.automatic[:os] = 'windows'
+ node.automatic[:os] = "windows"
run_context = Chef::RunContext.new(node, nil, nil)
@@ -41,7 +41,7 @@ describe Chef::Resource::Batch do
let(:resource_instance) { @resource }
let(:resource_instance_name ) { @resource.command }
let(:resource_name) { :batch }
- let(:interpreter_file_name) { 'cmd.exe' }
+ let(:interpreter_file_name) { "cmd.exe" }
it_should_behave_like "a Windows script resource"
end
diff --git a/spec/unit/resource/breakpoint_spec.rb b/spec/unit/resource/breakpoint_spec.rb
index 88ab34d568..a5b27bae16 100644
--- a/spec/unit/resource/breakpoint_spec.rb
+++ b/spec/unit/resource/breakpoint_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::Breakpoint do
@@ -25,7 +25,7 @@ describe Chef::Resource::Breakpoint do
resource: Chef::Resource::Breakpoint,
provider: Chef::Provider::Breakpoint,
name: :breakpoint,
- action: :break,
+ action: :break
)
before do
diff --git a/spec/unit/resource/cab_package_spec.rb b/spec/unit/resource/cab_package_spec.rb
new file mode 100644
index 0000000000..aa4890f171
--- /dev/null
+++ b/spec/unit/resource/cab_package_spec.rb
@@ -0,0 +1,38 @@
+#
+# Author:: Vasundhara Jagdale (<vasundhara.jagdale@msystechnologies.com>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::CabPackage do
+
+ let(:resource) { Chef::Resource::CabPackage.new("test_pkg") }
+
+ it "creates a new Chef::Resource::CabPackage" do
+ expect(resource).to be_a_kind_of(Chef::Resource)
+ expect(resource).to be_a_kind_of(Chef::Resource::Package)
+ expect(resource).to be_a_instance_of(Chef::Resource::CabPackage)
+ end
+
+ it "sets resource name as :cab_package" do
+ expect(resource.resource_name).to eql(:cab_package)
+ end
+
+ it "coerce its name to a package_name" do
+ expect(resource.package_name).to eql("test_pkg")
+ end
+end
diff --git a/spec/unit/resource/chef_gem_spec.rb b/spec/unit/resource/chef_gem_spec.rb
index 7352a8f5fe..c98b447582 100644
--- a/spec/unit/resource/chef_gem_spec.rb
+++ b/spec/unit/resource/chef_gem_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2008, 2012 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::ChefGem, "initialize" do
@@ -26,7 +26,7 @@ describe Chef::Resource::ChefGem, "initialize" do
resource: Chef::Resource::ChefGem,
provider: Chef::Provider::Package::Rubygems,
name: :chef_gem,
- action: :install,
+ action: :install
)
end
@@ -34,16 +34,12 @@ end
describe Chef::Resource::ChefGem, "gem_binary" do
let(:resource) { Chef::Resource::ChefGem.new("foo") }
- before(:each) do
- expect(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("/opt/chef/embedded/bin")
- end
-
it "should raise an exception when gem_binary is set" do
expect { resource.gem_binary("/lol/cats/gem") }.to raise_error(ArgumentError)
end
it "should set the gem_binary based on computing it from RbConfig" do
- expect(resource.gem_binary).to eql("/opt/chef/embedded/bin/gem")
+ expect(resource.gem_binary).to eql("#{RbConfig::CONFIG['bindir']}/gem")
end
it "should set the gem_binary based on computing it from RbConfig" do
@@ -52,7 +48,7 @@ describe Chef::Resource::ChefGem, "gem_binary" do
context "when building the resource" do
let(:node) do
- Chef::Node.new.tap {|n| n.normal[:tags] = [] }
+ Chef::Node.new
end
let(:run_context) do
@@ -74,14 +70,14 @@ describe Chef::Resource::ChefGem, "gem_binary" do
expect(Chef::Resource::ChefGem).to receive(:new).and_return(resource)
end
- it "runs the install at compile-time by default", :chef_lt_13_only do
+ it "runs the install at compile-time by default", chef: "< 13" do
expect(resource).to receive(:run_action).with(:install)
expect(Chef::Log).to receive(:deprecation).at_least(:once)
recipe.chef_gem "foo"
end
# the default behavior will change in Chef-13
- it "does not runs the install at compile-time by default", :chef_gte_13_only do
+ it "does not runs the install at compile-time by default", chef: ">= 13" do
expect(resource).not_to receive(:run_action).with(:install)
expect(Chef::Log).not_to receive(:deprecation)
recipe.chef_gem "foo"
diff --git a/spec/unit/resource/chocolatey_package_spec.rb b/spec/unit/resource/chocolatey_package_spec.rb
new file mode 100644
index 0000000000..9b433045c1
--- /dev/null
+++ b/spec/unit/resource/chocolatey_package_spec.rb
@@ -0,0 +1,79 @@
+#
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::ChocolateyPackage do
+
+ let(:resource) { Chef::Resource::ChocolateyPackage.new("fakey_fakerton") }
+
+ it "should create a new Chef::Resource::ChocolateyPackage" do
+ expect(resource).to be_a_kind_of(Chef::Resource)
+ expect(resource).to be_a_kind_of(Chef::Resource::Package)
+ expect(resource).to be_a_instance_of(Chef::Resource::ChocolateyPackage)
+ end
+
+ it "should have a resource name of :python" do
+ expect(resource.resource_name).to eql(:chocolatey_package)
+ end
+
+ it "should coerce its name to a package_name array" do
+ expect(resource.package_name).to eql(["fakey_fakerton"])
+ end
+
+ it "the package_name setter should coerce to arrays" do
+ resource.package_name("git")
+ expect(resource.package_name).to eql(["git"])
+ end
+
+ it "the package_name setter should accept arrays" do
+ resource.package_name(%w{git unzip})
+ expect(resource.package_name).to eql(%w{git unzip})
+ end
+
+ it "the name should accept arrays" do
+ resource = Chef::Resource::ChocolateyPackage.new(%w{git unzip})
+ expect(resource.package_name).to eql(%w{git unzip})
+ end
+
+ it "the default version should be nil" do
+ expect(resource.version).to eql(nil)
+ end
+
+ it "the version setter should coerce to arrays" do
+ resource.version("1.2.3")
+ expect(resource.version).to eql(["1.2.3"])
+ end
+
+ it "the version setter should accept arrays" do
+ resource.version(["1.2.3", "4.5.6"])
+ expect(resource.version).to eql(["1.2.3", "4.5.6"])
+ end
+
+ it "the default returns should be 0" do
+ expect(resource.returns).to eql([0])
+ end
+
+ # Integer, Array
+ [ 0, [0, 48, 49] ].each do |val|
+ it "supports setting an alternate return value as a #{val.class}" do
+ resource.returns(val)
+ expect(resource.returns).to eql(val)
+ end
+ end
+end
diff --git a/spec/unit/resource/conditional_action_not_nothing_spec.rb b/spec/unit/resource/conditional_action_not_nothing_spec.rb
index d140615cfc..d8a6190ee7 100644
--- a/spec/unit/resource/conditional_action_not_nothing_spec.rb
+++ b/spec/unit/resource/conditional_action_not_nothing_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Xabier de Zuazo (<xabier@onddo.com>)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::ConditionalActionNotNothing do
diff --git a/spec/unit/resource/conditional_spec.rb b/spec/unit/resource/conditional_spec.rb
index 489c1136b1..e84b0980c4 100644
--- a/spec/unit/resource/conditional_spec.rb
+++ b/spec/unit/resource/conditional_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Resource::Conditional do
before do
@@ -28,7 +28,7 @@ describe Chef::Resource::Conditional do
end
it "raises an exception when neither a block or command is given" do
- expect { Chef::Resource::Conditional.send(:new, :always, @parent_resource, nil, {})}.to raise_error(ArgumentError, /requires either a command or a block/)
+ expect { Chef::Resource::Conditional.send(:new, :always, @parent_resource, nil, {}) }.to raise_error(ArgumentError, /requires either a command or a block/)
end
it "does not evaluate a guard interpreter on initialization of the conditional" do
@@ -89,17 +89,17 @@ describe Chef::Resource::Conditional do
end
end
- describe 'after running a command which timed out' do
+ describe "after running a command which timed out" do
before do
@conditional = Chef::Resource::Conditional.only_if(@parent_resource, "false")
allow_any_instance_of(Chef::GuardInterpreter::DefaultGuardInterpreter).to receive(:shell_out).and_raise(Chef::Exceptions::CommandTimeout)
end
- it 'indicates that resource convergence should not continue' do
+ it "indicates that resource convergence should not continue" do
expect(@conditional.continue?).to be_falsey
end
- it 'should log a warning' do
+ it "should log a warning" do
expect(Chef::Log).to receive(:warn).with("Command 'false' timed out")
@conditional.continue?
end
@@ -124,6 +124,29 @@ describe Chef::Resource::Conditional do
expect(@conditional.continue?).to be_falsey
end
end
+
+ describe "after running a block that returns a string value" do
+ before do
+ @conditional = Chef::Resource::Conditional.only_if(@parent_resource) { "some command" }
+ end
+
+ it "logs a warning" do
+ expect(Chef::Log).to receive(:warn).with("only_if block for [] returned \"some command\", did you mean to run a command? If so use 'only_if \"some command\"' in your code.")
+ @conditional.evaluate
+ end
+ end
+
+ describe "after running a block that returns a string value on a sensitive resource" do
+ before do
+ @parent_resource.sensitive(true)
+ @conditional = Chef::Resource::Conditional.only_if(@parent_resource) { "some command" }
+ end
+
+ it "logs a warning" do
+ expect(Chef::Log).to receive(:warn).with("only_if block for [] returned a string, did you mean to run a command?")
+ @conditional.evaluate
+ end
+ end
end
describe "when created as a `not_if`" do
@@ -169,17 +192,17 @@ describe Chef::Resource::Conditional do
end
end
- describe 'after running a command which timed out' do
+ describe "after running a command which timed out" do
before do
- @conditional = Chef::Resource::Conditional.not_if(@parent_resource, "false")
+ @conditional = Chef::Resource::Conditional.not_if(@parent_resource, "false")
allow_any_instance_of(Chef::GuardInterpreter::DefaultGuardInterpreter).to receive(:shell_out).and_raise(Chef::Exceptions::CommandTimeout)
end
- it 'indicates that resource convergence should continue' do
+ it "indicates that resource convergence should continue" do
expect(@conditional.continue?).to be_truthy
end
- it 'should log a warning' do
+ it "should log a warning" do
expect(Chef::Log).to receive(:warn).with("Command 'false' timed out")
@conditional.continue?
end
@@ -204,5 +227,28 @@ describe Chef::Resource::Conditional do
expect(@conditional.continue?).to be_truthy
end
end
+
+ describe "after running a block that returns a string value" do
+ before do
+ @conditional = Chef::Resource::Conditional.not_if(@parent_resource) { "some command" }
+ end
+
+ it "logs a warning" do
+ expect(Chef::Log).to receive(:warn).with("not_if block for [] returned \"some command\", did you mean to run a command? If so use 'not_if \"some command\"' in your code.")
+ @conditional.evaluate
+ end
+ end
+
+ describe "after running a block that returns a string value on a sensitive resource" do
+ before do
+ @parent_resource.sensitive(true)
+ @conditional = Chef::Resource::Conditional.not_if(@parent_resource) { "some command" }
+ end
+
+ it "logs a warning" do
+ expect(Chef::Log).to receive(:warn).with("not_if block for [] returned a string, did you mean to run a command?")
+ @conditional.evaluate
+ end
+ end
end
end
diff --git a/spec/unit/resource/cookbook_file_spec.rb b/spec/unit/resource/cookbook_file_spec.rb
index 834e08bba4..6886ce1f31 100644
--- a/spec/unit/resource/cookbook_file_spec.rb
+++ b/spec/unit/resource/cookbook_file_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
#p License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,20 +17,20 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::CookbookFile do
before do
- @cookbook_file = Chef::Resource::CookbookFile.new('sourcecode_tarball.tgz')
+ @cookbook_file = Chef::Resource::CookbookFile.new("sourcecode_tarball.tgz")
end
it "uses the name parameter for the source parameter" do
- expect(@cookbook_file.name).to eq('sourcecode_tarball.tgz')
+ expect(@cookbook_file.name).to eq("sourcecode_tarball.tgz")
end
it "has a source parameter" do
- @cookbook_file.name('config_file.conf')
- expect(@cookbook_file.name).to eq('config_file.conf')
+ @cookbook_file.name("config_file.conf")
+ expect(@cookbook_file.name).to eq("config_file.conf")
end
it "defaults to a nil cookbook parameter (current cookbook will be used)" do
@@ -39,7 +39,7 @@ describe Chef::Resource::CookbookFile do
it "has a cookbook parameter" do
@cookbook_file.cookbook("munin")
- expect(@cookbook_file.cookbook).to eq('munin')
+ expect(@cookbook_file.cookbook).to eq("munin")
end
it "sets the provider to Chef::Provider::CookbookFile" do
@@ -48,28 +48,27 @@ describe Chef::Resource::CookbookFile do
describe "when it has a backup number, group, mode, owner, source, checksum, and cookbook on nix or path, rights, deny_rights, checksum on windows" do
before do
- if Chef::Platform.windows?
- @cookbook_file.path("C:/temp/origin/file.txt")
- @cookbook_file.rights(:read, "Everyone")
- @cookbook_file.deny_rights(:full_control, "Clumsy_Sam")
- else
- @cookbook_file.path("/tmp/origin/file.txt")
- @cookbook_file.group("wheel")
- @cookbook_file.mode("0664")
- @cookbook_file.owner("root")
- @cookbook_file.source("/tmp/foo.txt")
- @cookbook_file.cookbook("/tmp/cookbooks/cooked.rb")
- end
+ if Chef::Platform.windows?
+ @cookbook_file.path("C:/temp/origin/file.txt")
+ @cookbook_file.rights(:read, "Everyone")
+ @cookbook_file.deny_rights(:full_control, "Clumsy_Sam")
+ else
+ @cookbook_file.path("/tmp/origin/file.txt")
+ @cookbook_file.group("wheel")
+ @cookbook_file.mode("0664")
+ @cookbook_file.owner("root")
+ @cookbook_file.source("/tmp/foo.txt")
+ @cookbook_file.cookbook("/tmp/cookbooks/cooked.rb")
+ end
@cookbook_file.checksum("1" * 64)
end
-
it "describes the state" do
state = @cookbook_file.state
if Chef::Platform.windows?
puts state
- expect(state[:rights]).to eq([{:permissions => :read, :principals => "Everyone"}])
- expect(state[:deny_rights]).to eq([{:permissions => :full_control, :principals => "Clumsy_Sam"}])
+ expect(state[:rights]).to eq([{ :permissions => :read, :principals => "Everyone" }])
+ expect(state[:deny_rights]).to eq([{ :permissions => :full_control, :principals => "Clumsy_Sam" }])
else
expect(state[:group]).to eq("wheel")
expect(state[:mode]).to eq("0664")
diff --git a/spec/unit/resource/cron_spec.rb b/spec/unit/resource/cron_spec.rb
index 0978be6930..6e867b75e1 100644
--- a/spec/unit/resource/cron_spec.rb
+++ b/spec/unit/resource/cron_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2009-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Cron do
@@ -100,25 +100,25 @@ describe Chef::Resource::Cron do
end
it "should allow you to specify environment variables hash" do
- env = {"TEST" => "LOL"}
+ env = { "TEST" => "LOL" }
@resource.environment env
expect(@resource.environment).to eql(env)
end
it "should allow * for all time and date values" do
- [ "minute", "hour", "day", "month", "weekday" ].each do |x|
+ %w{minute hour day month weekday}.each do |x|
expect(@resource.send(x, "*")).to eql("*")
end
end
it "should allow ranges for all time and date values" do
- [ "minute", "hour", "day", "month", "weekday" ].each do |x|
+ %w{minute hour day month weekday}.each do |x|
expect(@resource.send(x, "1-2,5")).to eql("1-2,5")
end
end
it "should have a default value of * for all time and date values" do
- [ "minute", "hour", "day", "month", "weekday" ].each do |x|
+ %w{minute hour day month weekday}.each do |x|
expect(@resource.send(x)).to eql("*")
end
end
@@ -153,7 +153,7 @@ describe Chef::Resource::Cron do
end
it "should convert integer schedule values to a string" do
- [ "minute", "hour", "day", "month", "weekday" ].each do |x|
+ %w{minute hour day month weekday}.each do |x|
expect(@resource.send(x, 5)).to eql("5")
end
end
diff --git a/spec/unit/resource/csh_spec.rb b/spec/unit/resource/csh_spec.rb
index 5fb3b00507..864175fc85 100644
--- a/spec/unit/resource/csh_spec.rb
+++ b/spec/unit/resource/csh_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Csh do
diff --git a/spec/unit/resource/deploy_revision_spec.rb b/spec/unit/resource/deploy_revision_spec.rb
index d136aa251e..aa12b9595d 100644
--- a/spec/unit/resource/deploy_revision_spec.rb
+++ b/spec/unit/resource/deploy_revision_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::DeployRevision do
@@ -25,7 +25,7 @@ describe Chef::Resource::DeployRevision do
resource: Chef::Resource::DeployRevision,
provider: Chef::Provider::Deploy::Revision,
name: :deploy_revision,
- action: :deploy,
+ action: :deploy
)
end
@@ -36,7 +36,7 @@ describe Chef::Resource::DeployBranch do
resource: Chef::Resource::DeployBranch,
provider: Chef::Provider::Deploy::Revision,
name: :deploy_branch,
- action: :deploy,
+ action: :deploy
)
end
diff --git a/spec/unit/resource/deploy_spec.rb b/spec/unit/resource/deploy_spec.rb
index 5b6a452784..33f16b4a89 100644
--- a/spec/unit/resource/deploy_spec.rb
+++ b/spec/unit/resource/deploy_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::Deploy do
@@ -25,21 +25,20 @@ describe Chef::Resource::Deploy do
resource: Chef::Resource::Deploy,
provider: Chef::Provider::Deploy::Timestamped,
name: :deploy,
- action: :deploy,
+ action: :deploy
)
-
class << self
def resource_has_a_string_attribute(attr_name)
- it "has a String attribute for #{attr_name.to_s}" do
+ it "has a String attribute for #{attr_name}" do
@resource.send(attr_name, "this is a string")
expect(@resource.send(attr_name)).to eql("this is a string")
- expect {@resource.send(attr_name, 8675309)}.to raise_error(ArgumentError)
+ expect { @resource.send(attr_name, 8675309) }.to raise_error(ArgumentError)
end
end
- def resource_has_a_boolean_attribute(attr_name, opts={:defaults_to=>false})
- it "has a Boolean attribute for #{attr_name.to_s}" do
+ def resource_has_a_boolean_attribute(attr_name, opts = { :defaults_to => false })
+ it "has a Boolean attribute for #{attr_name}" do
expect(@resource.send(attr_name)).to eql(opts[:defaults_to])
@resource.send(attr_name, !opts[:defaults_to])
expect(@resource.send(attr_name)).to eql( !opts[:defaults_to] )
@@ -49,12 +48,12 @@ describe Chef::Resource::Deploy do
def resource_has_a_callback_attribute(attr_name)
it "has a Callback attribute #{attr_name}" do
callback_block = lambda { :noop }
- expect {@resource.send(attr_name, &callback_block)}.not_to raise_error
+ expect { @resource.send(attr_name, &callback_block) }.not_to raise_error
expect(@resource.send(attr_name)).to eq(callback_block)
callback_file = "path/to/callback.rb"
- expect {@resource.send(attr_name, callback_file)}.not_to raise_error
+ expect { @resource.send(attr_name, callback_file) }.not_to raise_error
expect(@resource.send(attr_name)).to eq(callback_file)
- expect {@resource.send(attr_name, :this_is_fail)}.to raise_error(ArgumentError)
+ expect { @resource.send(attr_name, :this_is_fail) }.to raise_error(ArgumentError)
end
end
end
@@ -80,9 +79,9 @@ describe Chef::Resource::Deploy do
resource_has_a_string_attribute(:svn_arguments)
resource_has_a_string_attribute(:svn_info_args)
- resource_has_a_boolean_attribute(:migrate, :defaults_to=>false)
- resource_has_a_boolean_attribute(:enable_submodules, :defaults_to=>false)
- resource_has_a_boolean_attribute(:shallow_clone, :defaults_to=>false)
+ resource_has_a_boolean_attribute(:migrate, :defaults_to => false)
+ resource_has_a_boolean_attribute(:enable_submodules, :defaults_to => false)
+ resource_has_a_boolean_attribute(:shallow_clone, :defaults_to => false)
it "uses the first argument as the deploy directory" do
expect(@resource.deploy_to).to eql("/my/deploy/dir")
@@ -118,17 +117,17 @@ describe Chef::Resource::Deploy do
expect(@resource.svn_force_export).to be_falsey
@resource.svn_force_export true
expect(@resource.svn_force_export).to be_truthy
- expect {@resource.svn_force_export(10053)}.to raise_error(ArgumentError)
+ expect { @resource.svn_force_export(10053) }.to raise_error(ArgumentError)
end
it "takes arbitrary environment variables in a hash" do
@resource.environment "RAILS_ENV" => "production"
- expect(@resource.environment).to eq({"RAILS_ENV" => "production"})
+ expect(@resource.environment).to eq({ "RAILS_ENV" => "production" })
end
it "takes string arguments to environment for backwards compat, setting RAILS_ENV, RACK_ENV, and MERB_ENV" do
@resource.environment "production"
- expect(@resource.environment).to eq({"RAILS_ENV"=>"production", "RACK_ENV"=>"production","MERB_ENV"=>"production"})
+ expect(@resource.environment).to eq({ "RAILS_ENV" => "production", "RACK_ENV" => "production", "MERB_ENV" => "production" })
end
it "sets destination to $deploy_to/shared/$repository_cache" do
@@ -183,16 +182,16 @@ describe Chef::Resource::Deploy do
end
it 'has a Hash attribute symlinks, default: {"system" => "public/system", "pids" => "tmp/pids", "log" => "log"}' do
- default = { "system" => "public/system", "pids" => "tmp/pids", "log" => "log"}
+ default = { "system" => "public/system", "pids" => "tmp/pids", "log" => "log" }
expect(@resource.symlinks).to eq(default)
@resource.symlinks "foo" => "bar/baz"
- expect(@resource.symlinks).to eq({"foo" => "bar/baz"})
+ expect(@resource.symlinks).to eq({ "foo" => "bar/baz" })
end
it 'has a Hash attribute symlink_before_migrate, default "config/database.yml" => "config/database.yml"' do
- expect(@resource.symlink_before_migrate).to eq({"config/database.yml" => "config/database.yml"})
+ expect(@resource.symlink_before_migrate).to eq({ "config/database.yml" => "config/database.yml" })
@resource.symlink_before_migrate "wtf?" => "wtf is going on"
- expect(@resource.symlink_before_migrate).to eq({"wtf?" => "wtf is going on"})
+ expect(@resource.symlink_before_migrate).to eq({ "wtf?" => "wtf is going on" })
end
resource_has_a_callback_attribute :before_migrate
@@ -206,7 +205,7 @@ describe Chef::Resource::Deploy do
end
it "takes a block for the restart parameter" do
- restart_like_this = lambda {p :noop}
+ restart_like_this = lambda { p :noop }
@resource.restart(&restart_like_this)
expect(@resource.restart).to eq(restart_like_this)
end
@@ -264,8 +263,8 @@ describe Chef::Resource::Deploy do
@resource.group("pokemon")
@resource.scm_provider(Chef::Provider::Git)
@resource.repository_cache("cached-copy")
- @resource.environment({"SUDO" => "TRUE"})
- @resource.symlinks({"system" => "public/system"})
+ @resource.environment({ "SUDO" => "TRUE" })
+ @resource.symlinks({ "system" => "public/system" })
@resource.migrate(false)
end
diff --git a/spec/unit/resource/directory_spec.rb b/spec/unit/resource/directory_spec.rb
index e9e80806db..cfb3ade135 100644
--- a/spec/unit/resource/directory_spec.rb
+++ b/spec/unit/resource/directory_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Directory do
diff --git a/spec/unit/resource/dnf_package_spec.rb b/spec/unit/resource/dnf_package_spec.rb
new file mode 100644
index 0000000000..0cc673d897
--- /dev/null
+++ b/spec/unit/resource/dnf_package_spec.rb
@@ -0,0 +1,99 @@
+#
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
+
+describe Chef::Resource::DnfPackage, "initialize" do
+
+ static_provider_resolution(
+ resource: Chef::Resource::DnfPackage,
+ provider: Chef::Provider::Package::Dnf,
+ name: :dnf_package,
+ action: :install,
+ os: "linux",
+ platform_family: "rhel"
+ )
+
+end
+
+describe Chef::Resource::DnfPackage, "arch" do
+ before(:each) do
+ @resource = Chef::Resource::DnfPackage.new("foo")
+ end
+
+ it "should set the arch variable to whatever is passed in" do
+ @resource.arch("i386")
+ expect(@resource.arch).to eql(["i386"])
+ end
+end
+
+describe Chef::Resource::DnfPackage, "flush_cache" do
+ before(:each) do
+ @resource = Chef::Resource::DnfPackage.new("foo")
+ end
+
+ it "should default the flush timing to false" do
+ flush_hash = { :before => false, :after => false }
+ expect(@resource.flush_cache).to eq(flush_hash)
+ end
+
+ it "should allow you to set the flush timing with an array" do
+ flush_array = [ :before, :after ]
+ flush_hash = { :before => true, :after => true }
+ @resource.flush_cache(flush_array)
+ expect(@resource.flush_cache).to eq(flush_hash)
+ end
+
+ it "should allow you to set the flush timing with a hash" do
+ flush_hash = { :before => true, :after => true }
+ @resource.flush_cache(flush_hash)
+ expect(@resource.flush_cache).to eq(flush_hash)
+ end
+
+ it "should allow 'true' for flush_cache" do
+ @resource.flush_cache(true)
+ expect(@resource.flush_cache).to eq({ before: true, after: true })
+ end
+
+ it "should allow 'false' for flush_cache" do
+ @resource.flush_cache(false)
+ expect(@resource.flush_cache).to eq({ before: false, after: false })
+ end
+
+ it "should allow ':before' for flush_cache" do
+ @resource.flush_cache(:before)
+ expect(@resource.flush_cache).to eq({ before: true, after: false })
+ end
+
+ it "should allow ':after' for flush_cache" do
+ @resource.flush_cache(:after)
+ expect(@resource.flush_cache).to eq({ before: false, after: true })
+ end
+end
+
+describe Chef::Resource::DnfPackage, "allow_downgrade" do
+ before(:each) do
+ @resource = Chef::Resource::DnfPackage.new("foo")
+ end
+
+ it "should allow you to specify whether allow_downgrade is true or false" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect { @resource.allow_downgrade true }.not_to raise_error
+ expect { @resource.allow_downgrade false }.not_to raise_error
+ end
+end
diff --git a/spec/unit/resource/dpkg_package_spec.rb b/spec/unit/resource/dpkg_package_spec.rb
index 931e6763bd..66ad86b861 100644
--- a/spec/unit/resource/dpkg_package_spec.rb
+++ b/spec/unit/resource/dpkg_package_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::DpkgPackage, "initialize" do
@@ -26,7 +26,7 @@ describe Chef::Resource::DpkgPackage, "initialize" do
provider: Chef::Provider::Package::Dpkg,
name: :dpkg_package,
action: :install,
- os: 'linux',
+ os: "linux"
)
end
diff --git a/spec/unit/resource/dsc_resource_spec.rb b/spec/unit/resource/dsc_resource_spec.rb
index 06769d86ce..b687811392 100644
--- a/spec/unit/resource/dsc_resource_spec.rb
+++ b/spec/unit/resource/dsc_resource_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,31 +15,33 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
-require 'spec_helper'
-
+require "spec_helper"
describe Chef::Resource::DscResource do
- let(:dsc_test_resource_name) { 'DSCTest' }
+ let(:dsc_test_resource_name) { "DSCTest" }
+ let(:dsc_test_resource_module_version) { "2.7.2" }
let(:dsc_test_property_name) { :DSCTestProperty }
- let(:dsc_test_property_value) { 'DSCTestValue' }
+ let(:dsc_test_property_value) { "DSCTestValue" }
+ let(:dsc_test_reboot_action) { :reboot_now }
+ let(:dsc_test_timeout) { 101 }
- context 'when Powershell supports Dsc' do
- let(:dsc_test_run_context) {
+ context "when Powershell supports Dsc" do
+ let(:dsc_test_run_context) do
node = Chef::Node.new
- node.automatic[:languages][:powershell][:version] = '5.0.10018.0'
+ node.automatic[:languages][:powershell][:version] = "5.0.10018.0"
empty_events = Chef::EventDispatch::Dispatcher.new
Chef::RunContext.new(node, {}, empty_events)
- }
- let(:dsc_test_resource) {
+ end
+
+ let(:dsc_test_resource) do
Chef::Resource::DscResource.new(dsc_test_resource_name, dsc_test_run_context)
- }
+ end
it "has a default action of `:run`" do
expect(dsc_test_resource.action).to eq([:run])
end
- it "has an allowed_actions attribute with only the `:run` and `:nothing` attributes" do
- expect(dsc_test_resource.allowed_actions.to_set).to eq([:run,:nothing].to_set)
+ it "has an ed_actions attribute with only the `:run` and `:nothing` attributes" do
+ expect(dsc_test_resource.allowed_actions.to_set).to eq([:run, :nothing].to_set)
end
it "allows the resource attribute to be set" do
@@ -52,6 +54,21 @@ describe Chef::Resource::DscResource do
expect(dsc_test_resource.module_name).to eq(dsc_test_resource_name)
end
+ it "allows the module_version attribute to be set" do
+ dsc_test_resource.module_version(dsc_test_resource_module_version)
+ expect(dsc_test_resource.module_version).to eq(dsc_test_resource_module_version)
+ end
+
+ it "allows the reboot_action attribute to be set" do
+ dsc_test_resource.reboot_action(dsc_test_reboot_action)
+ expect(dsc_test_resource.reboot_action).to eq(dsc_test_reboot_action)
+ end
+
+ it "allows the timeout attribute to be set" do
+ dsc_test_resource.timeout(dsc_test_timeout)
+ expect(dsc_test_resource.timeout).to eq(dsc_test_timeout)
+ end
+
context "when setting a dsc property" do
it "allows setting a dsc property with a property name of type Symbol" do
dsc_test_resource.property(dsc_test_property_name, dsc_test_property_value)
@@ -60,23 +77,23 @@ describe Chef::Resource::DscResource do
end
it "raises a TypeError if property_name is not a symbol" do
- expect{
- dsc_test_resource.property('Foo', dsc_test_property_value)
- }.to raise_error(TypeError)
+ expect do
+ dsc_test_resource.property("Foo", dsc_test_property_value)
+ end.to raise_error(TypeError)
end
context "when using DelayedEvaluators" do
it "allows setting a dsc property with a property name of type Symbol" do
- dsc_test_resource.property(dsc_test_property_name, Chef::DelayedEvaluator.new {
+ dsc_test_resource.property(dsc_test_property_name, Chef::DelayedEvaluator.new do
dsc_test_property_value
- })
+ end)
expect(dsc_test_resource.property(dsc_test_property_name)).to eq(dsc_test_property_value)
expect(dsc_test_resource.properties[dsc_test_property_name]).to eq(dsc_test_property_value)
end
end
end
- context 'Powershell DSL methods' do
+ context "Powershell DSL methods" do
it "responds to :ps_credential" do
expect(dsc_test_resource.respond_to?(:ps_credential)).to be true
end
diff --git a/spec/unit/resource/dsc_script_spec.rb b/spec/unit/resource/dsc_script_spec.rb
index 1fa865a2d5..f0c81e43b5 100644
--- a/spec/unit/resource/dsc_script_spec.rb
+++ b/spec/unit/resource/dsc_script_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,33 +16,33 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::DscScript do
- let(:dsc_test_resource_name) { 'DSCTest' }
+ let(:dsc_test_resource_name) { "DSCTest" }
- context 'when Powershell supports Dsc' do
- let(:dsc_test_run_context) {
+ context "when Powershell supports Dsc" do
+ let(:dsc_test_run_context) do
node = Chef::Node.new
- node.automatic[:languages][:powershell][:version] = '4.0'
+ node.automatic[:languages][:powershell][:version] = "4.0"
empty_events = Chef::EventDispatch::Dispatcher.new
Chef::RunContext.new(node, {}, empty_events)
- }
- let(:dsc_test_resource) {
+ end
+ let(:dsc_test_resource) do
Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
- }
- let(:configuration_code) {'echo "This is supposed to create a configuration document."'}
- let(:configuration_path) {'c:/myconfigs/formatc.ps1'}
- let(:configuration_name) { 'formatme' }
+ end
+ let(:configuration_code) { 'echo "This is supposed to create a configuration document."' }
+ let(:configuration_path) { "c:/myconfigs/formatc.ps1" }
+ let(:configuration_name) { "formatme" }
let(:configuration_data) { '@{AllNodes = @( @{ NodeName = "localhost"; PSDscAllowPlainTextPassword = $true })}' }
- let(:configuration_data_script) { 'c:/myconfigs/data/safedata.psd1' }
+ let(:configuration_data_script) { "c:/myconfigs/data/safedata.psd1" }
it "has a default action of `:run`" do
expect(dsc_test_resource.action).to eq([:run])
end
it "has an allowed_actions attribute with only the `:run` and `:nothing` attributes" do
- expect(dsc_test_resource.allowed_actions.to_set).to eq([:run,:nothing].to_set)
+ expect(dsc_test_resource.allowed_actions.to_set).to eq([:run, :nothing].to_set)
end
it "allows the code attribute to be set" do
@@ -75,9 +75,9 @@ describe Chef::Resource::DscScript do
end
context "when calling imports" do
- let(:module_name) { 'FooModule' }
- let(:module_name_b) { 'BarModule' }
- let(:dsc_resources) { ['ResourceA', 'ResourceB'] }
+ let(:module_name) { "FooModule" }
+ let(:module_name_b) { "BarModule" }
+ let(:dsc_resources) { %w{ResourceA ResourceB} }
it "allows an arbitrary number of resources to be set for a module to be set" do
dsc_test_resource.imports module_name, *dsc_resources
@@ -88,7 +88,7 @@ describe Chef::Resource::DscScript do
it "adds * to the imports when no resources are set for a moudle" do
dsc_test_resource.imports module_name
module_imports = dsc_test_resource.imports[module_name]
- expect(module_imports).to eq(['*'])
+ expect(module_imports).to eq(["*"])
end
it "allows an arbitrary number of modules" do
diff --git a/spec/unit/resource/easy_install_package_spec.rb b/spec/unit/resource/easy_install_package_spec.rb
index c68b026b39..ce8e6d8bf6 100644
--- a/spec/unit/resource/easy_install_package_spec.rb
+++ b/spec/unit/resource/easy_install_package_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::EasyInstallPackage, "initialize" do
@@ -25,7 +25,7 @@ describe Chef::Resource::EasyInstallPackage, "initialize" do
resource: Chef::Resource::EasyInstallPackage,
provider: Chef::Provider::Package::EasyInstall,
name: :easy_install_package,
- action: :install,
+ action: :install
)
before(:each) do
diff --git a/spec/unit/resource/env_spec.rb b/spec/unit/resource/env_spec.rb
index 9bee07c593..cff862b69e 100644
--- a/spec/unit/resource/env_spec.rb
+++ b/spec/unit/resource/env_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2010-2016, VMware, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Env do
@@ -38,8 +38,8 @@ describe Chef::Resource::Env do
expect(@resource.action).to eql([:create])
end
- { :create => false, :delete => false, :modify => false, :flibber => true }.each do |action,bad_value|
- it "should #{bad_value ? 'not' : ''} accept #{action.to_s}" do
+ { :create => false, :delete => false, :modify => false, :flibber => true }.each do |action, bad_value|
+ it "should #{bad_value ? 'not' : ''} accept #{action}" do
if bad_value
expect { @resource.action action }.to raise_error(ArgumentError)
else
diff --git a/spec/unit/resource/erl_call_spec.rb b/spec/unit/resource/erl_call_spec.rb
index 9abf2e7812..6d1f45ec63 100644
--- a/spec/unit/resource/erl_call_spec.rb
+++ b/spec/unit/resource/erl_call_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::ErlCall do
diff --git a/spec/unit/resource/execute_spec.rb b/spec/unit/resource/execute_spec.rb
index 09160ddbd0..4c0ee694c3 100644
--- a/spec/unit/resource/execute_spec.rb
+++ b/spec/unit/resource/execute_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Execute do
let(:resource_instance_name) { "some command" }
@@ -32,4 +32,218 @@ describe Chef::Resource::Execute do
expect(execute_resource.is_guard_interpreter).to eq(false)
end
+ describe "#qualify_user" do
+ let(:password) { "password" }
+ let(:domain) { nil }
+
+ context "when username is passed as user@domain" do
+ let(:username) { "user@domain" }
+
+ it "correctly parses the user and domain" do
+ identity = execute_resource.qualify_user(username, password, domain)
+ expect(identity[:domain]).to eq("domain")
+ expect(identity[:user]).to eq("user")
+ end
+ end
+
+ context "when username is passed as domain\\user" do
+ let(:username) { "domain\\user" }
+
+ it "correctly parses the user and domain" do
+ identity = execute_resource.qualify_user(username, password, domain)
+ expect(identity[:domain]).to eq("domain")
+ expect(identity[:user]).to eq("user")
+ end
+ end
+ end
+
+ shared_examples_for "it received valid credentials" do
+ describe "the validation method" do
+ it "should not raise an error" do
+ expect { execute_resource.validate_identity_platform(username, password, domain) }.not_to raise_error
+ end
+ end
+
+ describe "the name qualification method" do
+ it "should correctly translate the user and domain" do
+ identity = nil
+ expect { identity = execute_resource.qualify_user(username, password, domain) }.not_to raise_error
+ expect(identity[:domain]).to eq(domain)
+ expect(identity[:user]).to eq(username)
+ end
+ end
+ end
+
+ shared_examples_for "it received invalid credentials" do
+ describe "the validation method" do
+ it "should raise an error" do
+ expect { execute_resource.validate_identity_platform(username, password, domain) }.to raise_error(ArgumentError)
+ end
+ end
+ end
+
+ shared_examples_for "it received invalid username and domain" do
+ describe "the validation method" do
+ it "should raise an error" do
+ expect { execute_resource.qualify_user(username, password, domain) }.to raise_error(ArgumentError)
+ end
+ end
+ end
+
+ shared_examples_for "it received credentials that are not valid on the platform" do
+ describe "the validation method" do
+ it "should raise an error" do
+ expect { execute_resource.validate_identity_platform(username, password, domain) }.to raise_error(Chef::Exceptions::UnsupportedPlatform)
+ end
+ end
+ end
+
+ shared_examples_for "a consumer of the Execute resource" do
+ context "when running on Windows" do
+ before do
+ allow(execute_resource).to receive(:node).and_return({ :platform_family => "windows" })
+ end
+
+ context "when no user, domain, or password is specified" do
+ let(:username) { nil }
+ let(:domain) { nil }
+ let(:password) { nil }
+ it_behaves_like "it received valid credentials"
+ end
+
+ context "when a valid username is specified" do
+ let(:username) { "starchild" }
+ context "when a valid domain is specified" do
+ let(:domain) { "mothership" }
+
+ context "when the password is not specified" do
+ let(:password) { nil }
+ it_behaves_like "it received invalid credentials"
+ end
+
+ context "when the password is specified" do
+ let(:password) { "we.funk!" }
+ it_behaves_like "it received valid credentials"
+ end
+ end
+
+ context "when the domain is not specified" do
+ let(:domain) { nil }
+
+ context "when the password is not specified" do
+ let(:password) { nil }
+ it_behaves_like "it received invalid credentials"
+ end
+
+ context "when the password is specified" do
+ let(:password) { "we.funk!" }
+ it_behaves_like "it received valid credentials"
+ end
+ end
+
+ context "when username is not specified" do
+ let(:username) { nil }
+
+ context "when domain is specified" do
+ let(:domain) { "mothership" }
+ let(:password) { nil }
+ it_behaves_like "it received invalid username and domain"
+ end
+
+ context "when password is specified" do
+ let(:domain) { nil }
+ let(:password) { "we.funk!" }
+ it_behaves_like "it received invalid username and domain"
+ end
+ end
+ end
+
+ context "when invalid username is specified" do
+ let(:username) { "user@domain@domain" }
+ let(:domain) { nil }
+ let(:password) { "we.funk!" }
+ it_behaves_like "it received invalid username and domain"
+ end
+
+ context "when the domain is provided in both username and domain" do
+ let(:domain) { "some_domain" }
+ let(:password) { "we.funk!" }
+
+ context "when username is in the form domain\\user" do
+ let(:username) { "mothership\\starchild" }
+ it_behaves_like "it received invalid username and domain"
+ end
+
+ context "when username is in the form user@domain" do
+ let(:username) { "starchild@mothership" }
+ it_behaves_like "it received invalid username and domain"
+ end
+ end
+ end
+
+ context "when not running on Windows" do
+ before do
+ allow(execute_resource).to receive(:node).and_return({ :platform_family => "ubuntu" })
+ end
+
+ context "when no user, domain, or password is specified" do
+ let(:username) { nil }
+ let(:domain) { nil }
+ let(:password) { nil }
+ it_behaves_like "it received valid credentials"
+ end
+
+ context "when the user is specified and the domain and password are not" do
+ let(:username) { "starchild" }
+ let(:domain) { nil }
+ let(:password) { nil }
+ it_behaves_like "it received valid credentials"
+
+ context "when the password is specified and the domain is not" do
+ let(:password) { "we.funk!" }
+ let(:domain) { nil }
+ it_behaves_like "it received credentials that are not valid on the platform"
+ end
+
+ context "when the domain is specified and the password is not" do
+ let(:domain) { "mothership" }
+ let(:password) { nil }
+ it_behaves_like "it received credentials that are not valid on the platform"
+ end
+
+ context "when the domain and password are specified" do
+ let(:domain) { "mothership" }
+ let(:password) { "we.funk!" }
+ it_behaves_like "it received credentials that are not valid on the platform"
+ end
+ end
+
+ context "when the user is not specified" do
+ let(:username) { nil }
+ context "when the domain is specified" do
+ let(:domain) { "mothership" }
+ context "when the password is specified" do
+ let(:password) { "we.funk!" }
+ it_behaves_like "it received credentials that are not valid on the platform"
+ end
+
+ context "when password is not specified" do
+ let(:password) { nil }
+ it_behaves_like "it received credentials that are not valid on the platform"
+ end
+ end
+
+ context "when the domain is not specified" do
+ let(:domain) { nil }
+ context "when the password is specified" do
+ let(:password) { "we.funk!" }
+ it_behaves_like "it received credentials that are not valid on the platform"
+ end
+ end
+ end
+ end
+ end
+
+ it_behaves_like "a consumer of the Execute resource"
+
end
diff --git a/spec/unit/resource/file/verification/systemd_unit_spec.rb b/spec/unit/resource/file/verification/systemd_unit_spec.rb
new file mode 100644
index 0000000000..8a3d849582
--- /dev/null
+++ b/spec/unit/resource/file/verification/systemd_unit_spec.rb
@@ -0,0 +1,103 @@
+#
+# Author:: Mal Graty (<mal.graty@googlemail.com>)
+# Copyright:: Copyright 2014-2017, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::File::Verification::SystemdUnit do
+ let(:command) { "#{systemd_analyze_path} verify %{path}" }
+ let(:opts) { { :future => true } }
+ let(:parent_resource) { Chef::Resource.new("llama") }
+ let(:systemd_analyze_path) { "/usr/bin/systemd-analyze" }
+ let(:systemd_dir) { "/etc/systemd/system" }
+ let(:temp_path) { "/tmp" }
+ let(:unit_name) { "sysstat-collect.timer" }
+ let(:unit_path) { "#{systemd_dir}/#{unit_name}" }
+ let(:unit_temp_path) { "#{systemd_dir}/.chef-#{unit_name}" }
+ let(:unit_test_path) { "#{temp_path}/#{unit_name}" }
+
+ describe "verification registration" do
+ it "registers itself for later use" do
+ expect(Chef::Resource::File::Verification.lookup(:systemd_unit)).to eq(Chef::Resource::File::Verification::SystemdUnit)
+ end
+ end
+
+ describe "#initialize" do
+ before(:each) do
+ allow_any_instance_of(Chef::Resource::File::Verification::SystemdUnit).to receive(:which)
+ .with("systemd-analyze")
+ .and_return(systemd_analyze_path)
+ end
+
+ it "overwrites the @command variable with the verification command" do
+ v = Chef::Resource::File::Verification::SystemdUnit.new(parent_resource, :systemd_unit, {})
+ expect(v.instance_variable_get(:@command)).to eql(command)
+ end
+ end
+
+ describe "#verify" do
+ context "with the systemd-analyze binary available" do
+ before(:each) do
+ allow_any_instance_of(Chef::Resource::File::Verification::SystemdUnit).to receive(:which)
+ .with("systemd-analyze")
+ .and_return(systemd_analyze_path)
+
+ allow(parent_resource).to receive(:path)
+ .and_return(unit_path)
+ allow(Dir).to receive(:mktmpdir)
+ .with("chef-systemd-unit") { |&b| b.call temp_path }
+ allow(FileUtils).to receive(:cp)
+ .with(unit_temp_path, unit_test_path)
+ end
+
+ it "copies the temp file to secondary location under correct name" do
+ v = Chef::Resource::File::Verification::SystemdUnit.new(parent_resource, :systemd_unit, {})
+
+ expect(FileUtils).to receive(:cp).with(unit_temp_path, unit_test_path)
+ expect(v).to receive(:verify_command).with(unit_test_path, opts)
+
+ v.verify(unit_temp_path, opts)
+ end
+
+ it "returns the value given by #verify_command" do
+ v = Chef::Resource::File::Verification::SystemdUnit.new(parent_resource, :systemd_unit, {})
+
+ expect(v).to receive(:verify_command)
+ .with(unit_test_path, opts)
+ .and_return("foo")
+
+ expect(v.verify(unit_temp_path, opts)).to eql("foo")
+ end
+ end
+
+ context "with the systemd-analyze binary unavailable" do
+ before(:each) do
+ allow_any_instance_of(Chef::Resource::File::Verification::SystemdUnit).to receive(:which)
+ .with("systemd-analyze")
+ .and_return(false)
+ end
+
+ it "skips verification" do
+ v = Chef::Resource::File::Verification::SystemdUnit.new(parent_resource, :systemd_unit, {})
+
+ expect(v).to_not receive(:verify_command)
+
+ expect(v.verify(unit_temp_path)).to eq(true)
+ end
+ end
+ end
+end
diff --git a/spec/unit/resource/file/verification_spec.rb b/spec/unit/resource/file/verification_spec.rb
index 6b929789c8..6416bb3ad8 100644
--- a/spec/unit/resource/file/verification_spec.rb
+++ b/spec/unit/resource/file/verification_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Steven Danna (<steve@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc
+# Copyright:: Copyright 2014-2016, Chef Software, Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::File::Verification do
let(:t_block) { Proc.new { true } }
let(:f_block) { Proc.new { false } }
- let(:path_block) { Proc.new { |path| path }}
+ let(:path_block) { Proc.new { |path| path } }
let(:temp_path) { "/tmp/foobar" }
describe "verification registration" do
@@ -33,7 +33,7 @@ describe Chef::Resource::File::Verification do
end
it "raises an error if a verification can't be found" do
- expect{Chef::Resource::File::Verification.lookup(:dne)}.to raise_error(Chef::Exceptions::VerificationNotFound)
+ expect { Chef::Resource::File::Verification.lookup(:dne) }.to raise_error(Chef::Exceptions::VerificationNotFound)
end
end
@@ -42,13 +42,13 @@ describe Chef::Resource::File::Verification do
it "expects a string argument" do
v = Chef::Resource::File::Verification.new(parent_resource, nil, {}) {}
- expect{ v.verify("/foo/bar") }.to_not raise_error
- expect{ v.verify }.to raise_error
+ expect { v.verify("/foo/bar") }.to_not raise_error
+ expect { v.verify }.to raise_error(ArgumentError)
end
it "accepts an options hash" do
v = Chef::Resource::File::Verification.new(parent_resource, nil, {}) {}
- expect{ v.verify("/foo/bar", {:future => true}) }.to_not raise_error
+ expect { v.verify("/foo/bar", { :future => true }) }.to_not raise_error
end
context "with a verification block" do
@@ -82,27 +82,27 @@ describe Chef::Resource::File::Verification do
end
it "substitutes \%{file} with the path" do
- test_command = platform_specific_verify_command('file')
+ test_command = platform_specific_verify_command("file")
v = Chef::Resource::File::Verification.new(parent_resource, test_command, {})
expect(v.verify(temp_path)).to eq(true)
end
it "warns about deprecation when \%{file} is used" do
- expect(Chef::Log).to receive(:deprecation).with(/%{file} is deprecated/, /verification_spec\.rb/)
- test_command = platform_specific_verify_command('file')
+ expect(Chef).to receive(:deprecated).with(:verify_file, /%{file} is deprecated/)
+ test_command = platform_specific_verify_command("file")
Chef::Resource::File::Verification.new(parent_resource, test_command, {})
.verify(temp_path)
end
it "does not warn about deprecation when \%{file} is not used" do
expect(Chef::Log).to_not receive(:deprecation)
- test_command = platform_specific_verify_command('path')
+ test_command = platform_specific_verify_command("path")
Chef::Resource::File::Verification.new(parent_resource, test_command, {})
.verify(temp_path)
end
it "substitutes \%{path} with the path" do
- test_command = platform_specific_verify_command('path')
+ test_command = platform_specific_verify_command("path")
v = Chef::Resource::File::Verification.new(parent_resource, test_command, {})
expect(v.verify(temp_path)).to eq(true)
end
diff --git a/spec/unit/resource/file_spec.rb b/spec/unit/resource/file_spec.rb
index 76beaf15e1..19304cb6b8 100644
--- a/spec/unit/resource/file_spec.rb
+++ b/spec/unit/resource/file_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::File do
@@ -67,11 +67,11 @@ describe Chef::Resource::File do
end
it "should accept a block, symbol, or string for verify" do
- expect {@resource.verify {}}.not_to raise_error
- expect {@resource.verify ""}.not_to raise_error
- expect {@resource.verify :json}.not_to raise_error
- expect {@resource.verify true}.to raise_error
- expect {@resource.verify false}.to raise_error
+ expect { @resource.verify {} }.not_to raise_error
+ expect { @resource.verify "" }.not_to raise_error
+ expect { @resource.verify :json }.not_to raise_error
+ expect { @resource.verify true }.to raise_error(ArgumentError)
+ expect { @resource.verify false }.to raise_error(ArgumentError)
end
it "should accept multiple verify statements" do
@@ -122,8 +122,8 @@ describe Chef::Resource::File do
end
it "describes its state including windows ACL attributes" do
state = @resource.state
- expect(state[:rights]).to eq([ {:permissions => :read, :principals => "Everyone"},
- {:permissions => :full_control, :principals => "DOMAIN\User"} ])
+ expect(state[:rights]).to eq([ { :permissions => :read, :principals => "Everyone" },
+ { :permissions => :full_control, :principals => "DOMAIN\User" } ])
end
end
diff --git a/spec/unit/resource/freebsd_package_spec.rb b/spec/unit/resource/freebsd_package_spec.rb
index 7263d3a7ba..ce4300497e 100644
--- a/spec/unit/resource/freebsd_package_spec.rb
+++ b/spec/unit/resource/freebsd_package_spec.rb
@@ -1,8 +1,8 @@
#
-# Authors:: AJ Christensen (<aj@opscode.com>)
+# Authors:: AJ Christensen (<aj@chef.io>)
# Richard Manyanza (<liseki@nyikacraftsmen.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2014 Richard Manyanza.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2014-2016, Richard Manyanza.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Resource::FreebsdPackage do
before(:each) do
@@ -29,7 +29,6 @@ describe Chef::Resource::FreebsdPackage do
@resource = Chef::Resource::FreebsdPackage.new("foo", @run_context)
end
-
describe "Initialization" do
it "should return a Chef::Resource::FreebsdPackage" do
expect(@resource).to be_a_kind_of(Chef::Resource::FreebsdPackage)
@@ -44,20 +43,19 @@ describe Chef::Resource::FreebsdPackage do
end
end
-
describe "Assigning provider after creation" do
describe "if ports specified as source" do
it "should be Freebsd::Port" do
- @resource.source('ports')
+ @resource.source("ports")
@resource.after_created
expect(@resource.provider).to eq(Chef::Provider::Package::Freebsd::Port)
end
end
- describe "if __Freebsd_version is greater than or equal to 1000017" do
+ describe "if freebsd_version is greater than or equal to 1000017" do
it "should be Freebsd::Pkgng" do
- [1000017, 1000018, 1000500, 1001001, 1100000].each do |__freebsd_version|
- @node.automatic_attrs[:os_version] = __freebsd_version
+ [1000017, 1000018, 1000500, 1001001, 1100000].each do |freebsd_version|
+ @node.automatic_attrs[:os_version] = freebsd_version
@resource.after_created
expect(@resource.provider).to eq(Chef::Provider::Package::Freebsd::Pkgng)
end
@@ -67,19 +65,19 @@ describe Chef::Resource::FreebsdPackage do
describe "if pkgng enabled" do
it "should be Freebsd::Pkgng" do
pkg_enabled = OpenStruct.new(:stdout => "yes\n")
- allow(@resource).to receive(:shell_out!).with("make -V WITH_PKGNG", :env => nil).and_return(pkg_enabled)
+ allow(@resource).to receive(:shell_out!).with("make", "-V", "WITH_PKGNG", :env => nil).and_return(pkg_enabled)
@resource.after_created
expect(@resource.provider).to eq(Chef::Provider::Package::Freebsd::Pkgng)
end
end
- describe "if __Freebsd_version is less than 1000017 and pkgng not enabled" do
+ describe "if freebsd_version is less than 1000017 and pkgng not enabled" do
it "should be Freebsd::Pkg" do
pkg_enabled = OpenStruct.new(:stdout => "\n")
- allow(@resource).to receive(:shell_out!).with("make -V WITH_PKGNG", :env => nil).and_return(pkg_enabled)
+ allow(@resource).to receive(:shell_out!).with("make", "-V", "WITH_PKGNG", :env => nil).and_return(pkg_enabled)
- [1000016, 1000000, 901503, 902506, 802511].each do |__freebsd_version|
- @node.automatic_attrs[:os_version] = __freebsd_version
+ [1000016, 1000000, 901503, 902506, 802511].each do |freebsd_version|
+ @node.automatic_attrs[:os_version] = freebsd_version
@resource.after_created
expect(@resource.provider).to eq(Chef::Provider::Package::Freebsd::Pkg)
end
@@ -87,4 +85,3 @@ describe Chef::Resource::FreebsdPackage do
end
end
end
-
diff --git a/spec/unit/resource/gem_package_spec.rb b/spec/unit/resource/gem_package_spec.rb
index 0f3eae70bb..a1571ab9bb 100644
--- a/spec/unit/resource/gem_package_spec.rb
+++ b/spec/unit/resource/gem_package_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::GemPackage, "initialize" do
@@ -25,7 +25,7 @@ describe Chef::Resource::GemPackage, "initialize" do
resource: Chef::Resource::GemPackage,
provider: Chef::Provider::Package::Rubygems,
name: :gem_package,
- action: :install,
+ action: :install
)
end
diff --git a/spec/unit/resource/git_spec.rb b/spec/unit/resource/git_spec.rb
index 6a39b3d172..15c1e54f25 100644
--- a/spec/unit/resource/git_spec.rb
+++ b/spec/unit/resource/git_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::Git do
@@ -25,7 +25,7 @@ describe Chef::Resource::Git do
resource: Chef::Resource::Git,
provider: Chef::Provider::Git,
name: :git,
- action: :sync,
+ action: :sync
)
before(:each) do
diff --git a/spec/unit/resource/group_spec.rb b/spec/unit/resource/group_spec.rb
index a4029fc911..9d9b5c1111 100644
--- a/spec/unit/resource/group_spec.rb
+++ b/spec/unit/resource/group_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>);
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>);
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Group, "initialize" do
before(:each) do
@@ -110,9 +110,14 @@ describe Chef::Resource::Group, "members" do
expect(@resource.send(method)).to eql(["aj"])
end
+ it "(#{method}) should split a string on commas" do
+ @resource.send(method, "aj,adam")
+ expect(@resource.send(method)).to eql( %w{aj adam} )
+ end
+
it "(#{method}) should allow an array" do
- @resource.send(method, [ "aj", "adam" ])
- expect(@resource.send(method)).to eql( ["aj", "adam"] )
+ @resource.send(method, %w{aj adam})
+ expect(@resource.send(method)).to eql( %w{aj adam} )
end
it "(#{method}) should not allow a hash" do
@@ -142,12 +147,12 @@ describe Chef::Resource::Group, "append" do
describe "when it has members" do
before do
@resource.group_name("pokemon")
- @resource.members(["blastoise", "pikachu"])
+ @resource.members(%w{blastoise pikachu})
end
it "describes its state" do
state = @resource.state
- expect(state[:members]).to eql(["blastoise", "pikachu"])
+ expect(state[:members]).to eql(%w{blastoise pikachu})
end
it "returns the group name as its identity" do
diff --git a/spec/unit/resource/homebrew_package_spec.rb b/spec/unit/resource/homebrew_package_spec.rb
index bb248d1189..cfcfcd9c3a 100644
--- a/spec/unit/resource/homebrew_package_spec.rb
+++ b/spec/unit/resource/homebrew_package_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Joshua Timberman (<joshua@getchef.com>)
-# Copyright (c) 2014, Chef Software, Inc. <legal@getchef.com>
+# Author:: Joshua Timberman (<joshua@chef.io>)
+# Copyright 2014-2016, Chef Software, Inc. <legal@chef.io>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,35 +15,35 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
-describe Chef::Resource::HomebrewPackage, 'initialize' do
+describe Chef::Resource::HomebrewPackage, "initialize" do
static_provider_resolution(
resource: Chef::Resource::HomebrewPackage,
provider: Chef::Provider::Package::Homebrew,
name: :homebrew_package,
action: :install,
- os: "mac_os_x",
+ os: "mac_os_x"
)
- let(:resource) { Chef::Resource::HomebrewPackage.new('emacs') }
+ let(:resource) { Chef::Resource::HomebrewPackage.new("emacs") }
- shared_examples 'home_brew user set and returned' do
- it 'returns the configured homebrew_user' do
+ shared_examples "home_brew user set and returned" do
+ it "returns the configured homebrew_user" do
resource.homebrew_user user
expect(resource.homebrew_user).to eql(user)
end
end
- context 'homebrew_user is set' do
- let(:user) { 'Captain Picard' }
- include_examples 'home_brew user set and returned'
+ context "homebrew_user is set" do
+ let(:user) { "Captain Picard" }
+ include_examples "home_brew user set and returned"
- context 'as an integer' do
+ context "as an integer" do
let(:user) { 1001 }
- include_examples 'home_brew user set and returned'
+ include_examples "home_brew user set and returned"
end
end
diff --git a/spec/unit/resource/http_request_spec.rb b/spec/unit/resource/http_request_spec.rb
index aa4ce4dfbc..318a154b88 100644
--- a/spec/unit/resource/http_request_spec.rb
+++ b/spec/unit/resource/http_request_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::HttpRequest do
@@ -48,7 +48,7 @@ describe Chef::Resource::HttpRequest do
before do
@resource.url("http://www.trololol.net")
@resource.message("Get sum post brah.")
- @resource.headers({"head" => "tail"})
+ @resource.headers({ "head" => "tail" })
end
it "returns the url as its identity" do
diff --git a/spec/unit/resource/ifconfig_spec.rb b/spec/unit/resource/ifconfig_spec.rb
index e3e1f6daa2..eceba0c319 100644
--- a/spec/unit/resource/ifconfig_spec.rb
+++ b/spec/unit/resource/ifconfig_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Ifconfig do
@@ -49,8 +49,8 @@ describe Chef::Resource::Ifconfig do
shared_examples "being a platform based on an old Debian" do |platform, version|
before do
- @node.automatic_attrs[:os] = 'linux'
- @node.automatic_attrs[:platform_family] = 'debian'
+ @node.automatic_attrs[:os] = "linux"
+ @node.automatic_attrs[:platform_family] = "debian"
@node.automatic_attrs[:platform] = platform
@node.automatic_attrs[:platform_version] = version
end
@@ -62,8 +62,8 @@ describe Chef::Resource::Ifconfig do
shared_examples "being a platform based on RedHat" do |platform, version|
before do
- @node.automatic_attrs[:os] = 'linux'
- @node.automatic_attrs[:platform_family] = 'rhel'
+ @node.automatic_attrs[:os] = "linux"
+ @node.automatic_attrs[:platform_family] = "rhel"
@node.automatic_attrs[:platform] = platform
@node.automatic_attrs[:platform_version] = version
end
@@ -75,8 +75,8 @@ describe Chef::Resource::Ifconfig do
shared_examples "being a platform based on a recent Debian" do |platform, version|
before do
- @node.automatic_attrs[:os] = 'linux'
- @node.automatic_attrs[:platform_family] = 'debian'
+ @node.automatic_attrs[:os] = "linux"
+ @node.automatic_attrs[:platform_family] = "debian"
@node.automatic_attrs[:platform] = platform
@node.automatic_attrs[:platform_version] = version
end
diff --git a/spec/unit/resource/ips_package_spec.rb b/spec/unit/resource/ips_package_spec.rb
index 126ae00224..fd1fe2840c 100644
--- a/spec/unit/resource/ips_package_spec.rb
+++ b/spec/unit/resource/ips_package_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Bryan McLellan <btm@opscode.com>
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Bryan McLellan <btm@chef.io>
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::IpsPackage, "initialize" do
@@ -26,7 +26,7 @@ describe Chef::Resource::IpsPackage, "initialize" do
provider: Chef::Provider::Package::Ips,
name: :ips_package,
action: :install,
- os: "solaris2",
+ os: "solaris2"
)
before(:each) do
diff --git a/spec/unit/resource/ksh_spec.rb b/spec/unit/resource/ksh_spec.rb
new file mode 100644
index 0000000000..6c3ba291b4
--- /dev/null
+++ b/spec/unit/resource/ksh_spec.rb
@@ -0,0 +1,40 @@
+#
+# Author:: Nolan Davidson (<nolan.davidson@gmail.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::Ksh do
+
+ before(:each) do
+ @resource = Chef::Resource::Ksh.new("fakey_fakerton")
+ end
+
+ it "should create a new Chef::Resource::Ksh" do
+ expect(@resource).to be_a_kind_of(Chef::Resource)
+ expect(@resource).to be_a_kind_of(Chef::Resource::Ksh)
+ end
+
+ it "should have a resource name of :ksh" do
+ expect(@resource.resource_name).to eql(:ksh)
+ end
+
+ it "should have an interpreter of ksh" do
+ expect(@resource.interpreter).to eql("ksh")
+ end
+
+end
diff --git a/spec/unit/resource/launchd_spec.rb b/spec/unit/resource/launchd_spec.rb
new file mode 100644
index 0000000000..98d21a8234
--- /dev/null
+++ b/spec/unit/resource/launchd_spec.rb
@@ -0,0 +1,32 @@
+#
+
+require "spec_helper"
+
+describe Chef::Resource::Launchd do
+ @launchd = Chef::Resource::Launchd.new("io.chef.chef-client")
+ let(:resource) do
+ Chef::Resource::Launchd.new(
+ "io.chef.chef-client",
+ run_context
+ ) end
+
+ it "should create a new Chef::Resource::Launchd" do
+ expect(resource).to be_a_kind_of(Chef::Resource)
+ expect(resource).to be_a_kind_of(Chef::Resource::Launchd)
+ end
+
+ it "should have a resource name of Launchd" do
+ expect(resource.resource_name).to eql(:launchd)
+ end
+
+ it "should have a default action of create" do
+ expect(resource.action).to eql([:create])
+ end
+
+ it "should accept enable, disable, create, and delete as actions" do
+ expect { resource.action :enable }.not_to raise_error
+ expect { resource.action :disable }.not_to raise_error
+ expect { resource.action :create }.not_to raise_error
+ expect { resource.action :delete }.not_to raise_error
+ end
+end
diff --git a/spec/unit/resource/link_spec.rb b/spec/unit/resource/link_spec.rb
index 0246fcd13b..bd0976d8ea 100644
--- a/spec/unit/resource/link_spec.rb
+++ b/spec/unit/resource/link_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Link do
@@ -39,8 +39,8 @@ describe Chef::Resource::Link do
expect(@resource.action).to eql([:create])
end
- { :create => false, :delete => false, :blues => true }.each do |action,bad_value|
- it "should #{bad_value ? 'not' : ''} accept #{action.to_s}" do
+ { :create => false, :delete => false, :blues => true }.each do |action, bad_value|
+ it "should #{bad_value ? 'not' : ''} accept #{action}" do
if bad_value
expect { @resource.action action }.to raise_error(ArgumentError)
else
diff --git a/spec/unit/resource/log_spec.rb b/spec/unit/resource/log_spec.rb
index b2af194238..18a1eb65bf 100644
--- a/spec/unit/resource/log_spec.rb
+++ b/spec/unit/resource/log_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Cary Penniman (<cary@rightscale.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Log do
diff --git a/spec/unit/resource/macports_package_spec.rb b/spec/unit/resource/macports_package_spec.rb
index 0a203b2e97..62346def2d 100644
--- a/spec/unit/resource/macports_package_spec.rb
+++ b/spec/unit/resource/macports_package_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: David Balatero (<dbalatero@gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::MacportsPackage, "initialize" do
@@ -26,7 +26,7 @@ describe Chef::Resource::MacportsPackage, "initialize" do
provider: Chef::Provider::Package::Macports,
name: :macports_package,
action: :install,
- os: "mac_os_x",
+ os: "mac_os_x"
)
end
diff --git a/spec/unit/resource/mdadm_spec.rb b/spec/unit/resource/mdadm_spec.rb
index 6ca99c58e5..fe9acf807b 100644
--- a/spec/unit/resource/mdadm_spec.rb
+++ b/spec/unit/resource/mdadm_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Joe Williams (<joe@joetify.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2009-2016, Joe Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Mdadm do
@@ -65,8 +65,13 @@ describe Chef::Resource::Mdadm do
end
it "should allow you to set the bitmap attribute" do
- @resource.metadata "internal"
- expect(@resource.metadata).to eql("internal")
+ @resource.bitmap "internal"
+ expect(@resource.bitmap).to eql("internal")
+ end
+
+ it "should allow you to set the layout attribute" do
+ @resource.layout "f2"
+ expect(@resource.layout).to eql("f2")
end
it "should allow you to set the devices attribute" do
@@ -82,14 +87,14 @@ describe Chef::Resource::Mdadm do
describe "when it has devices, level, and chunk" do
before do
@resource.raid_device("raider")
- @resource.devices(["device1", "device2"])
+ @resource.devices(%w{device1 device2})
@resource.level(1)
@resource.chunk(42)
end
it "describes its state" do
state = @resource.state
- expect(state[:devices]).to eql(["device1", "device2"])
+ expect(state[:devices]).to eql(%w{device1 device2})
expect(state[:level]).to eq(1)
expect(state[:chunk]).to eq(42)
end
diff --git a/spec/unit/resource/mount_spec.rb b/spec/unit/resource/mount_spec.rb
index acce26dcab..832f7644ac 100644
--- a/spec/unit/resource/mount_spec.rb
+++ b/spec/unit/resource/mount_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Joshua Timberman (<joshua@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc
+# Author:: Joshua Timberman (<joshua@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Mount do
before(:each) do
@@ -41,9 +41,10 @@ describe Chef::Resource::Mount do
expect(@resource.action).to eql([:mount])
end
- it "should accept mount, umount and remount as actions" do
+ it "should accept mount, umount, unmount and remount as actions" do
expect { @resource.action :mount }.not_to raise_error
expect { @resource.action :umount }.not_to raise_error
+ expect { @resource.action :unmount }.not_to raise_error
expect { @resource.action :remount }.not_to raise_error
expect { @resource.action :brooklyn }.to raise_error(ArgumentError)
end
@@ -54,7 +55,7 @@ describe Chef::Resource::Mount do
end
it "should set fsck_device to '-' by default" do
- expect(@resource.fsck_device).to eql('-')
+ expect(@resource.fsck_device).to eql("-")
end
it "should allow you to set the fsck_device attribute" do
@@ -87,19 +88,19 @@ describe Chef::Resource::Mount do
end
it "should allow options attribute as an array" do
- @resource.options ["ro", "nosuid"]
+ @resource.options %w{ro nosuid}
expect(@resource.options).to be_a_kind_of(Array)
end
it "should allow options to be sent as a delayed evaluator" do
- @resource.options Chef::DelayedEvaluator.new {["rw", "noexec"]}
- expect(@resource.options).to eql(["rw", "noexec"])
+ @resource.options Chef::DelayedEvaluator.new { %w{rw noexec} }
+ expect(@resource.options).to eql(%w{rw noexec})
end
it "should allow options to be sent as a delayed evaluator, and convert to array" do
- @resource.options Chef::DelayedEvaluator.new {"rw,noexec"}
+ @resource.options Chef::DelayedEvaluator.new { "rw,noexec" }
expect(@resource.options).to be_a_kind_of(Array)
- expect(@resource.options).to eql(["rw", "noexec"])
+ expect(@resource.options).to eql(%w{rw noexec})
end
it "should accept true for mounted" do
diff --git a/spec/unit/resource/msu_package_spec.rb b/spec/unit/resource/msu_package_spec.rb
new file mode 100644
index 0000000000..349a382b31
--- /dev/null
+++ b/spec/unit/resource/msu_package_spec.rb
@@ -0,0 +1,49 @@
+#
+# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::MsuPackage do
+ let(:resource) { Chef::Resource::MsuPackage.new("test_pkg") }
+
+ it "creates a new Chef::Resource::MsuPackage" do
+ expect(resource).to be_a_kind_of(Chef::Resource)
+ expect(resource).to be_a_kind_of(Chef::Resource::Package)
+ expect(resource).to be_a_instance_of(Chef::Resource::MsuPackage)
+ end
+
+ it "sets resource name as :msu_package" do
+ expect(resource.resource_name).to eql(:msu_package)
+ end
+
+ it "sets the source as it's name" do
+ expect(resource.source).to eql("test_pkg")
+ end
+
+ it "sets the default action as :install" do
+ expect(resource.action).to eql(:install)
+ end
+
+ it "raises error if invalid action is given" do
+ expect { resource.action "abc" }.to raise_error(Chef::Exceptions::ValidationFailed)
+ end
+
+ it "coerce its name to a package_name" do
+ expect(resource.package_name).to eql("test_pkg")
+ end
+end
diff --git a/spec/unit/resource/ohai_spec.rb b/spec/unit/resource/ohai_spec.rb
index 3bc21a41d2..cf1748002b 100644
--- a/spec/unit/resource/ohai_spec.rb
+++ b/spec/unit/resource/ohai_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Michael Leinartas (<mleinartas@gmail.com>)
-# Copyright:: Copyright (c) 2010 Michael Leinartas
+# Copyright:: Copyright 2010-2016, Michael Leinartas
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Ohai do
@@ -33,7 +33,7 @@ describe Chef::Resource::Ohai do
expect(@resource.resource_name).to eql(:ohai)
end
- it "should have a default action of create" do
+ it "should have a default action of reload" do
expect(@resource.action).to eql([:reload])
end
@@ -58,5 +58,4 @@ describe Chef::Resource::Ohai do
end
end
-
end
diff --git a/spec/unit/resource/openbsd_package_spec.rb b/spec/unit/resource/openbsd_package_spec.rb
index 95921c2f02..9bdc823576 100644
--- a/spec/unit/resource/openbsd_package_spec.rb
+++ b/spec/unit/resource/openbsd_package_spec.rb
@@ -1,9 +1,9 @@
#
-# Authors:: AJ Christensen (<aj@opscode.com>)
+# Authors:: AJ Christensen (<aj@chef.io>)
# Richard Manyanza (<liseki@nyikacraftsmen.com>)
# Scott Bonds (<scott@ggr.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2014 Richard Manyanza, Scott Bonds
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2014-2016, Richard Manyanza, Scott Bonds
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,8 +19,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Chef::Resource::OpenbsdPackage do
@@ -46,4 +46,3 @@ describe Chef::Resource::OpenbsdPackage do
end
end
-
diff --git a/spec/unit/resource/osx_profile_spec.rb b/spec/unit/resource/osx_profile_spec.rb
new file mode 100644
index 0000000000..513e570e7c
--- /dev/null
+++ b/spec/unit/resource/osx_profile_spec.rb
@@ -0,0 +1,62 @@
+#
+# Author:: Nate Walck (<nate.walck@gmail.com>)
+# Copyright:: Copyright 2015-2016, Facebook, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::OsxProfile do
+ let(:resource) do
+ Chef::Resource::OsxProfile.new(
+ "Test Profile Resource",
+ run_context)
+ end
+
+ it "should create a new Chef::Resource::OsxProfile" do
+ expect(resource).to be_a_kind_of(Chef::Resource)
+ expect(resource).to be_a_kind_of(Chef::Resource::OsxProfile)
+ end
+
+ it "should have a resource name of profile" do
+ expect(resource.resource_name).to eql(:osx_profile)
+ end
+
+ it "should have a default action of install" do
+ expect(resource.action).to eql([:install])
+ end
+
+ it "should accept install and remove as actions" do
+ expect { resource.action :install }.not_to raise_error
+ expect { resource.action :remove }.not_to raise_error
+ end
+
+ it "should allow you to set the profile attribute" do
+ resource.profile "com.testprofile.screensaver"
+ expect(resource.profile).to eql("com.testprofile.screensaver")
+ end
+
+ it "should allow you to set the profile attribute to a string" do
+ resource.profile "com.testprofile.screensaver"
+ expect(resource.profile).to be_a(String)
+ expect(resource.profile).to eql("com.testprofile.screensaver")
+ end
+
+ it "should allow you to set the profile attribute to a hash" do
+ test_profile = { "profile" => false }
+ resource.profile test_profile
+ expect(resource.profile).to be_a(Hash)
+ end
+end
diff --git a/spec/unit/resource/package_spec.rb b/spec/unit/resource/package_spec.rb
index 449732a3c4..7ec3c198e4 100644
--- a/spec/unit/resource/package_spec.rb
+++ b/spec/unit/resource/package_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Package do
@@ -50,8 +50,8 @@ describe Chef::Resource::Package do
end
it "should accept a hash for response file template variables" do
- @resource.response_file_variables({:variables => true})
- expect(@resource.response_file_variables).to eql({:variables => true})
+ @resource.response_file_variables({ :variables => true })
+ expect(@resource.response_file_variables).to eql({ :variables => true })
end
it "should accept a string for the source" do
@@ -80,6 +80,11 @@ describe Chef::Resource::Package do
it "returns the file path as its identity" do
expect(@resource.identity).to eq("tomcat")
end
+
+ it "takes options as an array" do
+ @resource.options [ "-a", "-l" ]
+ expect(@resource.options).to eq(["-a", "-l" ])
+ end
end
# String, Integer
diff --git a/spec/unit/resource/pacman_package_spec.rb b/spec/unit/resource/pacman_package_spec.rb
index 975863d04f..b9d2ea21f6 100644
--- a/spec/unit/resource/pacman_package_spec.rb
+++ b/spec/unit/resource/pacman_package_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Jan Zimmek (<jan.zimmek@web.de>)
-# Copyright:: Copyright (c) 2010 Jan Zimmek
+# Copyright:: Copyright 2010-2016, Jan Zimmek
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::PacmanPackage, "initialize" do
@@ -26,7 +26,7 @@ describe Chef::Resource::PacmanPackage, "initialize" do
provider: Chef::Provider::Package::Pacman,
name: :pacman_package,
action: :install,
- os: "linux",
+ os: "linux"
)
end
diff --git a/spec/unit/resource/perl_spec.rb b/spec/unit/resource/perl_spec.rb
index 7247cce6e3..417d74a8c2 100644
--- a/spec/unit/resource/perl_spec.rb
+++ b/spec/unit/resource/perl_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Perl do
diff --git a/spec/unit/resource/portage_package_spec.rb b/spec/unit/resource/portage_package_spec.rb
index d2ac7ac4be..d2336744bf 100644
--- a/spec/unit/resource/portage_package_spec.rb
+++ b/spec/unit/resource/portage_package_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/spec/unit/resource/powershell_package_spec.rb b/spec/unit/resource/powershell_package_spec.rb
new file mode 100644
index 0000000000..ff4aa991a7
--- /dev/null
+++ b/spec/unit/resource/powershell_package_spec.rb
@@ -0,0 +1,68 @@
+#
+# Author:: Dheeraj Dubey(<dheeraj.dubey@msystechnologies.com>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::PowershellPackage do
+
+ let(:resource) { Chef::Resource::PowershellPackage.new("test_package") }
+
+ it "should create a new Chef::Resource::PowershellPackage" do
+ expect(resource).to be_a_kind_of(Chef::Resource)
+ expect(resource).to be_a_kind_of(Chef::Resource::Package)
+ expect(resource).to be_a_instance_of(Chef::Resource::PowershellPackage)
+ end
+
+ #to check the value of resource.resource_name
+ it "should have a resource name of :python" do
+ expect(resource.resource_name).to eql(:powershell_package)
+ end
+
+ it "should coerce its name to a package_name array" do
+ expect(resource.package_name).to eql(["test_package"])
+ end
+
+ it "the package_name setter should coerce to arrays" do
+ resource.package_name("git")
+ expect(resource.package_name).to eql(["git"])
+ end
+
+ it "the package_name setter should accept arrays" do
+ resource.package_name(%w{git unzip})
+ expect(resource.package_name).to eql(%w{git unzip})
+ end
+
+ it "the name should accept arrays" do
+ resource = Chef::Resource::PowershellPackage.new(%w{git unzip})
+ expect(resource.package_name).to eql(%w{git unzip})
+ end
+
+ it "the default version should be nil" do
+ expect(resource.version).to eql(nil)
+ end
+
+ it "the version setter should coerce to arrays" do
+ resource.version("1.2.3")
+ expect(resource.version).to eql(["1.2.3"])
+ end
+
+ it "the version setter should accept arrays" do
+ resource.version(["1.2.3", "4.5.6"])
+ expect(resource.version).to eql(["1.2.3", "4.5.6"])
+ end
+end
diff --git a/spec/unit/resource/powershell_script_spec.rb b/spec/unit/resource/powershell_script_spec.rb
index 42fcd61a58..6457090608 100644
--- a/spec/unit/resource/powershell_script_spec.rb
+++ b/spec/unit/resource/powershell_script_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards (<adamed@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::PowershellScript do
@@ -25,7 +25,7 @@ describe Chef::Resource::PowershellScript do
node.default["kernel"] = Hash.new
node.default["kernel"][:machine] = :x86_64.to_s
- node.automatic[:os] = 'windows'
+ node.automatic[:os] = "windows"
run_context = Chef::RunContext.new(node, nil, nil)
@@ -49,7 +49,7 @@ describe Chef::Resource::PowershellScript do
it "raises an error when architecture is i386 on Windows Nano Server" do
allow(Chef::Platform).to receive(:windows_nano_server?).and_return(true)
- expect{@resource.architecture(:i386)}.to raise_error(Chef::Exceptions::Win32ArchitectureIncorrect, "cannot execute script with requested architecture 'i386' on Windows Nano Server")
+ expect { @resource.architecture(:i386) }.to raise_error(Chef::Exceptions::Win32ArchitectureIncorrect, "cannot execute script with requested architecture 'i386' on Windows Nano Server")
end
context "when using guards" do
@@ -87,38 +87,38 @@ describe Chef::Resource::PowershellScript do
it "enables convert_boolean_return by default for guards in the context of powershell_script when no guard params are specified" do
allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(true)
allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
- {:convert_boolean_return => true, :code => "$true"}).and_return(Proc.new {})
+ { :convert_boolean_return => true, :code => "$true" }).and_return(Proc.new {})
resource.only_if("$true")
end
it "enables convert_boolean_return by default for guards in non-Chef::Resource::Script derived resources when no guard params are specified" do
node = Chef::Node.new
run_context = Chef::RunContext.new(node, nil, nil)
- file_resource = Chef::Resource::File.new('idontexist', run_context)
+ file_resource = Chef::Resource::File.new("idontexist", run_context)
file_resource.guard_interpreter :powershell_script
allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
- {:convert_boolean_return => true, :code => "$true"}).and_return(Proc.new {})
+ { :convert_boolean_return => true, :code => "$true" }).and_return(Proc.new {})
resource.only_if("$true")
end
it "enables convert_boolean_return by default for guards in the context of powershell_script when guard params are specified" do
- guard_parameters = {:cwd => '/etc/chef', :architecture => :x86_64}
+ guard_parameters = { :cwd => "/etc/chef", :architecture => :x86_64 }
allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
- {:convert_boolean_return => true, :code => "$true"}.merge(guard_parameters)).and_return(Proc.new {})
+ { :convert_boolean_return => true, :code => "$true" }.merge(guard_parameters)).and_return(Proc.new {})
resource.only_if("$true", guard_parameters)
end
it "passes convert_boolean_return as true if it was specified as true in a guard parameter" do
- guard_parameters = {:cwd => '/etc/chef', :convert_boolean_return => true, :architecture => :x86_64}
+ guard_parameters = { :cwd => "/etc/chef", :convert_boolean_return => true, :architecture => :x86_64 }
allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
- {:convert_boolean_return => true, :code => "$true"}.merge(guard_parameters)).and_return(Proc.new {})
+ { :convert_boolean_return => true, :code => "$true" }.merge(guard_parameters)).and_return(Proc.new {})
resource.only_if("$true", guard_parameters)
end
it "passes convert_boolean_return as false if it was specified as true in a guard parameter" do
- other_guard_parameters = {:cwd => '/etc/chef', :architecture => :x86_64}
- parameters_with_boolean_disabled = other_guard_parameters.merge({:convert_boolean_return => false, :code => "$true"})
+ other_guard_parameters = { :cwd => "/etc/chef", :architecture => :x86_64 }
+ parameters_with_boolean_disabled = other_guard_parameters.merge({ :convert_boolean_return => false, :code => "$true" })
allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
parameters_with_boolean_disabled).and_return(Proc.new {})
resource.only_if("$true", parameters_with_boolean_disabled)
@@ -129,7 +129,7 @@ describe Chef::Resource::PowershellScript do
let(:resource_instance) { @resource }
let(:resource_instance_name ) { @resource.command }
let(:resource_name) { :powershell_script }
- let(:interpreter_file_name) { 'powershell.exe' }
+ let(:interpreter_file_name) { "powershell.exe" }
it_behaves_like "a Windows script resource"
end
diff --git a/spec/unit/resource/python_spec.rb b/spec/unit/resource/python_spec.rb
index 8a3f7e48ca..aba84c4000 100644
--- a/spec/unit/resource/python_spec.rb
+++ b/spec/unit/resource/python_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Python do
diff --git a/spec/unit/resource/registry_key_spec.rb b/spec/unit/resource/registry_key_spec.rb
index 2d82f1a51c..d378da3ed0 100644
--- a/spec/unit/resource/registry_key_spec.rb
+++ b/spec/unit/resource/registry_key_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2012 OpsCode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::RegistryKey, "initialize" do
before(:each) do
@@ -80,42 +80,58 @@ describe Chef::Resource::RegistryKey, "values" do
end
it "should allow a single proper hash of registry values" do
- @resource.values( { :name => 'poosh', :type => :string, :data => 'carmen' } )
- expect(@resource.values).to eql([ { :name => 'poosh', :type => :string, :data => 'carmen' } ])
+ @resource.values( { :name => "poosh", :type => :string, :data => "carmen" } )
+ expect(@resource.values).to eql([ { :name => "poosh", :type => :string, :data => "carmen" } ])
end
it "should allow an array of proper hashes of registry values" do
- @resource.values [ { :name => 'poosh', :type => :string, :data => 'carmen' } ]
- expect(@resource.values).to eql([ { :name => 'poosh', :type => :string, :data => 'carmen' } ])
+ @resource.values [ { :name => "poosh", :type => :string, :data => "carmen" } ]
+ expect(@resource.values).to eql([ { :name => "poosh", :type => :string, :data => "carmen" } ])
end
it "should return checksummed data if the type is unsafe" do
- @resource.values( { :name => 'poosh', :type => :binary, :data => 255.chr * 1 })
- expect(@resource.values).to eql([ { :name => 'poosh', :type => :binary, :data => 'a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89' } ])
+ @resource.values( { :name => "poosh", :type => :binary, :data => 255.chr * 1 })
+ expect(@resource.values).to eql([ { :name => "poosh", :type => :binary, :data => "a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89" } ])
end
- it "should throw an exception if the name field is missing" do
- expect { @resource.values [ { :type => :string, :data => 'carmen' } ] }.to raise_error(ArgumentError)
+ it "should raise an exception if the name field is missing" do
+ expect { @resource.values [ { :type => :string, :data => "carmen" } ] }.to raise_error(ArgumentError)
end
- it "should throw an exception if the type field is missing" do
- expect { @resource.values [ { :name => 'poosh', :data => 'carmen' } ] }.to raise_error(ArgumentError)
+ it "should raise an exception if extra fields are present" do
+ expect { @resource.values [ { :name => "poosh", :type => :string, :data => "carmen", :screwdriver => "sonic" } ] }.to raise_error(ArgumentError)
end
- it "should throw an exception if the data field is missing" do
- expect { @resource.values [ { :name => 'poosh', :type => :string } ] }.to raise_error(ArgumentError)
+ it "should not allow a string" do
+ expect { @resource.send(:values, "souffle") }.to raise_error(ArgumentError)
end
- it "should throw an exception if extra fields are present" do
- expect { @resource.values [ { :name => 'poosh', :type => :string, :data => 'carmen', :screwdriver => 'sonic' } ] }.to raise_error(ArgumentError)
+ it "should not allow an integer" do
+ expect { @resource.send(:values, 100) }.to raise_error(ArgumentError)
end
- it "should not allow a string" do
- expect { @resource.send(:values, 'souffle') }.to raise_error(ArgumentError)
+ it "should raise an exception if type of name is not string" do
+ expect { @resource.values([ { :name => 123, :type => :string, :data => "carmen" } ]) }.to raise_error(ArgumentError)
end
- it "should not allow an integer" do
- expect { @resource.send(:values, 100) }.to raise_error(ArgumentError)
+ it "should not raise an exception if type of name is string" do
+ expect { @resource.values([ { :name => "123", :type => :string, :data => "carmen" } ]) }.to_not raise_error
+ end
+
+ context "type key not given" do
+ it "should not raise an exception" do
+ expect { @resource.values([ { :name => "123", :data => "carmen" } ]) }.to_not raise_error
+ end
+ end
+
+ context "type key given" do
+ it "should raise an exception if type of type is not symbol" do
+ expect { @resource.values([ { :name => "123", :type => "string", :data => "carmen" } ]) }.to raise_error(ArgumentError)
+ end
+
+ it "should not raise an exception if type of type is symbol" do
+ expect { @resource.values([ { :name => "123", :type => :string, :data => "carmen" } ]) }.to_not raise_error
+ end
end
end
@@ -130,7 +146,7 @@ describe Chef::Resource::RegistryKey, "recursive" do
end
it "should not allow a hash" do
- expect { @resource.recursive({:sonic => :screwdriver}) }.to raise_error(ArgumentError)
+ expect { @resource.recursive({ :sonic => :screwdriver }) }.to raise_error(ArgumentError)
end
it "should not allow an array" do
@@ -138,7 +154,7 @@ describe Chef::Resource::RegistryKey, "recursive" do
end
it "should not allow a string" do
- expect { @resource.recursive('souffle') }.to raise_error(ArgumentError)
+ expect { @resource.recursive("souffle") }.to raise_error(ArgumentError)
end
it "should not allow an integer" do
@@ -159,7 +175,7 @@ describe Chef::Resource::RegistryKey, "architecture" do
end
it "should not allow a hash" do
- expect { @resource.architecture({:sonic => :screwdriver}) }.to raise_error(ArgumentError)
+ expect { @resource.architecture({ :sonic => :screwdriver }) }.to raise_error(ArgumentError)
end
it "should not allow an array" do
@@ -167,7 +183,7 @@ describe Chef::Resource::RegistryKey, "architecture" do
end
it "should not allow a string" do
- expect { @resource.architecture('souffle') }.to raise_error(ArgumentError)
+ expect { @resource.architecture("souffle") }.to raise_error(ArgumentError)
end
it "should not allow an integer" do
@@ -181,7 +197,7 @@ describe Chef::Resource::RegistryKey, ":unscrubbed_values" do
end
it "should return unsafe data as-is" do
- key_values = [ { :name => 'poosh', :type => :binary, :data => 255.chr * 1 } ]
+ key_values = [ { :name => "poosh", :type => :binary, :data => 255.chr * 1 } ]
@resource.values(key_values)
expect(@resource.unscrubbed_values).to eql(key_values)
end
@@ -193,7 +209,7 @@ describe Chef::Resource::RegistryKey, "state" do
end
it "should return scrubbed values" do
- @resource.values([ { :name => 'poosh', :type => :binary, :data => 255.chr * 1 } ])
- expect(@resource.state).to eql( { :values => [{ :name => 'poosh', :type => :binary, :data => 'a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89'}] } )
+ @resource.values([ { :name => "poosh", :type => :binary, :data => 255.chr * 1 } ])
+ expect(@resource.state).to eql( { :values => [{ :name => "poosh", :type => :binary, :data => "a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89" }] } )
end
end
diff --git a/spec/unit/resource/remote_directory_spec.rb b/spec/unit/resource/remote_directory_spec.rb
index 1ab75586b6..cdca214db6 100644
--- a/spec/unit/resource/remote_directory_spec.rb
+++ b/spec/unit/resource/remote_directory_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::RemoteDirectory do
diff --git a/spec/unit/resource/remote_file_spec.rb b/spec/unit/resource/remote_file_spec.rb
index 0a379ff574..274f98e7f4 100644
--- a/spec/unit/resource/remote_file_spec.rb
+++ b/spec/unit/resource/remote_file_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::RemoteFile do
@@ -36,13 +36,13 @@ describe Chef::Resource::RemoteFile do
it "says its provider is RemoteFile when the source is an absolute URI" do
@resource.source("http://www.google.com/robots.txt")
expect(@resource.provider).to eq(Chef::Provider::RemoteFile)
- expect(Chef::Platform.find_provider(:noplatform, 'noversion', @resource)).to eq(Chef::Provider::RemoteFile)
+ expect(@resource.provider_for_action(:create)).to be_kind_of(Chef::Provider::RemoteFile)
end
it "says its provider is RemoteFile when the source is a network share" do
@resource.source("\\\\fakey\\fakerton\\fake.txt")
expect(@resource.provider).to eq(Chef::Provider::RemoteFile)
- expect(Chef::Platform.find_provider(:noplatform, 'noversion', @resource)).to eq(Chef::Provider::RemoteFile)
+ expect(@resource.provider_for_action(:create)).to be_kind_of(Chef::Provider::RemoteFile)
end
describe "source" do
@@ -60,13 +60,13 @@ describe Chef::Resource::RemoteFile do
expect(@resource.source).to eql([ "\\\\fakey\\fakerton\\fake.txt" ])
end
- it 'should accept file URIs with spaces' do
+ it "should accept file URIs with spaces" do
@resource.source("file:///C:/foo bar")
expect(@resource.source).to eql(["file:///C:/foo bar"])
end
it "should accept a delayed evalutator (string) for the remote file source" do
- @resource.source Chef::DelayedEvaluator.new {"http://opscode.com/"}
+ @resource.source Chef::DelayedEvaluator.new { "http://opscode.com/" }
expect(@resource.source).to eql([ "http://opscode.com/" ])
end
@@ -86,15 +86,15 @@ describe Chef::Resource::RemoteFile do
end
it "should only accept a single argument if a delayed evalutor is used" do
- expect {
- @resource.source("http://opscode.com/", Chef::DelayedEvaluator.new {"http://opscode.com/"})
- }.to raise_error(Chef::Exceptions::InvalidRemoteFileURI)
+ expect do
+ @resource.source("http://opscode.com/", Chef::DelayedEvaluator.new { "http://opscode.com/" })
+ end.to raise_error(Chef::Exceptions::InvalidRemoteFileURI)
end
it "should only accept a single array item if a delayed evalutor is used" do
- expect {
- @resource.source(["http://opscode.com/", Chef::DelayedEvaluator.new {"http://opscode.com/"}])
- }.to raise_error(Chef::Exceptions::InvalidRemoteFileURI)
+ expect do
+ @resource.source(["http://opscode.com/", Chef::DelayedEvaluator.new { "http://opscode.com/" }])
+ end.to raise_error(Chef::Exceptions::InvalidRemoteFileURI)
end
it "does not accept a non-URI as the source" do
@@ -102,10 +102,10 @@ describe Chef::Resource::RemoteFile do
end
it "does not accept a non-URI as the source when read from a delayed evaluator" do
- expect {
- @resource.source(Chef::DelayedEvaluator.new {"not-a-uri"})
+ expect do
+ @resource.source(Chef::DelayedEvaluator.new { "not-a-uri" })
@resource.source
- }.to raise_error(Chef::Exceptions::InvalidRemoteFileURI)
+ end.to raise_error(Chef::Exceptions::InvalidRemoteFileURI)
end
it "should raise an exception when source is an empty array" do
@@ -179,20 +179,20 @@ describe Chef::Resource::RemoteFile do
@resource.owner("root")
end
@resource.source("https://www.google.com/images/srpr/logo3w.png")
- @resource.checksum("1"*26)
+ @resource.checksum("1" * 26)
end
it "describes its state" do
state = @resource.state
if Chef::Platform.windows?
puts state
- expect(state[:rights]).to eq([{:permissions => :read, :principals => "Everyone"}])
- expect(state[:deny_rights]).to eq([{:permissions => :full_control, :principals => "Clumsy_Sam"}])
+ expect(state[:rights]).to eq([{ :permissions => :read, :principals => "Everyone" }])
+ expect(state[:deny_rights]).to eq([{ :permissions => :full_control, :principals => "Clumsy_Sam" }])
else
expect(state[:group]).to eq("pokemon")
expect(state[:mode]).to eq("0664")
expect(state[:owner]).to eq("root")
- expect(state[:checksum]).to eq("1"*26)
+ expect(state[:checksum]).to eq("1" * 26)
end
end
diff --git a/spec/unit/resource/resource_notification_spec.rb b/spec/unit/resource/resource_notification_spec.rb
index 024b6f93f7..e141e01fcf 100644
--- a/spec/unit/resource/resource_notification_spec.rb
+++ b/spec/unit/resource/resource_notification_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/resource/resource_notification'
+require "spec_helper"
+require "chef/resource/resource_notification"
describe Chef::Resource::Notification do
@@ -50,7 +50,7 @@ describe Chef::Resource::Notification do
end
it "raises an ArgumentError if you try to check a non-ducktype object for duplication" do
- expect {notification.duplicates?(:not_a_notification)}.to raise_error(ArgumentError)
+ expect { notification.duplicates?(:not_a_notification) }.to raise_error(ArgumentError)
end
it "takes no action to resolve a resource reference that doesn't need to be resolved" do
@@ -65,7 +65,7 @@ describe Chef::Resource::Notification do
end
it "resolves a lazy reference to a resource" do
- notification.resource = {:cat => "keyboard_cat"}
+ notification.resource = { :cat => "keyboard_cat" }
@keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
@resource_collection = Chef::ResourceCollection.new
@resource_collection << @keyboard_cat
@@ -78,7 +78,7 @@ describe Chef::Resource::Notification do
it "resolves a lazy reference to its notifying resource" do
@keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
notification.resource = @keyboard_cat
- notification.notifying_resource = {:cat => "long_cat"}
+ notification.notifying_resource = { :cat => "long_cat" }
@long_cat = Chef::Resource::Cat.new("long_cat")
@resource_collection = Chef::ResourceCollection.new
@resource_collection << @long_cat
@@ -87,11 +87,11 @@ describe Chef::Resource::Notification do
end
it "resolves lazy references to both its resource and its notifying resource" do
- notification.resource = {:cat => "keyboard_cat"}
+ notification.resource = { :cat => "keyboard_cat" }
@keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
@resource_collection = Chef::ResourceCollection.new
@resource_collection << @keyboard_cat
- notification.notifying_resource = {:cat => "long_cat"}
+ notification.notifying_resource = { :cat => "long_cat" }
@long_cat = Chef::Resource::Cat.new("long_cat")
@resource_collection << @long_cat
notification.resolve_resource_reference(@resource_collection)
@@ -100,7 +100,7 @@ describe Chef::Resource::Notification do
end
it "raises a RuntimeError if you try to reference multiple resources" do
- notification.resource = {:cat => ["keyboard_cat", "cheez_cat"]}
+ notification.resource = { :cat => %w{keyboard_cat cheez_cat} }
@keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
@cheez_cat = Chef::Resource::Cat.new("cheez_cat")
@resource_collection = Chef::ResourceCollection.new
@@ -108,11 +108,11 @@ describe Chef::Resource::Notification do
@resource_collection << @cheez_cat
@long_cat = Chef::Resource::Cat.new("long_cat")
notification.notifying_resource = @long_cat
- expect {notification.resolve_resource_reference(@resource_collection)}.to raise_error(RuntimeError)
+ expect { notification.resolve_resource_reference(@resource_collection) }.to raise_error(RuntimeError)
end
it "raises a RuntimeError if you try to reference multiple notifying resources" do
- notification.notifying_resource = {:cat => ["long_cat", "cheez_cat"]}
+ notification.notifying_resource = { :cat => %w{long_cat cheez_cat} }
@long_cat = Chef::Resource::Cat.new("long_cat")
@cheez_cat = Chef::Resource::Cat.new("cheez_cat")
@resource_collection = Chef::ResourceCollection.new
@@ -120,27 +120,27 @@ describe Chef::Resource::Notification do
@resource_collection << @cheez_cat
@keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
notification.resource = @keyboard_cat
- expect {notification.resolve_resource_reference(@resource_collection)}.to raise_error(RuntimeError)
+ expect { notification.resolve_resource_reference(@resource_collection) }.to raise_error(RuntimeError)
end
it "raises a RuntimeError if it can't find a resource in the resource collection when resolving a lazy reference" do
- notification.resource = {:cat => "keyboard_cat"}
+ notification.resource = { :cat => "keyboard_cat" }
@cheez_cat = Chef::Resource::Cat.new("cheez_cat")
@resource_collection = Chef::ResourceCollection.new
@resource_collection << @cheez_cat
@long_cat = Chef::Resource::Cat.new("long_cat")
notification.notifying_resource = @long_cat
- expect {notification.resolve_resource_reference(@resource_collection)}.to raise_error(RuntimeError)
+ expect { notification.resolve_resource_reference(@resource_collection) }.to raise_error(RuntimeError)
end
it "raises a RuntimeError if it can't find a notifying resource in the resource collection when resolving a lazy reference" do
- notification.notifying_resource = {:cat => "long_cat"}
+ notification.notifying_resource = { :cat => "long_cat" }
@cheez_cat = Chef::Resource::Cat.new("cheez_cat")
@resource_collection = Chef::ResourceCollection.new
@resource_collection << @cheez_cat
@keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
notification.resource = @keyboard_cat
- expect {notification.resolve_resource_reference(@resource_collection)}.to raise_error(RuntimeError)
+ expect { notification.resolve_resource_reference(@resource_collection) }.to raise_error(RuntimeError)
end
it "raises an ArgumentError if improper syntax is used in the lazy reference to its resource" do
@@ -150,7 +150,7 @@ describe Chef::Resource::Notification do
@resource_collection << @keyboard_cat
@long_cat = Chef::Resource::Cat.new("long_cat")
notification.notifying_resource = @long_cat
- expect {notification.resolve_resource_reference(@resource_collection)}.to raise_error(ArgumentError)
+ expect { notification.resolve_resource_reference(@resource_collection) }.to raise_error(ArgumentError)
end
it "raises an ArgumentError if improper syntax is used in the lazy reference to its notifying resource" do
@@ -160,7 +160,7 @@ describe Chef::Resource::Notification do
@resource_collection << @long_cat
@keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
notification.resource = @keyboard_cat
- expect {notification.resolve_resource_reference(@resource_collection)}.to raise_error(ArgumentError)
+ expect { notification.resolve_resource_reference(@resource_collection) }.to raise_error(ArgumentError)
end
# Create test to resolve lazy references to both notifying resource and dest. resource
diff --git a/spec/unit/resource/route_spec.rb b/spec/unit/resource/route_spec.rb
index ec1d369932..259ccf7eab 100644
--- a/spec/unit/resource/route_spec.rb
+++ b/spec/unit/resource/route_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Bryan McLellan (btm@loftninjas.org)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Bryan McLellan
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Bryan McLellan
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Route do
diff --git a/spec/unit/resource/rpm_package_spec.rb b/spec/unit/resource/rpm_package_spec.rb
index d3b505fff5..e1488f1dd1 100644
--- a/spec/unit/resource/rpm_package_spec.rb
+++ b/spec/unit/resource/rpm_package_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2010 Thomas Bishop
+# Copyright:: Copyright 2010-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::RpmPackage, "initialize" do
diff --git a/spec/unit/resource/ruby_block_spec.rb b/spec/unit/resource/ruby_block_spec.rb
index 8664564ac5..f393fbea46 100644
--- a/spec/unit/resource/ruby_block_spec.rb
+++ b/spec/unit/resource/ruby_block_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::RubyBlock do
diff --git a/spec/unit/resource/ruby_spec.rb b/spec/unit/resource/ruby_spec.rb
index e899810ab9..d7b6759462 100644
--- a/spec/unit/resource/ruby_spec.rb
+++ b/spec/unit/resource/ruby_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Ruby do
diff --git a/spec/unit/resource/scm_spec.rb b/spec/unit/resource/scm_spec.rb
index 72319277ab..f39334348e 100644
--- a/spec/unit/resource/scm_spec.rb
+++ b/spec/unit/resource/scm_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Scm do
@@ -101,7 +101,7 @@ describe Chef::Resource::Scm do
it "takes the depth as an integer for shallow clones" do
@resource.depth 5
expect(@resource.depth).to eq(5)
- expect {@resource.depth "five"}.to raise_error(ArgumentError)
+ expect { @resource.depth "five" }.to raise_error(ArgumentError)
end
it "defaults to nil depth for a full clone" do
@@ -111,7 +111,7 @@ describe Chef::Resource::Scm do
it "takes a boolean for #enable_submodules" do
@resource.enable_submodules true
expect(@resource.enable_submodules).to be_truthy
- expect {@resource.enable_submodules "lolz"}.to raise_error(ArgumentError)
+ expect { @resource.enable_submodules "lolz" }.to raise_error(ArgumentError)
end
it "defaults to not enabling submodules" do
@@ -121,7 +121,7 @@ describe Chef::Resource::Scm do
it "takes a boolean for #enable_checkout" do
@resource.enable_checkout true
expect(@resource.enable_checkout).to be_truthy
- expect {@resource.enable_checkout "lolz"}.to raise_error(ArgumentError)
+ expect { @resource.enable_checkout "lolz" }.to raise_error(ArgumentError)
end
it "defaults to enabling checkout" do
@@ -131,7 +131,7 @@ describe Chef::Resource::Scm do
it "takes a string for the remote" do
@resource.remote "opscode"
expect(@resource.remote).to eql("opscode")
- expect {@resource.remote 1337}.to raise_error(ArgumentError)
+ expect { @resource.remote 1337 }.to raise_error(ArgumentError)
end
it "defaults to ``origin'' for the remote" do
@@ -184,7 +184,7 @@ describe Chef::Resource::Scm do
end
describe "when it has a environment attribute" do
- let(:test_environment) { {'CHEF_ENV' => '/tmp' } }
+ let(:test_environment) { { "CHEF_ENV" => "/tmp" } }
before { @resource.environment(test_environment) }
it "stores this environment" do
expect(@resource.environment).to eq(test_environment)
diff --git a/spec/unit/resource/script_spec.rb b/spec/unit/resource/script_spec.rb
index 4affee8e8c..fca9fb0d7b 100644
--- a/spec/unit/resource/script_spec.rb
+++ b/spec/unit/resource/script_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Script do
let(:resource_instance_name) { "fakey_fakerton" }
diff --git a/spec/unit/resource/service_spec.rb b/spec/unit/resource/service_spec.rb
index b9e3757255..7aadc55532 100644
--- a/spec/unit/resource/service_spec.rb
+++ b/spec/unit/resource/service_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: AJ Christensen (<aj@hjksolutions.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Service do
@@ -53,9 +53,9 @@ describe Chef::Resource::Service do
end
it "should not accept a regexp for the service pattern" do
- expect {
+ expect do
@resource.pattern /.*/
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should accept a string for the service start command" do
@@ -64,9 +64,9 @@ describe Chef::Resource::Service do
end
it "should not accept a regexp for the service start command" do
- expect {
+ expect do
@resource.start_command /.*/
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should accept a string for the service stop command" do
@@ -75,9 +75,9 @@ describe Chef::Resource::Service do
end
it "should not accept a regexp for the service stop command" do
- expect {
+ expect do
@resource.stop_command /.*/
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should accept a string for the service status command" do
@@ -86,9 +86,9 @@ describe Chef::Resource::Service do
end
it "should not accept a regexp for the service status command" do
- expect {
+ expect do
@resource.status_command /.*/
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should accept a string for the service restart command" do
@@ -97,9 +97,9 @@ describe Chef::Resource::Service do
end
it "should not accept a regexp for the service restart command" do
- expect {
+ expect do
@resource.restart_command /.*/
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should accept a string for the service reload command" do
@@ -108,9 +108,9 @@ describe Chef::Resource::Service do
end
it "should not accept a regexp for the service reload command" do
- expect {
+ expect do
@resource.reload_command /.*/
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should accept a string for the service init command" do
@@ -119,9 +119,9 @@ describe Chef::Resource::Service do
end
it "should not accept a regexp for the service init command" do
- expect {
+ expect do
@resource.init_command /.*/
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
%w{enabled running}.each do |attrib|
@@ -140,7 +140,7 @@ describe Chef::Resource::Service do
end
it "should default all the feature support to nil" do
- support_hash = { :status => nil, :restart => nil, :reload=> nil }
+ support_hash = { :status => nil, :restart => nil, :reload => nil }
expect(@resource.supports).to eq(support_hash)
end
@@ -176,5 +176,4 @@ describe Chef::Resource::Service do
end
end
-
end
diff --git a/spec/unit/resource/smartos_package_spec.rb b/spec/unit/resource/smartos_package_spec.rb
index c2cf546dd5..56c0fbdb8b 100644
--- a/spec/unit/resource/smartos_package_spec.rb
+++ b/spec/unit/resource/smartos_package_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
-# Copyright:: Copyright (c) 2010 Thomas Bishop
+# Copyright:: Copyright 2010-2016, Thomas Bishop
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::SmartosPackage, "initialize" do
@@ -27,7 +27,7 @@ describe Chef::Resource::SmartosPackage, "initialize" do
name: :smartos_package,
action: :install,
os: "solaris2",
- platform_family: "smartos",
+ platform_family: "smartos"
)
end
diff --git a/spec/unit/resource/solaris_package_spec.rb b/spec/unit/resource/solaris_package_spec.rb
index f5d3e669a1..1f1ef4da30 100644
--- a/spec/unit/resource/solaris_package_spec.rb
+++ b/spec/unit/resource/solaris_package_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Prabhu Das (<prabhu.das@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::SolarisPackage, "initialize" do
@@ -28,7 +28,7 @@ describe Chef::Resource::SolarisPackage, "initialize" do
name: :solaris_package,
action: :install,
os: "solaris2",
- platform_family: platform_family,
+ platform_family: platform_family
)
end
diff --git a/spec/unit/resource/subversion_spec.rb b/spec/unit/resource/subversion_spec.rb
index aa4d1ed708..a2901bf53b 100644
--- a/spec/unit/resource/subversion_spec.rb
+++ b/spec/unit/resource/subversion_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::Subversion do
@@ -25,7 +25,7 @@ describe Chef::Resource::Subversion do
resource: Chef::Resource::Subversion,
provider: Chef::Provider::Subversion,
name: :subversion,
- action: :install,
+ action: :install
)
before do
@@ -42,7 +42,7 @@ describe Chef::Resource::Subversion do
end
it "sets svn info arguments to --no-auth-cache by default" do
- expect(@svn.svn_info_args).to eq('--no-auth-cache')
+ expect(@svn.svn_info_args).to eq("--no-auth-cache")
end
it "resets svn info arguments to nil when given false in the setter" do
@@ -51,7 +51,7 @@ describe Chef::Resource::Subversion do
end
it "sets svn arguments to --no-auth-cache by default" do
- expect(@svn.svn_arguments).to eq('--no-auth-cache')
+ expect(@svn.svn_arguments).to eq("--no-auth-cache")
end
it "sets svn binary to nil by default" do
diff --git a/spec/unit/resource/systemd_unit_spec.rb b/spec/unit/resource/systemd_unit_spec.rb
new file mode 100644
index 0000000000..7e46872525
--- /dev/null
+++ b/spec/unit/resource/systemd_unit_spec.rb
@@ -0,0 +1,133 @@
+#
+# Author:: Nathan Williams (<nath.e.will@gmail.com>)
+# Copyright:: Copyright 2016, Nathan Williams
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::SystemdUnit do
+ before(:each) do
+ @resource = Chef::Resource::SystemdUnit.new("sysstat-collect.timer")
+ end
+
+ let(:unit_content_string) { "[Unit]\nDescription = Run system activity accounting tool every 10 minutes\n\n[Timer]\nOnCalendar = *:00/10\n\n[Install]\nWantedBy = sysstat.service\n" }
+
+ let(:unit_content_hash) do
+ {
+ "Unit" => {
+ "Description" => "Run system activity accounting tool every 10 minutes",
+ },
+ "Timer" => {
+ "OnCalendar" => "*:00/10",
+ },
+ "Install" => {
+ "WantedBy" => "sysstat.service",
+ },
+ }
+ end
+
+ it "creates a new Chef::Resource::SystemdUnit" do
+ expect(@resource).to be_a_kind_of(Chef::Resource)
+ expect(@resource).to be_a_kind_of(Chef::Resource::SystemdUnit)
+ end
+
+ it "should have a name" do
+ expect(@resource.name).to eql("sysstat-collect.timer")
+ end
+
+ it "has a default action of nothing" do
+ expect(@resource.action).to eql([:nothing])
+ end
+
+ it "supports appropriate unit actions" do
+ expect { @resource.action :create }.not_to raise_error
+ expect { @resource.action :delete }.not_to raise_error
+ expect { @resource.action :enable }.not_to raise_error
+ expect { @resource.action :disable }.not_to raise_error
+ expect { @resource.action :mask }.not_to raise_error
+ expect { @resource.action :unmask }.not_to raise_error
+ expect { @resource.action :start }.not_to raise_error
+ expect { @resource.action :stop }.not_to raise_error
+ expect { @resource.action :restart }.not_to raise_error
+ expect { @resource.action :reload }.not_to raise_error
+ expect { @resource.action :wrong }.to raise_error(ArgumentError)
+ end
+
+ it "accepts boolean state properties" do
+ expect { @resource.active false }.not_to raise_error
+ expect { @resource.active true }.not_to raise_error
+ expect { @resource.active "yes" }.to raise_error(ArgumentError)
+
+ expect { @resource.enabled true }.not_to raise_error
+ expect { @resource.enabled false }.not_to raise_error
+ expect { @resource.enabled "no" }.to raise_error(ArgumentError)
+
+ expect { @resource.masked true }.not_to raise_error
+ expect { @resource.masked false }.not_to raise_error
+ expect { @resource.masked :nope }.to raise_error(ArgumentError)
+
+ expect { @resource.static true }.not_to raise_error
+ expect { @resource.static false }.not_to raise_error
+ expect { @resource.static "yep" }.to raise_error(ArgumentError)
+ end
+
+ it "accepts the content property" do
+ expect { @resource.content nil }.not_to raise_error
+ expect { @resource.content "test" }.not_to raise_error
+ expect { @resource.content({}) }.not_to raise_error
+ expect { @resource.content 5 }.to raise_error(ArgumentError)
+ end
+
+ it "accepts the user property" do
+ expect { @resource.user nil }.not_to raise_error
+ expect { @resource.user "deploy" }.not_to raise_error
+ expect { @resource.user 5 }.to raise_error(ArgumentError)
+ end
+
+ it "accepts the triggers_reload property" do
+ expect { @resource.triggers_reload true }.not_to raise_error
+ expect { @resource.triggers_reload false }.not_to raise_error
+ expect { @resource.triggers_reload "no" }.to raise_error(ArgumentError)
+ end
+
+ it "reports its state" do
+ @resource.active true
+ @resource.enabled true
+ @resource.masked false
+ @resource.static false
+ @resource.content "test"
+ state = @resource.state
+ expect(state[:active]).to eq(true)
+ expect(state[:enabled]).to eq(true)
+ expect(state[:masked]).to eq(false)
+ expect(state[:static]).to eq(false)
+ expect(state[:content]).to eq("test")
+ end
+
+ it "returns the unit name as its identity" do
+ expect(@resource.identity).to eq("sysstat-collect.timer")
+ end
+
+ it "serializes to ini with a string-formatted content property" do
+ @resource.content(unit_content_string)
+ expect(@resource.to_ini).to eq unit_content_string
+ end
+
+ it "serializes to ini with a hash-formatted content property" do
+ @resource.content(unit_content_hash)
+ expect(@resource.to_ini).to eq unit_content_string
+ end
+end
diff --git a/spec/unit/resource/template_spec.rb b/spec/unit/resource/template_spec.rb
index 2fd951b72d..9060f02d29 100644
--- a/spec/unit/resource/template_spec.rb
+++ b/spec/unit/resource/template_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::Template do
@@ -127,7 +127,7 @@ describe Chef::Resource::Template do
modules = @resource.helper_modules
expect(modules.size).to eq(1)
o = Object.new
- modules.each {|m| o.extend(m)}
+ modules.each { |m| o.extend(m) }
expect(o.example_1).to eq("example_1")
expect(o.example_2).to eq("example_2")
end
@@ -136,7 +136,7 @@ describe Chef::Resource::Template do
@resource.helper(:shout) { |quiet| quiet.upcase }
modules = @resource.helper_modules
o = Object.new
- modules.each {|m| o.extend(m)}
+ modules.each { |m| o.extend(m) }
expect(o.shout("shout")).to eq("SHOUT")
end
@@ -167,7 +167,7 @@ describe Chef::Resource::Template do
modules = @resource.helper_modules
expect(modules.size).to eq(1)
o = Object.new
- modules.each {|m| o.extend(m)}
+ modules.each { |m| o.extend(m) }
expect(o.example_1).to eq("example_1")
end
@@ -199,13 +199,12 @@ describe Chef::Resource::Template do
expect(@resource.helper_modules.size).to eq(3)
o = Object.new
- @resource.helper_modules.each {|m| o.extend(m)}
+ @resource.helper_modules.each { |m| o.extend(m) }
expect(o.static_example).to eq("static_example")
expect(o.inline_module).to eq("inline_module")
expect(o.inline_method).to eq("inline_method")
end
-
end
end
diff --git a/spec/unit/resource/timestamped_deploy_spec.rb b/spec/unit/resource/timestamped_deploy_spec.rb
index 4ebfdaf059..5a2dc8ae02 100644
--- a/spec/unit/resource/timestamped_deploy_spec.rb
+++ b/spec/unit/resource/timestamped_deploy_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::TimestampedDeploy, "initialize" do
@@ -25,8 +25,8 @@ describe Chef::Resource::TimestampedDeploy, "initialize" do
provider: Chef::Provider::Deploy::Timestamped,
name: :timestamped_deploy,
action: :deploy,
- os: 'linux',
- platform_family: 'rhel',
+ os: "linux",
+ platform_family: "rhel"
)
end
diff --git a/spec/unit/resource/user_spec.rb b/spec/unit/resource/user_spec.rb
index 3bf7e6187b..138ffb1bfe 100644
--- a/spec/unit/resource/user_spec.rb
+++ b/spec/unit/resource/user_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::User, "initialize" do
before(:each) do
@@ -29,7 +29,7 @@ describe Chef::Resource::User, "initialize" do
end
it "should set the resource_name to :user" do
- expect(@resource.resource_name).to eql(:user)
+ expect(@resource.resource_name).to eql(:user_resource_abstract_base_class)
end
it "should set the username equal to the argument to initialize" do
@@ -68,7 +68,7 @@ describe Chef::Resource::User, "initialize" do
expect { @resource.username "domain\@user" }.not_to raise_error
expect(@resource.username).to eq("domain\@user")
expect { @resource.username "domain\\user" }.not_to raise_error
- expect(@resource.username).to eq("domain\\user")
+ expect(@resource.username).to eq("domain\\user")
end
end
diff --git a/spec/unit/resource/windows_package_spec.rb b/spec/unit/resource/windows_package_spec.rb
index 6aa5d357ea..5aa3707199 100644
--- a/spec/unit/resource/windows_package_spec.rb
+++ b/spec/unit/resource/windows_package_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::WindowsPackage, "initialize" do
before(:each) do
@@ -80,12 +80,12 @@ describe Chef::Resource::WindowsPackage, "initialize" do
end
it "supports the checksum attribute" do
- resource.checksum('somechecksum')
- expect(resource.checksum).to eq('somechecksum')
+ resource.checksum("somechecksum")
+ expect(resource.checksum).to eq("somechecksum")
end
- context 'when a URL is used' do
- let(:resource_source) { 'https://foo.bar/solitare.msi' }
+ context "when a URL is used" do
+ let(:resource_source) { "https://foo.bar/solitare.msi" }
let(:resource) { Chef::Resource::WindowsPackage.new(resource_source) }
it "should return the source unmodified" do
diff --git a/spec/unit/resource/windows_service_spec.rb b/spec/unit/resource/windows_service_spec.rb
index 45a295c24e..2455a70f02 100644
--- a/spec/unit/resource/windows_service_spec.rb
+++ b/spec/unit/resource/windows_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource::WindowsService, "initialize" do
static_provider_resolution(
diff --git a/spec/unit/resource/yum_package_spec.rb b/spec/unit/resource/yum_package_spec.rb
index f24f1e3405..a1e8417e0e 100644
--- a/spec/unit/resource/yum_package_spec.rb
+++ b/spec/unit/resource/yum_package_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: AJ Christensen (<aj@opscode.com>)
-# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc.
+# Author:: AJ Christensen (<aj@chef.io>)
+# Copyright:: Copyright 2008-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
describe Chef::Resource::YumPackage, "initialize" do
@@ -26,12 +26,53 @@ describe Chef::Resource::YumPackage, "initialize" do
provider: Chef::Provider::Package::Yum,
name: :yum_package,
action: :install,
- os: 'linux',
- platform_family: 'rhel',
+ os: "linux",
+ platform_family: "rhel"
)
end
+describe Chef::Resource::YumPackage do
+ before(:each) do
+ @resource = Chef::Resource::YumPackage.new("foo")
+ end
+
+ # this set of tests is somewhat terrible. the yum provider promiscuously writes over
+ # the new_resource.package_named/version/arch properties. until that is fixed properly
+ # we need to coerce and dup those properties into normal arrays. this does not affect
+ # strings because those are not mutated in place and they are not (currently) frozen
+ # in immutable attributes (even though they really, really should be).
+ context "when passed immutable node attribute arrays" do
+ let(:node) { Chef::Node.new }
+
+ before do
+ node.default["foo"] = %w{one two three}
+ end
+
+ it "allows mutation of the package_name array" do
+ @resource.package_name node["foo"]
+ expect(@resource.package_name).not_to be_a_kind_of(Chef::Node::ImmutableArray)
+ expect { @resource.package_name[0] = "four" }.not_to raise_error
+ expect(@resource.package_name).to eql(%w{four two three})
+ end
+
+ it "allows mutation of the version array" do
+ @resource.version node["foo"]
+ expect(@resource.version).not_to be_a_kind_of(Chef::Node::ImmutableArray)
+ expect { @resource.version[0] = "four" }.not_to raise_error
+ expect(@resource.version).to eql(%w{four two three})
+ end
+
+ it "allows mutation of the arch array" do
+ @resource.arch node["foo"]
+ expect(@resource.arch).not_to be_a_kind_of(Chef::Node::ImmutableArray)
+ expect { @resource.arch[0] = "four" }.not_to raise_error
+ expect(@resource.arch).to eql(%w{four two three})
+ end
+
+ end
+end
+
describe Chef::Resource::YumPackage, "arch" do
before(:each) do
@resource = Chef::Resource::YumPackage.new("foo")
@@ -65,6 +106,26 @@ describe Chef::Resource::YumPackage, "flush_cache" do
@resource.flush_cache(flush_hash)
expect(@resource.flush_cache).to eq(flush_hash)
end
+
+ it "should allow 'true' for flush_cache" do
+ @resource.flush_cache(true)
+ expect(@resource.flush_cache).to eq({ before: true, after: true })
+ end
+
+ it "should allow 'false' for flush_cache" do
+ @resource.flush_cache(false)
+ expect(@resource.flush_cache).to eq({ before: false, after: false })
+ end
+
+ it "should allow ':before' for flush_cache" do
+ @resource.flush_cache(:before)
+ expect(@resource.flush_cache).to eq({ before: true, after: false })
+ end
+
+ it "should allow ':after' for flush_cache" do
+ @resource.flush_cache(:after)
+ expect(@resource.flush_cache).to eq({ before: false, after: true })
+ end
end
describe Chef::Resource::YumPackage, "allow_downgrade" do
diff --git a/spec/unit/resource/yum_repository_spec.rb b/spec/unit/resource/yum_repository_spec.rb
new file mode 100644
index 0000000000..afd6c6739a
--- /dev/null
+++ b/spec/unit/resource/yum_repository_spec.rb
@@ -0,0 +1,49 @@
+#
+# Author:: Thom May (<thom@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::YumRepository do
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:resource) { Chef::Resource::YumRepository.new("multiverse", run_context) }
+
+ context "on linux", :linux_only do
+ it "should create a new Chef::Resource::YumRepository" do
+ expect(resource).to be_a_kind_of(Chef::Resource)
+ expect(resource).to be_a_kind_of(Chef::Resource::YumRepository)
+ end
+
+ it "should resolve to a Noop class when yum is not found" do
+ expect(Chef::Provider::YumRepository).to receive(:which).with("yum").and_return(false)
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop)
+ end
+
+ it "should resolve to a YumRepository class when yum is found" do
+ expect(Chef::Provider::YumRepository).to receive(:which).with("yum").and_return(true)
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::YumRepository)
+ end
+ end
+
+ context "on windows", :windows_only do
+ it "should resolve to a NoOp provider" do
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop)
+ end
+ end
+end
diff --git a/spec/unit/resource_collection/resource_list_spec.rb b/spec/unit/resource_collection/resource_list_spec.rb
index 1e6c477854..dabb8f037d 100644
--- a/spec/unit/resource_collection/resource_list_spec.rb
+++ b/spec/unit/resource_collection/resource_list_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::ResourceCollection::ResourceList do
let(:resource_list) { Chef::ResourceCollection::ResourceList.new() }
@@ -24,7 +24,7 @@ describe Chef::ResourceCollection::ResourceList do
let(:second_resource) { Chef::Resource::ZenMaster.new("hattori") }
def insert_resource(res)
- expect{ resource_list.insert(res) }.not_to raise_error
+ expect { resource_list.insert(res) }.not_to raise_error
end
describe "initialize" do
@@ -47,14 +47,14 @@ describe Chef::ResourceCollection::ResourceList do
end
it "should raise error when trying to install something other than Chef::Resource" do
- expect{ resource_list.insert("not a resource") }.to raise_error(ArgumentError)
+ expect { resource_list.insert("not a resource") }.to raise_error(ArgumentError)
end
end
describe "accessors" do
it "should be able to insert with []=" do
- expect{ resource_list[0] = resource }.not_to raise_error
- expect{ resource_list[1] = second_resource }.not_to raise_error
+ expect { resource_list[0] = resource }.not_to raise_error
+ expect { resource_list[1] = second_resource }.not_to raise_error
expect(resource_list[0]).to be(resource)
expect(resource_list[1]).to be(second_resource)
end
diff --git a/spec/unit/resource_collection/resource_set_spec.rb b/spec/unit/resource_collection/resource_set_spec.rb
index 0e25934216..20f6f70911 100644
--- a/spec/unit/resource_collection/resource_set_spec.rb
+++ b/spec/unit/resource_collection/resource_set_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Tyler Ball (<tball@getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Tyler Ball (<tball@chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::ResourceCollection::ResourceSet do
let(:collection) { Chef::ResourceCollection::ResourceSet.new }
@@ -78,13 +78,13 @@ describe Chef::ResourceCollection::ResourceSet do
it "should find a resource by type symbol and array of names" do
collection.insert_as(zen_master)
collection.insert_as(zen_master2)
- check_by_names(collection.find(:zen_master => [zen_master_name,zen_master2_name]), zen_master_name, zen_master2_name)
+ check_by_names(collection.find(:zen_master => [zen_master_name, zen_master2_name]), zen_master_name, zen_master2_name)
end
it "should find a resource by type symbol and array of names with custom names" do
collection.insert_as(zen_master, :zzz, "name1")
collection.insert_as(zen_master2, :zzz, "name2")
- check_by_names(collection.find( :zzz => ["name1","name2"]), zen_master_name, zen_master2_name)
+ check_by_names(collection.find( :zzz => %w{name1 name2}), zen_master_name, zen_master2_name)
end
it "should find resources of multiple kinds (:zen_master => a, :zen_follower => b)" do
@@ -98,7 +98,7 @@ describe Chef::ResourceCollection::ResourceSet do
collection.insert_as(zen_master, :zzz, "name1")
collection.insert_as(zen_master2, :zzz, "name2")
collection.insert_as(zen_follower, :yyy, "name3")
- check_by_names(collection.find(:zzz => ["name1","name2"], :yyy => ["name3"]),
+ check_by_names(collection.find(:zzz => %w{name1 name2}, :yyy => ["name3"]),
zen_master_name, zen_follower_name, zen_master2_name)
end
@@ -138,13 +138,13 @@ describe Chef::ResourceCollection::ResourceSet do
collection.insert_as(zen_master2, :zzz, "name2")
collection.insert_as(zen_follower, :yyy, "name3")
check_by_names(collection.find("zzz[name1,name2]", "yyy[name3]"),
- zen_master_name, zen_follower_name,zen_master2_name)
+ zen_master_name, zen_follower_name, zen_master2_name)
end
it "should only keep the last copy when multiple instances of a Resource are inserted" do
collection.insert_as(zen_master)
expect(collection.find("zen_master[#{zen_master_name}]")).to eq(zen_master)
- new_zm =zen_master.dup
+ new_zm = zen_master.dup
new_zm.retries = 10
expect(new_zm).to_not eq(zen_master)
collection.insert_as(new_zm)
@@ -192,7 +192,7 @@ describe Chef::ResourceCollection::ResourceSet do
def check_by_names(results, *names)
expect(results.size).to eq(names.size)
names.each do |name|
- expect(results.detect{|r| r.name == name}).to_not eq(nil)
+ expect(results.detect { |r| r.name == name }).to_not eq(nil)
end
end
diff --git a/spec/unit/resource_collection/stepable_iterator_spec.rb b/spec/unit/resource_collection/stepable_iterator_spec.rb
index b34b7140fe..6354b1b7fb 100644
--- a/spec/unit/resource_collection/stepable_iterator_spec.rb
+++ b/spec/unit/resource_collection/stepable_iterator_spec.rb
@@ -1,5 +1,5 @@
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::ResourceCollection::StepableIterator do
CRSI = Chef::ResourceCollection::StepableIterator
@@ -26,7 +26,7 @@ describe Chef::ResourceCollection::StepableIterator do
describe "doing basic iteration" do
before do
- @simple_collection = [1,2,3,4]
+ @simple_collection = [1, 2, 3, 4]
@iterator = CRSI.for_collection(@simple_collection)
end
@@ -57,7 +57,7 @@ describe Chef::ResourceCollection::StepableIterator do
@iterator.each_with_index do |element, index|
collected[index] = element
end
- expect(collected).to eq({0=>1, 1=>2, 2=>3, 3=>4})
+ expect(collected).to eq({ 0 => 1, 1 => 2, 2 => 3, 3 => 4 })
end
end
@@ -117,7 +117,7 @@ describe Chef::ResourceCollection::StepableIterator do
it "doesn't step if there are no more steps" do
expect(@iterator.step).to eq(3)
- expect {@iterator.step}.not_to raise_error
+ expect { @iterator.step }.not_to raise_error
expect(@iterator.step).to be_nil
end
@@ -131,7 +131,7 @@ describe Chef::ResourceCollection::StepableIterator do
end
it "should work correctly when elements are added to the collection during iteration" do
- @collection.insert(2, lambda { @snitch_var = 815})
+ @collection.insert(2, lambda { @snitch_var = 815 })
@collection.insert(3, lambda { @iterator.pause })
@iterator.resume
expect(@snitch_var).to eq(815)
diff --git a/spec/unit/resource_collection_spec.rb b/spec/unit/resource_collection_spec.rb
index d52e7e2c26..5feb34833a 100644
--- a/spec/unit/resource_collection_spec.rb
+++ b/spec/unit/resource_collection_spec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::ResourceCollection do
let(:rc) { Chef::ResourceCollection.new() }
@@ -65,7 +65,7 @@ describe Chef::ResourceCollection do
end
it "should accept named arguments in any order" do
- rc.insert(resource, :instance_name => 'foo', :resource_type =>'bar')
+ rc.insert(resource, :instance_name => "foo", :resource_type => "bar")
expect(rc[0]).to eq(resource)
end
@@ -98,11 +98,11 @@ describe Chef::ResourceCollection do
it "should allow you to iterate over every resource in the collection" do
load_up_resources
results = Array.new
- expect {
+ expect do
rc.each do |r|
results << r.name
end
- }.not_to raise_error
+ end.not_to raise_error
results.each_index do |i|
case i
when 0
@@ -120,11 +120,11 @@ describe Chef::ResourceCollection do
it "should allow you to iterate over every resource by index" do
load_up_resources
results = Array.new
- expect {
+ expect do
rc.each_index do |i|
results << rc[i].name
end
- }.not_to raise_error
+ end.not_to raise_error
results.each_index do |i|
case i
when 0
@@ -162,6 +162,36 @@ describe Chef::ResourceCollection do
end
end
+ describe "delete" do
+ it "should allow you to delete resources by name via delete" do
+ zmr = Chef::Resource::ZenMaster.new("dog")
+ rc << zmr
+ expect(rc).not_to be_empty
+ expect(rc.delete(zmr.to_s)).to eql(zmr)
+ expect(rc).to be_empty
+
+ zmr = Chef::Resource::ZenMaster.new("cat")
+ rc[0] = zmr
+ expect(rc).not_to be_empty
+ expect(rc.delete(zmr)).to eql(zmr)
+ expect(rc).to be_empty
+
+ zmr = Chef::Resource::ZenMaster.new("monkey")
+ rc.push(zmr)
+ expect(rc).not_to be_empty
+ expect(rc.delete(zmr)).to eql(zmr)
+ expect(rc).to be_empty
+ end
+
+ it "should raise an exception if you send something strange to delete" do
+ expect { rc.delete(:symbol) }.to raise_error(ArgumentError)
+ end
+
+ it "should raise an exception if it cannot find a resource with delete" do
+ expect { rc.delete("zen_master[dog]") }.to raise_error(Chef::Exceptions::ResourceNotFound)
+ end
+ end
+
describe "resources" do
it "should find a resource by symbol and name (:zen_master => monkey)" do
@@ -171,7 +201,7 @@ describe Chef::ResourceCollection do
it "should find a resource by symbol and array of names (:zen_master => [a,b])" do
load_up_resources
- results = rc.resources(:zen_master => [ "monkey", "dog" ])
+ results = rc.resources(:zen_master => %w{monkey dog})
expect(results.length).to eql(2)
check_by_names(results, "monkey", "dog")
end
@@ -211,7 +241,7 @@ describe Chef::ResourceCollection do
end
it "raises an error when attempting to find a resource that does not exist" do
- expect {rc.find("script[nonesuch]")}.to raise_error(Chef::Exceptions::ResourceNotFound)
+ expect { rc.find("script[nonesuch]") }.to raise_error(Chef::Exceptions::ResourceNotFound)
end
end
@@ -225,7 +255,6 @@ describe Chef::ResourceCollection do
expect(rc.validate_lookup_spec!(:service => "apache2")).to be_truthy
end
-
it "accepts a chef resource object" do
res = Chef::Resource.new("foo", nil)
expect(rc.validate_lookup_spec!(res)).to be_truthy
@@ -284,15 +313,85 @@ describe Chef::ResourceCollection do
end
end
+ describe "multiple run_contexts" do
+ let(:node) { Chef::Node.new }
+ let(:parent_run_context) { Chef::RunContext.new(node, {}, nil) }
+ let(:parent_resource_collection) { parent_run_context.resource_collection }
+ let(:child_run_context) { parent_run_context.create_child }
+ let(:child_resource_collection) { child_run_context.resource_collection }
+
+ it "should find resources in the parent run_context with lookup" do
+ zmr = Chef::Resource::ZenMaster.new("dog")
+ parent_resource_collection << zmr
+ expect(child_resource_collection.lookup(zmr.to_s)).to eql(zmr)
+ end
+
+ it "should not find resources in the parent run_context with lookup_local" do
+ zmr = Chef::Resource::ZenMaster.new("dog")
+ parent_resource_collection << zmr
+ expect { child_resource_collection.lookup_local(zmr.to_s) }.to raise_error(Chef::Exceptions::ResourceNotFound)
+ end
+
+ it "should find resources in the child run_context with lookup_local" do
+ zmr = Chef::Resource::ZenMaster.new("dog")
+ child_resource_collection << zmr
+ expect(child_resource_collection.lookup_local(zmr.to_s)).to eql(zmr)
+ end
+
+ it "should find resources in the parent run_context with find" do
+ zmr = Chef::Resource::ZenMaster.new("dog")
+ parent_resource_collection << zmr
+ expect(child_resource_collection.find(zmr.to_s)).to eql(zmr)
+ end
+
+ it "should not find resources in the parent run_context with find_local" do
+ zmr = Chef::Resource::ZenMaster.new("dog")
+ parent_resource_collection << zmr
+ expect { child_resource_collection.find_local(zmr.to_s) }.to raise_error(Chef::Exceptions::ResourceNotFound)
+ end
+
+ it "should find resources in the child run_context with find_local" do
+ zmr = Chef::Resource::ZenMaster.new("dog")
+ child_resource_collection << zmr
+ expect(child_resource_collection.find_local(zmr.to_s)).to eql(zmr)
+ end
+
+ it "should not find resources in the child run_context in any way from the parent" do
+ zmr = Chef::Resource::ZenMaster.new("dog")
+ child_resource_collection << zmr
+ expect { parent_resource_collection.find_local(zmr.to_s) }.to raise_error(Chef::Exceptions::ResourceNotFound)
+ expect { parent_resource_collection.find(zmr.to_s) }.to raise_error(Chef::Exceptions::ResourceNotFound)
+ expect { parent_resource_collection.lookup_local(zmr.to_s) }.to raise_error(Chef::Exceptions::ResourceNotFound)
+ expect { parent_resource_collection.lookup(zmr.to_s) }.to raise_error(Chef::Exceptions::ResourceNotFound)
+ end
+
+ it "should behave correctly when there is an identically named resource in the child and parent" do
+ a = Chef::Resource::File.new("something")
+ a.content("foo")
+ parent_resource_collection << a
+ b = Chef::Resource::File.new("something")
+ b.content("bar")
+ child_resource_collection << b
+ expect(child_resource_collection.find_local("file[something]").content).to eql("bar")
+ expect(child_resource_collection.find("file[something]").content).to eql("bar")
+ expect(child_resource_collection.lookup_local("file[something]").content).to eql("bar")
+ expect(child_resource_collection.lookup("file[something]").content).to eql("bar")
+ expect(parent_resource_collection.find_local("file[something]").content).to eql("foo")
+ expect(parent_resource_collection.find("file[something]").content).to eql("foo")
+ expect(parent_resource_collection.lookup_local("file[something]").content).to eql("foo")
+ expect(parent_resource_collection.lookup("file[something]").content).to eql("foo")
+ end
+ end
+
def check_by_names(results, *names)
names.each do |res_name|
- expect(results.detect{ |res| res.name == res_name }).not_to eql(nil)
+ expect(results.detect { |res| res.name == res_name }).not_to eql(nil)
end
end
def load_up_resources
%w{dog cat monkey}.each do |n|
- rc << Chef::Resource::ZenMaster.new(n)
+ rc << Chef::Resource::ZenMaster.new(n)
end
rc << Chef::Resource::File.new("something")
end
diff --git a/spec/unit/resource_definition_spec.rb b/spec/unit/resource_definition_spec.rb
index 1371a8b9a6..cc19cc7a01 100644
--- a/spec/unit/resource_definition_spec.rb
+++ b/spec/unit/resource_definition_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::ResourceDefinition do
let(:defn) { Chef::ResourceDefinition.new() }
@@ -53,26 +53,26 @@ describe Chef::ResourceDefinition do
end
it "should accept a new definition with a symbol for a name" do
- expect {
+ expect do
defn.define :smoke do
end
- }.not_to raise_error
- expect {
+ end.not_to raise_error
+ expect do
defn.define "george washington" do
end
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
expect(defn.name).to eql(:smoke)
end
it "should accept a new definition with a hash" do
- expect {
+ expect do
defn.define :smoke, :cigar => "cuban", :cigarette => "marlboro" do
end
- }.not_to raise_error
+ end.not_to raise_error
end
it "should expose the prototype hash params in the params hash" do
- defn.define :smoke, :cigar => "cuban", :cigarette => "marlboro" do; end
+ defn.define(:smoke, :cigar => "cuban", :cigarette => "marlboro") {}
expect(defn.params[:cigar]).to eql("cuban")
expect(defn.params[:cigarette]).to eql("marlboro")
end
@@ -91,16 +91,16 @@ describe Chef::ResourceDefinition do
end
it "should raise an exception if prototype_params is not a hash" do
- expect {
+ expect do
defn.define :monkey, Array.new do
end
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should raise an exception if define is called without a block" do
- expect {
+ expect do
defn.define :monkey
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
it "should load a description from a file" do
diff --git a/spec/unit/resource_reporter_spec.rb b/spec/unit/resource_reporter_spec.rb
index f2c0b8fd8b..84cfb52418 100644
--- a/spec/unit/resource_reporter_spec.rb
+++ b/spec/unit/resource_reporter_spec.rb
@@ -1,9 +1,9 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Author:: Prajakta Purohit (<prajakta@opscode.com>)
-# Author:: Tyler Cloke (<tyler@opscode.com>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Author:: Prajakta Purohit (<prajakta@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
#
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,8 +20,8 @@
#
require File.expand_path("../../spec_helper", __FILE__)
-require 'chef/resource_reporter'
-require 'socket'
+require "chef/resource_reporter"
+require "socket"
describe Chef::ResourceReporter do
before(:all) do
@@ -36,22 +36,22 @@ describe Chef::ResourceReporter do
before do
@node = Chef::Node.new
@node.name("spitfire")
- @rest_client = double("Chef::REST (mock)")
- allow(@rest_client).to receive(:post_rest).and_return(true)
+ @rest_client = double("Chef::ServerAPI (mock)")
+ allow(@rest_client).to receive(:post).and_return(true)
@resource_reporter = Chef::ResourceReporter.new(@rest_client)
@new_resource = Chef::Resource::File.new("/tmp/a-file.txt")
@cookbook_name = "monkey"
@new_resource.cookbook_name = @cookbook_name
@cookbook_version = double("Cookbook::Version", :version => "1.2.3")
allow(@new_resource).to receive(:cookbook_version).and_return(@cookbook_version)
- @current_resource = Chef::Resource::File.new("/tmp/a-file.txt")
+ @current_resource = Chef::Resource::File.new("/tmp/a-file.txt")
@start_time = Time.new
@end_time = Time.new + 20
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@run_status = Chef::RunStatus.new(@node, @events)
@run_list = Chef::RunList.new
- @run_list << 'recipe[lobster]' << 'role[rage]' << 'recipe[fist]'
+ @run_list << "recipe[lobster]" << "role[rage]" << "recipe[fist]"
@expansion = Chef::RunList::RunListExpansion.new("_default", @run_list.run_list_items)
@run_id = @run_status.run_id
allow(Time).to receive(:now).and_return(@start_time, @end_time)
@@ -92,9 +92,8 @@ describe Chef::ResourceReporter do
context "when chef fails" do
before do
- allow(@rest_client).to receive(:create_url).and_return("reports/nodes/spitfire/runs/#{@run_id}");
- allow(@rest_client).to receive(:raw_http_request).and_return({"result"=>"ok"});
- allow(@rest_client).to receive(:post_rest).and_return({"uri"=>"https://example.com/reports/nodes/spitfire/runs/#{@run_id}"});
+ allow(@rest_client).to receive(:raw_request).and_return({ "result" => "ok" })
+ allow(@rest_client).to receive(:post).and_return({ "uri" => "https://example.com/reports/nodes/spitfire/runs/#{@run_id}" })
end
@@ -202,13 +201,13 @@ describe Chef::ResourceReporter do
context "and a nested resource is updated" do
before do
@implementation_resource = Chef::Resource::CookbookFile.new("/preseed-file.txt")
- @resource_reporter.resource_action_start(@implementation_resource , :create)
- @resource_reporter.resource_current_state_loaded(@implementation_resource, :create, @implementation_resource)
- @resource_reporter.resource_updated(@implementation_resource, :create)
- @resource_reporter.resource_completed(@implementation_resource)
- @resource_reporter.resource_updated(@new_resource, :create)
- @resource_reporter.resource_completed(@new_resource)
- end
+ @resource_reporter.resource_action_start(@implementation_resource , :create)
+ @resource_reporter.resource_current_state_loaded(@implementation_resource, :create, @implementation_resource)
+ @resource_reporter.resource_updated(@implementation_resource, :create)
+ @resource_reporter.resource_completed(@implementation_resource)
+ @resource_reporter.resource_updated(@new_resource, :create)
+ @resource_reporter.resource_completed(@new_resource)
+ end
it "does not collect data about the nested resource" do
expect(@resource_reporter.updated_resources.size).to eq(1)
@@ -260,19 +259,43 @@ describe Chef::ResourceReporter do
describe "when generating a report for the server" do
before do
- allow(@rest_client).to receive(:create_url).and_return("reports/nodes/spitfire/runs/#{@run_id}");
- allow(@rest_client).to receive(:raw_http_request).and_return({"result"=>"ok"});
- allow(@rest_client).to receive(:post_rest).and_return({"uri"=>"https://example.com/reports/nodes/spitfire/runs/#{@run_id}"});
+ allow(@rest_client).to receive(:raw_request).and_return({ "result" => "ok" })
+ allow(@rest_client).to receive(:post).and_return({ "uri" => "https://example.com/reports/nodes/spitfire/runs/#{@run_id}" })
@resource_reporter.run_started(@run_status)
end
+ context "when the new_resource is sensitive" do
+ before do
+ @execute_resource = Chef::Resource::Execute.new("sensitive-resource")
+ @execute_resource.name("sensitive-resource")
+ @execute_resource.command('echo "password: SECRET"')
+ @execute_resource.sensitive(true)
+ @resource_reporter.resource_action_start(@execute_resource, :run)
+ @resource_reporter.resource_current_state_loaded(@execute_resource, :run, @current_resource)
+ @resource_reporter.resource_updated(@execute_resource, :run)
+ @resource_reporter.resource_completed(@execute_resource)
+ @run_status.stop_clock
+ @report = @resource_reporter.prepare_run_data
+ @first_update_report = @report["resources"].first
+ end
+
+ it "resource_name in prepared_run_data should be the same" do
+ expect(@first_update_report["name"]).to eq("sensitive-resource")
+ end
+
+ it "resource_command in prepared_run_data should be blank" do
+ expect(@first_update_report["after"]).to eq({ :command => "sensitive-resource", :user => nil })
+ end
+ end
+
context "when the new_resource does not have a string for name and identity" do
context "the new_resource name and id are nil" do
before do
@bad_resource = Chef::Resource::File.new("/tmp/nameless_file.txt")
allow(@bad_resource).to receive(:name).and_return(nil)
allow(@bad_resource).to receive(:identity).and_return(nil)
+ allow(@bad_resource).to receive(:path).and_return(nil)
@resource_reporter.resource_action_start(@bad_resource, :create)
@resource_reporter.resource_current_state_loaded(@bad_resource, :create, @current_resource)
@resource_reporter.resource_updated(@bad_resource, :create)
@@ -294,8 +317,9 @@ describe Chef::ResourceReporter do
context "the new_resource name and id are hashes" do
before do
@bad_resource = Chef::Resource::File.new("/tmp/filename_as_hash.txt")
- allow(@bad_resource).to receive(:name).and_return({:foo=>:bar})
- allow(@bad_resource).to receive(:identity).and_return({:foo=>:bar})
+ allow(@bad_resource).to receive(:name).and_return({ :foo => :bar })
+ allow(@bad_resource).to receive(:identity).and_return({ :foo => :bar })
+ allow(@bad_resource).to receive(:path).and_return({ :foo => :bar })
@resource_reporter.resource_action_start(@bad_resource, :create)
@resource_reporter.resource_current_state_loaded(@bad_resource, :create, @current_resource)
@resource_reporter.resource_updated(@bad_resource, :create)
@@ -448,7 +472,7 @@ describe Chef::ResourceReporter do
context "when the resource is a RegistryKey with binary data" do
let(:new_resource) do
resource = Chef::Resource::RegistryKey.new('Wubba\Lubba\Dub\Dubs')
- resource.values([ { :name => 'rick', :type => :binary, :data => 255.chr * 1 } ])
+ resource.values([ { :name => "rick", :type => :binary, :data => 255.chr * 1 } ])
allow(resource).to receive(:cookbook_name).and_return(@cookbook_name)
allow(resource).to receive(:cookbook_version).and_return(@cookbook_version)
resource
@@ -456,7 +480,7 @@ describe Chef::ResourceReporter do
let(:current_resource) do
resource = Chef::Resource::RegistryKey.new('Wubba\Lubba\Dub\Dubs')
- resource.values([ { :name => 'rick', :type => :binary, :data => 255.chr * 1 } ])
+ resource.values([ { :name => "rick", :type => :binary, :data => 255.chr * 1 } ])
resource
end
@@ -466,7 +490,7 @@ describe Chef::ResourceReporter do
context "for an unsuccessful run" do
before do
- @backtrace = ["foo.rb:1 in `foo!'","bar.rb:2 in `bar!","'baz.rb:3 in `baz!'"]
+ @backtrace = ["foo.rb:1 in `foo!'", "bar.rb:2 in `bar!", "'baz.rb:3 in `baz!'"]
@node = Chef::Node.new
@node.name("spitfire")
@exception = ArgumentError.new
@@ -496,7 +520,7 @@ describe Chef::ResourceReporter do
it "includes the error inspector output in the event data" do
expect(@report["data"]["exception"]).to have_key("description")
- expect(@report["data"]["exception"]["description"]).to include({"title"=>"Error expanding the run_list:", "sections"=>[{"Unexpected Error:" => "ArgumentError: Object not found"}]})
+ expect(@report["data"]["exception"]["description"]).to include({ "title" => "Error expanding the run_list:", "sections" => [{ "Unexpected Error:" => "ArgumentError: Object not found" }] })
end
end
@@ -570,12 +594,12 @@ describe Chef::ResourceReporter do
it "sets before to {} instead of nil" do
expect(@first_update_report).to have_key("before")
- expect(@first_update_report['before']).to eq({})
+ expect(@first_update_report["before"]).to eq({})
end
it "sets after to {} instead of 'Running'" do
expect(@first_update_report).to have_key("after")
- expect(@first_update_report['after']).to eq({})
+ expect(@first_update_report["after"]).to eq({})
end
end
@@ -592,10 +616,10 @@ describe Chef::ResourceReporter do
# 404 getting the run_id
@response = Net::HTTPNotFound.new("a response body", "404", "Not Found")
@error = Net::HTTPServerException.new("404 message", @response)
- expect(@rest_client).to receive(:post_rest).
- with("reports/nodes/spitfire/runs", {:action => :start, :run_id => @run_id,
- :start_time => @start_time.to_s},
- {'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION}).
+ expect(@rest_client).to receive(:post).
+ with("reports/nodes/spitfire/runs", { :action => :start, :run_id => @run_id,
+ :start_time => @start_time.to_s },
+ { "X-Ops-Reporting-Protocol-Version" => Chef::ResourceReporter::PROTOCOL_VERSION }).
and_raise(@error)
end
@@ -606,7 +630,7 @@ describe Chef::ResourceReporter do
it "does not send a resource report to the server" do
@resource_reporter.run_started(@run_status)
- expect(@rest_client).not_to receive(:post_rest)
+ expect(@rest_client).not_to receive(:post)
@resource_reporter.run_completed(@node)
end
@@ -622,9 +646,9 @@ describe Chef::ResourceReporter do
# 500 getting the run_id
@response = Net::HTTPInternalServerError.new("a response body", "500", "Internal Server Error")
@error = Net::HTTPServerException.new("500 message", @response)
- expect(@rest_client).to receive(:post_rest).
- with("reports/nodes/spitfire/runs", {:action => :start, :run_id => @run_id, :start_time => @start_time.to_s},
- {'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION}).
+ expect(@rest_client).to receive(:post).
+ with("reports/nodes/spitfire/runs", { :action => :start, :run_id => @run_id, :start_time => @start_time.to_s },
+ { "X-Ops-Reporting-Protocol-Version" => Chef::ResourceReporter::PROTOCOL_VERSION }).
and_raise(@error)
end
@@ -635,7 +659,7 @@ describe Chef::ResourceReporter do
it "does not send a resource report to the server" do
@resource_reporter.run_started(@run_status)
- expect(@rest_client).not_to receive(:post_rest)
+ expect(@rest_client).not_to receive(:post)
@resource_reporter.run_completed(@node)
end
@@ -652,9 +676,9 @@ describe Chef::ResourceReporter do
# 500 getting the run_id
@response = Net::HTTPInternalServerError.new("a response body", "500", "Internal Server Error")
@error = Net::HTTPServerException.new("500 message", @response)
- expect(@rest_client).to receive(:post_rest).
- with("reports/nodes/spitfire/runs", {:action => :start, :run_id => @run_id, :start_time => @start_time.to_s},
- {'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION}).
+ expect(@rest_client).to receive(:post).
+ with("reports/nodes/spitfire/runs", { :action => :start, :run_id => @run_id, :start_time => @start_time.to_s },
+ { "X-Ops-Reporting-Protocol-Version" => Chef::ResourceReporter::PROTOCOL_VERSION }).
and_raise(@error)
end
@@ -664,18 +688,18 @@ describe Chef::ResourceReporter do
it "fails the run and prints an message about the error" do
expect(Chef::Log).to receive(:error).with(/500/)
- expect {
+ expect do
@resource_reporter.run_started(@run_status)
- }.to raise_error(Net::HTTPServerException)
+ end.to raise_error(Net::HTTPServerException)
end
end
context "after creating the run history document" do
before do
- response = {"uri"=>"https://example.com/reports/nodes/spitfire/runs/@run_id"}
- expect(@rest_client).to receive(:post_rest).
- with("reports/nodes/spitfire/runs", {:action => :start, :run_id => @run_id, :start_time => @start_time.to_s},
- {'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION}).
+ response = { "uri" => "https://example.com/reports/nodes/spitfire/runs/@run_id" }
+ expect(@rest_client).to receive(:post).
+ with("reports/nodes/spitfire/runs", { :action => :start, :run_id => @run_id, :start_time => @start_time.to_s },
+ { "X-Ops-Reporting-Protocol-Version" => Chef::ResourceReporter::PROTOCOL_VERSION }).
and_return(response)
@resource_reporter.run_started(@run_status)
end
@@ -693,18 +717,12 @@ describe Chef::ResourceReporter do
allow(@resource_reporter).to receive(:end_time).and_return(@end_time)
@expected_data = @resource_reporter.prepare_run_data
- post_url = "https://chef_server/example_url"
- response = {"result"=>"ok"}
+ response = { "result" => "ok" }
- expect(@rest_client).to receive(:create_url).
- with("reports/nodes/spitfire/runs/#{@run_id}").
- ordered.
- and_return(post_url)
- expect(@rest_client).to receive(:raw_http_request).ordered do |method, url, headers, data|
+ expect(@rest_client).to receive(:raw_request).ordered do |method, url, headers, data|
expect(method).to eq(:POST)
- expect(url).to eq(post_url)
- expect(headers).to eq({'Content-Encoding' => 'gzip',
- 'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION
+ expect(headers).to eq({ "Content-Encoding" => "gzip",
+ "X-Ops-Reporting-Protocol-Version" => Chef::ResourceReporter::PROTOCOL_VERSION,
})
data_stream = Zlib::GzipReader.new(StringIO.new(data))
data = data_stream.read
@@ -720,8 +738,6 @@ describe Chef::ResourceReporter do
before do
@enable_reporting_url_fatals = Chef::Config[:enable_reporting_url_fatals]
Chef::Config[:enable_reporting_url_fatals] = true
- # this call doesn't matter for this context
- allow(@rest_client).to receive(:create_url)
end
after do
@@ -731,7 +747,7 @@ describe Chef::ResourceReporter do
it "should log 4xx errors" do
response = Net::HTTPClientError.new("forbidden", "403", "Forbidden")
error = Net::HTTPServerException.new("403 message", response)
- allow(@rest_client).to receive(:raw_http_request).and_raise(error)
+ allow(@rest_client).to receive(:raw_request).and_raise(error)
expect(Chef::Log).to receive(:error).with(/403/)
@resource_reporter.post_reporting_data
@@ -740,14 +756,14 @@ describe Chef::ResourceReporter do
it "should log error 5xx errors" do
response = Net::HTTPServerError.new("internal error", "500", "Internal Server Error")
error = Net::HTTPFatalError.new("500 message", response)
- allow(@rest_client).to receive(:raw_http_request).and_raise(error)
+ allow(@rest_client).to receive(:raw_request).and_raise(error)
expect(Chef::Log).to receive(:error).with(/500/)
@resource_reporter.post_reporting_data
end
it "should log if a socket error happens" do
- allow(@rest_client).to receive(:raw_http_request).and_raise(SocketError.new("test socket error"))
+ allow(@rest_client).to receive(:raw_request).and_raise(SocketError.new("test socket error"))
expect(Chef::Log).to receive(:error).with(/test socket error/)
@resource_reporter.post_reporting_data
@@ -755,11 +771,11 @@ describe Chef::ResourceReporter do
end
it "should raise if an unkwown error happens" do
- allow(@rest_client).to receive(:raw_http_request).and_raise(Exception.new)
+ allow(@rest_client).to receive(:raw_request).and_raise(Exception.new)
- expect {
+ expect do
@resource_reporter.post_reporting_data
- }.to raise_error(Exception)
+ end.to raise_error(Exception)
end
end
end
diff --git a/spec/unit/resource_resolver_spec.rb b/spec/unit/resource_resolver_spec.rb
index b3bda9d945..d707ade009 100644
--- a/spec/unit/resource_resolver_spec.rb
+++ b/spec/unit/resource_resolver_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Ranjib Dey
-# Copyright:: Copyright (c) 2015 Ranjib Dey <ranjib@linux.com>.
+# Copyright:: Copyright 2015-2016, Ranjib Dey <ranjib@linux.com>.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,37 +16,36 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/resource_resolver'
-
+require "spec_helper"
+require "chef/resource_resolver"
describe Chef::ResourceResolver do
- it '#resolve' do
+ it "#resolve" do
expect(described_class.resolve(:execute)).to eq(Chef::Resource::Execute)
end
- it '#list' do
+ it "#list" do
expect(described_class.list(:package)).to_not be_empty
end
- context 'instance methods' do
+ context "instance methods" do
let(:resolver) do
- described_class.new(Chef::Node.new, 'execute')
+ described_class.new(Chef::Node.new, "execute")
end
- it '#resolve' do
+ it "#resolve" do
expect(resolver.resolve).to eq Chef::Resource::Execute
end
- it '#list' do
+ it "#list" do
expect(resolver.list).to eq [ Chef::Resource::Execute ]
end
- it '#provided_by? returns true when resource class is in the list' do
+ it "#provided_by? returns true when resource class is in the list" do
expect(resolver.provided_by?(Chef::Resource::Execute)).to be_truthy
end
- it '#provided_by? returns false when resource class is not in the list' do
+ it "#provided_by? returns false when resource class is not in the list" do
expect(resolver.provided_by?(Chef::Resource::File)).to be_falsey
end
end
diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb
index b9ba80068b..2f75ba0241 100644
--- a/spec/unit/resource_spec.rb
+++ b/spec/unit/resource_spec.rb
@@ -1,9 +1,9 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Seth Chisamore (<schisamo@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,28 +19,27 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Resource do
- before(:each) do
- @cookbook_repo_path = File.join(CHEF_SPEC_DATA, 'cookbooks')
- @cookbook_collection = Chef::CookbookCollection.new(Chef::CookbookLoader.new(@cookbook_repo_path))
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
- @resource = Chef::Resource.new("funk", @run_context)
- end
+ let(:cookbook_repo_path) { File.join(CHEF_SPEC_DATA, "cookbooks") }
+ let(:cookbook_collection) { Chef::CookbookCollection.new(Chef::CookbookLoader.new(cookbook_repo_path)) }
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) }
+ let(:resource) { resource_class.new("funk", run_context) }
+ let(:resource_class) { Chef::Resource }
it "should mixin shell_out" do
- expect(@resource.respond_to?(:shell_out)).to be true
+ expect(resource.respond_to?(:shell_out)).to be true
end
it "should mixin shell_out!" do
- expect(@resource.respond_to?(:shell_out!)).to be true
+ expect(resource.respond_to?(:shell_out!)).to be true
end
it "should mixin shell_out_with_systems_locale" do
- expect(@resource.respond_to?(:shell_out_with_systems_locale)).to be true
+ expect(resource.respond_to?(:shell_out_with_systems_locale)).to be true
end
describe "when inherited" do
@@ -86,30 +85,29 @@ describe Chef::Resource do
end
describe "when no identity attribute has been declared" do
- before do
- @resource_sans_id = Chef::Resource.new("my-name")
- end
+ let(:resource_sans_id) { Chef::Resource.new("my-name") }
# Would rather force identity attributes to be set for everything,
# but that's not plausible for back compat reasons.
it "uses the name as the identity" do
- expect(@resource_sans_id.identity).to eq("my-name")
+ expect(resource_sans_id.identity).to eq("my-name")
end
end
describe "when an identity attribute has been declared" do
- before do
- @file_resource_class = Class.new(Chef::Resource) do
+ let(:file_resource) do
+ file_resource_class = Class.new(Chef::Resource) do
identity_attr :path
attr_accessor :path
end
- @file_resource = @file_resource_class.new("identity-attr-test")
- @file_resource.path = "/tmp/foo.txt"
+ file_resource = file_resource_class.new("identity-attr-test")
+ file_resource.path = "/tmp/foo.txt"
+ file_resource
end
it "gives the value of its identity attribute" do
- expect(@file_resource.identity).to eq("/tmp/foo.txt")
+ expect(file_resource.identity).to eq("/tmp/foo.txt")
end
end
@@ -142,8 +140,8 @@ describe Chef::Resource do
end
describe "when a set of state attributes has been declared" do
- before do
- @file_resource_class = Class.new(Chef::Resource) do
+ let(:file_resource) do
+ file_resource_class = Class.new(Chef::Resource) do
state_attrs :checksum, :owner, :group, :mode
@@ -153,15 +151,16 @@ describe Chef::Resource do
attr_accessor :mode
end
- @file_resource = @file_resource_class.new("describe-state-test")
- @file_resource.checksum = "abc123"
- @file_resource.owner = "root"
- @file_resource.group = "wheel"
- @file_resource.mode = "0644"
+ file_resource = file_resource_class.new("describe-state-test")
+ file_resource.checksum = "abc123"
+ file_resource.owner = "root"
+ file_resource.group = "wheel"
+ file_resource.mode = "0644"
+ file_resource
end
it "describes its state" do
- resource_state = @file_resource.state
+ resource_state = file_resource.state
expect(resource_state.keys).to match_array([:checksum, :owner, :group, :mode])
expect(resource_state[:checksum]).to eq("abc123")
expect(resource_state[:owner]).to eq("root")
@@ -170,158 +169,181 @@ describe Chef::Resource do
end
end
+ describe "#state_for_resource_reporter" do
+ context "when a property is marked as sensitive" do
+ it "suppresses the sensitive property's value" do
+ resource_class = Class.new(Chef::Resource) { property :foo, String, sensitive: true }
+ resource = resource_class.new("sensitive_property_tests")
+ resource.foo = "some value"
+ expect(resource.state_for_resource_reporter[:foo]).to eq("*sensitive value suppressed*")
+ end
+ end
+
+ context "when a property is not marked as sensitive" do
+ it "does not suppress the property's value" do
+ resource_class = Class.new(Chef::Resource) { property :foo, String }
+ resource = resource_class.new("sensitive_property_tests")
+ resource.foo = "some value"
+ expect(resource.state_for_resource_reporter[:foo]).to eq("some value")
+ end
+ end
+ end
+
describe "load_from" do
+ let(:prior_resource) do
+ prior_resource = Chef::Resource.new("funk")
+ prior_resource.supports(:funky => true)
+ prior_resource.source_line
+ prior_resource.allowed_actions << :funkytown
+ prior_resource.action(:funkytown)
+ prior_resource
+ end
before(:each) do
- @prior_resource = Chef::Resource.new("funk")
- @prior_resource.supports(:funky => true)
- @prior_resource.source_line
- @prior_resource.allowed_actions << :funkytown
- @prior_resource.action(:funkytown)
- @resource.allowed_actions << :funkytown
- @run_context.resource_collection << @prior_resource
+ resource.allowed_actions << :funkytown
+ run_context.resource_collection << prior_resource
end
it "should load the attributes of a prior resource" do
- @resource.load_from(@prior_resource)
- expect(@resource.supports).to eq({ :funky => true })
+ resource.load_from(prior_resource)
+ expect(resource.supports).to eq({ :funky => true })
end
it "should not inherit the action from the prior resource" do
- @resource.load_from(@prior_resource)
- expect(@resource.action).not_to eq(@prior_resource.action)
+ resource.load_from(prior_resource)
+ expect(resource.action).not_to eq(prior_resource.action)
end
end
describe "name" do
it "should have a name" do
- expect(@resource.name).to eql("funk")
+ expect(resource.name).to eql("funk")
end
it "should let you set a new name" do
- @resource.name "monkey"
- expect(@resource.name).to eql("monkey")
+ resource.name "monkey"
+ expect(resource.name).to eql("monkey")
end
it "coerces arrays to names" do
- expect(@resource.name ['a', 'b']).to eql('a, b')
+ expect(resource.name %w{a b}).to eql("a, b")
end
it "should coerce objects to a string" do
- expect(@resource.name Object.new).to be_a(String)
+ expect(resource.name Object.new).to be_a(String)
end
end
describe "noop" do
it "should accept true or false for noop" do
- expect { @resource.noop true }.not_to raise_error
- expect { @resource.noop false }.not_to raise_error
- expect { @resource.noop "eat it" }.to raise_error(ArgumentError)
+ expect { resource.noop true }.not_to raise_error
+ expect { resource.noop false }.not_to raise_error
+ expect { resource.noop "eat it" }.to raise_error(ArgumentError)
end
end
describe "notifies" do
it "should make notified resources appear in the actions hash" do
- @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
- @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee")
- expect(@resource.delayed_notifications.detect{|e| e.resource.name == "coffee" && e.action == :reload}).not_to be_nil
+ run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+ resource.notifies :reload, run_context.resource_collection.find(:zen_master => "coffee")
+ expect(resource.delayed_notifications.detect { |e| e.resource.name == "coffee" && e.action == :reload }).not_to be_nil
end
it "should make notified resources be capable of acting immediately" do
- @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
- @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee"), :immediate
- expect(@resource.immediate_notifications.detect{|e| e.resource.name == "coffee" && e.action == :reload}).not_to be_nil
+ run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+ resource.notifies :reload, run_context.resource_collection.find(:zen_master => "coffee"), :immediate
+ expect(resource.immediate_notifications.detect { |e| e.resource.name == "coffee" && e.action == :reload }).not_to be_nil
end
it "should raise an exception if told to act in other than :delay or :immediate(ly)" do
- @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
- expect {
- @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee"), :someday
- }.to raise_error(ArgumentError)
+ run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+ expect do
+ resource.notifies :reload, run_context.resource_collection.find(:zen_master => "coffee"), :someday
+ end.to raise_error(ArgumentError)
end
it "should allow multiple notified resources appear in the actions hash" do
- @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
- @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee")
- expect(@resource.delayed_notifications.detect{|e| e.resource.name == "coffee" && e.action == :reload}).not_to be_nil
+ run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+ resource.notifies :reload, run_context.resource_collection.find(:zen_master => "coffee")
+ expect(resource.delayed_notifications.detect { |e| e.resource.name == "coffee" && e.action == :reload }).not_to be_nil
- @run_context.resource_collection << Chef::Resource::ZenMaster.new("beans")
- @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "beans")
- expect(@resource.delayed_notifications.detect{|e| e.resource.name == "beans" && e.action == :reload}).not_to be_nil
+ run_context.resource_collection << Chef::Resource::ZenMaster.new("beans")
+ resource.notifies :reload, run_context.resource_collection.find(:zen_master => "beans")
+ expect(resource.delayed_notifications.detect { |e| e.resource.name == "beans" && e.action == :reload }).not_to be_nil
end
it "creates a notification for a resource that is not yet in the resource collection" do
- @resource.notifies(:restart, :service => 'apache')
- expected_notification = Chef::Resource::Notification.new({:service => "apache"}, :restart, @resource)
- expect(@resource.delayed_notifications).to include(expected_notification)
+ resource.notifies(:restart, :service => "apache")
+ expected_notification = Chef::Resource::Notification.new({ :service => "apache" }, :restart, resource)
+ expect(resource.delayed_notifications).to include(expected_notification)
end
it "notifies another resource immediately" do
- @resource.notifies_immediately(:restart, :service => 'apache')
- expected_notification = Chef::Resource::Notification.new({:service => "apache"}, :restart, @resource)
- expect(@resource.immediate_notifications).to include(expected_notification)
+ resource.notifies_immediately(:restart, :service => "apache")
+ expected_notification = Chef::Resource::Notification.new({ :service => "apache" }, :restart, resource)
+ expect(resource.immediate_notifications).to include(expected_notification)
end
it "notifies a resource to take action at the end of the chef run" do
- @resource.notifies_delayed(:restart, :service => "apache")
- expected_notification = Chef::Resource::Notification.new({:service => "apache"}, :restart, @resource)
- expect(@resource.delayed_notifications).to include(expected_notification)
+ resource.notifies_delayed(:restart, :service => "apache")
+ expected_notification = Chef::Resource::Notification.new({ :service => "apache" }, :restart, resource)
+ expect(resource.delayed_notifications).to include(expected_notification)
end
it "notifies a resource with an array for its name via its prettified string name" do
- @run_context.resource_collection << Chef::Resource::ZenMaster.new(["coffee", "tea"])
- @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee, tea")
- expect(@resource.delayed_notifications.detect{|e| e.resource.name == "coffee, tea" && e.action == :reload}).not_to be_nil
+ run_context.resource_collection << Chef::Resource::ZenMaster.new(%w{coffee tea})
+ resource.notifies :reload, run_context.resource_collection.find(:zen_master => "coffee, tea")
+ expect(resource.delayed_notifications.detect { |e| e.resource.name == "coffee, tea" && e.action == :reload }).not_to be_nil
end
end
describe "subscribes" do
it "should make resources appear in the actions hash of subscribed nodes" do
- @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
- zr = @run_context.resource_collection.find(:zen_master => "coffee")
- @resource.subscribes :reload, zr
- expect(zr.delayed_notifications.detect{|e| e.resource.name == "funk" && e.action == :reload}).not_to be_nil
+ run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+ zr = run_context.resource_collection.find(:zen_master => "coffee")
+ resource.subscribes :reload, zr
+ expect(zr.delayed_notifications.detect { |e| e.resource.name == "funk" && e.action == :reload }).not_to be_nil
end
it "should make resources appear in the actions hash of subscribed nodes" do
- @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
- zr = @run_context.resource_collection.find(:zen_master => "coffee")
- @resource.subscribes :reload, zr
- expect(zr.delayed_notifications.detect{|e| e.resource.name == @resource.name && e.action == :reload}).not_to be_nil
+ run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+ zr = run_context.resource_collection.find(:zen_master => "coffee")
+ resource.subscribes :reload, zr
+ expect(zr.delayed_notifications.detect { |e| e.resource.name == resource.name && e.action == :reload }).not_to be_nil
- @run_context.resource_collection << Chef::Resource::ZenMaster.new("bean")
- zrb = @run_context.resource_collection.find(:zen_master => "bean")
+ run_context.resource_collection << Chef::Resource::ZenMaster.new("bean")
+ zrb = run_context.resource_collection.find(:zen_master => "bean")
zrb.subscribes :reload, zr
- expect(zr.delayed_notifications.detect{|e| e.resource.name == @resource.name && e.action == :reload}).not_to be_nil
+ expect(zr.delayed_notifications.detect { |e| e.resource.name == resource.name && e.action == :reload }).not_to be_nil
end
it "should make subscribed resources be capable of acting immediately" do
- @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
- zr = @run_context.resource_collection.find(:zen_master => "coffee")
- @resource.subscribes :reload, zr, :immediately
- expect(zr.immediate_notifications.detect{|e| e.resource.name == @resource.name && e.action == :reload}).not_to be_nil
+ run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+ zr = run_context.resource_collection.find(:zen_master => "coffee")
+ resource.subscribes :reload, zr, :immediately
+ expect(zr.immediate_notifications.detect { |e| e.resource.name == resource.name && e.action == :reload }).not_to be_nil
end
end
describe "defined_at" do
it "should correctly parse source_line on unix-like operating systems" do
- @resource.source_line = "/some/path/to/file.rb:80:in `wombat_tears'"
- expect(@resource.defined_at).to eq("/some/path/to/file.rb line 80")
+ resource.source_line = "/some/path/to/file.rb:80:in `wombat_tears'"
+ expect(resource.defined_at).to eq("/some/path/to/file.rb line 80")
end
it "should correctly parse source_line on Windows" do
- @resource.source_line = "C:/some/path/to/file.rb:80 in 1`wombat_tears'"
- expect(@resource.defined_at).to eq("C:/some/path/to/file.rb line 80")
+ resource.source_line = "C:/some/path/to/file.rb:80 in 1`wombat_tears'"
+ expect(resource.defined_at).to eq("C:/some/path/to/file.rb line 80")
end
it "should include the cookbook and recipe when it knows it" do
- @resource.source_line = "/some/path/to/file.rb:80:in `wombat_tears'"
- @resource.recipe_name = "wombats"
- @resource.cookbook_name = "animals"
- expect(@resource.defined_at).to eq("animals::wombats line 80")
+ resource.source_line = "/some/path/to/file.rb:80:in `wombat_tears'"
+ resource.recipe_name = "wombats"
+ resource.cookbook_name = "animals"
+ expect(resource.defined_at).to eq("animals::wombats line 80")
end
it "should recognize dynamically defined resources" do
- expect(@resource.defined_at).to eq("dynamically defined")
+ expect(resource.defined_at).to eq("dynamically defined")
end
end
@@ -332,20 +354,38 @@ describe Chef::Resource do
end
end
+ describe "to_text" do
+ it "prints nice message" do
+ resource_class = Class.new(Chef::Resource) { property :foo, String }
+ resource = resource_class.new("sensitive_property_tests")
+ resource.foo = "some value"
+ expect(resource.to_text).to match(/foo "some value"/)
+ end
+
+ context "when property is sensitive" do
+ it "supresses that properties value" do
+ resource_class = Class.new(Chef::Resource) { property :foo, String, sensitive: true }
+ resource = resource_class.new("sensitive_property_tests")
+ resource.foo = "some value"
+ expect(resource.to_text).to match(/foo "\*sensitive value suppressed\*"/)
+ end
+ end
+ end
+
describe "self.resource_name" do
context "When resource_name is not set" do
it "and there are no provides lines, resource_name is nil" do
c = Class.new(Chef::Resource) do
end
- r = c.new('hi')
+ r = c.new("hi")
r.declared_type = :d
expect(c.resource_name).to be_nil
expect(r.resource_name).to be_nil
expect(r.declared_type).to eq :d
end
- it "and there are no provides lines, @resource_name is used" do
+ it "and there are no provides lines, resource_name is used" do
c = Class.new(Chef::Resource) do
def initialize(*args, &block)
@resource_name = :blah
@@ -353,7 +393,7 @@ describe Chef::Resource do
end
end
- r = c.new('hi')
+ r = c.new("hi")
r.declared_type = :d
expect(c.resource_name).to be_nil
expect(r.resource_name).to eq :blah
@@ -367,7 +407,7 @@ describe Chef::Resource do
end
end
- r = c.new('hi')
+ r = c.new("hi")
r.declared_type = :d
expect(c.resource_name).to be_nil
expect(r.resource_name).to be_nil
@@ -377,10 +417,10 @@ describe Chef::Resource do
it "resource_name without provides is honored" do
c = Class.new(Chef::Resource) do
- resource_name 'blah'
+ resource_name "blah"
end
- r = c.new('hi')
+ r = c.new("hi")
r.declared_type = :d
expect(c.resource_name).to eq :blah
expect(r.resource_name).to eq :blah
@@ -392,7 +432,7 @@ describe Chef::Resource do
end
c.resource_name = :blah
- r = c.new('hi')
+ r = c.new("hi")
r.declared_type = :d
expect(c.resource_name).to eq :blah
expect(r.resource_name).to eq :blah
@@ -404,7 +444,7 @@ describe Chef::Resource do
provides :self_resource_name_test_3
end
- r = c.new('hi')
+ r = c.new("hi")
r.declared_type = :d
expect(c.resource_name).to eq :blah
expect(r.resource_name).to eq :blah
@@ -415,30 +455,43 @@ describe Chef::Resource do
describe "is" do
it "should return the arguments passed with 'is'" do
zm = Chef::Resource::ZenMaster.new("coffee")
- expect(zm.is("one", "two", "three")).to eq(%w|one two three|)
+ expect(zm.is("one", "two", "three")).to eq(%w{one two three})
end
it "should allow arguments preceded by is to methods" do
- @resource.noop(@resource.is(true))
- expect(@resource.noop).to eql(true)
+ resource.noop(resource.is(true))
+ expect(resource.noop).to eql(true)
end
end
describe "to_json" do
it "should serialize to json" do
- json = @resource.to_json
+ json = resource.to_json
expect(json).to match(/json_class/)
expect(json).to match(/instance_vars/)
end
include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
- let(:jsonable) { @resource }
+ let(:jsonable) { resource }
end
end
describe "to_hash" do
+ context "when the resource has a property with a default" do
+ let(:resource_class) { Class.new(Chef::Resource) { property :a, default: 1 } }
+ it "should include the default in the hash" do
+ expect(resource.to_hash.keys.sort).to eq([:a, :allowed_actions, :params, :provider, :updated,
+ :updated_by_last_action, :before, :supports,
+ :noop, :ignore_failure, :name, :source_line,
+ :action, :retries, :retry_delay, :elapsed_time,
+ :default_guard_interpreter, :guard_interpreter, :sensitive].sort)
+ expect(resource.to_hash[:name]).to eq "funk"
+ expect(resource.to_hash[:a]).to eq 1
+ end
+ end
+
it "should convert to a hash" do
- hash = @resource.to_hash
+ hash = resource.to_hash
expected_keys = [ :allowed_actions, :params, :provider, :updated,
:updated_by_last_action, :before, :supports,
:noop, :ignore_failure, :name, :source_line,
@@ -452,80 +505,83 @@ describe Chef::Resource do
describe "self.json_create" do
it "should deserialize itself from json" do
- json = Chef::JSONCompat.to_json(@resource)
+ json = Chef::JSONCompat.to_json(resource)
serialized_node = Chef::JSONCompat.from_json(json)
expect(serialized_node).to be_a_kind_of(Chef::Resource)
- expect(serialized_node.name).to eql(@resource.name)
+ expect(serialized_node.name).to eql(resource.name)
end
end
describe "supports" do
it "should allow you to set what features this resource supports" do
support_hash = { :one => :two }
- @resource.supports(support_hash)
- expect(@resource.supports).to eql(support_hash)
+ resource.supports(support_hash)
+ expect(resource.supports).to eql(support_hash)
end
it "should return the current value of supports" do
- expect(@resource.supports).to eq({})
+ expect(resource.supports).to eq({})
end
end
describe "ignore_failure" do
it "should default to throwing an error if a provider fails for a resource" do
- expect(@resource.ignore_failure).to eq(false)
+ expect(resource.ignore_failure).to eq(false)
end
it "should allow you to set whether a provider should throw exceptions with ignore_failure" do
- @resource.ignore_failure(true)
- expect(@resource.ignore_failure).to eq(true)
+ resource.ignore_failure(true)
+ expect(resource.ignore_failure).to eq(true)
end
it "should allow you to epic_fail" do
- @resource.epic_fail(true)
- expect(@resource.epic_fail).to eq(true)
+ resource.epic_fail(true)
+ expect(resource.epic_fail).to eq(true)
end
end
describe "retries" do
- before do
- @retriable_resource = Chef::Resource::Cat.new("precious", @run_context)
- @retriable_resource.provider = Chef::Provider::SnakeOil
- @retriable_resource.action = :purr
+ let(:retriable_resource) do
+ retriable_resource = Chef::Resource::Cat.new("precious", run_context)
+ retriable_resource.provider = Chef::Provider::SnakeOil
+ retriable_resource.action = :purr
+ retriable_resource
+ end
- @node.automatic_attrs[:platform] = "fubuntu"
- @node.automatic_attrs[:platform_version] = '10.04'
+ before do
+ node.automatic_attrs[:platform] = "fubuntu"
+ node.automatic_attrs[:platform_version] = "10.04"
end
it "should default to not retrying if a provider fails for a resource" do
- expect(@retriable_resource.retries).to eq(0)
+ expect(retriable_resource.retries).to eq(0)
end
it "should allow you to set how many retries a provider should attempt after a failure" do
- @retriable_resource.retries(2)
- expect(@retriable_resource.retries).to eq(2)
+ retriable_resource.retries(2)
+ expect(retriable_resource.retries).to eq(2)
end
it "should default to a retry delay of 2 seconds" do
- expect(@retriable_resource.retry_delay).to eq(2)
+ expect(retriable_resource.retry_delay).to eq(2)
end
it "should allow you to set the retry delay" do
- @retriable_resource.retry_delay(10)
- expect(@retriable_resource.retry_delay).to eq(10)
+ retriable_resource.retry_delay(10)
+ expect(retriable_resource.retry_delay).to eq(10)
end
it "should keep given value of retries intact after the provider fails for a resource" do
- @retriable_resource.retries(3)
- @retriable_resource.retry_delay(0) # No need to wait.
+ retriable_resource.retries(3)
+ retriable_resource.retry_delay(0) # No need to wait.
- provider = Chef::Provider::SnakeOil.new(@retriable_resource, @run_context)
+ provider = Chef::Provider::SnakeOil.new(retriable_resource, run_context)
allow(Chef::Provider::SnakeOil).to receive(:new).and_return(provider)
allow(provider).to receive(:action_purr).and_raise
- expect(@retriable_resource).to receive(:sleep).exactly(3).times
- expect { @retriable_resource.run_action(:purr) }.to raise_error
- expect(@retriable_resource.retries).to eq(3)
+ expect(retriable_resource).to receive(:sleep).exactly(3).times
+ expect { retriable_resource.run_action(:purr) }.to raise_error(RuntimeError)
+ expect(retriable_resource.retries).to eq(3)
end
end
@@ -545,11 +601,11 @@ describe Chef::Resource do
end
it "warns when setting provider_base" do
- expect {
+ expect do
class OverrideProviderBaseTest2 < Chef::Resource
provider_base Chef::Provider::Package
end
- }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+ end.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
end
end
@@ -560,28 +616,28 @@ describe Chef::Resource do
describe "when updated by a provider" do
before do
- @resource.updated_by_last_action(true)
+ resource.updated_by_last_action(true)
end
it "records that it was updated" do
- expect(@resource).to be_updated
+ expect(resource).to be_updated
end
it "records that the last action updated the resource" do
- expect(@resource).to be_updated_by_last_action
+ expect(resource).to be_updated_by_last_action
end
describe "and then run again without being updated" do
before do
- @resource.updated_by_last_action(false)
+ resource.updated_by_last_action(false)
end
it "reports that it is updated" do
- expect(@resource).to be_updated
+ expect(resource).to be_updated
end
it "reports that it was not updated by the last action" do
- expect(@resource).not_to be_updated_by_last_action
+ expect(resource).not_to be_updated_by_last_action
end
end
@@ -589,72 +645,75 @@ describe Chef::Resource do
end
describe "when invoking its action" do
+ let(:resource) do
+ resource = Chef::Resource.new("provided", run_context)
+ resource.provider = Chef::Provider::SnakeOil
+ resource
+ end
before do
- @resource = Chef::Resource.new("provided", @run_context)
- @resource.provider = Chef::Provider::SnakeOil
- @node.automatic_attrs[:platform] = "fubuntu"
- @node.automatic_attrs[:platform_version] = '10.04'
+ node.automatic_attrs[:platform] = "fubuntu"
+ node.automatic_attrs[:platform_version] = "10.04"
end
it "does not run only_if if no only_if command is given" do
expect_any_instance_of(Chef::Resource::Conditional).not_to receive(:evaluate)
- @resource.only_if.clear
- @resource.run_action(:purr)
+ resource.only_if.clear
+ resource.run_action(:purr)
end
it "runs runs an only_if when one is given" do
snitch_variable = nil
- @resource.only_if { snitch_variable = true }
- expect(@resource.only_if.first.positivity).to eq(:only_if)
+ resource.only_if { snitch_variable = true }
+ expect(resource.only_if.first.positivity).to eq(:only_if)
#Chef::Mixin::Command.should_receive(:only_if).with(true, {}).and_return(false)
- @resource.run_action(:purr)
+ resource.run_action(:purr)
expect(snitch_variable).to be_truthy
end
it "runs multiple only_if conditionals" do
snitch_var1, snitch_var2 = nil, nil
- @resource.only_if { snitch_var1 = 1 }
- @resource.only_if { snitch_var2 = 2 }
- @resource.run_action(:purr)
+ resource.only_if { snitch_var1 = 1 }
+ resource.only_if { snitch_var2 = 2 }
+ resource.run_action(:purr)
expect(snitch_var1).to eq(1)
expect(snitch_var2).to eq(2)
end
it "accepts command options for only_if conditionals" do
expect_any_instance_of(Chef::Resource::Conditional).to receive(:evaluate_command).at_least(1).times
- @resource.only_if("true", :cwd => '/tmp')
- expect(@resource.only_if.first.command_opts).to eq({:cwd => '/tmp'})
- @resource.run_action(:purr)
+ resource.only_if("true", :cwd => "/tmp")
+ expect(resource.only_if.first.command_opts).to eq({ :cwd => "/tmp" })
+ resource.run_action(:purr)
end
it "runs not_if as a command when it is a string" do
expect_any_instance_of(Chef::Resource::Conditional).to receive(:evaluate_command).at_least(1).times
- @resource.not_if "pwd"
- @resource.run_action(:purr)
+ resource.not_if "pwd"
+ resource.run_action(:purr)
end
it "runs not_if as a block when it is a ruby block" do
expect_any_instance_of(Chef::Resource::Conditional).to receive(:evaluate_block).at_least(1).times
- @resource.not_if { puts 'foo' }
- @resource.run_action(:purr)
+ resource.not_if { puts "foo" }
+ resource.run_action(:purr)
end
it "does not run not_if if no not_if command is given" do
expect_any_instance_of(Chef::Resource::Conditional).not_to receive(:evaluate)
- @resource.not_if.clear
- @resource.run_action(:purr)
+ resource.not_if.clear
+ resource.run_action(:purr)
end
it "accepts command options for not_if conditionals" do
- @resource.not_if("pwd" , :cwd => '/tmp')
- expect(@resource.not_if.first.command_opts).to eq({:cwd => '/tmp'})
+ resource.not_if("pwd" , :cwd => "/tmp")
+ expect(resource.not_if.first.command_opts).to eq({ :cwd => "/tmp" })
end
it "accepts multiple not_if conditionals" do
snitch_var1, snitch_var2 = true, true
- @resource.not_if {snitch_var1 = nil}
- @resource.not_if {snitch_var2 = false}
- @resource.run_action(:purr)
+ resource.not_if { snitch_var1 = nil }
+ resource.not_if { snitch_var2 = false }
+ resource.run_action(:purr)
expect(snitch_var1).to be_nil
expect(snitch_var2).to be_falsey
end
@@ -662,13 +721,11 @@ describe Chef::Resource do
it "reports 0 elapsed time if actual elapsed time is < 0" do
expected = Time.now
allow(Time).to receive(:now).and_return(expected, expected - 1)
- @resource.run_action(:purr)
- expect(@resource.elapsed_time).to eq(0)
+ resource.run_action(:purr)
+ expect(resource.elapsed_time).to eq(0)
end
describe "guard_interpreter attribute" do
- let(:resource) { @resource }
-
it "should be set to :default by default" do
expect(resource.guard_interpreter).to eq(:default)
end
@@ -679,7 +736,7 @@ describe Chef::Resource do
end
it "should raise Chef::Exceptions::ValidationFailed on an attempt to set the guard_interpreter attribute to something other than a Symbol" do
- expect { resource.guard_interpreter('command_dot_com') }.to raise_error(Chef::Exceptions::ValidationFailed)
+ expect { resource.guard_interpreter("command_dot_com") }.to raise_error(Chef::Exceptions::ValidationFailed)
end
it "should not raise an exception when setting the guard interpreter attribute to a Symbol" do
@@ -691,106 +748,130 @@ describe Chef::Resource do
describe "should_skip?" do
before do
- @resource = Chef::Resource::Cat.new("sugar", @run_context)
+ resource = Chef::Resource::Cat.new("sugar", run_context)
end
it "should return false by default" do
- expect(@resource.should_skip?(:purr)).to be_falsey
+ expect(resource.should_skip?(:purr)).to be_falsey
end
it "should return false when only_if is met" do
- @resource.only_if { true }
- expect(@resource.should_skip?(:purr)).to be_falsey
+ resource.only_if { true }
+ expect(resource.should_skip?(:purr)).to be_falsey
end
it "should return true when only_if is not met" do
- @resource.only_if { false }
- expect(@resource.should_skip?(:purr)).to be_truthy
+ resource.only_if { false }
+ expect(resource.should_skip?(:purr)).to be_truthy
end
it "should return true when not_if is met" do
- @resource.not_if { true }
- expect(@resource.should_skip?(:purr)).to be_truthy
+ resource.not_if { true }
+ expect(resource.should_skip?(:purr)).to be_truthy
end
it "should return false when not_if is not met" do
- @resource.not_if { false }
- expect(@resource.should_skip?(:purr)).to be_falsey
+ resource.not_if { false }
+ expect(resource.should_skip?(:purr)).to be_falsey
end
it "should return true when only_if is met but also not_if is met" do
- @resource.only_if { true }
- @resource.not_if { true }
- expect(@resource.should_skip?(:purr)).to be_truthy
+ resource.only_if { true }
+ resource.not_if { true }
+ expect(resource.should_skip?(:purr)).to be_truthy
+ end
+
+ it "should return false when only_if is met and also not_if is not met" do
+ resource.only_if { true }
+ resource.not_if { false }
+ expect(resource.should_skip?(:purr)).to be_falsey
end
it "should return true when one of multiple only_if's is not met" do
- @resource.only_if { true }
- @resource.only_if { false }
- @resource.only_if { true }
- expect(@resource.should_skip?(:purr)).to be_truthy
+ resource.only_if { true }
+ resource.only_if { false }
+ resource.only_if { true }
+ expect(resource.should_skip?(:purr)).to be_truthy
end
it "should return true when one of multiple not_if's is met" do
- @resource.not_if { false }
- @resource.not_if { true }
- @resource.not_if { false }
- expect(@resource.should_skip?(:purr)).to be_truthy
+ resource.not_if { false }
+ resource.not_if { true }
+ resource.not_if { false }
+ expect(resource.should_skip?(:purr)).to be_truthy
+ end
+
+ it "should return false when all of multiple only_if's are met" do
+ resource.only_if { true }
+ resource.only_if { true }
+ resource.only_if { true }
+ expect(resource.should_skip?(:purr)).to be_falsey
+ end
+
+ it "should return false when all of multiple not_if's are not met" do
+ resource.not_if { false }
+ resource.not_if { false }
+ resource.not_if { false }
+ expect(resource.should_skip?(:purr)).to be_falsey
end
it "should return true when action is :nothing" do
- expect(@resource.should_skip?(:nothing)).to be_truthy
+ expect(resource.should_skip?(:nothing)).to be_truthy
end
it "should return true when action is :nothing ignoring only_if/not_if conditionals" do
- @resource.only_if { true }
- @resource.not_if { false }
- expect(@resource.should_skip?(:nothing)).to be_truthy
+ resource.only_if { true }
+ resource.not_if { false }
+ expect(resource.should_skip?(:nothing)).to be_truthy
end
it "should print \"skipped due to action :nothing\" message for doc formatter when action is :nothing" do
fdoc = Chef::Formatters.new(:doc, STDOUT, STDERR)
- allow(@run_context).to receive(:events).and_return(fdoc)
+ allow(run_context).to receive(:events).and_return(fdoc)
expect(fdoc).to receive(:puts).with(" (skipped due to action :nothing)", anything())
- @resource.should_skip?(:nothing)
+ resource.should_skip?(:nothing)
end
end
describe "when resource action is :nothing" do
+ let(:resource1) do
+ resource1 = Chef::Resource::Cat.new("sugar", run_context)
+ resource1.action = :nothing
+ resource1
+ end
before do
- @resource1 = Chef::Resource::Cat.new("sugar", @run_context)
- @resource1.action = :nothing
-
- @node.automatic_attrs[:platform] = "fubuntu"
- @node.automatic_attrs[:platform_version] = '10.04'
+ node.automatic_attrs[:platform] = "fubuntu"
+ node.automatic_attrs[:platform_version] = "10.04"
end
it "should not run only_if/not_if conditionals (CHEF-972)" do
snitch_var1 = 0
- @resource1.only_if { snitch_var1 = 1 }
- @resource1.not_if { snitch_var1 = 2 }
- @resource1.run_action(:nothing)
+ resource1.only_if { snitch_var1 = 1 }
+ resource1.not_if { snitch_var1 = 2 }
+ resource1.run_action(:nothing)
expect(snitch_var1).to eq(0)
end
it "should run only_if/not_if conditionals when notified to run another action (CHEF-972)" do
snitch_var1 = snitch_var2 = 0
- @runner = Chef::Runner.new(@run_context)
+ runner = Chef::Runner.new(run_context)
+
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
Chef::Platform.set(
:resource => :cat,
:provider => Chef::Provider::SnakeOil
)
- @resource1.only_if { snitch_var1 = 1 }
- @resource1.not_if { snitch_var2 = 2 }
- @resource2 = Chef::Resource::Cat.new("coffee", @run_context)
- @resource2.notifies :purr, @resource1
- @resource2.action = :purr
+ resource1.only_if { snitch_var1 = 1 }
+ resource1.not_if { snitch_var2 = 2 }
+ resource2 = Chef::Resource::Cat.new("coffee", run_context)
+ resource2.notifies :purr, resource1
+ resource2.action = :purr
- @run_context.resource_collection << @resource1
- @run_context.resource_collection << @resource2
- @runner.converge
+ run_context.resource_collection << resource1
+ run_context.resource_collection << resource2
+ runner.converge
expect(snitch_var1).to eq(1)
expect(snitch_var2).to eq(2)
@@ -809,21 +890,21 @@ describe Chef::Resource do
Chef::Resource.send(:remove_const, :Klz)
end
- it 'adds mappings for a single platform' do
+ it "adds mappings for a single platform" do
expect(Chef.resource_handler_map).to receive(:set).with(
- :dinobot, Chef::Resource::Klz, { platform: ['autobots'] }
+ :dinobot, Chef::Resource::Klz, { platform: ["autobots"] }
)
- klz.provides :dinobot, platform: ['autobots']
+ klz.provides :dinobot, platform: ["autobots"]
end
- it 'adds mappings for multiple platforms' do
+ it "adds mappings for multiple platforms" do
expect(Chef.resource_handler_map).to receive(:set).with(
- :energy, Chef::Resource::Klz, { platform: ['autobots', 'decepticons']}
+ :energy, Chef::Resource::Klz, { platform: %w{autobots decepticons} }
)
- klz.provides :energy, platform: ['autobots', 'decepticons']
+ klz.provides :energy, platform: %w{autobots decepticons}
end
- it 'adds mappings for all platforms' do
+ it "adds mappings for all platforms" do
expect(Chef.resource_handler_map).to receive(:set).with(
:tape_deck, Chef::Resource::Klz, {}
)
@@ -838,11 +919,11 @@ describe Chef::Resource do
before(:each) do
Chef::Resource::Klz1 = klz1
- @node = Chef::Node.new
- @node.name("bumblebee")
- @node.automatic[:platform] = "autobots"
- @node.automatic[:platform_version] = "6.1"
- Object.const_set('Soundwave', klz1)
+ node = Chef::Node.new
+ node.name("bumblebee")
+ node.automatic[:platform] = "autobots"
+ node.automatic[:platform_version] = "6.1"
+ Object.const_set("Soundwave", klz1)
klz1.provides :soundwave
end
@@ -852,7 +933,7 @@ describe Chef::Resource do
end
it "returns a resource by short_name if nothing else matches" do
- expect(Chef::Resource.resource_for_node(:soundwave, @node)).to eql(klz1)
+ expect(Chef::Resource.resource_for_node(:soundwave, node)).to eql(klz1)
end
end
@@ -861,12 +942,11 @@ describe Chef::Resource do
before(:each) do
Chef::Resource::Klz2 = klz2
- @node = Chef::Node.new
- @node.name("bumblebee")
- @node.automatic[:platform] = "autobots"
- @node.automatic[:platform_version] = "6.1"
- klz2.provides :dinobot, :platform => ['autobots']
- Object.const_set('Grimlock', klz2)
+ node.name("bumblebee")
+ node.automatic[:platform] = "autobots"
+ node.automatic[:platform_version] = "6.1"
+ klz2.provides :dinobot, :platform => ["autobots"]
+ Object.const_set("Grimlock", klz2)
klz2.provides :grimlock
end
@@ -876,7 +956,7 @@ describe Chef::Resource do
end
it "returns a resource by short_name and node" do
- expect(Chef::Resource.resource_for_node(:dinobot, @node)).to eql(klz2)
+ expect(Chef::Resource.resource_for_node(:dinobot, node)).to eql(klz2)
end
end
@@ -887,69 +967,64 @@ describe Chef::Resource do
describe "with a string resource spec" do
it "creates a delayed notification when timing is not specified" do
- @resource.notifies(:run, "execute[foo]")
- expect(@run_context.delayed_notification_collection.size).to eq(1)
+ resource.notifies(:run, "execute[foo]")
+ expect(run_context.delayed_notification_collection.size).to eq(1)
end
it "creates a delayed notification when :delayed is not specified" do
- @resource.notifies(:run, "execute[foo]", :delayed)
- expect(@run_context.delayed_notification_collection.size).to eq(1)
+ resource.notifies(:run, "execute[foo]", :delayed)
+ expect(run_context.delayed_notification_collection.size).to eq(1)
end
it "creates an immediate notification when :immediate is specified" do
- @resource.notifies(:run, "execute[foo]", :immediate)
- expect(@run_context.immediate_notification_collection.size).to eq(1)
+ resource.notifies(:run, "execute[foo]", :immediate)
+ expect(run_context.immediate_notification_collection.size).to eq(1)
end
it "creates an immediate notification when :immediately is specified" do
- @resource.notifies(:run, "execute[foo]", :immediately)
- expect(@run_context.immediate_notification_collection.size).to eq(1)
+ resource.notifies(:run, "execute[foo]", :immediately)
+ expect(run_context.immediate_notification_collection.size).to eq(1)
end
describe "with a syntax error in the resource spec" do
it "raises an exception immmediately" do
expect do
- @resource.notifies(:run, "typo[missing-closing-bracket")
+ resource.notifies(:run, "typo[missing-closing-bracket")
end.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
end
end
end
describe "with a resource reference" do
- before do
- @notified_resource = Chef::Resource.new("punk", @run_context)
- end
+ let(:notified_resource) { Chef::Resource.new("punk", run_context) }
it "creates a delayed notification when timing is not specified" do
- @resource.notifies(:run, @notified_resource)
- expect(@run_context.delayed_notification_collection.size).to eq(1)
+ resource.notifies(:run, notified_resource)
+ expect(run_context.delayed_notification_collection.size).to eq(1)
end
it "creates a delayed notification when :delayed is not specified" do
- @resource.notifies(:run, @notified_resource, :delayed)
- expect(@run_context.delayed_notification_collection.size).to eq(1)
+ resource.notifies(:run, notified_resource, :delayed)
+ expect(run_context.delayed_notification_collection.size).to eq(1)
end
it "creates an immediate notification when :immediate is specified" do
- @resource.notifies(:run, @notified_resource, :immediate)
- expect(@run_context.immediate_notification_collection.size).to eq(1)
+ resource.notifies(:run, notified_resource, :immediate)
+ expect(run_context.immediate_notification_collection.size).to eq(1)
end
it "creates an immediate notification when :immediately is specified" do
- @resource.notifies(:run, @notified_resource, :immediately)
- expect(@run_context.immediate_notification_collection.size).to eq(1)
+ resource.notifies(:run, notified_resource, :immediately)
+ expect(run_context.immediate_notification_collection.size).to eq(1)
end
end
end
describe "resource sensitive attribute" do
-
- before(:each) do
- @resource_file = Chef::Resource::File.new("/nonexistent/CHEF-5098/file", @run_context)
- @action = :create
- end
+ let(:resource_file) { Chef::Resource::File.new("/nonexistent/CHEF-5098/file", run_context) }
+ let(:action) { :create }
def compiled_resource_data(resource, action, err)
error_inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(resource, action, err)
@@ -960,20 +1035,20 @@ describe Chef::Resource do
end
it "set to false by default" do
- expect(@resource.sensitive).to be_falsey
+ expect(resource.sensitive).to be_falsey
end
it "when set to false should show compiled resource for failed resource" do
- expect { @resource_file.run_action(@action) }.to raise_error { |err|
- expect(compiled_resource_data(@resource_file, @action, err)).to match 'path "/nonexistent/CHEF-5098/file"'
- }
+ expect { resource_file.run_action(action) }.to raise_error { |err|
+ expect(compiled_resource_data(resource_file, action, err)).to match 'path "/nonexistent/CHEF-5098/file"'
+ }
end
it "when set to true should show compiled resource for failed resource" do
- @resource_file.sensitive true
- expect { @resource_file.run_action(@action) }.to raise_error { |err|
- expect(compiled_resource_data(@resource_file, @action, err)).to eql("suppressed sensitive resource output")
- }
+ resource_file.sensitive true
+ expect { resource_file.run_action(action) }.to raise_error { |err|
+ expect(compiled_resource_data(resource_file, action, err)).to eql("suppressed sensitive resource output")
+ }
end
end
@@ -984,7 +1059,7 @@ describe Chef::Resource do
allowed_actions(%i{one two})
end
end
- let(:resource) { resource_class.new('test', nil) }
+ let(:resource) { resource_class.new("test", nil) }
subject { resource.action }
context "with a no action" do
@@ -1006,7 +1081,7 @@ describe Chef::Resource do
end
context "with a string action" do
- before { resource.action('two') }
+ before { resource.action("two") }
it { is_expected.to eq [:two] }
end
@@ -1035,7 +1110,7 @@ describe Chef::Resource do
end
describe ".default_action" do
- let(:default_action) { }
+ let(:default_action) {}
let(:resource_class) do
actions = default_action
Class.new(described_class) do
@@ -1054,7 +1129,7 @@ describe Chef::Resource do
end
context "with a string default action" do
- let(:default_action) { 'one' }
+ let(:default_action) { "one" }
it { is_expected.to eq [:one] }
end
diff --git a/spec/unit/rest/auth_credentials_spec.rb b/spec/unit/rest/auth_credentials_spec.rb
index 3465156b90..2728463c81 100644
--- a/spec/unit/rest/auth_credentials_spec.rb
+++ b/spec/unit/rest/auth_credentials_spec.rb
@@ -1,9 +1,9 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,44 +19,13 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'uri'
-require 'net/https'
-
-KEY_DOT_PEM=<<-END_RSA_KEY
------BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEA49TA0y81ps0zxkOpmf5V4/c4IeR5yVyQFpX3JpxO4TquwnRh
-8VSUhrw8kkTLmB3cS39Db+3HadvhoqCEbqPE6915kXSuk/cWIcNozujLK7tkuPEy
-YVsyTioQAddSdfe+8EhQVf3oHxaKmUd6waXrWqYCnhxgOjxocenREYNhZ/OETIei
-PbOku47vB4nJK/0GhKBytL2XnsRgfKgDxf42BqAi1jglIdeq8lAWZNF9TbNBU21A
-O1iuT7Pm6LyQujhggPznR5FJhXKRUARXBJZawxpGV4dGtdcahwXNE4601aXPra+x
-PcRd2puCNoEDBzgVuTSsLYeKBDMSfs173W1QYwIDAQABAoIBAGF05q7vqOGbMaSD
-2Q7YbuE/JTHKTBZIlBI1QC2x+0P5GDxyEFttNMOVzcs7xmNhkpRw8eX1LrInrpMk
-WsIBKAFFEfWYlf0RWtRChJjNl+szE9jQxB5FJnWtJH/FHa78tR6PsF24aQyzVcJP
-g0FGujBihwgfV0JSCNOBkz8MliQihjQA2i8PGGmo4R4RVzGfxYKTIq9vvRq/+QEa
-Q4lpVLoBqnENpnY/9PTl6JMMjW2b0spbLjOPVwDaIzXJ0dChjNXo15K5SHI5mALJ
-I5gN7ODGb8PKUf4619ez194FXq+eob5YJdilTFKensIUvt3YhP1ilGMM+Chi5Vi/
-/RCTw3ECgYEA9jTw4wv9pCswZ9wbzTaBj9yZS3YXspGg26y6Ohq3ZmvHz4jlT6uR
-xK+DDcUiK4072gci8S4Np0fIVS7q6ivqcOdzXPrTF5/j+MufS32UrBbUTPiM1yoO
-ECcy+1szl/KoLEV09bghPbvC58PFSXV71evkaTETYnA/F6RK12lEepcCgYEA7OSy
-bsMrGDVU/MKJtwqyGP9ubA53BorM4Pp9VVVSCrGGVhb9G/XNsjO5wJC8J30QAo4A
-s59ZzCpyNRy046AB8jwRQuSwEQbejSdeNgQGXhZ7aIVUtuDeFFdaIz/zjVgxsfj4
-DPOuzieMmJ2MLR4F71ocboxNoDI7xruPSE8dDhUCgYA3vx732cQxgtHwAkeNPJUz
-dLiE/JU7CnxIoSB9fYUfPLI+THnXgzp7NV5QJN2qzMzLfigsQcg3oyo6F2h7Yzwv
-GkjlualIRRzCPaCw4Btkp7qkPvbs1QngIHALt8fD1N69P3DPHkTwjG4COjKWgnJq
-qoHKS6Fe/ZlbigikI6KsuwKBgQCTlSLoyGRHr6oj0hqz01EDK9ciMJzMkZp0Kvn8
-OKxlBxYW+jlzut4MQBdgNYtS2qInxUoAnaz2+hauqhSzntK3k955GznpUatCqx0R
-b857vWviwPX2/P6+E3GPdl8IVsKXCvGWOBZWTuNTjQtwbDzsUepWoMgXnlQJSn5I
-YSlLxQKBgQD16Gw9kajpKlzsPa6XoQeGmZALT6aKWJQlrKtUQIrsIWM0Z6eFtX12
-2jjHZ0awuCQ4ldqwl8IfRogWMBkHOXjTPVK0YKWWlxMpD/5+bGPARa5fir8O1Zpo
-Y6S6MeZ69Rp89ma4ttMZ+kwi1+XyHqC/dlcVRW42Zl5Dc7BALRlJjQ==
------END RSA PRIVATE KEY-----
- END_RSA_KEY
-
+require "spec_helper"
+require "uri"
+require "net/https"
describe Chef::REST::AuthCredentials do
before do
- @key_file_fixture = CHEF_SPEC_DATA + '/ssl/private_key.pem'
+ @key_file_fixture = CHEF_SPEC_DATA + "/ssl/private_key.pem"
@key = OpenSSL::PKey::RSA.new(IO.read(@key_file_fixture).strip)
@auth_credentials = Chef::REST::AuthCredentials.new("client-name", @key)
end
@@ -67,52 +36,51 @@ describe Chef::REST::AuthCredentials do
it "loads the private key when initialized with the path to the key" do
expect(@auth_credentials.key).to respond_to(:private_encrypt)
- expect(@auth_credentials.key.to_s).to eq(KEY_DOT_PEM)
+ expect(@auth_credentials.key).to eq(@key)
end
describe "when loading the private key" do
it "strips extra whitespace before checking the key" do
- key_file_fixture = CHEF_SPEC_DATA + '/ssl/private_key_with_whitespace.pem'
- expect {Chef::REST::AuthCredentials.new("client-name", @key_file_fixture)}.not_to raise_error
+ key_file_fixture = CHEF_SPEC_DATA + "/ssl/private_key_with_whitespace.pem"
+ expect { Chef::REST::AuthCredentials.new("client-name", @key_file_fixture) }.not_to raise_error
end
end
describe "generating signature headers for a request" do
before do
@request_time = Time.at(1270920860)
- @request_params = {:http_method => :POST, :path => "/clients", :body => '{"some":"json"}', :host => "localhost"}
+ @request_params = { :http_method => :POST, :path => "/clients", :body => '{"some":"json"}', :host => "localhost" }
+ allow(Chef::Config).to(
+ receive(:[]).with(:authentication_protocol_version).and_return(protocol_version))
end
- it "generates signature headers for the request" do
- allow(Time).to receive(:now).and_return(@request_time)
- actual = @auth_credentials.signature_headers(@request_params)
- expect(actual["HOST"]).to eq("localhost")
- expect(actual["X-OPS-AUTHORIZATION-1"]).to eq("kBssX1ENEwKtNYFrHElN9vYGWS7OeowepN9EsYc9csWfh8oUovryPKDxytQ/")
- expect(actual["X-OPS-AUTHORIZATION-2"]).to eq("Wc2/nSSyxdWJjjfHzrE+YrqNQTaArOA7JkAf5p75eTUonCWcvNPjFrZVgKGS")
- expect(actual["X-OPS-AUTHORIZATION-3"]).to eq("yhzHJQh+lcVA9wwARg5Hu9q+ddS8xBOdm3Vp5atl5NGHiP0loiigMYvAvzPO")
- expect(actual["X-OPS-AUTHORIZATION-4"]).to eq("r9853eIxwYMhn5hLGhAGFQznJbE8+7F/lLU5Zmk2t2MlPY8q3o1Q61YD8QiJ")
- expect(actual["X-OPS-AUTHORIZATION-5"]).to eq("M8lIt53ckMyUmSU0DDURoiXLVkE9mag/6Yq2tPNzWq2AdFvBqku9h2w+DY5k")
- expect(actual["X-OPS-AUTHORIZATION-6"]).to eq("qA5Rnzw5rPpp3nrWA9jKkPw4Wq3+4ufO2Xs6w7GCjA==")
- expect(actual["X-OPS-CONTENT-HASH"]).to eq("1tuzs5XKztM1ANrkGNPah6rW9GY=")
- expect(actual["X-OPS-SIGN"]).to match(%r{(version=1\.0)|(algorithm=sha1;version=1.0;)})
- expect(actual["X-OPS-TIMESTAMP"]).to eq("2010-04-10T17:34:20Z")
- expect(actual["X-OPS-USERID"]).to eq("client-name")
-
- end
+ context "when configured for version 1.0 of the authn protocol" do
+ let(:protocol_version) { "1.0" }
- describe "when configured for version 1.1 of the authn protocol" do
- before do
- Chef::Config[:authentication_protocol_version] = "1.1"
+ it "generates signature headers for the request" do
+ allow(Time).to receive(:now).and_return(@request_time)
+ actual = @auth_credentials.signature_headers(@request_params)
+ expect(actual["HOST"]).to eq("localhost")
+ expect(actual["X-OPS-AUTHORIZATION-1"]).to eq("kBssX1ENEwKtNYFrHElN9vYGWS7OeowepN9EsYc9csWfh8oUovryPKDxytQ/")
+ expect(actual["X-OPS-AUTHORIZATION-2"]).to eq("Wc2/nSSyxdWJjjfHzrE+YrqNQTaArOA7JkAf5p75eTUonCWcvNPjFrZVgKGS")
+ expect(actual["X-OPS-AUTHORIZATION-3"]).to eq("yhzHJQh+lcVA9wwARg5Hu9q+ddS8xBOdm3Vp5atl5NGHiP0loiigMYvAvzPO")
+ expect(actual["X-OPS-AUTHORIZATION-4"]).to eq("r9853eIxwYMhn5hLGhAGFQznJbE8+7F/lLU5Zmk2t2MlPY8q3o1Q61YD8QiJ")
+ expect(actual["X-OPS-AUTHORIZATION-5"]).to eq("M8lIt53ckMyUmSU0DDURoiXLVkE9mag/6Yq2tPNzWq2AdFvBqku9h2w+DY5k")
+ expect(actual["X-OPS-AUTHORIZATION-6"]).to eq("qA5Rnzw5rPpp3nrWA9jKkPw4Wq3+4ufO2Xs6w7GCjA==")
+ expect(actual["X-OPS-CONTENT-HASH"]).to eq("1tuzs5XKztM1ANrkGNPah6rW9GY=")
+ expect(actual["X-OPS-SIGN"]).to match(%r{(version=1\.0)|(algorithm=sha1;version=1.0;)})
+ expect(actual["X-OPS-TIMESTAMP"]).to eq("2010-04-10T17:34:20Z")
+ expect(actual["X-OPS-USERID"]).to eq("client-name")
end
+ end
- after do
- Chef::Config[:authentication_protocol_version] = "1.0"
- end
+ context "when configured for version 1.1 of the authn protocol" do
+ let(:protocol_version) { "1.1" }
it "generates the correct signature for version 1.1" do
allow(Time).to receive(:now).and_return(@request_time)
actual = @auth_credentials.signature_headers(@request_params)
- expect(actual["HOST"]).to eq("localhost")
+ expect(actual["HOST"]).to eq("localhost")
expect(actual["X-OPS-CONTENT-HASH"]).to eq("1tuzs5XKztM1ANrkGNPah6rW9GY=")
expect(actual["X-OPS-SIGN"]).to eq("algorithm=sha1;version=1.1;")
expect(actual["X-OPS-TIMESTAMP"]).to eq("2010-04-10T17:34:20Z")
@@ -126,24 +94,25 @@ describe Chef::REST::AuthCredentials do
end
describe Chef::REST::RESTRequest do
- def new_request(method=nil)
+ let(:url) { URI.parse("http://chef.example.com:4000/?q=chef_is_awesome") }
+
+ def new_request(method = nil)
method ||= :POST
- Chef::REST::RESTRequest.new(method, @url, @req_body, @headers)
+ Chef::REST::RESTRequest.new(method, url, @req_body, @headers)
end
before do
- @auth_credentials = Chef::REST::AuthCredentials.new("client-name", CHEF_SPEC_DATA + '/ssl/private_key.pem')
- @url = URI.parse("http://chef.example.com:4000/?q=chef_is_awesome")
+ @auth_credentials = Chef::REST::AuthCredentials.new("client-name", CHEF_SPEC_DATA + "/ssl/private_key.pem")
@req_body = '{"json_data":"as_a_string"}'
- @headers = { "Content-type" =>"application/json",
- "Accept"=>"application/json",
+ @headers = { "Content-type" => "application/json",
+ "Accept" => "application/json",
"Accept-Encoding" => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
"Host" => "chef.example.com:4000" }
- @request = Chef::REST::RESTRequest.new(:POST, @url, @req_body, @headers)
+ @request = Chef::REST::RESTRequest.new(:POST, url, @req_body, @headers)
end
it "stores the url it was created with" do
- expect(@request.url).to eq(@url)
+ expect(@request.url).to eq(url)
end
it "stores the HTTP method" do
@@ -155,6 +124,10 @@ describe Chef::REST::RESTRequest do
end
describe "configuring the HTTP request" do
+ let(:url) do
+ URI.parse("http://homie:theclown@chef.example.com:4000/?q=chef_is_awesome")
+ end
+
it "configures GET requests" do
@req_body = nil
rest_req = new_request(:GET)
@@ -184,7 +157,6 @@ describe Chef::REST::RESTRequest do
end
it "configures HTTP basic auth" do
- @url = URI.parse("http://homie:theclown@chef.example.com:4000/?q=chef_is_awesome")
rest_req = new_request(:GET)
expect(rest_req.http_request.to_hash["authorization"]).to eq(["Basic aG9taWU6dGhlY2xvd24="])
end
@@ -204,23 +176,14 @@ describe Chef::REST::RESTRequest do
describe "for proxy" do
before do
- Chef::Config[:http_proxy] = "http://proxy.example.com:3128"
- Chef::Config[:https_proxy] = "http://sproxy.example.com:3129"
- Chef::Config[:http_proxy_user] = nil
- Chef::Config[:http_proxy_pass] = nil
- Chef::Config[:https_proxy_user] = nil
- Chef::Config[:https_proxy_pass] = nil
- Chef::Config[:no_proxy] = nil
- end
-
- after do
- Chef::Config[:http_proxy] = nil
- Chef::Config[:https_proxy] = nil
- Chef::Config[:http_proxy_user] = nil
- Chef::Config[:http_proxy_pass] = nil
- Chef::Config[:https_proxy_user] = nil
- Chef::Config[:https_proxy_pass] = nil
- Chef::Config[:no_proxy] = nil
+ stub_const("ENV", "http_proxy" => "http://proxy.example.com:3128",
+ "https_proxy" => "http://sproxy.example.com:3129",
+ "http_proxy_user" => nil,
+ "http_proxy_pass" => nil,
+ "https_proxy_user" => nil,
+ "https_proxy_pass" => nil,
+ "no_proxy" => nil
+ )
end
describe "with :no_proxy nil" do
@@ -233,20 +196,23 @@ describe Chef::REST::RESTRequest do
expect(http_client.proxy_pass).to be_nil
end
- it "configures the proxy address and port when using https scheme" do
- @url.scheme = "https"
- http_client = new_request.http_client
- expect(http_client.proxy?).to eq(true)
- expect(http_client.proxy_address).to eq("sproxy.example.com")
- expect(http_client.proxy_port).to eq(3129)
- expect(http_client.proxy_user).to be_nil
- expect(http_client.proxy_pass).to be_nil
+ context "when the url has an https scheme" do
+ let(:url) { URI.parse("https://chef.example.com:4000/?q=chef_is_awesome") }
+
+ it "configures the proxy address and port when using https scheme" do
+ http_client = new_request.http_client
+ expect(http_client.proxy?).to eq(true)
+ expect(http_client.proxy_address).to eq("sproxy.example.com")
+ expect(http_client.proxy_port).to eq(3129)
+ expect(http_client.proxy_user).to be_nil
+ expect(http_client.proxy_pass).to be_nil
+ end
end
end
describe "with :no_proxy set" do
before do
- Chef::Config[:no_proxy] = "10.*,*.example.com"
+ stub_const("ENV", "no_proxy" => "10.*,*.example.com")
end
it "does not configure the proxy address and port when using http scheme" do
@@ -258,26 +224,23 @@ describe Chef::REST::RESTRequest do
expect(http_client.proxy_pass).to be_nil
end
- it "does not configure the proxy address and port when using https scheme" do
- @url.scheme = "https"
- http_client = new_request.http_client
- expect(http_client.proxy?).to eq(false)
- expect(http_client.proxy_address).to be_nil
- expect(http_client.proxy_port).to be_nil
- expect(http_client.proxy_user).to be_nil
- expect(http_client.proxy_pass).to be_nil
+ context "when the url has an https scheme" do
+ let(:url) { URI.parse("https://chef.example.com:4000/?q=chef_is_awesome") }
+
+ it "does not configure the proxy address and port when using https scheme" do
+ http_client = new_request.http_client
+ expect(http_client.proxy?).to eq(false)
+ expect(http_client.proxy_address).to be_nil
+ expect(http_client.proxy_port).to be_nil
+ expect(http_client.proxy_user).to be_nil
+ expect(http_client.proxy_pass).to be_nil
+ end
end
end
describe "with :http_proxy_user and :http_proxy_pass set" do
before do
- Chef::Config[:http_proxy_user] = "homie"
- Chef::Config[:http_proxy_pass] = "theclown"
- end
-
- after do
- Chef::Config[:http_proxy_user] = nil
- Chef::Config[:http_proxy_pass] = nil
+ stub_const("ENV", "http_proxy" => "http://homie:theclown@proxy.example.com:3128")
end
it "configures the proxy user and pass when using http scheme" do
@@ -287,24 +250,23 @@ describe Chef::REST::RESTRequest do
expect(http_client.proxy_pass).to eq("theclown")
end
- it "does not configure the proxy user and pass when using https scheme" do
- @url.scheme = "https"
- http_client = new_request.http_client
- expect(http_client.proxy?).to eq(true)
- expect(http_client.proxy_user).to be_nil
- expect(http_client.proxy_pass).to be_nil
+ context "when the url has an https scheme" do
+ let(:url) { URI.parse("https://chef.example.com:4000/?q=chef_is_awesome") }
+
+ it "does not configure the proxy user and pass when using https scheme" do
+ http_client = new_request.http_client
+ expect(http_client.proxy?).to eq(false)
+ expect(http_client.proxy_user).to be_nil
+ expect(http_client.proxy_pass).to be_nil
+ end
end
end
describe "with :https_proxy_user and :https_proxy_pass set" do
before do
- Chef::Config[:https_proxy_user] = "homie"
- Chef::Config[:https_proxy_pass] = "theclown"
- end
-
- after do
- Chef::Config[:https_proxy_user] = nil
- Chef::Config[:https_proxy_pass] = nil
+ stub_const("ENV", "http_proxy" => "http://proxy.example.com:3128",
+ "https_proxy" => "https://homie:theclown@sproxy.example.com:3129"
+ )
end
it "does not configure the proxy user and pass when using http scheme" do
@@ -314,15 +276,17 @@ describe Chef::REST::RESTRequest do
expect(http_client.proxy_pass).to be_nil
end
- it "configures the proxy user and pass when using https scheme" do
- @url.scheme = "https"
- http_client = new_request.http_client
- expect(http_client.proxy?).to eq(true)
- expect(http_client.proxy_user).to eq("homie")
- expect(http_client.proxy_pass).to eq("theclown")
+ context "when the url has an https scheme" do
+ let(:url) { URI.parse("https://chef.example.com:4000/?q=chef_is_awesome") }
+
+ it "configures the proxy user and pass when using https scheme" do
+ http_client = new_request.http_client
+ expect(http_client.proxy?).to eq(true)
+ expect(http_client.proxy_user).to eq("homie")
+ expect(http_client.proxy_pass).to eq("theclown")
+ end
end
end
end
end
-
end
diff --git a/spec/unit/rest_spec.rb b/spec/unit/rest_spec.rb
index 3eee997c50..ea3bd88023 100644
--- a/spec/unit/rest_spec.rb
+++ b/spec/unit/rest_spec.rb
@@ -1,9 +1,9 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Brown (<cb@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Christopher Brown (<cb@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,12 +19,12 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'uri'
-require 'net/https'
-require 'stringio'
+require "spec_helper"
+require "uri"
+require "net/https"
+require "stringio"
-SIGNING_KEY_DOT_PEM="-----BEGIN RSA PRIVATE KEY-----
+SIGNING_KEY_DOT_PEM = "-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA49TA0y81ps0zxkOpmf5V4/c4IeR5yVyQFpX3JpxO4TquwnRh
8VSUhrw8kkTLmB3cS39Db+3HadvhoqCEbqPE6915kXSuk/cWIcNozujLK7tkuPEy
YVsyTioQAddSdfe+8EhQVf3oHxaKmUd6waXrWqYCnhxgOjxocenREYNhZ/OETIei
@@ -59,7 +59,7 @@ describe Chef::REST do
let(:log_stringio) { StringIO.new }
- let(:request_id) {"1234"}
+ let(:request_id) { "1234" }
let(:rest) do
allow(Chef::REST::CookieJar).to receive(:instance).and_return({})
@@ -69,11 +69,12 @@ describe Chef::REST do
rest
end
- let(:standard_read_headers) {{"Accept"=>"application/json", "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "X-REMOTE-REQUEST-ID"=>request_id, 'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION}}
- let(:standard_write_headers) {{"Accept"=>"application/json", "Content-Type"=>"application/json", "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "X-REMOTE-REQUEST-ID"=>request_id, 'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION}}
+ let(:standard_read_headers) { { "Accept" => "application/json", "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "X-REMOTE-REQUEST-ID" => request_id, "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION } }
+ let(:standard_write_headers) { { "Accept" => "application/json", "Content-Type" => "application/json", "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "X-REMOTE-REQUEST-ID" => request_id, "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION } }
before(:each) do
Chef::Log.init(log_stringio)
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
end
it "should have content length validation middleware after compressor middleware" do
@@ -92,7 +93,13 @@ describe Chef::REST do
Chef::REST.new(base_url, nil, nil, options)
end
- context 'when created with a chef zero URL' do
+ it "emits a deprecation warning" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = true
+ expect { Chef::REST.new(base_url) }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+ /Chef::REST is deprecated. Please use Chef::ServerAPI, or investigate Ridley or ChefAPI./
+ end
+
+ context "when created with a chef zero URL" do
let(:url) { "chefzero://localhost:1" }
@@ -113,41 +120,41 @@ describe Chef::REST do
it "makes a :GET request with the composed url object" do
expect(rest).to receive(:send_http_request).
with(:GET, monkey_uri, standard_read_headers, false).
- and_return([1,2,3])
- expect(rest).to receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
- expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
+ and_return([1, 2, 3])
+ expect(rest).to receive(:apply_response_middleware).with(1, 2, 3).and_return([1, 2, 3])
+ expect(rest).to receive("success_response?".to_sym).with(1).and_return(true)
rest.get_rest("monkey")
end
it "makes a :GET reqest for a streaming download with the composed url" do
- expect(rest).to receive(:streaming_request).with('monkey', {})
+ expect(rest).to receive(:streaming_request).with("monkey", {})
rest.get_rest("monkey", true)
end
it "makes a :DELETE request with the composed url object" do
expect(rest).to receive(:send_http_request).
with(:DELETE, monkey_uri, standard_read_headers, false).
- and_return([1,2,3])
- expect(rest).to receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
- expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
+ and_return([1, 2, 3])
+ expect(rest).to receive(:apply_response_middleware).with(1, 2, 3).and_return([1, 2, 3])
+ expect(rest).to receive("success_response?".to_sym).with(1).and_return(true)
rest.delete_rest("monkey")
end
it "makes a :POST request with the composed url object and data" do
expect(rest).to receive(:send_http_request).
with(:POST, monkey_uri, standard_write_headers, "\"data\"").
- and_return([1,2,3])
- expect(rest).to receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
- expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
+ and_return([1, 2, 3])
+ expect(rest).to receive(:apply_response_middleware).with(1, 2, 3).and_return([1, 2, 3])
+ expect(rest).to receive("success_response?".to_sym).with(1).and_return(true)
rest.post_rest("monkey", "data")
end
it "makes a :PUT request with the composed url object and data" do
expect(rest).to receive(:send_http_request).
with(:PUT, monkey_uri, standard_write_headers, "\"data\"").
- and_return([1,2,3])
- expect(rest).to receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
- expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
+ and_return([1, 2, 3])
+ expect(rest).to receive(:apply_response_middleware).with(1, 2, 3).and_return([1, 2, 3])
+ expect(rest).to receive("success_response?".to_sym).with(1).and_return(true)
rest.put_rest("monkey", "data")
end
end
@@ -162,38 +169,37 @@ describe Chef::REST do
Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem"
end
- it 'responds to raw_http_request as a public method' do
+ it "responds to raw_http_request as a public method" do
expect(rest.public_methods.map(&:to_s)).to include("raw_http_request")
end
- it 'calls the authn middleware' do
+ it "calls the authn middleware" do
data = "\"secure data\""
- auth_headers = standard_write_headers.merge({"auth_done"=>"yep"})
+ auth_headers = standard_write_headers.merge({ "auth_done" => "yep" })
expect(rest.authenticator).to receive(:handle_request).
with(:POST, monkey_uri, standard_write_headers, data).
and_return([:POST, monkey_uri, auth_headers, data])
expect(rest).to receive(:send_http_request).
with(:POST, monkey_uri, auth_headers, data).
- and_return([1,2,3])
- expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
+ and_return([1, 2, 3])
+ expect(rest).to receive("success_response?".to_sym).with(1).and_return(true)
rest.raw_http_request(:POST, monkey_uri, standard_write_headers, data)
end
- it 'sets correct authn headers' do
+ it "sets correct authn headers" do
data = "\"secure data\""
method, uri, auth_headers, d = rest.authenticator.handle_request(:POST, monkey_uri, standard_write_headers, data)
expect(rest).to receive(:send_http_request).
with(:POST, monkey_uri, auth_headers, data).
- and_return([1,2,3])
- expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
+ and_return([1, 2, 3])
+ expect(rest).to receive("success_response?".to_sym).with(1).and_return(true)
rest.raw_http_request(:POST, monkey_uri, standard_write_headers, data)
end
end
-
describe "when configured to authenticate to the Chef server" do
let(:base_url) { URI.parse("http://chef.example.com:4000") }
@@ -227,12 +233,12 @@ describe Chef::REST do
end
it "raises PrivateKeyMissing when the key file doesn't exist" do
- expect {Chef::REST.new(base_url, "client-name", "/dev/null/nothing_here")}.to raise_error(Chef::Exceptions::PrivateKeyMissing)
+ expect { Chef::REST.new(base_url, "client-name", "/dev/null/nothing_here") }.to raise_error(Chef::Exceptions::PrivateKeyMissing)
end
it "raises InvalidPrivateKey when the key file doesnt' look like a key" do
invalid_key_file = CHEF_SPEC_DATA + "/bad-config.rb"
- expect {Chef::REST.new(base_url, "client-name", invalid_key_file)}.to raise_error(Chef::Exceptions::InvalidPrivateKey)
+ expect { Chef::REST.new(base_url, "client-name", invalid_key_file) }.to raise_error(Chef::Exceptions::InvalidPrivateKey)
end
it "can take private key as a sting :raw_key in options during initializaton" do
@@ -240,7 +246,7 @@ describe Chef::REST do
end
it "raises InvalidPrivateKey when the key passed as string :raw_key in options doesnt' look like a key" do
- expect {Chef::REST.new(base_url, "client-name", nil, :raw_key => "bad key string")}.to raise_error(Chef::Exceptions::InvalidPrivateKey)
+ expect { Chef::REST.new(base_url, "client-name", nil, :raw_key => "bad key string") }.to raise_error(Chef::Exceptions::InvalidPrivateKey)
end
end
@@ -285,14 +291,14 @@ describe Chef::REST do
describe "as JSON API requests" do
let(:request_mock) { {} }
- let(:base_headers) do #FIXME: huh?
+ let(:base_headers) do #FIXME: huh?
{
- 'Accept' => 'application/json',
- 'X-Chef-Version' => Chef::VERSION,
- 'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
- 'Host' => host_header,
- 'X-REMOTE-REQUEST-ID' => request_id,
- 'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION
+ "Accept" => "application/json",
+ "X-Chef-Version" => Chef::VERSION,
+ "Accept-Encoding" => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
+ "Host" => host_header,
+ "X-REMOTE-REQUEST-ID" => request_id,
+ "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION,
}
end
@@ -314,14 +320,14 @@ describe Chef::REST do
# XXX: must reset to default b/c knife changes the UA
Chef::REST::RESTRequest.user_agent = Chef::REST::RESTRequest::DEFAULT_UA
rest.request(:GET, url, {})
- expect(request_mock['User-Agent']).to match(/^Chef Client\/#{Chef::VERSION}/)
+ expect(request_mock["User-Agent"]).to match(/^Chef Client\/#{Chef::VERSION}/)
end
# CHEF-3140
context "when configured to disable compression" do
let(:rest) do
allow(Net::HTTP).to receive(:new).and_return(http_client)
- Chef::REST.new(base_url, nil, nil, :disable_gzip => true)
+ Chef::REST.new(base_url, nil, nil, :disable_gzip => true)
end
it "does not accept encoding gzip" do
@@ -340,8 +346,8 @@ describe Chef::REST do
context "when configured with custom http headers" do
let(:custom_headers) do
{
- 'X-Custom-ChefSecret' => 'sharpknives',
- 'X-Custom-RequestPriority' => 'extremely low'
+ "X-Custom-ChefSecret" => "sharpknives",
+ "X-Custom-RequestPriority" => "extremely low",
}
end
@@ -371,7 +377,7 @@ describe Chef::REST do
end
it "should set the cookie for this request if one exists for the given host:port" do
- expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", base_headers.merge('Cookie' => "cookie monster")).and_return(request_mock)
+ expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", base_headers.merge("Cookie" => "cookie monster")).and_return(request_mock)
rest.request(:GET, url, {})
end
end
@@ -383,18 +389,18 @@ describe Chef::REST do
it "should build a new HTTP POST request" do
request = Net::HTTP::Post.new(url.path)
- expected_headers = base_headers.merge("Content-Type" => 'application/json', 'Content-Length' => '13')
+ expected_headers = base_headers.merge("Content-Type" => "application/json", "Content-Length" => "13")
expect(Net::HTTP::Post).to receive(:new).with("/?foo=bar", expected_headers).and_return(request)
- rest.request(:POST, url, {}, {:one=>:two})
+ rest.request(:POST, url, {}, { :one => :two })
expect(request.body).to eq('{"one":"two"}')
end
it "should build a new HTTP PUT request" do
request = Net::HTTP::Put.new(url.path)
- expected_headers = base_headers.merge("Content-Type" => 'application/json', 'Content-Length' => '13')
- expect(Net::HTTP::Put).to receive(:new).with("/?foo=bar",expected_headers).and_return(request)
- rest.request(:PUT, url, {}, {:one=>:two})
+ expected_headers = base_headers.merge("Content-Type" => "application/json", "Content-Length" => "13")
+ expect(Net::HTTP::Put).to receive(:new).with("/?foo=bar", expected_headers).and_return(request)
+ rest.request(:PUT, url, {}, { :one => :two })
expect(request.body).to eq('{"one":"two"}')
end
@@ -419,18 +425,18 @@ describe Chef::REST do
context "when JSON is returned" do
let(:body) { '{"ohai2u":"json_api"}' }
it "should inflate the body as to an object" do
- http_response.add_field('content-type', "application/json")
- expect(rest.request(:GET, url, {})).to eq({"ohai2u"=>"json_api"})
+ http_response.add_field("content-type", "application/json")
+ expect(rest.request(:GET, url, {})).to eq({ "ohai2u" => "json_api" })
end
it "should fail if the response is truncated" do
- http_response.add_field('content-type', "application/json")
+ http_response.add_field("content-type", "application/json")
http_response["Content-Length"] = (body.bytesize + 99).to_s
expect { rest.request(:GET, url, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
end
end
- %w[ HTTPFound HTTPMovedPermanently HTTPSeeOther HTTPUseProxy HTTPTemporaryRedirect HTTPMultipleChoice ].each do |resp_name|
+ %w{ HTTPFound HTTPMovedPermanently HTTPSeeOther HTTPUseProxy HTTPTemporaryRedirect HTTPMultipleChoice }.each do |resp_name|
describe "when encountering a #{resp_name} redirect" do
let(:http_response) do
resp_cls = Net.const_get(resp_name)
@@ -485,8 +491,8 @@ describe Chef::REST do
it "should show the JSON error message" do
allow(rest).to receive(:sleep)
- expect {rest.request(:GET, url)}.to raise_error(Net::HTTPFatalError)
- expect(log_stringio.string).to match(Regexp.escape('INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four'))
+ expect { rest.request(:GET, url) }.to raise_error(Net::HTTPFatalError)
+ expect(log_stringio.string).to match(Regexp.escape("INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four"))
end
end
@@ -510,13 +516,13 @@ describe Chef::REST do
end
it "decompresses the JSON error message" do
- expect {rest.request(:GET, url)}.to raise_error(Net::HTTPFatalError)
- expect(log_stringio.string).to match(Regexp.escape('INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four'))
+ expect { rest.request(:GET, url) }.to raise_error(Net::HTTPFatalError)
+ expect(log_stringio.string).to match(Regexp.escape("INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four"))
end
it "fails when the compressed body is truncated" do
http_response["Content-Length"] = (body.bytesize + 99).to_s
- expect {rest.request(:GET, url)}.to raise_error(Chef::Exceptions::ContentLengthMismatch)
+ expect { rest.request(:GET, url) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
end
end
@@ -530,7 +536,7 @@ describe Chef::REST do
it "retries then throws an exception" do
allow(rest).to receive(:sleep)
- expect {rest.request(:GET, url)}.to raise_error(Net::HTTPFatalError)
+ expect { rest.request(:GET, url) }.to raise_error(Net::HTTPFatalError)
count = Chef::Config[:http_retry_count]
expect(log_stringio.string).to match(Regexp.escape("ERROR: Server returned error 500 for #{url}, retrying #{count}/#{count}"))
end
@@ -544,7 +550,7 @@ describe Chef::REST do
let(:request_mock) { {} }
let(:http_response) do
- http_response = Net::HTTPSuccess.new("1.1",'200', "it-works")
+ http_response = Net::HTTPSuccess.new("1.1", "200", "it-works")
allow(http_response).to receive(:read_body)
expect(http_response).not_to receive(:body)
@@ -570,24 +576,24 @@ describe Chef::REST do
end
it " build a new HTTP GET request without the application/json accept header" do
- expected_headers = {'Accept' => "*/*",
- 'X-Chef-Version' => Chef::VERSION,
- 'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
- 'Host' => host_header,
- 'X-REMOTE-REQUEST-ID'=> request_id,
- 'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION
+ expected_headers = { "Accept" => "*/*",
+ "X-Chef-Version" => Chef::VERSION,
+ "Accept-Encoding" => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
+ "Host" => host_header,
+ "X-REMOTE-REQUEST-ID" => request_id,
+ "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION,
}
expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", expected_headers).and_return(request_mock)
rest.streaming_request(url, {})
end
it "build a new HTTP GET request with the X-Remote-Request-Id header" do
- expected_headers = {'Accept' => "*/*",
- 'X-Chef-Version' => Chef::VERSION,
- 'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
- 'Host' => host_header,
- 'X-REMOTE-REQUEST-ID'=> request_id,
- 'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION
+ expected_headers = { "Accept" => "*/*",
+ "X-Chef-Version" => Chef::VERSION,
+ "Accept-Encoding" => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
+ "Host" => host_header,
+ "X-REMOTE-REQUEST-ID" => request_id,
+ "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION,
}
expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", expected_headers).and_return(request_mock)
rest.streaming_request(url, {})
@@ -622,13 +628,13 @@ describe Chef::REST do
end
it "does not raise a divide by zero exception if the content's actual size is 0" do
- http_response['Content-Length'] = "5"
- allow(http_response).to receive(:read_body).and_yield('')
+ http_response["Content-Length"] = "5"
+ allow(http_response).to receive(:read_body).and_yield("")
expect { rest.streaming_request(url, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
end
it "does not raise a divide by zero exception when the Content-Length is 0" do
- http_response['Content-Length'] = "0"
+ http_response["Content-Length"] = "0"
allow(http_response).to receive(:read_body).and_yield("ninja")
expect { rest.streaming_request(url, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
end
@@ -654,7 +660,7 @@ describe Chef::REST do
path = tempfile.path
expect(path).not_to be_nil
allow(tempfile).to receive(:write).and_raise(IOError)
- rest.fetch("cookbooks/a_cookbook") {|tmpfile| "shouldn't get here"}
+ rest.fetch("cookbooks/a_cookbook") { |tmpfile| "shouldn't get here" }
expect(File.exists?(path)).to be_falsey
end
@@ -669,12 +675,12 @@ describe Chef::REST do
expect(http_client).to receive(:request).and_yield(redirect).and_return(redirect)
expect(http_client).to receive(:request).and_yield(http_response).and_return(http_response)
- rest.fetch("cookbooks/a_cookbook") {|tmpfile| "shouldn't get here"}
+ rest.fetch("cookbooks/a_cookbook") { |tmpfile| "shouldn't get here" }
end
it "passes the original block to the redirected request" do
http_redirect = Net::HTTPFound.new("1.1", "302", "bob is taking care of that one for me today")
- http_redirect.add_field("location","/that-thing-is-here-now")
+ http_redirect.add_field("location", "/that-thing-is-here-now")
allow(http_redirect).to receive(:read_body)
block_called = false
@@ -698,8 +704,8 @@ describe Chef::REST do
end
it "raises a RedirectLimitExceeded when redirected more than 10 times" do
- redirected = lambda {rest.follow_redirect { redirected.call }}
- expect {redirected.call}.to raise_error(Chef::Exceptions::RedirectLimitExceeded)
+ redirected = lambda { rest.follow_redirect { redirected.call } }
+ expect { redirected.call }.to raise_error(Chef::Exceptions::RedirectLimitExceeded)
end
it "does not count redirects from previous calls against the redirect limit" do
@@ -710,9 +716,9 @@ describe Chef::REST do
redirected.call unless total_redirects >= 9
end
end
- expect {redirected.call}.not_to raise_error
+ expect { redirected.call }.not_to raise_error
total_redirects = 0
- expect {redirected.call}.not_to raise_error
+ expect { redirected.call }.not_to raise_error
end
it "does not sign the redirected request when sign_on_redirect is false" do
@@ -736,11 +742,11 @@ describe Chef::REST do
redirected.call unless total_redirects >= 9
end
end
- expect {redirected.call}.not_to raise_error
+ expect { redirected.call }.not_to raise_error
total_redirects = 0
rest.redirect_limit = 3
- expect {redirected.call}.to raise_error(Chef::Exceptions::RedirectLimitExceeded)
+ expect { redirected.call }.to raise_error(Chef::Exceptions::RedirectLimitExceeded)
end
end
diff --git a/spec/unit/role_spec.rb b/spec/unit/role_spec.rb
index ecc7945a08..1bbbc4c7b0 100644
--- a/spec/unit/role_spec.rb
+++ b/spec/unit/role_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/role'
+require "spec_helper"
+require "chef/role"
describe Chef::Role do
before(:each) do
@@ -44,7 +44,6 @@ describe Chef::Role do
@role.run_list(%w{ nginx recipe[ree] role[base]})
end
-
it "returns the run list" do
expect(@role.run_list).to eq(%w{ nginx recipe[ree] role[base]})
end
@@ -79,20 +78,19 @@ describe Chef::Role do
it "env_run_lists can only be set with _default run list in it" do
long_exception_name = Chef::Exceptions::InvalidEnvironmentRunListSpecification
- expect {@role.env_run_lists({})}.to raise_error(long_exception_name)
+ expect { @role.env_run_lists({}) }.to raise_error(long_exception_name)
end
end
-
describe "using the old #recipes API" do
it "should let you set the recipe array" do
- expect(@role.recipes([ "one", "two" ])).to eq([ "one", "two" ])
+ expect(@role.recipes(%w{one two})).to eq(%w{one two})
end
it "should let you return the recipe array" do
- @role.recipes([ "one", "two" ])
- expect(@role.recipes).to eq([ "one", "two" ])
+ @role.recipes(%w{one two})
+ expect(@role.recipes).to eq(%w{one two})
end
it "should not list roles in the recipe array" do
@@ -104,16 +102,14 @@ describe Chef::Role do
end
-
-
describe "default_attributes" do
it "should let you set the default attributes hash explicitly" do
- expect(@role.default_attributes({ :one => 'two' })).to eq({ :one => 'two' })
+ expect(@role.default_attributes({ :one => "two" })).to eq({ :one => "two" })
end
it "should let you return the default attributes hash" do
- @role.default_attributes({ :one => 'two' })
- expect(@role.default_attributes).to eq({ :one => 'two' })
+ @role.default_attributes({ :one => "two" })
+ expect(@role.default_attributes).to eq({ :one => "two" })
end
it "should throw an ArgumentError if we aren't a kind of hash" do
@@ -123,12 +119,12 @@ describe Chef::Role do
describe "override_attributes" do
it "should let you set the override attributes hash explicitly" do
- expect(@role.override_attributes({ :one => 'two' })).to eq({ :one => 'two' })
+ expect(@role.override_attributes({ :one => "two" })).to eq({ :one => "two" })
end
it "should let you return the override attributes hash" do
- @role.override_attributes({ :one => 'two' })
- expect(@role.override_attributes).to eq({ :one => 'two' })
+ @role.override_attributes({ :one => "two" })
+ expect(@role.override_attributes).to eq({ :one => "two" })
end
it "should throw an ArgumentError if we aren't a kind of hash" do
@@ -138,18 +134,18 @@ describe Chef::Role do
describe "update_from!" do
before(:each) do
- @role.name('mars_volta')
- @role.description('Great band!')
- @role.run_list('one', 'two', 'role[a]')
- @role.default_attributes({ :el_groupo => 'nuevo' })
- @role.override_attributes({ :deloused => 'in the comatorium' })
+ @role.name("mars_volta")
+ @role.description("Great band!")
+ @role.run_list("one", "two", "role[a]")
+ @role.default_attributes({ :el_groupo => "nuevo" })
+ @role.override_attributes({ :deloused => "in the comatorium" })
@example = Chef::Role.new
- @example.name('newname')
- @example.description('Really Great band!')
- @example.run_list('alpha', 'bravo', 'role[alpha]')
- @example.default_attributes({ :el_groupo => 'nuevo dos' })
- @example.override_attributes({ :deloused => 'in the comatorium XOXO' })
+ @example.name("newname")
+ @example.description("Really Great band!")
+ @example.run_list("alpha", "bravo", "role[alpha]")
+ @example.default_attributes({ :el_groupo => "nuevo dos" })
+ @example.override_attributes({ :deloused => "in the comatorium XOXO" })
end
it "should update all fields except for name" do
@@ -164,11 +160,11 @@ describe Chef::Role do
describe "when serialized as JSON", :json => true do
before(:each) do
- @role.name('mars_volta')
- @role.description('Great band!')
- @role.run_list('one', 'two', 'role[a]')
- @role.default_attributes({ :el_groupo => 'nuevo' })
- @role.override_attributes({ :deloused => 'in the comatorium' })
+ @role.name("mars_volta")
+ @role.description("Great band!")
+ @role.run_list("one", "two", "role[a]")
+ @role.default_attributes({ :el_groupo => "nuevo" })
+ @role.override_attributes({ :deloused => "in the comatorium" })
@serialized_role = Chef::JSONCompat.to_json(@role)
end
@@ -200,14 +196,14 @@ describe Chef::Role do
describe "and it has per-environment run lists" do
before do
- @role.env_run_lists("_default" => ['one', 'two', 'role[a]'], "production" => ['role[monitoring]', 'role[auditing]', 'role[apache]'], "dev" => ["role[nginx]"])
- @serialized_role = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@role), :create_additions => false)
+ @role.env_run_lists("_default" => ["one", "two", "role[a]"], "production" => ["role[monitoring]", "role[auditing]", "role[apache]"], "dev" => ["role[nginx]"])
+ @serialized_role = Chef::JSONCompat.parse(Chef::JSONCompat.to_json(@role), :create_additions => false)
end
it "includes the per-environment run lists" do
#Activesupport messes with Chef json formatting
#This test should pass with and without activesupport
- expect(@serialized_role["env_run_lists"]["production"]).to eq(['role[monitoring]', 'role[auditing]', 'role[apache]'])
+ expect(@serialized_role["env_run_lists"]["production"]).to eq(["role[monitoring]", "role[auditing]", "role[apache]"])
expect(@serialized_role["env_run_lists"]["dev"]).to eq(["role[nginx]"])
end
@@ -224,12 +220,12 @@ describe Chef::Role do
describe "when created from JSON", :json => true do
before(:each) do
- @role.name('mars_volta')
- @role.description('Great band!')
- @role.run_list('one', 'two', 'role[a]')
- @role.default_attributes({ 'el_groupo' => 'nuevo' })
- @role.override_attributes({ 'deloused' => 'in the comatorium' })
- @deserial = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@role))
+ @role.name("mars_volta")
+ @role.description("Great band!")
+ @role.run_list("one", "two", "role[a]")
+ @role.default_attributes({ "el_groupo" => "nuevo" })
+ @role.override_attributes({ "deloused" => "in the comatorium" })
+ @deserial = Chef::Role.from_hash(Chef::JSONCompat.parse(Chef::JSONCompat.to_json(@role)))
end
it "should deserialize to a Chef::Role object" do
@@ -249,20 +245,20 @@ describe Chef::Role do
end
end
- ROLE_DSL=<<-EOR
+ ROLE_DSL = <<-EOR
name "ceiling_cat"
description "like Aliens, but furry"
EOR
describe "when loading from disk" do
before do
- default_cache_path = windows? ? 'C:\chef' : '/var/chef'
+ default_cache_path = windows? ? 'C:\chef' : "/var/chef"
allow(Chef::Config).to receive(:cache_path).and_return(default_cache_path)
end
it "should return a Chef::Role object from JSON" do
expect(Dir).to receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes", "#{Chef::Config[:role_path]}/memes/lolcat.json"])
- file_path = File.join(Chef::Config[:role_path], 'memes/lolcat.json')
+ file_path = File.join(Chef::Config[:role_path], "memes/lolcat.json")
expect(File).to receive(:exists?).with(file_path).exactly(1).times.and_return(true)
expect(IO).to receive(:read).with(file_path).and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }')
expect(@role).to be_a_kind_of(Chef::Role)
@@ -271,7 +267,7 @@ EOR
it "should return a Chef::Role object from a Ruby DSL" do
expect(Dir).to receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes", "#{Chef::Config[:role_path]}/memes/lolcat.rb"])
- rb_path = File.join(Chef::Config[:role_path], 'memes/lolcat.rb')
+ rb_path = File.join(Chef::Config[:role_path], "memes/lolcat.rb")
expect(File).to receive(:exists?).with(rb_path).exactly(2).times.and_return(true)
expect(File).to receive(:readable?).with(rb_path).exactly(1).times.and_return(true)
expect(IO).to receive(:read).with(rb_path).and_return(ROLE_DSL)
@@ -281,8 +277,8 @@ EOR
it "should prefer a Chef::Role Object from JSON over one from a Ruby DSL" do
expect(Dir).to receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes", "#{Chef::Config[:role_path]}/memes/lolcat.json", "#{Chef::Config[:role_path]}/memes/lolcat.rb"])
- js_path = File.join(Chef::Config[:role_path], 'memes/lolcat.json')
- rb_path = File.join(Chef::Config[:role_path], 'memes/lolcat.rb')
+ js_path = File.join(Chef::Config[:role_path], "memes/lolcat.json")
+ rb_path = File.join(Chef::Config[:role_path], "memes/lolcat.rb")
expect(File).to receive(:exists?).with(js_path).exactly(1).times.and_return(true)
expect(File).not_to receive(:exists?).with(rb_path)
expect(IO).to receive(:read).with(js_path).and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }')
@@ -293,69 +289,69 @@ EOR
it "should raise an exception if the file does not exist" do
expect(Dir).to receive(:glob).and_return(["#{Chef::Config[:role_path]}/meme.rb"])
expect(File).not_to receive(:exists?)
- expect {@role.class.from_disk("lolcat")}.to raise_error(Chef::Exceptions::RoleNotFound)
+ expect { @role.class.from_disk("lolcat") }.to raise_error(Chef::Exceptions::RoleNotFound)
end
it "should raise an exception if two files exist with the same name" do
expect(Dir).to receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes/lolcat.rb", "#{Chef::Config[:role_path]}/lolcat.rb"])
expect(File).not_to receive(:exists?)
- expect {@role.class.from_disk("lolcat")}.to raise_error(Chef::Exceptions::DuplicateRole)
+ expect { @role.class.from_disk("lolcat") }.to raise_error(Chef::Exceptions::DuplicateRole)
end
it "should not raise an exception if two files exist with a similar name" do
expect(Dir).to receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes/lolcat.rb", "#{Chef::Config[:role_path]}/super_lolcat.rb"])
expect(File).to receive(:exists?).with("#{Chef::Config[:role_path]}/memes/lolcat.rb").and_return(true)
allow_any_instance_of(Chef::Role).to receive(:from_file).with("#{Chef::Config[:role_path]}/memes/lolcat.rb")
- expect{ @role.class.from_disk("lolcat") }.not_to raise_error
+ expect { @role.class.from_disk("lolcat") }.not_to raise_error
end
end
describe "when loading from disk and role_path is an array" do
before(:each) do
- Chef::Config[:role_path] = ['/path1', '/path/path2']
+ Chef::Config[:role_path] = ["/path1", "/path/path2"]
end
it "should return a Chef::Role object from JSON" do
- expect(Dir).to receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return(['/path1/lolcat.json'])
- expect(File).to receive(:exists?).with('/path1/lolcat.json').exactly(1).times.and_return(true)
- expect(IO).to receive(:read).with('/path1/lolcat.json').and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }')
+ expect(Dir).to receive(:glob).with(File.join("/path1", "**", "**")).exactly(1).times.and_return(["/path1/lolcat.json"])
+ expect(File).to receive(:exists?).with("/path1/lolcat.json").exactly(1).times.and_return(true)
+ expect(IO).to receive(:read).with("/path1/lolcat.json").and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }')
expect(@role).to be_a_kind_of(Chef::Role)
@role.class.from_disk("lolcat")
end
it "should return a Chef::Role object from JSON when role is in the second path" do
- expect(Dir).to receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return([])
- expect(Dir).to receive(:glob).with(File.join('/path/path2', '**', '**')).exactly(1).times.and_return(['/path/path2/lolcat.json'])
- expect(File).to receive(:exists?).with('/path/path2/lolcat.json').exactly(1).times.and_return(true)
- expect(IO).to receive(:read).with('/path/path2/lolcat.json').and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }')
+ expect(Dir).to receive(:glob).with(File.join("/path1", "**", "**")).exactly(1).times.and_return([])
+ expect(Dir).to receive(:glob).with(File.join("/path/path2", "**", "**")).exactly(1).times.and_return(["/path/path2/lolcat.json"])
+ expect(File).to receive(:exists?).with("/path/path2/lolcat.json").exactly(1).times.and_return(true)
+ expect(IO).to receive(:read).with("/path/path2/lolcat.json").and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }')
expect(@role).to be_a_kind_of(Chef::Role)
@role.class.from_disk("lolcat")
end
it "should return a Chef::Role object from a Ruby DSL" do
- expect(Dir).to receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return(['/path1/lolcat.rb'])
- expect(File).to receive(:exists?).with('/path1/lolcat.rb').exactly(2).times.and_return(true)
- expect(File).to receive(:readable?).with('/path1/lolcat.rb').and_return(true)
- expect(IO).to receive(:read).with('/path1/lolcat.rb').exactly(1).times.and_return(ROLE_DSL)
+ expect(Dir).to receive(:glob).with(File.join("/path1", "**", "**")).exactly(1).times.and_return(["/path1/lolcat.rb"])
+ expect(File).to receive(:exists?).with("/path1/lolcat.rb").exactly(2).times.and_return(true)
+ expect(File).to receive(:readable?).with("/path1/lolcat.rb").and_return(true)
+ expect(IO).to receive(:read).with("/path1/lolcat.rb").exactly(1).times.and_return(ROLE_DSL)
expect(@role).to be_a_kind_of(Chef::Role)
@role.class.from_disk("lolcat")
end
it "should return a Chef::Role object from a Ruby DSL when role is in the second path" do
- expect(Dir).to receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return([])
- expect(Dir).to receive(:glob).with(File.join('/path/path2', '**', '**')).exactly(1).times.and_return(['/path/path2/lolcat.rb'])
- expect(File).to receive(:exists?).with('/path/path2/lolcat.rb').exactly(2).times.and_return(true)
- expect(File).to receive(:readable?).with('/path/path2/lolcat.rb').and_return(true)
- expect(IO).to receive(:read).with('/path/path2/lolcat.rb').exactly(1).times.and_return(ROLE_DSL)
+ expect(Dir).to receive(:glob).with(File.join("/path1", "**", "**")).exactly(1).times.and_return([])
+ expect(Dir).to receive(:glob).with(File.join("/path/path2", "**", "**")).exactly(1).times.and_return(["/path/path2/lolcat.rb"])
+ expect(File).to receive(:exists?).with("/path/path2/lolcat.rb").exactly(2).times.and_return(true)
+ expect(File).to receive(:readable?).with("/path/path2/lolcat.rb").and_return(true)
+ expect(IO).to receive(:read).with("/path/path2/lolcat.rb").exactly(1).times.and_return(ROLE_DSL)
expect(@role).to be_a_kind_of(Chef::Role)
@role.class.from_disk("lolcat")
end
it "should raise an exception if the file does not exist" do
- expect(Dir).to receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return([])
- expect(Dir).to receive(:glob).with(File.join('/path/path2', '**', '**')).exactly(1).times.and_return([])
- expect {@role.class.from_disk("lolcat")}.to raise_error(Chef::Exceptions::RoleNotFound)
+ expect(Dir).to receive(:glob).with(File.join("/path1", "**", "**")).exactly(1).times.and_return([])
+ expect(Dir).to receive(:glob).with(File.join("/path/path2", "**", "**")).exactly(1).times.and_return([])
+ expect { @role.class.from_disk("lolcat") }.to raise_error(Chef::Exceptions::RoleNotFound)
end
end
diff --git a/spec/unit/run_context/child_run_context_spec.rb b/spec/unit/run_context/child_run_context_spec.rb
index 63586e459c..47a6c84f7a 100644
--- a/spec/unit/run_context/child_run_context_spec.rb
+++ b/spec/unit/run_context/child_run_context_spec.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,22 +18,22 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/lib/library_load_order'
+require "spec_helper"
+require "support/lib/library_load_order"
describe Chef::RunContext::ChildRunContext do
context "with a run context with stuff in it" do
let(:chef_repo_path) { File.expand_path(File.join(CHEF_SPEC_DATA, "run_context", "cookbooks")) }
- let(:cookbook_collection) {
+ let(:cookbook_collection) do
cl = Chef::CookbookLoader.new(chef_repo_path)
cl.load_cookbooks
Chef::CookbookCollection.new(cl)
- }
- let(:node) {
+ end
+ let(:node) do
node = Chef::Node.new
node.run_list << "test" << "test::one" << "test::two"
node
- }
+ end
let(:events) { Chef::EventDispatch::Dispatcher.new }
let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) }
@@ -46,14 +46,14 @@ describe Chef::RunContext::ChildRunContext do
it "audits is not the same as the parent" do
expect(child.audits.object_id).not_to eq run_context.audits.object_id
- child.audits['hi'] = 'lo'
- expect(child.audits['hi']).to eq('lo')
- expect(run_context.audits['hi']).not_to eq('lo')
+ child.audits["hi"] = "lo"
+ expect(child.audits["hi"]).to eq("lo")
+ expect(run_context.audits["hi"]).not_to eq("lo")
end
it "resource_collection is not the same as the parent" do
expect(child.resource_collection.object_id).not_to eq run_context.resource_collection.object_id
- f = Chef::Resource::File.new('hi', child)
+ f = Chef::Resource::File.new("hi", child)
child.resource_collection.insert(f)
expect(child.resource_collection).to include f
expect(run_context.resource_collection).not_to include f
@@ -61,17 +61,17 @@ describe Chef::RunContext::ChildRunContext do
it "immediate_notification_collection is not the same as the parent" do
expect(child.immediate_notification_collection.object_id).not_to eq run_context.immediate_notification_collection.object_id
- src = Chef::Resource::File.new('hi', child)
- dest = Chef::Resource::File.new('argh', child)
+ src = Chef::Resource::File.new("hi", child)
+ dest = Chef::Resource::File.new("argh", child)
notification = Chef::Resource::Notification.new(dest, :create, src)
child.notifies_immediately(notification)
- expect(child.immediate_notification_collection['file[hi]']).to eq([notification])
- expect(run_context.immediate_notification_collection['file[hi]']).not_to eq([notification])
+ expect(child.immediate_notification_collection["file[hi]"]).to eq([notification])
+ expect(run_context.immediate_notification_collection["file[hi]"]).not_to eq([notification])
end
it "immediate_notifications is not the same as the parent" do
- src = Chef::Resource::File.new('hi', child)
- dest = Chef::Resource::File.new('argh', child)
+ src = Chef::Resource::File.new("hi", child)
+ dest = Chef::Resource::File.new("argh", child)
notification = Chef::Resource::Notification.new(dest, :create, src)
child.notifies_immediately(notification)
expect(child.immediate_notifications(src)).to eq([notification])
@@ -80,17 +80,17 @@ describe Chef::RunContext::ChildRunContext do
it "delayed_notification_collection is not the same as the parent" do
expect(child.delayed_notification_collection.object_id).not_to eq run_context.delayed_notification_collection.object_id
- src = Chef::Resource::File.new('hi', child)
- dest = Chef::Resource::File.new('argh', child)
+ src = Chef::Resource::File.new("hi", child)
+ dest = Chef::Resource::File.new("argh", child)
notification = Chef::Resource::Notification.new(dest, :create, src)
child.notifies_delayed(notification)
- expect(child.delayed_notification_collection['file[hi]']).to eq([notification])
- expect(run_context.delayed_notification_collection['file[hi]']).not_to eq([notification])
+ expect(child.delayed_notification_collection["file[hi]"]).to eq([notification])
+ expect(run_context.delayed_notification_collection["file[hi]"]).not_to eq([notification])
end
it "delayed_notifications is not the same as the parent" do
- src = Chef::Resource::File.new('hi', child)
- dest = Chef::Resource::File.new('argh', child)
+ src = Chef::Resource::File.new("hi", child)
+ dest = Chef::Resource::File.new("argh", child)
notification = Chef::Resource::Notification.new(dest, :create, src)
child.notifies_delayed(notification)
expect(child.delayed_notifications(src)).to eq([notification])
@@ -104,7 +104,7 @@ describe Chef::RunContext::ChildRunContext do
context "after load('include::default')" do
before do
- run_list = Chef::RunList.new('include::default').expand('_default')
+ run_list = Chef::RunList.new("include::default").expand("_default")
# TODO not sure why we had to do this to get everything to work ...
node.automatic_attrs[:recipes] = []
child.load(run_list)
diff --git a/spec/unit/run_context/cookbook_compiler_spec.rb b/spec/unit/run_context/cookbook_compiler_spec.rb
index 20ec1d2ef7..feb39615b6 100644
--- a/spec/unit/run_context/cookbook_compiler_spec.rb
+++ b/spec/unit/run_context/cookbook_compiler_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/lib/library_load_order'
+require "spec_helper"
+require "support/lib/library_load_order"
# These tests rely on fixture data in spec/data/run_context/cookbooks.
#
@@ -45,13 +45,12 @@ describe Chef::RunContext::CookbookCompiler do
let(:cookbook_collection) { Chef::CookbookCollection.new(cookbook_loader) }
# Lazy evaluation of `expansion` here is used to mutate the run list before expanding it
- let(:run_list_expansion) { node.run_list.expand('_default') }
+ let(:run_list_expansion) { node.run_list.expand("_default") }
let(:compiler) do
Chef::RunContext::CookbookCompiler.new(run_context, run_list_expansion, events)
end
-
describe "loading attribute files" do
# Attribute files in the fixture data will append their
@@ -159,7 +158,49 @@ describe Chef::RunContext::CookbookCompiler do
end
describe "loading recipes" do
- # Tests for this behavior are in RunContext's tests
+ # Additional tests for this behavior are in RunContext's tests
+
+ describe "event dispatch" do
+ let(:recipe) { "dependency1::default" }
+ let(:recipe_path) do
+ File.expand_path("../../../data/run_context/cookbooks/dependency1/recipes/default.rb", __FILE__).tap do |path|
+ path.gsub!(File::SEPARATOR, File::ALT_SEPARATOR) if File::ALT_SEPARATOR
+ end
+ end
+ before do
+ node.run_list(recipe)
+ end
+ subject { compiler.compile_recipes }
+
+ it "dispatches normally" do
+ allow(run_context).to receive(:load_recipe)
+ expect(events).to receive(:recipe_load_start).with(1)
+ expect(events).to receive(:recipe_file_loaded).with(recipe_path, "dependency1::default")
+ expect(events).to receive(:recipe_load_complete).with(no_args)
+ subject
+ end
+
+ it "dispatches when a recipe is not found" do
+ exc = Chef::Exceptions::RecipeNotFound.new
+ allow(run_context).to receive(:load_recipe).and_raise(exc)
+ expect(events).to receive(:recipe_load_start).with(1)
+ expect(events).to_not receive(:recipe_file_loaded)
+ expect(events).to receive(:recipe_not_found).with(exc)
+ expect(events).to_not receive(:recipe_load_complete)
+ expect { subject }.to raise_error(exc)
+ end
+
+ it "dispatches when a recipe has an error" do
+ exc = ArgumentError.new
+ allow(run_context).to receive(:load_recipe).and_raise(exc)
+ expect(events).to receive(:recipe_load_start).with(1)
+ expect(events).to_not receive(:recipe_file_loaded)
+ expect(events).to receive(:recipe_file_load_failed).with(recipe_path, exc, "dependency1::default")
+ expect(events).to_not receive(:recipe_load_complete)
+ expect { subject }.to raise_error(exc)
+ end
+ end
+
end
describe "listing cookbook order" do
@@ -181,6 +222,5 @@ describe Chef::RunContext::CookbookCompiler do
expect(compiler.unreachable_cookbook?(:'circular-dep2')).to be_truthy
end
-
end
end
diff --git a/spec/unit/run_context_spec.rb b/spec/unit/run_context_spec.rb
index 99801575ef..f1c3072b8e 100644
--- a/spec/unit/run_context_spec.rb
+++ b/spec/unit/run_context_spec.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Tim Hinderliter (<tim@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Tim Hinderliter (<tim@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,21 +18,21 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'support/lib/library_load_order'
+require "spec_helper"
+require "support/lib/library_load_order"
describe Chef::RunContext do
let(:chef_repo_path) { File.expand_path(File.join(CHEF_SPEC_DATA, "run_context", "cookbooks")) }
- let(:cookbook_collection) {
+ let(:cookbook_collection) do
cl = Chef::CookbookLoader.new(chef_repo_path)
cl.load_cookbooks
Chef::CookbookCollection.new(cl)
- }
- let(:node) {
+ end
+ let(:node) do
node = Chef::Node.new
node.run_list << "test" << "test::one" << "test::two"
node
- }
+ end
let(:events) { Chef::EventDispatch::Dispatcher.new }
let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) }
@@ -104,7 +104,7 @@ describe Chef::RunContext do
expect(node).to receive(:loaded_recipe).with(:test, "default")
expect(node).to receive(:loaded_recipe).with(:test, "one")
expect(node).to receive(:loaded_recipe).with(:test, "two")
- run_context.load(node.run_list.expand('_default'))
+ run_context.load(node.run_list.expand("_default"))
end
it "should load all the definitions in the cookbooks for this node" do
@@ -151,13 +151,13 @@ describe Chef::RunContext do
describe "querying the contents of cookbooks" do
let(:chef_repo_path) { File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) }
- let(:node) {
+ let(:node) do
node = Chef::Node.new
- node.set[:platform] = "ubuntu"
- node.set[:platform_version] = "13.04"
+ node.normal[:platform] = "ubuntu"
+ node.normal[:platform_version] = "13.04"
node.name("testing")
node
- }
+ end
it "queries whether a given cookbook has a specific template" do
expect(run_context).to have_template_in_cookbook("openldap", "test.erb")
@@ -202,7 +202,7 @@ describe Chef::RunContext do
let(:notification) { Chef::Resource::Notification.new(nil, nil, notifying_resource) }
shared_context "notifying resource is a Chef::Resource" do
- let(:notifying_resource) { Chef::Resource.new("gerbil") }
+ let(:notifying_resource) { Chef::Resource.new("gerbil") }
it "should be keyed off the resource name" do
run_context.send(setter, notification)
@@ -212,11 +212,11 @@ describe Chef::RunContext do
shared_context "notifying resource is a subclass of Chef::Resource" do
let(:declared_type) { :alpaca }
- let(:notifying_resource) {
+ let(:notifying_resource) do
r = Class.new(Chef::Resource).new("guinea pig")
r.declared_type = declared_type
r
- }
+ end
it "should be keyed off the resource declared key" do
run_context.send(setter, notification)
diff --git a/spec/unit/run_list/run_list_expansion_spec.rb b/spec/unit/run_list/run_list_expansion_spec.rb
index a7df9e749b..3a39bc79cc 100644
--- a/spec/unit/run_list/run_list_expansion_spec.rb
+++ b/spec/unit/run_list/run_list_expansion_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::RunList::RunListExpansion do
before do
@run_list = Chef::RunList.new
- @run_list << 'recipe[lobster::mastercookbook@0.1.0]' << 'role[rage]' << 'recipe[fist@0.1]'
+ @run_list << "recipe[lobster::mastercookbook@0.1.0]" << "role[rage]" << "recipe[fist@0.1]"
@expansion = Chef::RunList::RunListExpansion.new("_default", @run_list.run_list_items)
end
@@ -43,7 +43,7 @@ describe Chef::RunList::RunListExpansion do
end
it "has not applied its roles" do
- expect(@expansion.applied_role?('rage')).to be_falsey
+ expect(@expansion.applied_role?("rage")).to be_falsey
end
end
@@ -51,7 +51,7 @@ describe Chef::RunList::RunListExpansion do
before do
@rage_role = Chef::Role.new.tap do |r|
r.name("rage")
- r.env_run_lists('_default' => [], "prod" => ["recipe[prod-only]"])
+ r.env_run_lists("_default" => [], "prod" => ["recipe[prod-only]"])
end
@expansion = Chef::RunList::RunListExpansion.new("prod", @run_list.run_list_items)
expect(@expansion).to receive(:fetch_role).and_return(@rage_role)
@@ -67,34 +67,34 @@ describe Chef::RunList::RunListExpansion do
describe "after applying a role" do
before do
allow(@expansion).to receive(:fetch_role).and_return(Chef::Role.new)
- @expansion.inflate_role('rage', "role[base]")
+ @expansion.inflate_role("rage", "role[base]")
end
it "tracks the applied role" do
- expect(@expansion.applied_role?('rage')).to be_truthy
+ expect(@expansion.applied_role?("rage")).to be_truthy
end
it "does not inflate the role again" do
- expect(@expansion.inflate_role('rage', "role[base]")).to be_falsey
+ expect(@expansion.inflate_role("rage", "role[base]")).to be_falsey
end
end
describe "after expanding a run list" do
before do
@first_role = Chef::Role.new
- @first_role.name('rage')
- @first_role.run_list('role[mollusk]')
- @first_role.default_attributes({'foo' => 'bar'})
- @first_role.override_attributes({'baz' => 'qux'})
+ @first_role.name("rage")
+ @first_role.run_list("role[mollusk]")
+ @first_role.default_attributes({ "foo" => "bar" })
+ @first_role.override_attributes({ "baz" => "qux" })
@second_role = Chef::Role.new
- @second_role.name('rage')
- @second_role.run_list('recipe[crabrevenge]')
- @second_role.default_attributes({'foo' => 'boo'})
- @second_role.override_attributes({'baz' => 'bux'})
+ @second_role.name("rage")
+ @second_role.run_list("recipe[crabrevenge]")
+ @second_role.default_attributes({ "foo" => "boo" })
+ @second_role.override_attributes({ "baz" => "bux" })
allow(@expansion).to receive(:fetch_role).and_return(@first_role, @second_role)
@expansion.expand
@json = '{"id":"_default","run_list":[{"type":"recipe","name":"lobster::mastercookbook","version":"0.1.0",'
- .concat(
+ .concat(
'"skipped":false},{"type":"role","name":"rage","children":[{"type":"role","name":"mollusk","children":[],"missing":null,'
.concat(
'"error":null,"skipped":null},{"type":"recipe","name":"crabrevenge","version":null,"skipped":false}],"missing":null,'
@@ -104,29 +104,29 @@ describe Chef::RunList::RunListExpansion do
end
it "produces json tree upon tracing expansion" do
- jsonRunList = @expansion.to_json
- expect(jsonRunList).to eq(@json)
+ json_run_list = @expansion.to_json
+ expect(json_run_list).to eq(@json)
end
it "has the ordered list of recipes" do
- expect(@expansion.recipes).to eq(['lobster::mastercookbook', 'crabrevenge', 'fist'])
+ expect(@expansion.recipes).to eq(["lobster::mastercookbook", "crabrevenge", "fist"])
end
it "has the merged attributes from the roles with outer roles overriding inner" do
- expect(@expansion.default_attrs).to eq({'foo' => 'bar'})
- expect(@expansion.override_attrs).to eq({'baz' => 'qux'})
+ expect(@expansion.default_attrs).to eq({ "foo" => "bar" })
+ expect(@expansion.override_attrs).to eq({ "baz" => "qux" })
end
it "has the list of all roles applied" do
# this is the correct order, but 1.8 hash order is not stable
- expect(@expansion.roles).to match_array(['rage', 'mollusk'])
+ expect(@expansion.roles).to match_array(%w{rage mollusk})
end
end
describe "after expanding a run list with a non existent role" do
before do
- allow(@expansion).to receive(:fetch_role) { @expansion.role_not_found('crabrevenge', "role[base]") }
+ allow(@expansion).to receive(:fetch_role) { @expansion.role_not_found("crabrevenge", "role[base]") }
@expansion.expand
end
@@ -136,7 +136,7 @@ describe Chef::RunList::RunListExpansion do
end
it "has a list of invalid role names" do
- expect(@expansion.errors).to include('crabrevenge')
+ expect(@expansion.errors).to include("crabrevenge")
end
end
diff --git a/spec/unit/run_list/run_list_item_spec.rb b/spec/unit/run_list/run_list_item_spec.rb
index 16832c1b7d..3f8fd2ab3b 100644
--- a/spec/unit/run_list/run_list_item_spec.rb
+++ b/spec/unit/run_list/run_list_item_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,22 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::RunList::RunListItem do
describe "when creating from a Hash" do
it "raises an exception when the hash doesn't have a :type key" do
- expect {Chef::RunList::RunListItem.new(:name => "tatft")}.to raise_error(ArgumentError)
+ expect { Chef::RunList::RunListItem.new(:name => "tatft") }.to raise_error(ArgumentError)
end
it "raises an exception when the hash doesn't have an :name key" do
- expect {Chef::RunList::RunListItem.new(:type => 'R') }.to raise_error(ArgumentError)
+ expect { Chef::RunList::RunListItem.new(:type => "R") }.to raise_error(ArgumentError)
end
it "sets the name and type as given in the hash" do
- item = Chef::RunList::RunListItem.new(:type => 'fuuu', :name => 'uuuu')
- expect(item.to_s).to eq('fuuu[uuuu]')
+ item = Chef::RunList::RunListItem.new(:type => "fuuu", :name => "uuuu")
+ expect(item.to_s).to eq("fuuu[uuuu]")
end
end
@@ -41,77 +41,77 @@ describe Chef::RunList::RunListItem do
item = Chef::RunList::RunListItem.new("recipe[rage]")
expect(item).to be_a_recipe
expect(item).not_to be_a_role
- expect(item.to_s).to eq('recipe[rage]')
- expect(item.name).to eq('rage')
+ expect(item.to_s).to eq("recipe[rage]")
+ expect(item.name).to eq("rage")
end
it "parses a qualified recipe with a version" do
item = Chef::RunList::RunListItem.new("recipe[rage@0.1.0]")
expect(item).to be_a_recipe
expect(item).not_to be_a_role
- expect(item.to_s).to eq('recipe[rage@0.1.0]')
- expect(item.name).to eq('rage')
- expect(item.version).to eq('0.1.0')
+ expect(item.to_s).to eq("recipe[rage@0.1.0]")
+ expect(item.name).to eq("rage")
+ expect(item.version).to eq("0.1.0")
end
it "parses a qualified role" do
item = Chef::RunList::RunListItem.new("role[fist]")
expect(item).to be_a_role
expect(item).not_to be_a_recipe
- expect(item.to_s).to eq('role[fist]')
- expect(item.name).to eq('fist')
+ expect(item.to_s).to eq("role[fist]")
+ expect(item.name).to eq("fist")
end
it "parses an unqualified recipe" do
item = Chef::RunList::RunListItem.new("lobster")
expect(item).to be_a_recipe
expect(item).not_to be_a_role
- expect(item.to_s).to eq('recipe[lobster]')
- expect(item.name).to eq('lobster')
+ expect(item.to_s).to eq("recipe[lobster]")
+ expect(item.name).to eq("lobster")
end
it "raises an exception when the string has typo on the type part" do
- expect {Chef::RunList::RunListItem.new("Recipe[lobster]") }.to raise_error(ArgumentError)
+ expect { Chef::RunList::RunListItem.new("Recipe[lobster]") }.to raise_error(ArgumentError)
end
it "raises an exception when the string has extra space between the type and the name" do
- expect {Chef::RunList::RunListItem.new("recipe [lobster]") }.to raise_error(ArgumentError)
+ expect { Chef::RunList::RunListItem.new("recipe [lobster]") }.to raise_error(ArgumentError)
end
it "raises an exception when the string does not close the bracket" do
- expect {Chef::RunList::RunListItem.new("recipe[lobster") }.to raise_error(ArgumentError)
+ expect { Chef::RunList::RunListItem.new("recipe[lobster") }.to raise_error(ArgumentError)
end
end
describe "comparing to other run list items" do
it "is equal to another run list item that has the same name and type" do
- item1 = Chef::RunList::RunListItem.new('recipe[lrf]')
- item2 = Chef::RunList::RunListItem.new('recipe[lrf]')
+ item1 = Chef::RunList::RunListItem.new("recipe[lrf]")
+ item2 = Chef::RunList::RunListItem.new("recipe[lrf]")
expect(item1).to eq(item2)
end
it "is not equal to another run list item with the same name and different type" do
- item1 = Chef::RunList::RunListItem.new('recipe[lrf]')
- item2 = Chef::RunList::RunListItem.new('role[lrf]')
+ item1 = Chef::RunList::RunListItem.new("recipe[lrf]")
+ item2 = Chef::RunList::RunListItem.new("role[lrf]")
expect(item1).not_to eq(item2)
end
it "is not equal to another run list item with the same type and different name" do
- item1 = Chef::RunList::RunListItem.new('recipe[lrf]')
- item2 = Chef::RunList::RunListItem.new('recipe[lobsterragefist]')
+ item1 = Chef::RunList::RunListItem.new("recipe[lrf]")
+ item2 = Chef::RunList::RunListItem.new("recipe[lobsterragefist]")
expect(item1).not_to eq(item2)
end
it "is not equal to another run list item with the same name and type but different version" do
- item1 = Chef::RunList::RunListItem.new('recipe[lrf,0.1.0]')
- item2 = Chef::RunList::RunListItem.new('recipe[lrf,0.2.0]')
+ item1 = Chef::RunList::RunListItem.new("recipe[lrf,0.1.0]")
+ item2 = Chef::RunList::RunListItem.new("recipe[lrf,0.2.0]")
expect(item1).not_to eq(item2)
end
end
describe "comparing to strings" do
it "is equal to a string if that string matches its to_s representation" do
- expect(Chef::RunList::RunListItem.new('recipe[lrf]')).to eq('recipe[lrf]')
+ expect(Chef::RunList::RunListItem.new("recipe[lrf]")).to eq("recipe[lrf]")
end
end
end
diff --git a/spec/unit/run_list/versioned_recipe_list_spec.rb b/spec/unit/run_list/versioned_recipe_list_spec.rb
index be57d6c944..91c601b294 100644
--- a/spec/unit/run_list/versioned_recipe_list_spec.rb
+++ b/spec/unit/run_list/versioned_recipe_list_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Stephen Delano (<stephen@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
+require "spec_helper"
describe Chef::RunList::VersionedRecipeList do
@@ -34,50 +34,50 @@ describe Chef::RunList::VersionedRecipeList do
before do
recipes.each { |r| list << r }
- versioned_recipes.each {|r| list.add_recipe r[:name], r[:version]}
+ versioned_recipes.each { |r| list.add_recipe r[:name], r[:version] }
end
describe "add_recipe" do
- let(:recipes) { %w[ apt god apache2 ] }
+ let(:recipes) { %w{ apt god apache2 } }
it "should append the recipe to the end of the list" do
list.add_recipe "rails"
- expect(list).to eq(["apt", "god", "apache2", "rails"])
+ expect(list).to eq(%w{apt god apache2 rails})
end
it "should not duplicate entries" do
list.add_recipe "apt"
- expect(list).to eq(["apt", "god", "apache2"])
+ expect(list).to eq(%w{apt god apache2})
end
it "should allow you to specify a version" do
list.add_recipe "rails", "1.0.0"
- expect(list).to eq(["apt", "god", "apache2", "rails"])
- expect(list.with_versions).to include({:name => "rails", :version => "1.0.0"})
+ expect(list).to eq(%w{apt god apache2 rails})
+ expect(list.with_versions).to include({ :name => "rails", :version => "1.0.0" })
end
it "should allow you to specify a version for a recipe that already exists" do
list.add_recipe "apt", "1.2.3"
- expect(list).to eq(["apt", "god", "apache2"])
- expect(list.with_versions).to include({:name => "apt", :version => "1.2.3"})
+ expect(list).to eq(%w{apt god apache2})
+ expect(list.with_versions).to include({ :name => "apt", :version => "1.2.3" })
end
it "should allow you to specify the same version of a recipe twice" do
list.add_recipe "rails", "1.0.0"
list.add_recipe "rails", "1.0.0"
- expect(list.with_versions).to include({:name => "rails", :version => "1.0.0"})
+ expect(list.with_versions).to include({ :name => "rails", :version => "1.0.0" })
end
it "should allow you to spcify no version, even when a version already exists" do
list.add_recipe "rails", "1.0.0"
list.add_recipe "rails"
- expect(list.with_versions).to include({:name => "rails", :version => "1.0.0"})
+ expect(list.with_versions).to include({ :name => "rails", :version => "1.0.0" })
end
it "should not allow multiple versions of the same recipe" do
list.add_recipe "rails", "1.0.0"
- expect {list.add_recipe "rails", "0.1.0"}.to raise_error Chef::Exceptions::CookbookVersionConflict
+ expect { list.add_recipe "rails", "0.1.0" }.to raise_error Chef::Exceptions::CookbookVersionConflict
end
end
@@ -85,9 +85,9 @@ describe Chef::RunList::VersionedRecipeList do
let(:versioned_recipes) do
[
- {:name => "apt", :version => "1.0.0"},
- {:name => "god", :version => nil},
- {:name => "apache2", :version => "0.0.1"}
+ { :name => "apt", :version => "1.0.0" },
+ { :name => "god", :version => nil },
+ { :name => "apache2", :version => "0.0.1" },
]
end
it "should return an array of hashes with :name and :version" do
@@ -106,13 +106,12 @@ describe Chef::RunList::VersionedRecipeList do
let(:versioned_recipes) do
[
- {:name => "apt", :version => "~> 1.2.0"},
- {:name => "god", :version => nil},
- {:name => "apache2", :version => "0.0.1"}
+ { :name => "apt", :version => "~> 1.2.0" },
+ { :name => "god", :version => nil },
+ { :name => "apache2", :version => "0.0.1" },
]
end
-
it "should return an array of hashes with :name and :version_constraint" do
list.with_version_constraints.each_with_index do |recipe_spec, i|
@@ -130,20 +129,20 @@ describe Chef::RunList::VersionedRecipeList do
context "with bare cookbook names" do
- let(:recipes) { %w[ apache2 ] }
+ let(:recipes) { %w{ apache2 } }
it "gives $cookbook_name::default" do
- expect(fq_names).to eq( %w[ apache2::default ] )
+ expect(fq_names).to eq( %w{ apache2::default } )
end
end
context "with qualified recipe names but no versions" do
- let(:recipes) { %w[ mysql::server ] }
+ let(:recipes) { %w{ mysql::server } }
it "returns the qualified recipe names" do
- expect(fq_names).to eq( %w[ mysql::server ] )
+ expect(fq_names).to eq( %w{ mysql::server } )
end
end
@@ -152,7 +151,7 @@ describe Chef::RunList::VersionedRecipeList do
let(:versioned_recipes) do
[
- {:name => "apt", :version => "~> 1.2.0"},
+ { :name => "apt", :version => "~> 1.2.0" },
]
end
@@ -171,7 +170,7 @@ describe Chef::RunList::VersionedRecipeList do
let(:versioned_recipes) do
[
- {:name => "apt::cacher", :version => "~> 1.2.0"},
+ { :name => "apt::cacher", :version => "~> 1.2.0" },
]
end
@@ -187,7 +186,7 @@ describe Chef::RunList::VersionedRecipeList do
end
end
- context "with duplicated names", :chef_gte_13_only do
+ context "with duplicated names", chef: ">= 13" do
it "should fail in Chef 13" do
expect(list).to_not respond_to(:with_duplicate_names)
end
diff --git a/spec/unit/run_list_spec.rb b/spec/unit/run_list_spec.rb
index e150579431..0dcd349ced 100644
--- a/spec/unit/run_list_spec.rb
+++ b/spec/unit/run_list_spec.rb
@@ -1,8 +1,8 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Seth Falcon (<seth@chef.io>)
+# Author:: Christopher Walters (<cw@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,10 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/version_class'
-require 'chef/version_constraint'
+require "chef/version_class"
+require "chef/version_constraint"
describe Chef::RunList do
before(:each) do
@@ -30,21 +30,21 @@ describe Chef::RunList do
describe "<<" do
it "should add a recipe to the run list and recipe list with the fully qualified name" do
- @run_list << 'recipe[needy]'
- expect(@run_list).to include('recipe[needy]')
+ @run_list << "recipe[needy]"
+ expect(@run_list).to include("recipe[needy]")
expect(@run_list.recipes).to include("needy")
end
it "should add a role to the run list and role list with the fully qualified name" do
@run_list << "role[woot]"
- expect(@run_list).to include('role[woot]')
- expect(@run_list.roles).to include('woot')
+ expect(@run_list).to include("role[woot]")
+ expect(@run_list.roles).to include("woot")
end
it "should accept recipes that are unqualified" do
@run_list << "needy"
- expect(@run_list).to include('recipe[needy]')
- expect(@run_list.recipes.include?('needy')).to eq(true)
+ expect(@run_list).to include("recipe[needy]")
+ expect(@run_list.recipes.include?("needy")).to eq(true)
end
it "should not allow duplicates" do
@@ -59,7 +59,7 @@ describe Chef::RunList do
@run_list << "recipe[needy@0.1.0]"
expect(@run_list.run_list.length).to eq(2)
expect(@run_list.recipes.length).to eq(2)
- expect(@run_list.recipes.include?('needy')).to eq(true)
+ expect(@run_list.recipes.include?("needy")).to eq(true)
end
it "should not allow duplicate versions of a recipe" do
@@ -74,13 +74,13 @@ describe Chef::RunList do
# Testing only the basic functionality here
# since full behavior is tested above.
it "should add a recipe to the run_list" do
- @run_list.add 'recipe[needy]'
- expect(@run_list).to include('recipe[needy]')
+ @run_list.add "recipe[needy]"
+ expect(@run_list).to include("recipe[needy]")
end
it "should add a role to the run_list" do
- @run_list.add 'role[needy]'
- expect(@run_list).to include('role[needy]')
+ @run_list.add "role[needy]"
+ expect(@run_list).to include("role[needy]")
end
end
@@ -95,7 +95,7 @@ describe Chef::RunList do
it "should believe a RunList is equal to an array named after it's members" do
@run_list << "foo"
@run_list << "baz"
- expect(@run_list).to eq([ "foo", "baz" ])
+ expect(@run_list).to eq(%w{foo baz})
end
end
@@ -112,20 +112,20 @@ describe Chef::RunList do
describe "[]" do
it "should let you look up a member in the run list by position" do
- @run_list << 'recipe[loulou]'
- expect(@run_list[0]).to eq('recipe[loulou]')
+ @run_list << "recipe[loulou]"
+ expect(@run_list[0]).to eq("recipe[loulou]")
end
end
describe "[]=" do
it "should let you set a member of the run list by position" do
- @run_list[0] = 'recipe[loulou]'
- expect(@run_list[0]).to eq('recipe[loulou]')
+ @run_list[0] = "recipe[loulou]"
+ expect(@run_list[0]).to eq("recipe[loulou]")
end
it "should properly expand a member of the run list given by position" do
- @run_list[0] = 'loulou'
- expect(@run_list[0]).to eq('recipe[loulou]')
+ @run_list[0] = "loulou"
+ expect(@run_list[0]).to eq("recipe[loulou]")
end
end
@@ -172,10 +172,11 @@ describe Chef::RunList do
@role.run_list "one", "two"
@role.default_attributes :one => :two
@role.override_attributes :three => :four
+ @role.env_run_list["production"] = Chef::RunList.new( "one", "two", "five")
allow(Chef::Role).to receive(:load).and_return(@role)
- @rest = double("Chef::REST", { :get_rest => @role, :url => "/" })
- allow(Chef::REST).to receive(:new).and_return(@rest)
+ @rest = double("Chef::ServerAPI", { :get => @role.to_hash, :url => "/" })
+ allow(Chef::ServerAPI).to receive(:new).and_return(@rest)
@run_list << "role[stubby]"
@run_list << "kitty"
@@ -196,21 +197,17 @@ describe Chef::RunList do
describe "from the chef server" do
it "should load the role from the chef server" do
- #@rest.should_receive(:get_rest).with("roles/stubby")
+ #@rest.should_receive(:get).with("roles/stubby")
expansion = @run_list.expand("_default", "server")
- expect(expansion.recipes).to eq(['one', 'two', 'kitty'])
+ expect(expansion.recipes).to eq(%w{one two kitty})
end
it "should default to expanding from the server" do
- expect(@rest).to receive(:get_rest).with("roles/stubby")
+ expect(@rest).to receive(:get).with("roles/stubby")
@run_list.expand("_default")
end
describe "with an environment set" do
- before do
- @role.env_run_list["production"] = Chef::RunList.new( "one", "two", "five")
- end
-
it "expands the run list using the environment specific run list" do
expansion = @run_list.expand("production", "server")
expect(expansion.recipes).to eq(%w{one two five kitty})
@@ -218,7 +215,7 @@ describe Chef::RunList do
describe "and multiply nested roles" do
before do
- @multiple_rest_requests = double("Chef::REST")
+ @multiple_rest_requests = double("Chef::ServerAPI")
@role.env_run_list["production"] << "role[prod-base]"
@@ -226,17 +223,16 @@ describe Chef::RunList do
@role_prod_base.name("prod-base")
@role_prod_base.env_run_list["production"] = Chef::RunList.new("role[nested-deeper]")
-
@role_nested_deeper = Chef::Role.new
@role_nested_deeper.name("nested-deeper")
@role_nested_deeper.env_run_list["production"] = Chef::RunList.new("recipe[prod-secret-sauce]")
end
it "expands the run list using the specified environment for all nested roles" do
- allow(Chef::REST).to receive(:new).and_return(@multiple_rest_requests)
- expect(@multiple_rest_requests).to receive(:get_rest).with("roles/stubby").and_return(@role)
- expect(@multiple_rest_requests).to receive(:get_rest).with("roles/prod-base").and_return(@role_prod_base)
- expect(@multiple_rest_requests).to receive(:get_rest).with("roles/nested-deeper").and_return(@role_nested_deeper)
+ allow(Chef::ServerAPI).to receive(:new).and_return(@multiple_rest_requests)
+ expect(@multiple_rest_requests).to receive(:get).with("roles/stubby").and_return(@role.to_hash)
+ expect(@multiple_rest_requests).to receive(:get).with("roles/prod-base").and_return(@role_prod_base.to_hash)
+ expect(@multiple_rest_requests).to receive(:get).with("roles/nested-deeper").and_return(@role_nested_deeper.to_hash)
expansion = @run_list.expand("production", "server")
expect(expansion.recipes).to eq(%w{one two five prod-secret-sauce kitty})
@@ -273,7 +269,7 @@ describe Chef::RunList do
allow(Chef::Role).to receive(:from_disk).with("stubby").and_return(@role)
allow(Chef::Role).to receive(:from_disk).with("dog").and_return(dog)
- expansion = @run_list.expand("_default", 'disk')
+ expansion = @run_list.expand("_default", "disk")
expect(expansion.recipes[2]).to eq("three")
expect(expansion.default_attrs[:seven]).to eq(:nine)
end
@@ -287,7 +283,7 @@ describe Chef::RunList do
allow(Chef::Role).to receive(:from_disk).with("stubby").and_return(@role)
expect(Chef::Role).to receive(:from_disk).with("dog").once.and_return(dog)
- expansion = @run_list.expand("_default", 'disk')
+ expansion = @run_list.expand("_default", "disk")
expect(expansion.recipes[2]).to eq("three")
expect(expansion.recipes[3]).to eq("kitty")
expect(expansion.default_attrs[:seven]).to eq(:nine)
diff --git a/spec/unit/run_lock_spec.rb b/spec/unit/run_lock_spec.rb
index 51e6ba1b84..350a0b2c66 100644
--- a/spec/unit/run_lock_spec.rb
+++ b/spec/unit/run_lock_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,13 +15,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require File.expand_path('../../spec_helper', __FILE__)
-require 'chef/client'
+require File.expand_path("../../spec_helper", __FILE__)
+require "chef/client"
describe Chef::RunLock do
- default_cache_path = windows? ? 'C:\chef' : '/var/chef'
- default_pid_location = windows? ? 'C:\chef\cache\chef-client-running.pid' : '/var/chef/cache/chef-client-running.pid'
+ default_cache_path = windows? ? 'C:\chef' : "/var/chef"
+ default_pid_location = windows? ? 'C:\chef\cache\chef-client-running.pid' : "/var/chef/cache/chef-client-running.pid"
describe "when first created" do
it "locates the lockfile in the file cache path by default" do
@@ -91,7 +91,7 @@ describe Chef::RunLock do
it "should raise Chef::Exceptions::RunLockTimeout" do
stub_blocked_run(0.001)
expect(runlock).not_to receive(:wait)
- expect{ runlock.acquire }.to raise_error(Chef::Exceptions::RunLockTimeout)
+ expect { runlock.acquire }.to raise_error(Chef::Exceptions::RunLockTimeout)
end
end
end
@@ -118,9 +118,9 @@ describe Chef::RunLock do
describe "and the lockfile is locked by another client run" do
describe "and the lock is released before the timeout expires" do
it "should acquire the lock" do
- stub_blocked_run(@timeout/2.0)
+ stub_blocked_run(@timeout / 2.0)
expect(runlock).to receive(:wait)
- expect{ runlock.acquire }.not_to raise_error
+ expect { runlock.acquire }.not_to raise_error
end
end
@@ -128,7 +128,7 @@ describe Chef::RunLock do
it "should raise a RunLockTimeout exception" do
stub_blocked_run(2.0)
expect(runlock).to receive(:wait)
- expect{ runlock.acquire }.to raise_error(Chef::Exceptions::RunLockTimeout)
+ expect { runlock.acquire }.to raise_error(Chef::Exceptions::RunLockTimeout)
end
end
end
diff --git a/spec/unit/run_status_spec.rb b/spec/unit/run_status_spec.rb
index d658cb5a5a..60717fb3a8 100644
--- a/spec/unit/run_status_spec.rb
+++ b/spec/unit/run_status_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,7 @@
# limitations under the License.
#
-
-require 'spec_helper'
+require "spec_helper"
describe Chef::RunStatus do
before do
@@ -82,7 +81,7 @@ describe Chef::RunStatus do
describe "with resources in the resource_collection" do
before do
- @all_resources = [Chef::Resource::Cat.new("whiskers"), Chef::Resource::ZenMaster.new('dtz')]
+ @all_resources = [Chef::Resource::Cat.new("whiskers"), Chef::Resource::ZenMaster.new("dtz")]
@run_context.resource_collection.all_resources.replace(@all_resources)
end
@@ -101,7 +100,7 @@ describe Chef::RunStatus do
describe "and some have been updated" do
before do
- @all_resources.first.updated = true
+ @all_resources.first.updated_by_last_action true
end
it "lists the updated resources" do
diff --git a/spec/unit/runner_spec.rb b/spec/unit/runner_spec.rb
index b30f818da1..4e7f4d6671 100644
--- a/spec/unit/runner_spec.rb
+++ b/spec/unit/runner_spec.rb
@@ -1,6 +1,6 @@
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
class SnitchyProvider < Chef::Provider
def self.all_actions_called
@@ -101,6 +101,7 @@ describe Chef::Runner do
context "when we fall through to old Chef::Platform resolution" do
let(:provider_resolver) { Chef::ProviderResolver.new(node, first_resource, nil) }
before do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
# set up old Chef::Platform resolution instead of provider_resolver
Chef::Platform.set(
:resource => :cat,
@@ -239,7 +240,7 @@ describe Chef::Runner do
second_resource.notifies(:fail, third_resource, :delayed)
second_resource.notifies(:purr, first_resource, :delayed)
- expect {runner.converge}.to raise_error(FailureProvider::ChefClientFail)
+ expect { runner.converge }.to raise_error(FailureProvider::ChefClientFail)
expect(first_resource).to be_updated
end
@@ -271,7 +272,7 @@ describe Chef::Runner do
end
expect(exception).to be_a(Chef::Exceptions::MultipleFailures)
- expected_message =<<-E
+ expected_message = <<-E
Multiple failures occurred:
* FailureProvider::ChefClientFail occurred in delayed notification: [explode] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort
* FailureProvider::ChefClientFail occurred in delayed notification: [explode again] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort
@@ -372,10 +373,10 @@ Multiple failures occurred:
first_resource.action = :buy
only_if_called_times = 0
- first_resource.only_if {only_if_called_times += 1; true}
+ first_resource.only_if { only_if_called_times += 1; true }
not_if_called_times = 0
- first_resource.not_if {not_if_called_times += 1; false}
+ first_resource.not_if { not_if_called_times += 1; false }
second_resource = Chef::Resource::Cat.new("carmel", run_context)
run_context.resource_collection << second_resource
@@ -392,12 +393,12 @@ Multiple failures occurred:
it "should resolve resource references in notifications when resources are defined lazily" do
first_resource.action = :nothing
- lazy_resources = lambda {
+ lazy_resources = lambda do
last_resource = Chef::Resource::Cat.new("peanut", run_context)
run_context.resource_collection << last_resource
last_resource.notifies(:purr, first_resource.to_s, :delayed)
last_resource.action = :purr
- }
+ end
second_resource = Chef::Resource::RubyBlock.new("myblock", run_context)
run_context.resource_collection << second_resource
second_resource.block { lazy_resources.call }
diff --git a/spec/unit/scan_access_control_spec.rb b/spec/unit/scan_access_control_spec.rb
index 8cf681e994..c747f6cc4a 100644
--- a/spec/unit/scan_access_control_spec.rb
+++ b/spec/unit/scan_access_control_spec.rb
@@ -1,5 +1,5 @@
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
#
require File.expand_path("../../spec_helper", __FILE__)
-require 'chef/scan_access_control'
+require "chef/scan_access_control"
describe Chef::ScanAccessControl do
@@ -33,7 +33,7 @@ describe Chef::ScanAccessControl do
@new_resource.tap do |f|
f.owner("root")
f.group("root")
- f.mode('0755')
+ f.mode("0755")
end
@scanner.set_all!
end
@@ -181,4 +181,3 @@ describe Chef::ScanAccessControl do
end
end
end
-
diff --git a/spec/unit/search/query_spec.rb b/spec/unit/search/query_spec.rb
index f85b1760d4..51667784fb 100644
--- a/spec/unit/search/query_spec.rb
+++ b/spec/unit/search/query_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Copyright:: Copyright (c) 2009,2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,68 +16,68 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'chef/search/query'
+require "spec_helper"
+require "chef/search/query"
describe Chef::Search::Query do
- let(:rest) { double("Chef::REST") }
+ let(:rest) { double("Chef::ServerAPI") }
let(:query) { Chef::Search::Query.new }
shared_context "filtered search" do
let(:query_string) { "search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0" }
let(:server_url) { "https://api.opscode.com/organizations/opscode/nodes" }
let(:args) { { filter_key => filter_hash } }
- let(:filter_hash) {
+ let(:filter_hash) do
{
- 'env' => [ 'chef_environment' ],
- 'ruby_plat' => [ 'languages', 'ruby', 'platform' ]
+ "env" => [ "chef_environment" ],
+ "ruby_plat" => %w{languages ruby platform},
}
- }
- let(:response) {
+ end
+ let(:response) do
{
"rows" => [
{ "url" => "#{server_url}/my-name-is-node",
"data" => {
"env" => "elysium",
- "ruby_plat" => "nudibranch"
- }
+ "ruby_plat" => "nudibranch",
+ },
},
{ "url" => "#{server_url}/my-name-is-jonas",
"data" => {
"env" => "hades",
- "ruby_plat" => "i386-mingw32"
- }
+ "ruby_plat" => "i386-mingw32",
+ },
},
{ "url" => "#{server_url}/my-name-is-flipper",
"data" => {
"env" => "elysium",
- "ruby_plat" => "centos"
- }
+ "ruby_plat" => "centos",
+ },
},
{ "url" => "#{server_url}/my-name-is-butters",
"data" => {
"env" => "moon",
"ruby_plat" => "solaris2",
- }
- }
+ },
+ },
],
"start" => 0,
- "total" => 4
+ "total" => 4,
}
- }
- let(:response_rows) {
+ end
+ let(:response_rows) do
[
{ "env" => "elysium", "ruby_plat" => "nudibranch" },
- { "env" => "hades", "ruby_plat" => "i386-mingw32"},
- { "env" => "elysium", "ruby_plat" => "centos"},
- { "env" => "moon", "ruby_plat" => "solaris2"}
+ { "env" => "hades", "ruby_plat" => "i386-mingw32" },
+ { "env" => "elysium", "ruby_plat" => "centos" },
+ { "env" => "moon", "ruby_plat" => "solaris2" },
]
- }
+ end
end
before(:each) do
- allow(Chef::REST).to receive(:new).and_return(rest)
- allow(rest).to receive(:get_rest).and_return(response)
+ allow(Chef::ServerAPI).to receive(:new).and_return(rest)
+ allow(rest).to receive(:get).and_return(response)
end
describe "search" do
@@ -86,85 +86,90 @@ describe Chef::Search::Query do
let(:query_string_with_rows) { "search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=4" }
let(:query_string_continue_with_rows) { "search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=4&rows=4" }
- let(:response) { {
+ let(:response) do
+ {
"rows" => [
{ "name" => "my-name-is-node",
"chef_environment" => "elysium",
"platform" => "rhel",
+ "run_list" => [],
"automatic" => {
"languages" => {
"ruby" => {
"platform" => "nudibranch",
"version" => "1.9.3",
- "target" => "ming-the-merciless"
- }
- }
- }
+ "target" => "ming-the-merciless",
+ },
+ },
+ },
},
{ "name" => "my-name-is-jonas",
"chef_environment" => "hades",
"platform" => "rhel",
+ "run_list" => [],
"automatic" => {
"languages" => {
"ruby" => {
"platform" => "i386-mingw32",
"version" => "1.9.3",
- "target" => "bilbo"
- }
- }
- }
+ "target" => "bilbo",
+ },
+ },
+ },
},
{ "name" => "my-name-is-flipper",
"chef_environment" => "elysium",
"platform" => "rhel",
+ "run_list" => [],
"automatic" => {
"languages" => {
"ruby" => {
"platform" => "centos",
"version" => "2.0.0",
- "target" => "uno"
- }
- }
- }
+ "target" => "uno",
+ },
+ },
+ },
},
{ "name" => "my-name-is-butters",
"chef_environment" => "moon",
"platform" => "rhel",
+ "run_list" => [],
"automatic" => {
"languages" => {
"ruby" => {
"platform" => "solaris2",
"version" => "2.1.2",
- "target" => "random"
- }
- }
- }
+ "target" => "random",
+ },
+ },
+ },
},
],
"start" => 0,
- "total" => 4
- } }
+ "total" => 4,
+ } end
- let(:big_response) {
+ let(:big_response) do
r = response.dup
r["total"] = 8
r
- }
+ end
- let(:big_response_empty) {
+ let(:big_response_empty) do
{
"start" => 0,
"total" => 8,
- "rows" => []
+ "rows" => [],
}
- }
+ end
- let(:big_response_end) {
+ let(:big_response_end) do
r = response.dup
r["start"] = 4
r["total"] = 8
r
- }
+ end
it "accepts a type as the first argument" do
expect { query.search("node") }.not_to raise_error
@@ -173,27 +178,27 @@ describe Chef::Search::Query do
end
it "queries for every object of a type by default" do
- expect(rest).to receive(:get_rest).with("search/node?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0").and_return(response)
+ expect(rest).to receive(:get).with("search/node?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0").and_return(response)
query.search(:node)
end
it "allows a custom query" do
- expect(rest).to receive(:get_rest).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0").and_return(response)
+ expect(rest).to receive(:get).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0").and_return(response)
query.search(:node, "platform:rhel")
end
it "lets you set a sort order" do
- expect(rest).to receive(:get_rest).with("search/node?q=platform:rhel&sort=id%20desc&start=0").and_return(response)
+ expect(rest).to receive(:get).with("search/node?q=platform:rhel&sort=id%20desc&start=0").and_return(response)
query.search(:node, "platform:rhel", sort: "id desc")
end
it "lets you set a starting object" do
- expect(rest).to receive(:get_rest).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=2").and_return(response)
+ expect(rest).to receive(:get).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=2").and_return(response)
query.search(:node, "platform:rhel", start: 2)
end
it "lets you set how many rows to return" do
- expect(rest).to receive(:get_rest).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=40").and_return(response)
+ expect(rest).to receive(:get).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=40").and_return(response)
query.search(:node, "platform:rhel", rows: 40)
end
@@ -211,27 +216,27 @@ describe Chef::Search::Query do
it "calls a block for each object in the response" do
@call_me = double("blocky")
- response["rows"].each { |r| expect(@call_me).to receive(:do).with(r) }
+ response["rows"].each { |r| expect(@call_me).to receive(:do).with(Chef::Node.from_hash(r)) }
query.search(:node) { |r| @call_me.do(r) }
end
it "pages through the responses" do
@call_me = double("blocky")
- response["rows"].each { |r| expect(@call_me).to receive(:do).with(r) }
+ response["rows"].each { |r| expect(@call_me).to receive(:do).with(Chef::Node.from_hash(r)) }
query.search(:node, "*:*", sort: nil, start: 0, rows: 4) { |r| @call_me.do(r) }
end
it "sends multiple API requests when the server indicates there is more data" do
- expect(rest).to receive(:get_rest).with(query_string).and_return(big_response)
- expect(rest).to receive(:get_rest).with(query_string_continue).and_return(big_response_end)
+ expect(rest).to receive(:get).with(query_string).and_return(big_response)
+ expect(rest).to receive(:get).with(query_string_continue).and_return(big_response_end)
query.search(:node, "platform:rhel") do |r|
nil
end
end
it "paginates correctly in the face of filtered nodes" do
- expect(rest).to receive(:get_rest).with(query_string_with_rows).and_return(big_response_empty)
- expect(rest).to receive(:get_rest).with(query_string_continue_with_rows).and_return(big_response_end)
+ expect(rest).to receive(:get).with(query_string_with_rows).and_return(big_response_empty)
+ expect(rest).to receive(:get).with(query_string_continue_with_rows).and_return(big_response_end)
query.search(:node, "platform:rhel", rows: 4) do |r|
nil
end
@@ -242,17 +247,17 @@ describe Chef::Search::Query do
let(:filter_key) { :filter_result }
before(:each) do
- expect(rest).to receive(:post_rest).with(query_string, args[filter_key]).and_return(response)
+ expect(rest).to receive(:post).with(query_string, args[filter_key]).and_return(response)
end
it "returns start" do
start = query.search(:node, "platform:rhel", args)[1]
- expect(start).to eq(response['start'])
+ expect(start).to eq(response["start"])
end
it "returns total" do
total = query.search(:node, "platform:rhel", args)[2]
- expect(total).to eq(response['total'])
+ expect(total).to eq(response["total"])
end
it "returns rows with the filter applied" do
@@ -276,7 +281,7 @@ describe Chef::Search::Query do
end
it "returns an array of filtered hashes" do
- expect(rest).to receive(:post_rest).with(query_string, args[filter_key]).and_return(response)
+ expect(rest).to receive(:post).with(query_string, args[filter_key]).and_return(response)
results = query.partial_search(:node, "platform:rhel", args)
expect(results[0]).to match_array(response_rows)
end
diff --git a/spec/unit/server_api_spec.rb b/spec/unit/server_api_spec.rb
new file mode 100644
index 0000000000..05d2a28ed4
--- /dev/null
+++ b/spec/unit/server_api_spec.rb
@@ -0,0 +1,50 @@
+require "spec_helper"
+
+SIGNING_KEY_DOT_PEM = "-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA49TA0y81ps0zxkOpmf5V4/c4IeR5yVyQFpX3JpxO4TquwnRh
+8VSUhrw8kkTLmB3cS39Db+3HadvhoqCEbqPE6915kXSuk/cWIcNozujLK7tkuPEy
+YVsyTioQAddSdfe+8EhQVf3oHxaKmUd6waXrWqYCnhxgOjxocenREYNhZ/OETIei
+PbOku47vB4nJK/0GhKBytL2XnsRgfKgDxf42BqAi1jglIdeq8lAWZNF9TbNBU21A
+O1iuT7Pm6LyQujhggPznR5FJhXKRUARXBJZawxpGV4dGtdcahwXNE4601aXPra+x
+PcRd2puCNoEDBzgVuTSsLYeKBDMSfs173W1QYwIDAQABAoIBAGF05q7vqOGbMaSD
+2Q7YbuE/JTHKTBZIlBI1QC2x+0P5GDxyEFttNMOVzcs7xmNhkpRw8eX1LrInrpMk
+WsIBKAFFEfWYlf0RWtRChJjNl+szE9jQxB5FJnWtJH/FHa78tR6PsF24aQyzVcJP
+g0FGujBihwgfV0JSCNOBkz8MliQihjQA2i8PGGmo4R4RVzGfxYKTIq9vvRq/+QEa
+Q4lpVLoBqnENpnY/9PTl6JMMjW2b0spbLjOPVwDaIzXJ0dChjNXo15K5SHI5mALJ
+I5gN7ODGb8PKUf4619ez194FXq+eob5YJdilTFKensIUvt3YhP1ilGMM+Chi5Vi/
+/RCTw3ECgYEA9jTw4wv9pCswZ9wbzTaBj9yZS3YXspGg26y6Ohq3ZmvHz4jlT6uR
+xK+DDcUiK4072gci8S4Np0fIVS7q6ivqcOdzXPrTF5/j+MufS32UrBbUTPiM1yoO
+ECcy+1szl/KoLEV09bghPbvC58PFSXV71evkaTETYnA/F6RK12lEepcCgYEA7OSy
+bsMrGDVU/MKJtwqyGP9ubA53BorM4Pp9VVVSCrGGVhb9G/XNsjO5wJC8J30QAo4A
+s59ZzCpyNRy046AB8jwRQuSwEQbejSdeNgQGXhZ7aIVUtuDeFFdaIz/zjVgxsfj4
+DPOuzieMmJ2MLR4F71ocboxNoDI7xruPSE8dDhUCgYA3vx732cQxgtHwAkeNPJUz
+dLiE/JU7CnxIoSB9fYUfPLI+THnXgzp7NV5QJN2qzMzLfigsQcg3oyo6F2h7Yzwv
+GkjlualIRRzCPaCw4Btkp7qkPvbs1QngIHALt8fD1N69P3DPHkTwjG4COjKWgnJq
+qoHKS6Fe/ZlbigikI6KsuwKBgQCTlSLoyGRHr6oj0hqz01EDK9ciMJzMkZp0Kvn8
+OKxlBxYW+jlzut4MQBdgNYtS2qInxUoAnaz2+hauqhSzntK3k955GznpUatCqx0R
+b857vWviwPX2/P6+E3GPdl8IVsKXCvGWOBZWTuNTjQtwbDzsUepWoMgXnlQJSn5I
+YSlLxQKBgQD16Gw9kajpKlzsPa6XoQeGmZALT6aKWJQlrKtUQIrsIWM0Z6eFtX12
+2jjHZ0awuCQ4ldqwl8IfRogWMBkHOXjTPVK0YKWWlxMpD/5+bGPARa5fir8O1Zpo
+Y6S6MeZ69Rp89ma4ttMZ+kwi1+XyHqC/dlcVRW42Zl5Dc7BALRlJjQ==
+-----END RSA PRIVATE KEY-----"
+
+describe Chef::ServerAPI do
+ let(:url) { "http://chef.example.com:4000" }
+ let(:key_path) { "/tmp/foo" }
+
+ describe "#initialize" do
+ it "uses the configured key file" do
+ allow(IO).to receive(:read).with(key_path).and_return(SIGNING_KEY_DOT_PEM)
+ Chef::Config[:client_key] = key_path
+
+ api = described_class.new(url)
+ expect(api.options[:signing_key_filename]).to eql(key_path)
+ end
+
+ it "allows a user to set a raw_key" do
+ api = described_class.new(url, raw_key: SIGNING_KEY_DOT_PEM)
+ expect(api.options[:signing_key_filename]).to be_nil
+ expect(api.options[:raw_key]).to eql(SIGNING_KEY_DOT_PEM)
+ end
+ end
+end
diff --git a/spec/unit/server_api_versions_spec.rb b/spec/unit/server_api_versions_spec.rb
new file mode 100644
index 0000000000..43445eb825
--- /dev/null
+++ b/spec/unit/server_api_versions_spec.rb
@@ -0,0 +1,44 @@
+#
+# Copyright:: Copyright 2017, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::ServerAPIVersions do
+ before do
+ Chef::ServerAPIVersions.instance.reset!
+ end
+
+ describe "#min_server_version" do
+ it "returns nil if no versions have been recorded" do
+ expect(Chef::ServerAPIVersions.instance.min_server_version).to be_nil
+ end
+ it "returns the correct value" do
+ Chef::ServerAPIVersions.instance.set_versions({ "min_version" => 0, "max_version" => 2 })
+ expect(Chef::ServerAPIVersions.instance.min_server_version).to eq(0)
+ end
+ end
+
+ describe "#max_server_version" do
+ it "returns nil if no versions have been recorded" do
+ expect(Chef::ServerAPIVersions.instance.max_server_version).to be_nil
+ end
+ it "returns the correct value" do
+ Chef::ServerAPIVersions.instance.set_versions({ "min_version" => 0, "max_version" => 2 })
+ expect(Chef::ServerAPIVersions.instance.max_server_version).to eq(2)
+ end
+ end
+end
diff --git a/spec/unit/shell/model_wrapper_spec.rb b/spec/unit/shell/model_wrapper_spec.rb
index d6da2dcffc..00425f2a01 100644
--- a/spec/unit/shell/model_wrapper_spec.rb
+++ b/spec/unit/shell/model_wrapper_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,18 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
describe Shell::ModelWrapper do
before do
- @model = OpenStruct.new(:name=>"Chef::Node")
+ @model = OpenStruct.new(:name => "Chef::Node")
@wrapper = Shell::ModelWrapper.new(@model)
end
describe "when created with an explicit model_symbol" do
before do
- @model = OpenStruct.new(:name=>"Chef::ApiClient")
+ @model = OpenStruct.new(:name => "Chef::ApiClient")
@wrapper = Shell::ModelWrapper.new(@model, :client)
end
@@ -46,7 +46,7 @@ describe Shell::ModelWrapper do
@node_1.name("sammich")
@node_2 = Chef::Node.new
@node_2.name("yummy")
- @server_response = {:node_1 => @node_1, :node_2 => @node_2}
+ @server_response = { :node_1 => @node_1, :node_2 => @node_2 }
@wrapper = Shell::ModelWrapper.new(Chef::Node)
allow(Chef::Node).to receive(:list).and_return(@server_response)
end
@@ -57,7 +57,7 @@ describe Shell::ModelWrapper do
end
it "maps the listed nodes when given a block" do
- expect(@wrapper.all {|n| n.name }.sort.reverse).to eq(%w{yummy sammich})
+ expect(@wrapper.all { |n| n.name }.sort.reverse).to eq(%w{yummy sammich})
end
end
@@ -67,7 +67,7 @@ describe Shell::ModelWrapper do
@node_1.name("sammich")
@node_2 = Chef::Node.new
@node_2.name("yummy")
- @server_response = {:node_1 => @node_1, :node_2 => @node_2}
+ @server_response = { :node_1 => @node_1, :node_2 => @node_2 }
@wrapper = Shell::ModelWrapper.new(Chef::Node)
# Creating a Chef::Search::Query object tries to read the private key...
@@ -81,17 +81,16 @@ describe Shell::ModelWrapper do
end
it "searches for objects using the given query string" do
- expect(@searcher).to receive(:search).with(:node, 'name:app*').and_yield(@node_1).and_yield(@node_2)
+ expect(@searcher).to receive(:search).with(:node, "name:app*").and_yield(@node_1).and_yield(@node_2)
expect(@wrapper.find("name:app*")).to include(@node_1, @node_2)
end
it "creates a 'AND'-joined query string from a HASH" do
# Hash order woes
- expect(@searcher).to receive(:search).with(:node, 'name:app* AND name:app*').and_yield(@node_1).and_yield(@node_2)
- expect(@wrapper.find(:name=>"app*",'name'=>"app*")).to include(@node_1, @node_2)
+ expect(@searcher).to receive(:search).with(:node, "name:app* AND name:app*").and_yield(@node_1).and_yield(@node_2)
+ expect(@wrapper.find(:name => "app*", "name" => "app*")).to include(@node_1, @node_2)
end
end
-
end
diff --git a/spec/unit/shell/shell_ext_spec.rb b/spec/unit/shell/shell_ext_spec.rb
index 9521ae646b..0afa1f6390 100644
--- a/spec/unit/shell/shell_ext_spec.rb
+++ b/spec/unit/shell/shell_ext_spec.rb
@@ -1,6 +1,6 @@
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Shell::Extensions do
describe "extending object for top level methods" do
@@ -92,9 +92,9 @@ describe Shell::Extensions do
end
it "prints node attributes" do
- node = double("node", :attribute => {:foo => :bar})
+ node = double("node", :attribute => { :foo => :bar })
@shell_client.node = node
- expect(@root_context).to receive(:pp).with({:foo => :bar})
+ expect(@root_context).to receive(:pp).with({ :foo => :bar })
@root_context.ohai
expect(@root_context).to receive(:pp).with(:bar)
@root_context.ohai(:foo)
diff --git a/spec/unit/shell/shell_session_spec.rb b/spec/unit/shell/shell_session_spec.rb
index d72e3fa1bb..259e6096a4 100644
--- a/spec/unit/shell/shell_session_spec.rb
+++ b/spec/unit/shell/shell_session_spec.rb
@@ -1,5 +1,5 @@
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,10 +15,9 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
require "ostruct"
-
class TestableShellSession < Shell::ShellSession
def rebuild_node
@@ -49,8 +48,8 @@ end
describe Shell::ClientSession do
before do
- Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new('shell::override')] }
- @chef_rest = double("Chef::REST")
+ Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new("shell::override")] }
+ @chef_rest = double("Chef::ServerAPI")
@session = Shell::ClientSession.instance
@node = Chef::Node.build("foo")
@session.node = @node
@@ -67,7 +66,7 @@ describe Shell::ClientSession do
@expansion = Chef::RunList::RunListExpansion.new(@node.chef_environment, [])
expect(@node.run_list).to receive(:expand).with(@node.chef_environment).and_return(@expansion)
- expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(@chef_rest)
+ expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(@chef_rest)
@session.rebuild_context
end
@@ -80,7 +79,7 @@ end
describe Shell::StandAloneSession do
before do
- Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new('shell::override')] }
+ Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new("shell::override")] }
@session = Shell::StandAloneSession.instance
@node = @session.node = Chef::Node.new
@events = Chef::EventDispatch::Dispatcher.new
@@ -131,7 +130,7 @@ end
describe Shell::SoloSession do
before do
- Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new('shell::override')] }
+ Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new("shell::override")] }
Chef::Config[:shell_solo] = true
@session = Shell::SoloSession.instance
@node = Chef::Node.new
@@ -158,8 +157,8 @@ describe Shell::SoloSession do
end
it "keeps json attribs and passes them to the node for consumption" do
- @session.node_attributes = {"besnard_lakes" => "are_the_dark_horse"}
- expect(@session.node.besnard_lakes).to eq("are_the_dark_horse")
+ @session.node_attributes = { "besnard_lakes" => "are_the_dark_horse" }
+ expect(@session.node["besnard_lakes"]).to eq("are_the_dark_horse")
#pending "1) keep attribs in an ivar 2) pass them to the node 3) feed them to the node on reset"
end
diff --git a/spec/unit/shell_out_spec.rb b/spec/unit/shell_out_spec.rb
index 50b0b61cb7..35844f4961 100644
--- a/spec/unit/shell_out_spec.rb
+++ b/spec/unit/shell_out_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../spec_helper', __FILE__)
+require File.expand_path("../../spec_helper", __FILE__)
describe "Chef::ShellOut deprecation notices" do
it "logs a warning when initializing a new Chef::ShellOut object" do
diff --git a/spec/unit/shell_spec.rb b/spec/unit/shell_spec.rb
index 379043a017..8ba1afa72a 100644
--- a/spec/unit/shell_spec.rb
+++ b/spec/unit/shell_spec.rb
@@ -1,5 +1,5 @@
# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
require "ostruct"
ObjectTestHarness = Proc.new do
@@ -44,7 +44,7 @@ describe Shell do
Shell.irb_conf = {}
allow(Shell::ShellSession.instance).to receive(:reset!)
allow(ChefConfig).to receive(:windows?).and_return(false)
- allow(Chef::Util::PathHelper).to receive(:home).and_return('/home/foo')
+ allow(Chef::Util::PathHelper).to receive(:home).and_return("/home/foo")
end
describe "reporting its status" do
@@ -58,7 +58,7 @@ describe Shell do
describe "configuring IRB" do
it "configures irb history" do
Shell.configure_irb
- expect(Shell.irb_conf[:HISTORY_FILE]).to eq(Chef::Util::PathHelper.home('.chef', 'chef_shell_history'))
+ expect(Shell.irb_conf[:HISTORY_FILE]).to eq(Chef::Util::PathHelper.home(".chef", "chef_shell_history"))
expect(Shell.irb_conf[:SAVE_HISTORY]).to eq(1000)
end
@@ -82,7 +82,7 @@ describe Shell do
conf = OpenStruct.new
events = Chef::EventDispatch::Dispatcher.new
- conf.main = Chef::Recipe.new(nil,nil,Chef::RunContext.new(Chef::Node.new, {}, events))
+ conf.main = Chef::Recipe.new(nil, nil, Chef::RunContext.new(Chef::Node.new, {}, events))
Shell.irb_conf[:IRB_RC].call(conf)
expect(conf.prompt_c).to eq("chef:recipe > ")
expect(conf.prompt_i).to eq("chef:recipe (#{Chef::VERSION})> ")
@@ -116,7 +116,7 @@ describe Shell do
end
it "adds help text when a new method is described then defined" do
- describe_define =<<-EVAL
+ describe_define = <<-EVAL
desc "foo2the Bar"
def baz
end
@@ -127,7 +127,7 @@ describe Shell do
end
it "adds help text for subcommands" do
- describe_define =<<-EVAL
+ describe_define = <<-EVAL
subcommands :baz_obj_command => "something you can do with baz.baz_obj_command"
def baz
end
@@ -139,7 +139,7 @@ describe Shell do
end
it "doesn't add previous subcommand help to commands defined afterward" do
- describe_define =<<-EVAL
+ describe_define = <<-EVAL
desc "swingFromTree"
def monkey_time
end
@@ -150,7 +150,7 @@ describe Shell do
EVAL
@chef_object.instance_eval describe_define
expect(@chef_object.help_descriptions.size).to eq(2)
- expect(@chef_object.help_descriptions.select {|h| h.cmd == "super_monkey_time" }).to be_empty
+ expect(@chef_object.help_descriptions.select { |h| h.cmd == "super_monkey_time" }).to be_empty
end
it "creates a help banner with the command descriptions" do
diff --git a/spec/unit/user_spec.rb b/spec/unit/user_spec.rb
index 97cc32eb3e..a1806db987 100644
--- a/spec/unit/user_spec.rb
+++ b/spec/unit/user_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (steve@opscode.com)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (steve@chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,10 +21,10 @@
# Open Source Chef Server 11 and should be removed once support
# for OSC 11 ends. New development should occur in user_spec.rb.
-require 'spec_helper'
+require "spec_helper"
-require 'chef/user'
-require 'tempfile'
+require "chef/user"
+require "tempfile"
describe Chef::User do
before(:each) do
@@ -60,7 +60,6 @@ describe Chef::User do
expect { @user.name "foo&" }.to raise_error(ArgumentError)
end
-
it "should not accept spaces" do
expect { @user.name "ops master" }.to raise_error(ArgumentError)
end
@@ -168,10 +167,10 @@ describe Chef::User do
describe "when deserializing from JSON" do
before(:each) do
user = { "name" => "mr_spinks",
- "public_key" => "turtles",
- "private_key" => "pandas",
- "password" => "password",
- "admin" => true }
+ "public_key" => "turtles",
+ "private_key" => "pandas",
+ "password" => "password",
+ "admin" => true }
@user = Chef::User.from_json(Chef::JSONCompat.to_json(user))
end
@@ -212,8 +211,8 @@ describe Chef::User do
describe "list" do
before(:each) do
Chef::Config[:chef_server_url] = "http://www.example.com"
- @osc_response = { "admin" => "http://www.example.com/users/admin"}
- @ohc_response = [ { "user" => { "username" => "admin" }} ]
+ @osc_response = { "admin" => "http://www.example.com/users/admin" }
+ @ohc_response = [ { "user" => { "username" => "admin" } } ]
allow(Chef::User).to receive(:load).with("admin").and_return(@user)
@osc_inflated_response = { "admin" => @user }
end
@@ -244,14 +243,14 @@ describe Chef::User do
describe "create" do
it "creates a new user via the API" do
@user.password "password"
- expect(@http_client).to receive(:post).with("users", {:name => "foobar", :admin => false, :password => "password"}).and_return({})
+ expect(@http_client).to receive(:post).with("users", { :name => "foobar", :admin => false, :password => "password" }).and_return({})
@user.create
end
end
describe "read" do
it "loads a named user from the API" do
- expect(@http_client).to receive(:get).with("users/foobar").and_return({"name" => "foobar", "admin" => true, "public_key" => "pubkey"})
+ expect(@http_client).to receive(:get).with("users/foobar").and_return({ "name" => "foobar", "admin" => true, "public_key" => "pubkey" })
user = Chef::User.load("foobar")
expect(user.name).to eq("foobar")
expect(user.admin).to eq(true)
@@ -261,7 +260,7 @@ describe Chef::User do
describe "update" do
it "updates an existing user on via the API" do
- expect(@http_client).to receive(:put).with("users/foobar", {:name => "foobar", :admin => false}).and_return({})
+ expect(@http_client).to receive(:put).with("users/foobar", { :name => "foobar", :admin => false }).and_return({})
@user.update
end
end
diff --git a/spec/unit/user_v1_spec.rb b/spec/unit/user_v1_spec.rb
index 8fd370a010..16f0d0158b 100644
--- a/spec/unit/user_v1_spec.rb
+++ b/spec/unit/user_v1_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Steven Danna (steve@opscode.com)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (steve@chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
-require 'chef/user_v1'
-require 'tempfile'
+require "chef/user_v1"
+require "tempfile"
describe Chef::UserV1 do
before(:each) do
@@ -90,7 +90,6 @@ describe Chef::UserV1 do
expect { @user.username "foo&" }.to raise_error(ArgumentError)
end
-
it "should not accept spaces" do
expect { @user.username "ops master" }.to raise_error(ArgumentError)
end
@@ -261,7 +260,7 @@ describe Chef::UserV1 do
"password" => "password",
"public_key" => "turtles",
"private_key" => "pandas",
- "create_key" => false
+ "create_key" => false,
}
@user = Chef::UserV1.from_json(Chef::JSONCompat.to_json(user))
end
@@ -312,13 +311,13 @@ describe Chef::UserV1 do
end
describe "Versioned API Interactions" do
- let(:response_406) { OpenStruct.new(:code => '406') }
+ let(:response_406) { OpenStruct.new(:code => "406") }
let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) }
before (:each) do
@user = Chef::UserV1.new
- allow(@user).to receive(:chef_root_rest_v0).and_return(double('chef rest root v0 object'))
- allow(@user).to receive(:chef_root_rest_v1).and_return(double('chef rest root v1 object'))
+ allow(@user).to receive(:chef_root_rest_v0).and_return(double("chef rest root v0 object"))
+ allow(@user).to receive(:chef_root_rest_v1).and_return(double("chef rest root v1 object"))
end
describe "update" do
@@ -333,7 +332,7 @@ describe Chef::UserV1 do
@user.password "some_password"
end
- let(:payload) {
+ let(:payload) do
{
:username => "some_username",
:display_name => "some_display_name",
@@ -341,9 +340,9 @@ describe Chef::UserV1 do
:middle_name => "some_middle_name",
:last_name => "some_last_name",
:email => "some_email",
- :password => "some_password"
+ :password => "some_password",
}
- }
+ end
context "when server API V1 is valid on the Chef Server receiving the request" do
context "when the user submits valid data" do
@@ -355,7 +354,7 @@ describe Chef::UserV1 do
end
context "when server API V1 is not valid on the Chef Server receiving the request" do
- let(:payload) {
+ let(:payload) do
{
:username => "some_username",
:display_name => "some_display_name",
@@ -364,9 +363,9 @@ describe Chef::UserV1 do
:last_name => "some_last_name",
:email => "some_email",
:password => "some_password",
- :public_key => "some_public_key"
+ :public_key => "some_public_key",
}
- }
+ end
before do
@user.public_key "some_public_key"
@@ -374,7 +373,7 @@ describe Chef::UserV1 do
end
context "when the server returns a 400" do
- let(:response_400) { OpenStruct.new(:code => '400') }
+ let(:response_400) { OpenStruct.new(:code => "400") }
let(:exception_400) { Net::HTTPServerException.new("400 Bad Request", response_400) }
context "when the 400 was due to public / private key fields no longer being supported" do
@@ -443,16 +442,16 @@ describe Chef::UserV1 do
end # update
describe "create" do
- let(:payload) {
+ let(:payload) do
{
:username => "some_username",
:display_name => "some_display_name",
:first_name => "some_first_name",
:last_name => "some_last_name",
:email => "some_email",
- :password => "some_password"
+ :password => "some_password",
}
- }
+ end
before do
@user.username "some_username"
@user.display_name "some_display_name"
@@ -474,7 +473,7 @@ describe Chef::UserV1 do
context "when handling API V1" do
it "creates a new user via the API with a middle_name when it exists" do
@user.middle_name "some_middle_name"
- expect(@user.chef_root_rest_v1).to receive(:post).with("users", payload.merge({:middle_name => "some_middle_name"})).and_return({})
+ expect(@user.chef_root_rest_v1).to receive(:post).with("users", payload.merge({ :middle_name => "some_middle_name" })).and_return({})
@user.create
end
end # when server API V1 is valid on the Chef Server receiving the request
@@ -497,7 +496,7 @@ describe Chef::UserV1 do
it "creates a new user via the API with a middle_name when it exists" do
@user.middle_name "some_middle_name"
- expect(@user.chef_root_rest_v0).to receive(:post).with("users", payload.merge({:middle_name => "some_middle_name"})).and_return({})
+ expect(@user.chef_root_rest_v0).to receive(:post).with("users", payload.merge({ :middle_name => "some_middle_name" })).and_return({})
@user.create
end
end # when server API V1 is not valid on the Chef Server receiving the request
@@ -507,11 +506,11 @@ describe Chef::UserV1 do
# DEPRECATION
# This can be removed after API V0 support is gone
describe "reregister" do
- let(:payload) {
+ let(:payload) do
{
"username" => "some_username",
}
- }
+ end
before do
@user.username "some_username"
@@ -519,7 +518,7 @@ describe Chef::UserV1 do
context "when server API V0 is valid on the Chef Server receiving the request" do
it "creates a new object via the API" do
- expect(@user.chef_root_rest_v0).to receive(:put).with("users/#{@user.username}", payload.merge({"private_key" => true})).and_return({})
+ expect(@user.chef_root_rest_v0).to receive(:put).with("users/#{@user.username}", payload.merge({ "private_key" => true })).and_return({})
@user.reregister
end
end # when server API V0 is valid on the Chef Server receiving the request
@@ -539,15 +538,15 @@ describe Chef::UserV1 do
before (:each) do
@user = Chef::UserV1.new
@user.username "foobar"
- @http_client = double("Chef::REST mock")
- allow(Chef::REST).to receive(:new).and_return(@http_client)
+ @http_client = double("Chef::ServerAPI mock")
+ allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
end
describe "list" do
before(:each) do
Chef::Config[:chef_server_url] = "http://www.example.com"
- @osc_response = { "admin" => "http://www.example.com/users/admin"}
- @ohc_response = [ { "user" => { "username" => "admin" }} ]
+ @osc_response = { "admin" => "http://www.example.com/users/admin" }
+ @ohc_response = [ { "user" => { "username" => "admin" } } ]
allow(Chef::UserV1).to receive(:load).with("admin").and_return(@user)
@osc_inflated_response = { "admin" => @user }
end
@@ -567,7 +566,7 @@ describe Chef::UserV1 do
describe "read" do
it "loads a named user from the API" do
- expect(@http_client).to receive(:get).with("users/foobar").and_return({"username" => "foobar", "admin" => true, "public_key" => "pubkey"})
+ expect(@http_client).to receive(:get).with("users/foobar").and_return({ "username" => "foobar", "admin" => true, "public_key" => "pubkey" })
user = Chef::UserV1.load("foobar")
expect(user.username).to eq("foobar")
expect(user.public_key).to eq("pubkey")
diff --git a/spec/unit/util/backup_spec.rb b/spec/unit/util/backup_spec.rb
index f548e8241d..8bc68ec160 100644
--- a/spec/unit/util/backup_spec.rb
+++ b/spec/unit/util/backup_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,8 @@
# limitations under the License.
#
-
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
describe Chef::Util::Backup do
@@ -71,15 +70,15 @@ describe Chef::Util::Backup do
end
it "should not delete anything if this is the only backup" do
- expect(@backup).to receive(:sorted_backup_files).and_return(['a'])
+ expect(@backup).to receive(:sorted_backup_files).and_return(["a"])
expect(@backup).not_to receive(:delete_backup)
@backup.backup!
end
it "should keep only 1 backup copy" do
- expect(@backup).to receive(:sorted_backup_files).and_return(['a', 'b', 'c'])
- expect(@backup).to receive(:delete_backup).with('b')
- expect(@backup).to receive(:delete_backup).with('c')
+ expect(@backup).to receive(:sorted_backup_files).and_return(%w{a b c})
+ expect(@backup).to receive(:delete_backup).with("b")
+ expect(@backup).to receive(:delete_backup).with("c")
@backup.backup!
end
end
@@ -90,15 +89,15 @@ describe Chef::Util::Backup do
end
it "should not delete anything if we only have one other backup" do
- expect(@backup).to receive(:sorted_backup_files).and_return(['a', 'b'])
+ expect(@backup).to receive(:sorted_backup_files).and_return(%w{a b})
expect(@backup).not_to receive(:delete_backup)
@backup.backup!
end
it "should keep only 2 backup copies" do
- expect(@backup).to receive(:sorted_backup_files).and_return(['a', 'b', 'c', 'd'])
- expect(@backup).to receive(:delete_backup).with('c')
- expect(@backup).to receive(:delete_backup).with('d')
+ expect(@backup).to receive(:sorted_backup_files).and_return(%w{a b c d})
+ expect(@backup).to receive(:delete_backup).with("c")
+ expect(@backup).to receive(:delete_backup).with("d")
@backup.backup!
end
end
@@ -106,7 +105,7 @@ describe Chef::Util::Backup do
describe "backup_filename" do
it "should return a timestamped path" do
- expect(@backup).to receive(:path).and_return('/a/b/c.txt')
+ expect(@backup).to receive(:path).and_return("/a/b/c.txt")
expect(@backup.send(:backup_filename)).to match(%r|^/a/b/c.txt.chef-\d{14}.\d{6}$|)
end
it "should strip the drive letter off for windows" do
@@ -114,21 +113,21 @@ describe Chef::Util::Backup do
expect(@backup.send(:backup_filename)).to match(%r|^\\a\\b\\c.txt.chef-\d{14}.\d{6}$|)
end
it "should strip the drive letter off for windows (with forwardslashes)" do
- expect(@backup).to receive(:path).and_return('c:/a/b/c.txt')
+ expect(@backup).to receive(:path).and_return("c:/a/b/c.txt")
expect(@backup.send(:backup_filename)).to match(%r|^/a/b/c.txt.chef-\d{14}.\d{6}$|)
end
end
describe "backup_path" do
it "uses the file's directory when Chef::Config[:file_backup_path] is nil" do
- expect(@backup).to receive(:path).and_return('/a/b/c.txt')
+ expect(@backup).to receive(:path).and_return("/a/b/c.txt")
Chef::Config[:file_backup_path] = nil
expect(@backup.send(:backup_path)).to match(%r|^/a/b/c.txt.chef-\d{14}.\d{6}$|)
end
it "uses the configured Chef::Config[:file_backup_path]" do
- expect(@backup).to receive(:path).and_return('/a/b/c.txt')
- Chef::Config[:file_backup_path] = '/backupdir'
+ expect(@backup).to receive(:path).and_return("/a/b/c.txt")
+ Chef::Config[:file_backup_path] = "/backupdir"
expect(@backup.send(:backup_path)).to match(%r|^/backupdir[\\/]+a/b/c.txt.chef-\d{14}.\d{6}$|)
end
diff --git a/spec/unit/util/diff_spec.rb b/spec/unit/util/diff_spec.rb
index b0a57a32c0..4bb0abd087 100644
--- a/spec/unit/util/diff_spec.rb
+++ b/spec/unit/util/diff_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Lamont Granquist (<lamont@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,8 @@
# limitations under the License.
#
-
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
shared_context "using file paths with spaces" do
let!(:old_tempfile) { Tempfile.new("chef-util diff-spec") }
@@ -77,7 +76,7 @@ shared_examples_for "a diff util" do
describe "when the old_file has binary content" do
before do
- old_tempfile.write("\x01\xff")
+ old_tempfile.write("#{0x01.chr}#{0xFF.chr}")
old_tempfile.close
end
@@ -92,7 +91,7 @@ shared_examples_for "a diff util" do
describe "when the new_file has binary content" do
before do
- new_tempfile.write("\x01\xff")
+ new_tempfile.write("#{0x01.chr}#{0xFF.chr}")
new_tempfile.close
end
@@ -553,11 +552,11 @@ describe Chef::Util::Diff, :uses_diff => true do
let(:plain_ascii) { "This is a text file.\nWith more than one line.\nAnd a \tTab.\nAnd lets make sure that other printable chars work too: ~!@\#$%^&*()`:\"<>?{}|_+,./;'[]\\-=\n" }
# these are all byte sequences that are illegal in the other encodings... (but they may legally transcode)
- let(:utf_8) { "testing utf-8 unicode...\n\n\non a new line: \xE2\x80\x93\n" } # unicode em-dash
- let(:latin_1) { "It is more metal.\nif you have an \xFDmlaut.\n" } # NB: changed to y-with-diaresis, but i'm American so I don't know the difference
- let(:shift_jis) { "I have no idea what this character is:\n \x83\x80.\n" } # seriously, no clue, but \x80 is nice and illegal in other encodings
+ let(:utf_8) { "testing utf-8 unicode...\n\n\non a new line: \xE2\x80\x93\n" } # unicode em-dash
+ let(:latin_1) { "It is more metal.\nif you have an #{0xFD.chr}mlaut.\n" } # NB: changed to y-with-diaresis, but i'm American so I don't know the difference
+ let(:shift_jis) { "I have no idea what this character is:\n #{0x83.chr}#{0x80.chr}.\n" } # seriously, no clue, but \x80 is nice and illegal in other encodings
- let(:differ) do # subject
+ let(:differ) do # subject
differ = Chef::Util::Diff.new
differ.diff(old_file, new_file)
differ
@@ -569,11 +568,9 @@ describe Chef::Util::Diff, :uses_diff => true do
it_behaves_like "a diff util"
end
-
describe "when file path doesn't have spaces" do
include_context "using file paths without spaces"
it_behaves_like "a diff util"
end
end
-
diff --git a/spec/unit/util/dsc/configuration_generator_spec.rb b/spec/unit/util/dsc/configuration_generator_spec.rb
index 9fbd3aaa51..cfa7a4e264 100644
--- a/spec/unit/util/dsc/configuration_generator_spec.rb
+++ b/spec/unit/util/dsc/configuration_generator_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Jay Mundrawala <jmundrawala@getchef.com>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Jay Mundrawala <jmundrawala@chef.io>
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,99 +16,99 @@
# limitations under the License.
#
-require 'chef'
-require 'chef/util/dsc/configuration_generator'
+require "chef"
+require "chef/util/dsc/configuration_generator"
describe Chef::Util::DSC::ConfigurationGenerator do
let(:conf_man) do
node = Chef::Node.new
- Chef::Util::DSC::ConfigurationGenerator.new(node, 'tmp')
+ Chef::Util::DSC::ConfigurationGenerator.new(node, "tmp")
end
- describe '#validate_configuration_name!' do
- it 'should not raise an error if a name contains all upper case letters' do
+ describe "#validate_configuration_name!" do
+ it "should not raise an error if a name contains all upper case letters" do
conf_man.send(:validate_configuration_name!, "HELLO")
end
- it 'should not raise an error if the name contains all lower case letters' do
+ it "should not raise an error if the name contains all lower case letters" do
conf_man.send(:validate_configuration_name!, "hello")
end
- it 'should not raise an error if no special characters are used except _' do
+ it "should not raise an error if no special characters are used except _" do
conf_man.send(:validate_configuration_name!, "hello_world")
end
%w{! @ # $ % ^ & * & * ( ) - = + \{ \} . ? < > \\ /}.each do |sym|
it "raises an Argument error if it configuration name contains #{sym}" do
- expect {
+ expect do
conf_man.send(:validate_configuration_name!, "Hello#{sym}")
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
end
end
describe "#get_merged_configuration_flags" do
- context 'when strings are used as switches' do
- it 'should merge the hash if there are no restricted switches' do
- merged = conf_man.send(:get_merged_configuration_flags!, {'flag' => 'a'}, 'hello')
+ context "when strings are used as switches" do
+ it "should merge the hash if there are no restricted switches" do
+ merged = conf_man.send(:get_merged_configuration_flags!, { "flag" => "a" }, "hello")
expect(merged).to include(:flag)
- expect(merged[:flag]).to eql('a')
+ expect(merged[:flag]).to eql("a")
expect(merged).to include(:outputpath)
end
- it 'should raise an ArgumentError if you try to override outputpath' do
- expect {
- conf_man.send(:get_merged_configuration_flags!, {'outputpath' => 'a'}, 'hello')
- }.to raise_error(ArgumentError)
+ it "should raise an ArgumentError if you try to override outputpath" do
+ expect do
+ conf_man.send(:get_merged_configuration_flags!, { "outputpath" => "a" }, "hello")
+ end.to raise_error(ArgumentError)
end
- it 'should be case insensitive for switches that are not allowed' do
- expect {
- conf_man.send(:get_merged_configuration_flags!, {'OutputPath' => 'a'}, 'hello')
- }.to raise_error(ArgumentError)
+ it "should be case insensitive for switches that are not allowed" do
+ expect do
+ conf_man.send(:get_merged_configuration_flags!, { "OutputPath" => "a" }, "hello")
+ end.to raise_error(ArgumentError)
end
- it 'should be case insensitive to switches that are allowed' do
- merged = conf_man.send(:get_merged_configuration_flags!, {'FLAG' => 'a'}, 'hello')
+ it "should be case insensitive to switches that are allowed" do
+ merged = conf_man.send(:get_merged_configuration_flags!, { "FLAG" => "a" }, "hello")
expect(merged).to include(:flag)
end
end
- context 'when symbols are used as switches' do
- it 'should merge the hash if there are no restricted switches' do
- merged = conf_man.send(:get_merged_configuration_flags!, {:flag => 'a'}, 'hello')
+ context "when symbols are used as switches" do
+ it "should merge the hash if there are no restricted switches" do
+ merged = conf_man.send(:get_merged_configuration_flags!, { :flag => "a" }, "hello")
expect(merged).to include(:flag)
- expect(merged[:flag]).to eql('a')
+ expect(merged[:flag]).to eql("a")
expect(merged).to include(:outputpath)
end
- it 'should raise an ArgumentError if you try to override outputpath' do
- expect {
- conf_man.send(:get_merged_configuration_flags!, {:outputpath => 'a'}, 'hello')
- }.to raise_error(ArgumentError)
+ it "should raise an ArgumentError if you try to override outputpath" do
+ expect do
+ conf_man.send(:get_merged_configuration_flags!, { :outputpath => "a" }, "hello")
+ end.to raise_error(ArgumentError)
end
- it 'should be case insensitive for switches that are not allowed' do
- expect {
- conf_man.send(:get_merged_configuration_flags!, {:OutputPath => 'a'}, 'hello')
- }.to raise_error(ArgumentError)
+ it "should be case insensitive for switches that are not allowed" do
+ expect do
+ conf_man.send(:get_merged_configuration_flags!, { :OutputPath => "a" }, "hello")
+ end.to raise_error(ArgumentError)
end
- it 'should be case insensitive to switches that are allowed' do
- merged = conf_man.send(:get_merged_configuration_flags!, {:FLAG => 'a'}, 'hello')
+ it "should be case insensitive to switches that are allowed" do
+ merged = conf_man.send(:get_merged_configuration_flags!, { :FLAG => "a" }, "hello")
expect(merged).to include(:flag)
end
end
- context 'when there are no flags' do
- it 'should supply an output path if configuration_flags is an empty hash' do
- merged = conf_man.send(:get_merged_configuration_flags!, {}, 'hello')
+ context "when there are no flags" do
+ it "should supply an output path if configuration_flags is an empty hash" do
+ merged = conf_man.send(:get_merged_configuration_flags!, {}, "hello")
expect(merged).to include(:outputpath)
expect(merged.length).to eql(1)
end
- it 'should supply an output path if configuration_flags is an empty hash' do
- merged = conf_man.send(:get_merged_configuration_flags!, nil, 'hello')
+ it "should supply an output path if configuration_flags is an empty hash" do
+ merged = conf_man.send(:get_merged_configuration_flags!, nil, "hello")
expect(merged).to include(:outputpath)
expect(merged.length).to eql(1)
end
@@ -121,16 +121,16 @@ describe Chef::Util::DSC::ConfigurationGenerator do
#
end
- describe '#write_document_generation_script' do
+ describe "#write_document_generation_script" do
let(:file_like_object) { double("file like object") }
it "should write the input to a file" do
allow(File).to receive(:open).and_yield(file_like_object)
allow(File).to receive(:join) do |a, b|
- [a,b].join("++")
+ [a, b].join("++")
end
allow(file_like_object).to receive(:write)
- conf_man.send(:write_document_generation_script, 'file', 'hello', {})
+ conf_man.send(:write_document_generation_script, "file", "hello", {})
expect(file_like_object).to have_received(:write)
end
end
@@ -140,27 +140,27 @@ describe Chef::Util::DSC::ConfigurationGenerator do
# These tests seem way too implementation specific. Unfortunately, File and Dir
# need to be mocked because they are OS specific
allow(File).to receive(:join) do |a, b|
- [a,b].join("++")
+ [a, b].join("++")
end
- allow(Dir).to receive(:entries).with("tmp++hello") {['f1', 'f2', 'hello.mof', 'f3']}
- expect(conf_man.send(:find_configuration_document, 'hello')).to eql('tmp++hello++hello.mof')
+ allow(Dir).to receive(:entries).with("tmp++hello") { ["f1", "f2", "hello.mof", "f3"] }
+ expect(conf_man.send(:find_configuration_document, "hello")).to eql("tmp++hello++hello.mof")
end
it "should return nil if the mof file is not found" do
allow(File).to receive(:join) do |a, b|
- [a,b].join("++")
+ [a, b].join("++")
end
- allow(Dir).to receive(:entries).with("tmp++hello") {['f1', 'f2', 'f3']}
- expect(conf_man.send(:find_configuration_document, 'hello')).to be_nil
+ allow(Dir).to receive(:entries).with("tmp++hello") { %w{f1 f2 f3} }
+ expect(conf_man.send(:find_configuration_document, "hello")).to be_nil
end
end
describe "#configuration_code" do
it "should build dsc" do
- dsc = conf_man.send(:configuration_code, 'archive{}', 'hello', {})
+ dsc = conf_man.send(:configuration_code, "archive{}", "hello", {})
found_configuration = false
- dsc.split(';').each do |command|
+ dsc.split(";").each do |command|
if command.downcase =~ /\s*configuration\s+'hello'\s*\{\s*node\s+'localhost'\s*\{\s*archive\s*\{\s*\}\s*\}\s*\}\s*/
found_configuration = true
end
@@ -169,25 +169,25 @@ describe Chef::Util::DSC::ConfigurationGenerator do
end
context "with imports" do
it "should import all resources when a module has an empty list" do
- dsc = conf_man.send(:configuration_code, 'archive{}', 'hello', {'FooModule' => []})
+ dsc = conf_man.send(:configuration_code, "archive{}", "hello", { "FooModule" => [] })
expect(dsc).to match(/Import-DscResource -ModuleName FooModule\s*\n/)
end
it "should import all resources when a module has a list with *" do
- dsc = conf_man.send(:configuration_code, 'archive{}', 'hello', {'FooModule' => ['FooResource', '*', 'BarResource']})
+ dsc = conf_man.send(:configuration_code, "archive{}", "hello", { "FooModule" => ["FooResource", "*", "BarResource"] })
expect(dsc).to match(/Import-DscResource -ModuleName FooModule\s*\n/)
end
it "should import specific resources when a module has list without * that is not empty" do
- dsc = conf_man.send(:configuration_code, 'archive{}', 'hello', {'FooModule' => ['FooResource', 'BarResource']})
+ dsc = conf_man.send(:configuration_code, "archive{}", "hello", { "FooModule" => %w{FooResource BarResource} })
expect(dsc).to match(/Import-DscResource -ModuleName FooModule -Name FooResource,BarResource/)
end
it "should import multiple modules with multiple import statements" do
- dsc = conf_man.send(:configuration_code, 'archive{}', 'hello', {'FooModule' => ['FooResource', 'BarResource'], 'BazModule' => []})
+ dsc = conf_man.send(:configuration_code, "archive{}", "hello", { "FooModule" => %w{FooResource BarResource}, "BazModule" => [] })
expect(dsc).to match(/Import-DscResource -ModuleName FooModule -Name FooResource,BarResource/)
expect(dsc).to match(/Import-DscResource -ModuleName BazModule\s*\n/)
- end
+ end
end
end
end
diff --git a/spec/unit/util/dsc/lcm_output_parser_spec.rb b/spec/unit/util/dsc/lcm_output_parser_spec.rb
index 3d44e07885..d59497de6f 100644
--- a/spec/unit/util/dsc/lcm_output_parser_spec.rb
+++ b/spec/unit/util/dsc/lcm_output_parser_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,36 +16,36 @@
# limitations under the License.
#
-require 'chef/util/dsc/lcm_output_parser'
+require "chef/util/dsc/lcm_output_parser"
describe Chef::Util::DSC::LocalConfigurationManager::Parser do
- context 'empty input parameter' do
- it 'raises an exception when there are no valid lines' do
+ context "empty input parameter" do
+ it "raises an exception when there are no valid lines" do
str = <<-EOF
-
+
EOF
- expect {Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)}.to raise_error(Chef::Exceptions::LCMParser)
+ expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) }.to raise_error(Chef::Exceptions::LCMParser)
end
- it 'raises an exception for a nil input' do
- expect {Chef::Util::DSC::LocalConfigurationManager::Parser::parse(nil)}.to raise_error(Chef::Exceptions::LCMParser)
+ it "raises an exception for a nil input" do
+ expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(nil) }.to raise_error(Chef::Exceptions::LCMParser)
end
end
- context 'correctly formatted output from lcm' do
- it 'returns a single resource when only 1 logged with the correct name' do
+ context "correctly formatted output from lcm" do
+ it "returns a single resource when only 1 logged with the correct name" do
str = <<EOF
logtype: [machinename]: LCM: [ Start Set ]
logtype: [machinename]: LCM: [ Start Resource ] [name]
logtype: [machinename]: LCM: [ End Resource ] [name]
logtype: [machinename]: LCM: [ End Set ]
EOF
- resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str)
expect(resources.length).to eq(1)
- expect(resources[0].name).to eq('[name]')
+ expect(resources[0].name).to eq("[name]")
end
- it 'identifies when a resource changes the state of the system' do
+ it "identifies when a resource changes the state of the system" do
str = <<EOF
logtype: [machinename]: LCM: [ Start Set ]
logtype: [machinename]: LCM: [ Start Resource ] [name]
@@ -54,11 +54,11 @@ logtype: [machinename]: LCM: [ End Set ] [name]
logtype: [machinename]: LCM: [ End Resource ] [name]
logtype: [machinename]: LCM: [ End Set ]
EOF
- resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str)
expect(resources[0].changes_state?).to be_truthy
end
- it 'preserves the log provided for how the system changed the state' do
+ it "preserves the log provided for how the system changed the state" do
str = <<EOF
logtype: [machinename]: LCM: [ Start Set ]
logtype: [machinename]: LCM: [ Start Resource ] [name]
@@ -68,11 +68,11 @@ logtype: [machinename]: LCM: [ End Set ] [name]
logtype: [machinename]: LCM: [ End Resource ] [name]
logtype: [machinename]: LCM: [ End Set ]
EOF
- resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
- expect(resources[0].change_log).to match_array(["[name]","[message]","[name]"])
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str)
+ expect(resources[0].change_log).to match_array(["[name]", "[message]", "[name]"])
end
- it 'should return false for changes_state?' do
+ it "should return false for changes_state?" do
str = <<EOF
logtype: [machinename]: LCM: [ Start Set ]
logtype: [machinename]: LCM: [ Start Resource ] [name]
@@ -80,11 +80,11 @@ logtype: [machinename]: LCM: [ Skip Set ] [name]
logtype: [machinename]: LCM: [ End Resource ] [name]
logtype: [machinename]: LCM: [ End Set ]
EOF
- resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str)
expect(resources[0].changes_state?).to be_falsey
end
- it 'should return an empty array for change_log if changes_state? is false' do
+ it "should return an empty array for change_log if changes_state? is false" do
str = <<EOF
logtype: [machinename]: LCM: [ Start Set ]
logtype: [machinename]: LCM: [ Start Resource ] [name]
@@ -92,13 +92,13 @@ logtype: [machinename]: LCM: [ Skip Set ] [name]
logtype: [machinename]: LCM: [ End Resource ] [name]
logtype: [machinename]: LCM: [ End Set ]
EOF
- resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str)
expect(resources[0].change_log).to be_empty
end
end
- context 'Incorrectly formatted output from LCM' do
- it 'should allow missing a [End Resource] when its the last one and still find all the resource' do
+ context "Incorrectly formatted output from LCM" do
+ it "should allow missing a [End Resource] when its the last one and still find all the resource" do
str = <<-EOF
logtype: [machinename]: LCM: [ Start Set ]
logtype: [machinename]: LCM: [ Start Resource ] [name]
@@ -114,12 +114,12 @@ logtype: [machinename]: LCM: [ End Set ]
logtype: [machinename]: LCM: [ End Set ]
EOF
- resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str)
expect(resources[0].changes_state?).to be_falsey
expect(resources[1].changes_state?).to be_truthy
end
- it 'should allow missing a [End Resource] when its the first one and still find all the resource' do
+ it "should allow missing a [End Resource] when its the first one and still find all the resource" do
str = <<-EOF
logtype: [machinename]: LCM: [ Start Set ]
logtype: [machinename]: LCM: [ Start Resource ] [name]
@@ -135,12 +135,12 @@ logtype: [machinename]: LCM: [ End Resource ]
logtype: [machinename]: LCM: [ End Set ]
EOF
- resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str)
expect(resources[0].changes_state?).to be_falsey
expect(resources[1].changes_state?).to be_truthy
end
- it 'should allow missing set and end resource and assume an unconverged resource in this case' do
+ it "should allow missing set and end resource and assume an unconverged resource in this case" do
str = <<-EOF
logtype: [machinename]: LCM: [ Start Set ]
logtype: [machinename]: LCM: [ Start Resource ] [name]
@@ -154,11 +154,11 @@ logtype: [machinename]: LCM: [ End Set ]
logtype: [machinename]: LCM: [ End Resource ]
logtype: [machinename]: LCM: [ End Set ]
EOF
- resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str)
expect(resources[0].changes_state?).to be_truthy
- expect(resources[0].name).to eql('[name]')
+ expect(resources[0].name).to eql("[name]")
expect(resources[1].changes_state?).to be_truthy
- expect(resources[1].name).to eql('[name2]')
+ expect(resources[1].name).to eql("[name2]")
end
end
end
diff --git a/spec/unit/util/dsc/local_configuration_manager_spec.rb b/spec/unit/util/dsc/local_configuration_manager_spec.rb
index 1cff9e445b..3f1210dbf1 100644
--- a/spec/unit/util/dsc/local_configuration_manager_spec.rb
+++ b/spec/unit/util/dsc/local_configuration_manager_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Adam Edwards <adamed@getchef.com>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards <adamed@chef.io>
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,24 @@
# limitations under the License.
#
-require 'chef'
-require 'chef/util/dsc/local_configuration_manager'
+require "chef"
+require "chef/util/dsc/local_configuration_manager"
describe Chef::Util::DSC::LocalConfigurationManager do
- let(:lcm) { Chef::Util::DSC::LocalConfigurationManager.new(nil, 'tmp') }
+ let(:lcm) { Chef::Util::DSC::LocalConfigurationManager.new(nil, "tmp") }
- let(:normal_lcm_output) { <<-EOH
+ let(:normal_lcm_output) do
+ <<-EOH
logtype: [machinename]: LCM: [ Start Set ]
logtype: [machinename]: LCM: [ Start Resource ] [name]
logtype: [machinename]: LCM: [ End Resource ] [name]
logtype: [machinename]: LCM: [ End Set ]
EOH
- }
+ end
- let(:no_whatif_lcm_output) { <<-EOH
+ let(:no_whatif_lcm_output) do
+ <<-EOH
Start-DscConfiguration : A parameter cannot be found\r\n that matches parameter name 'whatif'.
At line:1 char:123
+ run-somecommand -whatif
@@ -39,101 +41,107 @@ At line:1 char:123
+ CategoryInfo : InvalidArgument: (:) [Start-DscConfiguration], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,SomeCompany.SomeAssembly.Commands.RunSomeCommand
EOH
- }
+ end
- let(:dsc_resource_import_failure_output) { <<-EOH
+ let(:dsc_resource_import_failure_output) do
+ <<-EOH
PowerShell provider MSFT_xWebsite failed to execute Test-TargetResource functionality with error message: Please ensure that WebAdministration module is installed. + CategoryInfo : InvalidOperation: (:) [], CimException + FullyQualifiedErrorId : ProviderOperationExecutionFailure + PSComputerName : . PowerShell provider MSFT_xWebsite failed to execute Test-TargetResource functionality with error message: Please ensure that WebAdministration module is installed. + CategoryInfo : InvalidOperation: (:) [], CimException + FullyQualifiedErrorId : ProviderOperationExecutionFailure + PSComputerName : . The SendConfigurationApply function did not succeed. + CategoryInfo : NotSpecified: (root/Microsoft/...gurationManager:String) [], CimException + FullyQualifiedErrorId : MI RESULT 1 + PSComputerName : .
EOH
- }
+ end
- let(:lcm_status) {
+ let(:lcm_status) do
double("LCM cmdlet status", :stderr => lcm_standard_error, :return_value => lcm_standard_output, :succeeded? => lcm_cmdlet_success)
- }
+ end
- describe 'test_configuration method invocation' do
- context 'when interacting with the LCM using a PowerShell cmdlet' do
+ describe "test_configuration method invocation" do
+ context "when interacting with the LCM using a PowerShell cmdlet" do
before(:each) do
allow(lcm).to receive(:run_configuration_cmdlet).and_return(lcm_status)
end
- context 'that returns successfully' do
- before(:each) do
- allow(lcm).to receive(:run_configuration_cmdlet).and_return(lcm_status)
- end
-
+ context "that returns successfully" do
let(:lcm_standard_output) { normal_lcm_output }
let(:lcm_standard_error) { nil }
let(:lcm_cmdlet_success) { true }
- it 'should successfully return resource information for normally formatted output when cmdlet the cmdlet succeeds' do
- test_configuration_result = lcm.test_configuration('config', {})
+ it "should successfully return resource information for normally formatted output when cmdlet the cmdlet succeeds" do
+ test_configuration_result = lcm.test_configuration("config", {})
expect(test_configuration_result.class).to be(Array)
expect(test_configuration_result.length).to be > 0
expect(Chef::Log).not_to receive(:warn)
end
end
- context 'that fails due to missing what-if switch in DSC resource cmdlet implementation' do
- let(:lcm_standard_output) { '' }
+ context "that fails due to missing what-if switch in DSC resource cmdlet implementation" do
+ let(:lcm_standard_output) { "" }
let(:lcm_standard_error) { no_whatif_lcm_output }
let(:lcm_cmdlet_success) { false }
- it 'returns true when passed to #whatif_not_supported?' do
+ it "returns true when passed to #whatif_not_supported?" do
expect(lcm.send(:whatif_not_supported?, no_whatif_lcm_output)).to be_truthy
end
- it 'should should return a (possibly empty) array of ResourceInfo instances' do
+ it "should should return a (possibly empty) array of ResourceInfo instances" do
expect(Chef::Log).to receive(:warn).at_least(:once)
expect(lcm).to receive(:whatif_not_supported?).and_call_original
test_configuration_result = nil
- expect {test_configuration_result = lcm.test_configuration('config', {})}.not_to raise_error
+ expect { test_configuration_result = lcm.test_configuration("config", {}) }.not_to raise_error
expect(test_configuration_result.class).to be(Array)
end
end
- context 'that fails due to a DSC resource not being imported before StartDSCConfiguration -whatif is executed' do
- let(:lcm_standard_output) { '' }
+ context "that fails due to a DSC resource not being imported before StartDSCConfiguration -whatif is executed" do
+ let(:lcm_standard_output) { "" }
let(:lcm_standard_error) { dsc_resource_import_failure_output }
let(:lcm_cmdlet_success) { false }
- it 'should log a warning if the message is formatted as expected when a resource import failure occurs' do
+ it "should log a warning if the message is formatted as expected when a resource import failure occurs" do
expect(Chef::Log).to receive(:warn).at_least(:once)
expect(lcm).to receive(:dsc_module_import_failure?).and_call_original
test_configuration_result = nil
- expect {test_configuration_result = lcm.test_configuration('config', {})}.not_to raise_error
+ expect { test_configuration_result = lcm.test_configuration("config", {}) }.not_to raise_error
end
- it 'should return a (possibly empty) array of ResourceInfo instances' do
+ it "should return a (possibly empty) array of ResourceInfo instances" do
expect(Chef::Log).to receive(:warn).at_least(:once)
test_configuration_result = nil
- expect {test_configuration_result = lcm.test_configuration('config', {})}.not_to raise_error
+ expect { test_configuration_result = lcm.test_configuration("config", {}) }.not_to raise_error
expect(test_configuration_result.class).to be(Array)
end
end
- context 'that fails due to an unknown PowerShell cmdlet error' do
- let(:lcm_standard_output) { 'some output' }
- let(:lcm_standard_error) { 'Abort, Retry, Fail?' }
+ context "that fails due to an unknown PowerShell cmdlet error" do
+ let(:lcm_standard_output) { "some output" }
+ let(:lcm_standard_error) { "Abort, Retry, Fail?" }
let(:lcm_cmdlet_success) { false }
- it 'should log a warning' do
+ it "should log a warning" do
expect(Chef::Log).to receive(:warn).at_least(:once)
expect(lcm).to receive(:dsc_module_import_failure?).and_call_original
- expect {lcm.test_configuration('config', {})}.not_to raise_error
+ expect { lcm.test_configuration("config", {}) }.not_to raise_error
end
end
end
- it 'should identify a correctly formatted error message as a resource import failure' do
+ it "should identify a correctly formatted error message as a resource import failure" do
expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output)).to be(true)
end
- it 'should not identify an incorrectly formatted error message as a resource import failure' do
- expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output.gsub('module', 'gibberish'))).to be(false)
+ it "should not identify an incorrectly formatted error message as a resource import failure" do
+ expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output.gsub("module", "gibberish"))).to be(false)
end
- it 'should not identify a message without a CimException reference as a resource import failure' do
- expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output.gsub('CimException', 'ArgumentException'))).to be(false)
+ it "should not identify a message without a CimException reference as a resource import failure" do
+ expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output.gsub("CimException", "ArgumentException"))).to be(false)
end
end
-end
+ describe "#run_configuration_cmdlet" do
+ context "when invalid dsc script is given" do
+ it "raises exception" do
+ configuration_document = "invalid-config"
+ shellout_flags = { :cwd => nil, :environment => nil, :timeout => nil }
+ expect { lcm.send(:run_configuration_cmdlet, configuration_document, true, shellout_flags) }.to raise_error(Chef::Exceptions::PowershellCmdletException)
+ end
+ end
+ end
+end
diff --git a/spec/unit/util/dsc/resource_store.rb b/spec/unit/util/dsc/resource_store.rb
index a89e73fcaa..a864a2c1da 100644
--- a/spec/unit/util/dsc/resource_store.rb
+++ b/spec/unit/util/dsc/resource_store.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala <jdm@chef.io>
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,61 +16,63 @@
# limitations under the License.
#
-require 'chef'
-require 'chef/util/dsc/resource_store'
+require "chef"
+require "chef/util/dsc/resource_store"
describe Chef::Util::DSC::ResourceStore do
let(:resource_store) { Chef::Util::DSC::ResourceStore.new }
- let(:resource_a) { {
- 'ResourceType' => 'AFoo',
- 'Name' => 'Foo',
- 'Module' => {'Name' => 'ModuleA'}
+ let(:resource_a) do
+ {
+ "ResourceType" => "AFoo",
+ "Name" => "Foo",
+ "Module" => { "Name" => "ModuleA" },
}
- }
+ end
- let(:resource_b) { {
- 'ResourceType' => 'BFoo',
- 'Name' => 'Foo',
- 'Module' => {'Name' => 'ModuleB'}
+ let(:resource_b) do
+ {
+ "ResourceType" => "BFoo",
+ "Name" => "Foo",
+ "Module" => { "Name" => "ModuleB" },
}
- }
+ end
- context 'when resources are not cached' do
- context 'when calling #resources' do
- it 'returns an empty array' do
+ context "when resources are not cached" do
+ context "when calling #resources" do
+ it "returns an empty array" do
expect(resource_store.resources).to eql([])
end
end
- context 'when calling #find' do
- it 'returns an empty list if it cannot find any matching resources' do
+ context "when calling #find" do
+ it "returns an empty list if it cannot find any matching resources" do
expect(resource_store).to receive(:query_resource).and_return([])
- expect(resource_store.find('foo')).to eql([])
+ expect(resource_store.find("foo")).to eql([])
end
- it 'returns the resource if it is found (comparisons are case insensitive)' do
+ it "returns the resource if it is found (comparisons are case insensitive)" do
expect(resource_store).to receive(:query_resource).and_return([resource_a])
- expect(resource_store.find('foo')).to eql([resource_a])
+ expect(resource_store.find("foo")).to eql([resource_a])
end
- it 'returns multiple resoures if they are found' do
+ it "returns multiple resoures if they are found" do
expect(resource_store).to receive(:query_resource).and_return([resource_a, resource_b])
- expect(resource_store.find('foo')).to include(resource_a, resource_b)
+ expect(resource_store.find("foo")).to include(resource_a, resource_b)
end
- it 'deduplicates resources by ResourceName' do
+ it "deduplicates resources by ResourceName" do
expect(resource_store).to receive(:query_resource).and_return([resource_a, resource_a])
- resource_store.find('foo')
+ resource_store.find("foo")
expect(resource_store.resources).to eq([resource_a])
end
end
end
- context 'when resources are cached' do
- it 'recalls resources from the cache if present' do
+ context "when resources are cached" do
+ it "recalls resources from the cache if present" do
expect(resource_store).not_to receive(:query_resource)
expect(resource_store).to receive(:resources).and_return([resource_a])
- resource_store.find('foo')
+ resource_store.find("foo")
end
end
end
diff --git a/spec/unit/util/editor_spec.rb b/spec/unit/util/editor_spec.rb
index 968302df17..e53bc9662a 100644
--- a/spec/unit/util/editor_spec.rb
+++ b/spec/unit/util/editor_spec.rb
@@ -1,14 +1,14 @@
-require 'spec_helper'
-require 'chef/util/editor'
+require "spec_helper"
+require "chef/util/editor"
describe Chef::Util::Editor do
- describe '#initialize' do
- it 'takes an Enumerable of lines' do
+ describe "#initialize" do
+ it "takes an Enumerable of lines" do
editor = described_class.new(File.open(__FILE__))
expect(editor.lines).to be == IO.readlines(__FILE__)
end
- it 'makes a copy of an Array' do
+ it "makes a copy of an Array" do
array = Array.new
editor = described_class.new(array)
expect(editor.lines).to_not be(array)
@@ -16,137 +16,137 @@ describe Chef::Util::Editor do
end
subject(:editor) { described_class.new(input_lines) }
- let(:input_lines) { ['one', 'two', 'two', 'three'] }
+ let(:input_lines) { %w{one two two three} }
- describe '#append_line_after' do
- context 'when there is no match' do
- subject(:execute) { editor.append_line_after('missing', 'new') }
+ describe "#append_line_after" do
+ context "when there is no match" do
+ subject(:execute) { editor.append_line_after("missing", "new") }
- it('returns the number of added lines') { is_expected.to eq(0) }
- it 'does not add any lines' do
+ it("returns the number of added lines") { is_expected.to eq(0) }
+ it "does not add any lines" do
expect { execute }.to_not change { editor.lines }
end
end
- context 'when there is a match' do
- subject(:execute) { editor.append_line_after('two', 'new') }
+ context "when there is a match" do
+ subject(:execute) { editor.append_line_after("two", "new") }
- it('returns the number of added lines') { is_expected.to eq(2) }
- it 'adds a line after each match' do
+ it("returns the number of added lines") { is_expected.to eq(2) }
+ it "adds a line after each match" do
execute
- expect(editor.lines).to be == ['one', 'two', 'new', 'two', 'new', 'three']
+ expect(editor.lines).to be == %w{one two new two new three}
end
end
- it 'matches a Regexp' do
- expect(editor.append_line_after(/^ee/, 'new')).to be == 0
- expect(editor.append_line_after(/ee$/, 'new')).to be == 1
+ it "matches a Regexp" do
+ expect(editor.append_line_after(/^ee/, "new")).to be == 0
+ expect(editor.append_line_after(/ee$/, "new")).to be == 1
end
end
- describe '#append_line_if_missing' do
- context 'when there is no match' do
- subject(:execute) { editor.append_line_if_missing('missing', 'new') }
+ describe "#append_line_if_missing" do
+ context "when there is no match" do
+ subject(:execute) { editor.append_line_if_missing("missing", "new") }
- it('returns the number of added lines') { is_expected.to eq(1) }
- it 'adds a line to the end' do
+ it("returns the number of added lines") { is_expected.to eq(1) }
+ it "adds a line to the end" do
execute
- expect(editor.lines).to be == ['one', 'two', 'two', 'three', 'new']
+ expect(editor.lines).to be == %w{one two two three new}
end
end
- context 'when there is a match' do
- subject(:execute) { editor.append_line_if_missing('one', 'new') }
+ context "when there is a match" do
+ subject(:execute) { editor.append_line_if_missing("one", "new") }
- it('returns the number of added lines') { is_expected.to eq(0) }
- it 'does not add any lines' do
+ it("returns the number of added lines") { is_expected.to eq(0) }
+ it "does not add any lines" do
expect { execute }.to_not change { editor.lines }
end
end
- it 'matches a Regexp' do
- expect(editor.append_line_if_missing(/ee$/, 'new')).to be == 0
- expect(editor.append_line_if_missing(/^ee/, 'new')).to be == 1
+ it "matches a Regexp" do
+ expect(editor.append_line_if_missing(/ee$/, "new")).to be == 0
+ expect(editor.append_line_if_missing(/^ee/, "new")).to be == 1
end
end
- describe '#remove_lines' do
- context 'when there is no match' do
- subject(:execute) { editor.remove_lines('missing') }
+ describe "#remove_lines" do
+ context "when there is no match" do
+ subject(:execute) { editor.remove_lines("missing") }
- it('returns the number of removed lines') { is_expected.to eq(0) }
- it 'does not remove any lines' do
+ it("returns the number of removed lines") { is_expected.to eq(0) }
+ it "does not remove any lines" do
expect { execute }.to_not change { editor.lines }
end
end
- context 'when there is a match' do
- subject(:execute) { editor.remove_lines('two') }
+ context "when there is a match" do
+ subject(:execute) { editor.remove_lines("two") }
- it('returns the number of removed lines') { is_expected.to eq(2) }
- it 'removes the matching lines' do
+ it("returns the number of removed lines") { is_expected.to eq(2) }
+ it "removes the matching lines" do
execute
- expect(editor.lines).to be == ['one', 'three']
+ expect(editor.lines).to be == %w{one three}
end
end
- it 'matches a Regexp' do
+ it "matches a Regexp" do
expect(editor.remove_lines(/^ee/)).to be == 0
expect(editor.remove_lines(/ee$/)).to be == 1
end
end
- describe '#replace' do
- context 'when there is no match' do
- subject(:execute) { editor.replace('missing', 'new') }
+ describe "#replace" do
+ context "when there is no match" do
+ subject(:execute) { editor.replace("missing", "new") }
- it('returns the number of changed lines') { is_expected.to eq(0) }
- it 'does not change any lines' do
+ it("returns the number of changed lines") { is_expected.to eq(0) }
+ it "does not change any lines" do
expect { execute }.to_not change { editor.lines }
end
end
- context 'when there is a match' do
- subject(:execute) { editor.replace('two', 'new') }
+ context "when there is a match" do
+ subject(:execute) { editor.replace("two", "new") }
- it('returns the number of changed lines') { is_expected.to eq(2) }
- it 'replaces the matching portions' do
+ it("returns the number of changed lines") { is_expected.to eq(2) }
+ it "replaces the matching portions" do
execute
- expect(editor.lines).to be == ['one', 'new', 'new', 'three']
+ expect(editor.lines).to be == %w{one new new three}
end
end
- it 'matches a Regexp' do
- expect(editor.replace(/^ee/, 'new')).to be == 0
- expect(editor.replace(/ee$/, 'new')).to be == 1
- expect(editor.lines).to be == ['one', 'two', 'two', 'thrnew']
+ it "matches a Regexp" do
+ expect(editor.replace(/^ee/, "new")).to be == 0
+ expect(editor.replace(/ee$/, "new")).to be == 1
+ expect(editor.lines).to be == %w{one two two thrnew}
end
end
- describe '#replace_lines' do
- context 'when there is no match' do
- subject(:execute) { editor.replace_lines('missing', 'new') }
+ describe "#replace_lines" do
+ context "when there is no match" do
+ subject(:execute) { editor.replace_lines("missing", "new") }
- it('returns the number of changed lines') { is_expected.to eq(0) }
- it 'does not change any lines' do
+ it("returns the number of changed lines") { is_expected.to eq(0) }
+ it "does not change any lines" do
expect { execute }.to_not change { editor.lines }
end
end
- context 'when there is a match' do
- subject(:execute) { editor.replace_lines('two', 'new') }
+ context "when there is a match" do
+ subject(:execute) { editor.replace_lines("two", "new") }
- it('returns the number of replaced lines') { is_expected.to eq(2) }
- it 'replaces the matching line' do
+ it("returns the number of replaced lines") { is_expected.to eq(2) }
+ it "replaces the matching line" do
execute
- expect(editor.lines).to be == ['one', 'new', 'new', 'three']
+ expect(editor.lines).to be == %w{one new new three}
end
end
- it 'matches a Regexp' do
- expect(editor.replace_lines(/^ee/, 'new')).to be == 0
- expect(editor.replace_lines(/ee$/, 'new')).to be == 1
- expect(editor.lines).to be == ['one', 'two', 'two', 'new']
+ it "matches a Regexp" do
+ expect(editor.replace_lines(/^ee/, "new")).to be == 0
+ expect(editor.replace_lines(/ee$/, "new")).to be == 1
+ expect(editor.lines).to be == %w{one two two new}
end
end
end
diff --git a/spec/unit/util/file_edit_spec.rb b/spec/unit/util/file_edit_spec.rb
index b99cf2f426..1a71d1d856 100644
--- a/spec/unit/util/file_edit_spec.rb
+++ b/spec/unit/util/file_edit_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Nuo Yan (<nuo@opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Nuo Yan (<nuo@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
# limitations under the License.
#
-require 'spec_helper'
-require 'tempfile'
+require "spec_helper"
+require "tempfile"
describe Chef::Util::FileEdit do
@@ -93,7 +93,7 @@ twice
end
let(:target_file) do
- f = Tempfile.open('file_edit_spec')
+ f = Tempfile.open("file_edit_spec")
f.write(starting_content)
f.close
f
@@ -111,7 +111,7 @@ twice
end
it "should throw an exception if the input file does not exist" do
- expect{Chef::Util::FileEdit.new("nonexistfile")}.to raise_error(ArgumentError)
+ expect { Chef::Util::FileEdit.new("nonexistfile") }.to raise_error(ArgumentError)
end
# CHEF-5018: people have monkey patched this and it has accidentally been broken
@@ -124,7 +124,7 @@ twice
let(:hosts_content) { "" }
it "should not throw an exception" do
- expect{ fedit }.not_to raise_error
+ expect { fedit }.not_to raise_error
end
end
diff --git a/spec/unit/util/powershell/cmdlet_spec.rb b/spec/unit/util/powershell/cmdlet_spec.rb
index 5ddf9282c4..800e4cc9c0 100644
--- a/spec/unit/util/powershell/cmdlet_spec.rb
+++ b/spec/unit/util/powershell/cmdlet_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Jay Mundrawala <jdm@getchef.com>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Jay Mundrawala <jdm@chef.io>
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,38 +16,38 @@
# limitations under the License.
#
-require 'chef'
-require 'chef/util/powershell/cmdlet'
+require "chef"
+require "chef/util/powershell/cmdlet"
describe Chef::Util::Powershell::Cmdlet do
before (:all) do
@node = Chef::Node.new
- @cmdlet = Chef::Util::Powershell::Cmdlet.new(@node, 'Some-Commandlet')
+ @cmdlet = Chef::Util::Powershell::Cmdlet.new(@node, "Some-Commandlet")
end
- describe '#validate_switch_name!' do
- it 'should not raise an error if a name contains all upper case letters' do
+ describe "#validate_switch_name!" do
+ it "should not raise an error if a name contains all upper case letters" do
@cmdlet.send(:validate_switch_name!, "HELLO")
end
- it 'should not raise an error if the name contains all lower case letters' do
+ it "should not raise an error if the name contains all lower case letters" do
@cmdlet.send(:validate_switch_name!, "hello")
end
- it 'should not raise an error if no special characters are used except _' do
+ it "should not raise an error if no special characters are used except _" do
@cmdlet.send(:validate_switch_name!, "hello_world")
end
%w{! @ # $ % ^ & * & * ( ) - = + \{ \} . ? < > \\ /}.each do |sym|
it "raises an Argument error if it configuration name contains #{sym}" do
- expect {
+ expect do
@cmdlet.send(:validate_switch_name!, "Hello#{sym}")
- }.to raise_error(ArgumentError)
+ end.to raise_error(ArgumentError)
end
end
end
- describe '#escape_parameter_value' do
+ describe "#escape_parameter_value" do
# Is this list really complete?
%w{` " # '}.each do |c|
it "escapse #{c}" do
@@ -55,52 +55,52 @@ describe Chef::Util::Powershell::Cmdlet do
end
end
- it 'does not do anything to a string without special characters' do
- expect(@cmdlet.send(:escape_parameter_value, 'stuff')).to eql('stuff')
+ it "does not do anything to a string without special characters" do
+ expect(@cmdlet.send(:escape_parameter_value, "stuff")).to eql("stuff")
end
end
- describe '#escape_string_parameter_value' do
+ describe "#escape_string_parameter_value" do
it "surrounds a string with ''" do
- expect(@cmdlet.send(:escape_string_parameter_value, 'stuff')).to eql("'stuff'")
+ expect(@cmdlet.send(:escape_string_parameter_value, "stuff")).to eql("'stuff'")
end
end
- describe '#command_switches_string' do
- it 'raises an ArgumentError if the key is not a symbol' do
- expect {
- @cmdlet.send(:command_switches_string, {'foo' => 'bar'})
- }.to raise_error(ArgumentError)
+ describe "#command_switches_string" do
+ it "raises an ArgumentError if the key is not a symbol" do
+ expect do
+ @cmdlet.send(:command_switches_string, { "foo" => "bar" })
+ end.to raise_error(ArgumentError)
end
- it 'does not allow invalid switch names' do
- expect {
- @cmdlet.send(:command_switches_string, {:foo! => 'bar'})
- }.to raise_error(ArgumentError)
+ it "does not allow invalid switch names" do
+ expect do
+ @cmdlet.send(:command_switches_string, { :foo! => "bar" })
+ end.to raise_error(ArgumentError)
end
- it 'ignores switches with a false value' do
- expect(@cmdlet.send(:command_switches_string, {foo: false})).to eql('')
+ it "ignores switches with a false value" do
+ expect(@cmdlet.send(:command_switches_string, { foo: false })).to eql("")
end
- it 'should correctly handle a value type of string' do
- expect(@cmdlet.send(:command_switches_string, {foo: 'bar'})).to eql("-foo 'bar'")
+ it "should correctly handle a value type of string" do
+ expect(@cmdlet.send(:command_switches_string, { foo: "bar" })).to eql("-foo 'bar'")
end
- it 'should correctly handle a value type of string even when it is 0 length' do
- expect(@cmdlet.send(:command_switches_string, {foo: ''})).to eql("-foo ''")
+ it "should correctly handle a value type of string even when it is 0 length" do
+ expect(@cmdlet.send(:command_switches_string, { foo: "" })).to eql("-foo ''")
end
- it 'should not quote integers' do
- expect(@cmdlet.send(:command_switches_string, {foo: 1})).to eql("-foo 1")
+ it "should not quote integers" do
+ expect(@cmdlet.send(:command_switches_string, { foo: 1 })).to eql("-foo 1")
end
- it 'should not quote floats' do
- expect(@cmdlet.send(:command_switches_string, {foo: 1.0})).to eql("-foo 1.0")
+ it "should not quote floats" do
+ expect(@cmdlet.send(:command_switches_string, { foo: 1.0 })).to eql("-foo 1.0")
end
- it 'has just the switch when the value is true' do
- expect(@cmdlet.send(:command_switches_string, {foo: true})).to eql("-foo")
+ it "has just the switch when the value is true" do
+ expect(@cmdlet.send(:command_switches_string, { foo: true })).to eql("-foo")
end
end
end
diff --git a/spec/unit/util/powershell/ps_credential_spec.rb b/spec/unit/util/powershell/ps_credential_spec.rb
index bac58b02e5..6f65174d15 100644
--- a/spec/unit/util/powershell/ps_credential_spec.rb
+++ b/spec/unit/util/powershell/ps_credential_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Jay Mundrawala <jdm@chef.io>
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,29 @@
# limitations under the License.
#
-require 'chef'
-require 'chef/util/powershell/ps_credential'
+require "chef"
+require "chef/util/powershell/ps_credential"
describe Chef::Util::Powershell::PSCredential do
- let (:username) { 'foo' }
- let (:password) { 'password' }
+ let (:username) { "foo" }
+ let (:password) { "ThIsIsThEpAsSwOrD" }
- context 'when username and password are provided' do
- let(:ps_credential) { Chef::Util::Powershell::PSCredential.new(username, password)}
- context 'when calling to_psobject' do
- it 'should create the script to create a PSCredential when calling' do
- allow(ps_credential).to receive(:encrypt).with(password).and_return('encrypted')
+ context "when username and password are provided" do
+ let(:ps_credential) { Chef::Util::Powershell::PSCredential.new(username, password) }
+ context "when calling to_psobject" do
+ it "should create the script to create a PSCredential when calling" do
+ allow(ps_credential).to receive(:encrypt).with(password).and_return("encrypted")
expect(ps_credential.to_psobject).to eq(
"New-Object System.Management.Automation.PSCredential("\
"'#{username}',('encrypted' | ConvertTo-SecureString))")
end
end
+
+ context "when to_text is called" do
+ it "should not contain the password" do
+ allow(ps_credential).to receive(:encrypt).with(password).and_return("encrypted")
+ expect(ps_credential.to_text).not_to match(/#{password}/)
+ end
+ end
end
end
diff --git a/spec/unit/util/selinux_spec.rb b/spec/unit/util/selinux_spec.rb
index 0ed138c7bc..751092bc9a 100644
--- a/spec/unit/util/selinux_spec.rb
+++ b/spec/unit/util/selinux_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Serdar Sutay (<serdar@opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar@chef.io>)
+# Copyright:: Copyright 2013-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,7 @@
# limitations under the License.
#
-
-require 'spec_helper'
+require "spec_helper"
describe Chef::Util::Selinux do
class TestClass
@@ -40,7 +39,7 @@ describe Chef::Util::Selinux do
end
it "each part of ENV['PATH'] should be checked" do
- expected_paths = ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/bin', '/usr/bin', '/sbin', '/usr/sbin' ]
+ expected_paths = ENV["PATH"].split(File::PATH_SEPARATOR) + [ "/bin", "/usr/bin", "/sbin", "/usr/sbin" ]
expected_paths.each do |bin_path|
selinux_path = File.join(bin_path, "selinuxenabled")
@@ -62,7 +61,7 @@ describe Chef::Util::Selinux do
describe "when selinux is enabled" do
before do
cmd_result = double("Cmd Result", :exitstatus => 0)
- expect(@test_instance).to receive(:shell_out!).once.with(@selinux_enabled_path, {:returns=>[0, 1]}).and_return(cmd_result)
+ expect(@test_instance).to receive(:shell_out!).once.with(@selinux_enabled_path, { :returns => [0, 1] }).and_return(cmd_result)
end
it "should report selinux is enabled" do
@@ -75,7 +74,7 @@ describe Chef::Util::Selinux do
describe "when selinux is disabled" do
before do
cmd_result = double("Cmd Result", :exitstatus => 1)
- expect(@test_instance).to receive(:shell_out!).once.with(@selinux_enabled_path, {:returns=>[0, 1]}).and_return(cmd_result)
+ expect(@test_instance).to receive(:shell_out!).once.with(@selinux_enabled_path, { :returns => [0, 1] }).and_return(cmd_result)
end
it "should report selinux is disabled" do
@@ -88,11 +87,11 @@ describe Chef::Util::Selinux do
describe "when selinux gives an unexpected status" do
before do
cmd_result = double("Cmd Result", :exitstatus => 101)
- expect(@test_instance).to receive(:shell_out!).once.with(@selinux_enabled_path, {:returns=>[0, 1]}).and_return(cmd_result)
+ expect(@test_instance).to receive(:shell_out!).once.with(@selinux_enabled_path, { :returns => [0, 1] }).and_return(cmd_result)
end
it "should throw an error" do
- expect {@test_instance.selinux_enabled?}.to raise_error(RuntimeError)
+ expect { @test_instance.selinux_enabled? }.to raise_error(RuntimeError)
end
end
end
@@ -149,21 +148,10 @@ describe Chef::Util::Selinux do
end
describe "when restorecon doesn't exist on the system" do
- before do
- allow(File).to receive(:executable?) do |file_path|
- expect(file_path.end_with?("restorecon")).to be_truthy
- false
- end
- end
-
it "should log a warning message" do
- log = [ ]
- allow(Chef::Log).to receive(:warn) do |message|
- log << message
- end
-
+ allow(File).to receive(:executable?).with(/restorecon$/).and_return(false)
+ expect(Chef::Log).to receive(:warn).with(/Can not find 'restorecon' on the system. Skipping selinux security context restore./).at_least(:once)
@test_instance.restore_security_context(path)
- expect(log).not_to be_empty
expect(File).not_to receive(:executable?)
@test_instance.restore_security_context(path)
end
diff --git a/spec/unit/util/threaded_job_queue_spec.rb b/spec/unit/util/threaded_job_queue_spec.rb
index 22626328be..8a89943a8a 100644
--- a/spec/unit/util/threaded_job_queue_spec.rb
+++ b/spec/unit/util/threaded_job_queue_spec.rb
@@ -1,4 +1,4 @@
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
+require "spec_helper"
class WorkerThreadError < StandardError
end
diff --git a/spec/unit/version/platform_spec.rb b/spec/unit/version/platform_spec.rb
index dd425b32a5..cd2d37f5d4 100644
--- a/spec/unit/version/platform_spec.rb
+++ b/spec/unit/version/platform_spec.rb
@@ -1,5 +1,5 @@
# Author:: Xabier de Zuazo (<xabier@onddo.com>)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,13 +14,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
-require 'chef/version/platform'
+require "spec_helper"
+require "chef/version/platform"
describe Chef::Version::Platform do
it "is a subclass of Chef::Version" do
- v = Chef::Version::Platform.new('1.1')
+ v = Chef::Version::Platform.new("1.1")
expect(v).to be_an_instance_of(Chef::Version::Platform)
expect(v).to be_a_kind_of(Chef::Version)
end
@@ -30,7 +30,7 @@ describe Chef::Version::Platform do
end
describe "when creating valid Versions" do
- good_versions = %w(1 1.2 1.2.3 1000.80.50000 0.300.25 001.02.00003 1.2-STABLE 10.0-BETA3 9.1-RELEASE-p3)
+ good_versions = %w{1 1.2 1.2.3 1000.80.50000 0.300.25 001.02.00003 1.2-STABLE 10.0-BETA3 9.1-RELEASE-p3}
good_versions.each do |v|
it "should accept '#{v}'" do
Chef::Version::Platform.new v
@@ -58,4 +58,3 @@ describe Chef::Version::Platform do
end
end
-
diff --git a/spec/unit/version_class_spec.rb b/spec/unit/version_class_spec.rb
index fe1488550b..5543fbe3c7 100644
--- a/spec/unit/version_class_spec.rb
+++ b/spec/unit/version_class_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
-require 'chef/version_class'
+require "spec_helper"
+require "chef/version_class"
describe Chef::Version do
before do
@@ -44,7 +44,7 @@ describe Chef::Version do
end
describe "when creating valid Versions" do
- good_versions = %w(1.2 1.2.3 1000.80.50000 0.300.25 001.02.00003)
+ good_versions = %w{1.2 1.2.3 1000.80.50000 0.300.25 001.02.00003}
good_versions.each do |v|
it "should accept '#{v}'" do
Chef::Version.new v
@@ -90,7 +90,7 @@ describe Chef::Version do
["1.2", "1.3.0"],
["1.2", "1.3"],
["1.2", "2.1.1"],
- ["1.2", "2.1"]
+ ["1.2", "2.1"],
]
examples.each do |smaller, larger|
sm = Chef::Version.new(smaller)
@@ -105,7 +105,7 @@ describe Chef::Version do
a = %w{0.0.0 0.0.1 0.1.0 0.1.1 1.0.0 1.1.0 1.1.1}.map do |s|
Chef::Version.new(s)
end
- got = a.sort.map {|v| v.to_s }
+ got = a.sort.map { |v| v.to_s }
expect(got).to eq(%w{0.0.0 0.0.1 0.1.0 0.1.1 1.0.0 1.1.0 1.1.1})
end
@@ -158,7 +158,7 @@ describe Chef::Version do
[ "1.2.2", :>=, "1.2.1", true ],
[ "1.2.2", :==, "1.2.1", false ],
[ "1.2.2", :<=, "1.2.1", false ],
- [ "1.2.2", :<, "1.2.1", false ]
+ [ "1.2.2", :<, "1.2.1", false ],
].each do |spec|
it "(#{spec.first(3).join(' ')}) should be #{spec[3]}" do
got = Chef::Version.new(spec[0]).send(spec[1],
@@ -169,4 +169,3 @@ describe Chef::Version do
end
end
end
-
diff --git a/spec/unit/version_constraint/platform_spec.rb b/spec/unit/version_constraint/platform_spec.rb
index f38eb49689..593a47b903 100644
--- a/spec/unit/version_constraint/platform_spec.rb
+++ b/spec/unit/version_constraint/platform_spec.rb
@@ -1,5 +1,5 @@
# Author:: Xabier de Zuazo (<xabier@onddo.com>)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
-require 'chef/version_constraint/platform'
+require "spec_helper"
+require "chef/version_constraint/platform"
describe Chef::VersionConstraint::Platform do
@@ -43,4 +43,3 @@ describe Chef::VersionConstraint::Platform do
end
end
-
diff --git a/spec/unit/version_constraint_spec.rb b/spec/unit/version_constraint_spec.rb
index 0ae502f66d..f83af03fb7 100644
--- a/spec/unit/version_constraint_spec.rb
+++ b/spec/unit/version_constraint_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Seth Falcon (<seth@opscode.com>)
-# Copyright:: Copyright 2010 Opscode, Inc.
+# Author:: Seth Falcon (<seth@chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'spec_helper'
-require 'chef/version_constraint'
+require "spec_helper"
+require "chef/version_constraint"
describe Chef::VersionConstraint do
describe "validation" do
@@ -88,7 +88,7 @@ describe Chef::VersionConstraint do
expect(@vc).to include Chef::Version.new("1.4")
end
it "Chef::CookbookVersion" do
- cv = Chef::CookbookVersion.new("alice", '/tmp/blah.txt')
+ cv = Chef::CookbookVersion.new("alice", "/tmp/blah.txt")
cv.version = "1.4"
expect(@vc).to include cv
end
@@ -149,31 +149,31 @@ describe Chef::VersionConstraint do
end
end
- describe 'to_s' do
- it 'shows a patch-level if one is given' do
- vc = Chef::VersionConstraint.new '~> 1.2.0'
+ describe "to_s" do
+ it "shows a patch-level if one is given" do
+ vc = Chef::VersionConstraint.new "~> 1.2.0"
- expect(vc.to_s).to eq('~> 1.2.0')
+ expect(vc.to_s).to eq("~> 1.2.0")
end
- it 'shows no patch-level if one is not given' do
- vc = Chef::VersionConstraint.new '~> 1.2'
+ it "shows no patch-level if one is not given" do
+ vc = Chef::VersionConstraint.new "~> 1.2"
- expect(vc.to_s).to eq('~> 1.2')
+ expect(vc.to_s).to eq("~> 1.2")
end
end
- describe 'inspect' do
- it 'shows a patch-level if one is given' do
- vc = Chef::VersionConstraint.new '~> 1.2.0'
+ describe "inspect" do
+ it "shows a patch-level if one is given" do
+ vc = Chef::VersionConstraint.new "~> 1.2.0"
- expect(vc.inspect).to eq('(~> 1.2.0)')
+ expect(vc.inspect).to eq("(~> 1.2.0)")
end
- it 'shows no patch-level if one is not given' do
- vc = Chef::VersionConstraint.new '~> 1.2'
+ it "shows no patch-level if one is not given" do
+ vc = Chef::VersionConstraint.new "~> 1.2"
- expect(vc.inspect).to eq('(~> 1.2)')
+ expect(vc.inspect).to eq("(~> 1.2)")
end
end
end
diff --git a/spec/unit/win32/error_spec.rb b/spec/unit/win32/error_spec.rb
new file mode 100644
index 0000000000..e8b6d5af6a
--- /dev/null
+++ b/spec/unit/win32/error_spec.rb
@@ -0,0 +1,67 @@
+#
+# Author:: Aliasgar Batterywala (aliasgar.batterywala@msystechnologies.com)
+# Copyright:: Copyright 2017, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+if Chef::Platform.windows?
+ require "chef/win32/error"
+ require "chef/win32/api/error"
+end
+
+describe "Chef::Win32::Error", :windows_only do
+ describe "self.raise!" do
+ context "code is not passed to the raise! method" do
+ context "last error received is user_not_found" do
+ it "raises UserIDNotFound exception" do
+ expect(Chef::ReservedNames::Win32::Error).to receive(:get_last_error).and_return(
+ Chef::ReservedNames::Win32::API::Error::ERROR_USER_NOT_FOUND
+ )
+ expect(Chef::ReservedNames::Win32::Error).to receive_message_chain(:format_message, :strip)
+ expect { Chef::ReservedNames::Win32::Error.raise! }.to raise_error Chef::Exceptions::UserIDNotFound
+ end
+ end
+
+ context "last error received is not user_not_found" do
+ it "raises Win32APIError exception" do
+ expect(Chef::ReservedNames::Win32::Error).to receive(:get_last_error).and_return(
+ Chef::ReservedNames::Win32::API::Error::ERROR_BAD_USERNAME
+ )
+ expect(Chef::ReservedNames::Win32::Error).to receive_message_chain(:format_message, :strip).and_return("Bad Username")
+ expect { Chef::ReservedNames::Win32::Error.raise! }.to raise_error Chef::Exceptions::Win32APIError
+ end
+ end
+ end
+
+ context "code is passed to the raise! method" do
+ context "last error received is user_not_found" do
+ it "raises UserIDNotFound exception" do
+ expect(Chef::ReservedNames::Win32::Error).to_not receive(:get_last_error)
+ expect(Chef::ReservedNames::Win32::Error).to receive_message_chain(:format_message, :strip)
+ expect { Chef::ReservedNames::Win32::Error.raise! nil, Chef::ReservedNames::Win32::API::Error::ERROR_USER_NOT_FOUND }.to raise_error Chef::Exceptions::UserIDNotFound
+ end
+ end
+
+ context "last error received is not user_not_found" do
+ it "raises Win32APIError exception" do
+ expect(Chef::ReservedNames::Win32::Error).to_not receive(:get_last_error)
+ expect(Chef::ReservedNames::Win32::Error).to receive_message_chain(:format_message, :strip).and_return("Bad Username")
+ expect { Chef::ReservedNames::Win32::Error.raise! nil, Chef::ReservedNames::Win32::API::Error::ERROR_BAD_USERNAME }.to raise_error Chef::Exceptions::Win32APIError
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/win32/registry_spec.rb b/spec/unit/win32/registry_spec.rb
index 56def30638..1523ac1919 100644
--- a/spec/unit/win32/registry_spec.rb
+++ b/spec/unit/win32/registry_spec.rb
@@ -1,6 +1,6 @@
#
-# Author:: Prajakta Purohit (prajakta@opscode.com)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Prajakta Purohit (prajakta@chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,19 @@
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
describe Chef::Win32::Registry do
include_context "Win32"
let(:value1) { { :name => "one", :type => :string, :data => "1" } }
- let(:value1_upcase_name) { {:name => "ONE", :type => :string, :data => "1"} }
+ let(:value1_upcase_name) { { :name => "ONE", :type => :string, :data => "1" } }
let(:key_path) { 'HKCU\Software\OpscodeNumbers' }
let(:key) { 'Software\OpscodeNumbers' }
- let(:key_parent) { 'Software' }
- let(:key_to_delete) { 'OpscodeNumbers' }
- let(:sub_key) {'OpscodePrimes'}
- let(:missing_key_path) {'HKCU\Software'}
+ let(:key_parent) { "Software" }
+ let(:key_to_delete) { "OpscodeNumbers" }
+ let(:sub_key) { "OpscodePrimes" }
+ let(:missing_key_path) { 'HKCU\Software' }
let(:registry) { Chef::Win32::Registry.new() }
let(:hive_mock) { double("::Win32::Registry::KHKEY_CURRENT_USER") }
let(:reg_mock) { double("reg") }
@@ -40,7 +40,7 @@ describe Chef::Win32::Registry do
before(:each) do
allow_any_instance_of(Chef::Win32::Registry).to receive(:machine_architecture).and_return(:x86_64)
-
+
#Making the values for registry constants available on unix
Win32::Registry::KEY_SET_VALUE = 0x0002
Win32::Registry::KEY_QUERY_VALUE = 0x0001
@@ -49,10 +49,10 @@ describe Chef::Win32::Registry do
end
after(:each) do
- Win32::Registry.send(:remove_const, 'KEY_SET_VALUE') if defined?(Win32::Registry::KEY_SET_VALUE)
- Win32::Registry.send(:remove_const, 'KEY_QUERY_VALUE') if defined?(Win32::Registry::KEY_QUERY_VALUE)
- Win32::Registry.send(:remove_const, 'KEY_READ') if defined?(Win32::Registry::KEY_READ)
- Win32::Registry.send(:remove_const, 'KEY_WRITE') if defined?(Win32::Registry::KEY_WRITE)
+ Win32::Registry.send(:remove_const, "KEY_SET_VALUE") if defined?(Win32::Registry::KEY_SET_VALUE)
+ Win32::Registry.send(:remove_const, "KEY_QUERY_VALUE") if defined?(Win32::Registry::KEY_QUERY_VALUE)
+ Win32::Registry.send(:remove_const, "KEY_READ") if defined?(Win32::Registry::KEY_READ)
+ Win32::Registry.send(:remove_const, "KEY_WRITE") if defined?(Win32::Registry::KEY_WRITE)
end
describe "get_values" do
@@ -67,7 +67,7 @@ describe Chef::Win32::Registry do
it "throws an exception if key does not exist" do
expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
expect(registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
- expect{registry.get_values(key_path)}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { registry.get_values(key_path) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
end
@@ -116,7 +116,7 @@ describe Chef::Win32::Registry do
it "should raise an exception if the key does not exist" do
expect(registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
- expect {registry.set_value(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { registry.set_value(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
end
@@ -153,7 +153,7 @@ describe Chef::Win32::Registry do
it "raises an exception if intermediate keys are missing and recursive is set to false" do
expect(registry).to receive(:keys_missing?).with(key_path).and_return(true)
- expect{registry.create_key(key_path, false)}.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+ expect { registry.create_key(key_path, false) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
end
it "does nothing if the key exists" do
@@ -193,7 +193,7 @@ describe Chef::Win32::Registry do
it "raises an exception if it has subkeys but recursive is set to false" do
expect(registry).to receive(:key_exists?).with(key_path).and_return(true)
expect(registry).to receive(:has_subkeys?).with(key_path).and_return(true)
- expect{registry.delete_key(key_path, false)}.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+ expect { registry.delete_key(key_path, false) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
end
it "deletes key if the key exists and has no subkeys" do
@@ -223,7 +223,7 @@ describe Chef::Win32::Registry do
describe "key_exists!" do
it "throws an exception if the key_parent does not exist" do
expect(registry).to receive(:key_exists?).with(key_path).and_return(false)
- expect{registry.key_exists!(key_path)}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { registry.key_exists!(key_path) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
end
@@ -258,7 +258,7 @@ describe Chef::Win32::Registry do
it "throws an exception if the key does not exist" do
expect(registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
- expect {registry.set_value(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { registry.set_value(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
end
@@ -275,7 +275,7 @@ describe Chef::Win32::Registry do
describe "value_exists?" do
it "throws an exception if the key does not exist" do
expect(registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
- expect {registry.value_exists?(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { registry.value_exists?(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "returns true if the value exists" do
@@ -298,7 +298,7 @@ describe Chef::Win32::Registry do
describe "data_exists?" do
it "throws an exception if the key does not exist" do
expect(registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
- expect {registry.data_exists?(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+ expect { registry.data_exists?(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
end
it "returns true if the data exists" do
@@ -328,7 +328,7 @@ describe Chef::Win32::Registry do
it "throws an exception if the value does not exist" do
expect(registry).to receive(:value_exists?).with(key_path, value1).and_return(false)
- expect{registry.value_exists!(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegValueMissing)
+ expect { registry.value_exists!(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegValueMissing)
end
end
@@ -340,7 +340,7 @@ describe Chef::Win32::Registry do
it "throws an exception if the data does not exist" do
expect(registry).to receive(:data_exists?).with(key_path, value1).and_return(false)
- expect{registry.data_exists!(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegDataMissing)
+ expect { registry.data_exists!(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegDataMissing)
end
end
@@ -364,7 +364,7 @@ describe Chef::Win32::Registry do
it "throws an exception if value does not exist" do
expect(registry).to receive(:value_exists?).with(key_path, value1).and_return(false)
- expect{registry.type_matches?(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegValueMissing)
+ expect { registry.type_matches?(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegValueMissing)
end
end
@@ -376,7 +376,7 @@ describe Chef::Win32::Registry do
it "throws an exception if the type does not match" do
expect(registry).to receive(:type_matches?).with(key_path, value1).and_return(false)
- expect{registry.type_matches!(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegTypesMismatch)
+ expect { registry.type_matches!(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegTypesMismatch)
end
end
diff --git a/spec/unit/win32/security_spec.rb b/spec/unit/win32/security_spec.rb
new file mode 100644
index 0000000000..1c755061ce
--- /dev/null
+++ b/spec/unit/win32/security_spec.rb
@@ -0,0 +1,66 @@
+#
+# Author:: Aliasgar Batterywala (aliasgar.batterywala@msystechnologies.com)
+# Copyright:: Copyright 2017, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+if Chef::Platform.windows?
+ require "chef/win32/error"
+ require "chef/win32/security"
+ require "chef/win32/api/error"
+end
+
+describe "Chef::Win32::Security", :windows_only do
+ describe "self.get_named_security_info" do
+ context "when HR result is ERROR_SUCCESS" do
+ it "does not raise the exception" do
+ expect(Chef::ReservedNames::Win32::Security).to receive(:GetNamedSecurityInfoW).and_return(
+ Chef::ReservedNames::Win32::API::Error::ERROR_SUCCESS
+ )
+ expect { Chef::ReservedNames::Win32::Security.get_named_security_info "/temp_path" }.to_not raise_error
+ end
+ end
+
+ context "when HR result is not ERROR_SUCCESS and not ERROR_USER_NOT_FOUND" do
+ it "raises Win32APIError exception" do
+ expect(Chef::ReservedNames::Win32::Security).to receive(:GetNamedSecurityInfoW).and_return(
+ Chef::ReservedNames::Win32::API::Error::ERROR_INVALID_ACCESS
+ )
+ expect { Chef::ReservedNames::Win32::Security.get_named_security_info "/temp_path" }.to raise_error Chef::Exceptions::Win32APIError
+ end
+ end
+ end
+
+ describe "self.set_named_security_info" do
+ context "when HR result is ERROR_SUCCESS" do
+ it "does not raise the exception" do
+ expect(Chef::ReservedNames::Win32::Security).to receive(:SetNamedSecurityInfoW).and_return(
+ Chef::ReservedNames::Win32::API::Error::ERROR_SUCCESS
+ )
+ expect { Chef::ReservedNames::Win32::Security.set_named_security_info "/temp_path", :SE_FILE_OBJECT, {} }.to_not raise_error
+ end
+ end
+
+ context "when HR result is not ERROR_SUCCESS but it is ERROR_USER_NOT_FOUND" do
+ it "raises UserIDNotFound exception" do
+ expect(Chef::ReservedNames::Win32::Security).to receive(:SetNamedSecurityInfoW).and_return(
+ Chef::ReservedNames::Win32::API::Error::ERROR_USER_NOT_FOUND
+ )
+ expect { Chef::ReservedNames::Win32::Security.set_named_security_info "/temp_path", :SE_FILE_OBJECT, {} }.to raise_error Chef::Exceptions::Chef::Exceptions::UserIDNotFound
+ end
+ end
+ end
+end
diff --git a/spec/unit/windows_service_spec.rb b/spec/unit/windows_service_spec.rb
index 396584716d..3555b70f1b 100644
--- a/spec/unit/windows_service_spec.rb
+++ b/spec/unit/windows_service_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Mukta Aphale (<mukta.aphale@clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,65 +15,102 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'spec_helper'
+require "spec_helper"
if Chef::Platform.windows?
- require 'chef/application/windows_service'
+ require "chef/application/windows_service"
end
describe "Chef::Application::WindowsService", :windows_only do
- let (:instance) {Chef::Application::WindowsService.new}
- let (:shell_out_result) {Object.new}
- let (:tempfile) {Tempfile.new "log_file"}
+ let(:shell_out_result) { double("shellout", stdout: nil, stderr: nil) }
+ let(:config_options) do
+ {
+ log_location: STDOUT,
+ config_file: "test_config_file",
+ log_level: :info,
+ }
+ end
+ let(:timeout) { 7200 }
+ let(:shellout_options) do
+ {
+ :timeout => timeout,
+ :logger => Chef::Log,
+ }
+ end
+
before do
- allow(instance).to receive(:parse_options)
- allow(shell_out_result).to receive(:stdout)
- allow(shell_out_result).to receive(:stderr)
+ Chef::Config.merge!(config_options)
+ allow(subject).to receive(:configure_chef)
+ allow(subject).to receive(:parse_options)
+ allow(MonoLogger).to receive(:new)
+ allow(subject).to receive(:running?).and_return(true, false)
+ allow(subject).to receive(:state).and_return(4)
+ subject.service_init
end
- it "runs chef-client in new process" do
- expect(instance).to receive(:configure_chef).twice
- instance.service_init
- expect(instance).to receive(:run_chef_client).and_call_original
- expect(instance).to receive(:shell_out).and_return(shell_out_result)
- allow(instance).to receive(:running?).and_return(true, false)
- allow(instance.instance_variable_get(:@service_signal)).to receive(:wait)
- allow(instance).to receive(:state).and_return(4)
- instance.service_main
+
+ subject { Chef::Application::WindowsService.new }
+
+ it "passes DEFAULT_LOG_LOCATION to chef-client instead of STDOUT" do
+ expect(subject).to receive(:shell_out).with(
+ "chef-client.bat --no-fork -c test_config_file -L #{Chef::Application::WindowsService::DEFAULT_LOG_LOCATION}",
+ shellout_options
+ ).and_return(shell_out_result)
+ subject.service_main
end
- context 'when running chef-client' do
- it "passes config params to new process with a default timeout of 2 hours (7200 seconds)" do
- Chef::Config.merge!({:log_location => tempfile.path, :config_file => "test_config_file", :log_level => :info})
- expect(instance).to receive(:configure_chef).twice
- instance.service_init
- allow(instance).to receive(:running?).and_return(true, false)
- allow(instance.instance_variable_get(:@service_signal)).to receive(:wait)
- allow(instance).to receive(:state).and_return(4)
- expect(instance).to receive(:run_chef_client).and_call_original
- expect(instance).to receive(:shell_out).with("chef-client --no-fork -c test_config_file -L #{tempfile.path}",
- {
- :timeout => 7200,
- :logger => Chef::Log
- }).and_return(shell_out_result)
- instance.service_main
+ context "has a log location configured" do
+ let(:tempfile) { Tempfile.new "log_file" }
+ let(:config_options) do
+ {
+ log_location: tempfile.path,
+ config_file: "test_config_file",
+ log_level: :info,
+ }
+ end
+
+ after do
tempfile.unlink
end
- it "passes config params to new process with a the timeout specified in the config" do
- Chef::Config.merge!({:log_location => tempfile.path, :config_file => "test_config_file", :log_level => :info})
- Chef::Config[:windows_service][:watchdog_timeout] = 10
- expect(instance).to receive(:configure_chef).twice
- instance.service_init
- allow(instance).to receive(:running?).and_return(true, false)
- allow(instance.instance_variable_get(:@service_signal)).to receive(:wait)
- allow(instance).to receive(:state).and_return(4)
- expect(instance).to receive(:run_chef_client).and_call_original
- expect(instance).to receive(:shell_out).with("chef-client --no-fork -c test_config_file -L #{tempfile.path}",
+ it "uses the configured log location" do
+ expect(subject).to receive(:shell_out).with(
+ "chef-client.bat --no-fork -c test_config_file -L #{tempfile.path}",
+ shellout_options
+ ).and_return(shell_out_result)
+ subject.service_main
+ end
+
+ context "configured to Event Logger" do
+ let(:config_options) do
{
- :timeout => 10,
- :logger => Chef::Log
- }).and_return(shell_out_result)
- instance.service_main
- tempfile.unlink
+ log_location: Chef::Log::WinEvt.new,
+ config_file: "test_config_file",
+ log_level: :info,
+ }
+ end
+
+ it "does not pass log location to new process" do
+ expect(subject).to receive(:shell_out).with(
+ "chef-client.bat --no-fork -c test_config_file",
+ shellout_options
+ ).and_return(shell_out_result)
+ subject.service_main
+ end
+ end
+ end
+
+ context "configueres a watchdog timeout" do
+ let(:timeout) { 10 }
+
+ before do
+ Chef::Config[:windows_service][:watchdog_timeout] = 10
+ end
+
+ it "passes watchdog timeout to new process" do
+ expect(subject).to receive(:shell_out).with(
+ "chef-client.bat --no-fork -c test_config_file -L #{Chef::Application::WindowsService::DEFAULT_LOG_LOCATION}",
+ shellout_options
+ ).and_return(shell_out_result)
+ subject.service_main
end
end
end
diff --git a/tasks/announce.rb b/tasks/announce.rb
new file mode 100644
index 0000000000..0399137eb0
--- /dev/null
+++ b/tasks/announce.rb
@@ -0,0 +1,58 @@
+#
+# Copyright:: Copyright (c) 2016 Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "date"
+require "erb"
+
+class ReleaseAnnouncement
+ include ERB::Util
+ attr_accessor :type, :version, :maj_minor, :date, :release_notes
+
+ def initialize(version, date, type)
+ @version = version
+ @maj_minor = version.split(".")[0..1].join(".")
+ @date = Date.parse(date) unless date.nil?
+ @release_notes = release_notes_from_file
+ @type = type
+ end
+
+ def render
+ puts "-" * 30
+ puts ERB.new(template_for(@type)).result(binding)
+ puts "-" * 30
+ end
+
+ def template_for(type)
+ File.read("tasks/templates/#{type}.md.erb")
+ end
+
+ def release_notes_from_file
+ File.read("RELEASE_NOTES.md").match(/^# Chef Client Release Notes #{@maj_minor}:\n\n(.*)/m)[1]
+ end
+end
+
+namespace :announce do
+ desc "Generate the Prerelease Announcement (version: X.Y.Z, release_date: YYYY-MM-DD)"
+ task :prerelease, :version, :release_date do |t, args|
+ ReleaseAnnouncement.new(args[:version], args[:release_date], "prerelease").render
+ end
+
+ desc "Generate the Release Announcement (version: X.Y.Z)"
+ task :release, :version do |t, args|
+ ReleaseAnnouncement.new(args[:version], nil, "release").render
+ end
+end
diff --git a/tasks/bin/bundle-platform b/tasks/bin/bundle-platform
new file mode 100755
index 0000000000..aaf433c98d
--- /dev/null
+++ b/tasks/bin/bundle-platform
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+require_relative "bundler_patch"
+
+platforms = ARGV.shift
+platforms = platforms.split(" ").map { |p| Gem::Platform.new(p) }
+Gem::Platform.instance_eval { @local = platforms.last }
+old_platforms = Gem.platforms
+Gem.platforms = platforms
+puts "bundle-platform set Gem.platforms to #{Gem.platforms.map { |p| p.to_s }} (was #{old_platforms.map { |p| p.to_s }})"
+
+desired_version = ARGV.shift.delete("_")
+
+# The rest of this is a normal bundler binstub
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+
+load Gem.bin_path("bundler", "bundle", desired_version)
diff --git a/tasks/bin/bundle-platform.bat b/tasks/bin/bundle-platform.bat
new file mode 100644
index 0000000000..d193eb0c05
--- /dev/null
+++ b/tasks/bin/bundle-platform.bat
@@ -0,0 +1,2 @@
+@ECHO OFF
+ruby "%~dpn0" %*
diff --git a/tasks/bin/bundler_patch.rb b/tasks/bin/bundler_patch.rb
new file mode 100644
index 0000000000..5665e44eca
--- /dev/null
+++ b/tasks/bin/bundler_patch.rb
@@ -0,0 +1,27 @@
+# This is a temporary monkey patch to address https://github.com/bundler/bundler/issues/4896
+# the heart of the fix is line #18 with the addition of:
+# && (possibility.activated - existing_node.payload.activated).empty?
+# This ensures we do not mis linux platform gems in some scenarios like ffi in kitchen-test.
+# There is a permanent fix to bundler (See https://github.com/bundler/bundler/pull/4836) which
+# is due to ship in v1.14. Once we adopt that version, we can remove this file
+
+require "bundler"
+require "bundler/vendor/molinillo/lib/molinillo/resolution"
+
+module Bundler::Molinillo
+ class Resolver
+ # A specific resolution from a given {Resolver}
+ class Resolution
+ def attempt_to_activate
+ debug(depth) { "Attempting to activate " + possibility.to_s }
+ existing_node = activated.vertex_named(name)
+ if existing_node.payload && (possibility.activated - existing_node.payload.activated).empty?
+ debug(depth) { "Found existing spec (#{existing_node.payload})" }
+ attempt_to_activate_existing_spec(existing_node)
+ else
+ attempt_to_activate_new_spec
+ end
+ end
+ end
+ end
+end
diff --git a/tasks/bin/create-override-gemfile b/tasks/bin/create-override-gemfile
new file mode 100755
index 0000000000..b67da025d2
--- /dev/null
+++ b/tasks/bin/create-override-gemfile
@@ -0,0 +1,110 @@
+#!/usr/bin/env ruby
+
+require "rubygems"
+require "bundler"
+
+Bundler.with_clean_env do
+ require_relative "../gemfile_util"
+
+ options = {}
+ opts = OptionParser.new do |opts|
+ opts.banner = "Usage: create-override-gemfile [OPTIONS]"
+
+ opts.on("--gemfile GEMFILE", "The Gemfile to read (default: Gemfile).") { |path| options[:gemfile_path] = path }
+ opts.on("--lockfile GEMFILE", "The lockfile to read (default: <gemfile>.lock).") { |path| options[:lockfile_path] = path }
+
+ opts.on("--group GROUP", "Groups to include (whitelist).") do |group|
+ options[:groups] ||= []
+ options[:groups] << group.to_sym
+ end
+
+ opts.on("--without GROUP", "Groups to exclude.") do |group|
+ options[:without_groups] ||= []
+ options[:without_groups] << group.to_sym
+ end
+
+ opts.on("--gem GEM", "Gems to include regardless of groups.") do |name|
+ options[:gems] ||= []
+ options[:gems] << name
+ end
+
+ opts.on("--relative-to PATH", "A path to prepend to any relative paths in the Gemfile.") do |path|
+ unless Pathname.new(path).absolute?
+ puts opts
+ raise "--relative-to #{path} was not an absolute path!"
+ end
+ options[:relative_to] = path
+ end
+
+ opts.on("--[no-]copy-groups", "Whether to copy groups over from the original Gemfile or not (default: false).") { |val| options[:copy_groups] = val }
+
+ opts.on("--[no-]override", "Whether to emit override: true on each gem line (default: false).") { |val| options[:override] = val }
+
+ opts.on("-h", "--help", "Print this message.") do
+ puts opts
+ exit(0)
+ end
+ end
+
+ args = opts.parse(ARGV)
+
+ if args.size > 0
+ puts opts
+ raise "Invalid arguments #{args}"
+ end
+
+ def create_override_gemfile(gemfile_path: "Gemfile", lockfile_path: "#{gemfile_path}.lock", groups: nil, without_groups: nil, gems: [], copy_groups: false, relative_to: ".", override: false)
+ relative_to = Pathname.new(relative_to).realpath
+ # Select the gems we want
+ bundle = GemfileUtil::Bundle.parse(gemfile_path, lockfile_path)
+ gems_to_include = bundle.select_gems(groups: groups, without_groups: without_groups)
+ gems.each do |name|
+ raise "Requested gem #{name} is not in #{gemfile_path}.lock!" if !bundle.gems[name]
+ gems_to_include[name] ||= bundle.gems[name]
+ gems_to_include[name][:dependencies].each do |dep|
+ gems_to_include[name] ||= bundle.gems[dep]
+ end
+ end
+
+ # Add the gems to the Gemfile
+ gem_root = Pathname.new(gemfile_path).dirname.realpath
+ gems_to_include.sort_by { |name, options| options[:declared_groups].empty? ? 1 : 0 }.each do |name, options|
+ comment = nil
+ options = options.dup
+ version = options.delete(:version)
+ if copy_groups
+ # Some dependencies have no groups (are not in the Gemfile--just runtime
+ # dependencies). If we actually record that they have no groups, they
+ # will *always* be installed (or perhaps never). We only want them to
+ # install if their other deps do, so we mark them with the groups of the
+ # things that brought them in (the gems that depended on them). To do
+ # this, we just leave :groups intact.
+ if options[:declared_groups].empty?
+ options.delete(:declared_groups)
+ comment = " # Transitive dependency, not actually in original Gemfile"
+ else
+ # For other things, we want to copy the actual declared_groups--the
+ # ones that were in the Gemfile. We want the same --with and --without
+ # options to include and exclude them as worked with the original
+ # Gemfile.
+ options[:groups] = options.delete(:declared_groups)
+ end
+ else
+ options.delete(:groups)
+ options.delete(:declared_groups)
+ end
+ options.delete(:dependencies)
+ options.delete(:development_dependencies)
+ options[:override] = true if override
+ options[:path] = Pathname.new(options[:path]).expand_path(gem_root).relative_path_from(relative_to).to_s if options[:path]
+ line = "gem #{name.inspect}, #{version.inspect}"
+ options.each do |name, value|
+ line << ", #{name}: #{value.inspect}"
+ end
+ line << comment if comment
+ puts line
+ end
+ end
+
+ create_override_gemfile(options)
+end
diff --git a/tasks/bin/gem-version-diff b/tasks/bin/gem-version-diff
new file mode 100755
index 0000000000..617402d4e6
--- /dev/null
+++ b/tasks/bin/gem-version-diff
@@ -0,0 +1,37 @@
+#!/usr/bin/env ruby
+
+require_relative "../../version_policy"
+
+old_version, new_version = ARGV[0..1]
+
+require "set"
+ENV["BUNDLE_WITHOUT"] = INSTALL_WITHOUT_GROUPS.join(":")
+relevant_gems = Set.new
+`bundle list`.each_line do |line|
+ next unless line =~ /^ \* (\S+)/
+ relevant_gems.add($1)
+end
+
+old_gems = {}
+old_file = `git show #{old_version}:Gemfile.lock`
+old_file.each_line do |line|
+ next unless line =~ /^ (\S+) \(([^\)]+)\)$/
+ next unless relevant_gems.include?($1)
+ old_gems[$1] = $2
+end
+
+new_gems = {}
+new_file = `git show #{new_version}:Gemfile.lock`
+new_file.each_line do |line|
+ next unless line =~ /^ (\S+) \(([^\)]+)\)$/
+ next unless relevant_gems.include?($1)
+ new_gems[$1] = $2
+end
+
+modified_gems = (old_gems.keys & new_gems.keys).sort.select { |name| new_gems[name] != old_gems[name] }.map { |name| "#{name} - #{new_gems[name]} (was #{old_gems[name]})" }
+removed_gems = (old_gems.keys - new_gems.keys).sort.map { |name| "#{name} - #{old_gems[name]}" }
+added_gems = (new_gems.keys - old_gems.keys).sort.map { |name| "#{name} - #{new_gems[name]}" }
+
+puts "MODIFIED:\n#{modified_gems.join("\n")}" if modified_gems.any?
+puts "\nADDED:\n#{added_gems.join("\n")}" if added_gems.any?
+puts "\nREMOVED:\n#{removed_gems.join("\n")}" if removed_gems.any?
diff --git a/tasks/bin/run_external_test b/tasks/bin/run_external_test
new file mode 100755
index 0000000000..74f76d3229
--- /dev/null
+++ b/tasks/bin/run_external_test
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# Fail fast (e) and echo commands (vx)
+set -evx
+
+# Arguments
+TEST_GEM=$1
+shift
+
+PROJECT_ROOT=$(pwd)
+PROJECT_BUNDLE_PATH=${BUNDLE_PATH:-$(grep BUNDLE_PATH: $PROJECT_ROOT/.bundle/config | cut -d' ' -f2-)}
+if [ -n "$PROJECT_BUNDLE_PATH" ]; then
+ PROJECT_BUNDLE_PATH=$PROJECT_ROOT/$PROJECT_BUNDLE_PATH
+fi
+
+TEST_GEM_ROOT=$(bundle show $TEST_GEM)
+
+# Make a copy of the original Gemfile and stitch in our Gemfile.lock
+TEST_GEMFILE=$TEST_GEM_ROOT/Gemfile
+MODIFIED_TEST_GEMFILE=$TEST_GEMFILE.externaltest
+cat <<EOM > $MODIFIED_TEST_GEMFILE
+require_relative "$PROJECT_ROOT/tasks/gemfile_util"
+GemfileUtil.include_locked_gemfile(self, "$PROJECT_ROOT/Gemfile", gems: ["$TEST_GEM"] + "$TEST_WITH_GEMS".split(/\s+/))
+$TEST_GEM_OVERRIDES
+EOM
+cat $TEST_GEMFILE >> $MODIFIED_TEST_GEMFILE
+if [ -f $TEST_GEMFILE.lock ]; then
+ cp $TEST_GEMFILE.lock $MODIFIED_TEST_GEMFILE.lock
+elif [ -f $MODIFIED_TEST_GEMFILE.lock ]; then
+ rm -f $MODIFIED_TEST_GEMFILE.lock
+fi
+
+# Run the bundle install
+cd $TEST_GEM_ROOT
+export BUNDLE_GEMFILE=$MODIFIED_TEST_GEMFILE
+# Don't read from the project .bundle/config, just our env vars
+export BUNDLE_IGNORE_CONFIG=true
+# Use the top level bundle cache so we don't have to reinstall their packages
+if [ -n "$PROJECT_BUNDLE_PATH" ]; then
+ export BUNDLE_PATH=$PROJECT_BUNDLE_PATH
+fi
+export BUNDLE_FROZEN=
+bundle install
+export BUNDLE_FROZEN=true
+
+bundle config
+bundle exec $@
diff --git a/tasks/bundle.rb b/tasks/bundle.rb
new file mode 100644
index 0000000000..0176fe209e
--- /dev/null
+++ b/tasks/bundle.rb
@@ -0,0 +1,97 @@
+#
+# Copyright:: Copyright (c) 2016 Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require_relative "bundle_util"
+require_relative "../version_policy"
+require "fileutils"
+
+desc "Tasks to work with the main Gemfile and Gemfile.<platform>"
+namespace :bundle do
+ desc "Update Gemfile.lock and all Gemfile.<platform>.locks (or one or more gems via bundle:update gem1 gem2 ...)."
+ task :update, [:args] do |t, rake_args|
+ extend BundleUtil
+ args = rake_args[:args] || ""
+ with_bundle_unfrozen do
+ puts ""
+ puts "-------------------------------------------------------------------"
+ puts "Updating Gemfile.lock ..."
+ puts "-------------------------------------------------------------------"
+ bundle "update #{args}"
+ platforms.each do |platform|
+ bundle "update #{args}", platform: platform
+ end
+ end
+ end
+
+ desc "Conservatively update Gemfile.lock and all Gemfile.<platform>.locks"
+ task :install, [:args] do |t, rake_args|
+ extend BundleUtil
+ args = rake_args[:args] || ""
+ with_bundle_unfrozen do
+ puts ""
+ puts "-------------------------------------------------------------------"
+ puts "Updating Gemfile.lock ..."
+ puts "-------------------------------------------------------------------"
+ bundle "install #{args}"
+ platforms.each do |platform|
+ bundle "lock", platform: platform
+ end
+ end
+ end
+
+ # Find out if we're using the latest gems we can (so we don't regress versions)
+ desc "Check for gems that are not at the latest released version, and report if anything not in ACCEPTABLE_OUTDATED_GEMS (version_policy.rb) is out of date."
+ task :outdated do
+ extend BundleUtil
+ puts ""
+ puts "-------------------------------------------------------------------"
+ puts "Checking for outdated gems ..."
+ puts "-------------------------------------------------------------------"
+ # TODO check for outdated windows gems too
+ with_bundle_unfrozen do
+ bundle_outdated = bundle("outdated", extract_output: true)
+ puts bundle_outdated
+ outdated_gems = parse_bundle_outdated(bundle_outdated).map { |line, gem_name| gem_name }
+ # Weed out the acceptable ones
+ outdated_gems = outdated_gems.reject { |gem_name| ACCEPTABLE_OUTDATED_GEMS.include?(gem_name) }
+ if outdated_gems.empty?
+ puts ""
+ puts "SUCCESS!"
+ else
+ raise "ERROR: outdated gems: #{outdated_gems.join(", ")}. Either fix them or add them to ACCEPTABLE_OUTDATED_GEMS in #{__FILE__}."
+ end
+ end
+ end
+end
+
+desc "Run bundle with arbitrary args against the given platform; e.g. rake bundle[show]. No platform to run against the main bundle; bundle[show,windows] to run the windows one; bundle[show,*] to run against all non-default platforms."
+task :bundle, [:args, :platform] do |t, rake_args|
+ extend BundleUtil
+ args = rake_args[:args] || ""
+ platform = rake_args[:platform]
+ with_bundle_unfrozen do
+ if platform == "*"
+ platforms.each do |platform|
+ bundle args, platform: platform
+ end
+ elsif platform
+ bundle args, platform: platform
+ else
+ bundle args
+ end
+ end
+end
diff --git a/tasks/bundle_util.rb b/tasks/bundle_util.rb
new file mode 100644
index 0000000000..67647dd4f0
--- /dev/null
+++ b/tasks/bundle_util.rb
@@ -0,0 +1,110 @@
+require "bundler"
+require "shellwords"
+
+module BundleUtil
+ PLATFORMS = { "windows" => %w{ruby x86-mingw32} }
+
+ def project_root
+ File.expand_path("../..", __FILE__)
+ end
+
+ def bundle_platform
+ File.join(project_root, "tasks", "bin", "bundle-platform")
+ end
+
+ # Parse the output of "bundle outdated" and get the list of gems that
+ # were outdated
+ def parse_bundle_outdated(bundle_outdated_output)
+ result = []
+ bundle_outdated_output.each_line do |line|
+ if line =~ /^\s*\* (.+) \(newest ([^,]+), installed ([^,)])*/
+ gem_name, newest_version, installed_version = $1, $2, $3
+ result << [ line, gem_name ]
+ end
+ end
+ result
+ end
+
+ def with_bundle_unfrozen(cwd: nil, leave_frozen: false)
+ bundle "config --delete frozen", cwd: cwd
+ begin
+ yield
+ ensure
+ bundle "config --local frozen 1", cwd: cwd unless leave_frozen
+ end
+ end
+
+ # Run bundle-platform with the given ruby platform(s)
+ def bundle(args, gemfile: nil, platform: nil, cwd: nil, extract_output: false, delete_gemfile_lock: false)
+ args = args.split(/\s+/)
+ if cwd
+ prefix = "[#{cwd}] "
+ end
+ cwd = File.expand_path(cwd || ".", project_root)
+ Bundler.with_clean_env do
+ Dir.chdir(cwd) do
+ gemfile ||= "Gemfile"
+ gemfile = File.expand_path(gemfile, cwd)
+ raise "No platform #{platform} (supported: #{PLATFORMS.keys.join(", ")})" if platform && !PLATFORMS[platform]
+
+ # First delete the gemfile.lock
+ if delete_gemfile_lock
+ if File.exist?("#{gemfile}.lock")
+ puts "Deleting #{gemfile}.lock ..."
+ File.delete("#{gemfile}.lock")
+ end
+ end
+
+ # Run the bundle command
+ ruby_platforms = platform ? PLATFORMS[platform].join(" ") : "ruby"
+ cmd = Shellwords.join([
+ Gem.ruby,
+ "-S",
+ bundle_platform,
+ ruby_platforms,
+ "_#{desired_bundler_version}_",
+ *args,
+ ])
+ puts "#{prefix}#{Shellwords.join(["bundle", *args])}#{platform ? " for #{platform} platform" : ""}:"
+ with_gemfile(gemfile) do
+ puts "#{prefix}BUNDLE_GEMFILE=#{gemfile}"
+ puts "#{prefix}> #{cmd}"
+ if extract_output
+ `#{cmd}`
+ else
+ unless system(bundle_platform, ruby_platforms, "_#{desired_bundler_version}_", *args)
+ raise "#{bundle_platform} failed: exit code #{$?}"
+ end
+ end
+ end
+ end
+ end
+ end
+
+ def with_gemfile(gemfile)
+ old_gemfile = ENV["BUNDLE_GEMFILE"]
+ ENV["BUNDLE_GEMFILE"] = gemfile
+ begin
+ yield
+ ensure
+ if old_gemfile
+ ENV["BUNDLE_GEMFILE"] = old_gemfile
+ else
+ ENV.delete("BUNDLE_GEMFILE")
+ end
+ end
+ end
+
+ def platforms
+ PLATFORMS.keys
+ end
+
+ def desired_bundler_version
+ @desired_bundler_version ||= begin
+ omnibus_overrides = File.join(project_root, "omnibus_overrides.rb")
+ File.readlines(omnibus_overrides).each do |line|
+ return $1 if line =~ /^override :bundler, version: "(.+)"$/
+ end
+ end
+ end
+end
diff --git a/tasks/cbgb.rb b/tasks/cbgb.rb
new file mode 100644
index 0000000000..70ca1036e8
--- /dev/null
+++ b/tasks/cbgb.rb
@@ -0,0 +1,84 @@
+#
+# Author:: Thom May (tmay@chef.io)
+# Author:: Nathen Harvey (nharvey@chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "rake"
+
+CBGB_SOURCE = File.join(File.dirname(__FILE__), "..", "CBGB.toml")
+CBGB_TARGET = File.join(File.dirname(__FILE__), "..", "CBGB.md")
+
+begin
+ require "tomlrb"
+
+ task :default => :generate
+
+ namespace :cbgb do
+ desc "Generate MarkDown version of CBGB file"
+ task :generate do
+ cbgb = Tomlrb.load_file CBGB_SOURCE
+ out = "<!-- This is a generated file. Please do not edit directly -->\n"
+ out << "<!-- Modify CBGB.toml file and run `rake cbgb:generate` to regenerate -->\n\n"
+ out << "# " + cbgb["Preamble"]["title"] + "\n\n"
+ out << cbgb["Preamble"]["text"] + "\n"
+ out << "# Board of Governors\n\n"
+ out << "## " + cbgb["Org"]["Lead"]["title"] + "\n\n"
+ out << person(cbgb["people"], cbgb["Org"]["Lead"]["person"]) + "\n\n"
+ out << "### " + cbgb["Org"]["Contributors"]["title"] + "\n\n"
+ out << cbgb(cbgb["people"], cbgb["Org"]["Contributors"]["governers"]) + "\n\n"
+ out << "### " + cbgb["Org"]["Corporate-Contributors"]["title"] + "\n\n"
+ out << cbgb(cbgb["corporations"], cbgb["Org"]["Corporate-Contributors"]["governers"]) + "\n\n"
+ out << "### " + cbgb["Org"]["Lieutenants"]["title"] + "\n\n"
+ out << cbgb(cbgb["people"], cbgb["Org"]["Lieutenants"]["governers"]) + "\n\n"
+ File.open(CBGB_TARGET, "w") do |fn|
+ fn.write out
+ end
+ end
+ end
+
+ def components(list, cmp)
+ out = ""
+ cmp.each do |k, v|
+ out << "\n#### #{v['title'].gsub('#', '\\#')}\n"
+ out << cbgb(list, v["cbgb"])
+ end
+ out
+ end
+
+ def cbgb(list, people)
+ o = ""
+ people.each do |p|
+ o << person(list, p) + "\n"
+ end
+ o
+ end
+
+ def person(list, person)
+ if list[person].has_key?("GitHub")
+ out = "* [#{list[person]["Name"]}](https://github.com/#{list[person]["GitHub"]})"
+ else
+ out = "* #{list[person]["Name"]}"
+ end
+ if list[person].has_key?("Person")
+ out << " - #{list[person]["Person"]}"
+ end
+ out
+ end
+
+rescue LoadError
+ STDERR.puts "\n*** TomlRb not available.\n\n"
+end
diff --git a/tasks/changelog.rb b/tasks/changelog.rb
new file mode 100644
index 0000000000..8484acde24
--- /dev/null
+++ b/tasks/changelog.rb
@@ -0,0 +1,33 @@
+begin
+ require "github_changelog_generator/task"
+ require "mixlib/install"
+
+ namespace :changelog do
+ # Fetch the latest version from mixlib-install
+ latest_stable_version = Mixlib::Install.available_versions("chef", "stable").last
+
+ # Take the changelog from the latest stable release and put it into history.
+ task :archive do
+ changelog = Net::HTTP.get(URI("https://raw.githubusercontent.com/chef/chef/v#{latest_stable_version}/CHANGELOG.md")).chomp.split("\n")
+ File.open("HISTORY.md", "w+") { |f| f.write(changelog[2..-4].join("\n")) }
+ end
+
+ # Run this to just update the changelog for the current release. This will
+ # take what is in HISTORY and generate a changelog of PRs between the most
+ # recent stable version and HEAD.
+ GitHubChangelogGenerator::RakeTask.new :update do |config|
+ config.future_release = "v#{Chef::VERSION}"
+ config.between_tags = ["v#{latest_stable_version}", "v#{Chef::VERSION}"]
+ config.max_issues = 0
+ config.add_issues_wo_labels = false
+ config.enhancement_labels = "enhancement,Enhancement,New Feature,Feature".split(",")
+ config.bug_labels = "bug,Bug,Improvement,Upstream Bug".split(",")
+ config.exclude_labels = "duplicate,question,invalid,wontfix,no_changelog,Exclude From Changelog,Question,Discussion,Meta: Exclude From Changelog".split(",")
+ config.header = "This changelog reflects the current state of chef's master branch on github and may not reflect the current released version of chef, which is [![Gem Version](https://badge.fury.io/rb/chef.svg)](https://badge.fury.io/rb/chef)."
+ end
+ end
+
+ task :changelog => "changelog:update"
+rescue LoadError
+ puts "github_changelog_generator is not available. gem install github_changelog_generator to generate changelogs"
+end
diff --git a/tasks/dependencies.rb b/tasks/dependencies.rb
new file mode 100644
index 0000000000..b37c351d12
--- /dev/null
+++ b/tasks/dependencies.rb
@@ -0,0 +1,151 @@
+#
+# Copyright:: Copyright (c) 2016 Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require_relative "bundle_util"
+require_relative "bundle"
+require_relative "../version_policy"
+
+desc "Tasks to update and check dependencies"
+namespace :dependencies do
+
+ # Running update_ci on your local system wont' work. The best way to update
+ # dependencies locally is by running the dependency update script.
+ desc "Update all dependencies. dependencies:update to update as little as possible."
+ task :update do |t, rake_args|
+ system("#{File.join(Dir.pwd, "ci", "dependency_update.sh")}")
+ end
+
+ desc "Force update (when adding new gems to Gemfiles)"
+ task :force_update do |t, rake_args|
+ FileUtils.rm_f(File.join(Dir.pwd, ".bundle", "config"))
+ system("#{File.join(Dir.pwd, "ci", "dependency_update.sh")}")
+ end
+
+ # Update all dependencies to the latest constraint-matching version
+ desc "Update all dependencies. dependencies:update to update as little as possible (CI-only)."
+ task :update_ci => %w{
+ dependencies:update_gemfile_lock
+ dependencies:update_omnibus_overrides
+ dependencies:update_omnibus_gemfile_lock
+ dependencies:update_acceptance_gemfile_lock
+ dependencies:update_kitchen_tests_gemfile_lock
+ dependencies:update_kitchen_tests_berksfile_lock
+ }
+
+ desc "Update Gemfile.lock and all Gemfile.<platform>.locks."
+ task :update_gemfile_lock do |t, rake_args|
+ Rake::Task["bundle:update"].invoke
+ end
+
+ def gemfile_lock_task(task_name, dirs: [], other_platforms: true, leave_frozen: true)
+ dirs.each do |dir|
+ desc "Update #{dir}/Gemfile.lock."
+ task task_name do |t, rake_args|
+ extend BundleUtil
+ puts ""
+ puts "-------------------------------------------------------------------"
+ puts "Updating #{dir}/Gemfile.lock ..."
+ puts "-------------------------------------------------------------------"
+ with_bundle_unfrozen(cwd: dir, leave_frozen: leave_frozen) do
+ bundle "install", cwd: dir, delete_gemfile_lock: true
+ if other_platforms
+ # Include all other supported platforms into the lockfile as well
+ platforms.each do |platform|
+ bundle "lock", cwd: dir, platform: platform
+ end
+ end
+ end
+ end
+ end
+ end
+
+ def berksfile_lock_task(task_name, dirs: [])
+ dirs.each do |dir|
+ desc "Update #{dir}/Berksfile.lock."
+ task task_name do |t, rake_args|
+ extend BundleUtil
+ puts ""
+ puts "-------------------------------------------------------------------"
+ puts "Updating #{dir}/Berksfile.lock ..."
+ puts "-------------------------------------------------------------------"
+ if File.exist?("#{project_root}/#{dir}/Berksfile.lock")
+ File.delete("#{project_root}/#{dir}/Berksfile.lock")
+ end
+ Dir.chdir("#{project_root}/#{dir}") do
+ Bundler.with_clean_env do
+ sh "bundle exec berks install"
+ end
+ end
+ end
+ end
+ end
+
+ gemfile_lock_task :update_omnibus_gemfile_lock, dirs: %w{omnibus}
+ gemfile_lock_task :update_acceptance_gemfile_lock, dirs: %w{acceptance},
+ other_platforms: false, leave_frozen: false
+ gemfile_lock_task :update_kitchen_tests_gemfile_lock, dirs: %w{
+ kitchen-tests
+ }
+ berksfile_lock_task :update_kitchen_tests_berksfile_lock, dirs: %w{
+ kitchen-tests
+ kitchen-tests/cookbooks/audit_test
+ }
+
+ desc "Update omnibus overrides, including versions in version_policy.rb and latest version of gems: #{OMNIBUS_RUBYGEMS_AT_LATEST_VERSION.keys}."
+ task :update_omnibus_overrides do |t, rake_args|
+ puts ""
+ puts "-------------------------------------------------------------------"
+ puts "Updating omnibus_overrides.rb ..."
+ puts "-------------------------------------------------------------------"
+
+ # Generate the new overrides file
+ overrides = "# DO NOT EDIT. Generated by \"rake dependencies\". Edit version_policy.rb instead.\n"
+
+ # Replace the bundler and rubygems versions
+ OMNIBUS_RUBYGEMS_AT_LATEST_VERSION.each do |override_name, gem_name|
+ # Get the latest bundler version
+ puts "Running gem list -r #{gem_name} ..."
+ gem_list = `gem list -r #{gem_name}`
+ unless gem_list =~ /^#{gem_name}\s*\(([^)]*)\)$/
+ raise "gem list -r #{gem_name} failed with output:\n#{gem_list}"
+ end
+
+ # Emit it
+ puts "Latest version of #{gem_name} is #{$1}"
+ overrides << "override #{override_name.inspect}, version: #{$1.inspect}\n"
+ end
+
+ # Add explicit overrides
+ OMNIBUS_OVERRIDES.each do |override_name, version|
+ overrides << "override #{override_name.inspect}, version: #{version.inspect}\n"
+ end
+
+ # Write the file out (if changed)
+ overrides_path = File.expand_path("../../omnibus_overrides.rb", __FILE__)
+ if overrides != IO.read(overrides_path)
+ puts "Overrides changed!"
+ puts `git diff #{overrides_path}`
+ puts "Writing modified #{overrides_path} ..."
+ IO.write(overrides_path, overrides)
+ end
+ end
+end
+
+desc "Update all dependencies and check for outdated gems."
+task :dependencies_ci => [ "dependencies:update_ci", "bundle:outdated" ]
+task :dependencies => [ "dependencies:update" ]
+task :update => [ "dependencies:update" ]
diff --git a/tasks/external_tests.rb b/tasks/external_tests.rb
deleted file mode 100644
index 9304244424..0000000000
--- a/tasks/external_tests.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-require 'tempfile'
-
-def bundle_exec_with_chef(test_gem, commands)
- gem_path = Bundler.environment.specs[test_gem].first.full_gem_path
- gemfile_path = File.join(gem_path, 'Gemfile.chef-external-test')
- gemfile = File.open(gemfile_path, "w")
- begin
- IO.read(File.join(gem_path, 'Gemfile')).each_line do |line|
- if line =~ /^\s*gemspec/
- next
- elsif line =~ /^\s*gem 'chef'|\s*gem "chef"/
- next
- elsif line =~ /^\s*dev_gem\s*['"](.+)['"]\s*$/
- line = "gem '#{$1}', github: 'poise/#{$1}'"
- elsif line =~ /\s*gem\s*['"]#{test_gem}['"]/ # foodcritic
- next
- end
- gemfile.puts(line)
- end
- gemfile.puts("gem 'chef', path: #{File.expand_path('../..', __FILE__).inspect}")
- gemfile.puts("gemspec path: #{gem_path.inspect}")
- gemfile.close
- Dir.chdir(gem_path) do
- system({ 'BUNDLE_GEMFILE' => gemfile.path, 'RUBYOPT' => nil }, "bundle install")
- Array(commands).each do |command|
- system({ 'BUNDLE_GEMFILE' => gemfile.path, 'RUBYOPT' => nil }, "bundle exec #{command}")
- end
- end
- ensure
- File.delete(gemfile_path)
- end
-end
-
-EXTERNAL_PROJECTS = {
- "chef-zero" => [ "rake spec", "rake pedant" ],
- "cheffish" => "rake spec",
- "chef-provisioning" => "rake spec",
- "chef-provisioning-aws" => "rake spec",
- "chef-sugar" => "rake",
- "foodcritic" => "rake test",
- "chefspec" => "rake",
- "chef-rewind" => "rake spec",
- "poise" => "rake spec",
- "halite" => "rake spec"
-}
-
-task :external_specs => EXTERNAL_PROJECTS.keys.map { |g| :"#{g.sub("-","_")}_spec" }
-
-EXTERNAL_PROJECTS.each do |test_gem, commands|
- task :"#{test_gem.gsub('-','_')}_spec" do
- bundle_exec_with_chef(test_gem, commands)
- end
-end
diff --git a/tasks/gemfile_util.rb b/tasks/gemfile_util.rb
new file mode 100644
index 0000000000..03a729148a
--- /dev/null
+++ b/tasks/gemfile_util.rb
@@ -0,0 +1,390 @@
+require "rubygems"
+require "bundler"
+require "shellwords"
+require "set"
+
+module GemfileUtil
+ #
+ # Adds `override: true`, which allows your statement to override any other
+ # gem statement about the same gem in the Gemfile.
+ #
+ def gem(name, *args)
+ options = args[-1].is_a?(Hash) ? args[-1] : {}
+
+ # Unless we're finished with everything, ignore gems that are being overridden
+ unless overridden_gems == :finished
+ # If it's a path or override gem, it overrides whatever else is there.
+ if options[:path] || options[:override]
+ options.delete(:override)
+ warn_if_replacing(name, overridden_gems[name], args)
+ overridden_gems[name] = args
+ return
+
+ # If there's an override gem, and we're *not* an override gem, don't do anything
+ elsif overridden_gems[name]
+ warn_if_replacing(name, args, overridden_gems[name])
+ return
+ end
+ end
+
+ # Otherwise, add the gem normally
+ super
+ rescue
+ puts $!.backtrace
+ raise
+ end
+
+ def overridden_gems
+ @overridden_gems ||= {}
+ end
+
+ #
+ # Just before we finish the Gemfile, finish up the override gems
+ #
+ def to_definition(*args)
+ complete_overrides
+ super
+ end
+
+ def complete_overrides
+ to_override = overridden_gems
+ unless to_override == :finished
+ @overridden_gems = :finished
+ to_override.each do |name, args|
+ gem name, *args
+ end
+ end
+ end
+
+ #
+ # Include all gems in the locked gemfile.
+ #
+ # @param gemfile_path Path to the Gemfile to load (relative to your Gemfile)
+ # @param lockfile_path Path to the Gemfile to load (relative to your Gemfile).
+ # Defaults to <gemfile_path>.lock.
+ # @param groups A list of groups to include (whitelist). If not passed (or set
+ # to nil), all gems will be selected.
+ # @param without_groups A list of groups to ignore. Gems will be excluded from
+ # the results if all groups they belong to are ignored. This matches
+ # bundler's `without` behavior.
+ # @param gems A list of gems to include above and beyond the given groups.
+ # Gems in this list must be explicitly included in the Gemfile
+ # with a `gem "gem_name", ...` line or they will be silently
+ # ignored.
+ # @param copy_groups Whether to copy the groups over from the old lockfile to
+ # the new. Use this when the new lockfile has the same convention for
+ # groups as the old. Defaults to `false`.
+ #
+ def include_locked_gemfile(gemfile_path, lockfile_path = "#{gemfile_path}.lock", groups: nil, without_groups: nil, gems: [], copy_groups: false)
+ # Parse the desired lockfile
+ gemfile_path = Pathname.new(gemfile_path).expand_path(Bundler.default_gemfile.dirname).realpath
+ lockfile_path = Pathname.new(lockfile_path).expand_path(Bundler.default_gemfile.dirname).realpath
+
+ # Calculate relative_to
+ relative_to = Bundler.default_gemfile.dirname.realpath
+
+ # Call out to create-override-gemfile to read the Gemfile+Gemfile.lock (bundler does not work well if you do two things in one process)
+ create_override_gemfile_bin = File.expand_path("../bin/create-override-gemfile", __FILE__)
+ arguments = [
+ "--gemfile", gemfile_path,
+ "--lockfile", lockfile_path,
+ "--override"
+ ]
+ arguments += [ "--relative-to", relative_to ] if relative_to != "."
+ arguments += Array(groups).flat_map { |group| [ "--group", group ] }
+ arguments += Array(without_groups).flat_map { |without| [ "--without", without ] }
+ arguments += Array(gems).flat_map { |name| [ "--gem", name ] }
+ arguments << "--copy-groups" if copy_groups
+ cmd = Shellwords.join([ Gem.ruby, "-S", create_override_gemfile_bin, *arguments ])
+ output = nil
+ Bundler.ui.info("> #{cmd}")
+ Bundler.with_clean_env do
+ output = `#{cmd}`
+ end
+ instance_eval(output, cmd, 1)
+ end
+
+ #
+ # Include all gems in the locked gemfile.
+ #
+ # @param current_gemfile The Gemfile you are currently loading (`self`).
+ # @param gemfile_path Path to the Gemfile to load (relative to your Gemfile)
+ # @param lockfile_path Path to the Gemfile to load (relative to your Gemfile).
+ # Defaults to <gemfile_path>.lock.
+ # @param groups A list of groups to include (whitelist). If not passed (or set
+ # to nil), all gems will be selected.
+ # @param without_groups A list of groups to ignore. Gems will be excluded from
+ # the results if all groups they belong to are ignored. This matches
+ # bundler's `without` behavior.
+ # @param gems A list of gems to include above and beyond the given groups.
+ # Gems in this list must be explicitly included in the Gemfile
+ # with a `gem "gem_name", ...` line or they will be silently
+ # ignored.
+ # @param copy_groups Whether to copy the groups over from the old lockfile to
+ # the new. Use this when the new lockfile has the same convention for
+ # groups as the old. Defaults to `false`.
+ #
+ def self.include_locked_gemfile(current_gemfile, gemfile_path, lockfile_path = "#{gemfile_path}.lock", groups: nil, without_groups: nil, gems: [], copy_groups: false)
+ current_gemfile.instance_eval do
+ extend GemfileUtil
+ include_locked_gemfile(gemfile_path, lockfile_path, groups: groups, without_groups: without_groups, gems: gems, copy_groups: copy_groups)
+ end
+ end
+
+ def warn_if_replacing(name, old_args, new_args)
+ return if !old_args || !new_args
+ if args_to_dep(name, *old_args) =~ args_to_dep(name, *new_args)
+ Bundler.ui.debug "Replaced Gemfile dependency #{name} (#{old_args}) with (#{new_args})"
+ else
+ Bundler.ui.warn "Replaced Gemfile dependency #{name} (#{old_args}) with (#{new_args})"
+ end
+ end
+
+ def args_to_dep(name, *version, **options)
+ version = [">= 0"] if version.empty?
+ Bundler::Dependency.new(name, version, options)
+ end
+
+ #
+ # Reads a bundle, including a gemfile and lockfile.
+ #
+ # Does no validation, does not update the lockfile or its gems in any way.
+ #
+ class Bundle
+ #
+ # Parse the given gemfile/lockfile pair.
+ #
+ # @return [Bundle] The parsed bundle.
+ #
+ def self.parse(gemfile_path, lockfile_path = "#{gemfile_path}.lock")
+ result = new(gemfile_path, lockfile_path)
+ result.gems
+ result
+ end
+
+ #
+ # Create a new Bundle to parse the given gemfile/lockfile pair.
+ #
+ def initialize(gemfile_path, lockfile_path = "#{gemfile_path}.lock")
+ @gemfile_path = gemfile_path
+ @lockfile_path = lockfile_path
+ end
+
+ #
+ # The path to the Gemfile
+ #
+ attr_reader :gemfile_path
+
+ #
+ # The path to the Lockfile
+ #
+ attr_reader :lockfile_path
+
+ #
+ # The list of gems.
+ #
+ # @return [Hash<String, Hash>] The resulting gems, where key = gem_name, and the
+ # hash has:
+ # - version: version of the gem.
+ # - source info (:source/:git/:ref/:path) from the lockfile
+ # - dependencies: A list of gem names this gem has a runtime
+ # dependency on. Dependencies are transitive: if A depends on B,
+ # and B depends on C, then A has C in its :dependencies list.
+ # - development_dependencies: - A list of gem names this gem has a
+ # development dependency on. Dependencies are transitive: if A
+ # depends on B, and B depends on C, then A has C in its
+ # :development_dependencies list. development dependencies *include*
+ # runtime dependencies.
+ # - groups: The list of groups (symbols) this gem is in. Groups
+ # are transitive: if A has a runtime dependency on B, and A is
+ # in group X, then B is also in group X.
+ # - declared_groups: The list of groups (symbols) this gem was
+ # declared in the Gemfile.
+ #
+ def gems
+ @gems ||= begin
+ gems = locks.dup
+ gems.each do |name, g|
+ if gem_declarations.has_key?(name)
+ g[:declared_groups] = gem_declarations[name][:groups]
+ else
+ g[:declared_groups] = []
+ end
+ g[:groups] = g[:declared_groups].dup
+ end
+ # Transitivize groups (since dependencies are already transitive, this is easy)
+ gems.each do |name, g|
+ g[:dependencies].each do |dep|
+ gems[dep][:groups] |= gems[name][:declared_groups].dup
+ end
+ end
+ gems
+ end
+ end
+
+ #
+ # Get the gems (and their deps) in the given group.
+ #
+ # @param groups A list of groups to include (whitelist). If not passed (or set
+ # to nil), all gems will be selected.
+ # @param without_groups A list of groups to ignore. Gems will be excluded from
+ # the results if all groups they belong to are ignored.
+ # This matches bundler's `without` behavior.
+ # @param gems A list of gems to include regardless of what groups are included.
+ #
+ # @return Hash[String, Hash] The resulting gems, where key = gem_name, and the
+ # hash has:
+ # - version: version of the gem.
+ # - source info (:source/:git/:ref/:path) from the lockfile
+ # - dependencies: A list of gem names this gem has a runtime
+ # dependency on. Dependencies are transitive: if A depends on B,
+ # and B depends on C, then A has C in its :dependencies list.
+ # - development_dependencies: - A list of gem names this gem has a
+ # development dependency on. Dependencies are transitive: if A
+ # depends on B, and B depends on C, then A has C in its
+ # :development_dependencies list. development dependencies
+ # *include* runtime dependencies.
+ # - groups: The list of groups (symbols) this gem is in. Groups
+ # are transitive: if A has a runtime dependency on B, and A is
+ # in group X, then B is also in group X.
+ # - declared_groups: The list of groups (symbols) this gem was
+ # declared in the Gemfile.
+ #
+ def select_gems(groups: nil, without_groups: nil)
+ # First, select the gems that match
+ result = {}
+ gems.each do |name, g|
+ dep_groups = g[:declared_groups] - [ :only_a_runtime_dependency_of_other_gems ]
+ dep_groups &= groups if groups
+ dep_groups -= without_groups if without_groups
+ if dep_groups.any?
+ result[name] ||= g
+ g[:dependencies].each do |dep|
+ result[dep] ||= gems[dep]
+ end
+ end
+ end
+ result
+ end
+
+ #
+ # Get all locks from the given lockfile.
+ #
+ # @return Hash[String, Hash] The resulting gems, where key = gem_name, and the
+ # hash has:
+ # - version: version of the gem.
+ # - source info (:source/:git/:ref/:path)
+ # - dependencies: A list of gem names this gem has a runtime
+ # dependency on. Dependencies are transitive: if A depends on B,
+ # and B depends on C, then A has C in its :dependencies list.
+ # - development_dependencies: - A list of gem names this gem has a
+ # development dependency on. Dependencies are transitive: if A
+ # depends on B, and B depends on C, then A has C in its
+ # :development_dependencies list. development dependencies *include*
+ # runtime dependencies.
+ #
+ def locks
+ @locks ||= begin
+ # Grab all the specs from the lockfile
+ locks = {}
+ parsed_lockfile = Bundler::LockfileParser.new(IO.read(lockfile_path))
+ parsed_lockfile.specs.each do |spec|
+ # Never include bundler, it can't be bundled and doesn't put itself in
+ # the lockfile correctly anyway
+ next if spec.name == "bundler"
+ # Only the platform-specific locks for now (TODO make it possible to emit all locks)
+ next if spec.platform && spec.platform != Gem::Platform::RUBY
+ lock = lock_source_metadata(spec)
+ lock[:version] = spec.version.to_s
+ runtime = spec.dependencies.select { |dep| dep.type == :runtime }
+ lock[:dependencies] = Set.new(runtime.map { |dep| dep.name })
+ lock[:development_dependencies] = Set.new(spec.dependencies.map { |dep| dep.name })
+ lock[:dependencies].delete("bundler")
+ lock[:development_dependencies].delete("bundler")
+ locks[spec.name] = lock
+ end
+
+ # Transitivize the deps.
+ locks.each do |name, lock|
+ # Not all deps were brought over (platform-specific ones) so weed them out
+ lock[:dependencies] &= locks.keys
+ lock[:development_dependencies] &= locks.keys
+
+ lock[:dependencies] = transitive_dependencies(locks, name, :dependencies)
+ lock[:development_dependencies] = transitive_dependencies(locks, name, :development_dependencies)
+ end
+
+ locks
+ end
+ end
+
+ #
+ # Get all desired gems, sans dependencies, from the gemfile.
+ #
+ # @param gemfile Path to the Gemfile to load
+ #
+ # @return Hash<String, Hash> An array of hashes where key = gem name and value
+ # has :groups (an array of symbols representing the groups the gem
+ # is in). :groups are not transitive, since we don't know the
+ # dependency tree yet.
+ #
+ def gem_declarations
+ @gem_declarations ||= begin
+ Bundler.with_clean_env do
+ # Set BUNDLE_GEMFILE to the new gemfile temporarily so all bundler's things work
+ # This works around some issues in bundler 1.11.2.
+ ENV["BUNDLE_GEMFILE"] = gemfile_path
+
+ parsed_gemfile = Bundler::Dsl.new
+ parsed_gemfile.eval_gemfile(gemfile_path)
+ parsed_gemfile.complete_overrides if parsed_gemfile.respond_to?(:complete_overrides)
+
+ result = {}
+ parsed_gemfile.dependencies.each do |dep|
+ groups = dep.groups.empty? ? [:default] : dep.groups
+ result[dep.name] = { groups: groups, platforms: dep.platforms }
+ end
+ result
+ end
+ end
+ end
+
+ private
+
+ #
+ # Given a bunch of locks (name -> { dependencies: [name,name] }) and a
+ # dependency name, add its dependencies to the result transitively.
+ #
+ def transitive_dependencies(locks, name, dep_key, result = Set.new)
+ locks[name][dep_key].each do |dep|
+ # Only ever add a dep once, so we don't infinitely recurse
+ if result.add?(dep)
+ transitive_dependencies(locks, dep, dep_key, result)
+ end
+ end
+ result
+ end
+
+ #
+ # Get source and version metadata for the given Bundler spec (coming from a lockfile).
+ #
+ # @return Hash { version: <version>, git: <git>, path: <path>, source: <source>, ref: <ref> }
+ #
+ def lock_source_metadata(spec)
+ # Copy source information from included Gemfile
+ result = {}
+ case spec.source
+ when Bundler::Source::Rubygems
+ result[:source] = spec.source.remotes.first.to_s
+ when Bundler::Source::Git
+ result[:git] = spec.source.uri.to_s
+ result[:ref] = spec.source.revision
+ when Bundler::Source::Path
+ result[:path] = spec.source.path.to_s
+ else
+ raise "Unknown source #{spec.source} for gem #{spec.name}"
+ end
+ result
+ end
+ end
+end
diff --git a/tasks/maintainers.rb b/tasks/maintainers.rb
index 73a422fc61..e13d4724b0 100644
--- a/tasks/maintainers.rb
+++ b/tasks/maintainers.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
# limitations under the License.
#
-require 'rake'
+require "rake"
SOURCE = File.join(File.dirname(__FILE__), "..", "MAINTAINERS.toml")
TARGET = File.join(File.dirname(__FILE__), "..", "MAINTAINERS.md")
@@ -28,26 +28,27 @@ REPOSITORIES = ["chef/chef", "chef/chef-census", "chef/chef-repo",
"chef/mixlib-shellout", "chef/ohai", "chef/omnibus-chef"]
begin
- require 'tomlrb'
- require 'octokit'
- require 'pp'
- task :default => :generate
+ require "tomlrb"
+ require "octokit"
+ require "pp"
namespace :maintainers do
+ task :default => :generate
+
desc "Generate MarkDown version of MAINTAINERS file"
task :generate do
out = "<!-- This is a generated file. Please do not edit directly -->\n\n"
out << "# " + source["Preamble"]["title"] + "\n\n"
- out << source["Preamble"]["text"] + "\n"
+ out << source["Preamble"]["text"] + "\n"
# The project lead is a special case
out << "# " + source["Org"]["Lead"]["title"] + "\n\n"
out << format_person(source["Org"]["Lead"]["person"]) + "\n\n"
out << format_components(source["Org"]["Components"])
- File.open(TARGET, "w") { |fn|
+ File.open(TARGET, "w") do |fn|
fn.write out
- }
+ end
end
desc "Synchronize GitHub teams"
@@ -70,7 +71,7 @@ begin
end
def teams
- @teams ||= {"client-maintainers" => {"title" => "Client Maintainers"}}
+ @teams ||= { "client-maintainers" => { "title" => "Client Maintainers" } }
end
def add_members(team, name)
@@ -94,7 +95,7 @@ begin
# setting, so we know whether we need to update it
def get_github_teams
github.org_teams("chef").each do |team|
- gh_teams[team[:slug]] = {"id" => team[:id], "privacy" => team[:privacy]}
+ gh_teams[team[:slug]] = { "id" => team[:id], "privacy" => team[:privacy] }
end
end
@@ -109,8 +110,8 @@ begin
def create_team(team)
puts "creating new github team: #{team} with title: #{teams[team]["title"]} "
t = github.create_team("chef", name: team, description: teams[team]["title"],
- privacy: "closed", repo_names: REPOSITORIES,
- accept: "application/vnd.github.ironman-preview+json")
+ privacy: "closed", repo_names: REPOSITORIES,
+ accept: "application/vnd.github.ironman-preview+json")
gh_teams[team] = { "id" => t[:id], "privacy" => t[:privacy] }
end
@@ -121,14 +122,14 @@ begin
end
def prepare_teams(cmp)
- %w(text paths).each { |k| cmp.delete(k) }
+ %w{text paths}.each { |k| cmp.delete(k) }
if cmp.key?("team")
team = cmp.delete("team")
add_members(team, cmp.delete("lieutenant")) if cmp.key?("lieutenant")
add_members(team, cmp.delete("maintainers")) if cmp.key?("maintainers")
set_team_title(team, cmp.delete("title"))
else
- %w(maintainers lieutenant title).each { |k| cmp.delete(k) }
+ %w{maintainers lieutenant title}.each { |k| cmp.delete(k) }
end
cmp.each { |_k, v| prepare_teams(v) }
end
@@ -146,14 +147,14 @@ begin
return if gh_teams[team]["privacy"] == "closed"
puts "Setting #{team} privacy to closed from #{gh_teams[team]["privacy"]}"
github.update_team(gh_teams[team]["id"], privacy: "closed",
- accept: "application/vnd.github.ironman-preview+json")
+ accept: "application/vnd.github.ironman-preview+json")
end
def add_team_members(team, additions)
additions.each do |member|
puts "Adding #{member} to #{team}"
github.add_team_membership(gh_teams[team]["id"], member, role: "member",
- accept: "application/vnd.github.ironman-preview+json")
+ accept: "application/vnd.github.ironman-preview+json")
end
end
@@ -188,7 +189,7 @@ begin
end
out << format_maintainers(cmp.delete("maintainers")) + "\n" if cmp.has_key?("maintainers")
cmp.delete("paths")
- cmp.each {|k,v| out << format_components(v) }
+ cmp.each { |k, v| out << format_components(v) }
out
end
diff --git a/tasks/rspec.rb b/tasks/rspec.rb
index 6e802d3df8..616a68f09e 100644
--- a/tasks/rspec.rb
+++ b/tasks/rspec.rb
@@ -1,7 +1,7 @@
#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Daniel DeLeo (<dan@opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam@chef.io>)
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,20 +17,19 @@
# limitations under the License.
#
-require 'rubygems'
-require 'rake'
+require "rubygems"
+require "rake"
CHEF_ROOT = File.join(File.dirname(__FILE__), "..")
begin
- require 'rspec/core/rake_task'
-
+ require "rspec/core/rake_task"
desc "Run specs for Chef's Components"
task :component_specs do
Dir.chdir("chef-config") do
Bundler.with_clean_env do
- sh("bundle install --local")
+ sh("bundle install")
sh("bundle exec rake spec")
end
end
@@ -42,41 +41,46 @@ begin
desc "Run standard specs (minus long running specs)"
RSpec::Core::RakeTask.new(:spec) do |t|
+ t.rspec_opts = %w{--profile}
# right now this just limits to functional + unit, but could also remove
# individual tests marked long-running
- t.pattern = FileList['spec/**/*_spec.rb']
+ t.pattern = FileList["spec/**/*_spec.rb"]
end
namespace :spec do
desc "Run all specs in spec directory with RCov"
RSpec::Core::RakeTask.new(:rcov) do |t|
- t.pattern = FileList['spec/**/*_spec.rb']
+ t.rspec_opts = %w{--profile}
+ t.pattern = FileList["spec/**/*_spec.rb"]
t.rcov = true
t.rcov_opts = lambda do
- IO.readlines("#{CHEF_ROOT}/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
+ IO.readlines("#{CHEF_ROOT}/spec/rcov.opts").map { |l| l.chomp.split " " }.flatten
end
end
desc "Run all specs in spec directory"
RSpec::Core::RakeTask.new(:all) do |t|
- t.pattern = FileList['spec/**/*_spec.rb']
+ t.rspec_opts = %w{--profile}
+ t.pattern = FileList["spec/**/*_spec.rb"]
end
desc "Print Specdoc for all specs"
RSpec::Core::RakeTask.new(:doc) do |t|
- t.rspec_opts = ["--format", "specdoc", "--dry-run"]
- t.pattern = FileList['spec/**/*_spec.rb']
+ t.rspec_opts = %w{--format specdoc --dry-run --profile}
+ t.pattern = FileList["spec/**/*_spec.rb"]
end
desc "Run the specs under spec/unit with activesupport loaded"
RSpec::Core::RakeTask.new(:activesupport) do |t|
- t.rspec_opts = ["--require active_support/core_ext"]
- t.pattern = FileList['spec/unit/**/*_spec.rb']
+ t.rspec_opts = %w{--require active_support/core_ext --profile}
+ # Only node_spec and role_spec specifically have issues, target those tests
+ t.pattern = FileList["spec/unit/node_spec.rb", "spec/unit/role_spec.rb"]
end
[:unit, :functional, :integration, :stress].each do |sub|
desc "Run the specs under spec/#{sub}"
RSpec::Core::RakeTask.new(sub) do |t|
+ t.rspec_opts = %w{--profile}
t.pattern = FileList["spec/#{sub}/**/*_spec.rb"]
end
end
diff --git a/tasks/templates/prerelease.md.erb b/tasks/templates/prerelease.md.erb
new file mode 100644
index 0000000000..0c5c55cffc
--- /dev/null
+++ b/tasks/templates/prerelease.md.erb
@@ -0,0 +1,26 @@
+Ohai Chefs!
+
+We have selected <%= @version %> as our Chef v<%= @maj_minor %> release candidate which is scheduled for release on <%= @date.strftime('%A %B %-d, %Y') %>.
+
+# Release Highlights
+
+<%= @release_notes %>
+
+Please see the [CHANGELOG](https://github.com/chef/chef/blob/master/CHANGELOG.md) for the complete list of changes.
+
+# Get the Build
+As always, you can download binaries directly from [downloads.chef.io](https://downloads.chef.io/chef/current/<%= @version %>) or by using the new `mixlib-install` command line utility available in ChefDK 0.19.6 or greater.
+
+```shell
+$ mixlib-install download chef -v <%= @version %> -c current
+```
+
+Alternatively, you can install Chef using one of the following command options:
+
+```shell
+# In Shell
+$ curl https://omnitruck.chef.io/install.sh | sudo bash -s -- -P chef -v <%= @version %> -c current
+
+# In Windows Powershell
+. { iwr -useb https://omnitruck.chef.io/install.ps1 } | iex; install -project chef -version <%= @version %> -channel current
+```
diff --git a/tasks/templates/release.md.erb b/tasks/templates/release.md.erb
new file mode 100644
index 0000000000..2c6ff0b7c6
--- /dev/null
+++ b/tasks/templates/release.md.erb
@@ -0,0 +1,26 @@
+Ohai Chefs!
+
+We're happy to announce the release of Chef v<%= @maj_minor %>!
+
+# Release Highlights
+
+<%= @release_notes %>
+
+Please see the [CHANGELOG](https://github.com/chef/chef/blob/master/CHANGELOG.md) for the complete list of changes.
+
+# Get the Build
+As always, you can download binaries directly from [downloads.chef.io](https://downloads.chef.io/chef/<%= @version %>) or by using the new `mixlib-install` command line utility available in ChefDK 0.19.6 or greater.
+
+```shell
+$ mixlib-install download chef -v <%= @version %>
+```
+
+Alternatively, you can install Chef using one of the following command options:
+
+```shell
+# In Shell
+$ curl https://omnitruck.chef.io/install.sh | sudo bash -s -- -P chef -v <%= @version %>
+
+# In Windows Powershell
+. { iwr -useb https://omnitruck.chef.io/install.ps1 } | iex; install -project chef -version <%= @version %>
+```
diff --git a/version_policy.rb b/version_policy.rb
new file mode 100644
index 0000000000..85c29a760b
--- /dev/null
+++ b/version_policy.rb
@@ -0,0 +1,120 @@
+#
+# Copyright:: Copyright (c) 2016 Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Explicit omnibus overrides.
+OMNIBUS_OVERRIDES = {
+ # Lower level library pins
+ ## according to comment in omnibus-sw, latest versions don't work on solaris
+ # https://github.com/chef/omnibus-software/blob/aefb7e79d29ca746c3f843673ef5e317fa3cba54/config/software/libtool.rb#L23
+ :bundler => "1.12.5", # until we figure out how to work with 1.13.0
+ "libffi" => "3.2.1",
+ "libiconv" => "1.14",
+ "liblzma" => "5.2.2",
+ ## according to comment in omnibus-sw, the very latest versions don't work on solaris
+ # https://github.com/chef/omnibus-software/blob/aefb7e79d29ca746c3f843673ef5e317fa3cba54/config/software/libtool.rb#L23
+ "libtool" => "2.4.2",
+ "libxml2" => "2.9.4",
+ "libxslt" => "1.1.29",
+ "libyaml" => "0.1.6",
+ "makedepend" => "1.0.5",
+ "ncurses" => "5.9",
+ "pkg-config-lite" => "0.28-1",
+ "ruby" => "2.3.1",
+ # Leave dev-kit pinned to 4.5 on 32-bit, because 4.7 is 20MB larger and we don't want
+ # to unnecessarily make the client any fatter. (Since it's different between
+ # 32 and 64, we have to do it in the project file still.)
+ # "ruby-windows-devkit" => "4.5.2-20111229-1559",
+ "ruby-windows-devkit-bash" => "3.1.23-4-msys-1.0.18",
+ "util-macros" => "1.19.0",
+ "xproto" => "7.0.28",
+ "zlib" => "1.2.8",
+
+ ## These can float as they are frequently updated in a way that works for us
+ #override "cacerts" =>"???",
+ "openssl" => "1.0.2j",
+}
+
+#
+# rake dependencies:update_omnibus_overrides (tasks/dependencies.rb) reads this
+# and modifies omnibus_overrides.rb
+#
+# The left side is the software definition name, and the right side is the
+# name of the rubygem (gem list -re <rubygem name> gets us the latest version).
+#
+OMNIBUS_RUBYGEMS_AT_LATEST_VERSION = {
+ rubygems: "rubygems-update",
+ # bundler: "bundler", # until we get working with 1.13.0
+}
+
+#
+# rake dependencies:check (tasks/dependencies.rb) uses this as a list of gems
+# that are allowed to be outdated according to `bundle updated`
+#
+# Once you decide that the list of outdated gems is OK, you can just
+# add gems to the output of bundle outdated here and we'll parse it to get the
+# list of outdated gems.
+#
+# gherkin - expected to update with new cucumber (and foodcritic?) release
+# jwt - expected to update with new oauth2 release
+# mini_portile2 - should go away *entirely* with new nokogiri release (not a dep anymore)
+# slop - expected to disappear with new pry release
+# stove - halite pins to ~> 3.2 in 1.2.1
+# rubocop - chef-style pins to 0.39.0 in 0.3.1
+#
+ACCEPTABLE_OUTDATED_GEMS = [
+ "json", # aws-sdk-v1 pins this because Ruby 2.0; chef-provisioning fix to abandon v1 TBD
+ "rubocop", # chefstyle pins this, will often be somewhat behind
+ "slop", # expected to disappear with pry 0.11
+ "typhoeus", # Until the travis gem updates to 1.0.
+ "cucumber-core", # Until cucumber 2.0
+ "addressable", # gh (via travis) wants this ~> 2.4.0
+ "rake", # poise limits this to < 12
+ "github_changelog_generator", # we manage this independent of the rubygem
+ "cheffish", # 5.0.0 breaks chef-provisioning
+ "net-ssh-gateway", # chef-provisiong and test-kitchen have ~> 1.2 constraint
+]
+
+#
+# Some gems are part of our bundle (must be installed) but not important
+# enough to lock. We allow `bundle install` in test-kitchen, berks, etc.
+# to use their own versions of these.
+#
+# This mainly tells you which gems `chef verify` allows you to install and
+# run.
+#
+GEMS_ALLOWED_TO_FLOAT = [
+]
+
+#
+# The list of groups we install without: this drives both the `bundle install`
+# we do in chef-dk, and the `bundle check` we do to ensure installed gems don't
+# have extra deps hiding in their Gemfiles.
+#
+# NOTE: we DO install test, because there aren't many gems there, and it makes
+# our test phase a lot easier.
+#
+INSTALL_WITHOUT_GROUPS = %w{
+ changelog
+ development
+ docgen
+ guard
+ integration
+ maintenance
+ tools
+ travis
+ style
+}