# 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"; "Copy binaries" usebundle => failsafe_copy_binaries, comment => "Not all distributions populate /var/cfengine/bin"; "Fetch Inputs" usebundle => failsafe_update, comment => "We need to fetch policy from upstream if we are bootstrapping or if we are performing failsafe recovery."; "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_copy_binaries { vars: freebsd:: "binaries" slist => { "cf-agent", "cf-execd", "cf-key", "cf-monitord", "cf-promises", "cf-runagent", "cf-serverd", "cf-upgrade", }; files: freebsd:: "$(sys.bindir)/$(binaries)" copy_from => failsafe_cp("/usr/local/sbin/$(binaries)"), action => failsafe_u_immediate, classes => failsafe_results("namespace", "copy_binaries"); reports: copy_binaries_repaired:: "cf-engine binaries updated"; } 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" ); classes: systemd:: "cfengine3_service_running" expression => returnszero("/bin/systemctl status cfengine3", "noshell"); files: any:: "$(sys.inputdir)" copy_from => failsafe_scp("$(masterfiles_dir_remote)"), depth_search => failsafe_recurse("inf"), action => failsafe_u_immediate, 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."; !am_policy_hub:: "$(sys.workdir)/modules" copy_from => failsafe_scp("modules"), depth_search => failsafe_recurse("inf"), perms => failsafe_u_m("755"), action => failsafe_u_immediate, file_select => failsafe_exclude_vcs_files, classes => failsafe_results("namespace", "modulesdir_update"); processes: !(windows|systemd):: "cf-serverd" restart_class => "cf_serverd_not_running"; !systemd.inputdir_update_repaired:: "cf-execd" restart_class => "cf_execd_not_running"; commands: cf_execd_not_running:: "$(sys.cf_execd)" classes => failsafe_results("namespace", "cf_execd_running"); cf_serverd_not_running:: "$(sys.cf_serverd)" classes => failsafe_results("namespace", "cf_serverd_running"); systemd.(!cfengine3_service_running|inputdir_update_repaired):: "/bin/systemctl restart cfengine3" contain => failsafe_noshell_and_silent, classes => failsafe_results("namespace", "systemctl_restart_cfengine3"); } 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."; bootstrap_mode.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_cp(from) { any:: source => "$(from)"; compare => "digest"; encrypt => "true"; verify => "true"; copy_backup => "false"; purge => "true"; } ############################################ 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" }; } body contain failsafe_noshell_and_silent { useshell => "noshell"; no_output => true; } body perms failsafe_u_m(p) { mode => "$(p)"; } body action failsafe_u_immediate { ifelapsed => "0"; }