Skip to content

Commit

Permalink
Fixes #7192: Rewrite the service_* methods
Browse files Browse the repository at this point in the history
  • Loading branch information
amousset committed Feb 28, 2017
1 parent 9b20fc2 commit cf762a1
Show file tree
Hide file tree
Showing 13 changed files with 389 additions and 328 deletions.
270 changes: 270 additions & 0 deletions tree/20_cfe_basics/ncf_lib.cf
Original file line number Diff line number Diff line change
Expand Up @@ -772,3 +772,273 @@ body edit_defaults ncf_empty_select(select)
max_file_size => "25M";
edit_backup => "timestamp";
}

# defines ncf_services_${service}_${action}
# Set variables with the error
# Test behavior with unkown action
# is-active not implemented for service/init.d

# Standard actions are:
#
# * start
# * stop
# * restart
# * reload (with an alias to refresh)
# * is-active
# * is-active-process
# * enable
# * disable
# * is-enabled
#
# When using service, init.d or systemd, any unkown action will be passed as is to the command
#
bundle agent ncf_services(service, action)
{
vars:

###########################################################################
# All actions
###########################################################################

# These commands (sadly) are not completely static (as on debian 8 the outcome depends on the service)

# systemd
pass1.!broken_systemctl.systemctl_utility_present::
"action_command" string => "${paths.path[systemctl]} --no-ask-password ${action} ${service}.service";
"method" string => "systemctl";

# svcadm/svcs
pass1.!systemctl_utility_present.svcadm_utility_present::
# non-boot
"svc_action_cmd[start]" string => "${paths.path[svcadm]} enable -s -t ${service}";
"svc_action_cmd[stop]" string => "${paths.path[svcadm]} disable -s -t ${service}";
"svc_action_cmd[restart]" string => "${paths.path[svcadm]} restart -s ${service}";
"svc_action_cmd[reload]" string => "${paths.path[svcadm]} refresh -s ${service}";
"svc_action_cmd[is-active]" string => "${paths.path[svcs]} -H ${service} | grep '^online'";
# boot
"svc_action_cmd[enable]" string => "${paths.path[svcadm]} enable -s ${service}";
"svc_action_cmd[disable]" string => "${paths.path[svcadm]} disable -s ${service}";
"svc_action_cmd[is-enabled]" string => "${paths.path[svcs]} -l ${service} | egrep '^enabled [ ]+(true|false \(temporary\))'";
"action_command" string => "${svc_action_cmd[${action}]}";
"method" string => "svcadm/svcs";

###########################################################################
# Boot actions
###########################################################################

# chkconfig
pass1.is_boot_action.!systemctl_utility_present.!svcadm_utility_present.chkconfig_utility_present::
"chkconfig_action_cmd[enable]" string => "${paths.path[chkconfig]} ${service} on";
"chkconfig_action_cmd[disable]" string => "${paths.path[chkconfig]} ${service} off";
"chkconfig_action_cmd[is-enabled]" string => "${paths.path[chkconfig]} --list ${service} | grep -q -e 3:on -e B:on";
"action_command" string => "${chkconfig_action_cmd[${action}]}";
"method" string => "chkconfig";

# update-rc.d
# WARN: "is-enabled" will use /etc/rcX.d/ directly
pass1.is_boot_action.!is_check_action.!systemctl_utility_present.!svcadm_utility_present.!chkconfig_utility_present.update_rcd_utility_present::
"update_rcd_action_cmd[enable]" string => "${paths.path[update_rc_d]} ${service} defaults";
"update_rcd_action_cmd[disable]" string => "${paths.path[update_rc_d]} ${service} disable";
"action_command" string => "${update_rcd_action_cmd[${action}]}";
"method" string => "update-rc.d";

# chitab/lsitab
pass1.is_boot_action.!systemctl_utility_present.!svcadm_utility_present.!chkconfig_utility_present.!update_rcd_utility_present.chitab_utility_present::
"chitab_action_cmd[enable]" string => "/usr/sbin/chitab \"`lsitab -a | grep '^${service}:' | sed 's/\([^:]*\):\([^:]*\):[^:]*:\(.*\)/\1:\2:respawn:\3/'`\"";
"chitab_action_cmd[disable]" string => "/usr/sbin/chitab \"`lsitab -a | grep '^${service}:' | sed 's/\([^:]*\):\([^:]*\):[^:]*:\(.*\)/\1:\2:off:\3/'`\"";
"lsitab_action_cmd[is-enabled]" string => "/usr/sbin/lsitab -a | egrep '^${service}:[0-9]+:(respawn|boot|bootwait|wait|once|initdefault|sysinit):'";
"action_command" string => "${lsitab_action_cmd[${action}]}";
"method" string => "lsitab/chitab";

# /etc/rcX.d/
pass1.is_boot_action.is_check_action.(broken_systemctl|(!systemctl_utility_present.!svcadm_utility_present.!chkconfig_utility_present.!chitab_utility_present))::
"action_command" string => "${paths.path[test]} -f /etc/rc`runlevel | ${paths.path[cut]} -d' ' -f2`.d/S??${service_name}";
"method" string => "/etc/rcX.d/";

###########################################################################
# Non-boot actions
###########################################################################

# service
# WARN: Some actions may not be supported by the init script
pass1.!is_boot_action.!systemctl_utility_present.!svcadm_utility_present.service_utility_present::
"action_command" string => "${paths.path[service]} ${service} ${action}";
"method" string => "service";

# src
pass1.!is_boot_action.!systemctl_utility_present.!svcadm_utility_present.!service_utility_present.startsrc_utility_present::
"svc_action_cmd[start]" string => "/usr/bin/startsrc -s ${service}";
"svc_action_cmd[stop]" string => "/usr/bin/stopsrc -s ${service}";
"svc_action_cmd[restart]" string => "/usr/bin/stopsrc -s ${service} && until /usr/bin/lssrc -s ${service} | ${paths.grep} -q inoperative; do ${paths.perl} -e 'select(undef,undef,undef,.25)'; done; /usr/bin/startsrc -s ${service_name}";
"svc_action_cmd[reload]" string => "/usr/bin/refresh -s ${service}";
"svc_action_cmd[is-active]" string => "/usr/bin/lssrc -s ${service} | grep -q 'active'";
"action_command" string => "${svc_action_cmd[${action}]}";
"method" string => "src";

# init.d
# WARN: Some actions may not be supported by the init script
pass1.!is_boot_action.!systemctl_utility_present.!svcadm_utility_present.!service_utility_present.!startsrc_utility_present.init_d_directory_present::
"action_command" string => "/etc/init.d/${service} ${action}";
"method" string => "/etc/init.d/";

# windows
# Implementation is done in services promises
windows::
"method" string => "Windows Service Manager";

###########################################################################

any::
"canonified_service" string => canonify("${service}");
"canonified_action" string => canonify("${action}");
"canonified_action_command" string => canonify("${action_command}");

"old_class_prefix" string => "ncf_services_${canonified_service}_${canonified_action}";
"promisers" slist => { @{this.callers_promisers}, cf_null }, policy => "ifdefined";
"class_prefix" string => canonify(join("_", "promisers"));
"args" slist => { "${service}", "${action}" };

defaults:
# Rename "is-active" to "status" for service and init.d methods
# The condition is ((use service) or (use init.d))
# This allows staying compatible with any action and not be restricted to a predefined list
!systemctl_utility_present.!svcadm_utility_present.(service_utility_present|(!startsrc_utility_present.init_d_directory_present)))::
"action" string => "status", if_match_regex => "is-active";

