diff --git a/acceptance/tests/resource/service/ticket_3927_redhat_systemd_vs_service_provider.rb b/acceptance/tests/resource/service/ticket_3927_redhat_systemd_vs_service_provider.rb new file mode 100644 index 000000000..eb5688241 --- /dev/null +++ b/acceptance/tests/resource/service/ticket_3927_redhat_systemd_vs_service_provider.rb @@ -0,0 +1,46 @@ +test_name 'RedHat Service vs. Systemd Provider Validation' + +# A simple acceptance test to ensure basic usage of the service +# provider works for a mix of sysV and systemd RedHat Linux platforms +confine :to, :platform => /el|centos|fedora/ + +manifest_install_httpd = %Q{ + package { 'httpd': + ensure => present, + } +} + +manifest_httpd_enabled = %Q{ + service { 'httpd': + enable => true, + } +} + +manifest_httpd_disabled = %Q{ + service { 'httpd': + enable => false, + } +} + +agents.each do |agent| + distro = on(agent, facter('operatingsystem')).stdout.chomp + if distro == 'fedora' + majrelease = on(agent, facter('operatingsystemmajrelease')).stdout.chomp.to_i + if majrelease < 17 + skip_test "Test not applicable to Fedora #{majrelease}" + elsif majrelease > 21 + # This is a reminder so we update the provider's defaultfor when new + # versions of Fedora are released (then update this test) + fail_test "Provider needs manual update to support Fedora #{majrelease}" + end + end + + step "installing httpd" + apply_manifest_on(agent, manifest_install_httpd, :catch_failures => true) + + step "enabling httpd" + apply_manifest_on(agent, manifest_httpd_enabled, :catch_failures => true) + + step "disabling httpd" + apply_manifest_on(agent, manifest_httpd_disabled, :catch_failures => true) +end diff --git a/lib/puppet/provider/service/systemd.rb b/lib/puppet/provider/service/systemd.rb index eb6df2927..94443e45b 100644 --- a/lib/puppet/provider/service/systemd.rb +++ b/lib/puppet/provider/service/systemd.rb @@ -1,65 +1,66 @@ # Manage systemd services using /bin/systemctl Puppet::Type.type(:service).provide :systemd, :parent => :base do desc "Manages `systemd` services using `systemctl`." commands :systemctl => "systemctl" defaultfor :osfamily => [:archlinux] defaultfor :osfamily => :redhat, :operatingsystemmajrelease => "7" + defaultfor :osfamily => :redhat, :operatingsystem => :fedora, :operatingsystemmajrelease => ["17", "18", "19", "20", "21"] def self.instances i = [] output = systemctl('list-unit-files', '--type', 'service', '--full', '--all', '--no-pager') output.scan(/^(\S+)\s+(disabled|enabled)\s*$/i).each do |m| i << new(:name => m[0]) end return i rescue Puppet::ExecutionFailure return [] end def disable output = systemctl(:disable, @resource[:name]) rescue Puppet::ExecutionFailure raise Puppet::Error, "Could not disable #{self.name}: #{output}", $!.backtrace end def enabled? begin systemctl("is-enabled", @resource[:name]) rescue Puppet::ExecutionFailure return :false end :true end def status begin systemctl("is-active", @resource[:name]) rescue Puppet::ExecutionFailure return :stopped end return :running end def enable output = systemctl("enable", @resource[:name]) rescue Puppet::ExecutionFailure raise Puppet::Error, "Could not enable #{self.name}: #{output}", $!.backtrace end def restartcmd [command(:systemctl), "restart", @resource[:name]] end def startcmd [command(:systemctl), "start", @resource[:name]] end def stopcmd [command(:systemctl), "stop", @resource[:name]] end end diff --git a/spec/unit/provider/service/systemd_spec.rb b/spec/unit/provider/service/systemd_spec.rb index 54c95da96..2697b9c30 100755 --- a/spec/unit/provider/service/systemd_spec.rb +++ b/spec/unit/provider/service/systemd_spec.rb @@ -1,158 +1,170 @@ #! /usr/bin/env ruby # # Unit testing for the systemd service Provider # require 'spec_helper' describe Puppet::Type.type(:service).provider(:systemd) do before :each do Puppet::Type.type(:service).stubs(:defaultprovider).returns described_class described_class.stubs(:which).with('systemctl').returns '/bin/systemctl' end let :provider do described_class.new(:name => 'sshd.service') end osfamily = [ 'archlinux' ] osfamily.each do |osfamily| it "should be the default provider on #{osfamily}" do Facter.expects(:value).with(:osfamily).returns(osfamily) described_class.default?.should be_true end end it "should be the default provider on rhel7" do Facter.expects(:value).with(:osfamily).at_least_once.returns(:redhat) Facter.expects(:value).with(:operatingsystemmajrelease).returns("7") described_class.default?.should be_true end - it "should not be the default provider on rhel6" do - Facter.expects(:value).with(:osfamily).at_least_once.returns(:redhat) - Facter.expects(:value).with(:operatingsystemmajrelease).returns("6") - described_class.default?.should_not be_true + [ 4, 5, 6 ].each do |ver| + it "should not be the default provider on rhel#{ver}" do + Facter.expects(:value).with(:osfamily).at_least_once.returns(:redhat) + Facter.expects(:value).with(:operatingsystem).returns(:redhat) + Facter.expects(:value).with(:operatingsystemmajrelease).at_least_once.returns("#{ver}") + described_class.default?.should_not be_true + end + end + + [ 17, 18, 19, 20, 21 ].each do |ver| + it "should be the default provider on fedora#{ver}" do + Facter.expects(:value).with(:osfamily).at_least_once.returns(:redhat) + Facter.expects(:value).with(:operatingsystem).at_least_once.returns(:fedora) + Facter.expects(:value).with(:operatingsystemmajrelease).at_least_once.returns("#{ver}") + described_class.default?.should be_true + end end [:enabled?, :enable, :disable, :start, :stop, :status, :restart].each do |method| it "should have a #{method} method" do provider.should respond_to(method) end end describe ".instances" do it "should have an instances method" do described_class.should respond_to :instances end it "should return only services" do described_class.expects(:systemctl).with('list-unit-files', '--type', 'service', '--full', '--all', '--no-pager').returns File.read(my_fixture('list_unit_files_services')) described_class.instances.map(&:name).should =~ %w{ arp-ethers.service auditd.service autovt@.service avahi-daemon.service blk-availability.service } end end describe "#start" do it "should use the supplied start command if specified" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service', :start => '/bin/foo')) provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :override_locale => false, :squelch => false, :combine => true) provider.start end it "should start the service with systemctl start otherwise" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service')) provider.expects(:execute).with(['/bin/systemctl','start','sshd.service'], :failonfail => true, :override_locale => false, :squelch => false, :combine => true) provider.start end end describe "#stop" do it "should use the supplied stop command if specified" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service', :stop => '/bin/foo')) provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :override_locale => false, :squelch => false, :combine => true) provider.stop end it "should stop the service with systemctl stop otherwise" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service')) provider.expects(:execute).with(['/bin/systemctl','stop','sshd.service'], :failonfail => true, :override_locale => false, :squelch => false, :combine => true) provider.stop end end describe "#enabled?" do it "should return :true if the service is enabled" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service')) provider.expects(:systemctl).with('is-enabled', 'sshd.service').returns 'enabled' provider.enabled?.should == :true end it "should return :false if the service is disabled" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service')) provider.expects(:systemctl).with('is-enabled', 'sshd.service').raises Puppet::ExecutionFailure, "Execution of '/bin/systemctl is-enabled sshd.service' returned 1: disabled" provider.enabled?.should == :false end end describe "#enable" do it "should run systemctl enable to enable a service" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service')) provider.expects(:systemctl).with('enable', 'sshd.service') provider.enable end end describe "#disable" do it "should run systemctl disable to disable a service" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service')) provider.expects(:systemctl).with(:disable, 'sshd.service') provider.disable end end # Note: systemd provider does not care about hasstatus or a custom status # command. I just assume that it does not make sense for systemd. describe "#status" do it "should return running if active" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service')) provider.expects(:systemctl).with('is-active', 'sshd.service').returns 'active' provider.status.should == :running end it "should return stopped if inactive" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service')) provider.expects(:systemctl).with('is-active', 'sshd.service').raises Puppet::ExecutionFailure, "Execution of '/bin/systemctl is-active sshd.service' returned 3: inactive" provider.status.should == :stopped end end # Note: systemd provider does not care about hasrestart. I just assume it # does not make sense for systemd describe "#restart" do it "should use the supplied restart command if specified" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :restart => '/bin/foo')) provider.expects(:execute).with(['/bin/systemctl','restart','sshd.service'], :failonfail => true, :override_locale => false, :squelch => false, :combine => true).never provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :override_locale => false, :squelch => false, :combine => true) provider.restart end it "should restart the service with systemctl restart" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service')) provider.expects(:execute).with(['/bin/systemctl','restart','sshd.service'], :failonfail => true, :override_locale => false, :squelch => false, :combine => true) provider.restart end end it "(#16451) has command systemctl without being fully qualified" do described_class.instance_variable_get(:@commands). should include(:systemctl => 'systemctl') end end