############################################################
#
#  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 => { "$(sys.libdir)/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)"),
      if => "$(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)"),
      if => "$(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)"),
      if => "$(satellite)";

  methods:
    "check in at home"
      comment => "Edit the load balancer?",
      usebundle => next_host("$(satellite)", "$(predecessor)"),
      classes => if_repaired("send_the_dragon_to_$(satellite)"),
      if => "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)"),
      if => "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)"),
      if => "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)"
      ),
      if => "send_the_dragon_back_from_$(satellite)";

  reports:
    "Done $(satellite)" if => "$(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)"
        if => "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"),
        if => "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";
}
