1###############################################################################
2#
3#   failsafe.cf - Basic Failsafe Policy for Community
4#
5###############################################################################
6
7body common control
8{
9 bundlesequence => { "git_update" };
10 version => "git-failsafe.cf 1.0.0";
11}
12
13#############################################################################
14
15body agent control
16{
17 ifelapsed => "1";
18 skipidentify => "true";
19}
20
21#############################################################################
22
23bundle agent git_update
24{
25 vars:
26
27   "inputs_dir"         string => translatepath("$(sys.workdir)/inputs"),
28                       comment => "Directory containing Cfengine policies",
29                        handle => "update_vars_inputs_dir";
30
31   "ppkeys_file"        string => translatepath("$(sys.workdir)/ppkeys/localhost.pub"),
32                       comment => "Path to public key file",
33                        handle => "update_vars_ppkeys_file";
34
35   "file_check"         string => translatepath("$(inputs_dir)/promises.cf"),
36                       comment => "Path to a policy file",
37                        handle => "update_vars_file_check";
38
39   "master_location"    string => "/var/cfengine/masterfiles",
40                       comment => "The master cfengine policy directory on the policy host",
41                        handle => "update_vars_master_location";
42
43      "git_origin" string => "http://myserver.com/myrepo.git",
44      comment => "The URL to the Git repository.",
45      handle => "update_vars_git_origin";
46
47      "git_checkout_location" string => "$(master_location)/myrepo",
48      comment => "The desired checkout location of the Git repository",
49      handle => "update_vars_git_checkout_location";
50
51      "git_checkout_umask" string => "077",
52      comment => "The desired umask while checking out the Git repository",
53      handle => "update_vars_git_checkout_umask";
54
55      "git_configfile" string => "$(git_checkout_location)/.git/config",
56      comment => "The .git/config file location",
57      handle => "update_vars_git_configfile";
58
59      "git_branch" string => "master",
60      comment => "The desired branch of the Git repository",
61      handle => "update_vars_git_branch";
62
63      "git_binary" string => "/usr/bin/git",
64      comment => "The location of the Git executable.  Leave blank if you don't want to use Git.",
65      handle => "update_vars_git_binary";
66
67      # 1. Remove untracked files, 2. Discard changes to index and working tree since HEAD
68      # 3. Check out the proper branch; 4. Pull the latest changes from origin;
69      # 5. Reset the working tree to the latest updates
70      "git_update_command" string => "$(git_binary) clean -f -f -x -q -d .; $(git_binary) reset -q --hard HEAD; $(git_binary) checkout -q $(git_branch); $(git_binary) pull -q -s recursive -Xtheirs origin $(git_branch); $(git_binary) reset -q --hard HEAD",
71      comment => "The commands to do a Git update.  They should DTRT for your environment (checkout/reset/clean/etc).",
72      handle => "update_vars_git_update_command";
73
74      "git_clone_command" string => "$(git_binary) clone -b $(git_branch) $(git_origin) $(git_checkout_location)",
75      comment => "The commands to do a Git update.  They should DTRT for your environment (checkout/reset/clean/etc).",
76      handle => "update_vars_git_clone_command";
77
78      "git_config_template" string => "
79[core]
80        repositoryformatversion = 0
81        filemode = true
82        bare = false
83        logallrefupdates = true
84[remote \"origin\"]
85        fetch = +refs/heads/*:refs/remotes/origin/*
86        url = $(git_origin)
87[branch \"master\"]
88        remote = origin
89        merge = refs/heads/master
90[branch \"$(git_branch)\"]
91        remote = origin
92        merge = refs/heads/$(git_branch)
93",
94      comment => "The $(git_configfile) template.",
95      handle => "update_vars_git_config_template";
96
97#
98
99 classes:
100
101      # Set this to "any" or a machine class to have those machines do
102      # the Git checkouts locally, effectively replacing the policy
103      # hub model for a "just checkout from Git everywhere" model.
104
105      # This is not recommended unless you are testing in isolation or
106      # have other very specific requirements.
107      "idempotent_git" expression => "!any";
108
109      "use_git" expression => fileexists("$(git_binary)"),
110      comment => "True if we found the Git binary and should use Git.",
111      handle => "update_classes_use_git";
112
113      "git_checkout_location_exists" expression => fileexists("$(git_checkout_location)"),
114      comment => "True if the Git checkout location exists.",
115      handle => "update_classes_git_checkout_location_exists";
116
117      "git_checkout_exists" expression => fileexists("$(git_checkout_location)/.git"),
118      comment => "True if the Git checkout has already happened.",
119      handle => "update_classes_git_checkout_exists";
120
121
122   "have_ppkeys"   expression => fileexists("$(ppkeys_file)"),
123                      comment => "Check for /var/cfengine/ppkeys/localhost.pub",
124                       handle => "update_classes_have_ppkeys";
125
126   "files_ok"      expression => fileexists("$(file_check)"),
127                      comment => "Check for /var/cfengine/masterfiles/promises.cf",
128                       handle => "update_classes_files_ok";
129
130#
131
132 processes:
133
134  files_ok::
135
136   "cf-serverd"  restart_class => "start_server",
137                       comment => "Monitor cf-serverd process",
138                        handle => "update_processes_cf_serverd";
139
140   "cf-monitord" restart_class => "start_monitor",
141                       comment => "Monitor cf-monitord process",
142                        handle => "update_processes_cf_monitord";
143
144  files_ok.!windows::
145
146   "cf-execd"    restart_class => "start_exec",
147                       comment => "Monitor cf-execd process",
148                        handle => "update_processes_cf_execd";
149
150#
151
152 commands:
153
154  start_server::
155
156   "$(sys.cf_serverd)"
157      comment => "Start cf-serverd process",
158       handle => "update_commands_start_cf_serverd";
159
160  start_monitor::
161
162   "$(sys.cf_monitord)"
163      comment => "Start cf-monitord process",
164       handle => "update_commands_start_cf_monitord";
165
166  !windows.start_exec::
167
168   "$(sys.cf_execd)"
169      comment => "Start cf-execd process",
170       handle => "update_commands_start_cf_execd_not_windows";
171
172  !have_ppkeys::
173
174   "$(sys.cf_key)",
175      comment => "Generate cfengine encryption keys if necessary",
176       handle => "update_commands_generate_keys";
177
178    (idempotent_git||am_policy_hub).use_git.git_config_ok::
179      "$(git_update_command)"
180      contain => u_in_dir_umask_shell("$(git_checkout_location)", "$(git_checkout_umask)"),
181      comment => "Update the Git repository.",
182      handle => "update_commands_git_update",
183      classes => u_if_repaired("git_resolve_updated");
184
185    (idempotent_git||am_policy_hub).use_git.!git_checkout_location_exists.!git_checkout_exists::
186      "$(git_clone_command)"
187      contain => u_in_dir_umask_shell("/", "$(git_checkout_umask)"),
188      comment => "Clone the Git repository.",
189      handle => "update_commands_git_clone",
190      classes => u_if_repaired("git_resolve_cloned");
191
192#
193
194 files:
195
196  !(idempotent_git||am_policy_hub)::  # policy hub should not alter inputs/ uneccessary
197
198   "$(inputs_dir)/cf_promises_validated"
199        comment => "Check whether a validation stamp is available for a new policy update to reduce the distributed load",
200         handle => "check_valid_update",
201      copy_from => u_rcp("$(master_location)/cf_promises_validated","$(sys.policy_hub)"),
202         action => u_immediate,
203        classes => u_if_repaired("validated_updates_ready");
204
205      # on the policy hub, converge the .git/config file iff the checkout has been made already
206    (idempotent_git||am_policy_hub).use_git.git_checkout_location_exists.git_checkout_exists::
207      "$(git_configfile)"
208      handle => "converge_git_configfile",
209      classes => u_if_ok("git_config_ok"),
210      perms => u_m("600"),
211      edit_defaults => u_empty,
212      edit_line => u_insert_lines("$(git_config_template)");
213
214  # on the policy hub, do the following if a) we don't use Git
215  # or b) the Git update succeeded
216  !idempotent_git.(am_policy_hub.((git_resolve_cloned||git_resolve_updated)|!use_git))|validated_updates_ready::  # policy hub should always put masterfiles in inputs in order to check new policy
217
218   "$(inputs_dir)"
219           comment => "Copy policy updates from master source on policy server if a new validation was acquired",
220            handle => "update_files_inputs_dir",
221         copy_from => u_rcp("$(master_location)","$(sys.policy_hub)"),
222      depth_search => u_recurse("inf"),
223      file_select  => u_input_files,
224        depends_on => { "check_valid_update" },
225            action => u_immediate,
226           classes => u_if_repaired("update_report");
227
228  !windows::
229
230   "$(sys.workdir)/bin"
231           comment => "Make sure cfengine binaries have right file permissions",
232            handle => "update_files_sys_workdir_bin",
233             perms => u_m("755"),
234      depth_search => u_recurse_basedir("inf"),
235            action => u_immediate;
236
237   "$(sys.workdir)/lib"
238           comment => "Make sure cfengine libraries have right file permissions",
239            handle => "update_files_sys_workdir_lib",
240             perms => u_m("644"),
241      depth_search => u_recurse_basedir("inf"),
242            action => u_immediate;
243
244   "$(sys.workdir)/lib"
245           comment => "Make sure cfengine libraries have right file permissions for only HP-UX",
246            handle => "update_files_sys_workdir_lib_hpux",
247             perms => u_m("755"),
248      depth_search => u_recurse_basedir("inf"),
249            action => u_immediate,
250        ifvarclass => "hpux";
251
252   "/usr/local/bin"
253           comment => "Ensure cfengine binaries were copied to /usr/local/bin",
254            handle => "update_files_usr_local_bin",
255             perms => u_m("755"),
256         copy_from => u_cp_nobck("$(sys.workdir)/bin"),
257       file_select => u_cf3_files,
258      depth_search => u_recurse("1"),
259            action => u_immediate;
260
261  am_policy_hub::
262
263   "$(master_location)/."
264           comment => "Make sure masterfiles folder has right file permissions",
265            handle => "update_files_sys_workdir_masterfiles",
266             perms => u_m("644"),
267      depth_search => u_recurse_basedir("inf"),
268            action => u_immediate;
269
270  reports:
271    git_checkout_location_exists.!git_checkout_exists::
272      "$(git_checkout_location) already exists but it's not a Git checkout location.  Aborting.";
273    git_resolve_updated::
274      "Updated $(git_origin) (branch $(git_branch), umask $(git_checkout_umask)) into $(git_checkout_location)";
275    git_resolve_cloned::
276      "Cloned $(git_origin) (branch $(git_branch), umask $(git_checkout_umask)) into $(git_checkout_location)";
277}
278
279#########################################################
280# Self-contained bodies from the lib to avoid dependencies
281#########################################################
282
283body perms u_m(p)
284{
285 mode  => "$(p)";
286}
287
288#########################################################
289
290body file_select u_cf3_files
291{
292 leaf_name => { "cf-.*" };
293 file_result => "leaf_name";
294}
295
296#########################################################
297
298body file_select u_input_files
299{
300 leaf_name => { ".*.cf",".*.dat",".*.txt" };
301 file_result => "leaf_name";
302}
303
304#########################################################
305
306body copy_from u_rcp(from,server)
307{
308 source      => "$(from)";
309 compare     => "digest";
310 trustkey    => "false";
311
312!am_policy_hub::
313
314 servers => { "$(server)" };
315}
316
317#########################################################
318
319body copy_from u_cp_nobck(from)
320{
321 source      => "$(from)";
322 compare     => "digest";
323 copy_backup => "false";
324}
325
326#########################################################
327
328body action u_immediate
329{
330 ifelapsed => "0";
331}
332
333#########################################################
334
335body depth_search u_recurse(d)
336{
337 depth => "$(d)";
338 exclude_dirs => { "\.svn", "\.git", "\.hg", "\.bzr" };
339}
340
341#########################################################
342
343body depth_search u_recurse_basedir(d)
344{
345 include_basedir => "true";
346 depth => "$(d)";
347 exclude_dirs => { "\.svn", "\.git", "\.hg", "\.bzr" };
348}
349
350#########################################################
351
352body classes u_if_repaired(x)
353{
354 promise_repaired => { "$(x)" };
355}
356
357body classes u_if_ok(x)
358{
359      promise_repaired => { "$(x)" };
360      promise_kept => { "$(x)" };
361}
362
363#########################################################
364
365body contain u_in_dir_umask_shell(dir, umask)
366{
367      chdir => "$(dir)";
368      useshell => "true";
369      umask => "$(umask)";
370}
371
372#########################################################
373
374bundle edit_line u_insert_lines(lines)
375{
376  insert_lines:
377
378      "$(lines)"
379      comment => "Append lines if they don't exist";
380}
381
382#########################################################
383
384body edit_defaults u_empty
385{
386      empty_file_before_editing => "true";
387      edit_backup => "false";
388}
389
390#########################################################
391