# refresh is an alias to reload
any::
"action" string => "reload", if_match_regex => "refresh";

classes:

windows::
"is_valid_action" or => {
strcmp("start", "${action}"),
strcmp("stop", "${action}"),
strcmp("restart", "${action}"),
};
"is_restart_action" expression => strcmp("restart", "${action}");

any::
"is_boot_action" or => {
strcmp("enable", "${action}"),
strcmp("disable", "${action}"),
strcmp("is-enabled", "${action}")
};

"is_check_action" or => {
strcmp("is-active", "${action}"),
strcmp("is-active-process", "${action}"),
strcmp("is-enabled", "${action}")
};

"is_process_action" expression => strcmp("is-active-process", "${action}");

pass1::
"method_found" expression => isvariable("method");

#####
# Actual command - for checks on non-windows systems
#####
pass1.!windows.!is_process_action.method_found::
"action_ok" expression => returnszero("${action_command}", "useshell");

debian_8::
# This is to workaround a bug in Debian Jessie, that makes systemctl is-enabled
# fail if run against a service that still uses SysV style scripts
# See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=760616
"is_broken_action" expression => strcmp("is-enabled", "${action}");
"init_script_present" expression => fileexists("/etc/init.d/${service}");
"broken_systemctl" expression => "is_broken_action.init_script_present";

