From e7fe6c1dcaa905bddcb27e23706e842df0da43a1 Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Tue, 13 Mar 2018 17:57:11 +0100 Subject: Moved to a more traditional update.cf mechanism without overwriting the builtin failsafe.cf --- controls/cf_execd.cf | 2 +- failsafe.cf | 255 --------------------------------------------------- promises.cf | 2 +- update.cf | 134 ++++++++++++++++++++++++++- 4 files changed, 133 insertions(+), 260 deletions(-) delete mode 100644 failsafe.cf diff --git a/controls/cf_execd.cf b/controls/cf_execd.cf index ddb9124..f75fe3c 100644 --- a/controls/cf_execd.cf +++ b/controls/cf_execd.cf @@ -2,7 +2,7 @@ body executor control { any:: splaytime => "4"; # activity will be spread over this many time slices - exec_command => "$(sys.cf_agent) -Dfrom_cfexecd,cf_execd_initiated -f \"$(sys.failsafe_policy_path)\" ; $(sys.cf_agent) -Dfrom_cfexecd,cf_execd_initiated"; + exec_command => "$(sys.cf_agent) -Dfrom_cfexecd,cf_execd_initiated -f \"$(sys.update_policy_path)\" ; $(sys.cf_agent) -Dfrom_cfexecd,cf_execd_initiated"; !cfengine_internal_disable_agent_email:: mailto => "root@adyxax.org"; mailfrom => "root@adyxax.org"; diff --git a/failsafe.cf b/failsafe.cf deleted file mode 100644 index a7cacc1..0000000 --- a/failsafe.cf +++ /dev/null @@ -1,255 +0,0 @@ -# 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 -{ - classes: - any:: - "alpinelinux" expression => fileexists("/etc/alpine-release"); - vars: - alpinelinux|freebsd:: - "binaries" slist => { - "cf-agent", - "cf-execd", - "cf-key", - "cf-monitord", - "cf-promises", - "cf-runagent", - "cf-serverd", - "cf-upgrade", - }; - files: - alpinelinux:: - "$(sys.bindir)/$(binaries)" - copy_from => failsafe_cp("/usr/sbin/$(binaries)"), - action => failsafe_u_immediate, - classes => failsafe_results("namespace", "copy_binaries"); - 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: - any:: - "alpinelinux" expression => fileexists("/etc/alpine-release"); - alpinelinux:: - "cf_execd_not_running" expression => returnszero("/usr/bin/pgrep cf-execd", "noshell"); - "cf_serverd_not_running" expression => returnszero("/usr/bin/pgrep cf-serverd", "noshell"); - 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: - !(alpinelinux|systemd|windows):: - "cf-serverd" restart_class => "cf_serverd_not_running"; - !(alpinelinux|systemd|windows).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"; -} diff --git a/promises.cf b/promises.cf index 5712848..3da719c 100644 --- a/promises.cf +++ b/promises.cf @@ -43,4 +43,4 @@ bundle common cfengine_stdlib reports: DEBUG|DEBUG_cfengine_stdlib:: "$(const.t): defining inputs='$(inputs)'"; -} +} \ No newline at end of file diff --git a/update.cf b/update.cf index 94cd97a..7f0d6ff 100644 --- a/update.cf +++ b/update.cf @@ -4,7 +4,135 @@ body common control bundlesequence => { main, }; - inputs => { - "failsafe.cf", - }; + inputs => {}; +} + +bundle agent main +{ + vars: + any:: + "input_name_patterns" slist => { + "authorized_keys", + "cf_promises_release_id", + ".*templates.*", + ".*\.cf", + ".*\.dat", + ".*\.txt", + ".*\.cfg", + ".*\.conf", + ".*\.json", + ".*\.mustache", + ".*\.pl", + ".*\.py", + ".*\.rb", + ".*\.sh", + ".*\.yaml", + }; + files: + !am_policy_hub:: + "$(sys.inputdir)/cf_promises_validated" + copy_from => secure_cp("$(sys.masterdir)/cf_promises_validated"), + action => immediate, + classes => if_repaired("validated_updates_ready"); + "$(sys.workdir)/modules" + copy_from => secure_cp("modules"), + depth_search => recurse("inf"), + perms => m("755"), + action => immediate, + file_select => exclude_vcs_files; + am_policy_hub:: + "$(sys.masterdir)/." + perms => m(700), + depth_search => recurse_basedir("inf"), + action => immediate; + am_policy_hub|validated_updates_ready:: + "$(sys.inputdir)" + copy_from => secure_cp("$(sys.masterdir)"), + depth_search => recurse("inf"), + file_select => input_files, + action => immediate, + classes => results("bundle", "update_inputs"); + update_inputs_not_kept:: + "$(sys.inputdir)/cf_promises_validated" + delete => tidy; +} + +body file_select exclude_vcs_files +{ + leaf_name => { "\.git.*" }; + file_result => "!leaf_name"; +} + +body file_select input_files +{ + leaf_name => { @(main.input_name_patterns) }; + file_result => "leaf_name"; +} + +body perms m(mode) +{ + mode => "$(mode)"; +} + +body copy_from secure_cp(from) +{ + any:: + source => "$(from)"; + compare => "digest"; + encrypt => "true"; + verify => "true"; + !am_policy_hub:: + servers => { "$(sys.policy_hub)" }; + portnumber => "$(sys.policy_hub_port)"; } + +body action immediate +{ + ifelapsed => "0"; +} + +body classes if_repaired(x) +{ + promise_repaired => { "$(x)" }; +} + +body depth_search recurse(d) +{ + depth => "$(d)"; + xdev => "true"; +} + +body depth_search recurse_basedir(d) +{ + include_basedir => "true"; + depth => "$(d)"; + exclude_dirs => { "\.svn", "\.git", "git-core" }; +} + +body delete tidy +{ + dirlinks => "delete"; + rmdirs => "true"; +} + +body classes results(scope, class_prefix) +{ + 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" }; +} \ No newline at end of file -- cgit v1.2.3