From 0b3908ea518f371237642dec2790be6b1c25db95 Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Sun, 5 Mar 2017 14:43:06 +0000 Subject: Initial import --- failsafe.cf | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 failsafe.cf (limited to 'failsafe.cf') diff --git a/failsafe.cf b/failsafe.cf new file mode 100644 index 0000000..c23942e --- /dev/null +++ b/failsafe.cf @@ -0,0 +1,185 @@ +# Failsafe file +# - Always ensured to run the update bundle. Do not modify. Ever. + +# Failsafe imports and promises +body agent control { + any:: + abortclasses => { "no_ppkeys_ABORT_kept" }; # Bootstrapping can't continue without keys + ifelapsed => "0"; # Make sure that running failsafe many times in a row does not change functionality +} + +bundle agent main { + methods: + any:: + "Check Keys" + usebundle => failsafe_checkkeys, + comment => "Without a valid keypair we aren't going to be able to establish trust"; + "Fetch Inputs" + usebundle => failsafe_update, + comment => "We need to fetch policy from upstream if we are bootstrapping or if we are performing failsafe recovery."; + "Actuate Update Policy" + usebundle => failsafe_call_update, + comment => "In order to speed up convergence and reporting we trigger the update policy right after initial + bootstrap. This allows the first scheduled run to happen with the most up to date and complete information."; + "Report" + usebundle => failsafe_report, + comment => "It's important to let the user know what happened as the result of the bootstrap or failsafe operation."; +} + +bundle agent failsafe_checkkeys +{ + classes: + any:: + "have_ppkeys" expression => fileexists("$(sys.workdir)/ppkeys/localhost.pub"); + reports: + !have_ppkeys:: + "No public/private key pair is loaded, please create one by running \"cf-key\"" classes => failsafe_results("namespace", "no_ppkeys_ABORT"); +} + +bundle agent failsafe_update { + vars: + any:: + # A policy server cannot use the shortcut feature to resolve + # masterfiles since cf-serverd is potentially not yet up and + # running. + # The unqualified path is used for non policy servers so that + # the policy server can use a shortcut to decide on behalf of + # the client which policy to serve by default. This is useful + # when running binaires from mixed sources (for example CFEngine + # produced binaries vs packages from the debian repository). + "masterfiles_dir_remote" string => ifelse( "policy_server", $(sys.masterdir), "masterfiles" ); + files: + any:: + "$(sys.inputdir)" + copy_from => failsafe_scp("$(masterfiles_dir_remote)"), + depth_search => failsafe_recurse("inf"), + file_select => failsafe_exclude_vcs_files, + classes => failsafe_results("namespace", "inputdir_update"); + inputdir_update_error:: + "$(sys.inputdir)" + copy_from => failsafe_scp("$(sys.masterdir)"), + depth_search => failsafe_recurse("inf"), + file_select => failsafe_exclude_vcs_files, + classes => failsafe_results("namespace", "inputdir_update"), + comment => "If we failed to fetch policy we try again using the legacy default in case we are fetching policy + from a hub that is not serving masterfiles via a shortcut."; + processes: + any:: + "cf-serverd" restart_class => "cf_serverd_not_running"; + inputdir_update_repaired:: + "cf-execd" restart_class => "cf_execd_not_running"; + commands: + cf_execd_not_running.!systemd:: + "$(sys.cf_execd)" classes => failsafe_results("namespace", "cf_execd_running"); + cf_serverd_not_running.!(windows|systemd):: + "$(sys.cf_serverd)" classes => failsafe_results("namespace", "cf_serverd_running"); + cf_execd_not_running.systemd:: + "/bin/systemctl restart cfengine3" classes => failsafe_results("namespace", "systemctl_restart_cfengine3"); +} + +bundle agent failsafe_call_update +{ + vars: + any:: + "mode" string => ifelse("bootstrap_mode", "bootstrap_mode", "failsafe_mode"); + commands: + any:: + "$(sys.cf_agent) -f $(sys.update_policy_path) --define $(mode)" if => fileexists( $(sys.update_policy_path) ); +} + +bundle agent failsafe_report { + classes: + any:: + "have_promises_cf" expression => fileexists("$(sys.inputdir)/promises.cf"); + reports: + !bootstrap_mode:: + "Built-in failsafe policy triggered"; + bootstrap_mode:: + "Bootstrapping from host '$(sys.policy_hub)' via built-in policy '$(this.promise_filename)'"; + bootstrap_mode.policy_server:: + "This host assumes the role of policy server"; + bootstrap_mode.!policy_server:: + "This autonomous node assumes the role of voluntary client"; + inputdir_update_repaired:: + "Updated local policy from policy server"; + inputdir_update_repaired.!have_promises_cf:: + "Failed to copy policy from policy server at $(sys.policy_hub):$(sys.masterdir) +Please check + * cf-serverd is running on $(sys.policy_hub) + * CFEngine version on the policy hub is 3.6.0 or latest - otherwise you need to tweak the protocol_version setting + * network connectivity to $(sys.policy_hub) on port $(sys.policy_hub_port) + * masterfiles 'body server control' - in particular allowconnects, trustkeysfrom and skipverify + * masterfiles 'bundle server' -> access: -> masterfiles -> admit/deny +It is often useful to restart cf-serverd in verbose mode (cf-serverd -v) on $(sys.policy_hub) to diagnose connection issues. +When updating masterfiles, wait (usually 5 minutes) for files to propagate to inputs on $(sys.policy_hub) before retrying."; + systemctl_restart_cfengine3_repaired:: + "Restarted systemd unit cfengine3"; + systemctl_restart_cfengine3_error:: + "Error restarting systemd unit cfengine3"; + cf_serverd_running_repaired:: + "Started the server"; + cf_serverd_running_failed:: + "Failed to start the server"; + cf_execd_running_repaired:: + "Started the scheduler"; + cf_execd_running_failed:: + "Failed to start the scheduler"; +} + +############################################ +body copy_from failsafe_scp(from) +{ + any:: + source => "$(from)"; + compare => "digest"; + encrypt => "true"; + verify => "true"; + copy_backup => "false"; + purge => "true"; + # This class is always set when bootstrapping. You can deactivate + # this class with --trust-server=no when bootstrapping + trust_server:: + trustkey => "true"; + !policy_server:: + servers => { "$(sys.policy_hub)" }; + portnumber => "$(sys.policy_hub_port)"; +} +############################################ +body depth_search failsafe_recurse(d) +{ + depth => "$(d)"; + exclude_dirs => { "\.svn", "\.git" }; +} +############################################ +body file_select failsafe_exclude_vcs_files +{ + leaf_name => { "\.git.*", "\.mailmap" }; + file_result => "!leaf_name"; +} +############################################ +body classes failsafe_results(scope, class_prefix) +# @brief Define classes prefixed with `class_prefix` and suffixed with +# appropriate outcomes: _kept, _repaired, _not_kept, _error, _failed, +# _denied, _timeout, _reached +# +# @param scope The scope in which the class should be defined (`bundle` or `namespace`) +# @param class_prefix The prefix for the classes defined +{ + scope => "$(scope)"; + promise_kept => { "$(class_prefix)_reached", + "$(class_prefix)_kept" }; + promise_repaired => { "$(class_prefix)_reached", + "$(class_prefix)_repaired" }; + repair_failed => { "$(class_prefix)_reached", + "$(class_prefix)_error", + "$(class_prefix)_not_kept", + "$(class_prefix)_failed" }; + repair_denied => { "$(class_prefix)_reached", + "$(class_prefix)_error", + "$(class_prefix)_not_kept", + "$(class_prefix)_denied" }; + repair_timeout => { "$(class_prefix)_reached", + "$(class_prefix)_error", + "$(class_prefix)_not_kept", + "$(class_prefix)_timeout" }; +} -- cgit v1.2.3