any::
"pass3" expression => "pass2";
"pass2" expression => "pass1";
"pass1" expression => "any";

methods:

#####
# Actual command - for actions on non-windows systems, non using systemd
#####
pass2.!windows.!is_process_action.method_found.action_ok.is_check_action::
"force_success_class" usebundle => _classes_success("${old_class_prefix}");
"force_success_class" usebundle => _classes_success("${class_prefix}");

pass2.!windows.!is_process_action.method_found.action_ok.!is_check_action::
"force_success_class" usebundle => _classes_repaired("${old_class_prefix}");
"force_success_class" usebundle => _classes_repaired("${class_prefix}");

pass2.!windows.!is_process_action.method_found.!action_ok::
"force_failure_class" usebundle => _classes_failure("${old_class_prefix}");
"force_failure_class" usebundle => _classes_failure("${class_prefix}");

# Method not found
pass2.(!method_found|(windows.!is_valid_action))::
"force_failure_class" usebundle => _classes_failure("${old_class_prefix}");
"force_failure_class" usebundle => _classes_failure("${class_prefix}");

# Classes for process check
pass2::
"force_failure_process" usebundle => _classes_failure("${old_class_prefix}"),
ifvarclass => "${old_class_prefix}_checked_not_ok";
"force_failure_process" usebundle => _classes_failure("${class_prefix}"),
ifvarclass => "${old_class_prefix}_checked_not_ok";

"force_success_process" usebundle => _classes_success("${old_class_prefix}"),
ifvarclass => "${old_class_prefix}_checked_ok";
"force_success_process" usebundle => _classes_success("${class_prefix}"),
ifvarclass => "${class_prefix}_checked_ok";

services:

###########################################################################
# Windows - only non-boot actions
###########################################################################

#####
# Actual command - for actions on windows systems
#####
# Restart causes the agent to fail, so we must replace it by stop and start
windows.is_valid_action.!is_restart_action::
"${service}"
service_policy => "${action}",
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

windows.is_restart_action::
"${service}"
service_policy => "stop",
classes => classes_generic_two("${old_class_prefix}_stop_service", "${class_prefix}_stop_service");

"${service}"
service_policy => "start",
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}"),
ifvarclass => "(!has_promiser_stack.${old_class_prefix}_stop_service_ok)|(has_promiser_stack.${class_prefix}_stop_service_ok)";

processes:

###########################################################################
# is-active-process action
###########################################################################

is_process_action::
"${service}"
process_count => any_count_two("${old_class_prefix}_checked_ok", "${class_prefix}_checked_ok");

"${service}"
# missing new_class_prefix : we cannot put 2 classes here, so we put the only one that we are sure works
restart_class => "${old_class_prefix}_checked_not_ok";

reports:

pass3.error.!method_found::
"${configuration.error} Could not find a supported service management method on this system";
pass3.error.!is_valid_action::
"${configuration.error} The ${action} action is not supported on Windows (use 'start', 'stop' or 'restart')";

pass3.info.method_found.(!windows|is_valid_action)::
"${configuration.info} Executing ${action} on ${service} using the ${method} method";

pass3.debug.method_found.!windows::
"${configuration.debug} Executing: '${action_command}'";
}
30 changes: 3 additions & 27 deletions tree/30_generic_methods/_service_check_running_smf.cf
Original file line number Diff line number Diff line change
Expand Up @@ -23,45 +23,21 @@
#
# @class_prefix service_check_running
# @class_parameter service_name
# @deprecated Use [service_check_running](#service_check_running) instead.

