summaryrefslogtreecommitdiff
path: root/failsafe.cf
diff options
context:
space:
mode:
authorJulien Dessaux2017-03-05 14:43:06 +0000
committerJulien Dessaux2017-03-05 14:43:06 +0000
commit0b3908ea518f371237642dec2790be6b1c25db95 (patch)
treee4f3ae69b69009cfec8f727c604694f0b33adab5 /failsafe.cf
downloadmasterfiles-0b3908ea518f371237642dec2790be6b1c25db95.tar.gz
masterfiles-0b3908ea518f371237642dec2790be6b1c25db95.tar.bz2
masterfiles-0b3908ea518f371237642dec2790be6b1c25db95.zip
Initial import
Diffstat (limited to 'failsafe.cf')
-rw-r--r--failsafe.cf185
1 files changed, 185 insertions, 0 deletions
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" };
+}