chef 12.4.3-universal-mingw32 → 12.5.1-universal-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +21 -25
- data/Gemfile +46 -0
- data/README.md +4 -4
- data/Rakefile +4 -110
- data/bin/chef-service-manager +3 -1
- data/distro/common/html/knife_cookbook_site.html +18 -18
- data/distro/common/man/man1/knife-cookbook-site.1 +11 -11
- data/lib/chef.rb +1 -1
- data/lib/chef/application.rb +1 -1
- data/lib/chef/application/apply.rb +19 -1
- data/lib/chef/application/client.rb +11 -5
- data/lib/chef/application/knife.rb +2 -2
- data/lib/chef/application/solo.rb +1 -1
- data/lib/chef/application/windows_service_manager.rb +19 -12
- data/lib/chef/chef_class.rb +46 -0
- data/lib/chef/chef_fs/config.rb +22 -24
- data/lib/chef/chef_fs/data_handler/client_data_handler.rb +3 -1
- data/lib/chef/chef_fs/file_pattern.rb +4 -15
- data/lib/chef/chef_fs/file_system/acl_dir.rb +3 -4
- data/lib/chef/chef_fs/file_system/acls_dir.rb +5 -1
- data/lib/chef/chef_fs/file_system/base_fs_dir.rb +0 -5
- data/lib/chef/chef_fs/file_system/base_fs_object.rb +5 -2
- data/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb +2 -9
- data/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb +2 -9
- data/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb +10 -17
- data/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb +1 -12
- data/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb +15 -11
- data/lib/chef/chef_fs/file_system/chef_server_root_dir.rb +8 -2
- data/lib/chef/chef_fs/file_system/cookbook_dir.rb +4 -4
- data/lib/chef/chef_fs/file_system/cookbooks_acl_dir.rb +1 -1
- data/lib/chef/chef_fs/file_system/cookbooks_dir.rb +3 -11
- data/lib/chef/chef_fs/file_system/data_bags_dir.rb +3 -5
- data/lib/chef/chef_fs/file_system/environments_dir.rb +1 -1
- data/lib/chef/chef_fs/file_system/file_system_entry.rb +7 -4
- data/lib/chef/chef_fs/file_system/memory_dir.rb +2 -3
- data/lib/chef/chef_fs/file_system/multiplexed_dir.rb +15 -0
- data/lib/chef/chef_fs/file_system/nodes_dir.rb +1 -1
- data/lib/chef/chef_fs/file_system/organization_members_entry.rb +2 -2
- data/lib/chef/chef_fs/file_system/rest_list_dir.rb +4 -9
- data/lib/chef/chef_fs/knife.rb +35 -7
- data/lib/chef/chef_fs/path_utils.rb +65 -34
- data/lib/chef/client.rb +2 -3
- data/lib/chef/config.rb +34 -2
- data/lib/chef/{mixin/wstring.rb → constants.rb} +9 -13
- data/lib/chef/cookbook/metadata.rb +25 -3
- data/lib/chef/cookbook/synchronizer.rb +1 -1
- data/lib/chef/cookbook_site_streaming_uploader.rb +1 -1
- data/lib/chef/cookbook_version.rb +3 -3
- data/lib/chef/delayed_evaluator.rb +21 -0
- data/lib/chef/deprecation/mixin/template.rb +1 -2
- data/lib/chef/deprecation/provider/cookbook_file.rb +1 -1
- data/lib/chef/deprecation/provider/file.rb +1 -1
- data/lib/chef/deprecation/provider/remote_directory.rb +52 -0
- data/lib/chef/deprecation/provider/remote_file.rb +1 -2
- data/lib/chef/deprecation/provider/template.rb +1 -1
- data/lib/chef/deprecation/warnings.rb +3 -4
- data/lib/chef/dsl/reboot_pending.rb +3 -2
- data/lib/chef/dsl/recipe.rb +26 -7
- data/lib/chef/dsl/resources.rb +2 -2
- data/lib/chef/event_dispatch/base.rb +51 -22
- data/lib/chef/event_dispatch/dispatcher.rb +21 -6
- data/lib/chef/event_dispatch/dsl.rb +64 -0
- data/lib/chef/exceptions.rb +28 -1
- data/lib/chef/file_content_management/tempfile.rb +1 -1
- data/lib/chef/formatters/base.rb +3 -0
- data/lib/chef/formatters/doc.rb +56 -6
- data/lib/chef/formatters/error_inspectors/compile_error_inspector.rb +36 -0
- data/lib/chef/formatters/minimal.rb +2 -2
- data/lib/chef/guard_interpreter/resource_guard_interpreter.rb +3 -1
- data/lib/chef/http/http_request.rb +1 -1
- data/lib/chef/knife.rb +35 -55
- data/lib/chef/knife/bootstrap.rb +41 -0
- data/lib/chef/knife/bootstrap/chef_vault_handler.rb +1 -0
- data/lib/chef/knife/bootstrap/client_builder.rb +16 -0
- data/lib/chef/knife/bootstrap/templates/README.md +3 -4
- data/lib/chef/knife/bootstrap/templates/chef-full.erb +1 -1
- data/lib/chef/knife/cookbook_create.rb +1 -1
- data/lib/chef/knife/cookbook_site_download.rb +1 -1
- data/lib/chef/knife/cookbook_site_install.rb +1 -1
- data/lib/chef/knife/cookbook_site_share.rb +6 -6
- data/lib/chef/knife/cookbook_site_unshare.rb +2 -2
- data/lib/chef/knife/core/bootstrap_context.rb +12 -4
- data/lib/chef/knife/core/custom_manifest_loader.rb +69 -0
- data/lib/chef/knife/core/gem_glob_loader.rb +138 -0
- data/lib/chef/knife/core/hashed_command_loader.rb +80 -0
- data/lib/chef/knife/core/node_presenter.rb +24 -1
- data/lib/chef/knife/core/object_loader.rb +1 -0
- data/lib/chef/knife/core/subcommand_loader.rb +131 -146
- data/lib/chef/knife/node_run_list_remove.rb +12 -1
- data/lib/chef/knife/null.rb +10 -0
- data/lib/chef/knife/rehash.rb +62 -0
- data/lib/chef/knife/search.rb +3 -3
- data/lib/chef/knife/ssh.rb +52 -30
- data/lib/chef/knife/ssl_check.rb +3 -2
- data/lib/chef/knife/user_edit.rb +1 -2
- data/lib/chef/local_mode.rb +5 -0
- data/lib/chef/log.rb +5 -1
- data/lib/chef/mixin/deprecation.rb +8 -8
- data/lib/chef/mixin/params_validate.rb +362 -135
- data/lib/chef/mixin/template.rb +48 -0
- data/lib/chef/mixin/which.rb +1 -1
- data/lib/chef/mixin/wide_string.rb +72 -0
- data/lib/chef/mixin/windows_architecture_helper.rb +15 -39
- data/lib/chef/mixin/windows_env_helper.rb +4 -1
- data/lib/chef/monkey_patches/webrick-utils.rb +51 -0
- data/lib/chef/monkey_patches/win32/registry.rb +72 -0
- data/lib/chef/node.rb +116 -3
- data/lib/chef/node_map.rb +2 -2
- data/lib/chef/platform/handler_map.rb +0 -5
- data/lib/chef/platform/provider_mapping.rb +5 -6
- data/lib/chef/platform/query_helpers.rb +46 -4
- data/lib/chef/platform/rebooter.rb +1 -1
- data/lib/chef/platform/service_helpers.rb +30 -32
- data/lib/chef/policy_builder.rb +1 -8
- data/lib/chef/policy_builder/dynamic.rb +186 -0
- data/lib/chef/policy_builder/expand_node_object.rb +30 -15
- data/lib/chef/policy_builder/policyfile.rb +155 -18
- data/lib/chef/property.rb +568 -0
- data/lib/chef/provider.rb +222 -13
- data/lib/chef/provider/batch.rb +8 -0
- data/lib/chef/provider/deploy.rb +5 -7
- data/lib/chef/provider/directory.rb +14 -2
- data/lib/chef/provider/dsc_resource.rb +5 -9
- data/lib/chef/provider/group/pw.rb +1 -1
- data/lib/chef/provider/ifconfig.rb +2 -2
- data/lib/chef/provider/lwrp_base.rb +1 -75
- data/lib/chef/provider/mount.rb +7 -3
- data/lib/chef/provider/package.rb +1 -1
- data/lib/chef/provider/package/dpkg.rb +5 -11
- data/lib/chef/provider/package/rpm.rb +2 -2
- data/lib/chef/provider/package/rubygems.rb +1 -1
- data/lib/chef/provider/package/windows/msi.rb +2 -2
- data/lib/chef/provider/package/yum.rb +17 -5
- data/lib/chef/provider/powershell_script.rb +59 -23
- data/lib/chef/provider/registry_key.rb +5 -5
- data/lib/chef/provider/remote_directory.rb +190 -102
- data/lib/chef/provider/service.rb +12 -2
- data/lib/chef/provider/service/aix.rb +1 -1
- data/lib/chef/provider/service/debian.rb +3 -5
- data/lib/chef/provider/service/freebsd.rb +1 -1
- data/lib/chef/provider/service/gentoo.rb +3 -3
- data/lib/chef/provider/service/init.rb +3 -3
- data/lib/chef/provider/service/insserv.rb +2 -4
- data/lib/chef/provider/service/invokercd.rb +2 -4
- data/lib/chef/provider/service/macosx.rb +5 -1
- data/lib/chef/provider/service/openbsd.rb +2 -1
- data/lib/chef/provider/service/redhat.rb +52 -16
- data/lib/chef/provider/service/simple.rb +2 -2
- data/lib/chef/provider/service/systemd.rb +3 -5
- data/lib/chef/provider/service/upstart.rb +4 -6
- data/lib/chef/provider/subversion.rb +13 -7
- data/lib/chef/provider/template/content.rb +16 -6
- data/lib/chef/provider/user/solaris.rb +32 -4
- data/lib/chef/provider/windows_script.rb +3 -5
- data/lib/chef/provider_resolver.rb +2 -2
- data/lib/chef/recipe.rb +1 -8
- data/lib/chef/resource.rb +563 -90
- data/lib/chef/resource/action_class.rb +83 -0
- data/lib/chef/resource/chef_gem.rb +3 -3
- data/lib/chef/resource/deploy.rb +8 -2
- data/lib/chef/resource/dsc_script.rb +2 -0
- data/lib/chef/resource/file/verification.rb +7 -1
- data/lib/chef/resource/lwrp_base.rb +1 -7
- data/lib/chef/resource/registry_key.rb +1 -1
- data/lib/chef/resource/service.rb +10 -2
- data/lib/chef/resource/subversion.rb +5 -0
- data/lib/chef/resource/windows_script.rb +6 -2
- data/lib/chef/resource/yum_package.rb +10 -1
- data/lib/chef/resource_resolver.rb +3 -3
- data/lib/chef/run_context.rb +402 -83
- data/lib/chef/run_list/versioned_recipe_list.rb +15 -0
- data/lib/chef/run_lock.rb +30 -21
- data/lib/chef/util/powershell/ps_credential.rb +4 -0
- data/lib/chef/util/windows.rb +0 -32
- data/lib/chef/util/windows/net_group.rb +85 -106
- data/lib/chef/util/windows/net_use.rb +35 -71
- data/lib/chef/util/windows/net_user.rb +0 -1
- data/lib/chef/util/windows/volume.rb +19 -19
- data/lib/chef/version.rb +3 -3
- data/lib/chef/win32/api.rb +1 -0
- data/lib/chef/win32/api/file.rb +20 -0
- data/lib/chef/win32/api/net.rb +163 -43
- data/lib/chef/win32/api/registry.rb +51 -0
- data/lib/chef/win32/api/system.rb +23 -0
- data/lib/chef/win32/api/unicode.rb +0 -43
- data/lib/chef/win32/crypto.rb +2 -1
- data/lib/chef/win32/file.rb +28 -3
- data/lib/chef/win32/mutex.rb +1 -2
- data/lib/chef/win32/net.rb +162 -8
- data/lib/chef/win32/process.rb +13 -0
- data/lib/chef/win32/registry.rb +35 -30
- data/lib/chef/win32/security.rb +1 -1
- data/lib/chef/win32/security/token.rb +1 -1
- data/lib/chef/win32/system.rb +62 -0
- data/lib/chef/win32/unicode.rb +7 -2
- data/lib/chef/win32/version.rb +0 -4
- data/lib/chef/workstation_config_loader.rb +3 -158
- data/spec/data/cookbooks/openldap/templates/default/helpers.erb +14 -0
- data/spec/data/cookbooks/openldap/templates/default/nested_openldap_partials.erb +1 -0
- data/spec/data/cookbooks/openldap/templates/default/nested_partial.erb +1 -0
- data/spec/data/dsc_lcm.pfx +0 -0
- data/spec/data/run_context/cookbooks/include/recipes/default.rb +24 -0
- data/spec/data/run_context/cookbooks/include/recipes/includee.rb +3 -0
- data/spec/functional/dsl/reboot_pending_spec.rb +33 -43
- data/spec/functional/knife/cookbook_delete_spec.rb +17 -7
- data/spec/functional/knife/ssh_spec.rb +16 -0
- data/spec/functional/rebooter_spec.rb +1 -1
- data/spec/functional/resource/deploy_revision_spec.rb +1 -1
- data/spec/functional/resource/dsc_resource_spec.rb +2 -0
- data/spec/functional/resource/dsc_script_spec.rb +91 -2
- data/spec/functional/resource/group_spec.rb +67 -44
- data/spec/functional/resource/{powershell_spec.rb → powershell_script_spec.rb} +107 -18
- data/spec/functional/resource/windows_service_spec.rb +1 -1
- data/spec/functional/run_lock_spec.rb +368 -189
- data/spec/functional/win32/{registry_helper_spec.rb → registry_spec.rb} +16 -23
- data/spec/functional/win32/service_manager_spec.rb +2 -2
- data/spec/integration/client/client_spec.rb +51 -0
- data/spec/integration/knife/chef_repo_path_spec.rb +13 -11
- data/spec/integration/knife/download_spec.rb +4 -0
- data/spec/integration/knife/list_spec.rb +8 -0
- data/spec/integration/knife/upload_spec.rb +1 -1
- data/spec/integration/recipes/recipe_dsl_spec.rb +1 -16
- data/spec/integration/recipes/remote_directory.rb +74 -0
- data/spec/integration/recipes/resource_action_spec.rb +363 -0
- data/spec/integration/recipes/resource_converge_if_changed_spec.rb +423 -0
- data/spec/integration/recipes/resource_load_spec.rb +206 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/platform_helpers.rb +13 -0
- data/spec/support/shared/context/win32.rb +34 -0
- data/spec/support/shared/functional/win32_service.rb +2 -1
- data/spec/support/shared/functional/windows_script.rb +63 -26
- data/spec/support/shared/unit/mock_shellout.rb +46 -0
- data/spec/support/shared/unit/provider/file.rb +10 -4
- data/spec/unit/application/client_spec.rb +16 -3
- data/spec/unit/application/knife_spec.rb +2 -2
- data/spec/unit/application/solo_spec.rb +4 -3
- data/spec/unit/chef_class_spec.rb +23 -4
- data/spec/unit/chef_fs/path_util_spec.rb +108 -0
- data/spec/unit/client_spec.rb +6 -1
- data/spec/unit/config_spec.rb +31 -0
- data/spec/unit/cookbook/metadata_spec.rb +23 -3
- data/spec/unit/cookbook/syntax_check_spec.rb +3 -0
- data/spec/unit/deprecation_spec.rb +3 -6
- data/spec/unit/dsl/reboot_pending_spec.rb +12 -6
- data/spec/unit/event_dispatch/dispatcher_spec.rb +65 -3
- data/spec/unit/event_dispatch/dsl_spec.rb +83 -0
- data/spec/unit/formatters/doc_spec.rb +32 -0
- data/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb +26 -0
- data/spec/unit/json_compat_spec.rb +4 -3
- data/spec/unit/knife/bootstrap/client_builder_spec.rb +27 -0
- data/spec/unit/knife/bootstrap_spec.rb +55 -3
- data/spec/unit/knife/cookbook_site_share_spec.rb +3 -3
- data/spec/unit/knife/core/bootstrap_context_spec.rb +21 -4
- data/spec/unit/knife/core/custom_manifest_loader_spec.rb +41 -0
- data/spec/unit/knife/core/gem_glob_loader_spec.rb +210 -0
- data/spec/unit/knife/core/hashed_command_loader_spec.rb +93 -0
- data/spec/unit/knife/core/subcommand_loader_spec.rb +16 -192
- data/spec/unit/knife/node_run_list_remove_spec.rb +17 -0
- data/spec/unit/knife/ssl_check_spec.rb +4 -0
- data/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb +10 -10
- data/spec/unit/mixin/params_validate_spec.rb +4 -2
- data/spec/unit/mixin/template_spec.rb +5 -1
- data/spec/unit/mixin/windows_architecture_helper_spec.rb +13 -8
- data/spec/unit/node_spec.rb +220 -0
- data/spec/unit/platform/query_helpers_spec.rb +146 -3
- data/spec/unit/policy_builder/dynamic_spec.rb +275 -0
- data/spec/unit/policy_builder/expand_node_object_spec.rb +37 -38
- data/spec/unit/policy_builder/policyfile_spec.rb +260 -46
- data/spec/unit/property/state_spec.rb +506 -0
- data/spec/unit/property/validation_spec.rb +663 -0
- data/spec/unit/property_spec.rb +1094 -0
- data/spec/unit/provider/deploy_spec.rb +5 -5
- data/spec/unit/provider/directory_spec.rb +35 -0
- data/spec/unit/provider/dsc_resource_spec.rb +3 -10
- data/spec/unit/provider/ifconfig_spec.rb +22 -2
- data/spec/unit/provider/mount/aix_spec.rb +2 -1
- data/spec/unit/provider/mount/mount_spec.rb +6 -0
- data/spec/unit/provider/mount/windows_spec.rb +14 -0
- data/spec/unit/provider/mount_spec.rb +12 -1
- data/spec/unit/provider/package/dpkg_spec.rb +8 -1
- data/spec/unit/provider/package/rpm_spec.rb +18 -1
- data/spec/unit/provider/package/rubygems_spec.rb +18 -0
- data/spec/unit/provider/package/yum_spec.rb +97 -24
- data/spec/unit/provider/powershell_script_spec.rb +106 -0
- data/spec/unit/provider/registry_key_spec.rb +12 -0
- data/spec/unit/provider/remote_directory_spec.rb +1 -2
- data/spec/unit/provider/service/aix_service_spec.rb +3 -3
- data/spec/unit/provider/service/gentoo_service_spec.rb +4 -4
- data/spec/unit/provider/service/macosx_spec.rb +4 -4
- data/spec/unit/provider/service/openbsd_service_spec.rb +10 -8
- data/spec/unit/provider/service/redhat_spec.rb +88 -8
- data/spec/unit/provider/service/upstart_service_spec.rb +11 -7
- data/spec/unit/provider/service/windows_spec.rb +211 -200
- data/spec/unit/provider/subversion_spec.rb +50 -31
- data/spec/unit/provider/template/content_spec.rb +93 -2
- data/spec/unit/provider/user/solaris_spec.rb +66 -9
- data/spec/unit/provider_resolver_spec.rb +707 -650
- data/spec/unit/provider_spec.rb +1 -3
- data/spec/unit/recipe_spec.rb +0 -4
- data/spec/unit/resource/deploy_spec.rb +7 -1
- data/spec/unit/resource/dsc_script_spec.rb +4 -0
- data/spec/unit/resource/file/verification_spec.rb +33 -5
- data/spec/unit/resource/{powershell_spec.rb → powershell_script_spec.rb} +17 -13
- data/spec/unit/resource/service_spec.rb +4 -4
- data/spec/unit/resource/subversion_spec.rb +4 -0
- data/spec/unit/resource/yum_package_spec.rb +10 -1
- data/spec/unit/resource_spec.rb +2 -2
- data/spec/unit/run_context/child_run_context_spec.rb +133 -0
- data/spec/unit/run_context_spec.rb +7 -0
- data/spec/unit/run_list/versioned_recipe_list_spec.rb +5 -0
- data/spec/unit/win32/registry_spec.rb +394 -0
- data/tasks/external_tests.rb +47 -23
- data/tasks/maintainers.rb +155 -14
- metadata +64 -53
- data/lib/chef/knife/bootstrap/templates/archlinux-gems.erb +0 -76
- data/lib/chef/knife/bootstrap/templates/chef-aix.erb +0 -72
- data/spec/unit/provider/powershell_spec.rb +0 -80
- data/spec/unit/registry_helper_spec.rb +0 -376
- data/spec/unit/workstation_config_loader_spec.rb +0 -283
@@ -18,7 +18,7 @@
|
|
18
18
|
|
19
19
|
require 'spec_helper'
|
20
20
|
|
21
|
-
describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_gem_only do
|
21
|
+
describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_gem_only, :appveyor_only do
|
22
22
|
|
23
23
|
include_context "using Win32::Service"
|
24
24
|
|
@@ -34,211 +34,232 @@ describe Chef::RunLock do
|
|
34
34
|
let(:lockfile){ "#{random_temp_root}/this/long/path/does/not/exist/chef-client-running.pid" }
|
35
35
|
|
36
36
|
# make sure to start with a clean slate.
|
37
|
-
before(:each){ FileUtils.rm_r(random_temp_root) if File.exist?(random_temp_root) }
|
38
|
-
after(:each){ FileUtils.rm_r(random_temp_root) }
|
37
|
+
before(:each){ log_event("rm -rf before"); FileUtils.rm_r(random_temp_root) if File.exist?(random_temp_root) }
|
38
|
+
after(:each){ log_event("rm -rf after"); FileUtils.rm_r(random_temp_root) if File.exist?(random_temp_root) }
|
39
39
|
|
40
|
-
def
|
41
|
-
|
42
|
-
until File.exist?(lockfile)
|
43
|
-
raise "Lockfile never created, abandoning test" if tries > 10
|
44
|
-
tries += 1
|
45
|
-
sleep 0.1
|
46
|
-
end
|
40
|
+
def log_event(message, time=Time.now.strftime("%H:%M:%S.%L"))
|
41
|
+
events << [ message, time ]
|
47
42
|
end
|
48
|
-
|
49
|
-
|
50
|
-
# Side channel via a pipe allows child processes to send errors to the parent
|
51
|
-
|
52
|
-
# Don't lazy create the pipe or else we might not share it with subprocesses
|
53
|
-
let!(:error_pipe) do
|
54
|
-
r,w = IO.pipe
|
55
|
-
w.sync = true
|
56
|
-
[r,w]
|
43
|
+
def events
|
44
|
+
@events ||= []
|
57
45
|
end
|
58
46
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
47
|
+
WAIT_ON_LOCK_TIME = 1.0
|
48
|
+
def wait_on_lock
|
49
|
+
Timeout::timeout(WAIT_ON_LOCK_TIME) do
|
50
|
+
until File.exist?(lockfile)
|
51
|
+
sleep 0.1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
rescue Timeout::Error
|
55
|
+
raise "Lockfile never created, abandoning test"
|
65
56
|
end
|
66
57
|
|
67
|
-
|
68
|
-
|
69
|
-
# marshaling stuff.
|
70
|
-
def send_side_channel_error(message)
|
71
|
-
$stderr.puts(message)
|
72
|
-
$stderr.puts(caller)
|
73
|
-
e = RuntimeError.new(message)
|
74
|
-
error_write.print(Marshal.dump(e))
|
75
|
-
end
|
58
|
+
CLIENT_PROCESS_TIMEOUT = 10
|
59
|
+
BREATHING_ROOM = 1
|
76
60
|
|
77
|
-
#
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
err = error_read.read
|
82
|
-
error_read.close
|
61
|
+
# ClientProcess is defined below
|
62
|
+
let!(:p1) { ClientProcess.new(self, 'p1') }
|
63
|
+
let!(:p2) { ClientProcess.new(self, 'p2') }
|
64
|
+
after(:each) do |example|
|
83
65
|
begin
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
66
|
+
p1.stop
|
67
|
+
p2.stop
|
68
|
+
rescue
|
69
|
+
example.exception = $!
|
70
|
+
raise
|
71
|
+
ensure
|
72
|
+
if example.exception
|
73
|
+
print_events
|
74
|
+
end
|
89
75
|
end
|
90
76
|
end
|
91
77
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
w.sync = true
|
99
|
-
[r,w]
|
100
|
-
end
|
101
|
-
let(:sync_read) { sync_pipe[0] }
|
102
|
-
let(:sync_write) { sync_pipe[1] }
|
103
|
-
|
104
|
-
after do
|
105
|
-
sync_read.close unless sync_read.closed?
|
106
|
-
sync_write.close unless sync_write.closed?
|
107
|
-
end
|
108
|
-
|
109
|
-
# Wait on synchronization signal. If not received within the timeout, an
|
110
|
-
# error is sent via the error channel, and the process exits.
|
111
|
-
def sync_wait
|
112
|
-
if IO.select([sync_read], nil, nil, 20).nil?
|
113
|
-
# timeout reading from the sync pipe.
|
114
|
-
send_side_channel_error("Error syncing processes in run lock test (timeout)")
|
115
|
-
exit!(1)
|
116
|
-
else
|
117
|
-
sync_read.getc
|
78
|
+
def print_events
|
79
|
+
# Consume any remaining events that went on the channel and print them all
|
80
|
+
p1.last_event
|
81
|
+
p2.last_event
|
82
|
+
events.each_with_index.sort_by { |(message, time), index| [ time, index ] }.each do |(message, time), index|
|
83
|
+
print "#{time} #{message}\n"
|
118
84
|
end
|
119
85
|
end
|
120
86
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
it "sets FD_CLOEXEC on the lockfile", :supports_cloexec => true do
|
171
|
-
run_lock.acquire
|
172
|
-
expect(run_lock.runlock.fcntl(Fcntl::F_GETFD, 0) & Fcntl::FD_CLOEXEC).to eq(Fcntl::FD_CLOEXEC)
|
173
|
-
end
|
174
|
-
|
175
|
-
it "allows only one chef client run per lockfile" do
|
176
|
-
# First process, gets the lock and keeps it.
|
177
|
-
p1 = fork do
|
178
|
-
run_lock.acquire
|
179
|
-
record "p1 has lock"
|
180
|
-
# Wait until the other process is trying to get the lock:
|
181
|
-
sync_wait
|
182
|
-
# sleep a little bit to make process p2 wait on the lock
|
183
|
-
sleep 2
|
184
|
-
record "p1 releasing lock"
|
185
|
-
run_lock.release
|
186
|
-
exit!(0)
|
87
|
+
context "when the lockfile does not already exist" do
|
88
|
+
context "when a client creates the lockfile but has not yet acquired the lock" do
|
89
|
+
before { p1.run_to("created lock") }
|
90
|
+
shared_context "second client gets the lock" do
|
91
|
+
it "the lockfile is created" do
|
92
|
+
log_event("lockfile exists? #{File.exist?(lockfile)}")
|
93
|
+
expect(File.exist?(lockfile)).to be_truthy
|
94
|
+
end
|
95
|
+
|
96
|
+
it "the lockfile is not locked" do
|
97
|
+
run_lock = Chef::RunLock.new(lockfile)
|
98
|
+
begin
|
99
|
+
expect(run_lock.test).to be_truthy
|
100
|
+
ensure
|
101
|
+
run_lock.release
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it "the lockfile is empty" do
|
106
|
+
expect(IO.read(lockfile)).to eq('')
|
107
|
+
end
|
108
|
+
|
109
|
+
context "and a second client gets the lock" do
|
110
|
+
before { p2.run_to("acquired lock") }
|
111
|
+
it "the first client does not get the lock until the second finishes" do
|
112
|
+
p1.run_to("acquired lock") do
|
113
|
+
p2.run_to_completion
|
114
|
+
end
|
115
|
+
end
|
116
|
+
it "and the first client tries to get the lock and the second is killed, the first client gets the lock immediately" do
|
117
|
+
p1.run_to("acquired lock") do
|
118
|
+
sleep BREATHING_ROOM
|
119
|
+
expect(p1.last_event).to match(/after (started|created lock)/)
|
120
|
+
p2.stop
|
121
|
+
end
|
122
|
+
p1.run_to_completion
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "and the second client has done nothing" do
|
128
|
+
include_context "second client gets the lock"
|
129
|
+
end
|
130
|
+
|
131
|
+
context "and the second client has created the lockfile but not yet acquired the lock" do
|
132
|
+
before { p2.run_to("created lock") }
|
133
|
+
include_context "second client gets the lock"
|
134
|
+
end
|
187
135
|
end
|
188
136
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
137
|
+
context "when a client acquires the lock but has not yet saved the pid" do
|
138
|
+
before { p1.run_to("acquired lock") }
|
139
|
+
|
140
|
+
it "the lockfile is created" do
|
141
|
+
log_event("lockfile exists? #{File.exist?(lockfile)}")
|
142
|
+
expect(File.exist?(lockfile)).to be_truthy
|
143
|
+
end
|
144
|
+
|
145
|
+
it "the lockfile is locked" do
|
146
|
+
run_lock = Chef::RunLock.new(lockfile)
|
147
|
+
begin
|
148
|
+
expect(run_lock.test).to be_falsey
|
149
|
+
ensure
|
150
|
+
run_lock.release
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
it "sets FD_CLOEXEC on the lockfile", :supports_cloexec => true do
|
155
|
+
run_lock = File.open(lockfile)
|
156
|
+
expect(run_lock.fcntl(Fcntl::F_GETFD, 0) & Fcntl::FD_CLOEXEC).to eq(Fcntl::FD_CLOEXEC)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "the lockfile is empty" do
|
160
|
+
expect(IO.read(lockfile)).to eq('')
|
161
|
+
end
|
162
|
+
|
163
|
+
it "and a second client tries to acquire the lock, it doesn't get the lock until *after* the first client exits" do
|
164
|
+
# Start p2 and tell it to move forward in the background
|
165
|
+
p2.run_to("acquired lock") do
|
166
|
+
# While p2 is trying to acquire, wait a bit and then let p1 complete
|
167
|
+
sleep(BREATHING_ROOM)
|
168
|
+
expect(p2.last_event).to match(/after (started|created lock)/)
|
169
|
+
p1.run_to_completion
|
170
|
+
end
|
171
|
+
|
172
|
+
p2.run_to_completion
|
173
|
+
end
|
174
|
+
|
175
|
+
it "and a second client tries to get the lock and the first is killed, the second client gets the lock immediately" do
|
176
|
+
p2.run_to("acquired lock") do
|
177
|
+
sleep BREATHING_ROOM
|
178
|
+
expect(p2.last_event).to match(/after (started|created lock)/)
|
179
|
+
p1.stop
|
180
|
+
end
|
181
|
+
p2.run_to_completion
|
182
|
+
end
|
199
183
|
end
|
200
184
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
185
|
+
context "when a client acquires the lock and saves the pid" do
|
186
|
+
before { p1.run_to("saved pid") }
|
187
|
+
|
188
|
+
it "the lockfile is created" do
|
189
|
+
expect(File.exist?(lockfile)).to be_truthy
|
190
|
+
end
|
191
|
+
|
192
|
+
it "the lockfile is locked" do
|
193
|
+
run_lock = Chef::RunLock.new(lockfile)
|
194
|
+
begin
|
195
|
+
expect(run_lock.test).to be_falsey
|
196
|
+
ensure
|
197
|
+
run_lock.release
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
it "sets FD_CLOEXEC on the lockfile", :supports_cloexec => true do
|
202
|
+
run_lock = File.open(lockfile)
|
203
|
+
expect(run_lock.fcntl(Fcntl::F_GETFD, 0) & Fcntl::FD_CLOEXEC).to eq(Fcntl::FD_CLOEXEC)
|
204
|
+
end
|
205
|
+
|
206
|
+
it "the PID is in the lockfile" do
|
207
|
+
expect(IO.read(lockfile)).to eq p1.pid.to_s
|
208
|
+
end
|
209
|
+
|
210
|
+
it "and a second client tries to acquire the lock, it doesn't get the lock until *after* the first client exits" do
|
211
|
+
# Start p2 and tell it to move forward in the background
|
212
|
+
p2.run_to("acquired lock") do
|
213
|
+
# While p2 is trying to acquire, wait a bit and then let p1 complete
|
214
|
+
sleep(BREATHING_ROOM)
|
215
|
+
expect(p2.last_event).to match(/after (started|created lock)/)
|
216
|
+
p1.run_to_completion
|
217
|
+
end
|
218
|
+
|
219
|
+
p2.run_to_completion
|
220
|
+
end
|
221
|
+
|
222
|
+
it "when a second client tries to get the lock and the first is killed, the second client gets the lock immediately" do
|
223
|
+
p2.run_to("acquired lock") do
|
224
|
+
sleep BREATHING_ROOM
|
225
|
+
expect(p2.last_event).to match(/after (started|created lock)/)
|
226
|
+
p1.stop
|
227
|
+
end
|
228
|
+
p2.run_to_completion
|
229
|
+
end
|
221
230
|
end
|
222
231
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
+
context "when a client acquires a lock and exits normally" do
|
233
|
+
before { p1.run_to_completion }
|
234
|
+
|
235
|
+
it "the lockfile remains" do
|
236
|
+
expect(File.exist?(lockfile)).to be_truthy
|
237
|
+
end
|
238
|
+
|
239
|
+
it "the lockfile is not locked" do
|
240
|
+
run_lock = Chef::RunLock.new(lockfile)
|
241
|
+
begin
|
242
|
+
expect(run_lock.test).to be_truthy
|
243
|
+
ensure
|
244
|
+
run_lock.release
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
it "the PID is in the lockfile" do
|
249
|
+
expect(IO.read(lockfile)).to eq p1.pid.to_s
|
250
|
+
end
|
251
|
+
|
252
|
+
it "and a second client tries to acquire the lock, it gets the lock immediately" do
|
253
|
+
p2.run_to_completion
|
254
|
+
end
|
232
255
|
end
|
233
|
-
|
234
|
-
Process.waitpid2(p2)
|
235
|
-
|
236
|
-
expect(results).to match(/p2 has lock\Z/)
|
237
256
|
end
|
238
257
|
|
239
258
|
it "test returns true and acquires the lock" do
|
259
|
+
run_lock = Chef::RunLock.new(lockfile)
|
240
260
|
p1 = fork do
|
241
261
|
expect(run_lock.test).to eq(true)
|
262
|
+
run_lock.save_pid
|
242
263
|
sleep 2
|
243
264
|
exit! 1
|
244
265
|
end
|
@@ -255,8 +276,10 @@ E
|
|
255
276
|
end
|
256
277
|
|
257
278
|
it "test returns without waiting when the lock is acquired" do
|
279
|
+
run_lock = Chef::RunLock.new(lockfile)
|
258
280
|
p1 = fork do
|
259
281
|
run_lock.acquire
|
282
|
+
run_lock.save_pid
|
260
283
|
sleep 2
|
261
284
|
exit! 1
|
262
285
|
end
|
@@ -267,20 +290,176 @@ E
|
|
267
290
|
Process.waitpid2(p1)
|
268
291
|
end
|
269
292
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
293
|
+
end
|
294
|
+
|
295
|
+
#
|
296
|
+
# Runs a process in the background that will:
|
297
|
+
#
|
298
|
+
# 1. start up (`started` event)
|
299
|
+
# 2. acquire the runlock file (`acquired lock` event)
|
300
|
+
# 3. save the pid to the lockfile (`saved pid` event)
|
301
|
+
# 4. exit
|
302
|
+
#
|
303
|
+
# You control exactly how far the client process goes with the `run_to`
|
304
|
+
# method: it will stop at any given spot so you can test for race conditions.
|
305
|
+
#
|
306
|
+
# It uses a pair of pipes to communicate with the process. The tests will
|
307
|
+
# send an event name over to the process, which gives the process permission
|
308
|
+
# to run until it reaches that event (at which point it waits for another event
|
309
|
+
# name). The process sends the name of each event it reaches back to the tests.
|
310
|
+
#
|
311
|
+
class ClientProcess
|
312
|
+
def initialize(example, name)
|
313
|
+
@example = example
|
314
|
+
@name = name
|
315
|
+
@read_from_process, @write_to_tests = IO.pipe
|
316
|
+
@read_from_tests, @write_to_process = IO.pipe
|
317
|
+
end
|
318
|
+
|
319
|
+
attr_reader :example
|
320
|
+
attr_reader :name
|
321
|
+
attr_reader :pid
|
322
|
+
|
323
|
+
def last_event
|
324
|
+
while true
|
325
|
+
line = readline_nonblock(read_from_process)
|
326
|
+
break if line.nil?
|
327
|
+
event, time = line.split("@")
|
328
|
+
example.log_event("#{name}.last_event got #{event}")
|
329
|
+
example.log_event("[#{name}] #{event}", time.strip)
|
330
|
+
@last_event = event
|
276
331
|
end
|
332
|
+
@last_event
|
333
|
+
end
|
277
334
|
|
278
|
-
|
279
|
-
|
280
|
-
expect(File.read(lockfile)).to eq(p1.to_s)
|
335
|
+
def run_to(to_event, &background_block)
|
336
|
+
example.log_event("#{name}.run_to(#{to_event.inspect})")
|
281
337
|
|
282
|
-
|
338
|
+
# Start the process if it's not started
|
339
|
+
start if !pid
|
340
|
+
|
341
|
+
# Tell the process what to stop at (also means it can go)
|
342
|
+
write_to_process.print "#{to_event}\n"
|
343
|
+
|
344
|
+
# Run the background block
|
345
|
+
background_block.call if background_block
|
346
|
+
|
347
|
+
# Wait until it gets there
|
348
|
+
Timeout::timeout(CLIENT_PROCESS_TIMEOUT) do
|
349
|
+
until @last_event == "after #{to_event}"
|
350
|
+
got_event, time = read_from_process.gets.split("@")
|
351
|
+
example.log_event("#{name}.last_event got #{got_event}")
|
352
|
+
example.log_event("[#{name}] #{got_event}", time.strip)
|
353
|
+
@last_event = got_event
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
example.log_event("#{name}.run_to(#{to_event.inspect}) finished")
|
283
358
|
end
|
284
359
|
|
360
|
+
def run_to_completion
|
361
|
+
example.log_event("#{name}.run_to_completion")
|
362
|
+
# Start the process if it's not started
|
363
|
+
start if !pid
|
364
|
+
|
365
|
+
# Tell the process to stop at nothing (no blocking)
|
366
|
+
@write_to_process.print "nothing\n"
|
367
|
+
|
368
|
+
# Wait for the process to exit
|
369
|
+
wait_for_exit
|
370
|
+
example.log_event("#{name}.run_to_completion finished")
|
371
|
+
end
|
372
|
+
|
373
|
+
def wait_for_exit
|
374
|
+
example.log_event("#{name}.wait_for_exit (pid #{pid})")
|
375
|
+
Timeout::timeout(CLIENT_PROCESS_TIMEOUT) do
|
376
|
+
Process.wait(pid) if pid
|
377
|
+
end
|
378
|
+
example.log_event("#{name}.wait_for_exit finished (pid #{pid})")
|
379
|
+
end
|
380
|
+
|
381
|
+
def stop
|
382
|
+
if pid
|
383
|
+
example.log_event("#{name}.stop (pid #{pid})")
|
384
|
+
begin
|
385
|
+
# Send it the kill signal over and over until it dies
|
386
|
+
Timeout::timeout(CLIENT_PROCESS_TIMEOUT) do
|
387
|
+
Process.kill(:KILL, pid)
|
388
|
+
while !Process.waitpid2(pid, Process::WNOHANG)
|
389
|
+
sleep(0.05)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
example.log_event("#{name}.stop finished (stopped pid #{pid})")
|
393
|
+
# Process not found is perfectly fine when we're trying to kill a process :)
|
394
|
+
rescue Errno::ESRCH
|
395
|
+
example.log_event("#{name}.stop finished (pid #{pid} wasn't running)")
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
def fire_event(event)
|
401
|
+
# Let the caller know what event we've reached
|
402
|
+
write_to_tests.print("after #{event}@#{Time.now.strftime("%H:%M:%S.%L")}\n")
|
403
|
+
|
404
|
+
# Block until the client tells us where to stop
|
405
|
+
if !@run_to_event || event == @run_to_event
|
406
|
+
write_to_tests.print("waiting for instructions after #{event}@#{Time.now.strftime("%H:%M:%S.%L")}\n")
|
407
|
+
@run_to_event = read_from_tests.gets.strip
|
408
|
+
write_to_tests.print("told to run to #{@run_to_event} after #{event}@#{Time.now.strftime("%H:%M:%S.%L")}\n")
|
409
|
+
elsif @run_to_event
|
410
|
+
write_to_tests.print("continuing until #{@run_to_event} after #{event}@#{Time.now.strftime("%H:%M:%S.%L")}\n")
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
private
|
415
|
+
|
416
|
+
attr_reader :read_from_process
|
417
|
+
attr_reader :write_to_tests
|
418
|
+
attr_reader :read_from_tests
|
419
|
+
attr_reader :write_to_process
|
420
|
+
|
421
|
+
class TestRunLock < Chef::RunLock
|
422
|
+
attr_accessor :client_process
|
423
|
+
def create_lock
|
424
|
+
super
|
425
|
+
client_process.fire_event("created lock")
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def start
|
430
|
+
example.log_event("#{name}.start")
|
431
|
+
@pid = fork do
|
432
|
+
begin
|
433
|
+
Timeout::timeout(CLIENT_PROCESS_TIMEOUT) do
|
434
|
+
run_lock = TestRunLock.new(example.lockfile)
|
435
|
+
run_lock.client_process = self
|
436
|
+
fire_event("started")
|
437
|
+
run_lock.acquire
|
438
|
+
fire_event("acquired lock")
|
439
|
+
run_lock.save_pid
|
440
|
+
fire_event("saved pid")
|
441
|
+
exit!(0)
|
442
|
+
end
|
443
|
+
rescue
|
444
|
+
fire_event($!.message.lines.join(" // "))
|
445
|
+
raise
|
446
|
+
end
|
447
|
+
end
|
448
|
+
example.log_event("#{name}.start forked (pid #{pid})")
|
449
|
+
end
|
450
|
+
|
451
|
+
def readline_nonblock(fd)
|
452
|
+
buffer = ""
|
453
|
+
buffer << fd.read_nonblock(1) while buffer[-1] != "\n"
|
454
|
+
|
455
|
+
buffer
|
456
|
+
#rescue IO::EAGAINUnreadable
|
457
|
+
rescue IO::WaitReadable
|
458
|
+
unless buffer == ""
|
459
|
+
sleep 0.1
|
460
|
+
retry
|
461
|
+
end
|
462
|
+
nil
|
463
|
+
end
|
285
464
|
end
|
286
465
|
end
|