bundle agent _service_check_running_smf(service_name)
{
vars:
"canonified_service_name" string => canonify("${service_name}");

"old_class_prefix" string => canonify("service_check_running_${service_name}");
"promisers" slist => { @{this.callers_promisers}, cf_null }, policy => "ifdefined";
"class_prefix" string => canonify(join("_", "promisers"));
"args" slist => { "${service_name}" };

"check_command" string => "${paths.path[svcs]} -H ${service_name} | grep '^online'";
"check_command_canon" string => canonify("${check_command}");

methods:

svcs_utility_present::
"check_if_service_is_running" usebundle => command_execution_result("${check_command}", "0", "1");

"old_success_classes"
usebundle => _classes_success("${old_class_prefix}"),
ifvarclass => "command_execution_result_${check_command_canon}_kept";

"success_classes"
usebundle => _classes_success("${class_prefix}"),
ifvarclass => "${class_prefix}_check_if_service_is_running_kept";

"old_failure_class"
usebundle => _classes_failure("${old_class_prefix}"),
ifvarclass => canonify("command_execution_result_${check_command}_repaired");

"failure_class"
usebundle => _classes_failure("${class_prefix}"),
ifvarclass => "${class_prefix}_check_if_service_is_running_repaired";
"check_if_service_is_running" usebundle => service_check_running("${service_name}");

"report"
usebundle => _log("Check if the service ${service_name} is started using SMF", "${old_class_prefix}", "${class_prefix}", @{args});

!svcs_utility_present::
"old_force_failure_class" usebundle => _classes_failure("${old_class_prefix}");
"force_failure_class" usebundle => _classes_failure("${class_prefix}");
"report" usebundle => _log("Can't check if service ${service_name} is running, svcs is not available", "${old_class_prefix}", "${class_prefix}", @{args});
}
30 changes: 3 additions & 27 deletions tree/30_generic_methods/_service_check_running_src.cf
Original file line number Diff line number Diff line change
Expand Up @@ -23,45 +23,21 @@
#
# @class_prefix service_check_running
# @class_parameter service_name
# @deprecated Use [service_check_running](#service_check_running) instead.

bundle agent _service_check_running_src(service_name)
{
vars:
"canonified_service_name" string => canonify("${service_name}");

"old_class_prefix" string => canonify("service_check_running_${service_name}");
"promisers" slist => { @{this.callers_promisers}, cf_null }, policy => "ifdefined";
"class_prefix" string => canonify(join("_", "promisers"));
"args" slist => { "${service_name}" };

"check_command" string => "/usr/bin/lssrc -s ${service_name} | grep -q 'active'";
"check_command_canon" string => canonify("${check_command}");

methods:

lssrc_utility_present::
"check if subsystem is running" usebundle => command_execution_result("${check_command}", "0", "1");

"success_classes"
usebundle => _classes_success("${old_class_prefix}"),
ifvarclass => "command_execution_result_${check_command_canon}_kept";

"success_classes"
usebundle => _classes_success("${class_prefix}"),
ifvarclass => "has_promiser_stack.${class_prefix}_check_if_subsystem_is_running_kept";

"failure_class"
usebundle => _classes_failure("${old_class_prefix}"),
ifvarclass => canonify("command_execution_result_${check_command}_repaired");

"failure_class"
usebundle => _classes_failure("${class_prefix}"),
ifvarclass => "has_promiser_stack.${class_prefix}_check_if_subsystem_is_running_repaired";
"check if subsystem is running" usebundle => service_check_running("${service_name}");

"report"
usebundle => _log("Check if the service ${service_name} is started using SRC", "${old_class_prefix}", "${class_prefix}", @{args});

!lssrc_utility_present::
"force_failure_class" usebundle => _classes_failure("${class_prefix}");
"report" usebundle => _log("Can't check if service ${service_name} is running, lssrc is not available", "${old_class_prefix}", "${class_prefix}", @{args});

}
Loading

0 comments on commit cf762a1

Please sign in to comment.