Feature Friday #9: body file control - inputs

Posted by Nick Anderson
May 10, 2024

Did you know you can include one policy file from another?

Traditionally you specify the files you want to make up a policy set using inputs in body common control found in your policy entry (promises.cf by default).

body common control
{
  # Paths are relative to $(sys.policy_entry_dirname) if not
  # fully qualified
  inputs => {
    "path/to/policy-1.cf",
    "path/to/policy-2.cf",
  };
}

body file control lets you specify additional inputs from any file that’s included in the policy and those files can include other files.

Let’s check out a contrived example.

First, we have our policy entry /tmp/feature-friday-9/promises.cf:

/tmp/feature-friday-9/promises.cf
body common control
{
  inputs => {
    "policy-1.cf",
  };
  bundlesequence => { "go" };
}
bundle agent go
{
  methods:
    # Methods promises run before reports promises (Normal Order), we
    # want the message about the bundle we are in to be emitted before
    # we go running a different bundle, so we depend on that report.

    "policy_1"
      depends_on => { "$(this.namespace):$(this.bundle)-report-bundle" };

  reports:
    "In $(this.namespace):$(this.bundle)"
      handle => "$(this.namespace):$(this.bundle)-report-bundle";
}

We see that policy-1.cf is included in the policy set, the go agent bundle gets run by default and it wants to run the policy_1 bundle (which is found in policy-1.cf).

Next we have /tmp/feature-friday-9/policy-1.cf:

/tmp/feature-friday-9/policy-1.cf
body file control
{
  # Remember that inputs is relative to sys.policy_entry_dirname
  # if it's not a fully qualified path.
  inputs => {
    "1/1.cf",
  };
}
bundle agent policy_1
{
  methods:
    # Methods promises run before reports promises (Normal Order), we
    # want the message about the bundle we are in to be emitted before
    # we go running a different bundle, so we depend on that report.
    "policy_1_1"
      depends_on => { "$(this.namespace):$(this.bundle)-report-bundle" };

  reports:
    "In $(this.namespace):$(this.bundle)"
      handle => "$(this.namespace):$(this.bundle)-report-bundle";
}

We see that 1/1.cf is part of inputs in body file control and we see the definition for the policy_1 agent bundle which emits a report and runs bundle policy_1_1. (which comes from 1/1.cf)

Remember, inputs if not a fully qualified path is relative to the policy entry, so 1/1.cf will be looked for in /tmp/feature-friday-9/1/1.cf.

/tmp/feature-friday-9/1/1.cf
body file control
{
  # Remember that inputs is relative to sys.policy_entry_dirname if
  # it's not a fully qualified path.
  inputs => {
    "1/1-1.cf",
  };
}
bundle agent policy_1_1
{
  methods:
    # Methods promises run before reports promises (Normal Order), we
    # want the message about the bundle we are in to be emitted before
    # we go running a different bundle, so we depend on that report.
    "policy_1_1_1"
      depends_on => { "$(this.namespace):$(this.bundle)-report-bundle" };

  reports:
    "In $(this.namespace):$(this.bundle)"
      handle => "$(this.namespace):$(this.bundle)-report-bundle";
}

And finally, /tmp/feature-friday-9/1/1-1.cf:

/tmp/feature-friday-9/1/1-1.cf
bundle agent policy_1_1_1
{
  reports:
    "In $(this.namespace):$(this.bundle)"
      handle => "$(this.namespace):$(this.bundle)-report-bundle";
}

Running our policy entry we can see from the output that all of the policy files were properly included:

command
cf-agent -Kf /tmp/feature-friday-9/promises.cf
output
R: In default:go
R: In default:policy_1
R: In default:policy_1_1
R: In default:policy_1_1_1

We can also see that if we specify a different entry e.g. /tmp/feature-friday-9/policy-1.cf and bundlesequence (policy_1), that things still work as expected given the partial policy set.

command
cf-agent -Kf /tmp/feature-friday-9/policy-1.cf --bundlesequence policy_1
output
R: In default:policy_1
R: In default:policy_1_1
R: In default:policy_1_1_1

Happy Friday! 🎉