diff options
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | lib/chef/knife/bootstrap/templates/chef-full.erb | 2 | ||||
-rw-r--r-- | lib/chef/provider/package/openbsd.rb | 67 | ||||
-rw-r--r-- | spec/unit/provider/package/openbsd_spec.rb | 122 |
4 files changed, 156 insertions, 36 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 5760097934..609cf9825f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ 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 ## 12.1.2 * [Issue 3022](https://github.com/chef/chef/issues/3022): Homebrew Cask install fails diff --git a/lib/chef/knife/bootstrap/templates/chef-full.erb b/lib/chef/knife/bootstrap/templates/chef-full.erb index 17d7a9e3b5..a87ab8e544 100644 --- a/lib/chef/knife/bootstrap/templates/chef-full.erb +++ b/lib/chef/knife/bootstrap/templates/chef-full.erb @@ -22,7 +22,7 @@ exists() { <% if knife_config[:bootstrap_install_command] %> <%= knife_config[:bootstrap_install_command] %> <% else %> - install_sh="<%= knife_config[:bootstrap_url] ? knife_config[:bootstrap_url] : "https://www.chef.io/chef/install.sh" %>" + install_sh="<%= knife_config[:bootstrap_url] ? knife_config[:bootstrap_url] : "https://www.opscode.com/chef/install.sh" %>" if ! exists /usr/bin/chef-client; then echo "Installing Chef Client..." if exists wget; then diff --git a/lib/chef/provider/package/openbsd.rb b/lib/chef/provider/package/openbsd.rb index f0931d7555..82048c3bd4 100644 --- a/lib/chef/provider/package/openbsd.rb +++ b/lib/chef/provider/package/openbsd.rb @@ -24,6 +24,7 @@ require 'chef/resource/package' require 'chef/provider/package' require 'chef/mixin/shell_out' require 'chef/mixin/get_source_from_package' +require 'chef/exceptions' class Chef class Provider @@ -37,25 +38,42 @@ class Chef def initialize(*args) super - @current_resource = Chef::Resource::Package.new(@new_resource.name) - @new_resource.source(pkg_path) if !@new_resource.source + @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(installed_version) @current_resource end + def define_resource_requirements + super + + # 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') + end + requirements.assert(:all_actions) do |a| + a.assertion do + if new_resource.package_name =~ /^(.+?)--(.+)/ + !new_resource.version + else + true + end + end + 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 - version_string = '' - version_string += "-#{version}" if version if parts = name.match(/^(.+?)--(.+)/) # use double-dash for stems with flavors, see man page for pkg_add name = parts[1] end - shell_out!("pkg_add -r #{name}#{version_string}", :env => {"PKG_PATH" => @new_resource.source}).status - Chef::Log.debug("#{@new_resource} installed from: #{@new_resource.source}") + shell_out!("pkg_add -r #{name}#{version_string}", :env => {"PKG_PATH" => pkg_path}).status + Chef::Log.debug("#{new_resource.package_name} installed") end end @@ -71,32 +89,45 @@ class Chef private def installed_version - if parts = @new_resource.package_name.match(/^(.+?)--(.+)/) + if parts = new_resource.package_name.match(/^(.+?)--(.+)/) name = parts[1] else - name = @new_resource.package_name + name = new_resource.package_name end pkg_info = shell_out!("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}'") + Chef::Log.debug("installed_version of '#{new_resource.package_name}' is '#{result}'") result end def candidate_version @candidate_version ||= begin - version_string = '' - version_string += "-#{version}" if @new_resource.version - pkg_info = shell_out!("pkg_info -I \"#{@new_resource.package_name}#{version_string}\"", :env => nil, :returns => [0,1]) - if parts = @new_resource.package_name.match(/^(.+?)--(.+)/) - result = pkg_info.stdout[/^#{Regexp.escape(parts[1])}-(.+?)\s/, 1] + results = [] + shell_out!("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 + end + results = results.reject(&:nil?) + Chef::Log.debug("candidate versions of '#{new_resource.package_name}' are '#{results}'") + case results.length + when 0 + [] + when 1 + results[0] else - result = pkg_info.stdout[/^#{Regexp.escape(@new_resource.package_name)}-(.+?)\s/, 1] + raise Chef::Exceptions::Package, "#{new_resource.name} has multiple matching candidates. Please use a more specific name" if results.length > 1 end - Chef::Log.debug("candidate_version of '#{@new_resource.package_name}' is '#{result}'") - result end end + def version_string + ver = '' + ver += "-#{new_resource.version}" if new_resource.version + end + def pkg_path ENV['PKG_PATH'] || "http://ftp.OpenBSD.org/pub/#{node.kernel.name}/#{node.kernel.release}/packages/#{node.kernel.machine}/" end diff --git a/spec/unit/provider/package/openbsd_spec.rb b/spec/unit/provider/package/openbsd_spec.rb index ee9c9e89fb..b0cdb9969d 100644 --- a/spec/unit/provider/package/openbsd_spec.rb +++ b/spec/unit/provider/package/openbsd_spec.rb @@ -21,28 +21,116 @@ 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 + end + + let (:provider) do + events = Chef::EventDispatch::Dispatcher.new + run_context = Chef::RunContext.new(node, {}, events) + Chef::Provider::Package::Openbsd.new(new_resource, run_context) + end + + let(:new_resource) { Chef::Resource::Package.new(name)} + before(:each) do - @node = Chef::Node.new - @node.default['kernel'] = {'name' => 'OpenBSD', 'release' => '5.5', 'machine' => 'amd64'} - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) ENV['PKG_PATH'] = nil end describe "install a package" do - before do - @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) - @provider.current_resource = @current_resource - end - it "should run the installation command" do - expect(@provider).to receive(:shell_out!).with( - "pkg_add -r #{@name}", - {:env => {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}} - ) {OpenStruct.new :status => true} - @provider.install_package(@name, nil) + let(:name) { 'ihavetoes' } + let(:version) {'0.0'} + + 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 => '')) + end + + context 'when there is a single candidate' do + + context 'when installing from source' do + it 'should run the installation command' do + pending('Installing from source is not supported yet') + # This is a consequence of load_current_resource being called before define_resource_requirements + # It can be deleted once an implementation is provided + allow(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}\"", anything()).and_return( + instance_double('shellout', :stdout => "#{name}-#{version}\n")) + new_resource.source('/some/path/on/disk.tgz') + provider.run_action(:install) + end + end + + 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/"}} + ) {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 '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 + + 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")) + 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/"}} + ) {OpenStruct.new :status => true} + provider.run_action(:install) + end + end + + context 'if a version is specified' do + it 'runs the installation command' do + pending('Specifying both a version and flavor is not supported') + new_resource.version(version) + allow(provider).to receive(:shell_out!).with(/pkg_info -e/, anything()).and_return(instance_double('shellout', :stdout => '')) + allow(provider).to receive(:candidate_version).and_return("#{package_name}-#{version}-#{flavor}") + 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")) + + 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/"}} + ) {OpenStruct.new :status => true} + provider.run_action(:install) + end + end + end end end |