Class: RuboCop::Cop::Chef::RedundantCode::ServiceGuardOnStopDisable

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Includes:
RangeHelp, RuboCop::Chef::CookbookHelpers
Defined in:
lib/rubocop/cop/chef/redundant/service_guard_on_stop_disable.rb

Overview

The :stop and :disable actions of the service resource are already no-ops when the service isn't installed, so guarding them with a check for the init script or unit file adds nothing. The base provider only converges these actions when current_resource.running/current_resource.enabled is set, and the platform providers never set that state for a service they can't find.

The guard is also actively harmful because it hardcodes a single path while the provider searches several. A guard on /usr/local/etc/rc.d/snmpd skips a FreeBSD host running the service out of /etc/rc.d, and the run then reports success while leaving the service enabled.

This cop only fires when every action is :stop or :disable. Actions like :start, :enable, :restart, and :reload are asserted against the init script, so a guard there is meaningful. The systemd_unit resource shells out unconditionally, so its guards are meaningful as well and are never flagged.

Examples:


# bad
service 'snmpd' do
  action %i(stop disable)
  only_if { ::File.exist?('/usr/local/etc/rc.d/snmpd') }
end

# good
service 'snmpd' do
  action %i(stop disable)
end

Constant Summary collapse

MSG =
'A service resource that only stops or disables a service does not need a guard checking for the init script or unit file. Chef Infra Client already skips these actions when the service does not exist, and hardcoding a single path can silently skip services installed elsewhere.'
NO_OP_ACTIONS =

actions that Chef Infra Client treats as no-ops when the service can't be found

%i(stop disable).freeze
INIT_SCRIPT_PATH =

the directories the various service providers search for init scripts and unit files

%r{/(?:etc/init\.d|etc/rc\.d|usr/local/etc/rc\.d|etc/sv|systemd/system)/}.freeze

Instance Method Summary collapse

Methods included from RuboCop::Chef::CookbookHelpers

#each_action_symbol, #match_property_in_resource?, #match_resource_type?, #method_arg_ast_to_string, #resource_block_name_if_string

Methods inherited from Base

#target_chef_version

Instance Method Details

#on_block(node) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/rubocop/cop/chef/redundant/service_guard_on_stop_disable.rb', line 68

def on_block(node)
  match_property_in_resource?(:service, %i(only_if not_if), node) do |guard|
    # a string guard like `only_if 'test -f /etc/init.d/foo'` isn't a Ruby block
    next unless guard.block_type?
    next unless only_no_op_actions?(node)

    # `guard.body` is only a bare send when the block does nothing but the existence check.
    # Anything more (a `&&`, a second statement) is a guard we shouldn't touch.
    path = file_exist_check(guard.body)
    next unless path && INIT_SCRIPT_PATH.match?(path.source)

    add_offense(guard, severity: :refactor) do |corrector|
      corrector.remove(range_by_whole_lines(guard.source_range, include_final_newline: true))
    end
  end
end