############################################################
#
#  Chinese Dragon Dancing on a Star
#
#  This method works with either Community or Enterprise.
#  and uses named signals
#
#  If you want to test this on localhost, just edit /etc/hosts
#  to add host1 host2 host3 host4 as aliases to localhost
#
# Start a switch file /tmp/switch_file with
#   host1 ON
#   host2 ON
#   host3 ON etc


############################################################

body common control
{
bundlesequence => { "dragon_symphony" };
inputs => { "cfengine_stdlib.cf" };
}

############################################################

bundle agent dragon_symphony
{
methods:

   # We have to seed the beginning by creating the dragon
   # /tmp/dragon_localhost

    "dragon"  usebundle => upgrade_host("localhost","host1","chapter1");

    "dragon"  usebundle => upgrade_host("host1","host2","chapter2");

    "dragon"  usebundle => upgrade_host("host2","host3","chapter3");

    "dragon"  usebundle => upgrade_host("host3","host4","chapter4"),
                classes => if_ok("finale");

  finale::

    "dragon"  usebundle => restore_final("host4"),
                comment => "Restore all the deactivated satellites";


reports:

  finale::

    "The dragon is slain!!!"
       printfile => visitors_book("/tmp/shoo_dragon_host4");

    "And the switch state is..."
       printfile => visitors_book("/tmp/switch_file");
}

############################################################
# Define the 
############################################################

bundle agent chapter1(x)
{
# Do something significant here

reports:

 host1::
    " ----> Breathing fire on $(x)";
}

################################

bundle agent chapter2(x)
{
# Do something significant here

reports:

 host2::
    " ----> Breathing fire on $(x)";

}

################################

bundle agent chapter3(x)
{
# Do something significant here

reports:

 host3::
    " ----> Breathing fire on $(x)";

}

################################

bundle agent chapter4(x)
{
# Do something significant here

reports:

 host4::
    " ----> Breathing fire on $(x)";

}

############################################################
# Orchestration wrappers
############################################################

bundle agent upgrade_host(predecessor,satellite,method)
{

 # This is a wrapper for the orchestration will be acted on
 # first by the dragon's lair and then by the satellite

vars:

  "dragons_lair" string => "host0";

files:

  # We start in the dragon's lair ..

  "/tmp/unleash_dragon"

        comment => "Unleash the dragon",
      rename => to("/tmp/enter_the_dragon"),
        classes => if_repaired("dispatch_dragon_$(satellite)"),
     ifvarclass => "$(dragons_lair)";

  # if we are the dragon's lair, welcome the dragon back, shooed from the satellite

  "/tmp/enter_the_dragon"

        comment => "Returning from a visit to a satellite",
      copy_from => secure_cp("/tmp/shoo_dragon_$(predecessor)","$(predecessor)"),
        classes => if_repaired("dispatch_dragon_$(satellite)"),
     ifvarclass => "$(dragons_lair)";

  # If we are a satellite, receive the dragon from its lair

  "/tmp/enter_the_dragon"
        comment => "Wait for our cue or relay/conductor baton",
      copy_from => secure_cp("/tmp/dragon_$(satellite)","$(dragons_lair)"),
        classes => if_repaired("cue_action_on_$(satellite)"),
     ifvarclass => "$(satellite)";

methods:

   "check in at home"
        comment => "Edit the load balancer?",
      usebundle => next_host("$(satellite)","$(predecessor)"),
        classes => if_repaired("send_the_dragon_to_$(satellite)"),
     ifvarclass => "dispatch_dragon_$(satellite)";

   "dragon visits"
        comment => "One off activity that the nodes carry out while the dragon visits",
      usebundle => $(method)("$(satellite)"),
        classes => if_repaired("send_the_dragon_back_from_$(satellite)"),
     ifvarclass => "cue_action_on_$(satellite)";


files:

  # hub/lair hub signs the book too and schedules the dragon for next satellite

   "/tmp/dragon_$(satellite)"   
         create => "true",
        comment => "Add our signature to the dragon's tail",
      edit_line => sign_visitor_book("Dragon returned from $(predecessor)"),
     ifvarclass => "send_the_dragon_to_$(satellite)";

   # Satellite signs the book and shoos dragon for hub to collect

   "/tmp/shoo_dragon_$(satellite)"
         create => "true",
        comment => "Add our signature to the dragon's tail",
      edit_line => sign_visitor_book("Dragon visited $(satellite) and did: $(method)"),
     ifvarclass => "send_the_dragon_back_from_$(satellite)";

reports:

      "Done $(satellite)",
     ifvarclass => "$(satellite)";
}

############################################################

bundle agent next_host(name,pred)
{
files:

   "/tmp/enter_the_dragon"
        comment => "Add our signature to the dragon's tail",
      edit_line => append_if_no_line("Switch new dragon's target $(name)");

   # Edit the switch file

   "/tmp/switch_file"
      comment => "Restore whatever is missing and comment out",
    edit_line => restore_and_comment("$(name)","$(pred)"),
      classes => if_repaired("reload_switch_$(name)");

reports:

  !problem::

   "Returned from $(pred), heading out to $(name)";

   " X Restoring $(pred) and switching new dragon's target $(name)"
        ifvarclass => "reload_switch_$(name)";
}

############################################################

bundle agent restore_final(name)
{
files:

  host0::

   "/tmp/switch_file"
      comment => "Restore whatever is missing and comment out",
    edit_line => restore_and_comment("NONE","$(name)"),
      classes => if_repaired("reload_switch");

reports:

  reload_switch::
   " X Restoring $(name) to tidy up loose ends";

}

############################################################

bundle edit_line sign_visitor_book(s)
{
insert_lines:

  "/tmp/enter_the_dragon"
        comment => "Import the current visitor's book",
    insert_type => "file";

  "$(s)" comment => "Append this string to the visitor's book";
}

#

bundle edit_line restore_and_comment(name,pred)
{
replace_patterns:
	 
 "$(name) ON" 

       replace_with => value("$(name) OFF"),
            comment => "Uncomment the predecessor to reactivate";

 "$(pred) OFF" 

     replace_with => value("$(pred) ON"),
          comment => "Comment out the new host",
          classes => if_repaired("show_switch_$(name)");

reports:

 !problem::

  "The state of the switch was:",
     printfile => visitors_book("/tmp/switch_file"),
    ifvarclass => "show_switch_$(name)";


}

############################################################


bundle server access_rules()
{
access:

  "/tmp"

        admit => { "127.0.0.1" };

  "did.*"
    resource_type => "context",
    admit => { "127.0.0.1" };

}

############################################################

body printfile visitors_book(file)
{
file_to_print   => "$(file)";
number_of_lines => "100";
}


