Namespaces

Table of Contents

By default all promises are made in the default namespace. Specifying a namespace places the bundle or body in a different namespace to allow re-use of common names. Using namespaces makes it easier to share and consume policy from other authors.

Like bundle names and classes, namespaces may only contain alphanumeric and underscore characters (a-zA-Z0-9_).

Declaration

Namespaces are declared with body file control. A namespace applies within a single file to all subsequently defined bodies and bundles following the namespace declaration until a different namespace has been declared or until the end of the file.

bundle agent __main__
{
  methods:
      "Main in my_namespace namespace"
        usebundle => my_namespace:main;

      "Main in your_namespace namespace"
        usebundle => your_namespace:main;

      "my_bundle in default namespace"
        usebundle => my_bundle;

  reports:
      "Inside $(this.namespace):$(this.bundle)";
}

body file control
{
      namespace => "my_namespace";
}

bundle agent main
{
  reports:
      "Inside $(this.namespace):$(this.bundle)";
}

body file control
{
        namespace => "your_namespace";
}

bundle agent main
{
  reports:
      "Inside $(this.namespace):$(this.bundle)";
}

body file control
{
        namespace => "default";
}

bundle agent my_bundle
{
  reports:
      "Inside $(this.namespace):$(this.bundle)";
}
R: Inside my_namespace:main
R: Inside your_namespace:main
R: Inside default:my_bundle
R: Inside default:main

This policy can be found in /var/cfengine/share/doc/examples/namespace_declaration.cf and downloaded directly from github.

Notes:

  • Multiple namespaces can be declared within the same file
  • The same namespace can be declared in multiple files
  • The same namespace can be declared in the same file multiple times

Methods|usebundle

Methods promises assume you are referring to a bundle in the same namespace as the promiser. To refer to a bundle in another namespace you must specify the namespace by prefixing the bundle name with the namespace followed by a colon (:).

bundle agent __main__
{
  methods:
      # Call the bundle named main within the example_space namespace.
      "example_space:main";
}
body file control
{
        namespace => "example_space";
}

bundle agent main
{
  methods:
      # Call the bundle 'my_bundle' within the current namespace
      "When not specified, we assume you are refering to a bundle or body within the same namespace"
        usebundle => my_bundle( "Called 'my_bundle' from $(this.namespace):$(this.bundle) (the same namespace).");

      # Call the bundle 'my_bundle' from the 'example_space' namespace
      "When explicitly specified, the policy reader has less congnitive burden"
        usebundle => example_space:my_bundle( "Called 'example_space:my_bundle' $(this.namespace):$(this.bundle) (the same namespace).");
}

bundle agent my_bundle(string)
{
  reports:
      "In $(this.namespace):$(this.bundle)"
        handle => "$(string)";
      "$(string)";
}
R: In example_space:my_bundle
R: Called 'my_bundle' from example_space:main (the same namespace).
R: In example_space:my_bundle
R: Called 'example_space:my_bundle' example_space:main (the same namespace).

This policy can be found in /var/cfengine/share/doc/examples/namespace_methods-usebundle.cf and downloaded directly from github.

Bodies

Bodies are assumed to be within the same namespace as the promiser. To use a body from another namespace the namespace must be specified by prefixing the body name with the namespace followed by a colon (:).

A common mistake is forgetting to specify default: when using bodies from the standard library which resides in the default namespace.

bundle agent __main__
{
  methods:
      "example_space:main";
}
body file control
{
        namespace => "example_space";
}

bundle agent main
{

  reports:
      # Use the 'first_line' printfile body from the current namespace
      "Specifying a body without explict namespace assumes the same namespace.$(const.n)Show me the first 1 line of this file"
        printfile => first_line( $(this.promise_filename) );

      # Use the 'first_two_lines' printfile body from the 'default' namespace
      "Forgetting to prefix bodies with 'default:' is a common mistake when using the standard library.$(const.n)Show me the first 2 line of this file"
        printfile => default:first_two_lines( $(this.promise_filename) );

}

body printfile first_line(file)
{
        file_to_print => "$(file)";
        number_of_lines => "1";
}
body file control
{
        namespace => "default";
}
body printfile first_two_lines(file)
{
        file_to_print => "$(file)";
        number_of_lines => "2";
}
R: Specifying a body without explict namespace assumes the same namespace.
Show me the first 1 line of this file
R: bundle agent __main__
R: Forgetting to prefix bodies with 'default:' is a common mistake when using the standard library.
Show me the first 2 line of this file
R: bundle agent __main__
R: {

This policy can be found in /var/cfengine/share/doc/examples/namespace_bodies.cf and downloaded directly from github.

Variables

Variables (except for Special Variables) are assumed to be within the same scope as the promiser but can also be referenced fully qualified with the namespace.

bundle agent __main__
{
      methods: "example:demo";
}
body file control
{
        namespace => "example";
}
bundle agent demo
{
  vars:
      "color" string => "#f5821f";

  reports:
      "Unqualified: The color is $(color)";
      # ENT-8817 "Bundle-qualified: The color is $(demo.color)";
      "Fully-qualified: The color is $(example:demo.color)";
}
R: Unqualified: The color is #f5821f
R: Fully-qualified: The color is #f5821f

This policy can be found in /var/cfengine/share/doc/examples/namespace_variable_references.cf and downloaded directly from github.

Special variables are always accessible without a namespace prefix. For example, this, mon, sys, and const fall in this category.

bundle agent __main__
{
      methods: "special_variables_example:demo";
}
body file control
{
        namespace => "special_variables_example";
}
bundle agent demo
{
  reports:
      "Special Variables live in the default namespace but don't have to be fully qualified when referenced ...";
      "In $(this.namespace):$(this.bundle) $(const.dollar)(sys.cf_version_major) == $(sys.cf_version_major)";
      "In $(this.namespace):$(this.bundle) $(default:const.dollar)(default:sys.cf_version_major) == $(default:sys.cf_version_major)";
}
R: Special Variables live in the default namespace but don't have to be fully qualified when referenced ...
R: In special_variables_example:demo $(sys.cf_version_major) == 3
R: In special_variables_example:demo $(default:sys.cf_version_major) == 3

This policy can be found in /var/cfengine/share/doc/examples/namespace_special_var_exception.cf and downloaded directly from github.

Notes:

  • The variables Augments key defines variables in the main bundle of the data namespace by default but supports seeding variable values in any specified namespace.

Classes

Promises can only define classes within the current namespace. Classes are understood to refer to classes in the current namespace if a namespace is not specified (except for Hard Classes). To refer to a class in a different namespace prefix the class with the namespace suffixed by a colon (:).

bundle agent __main__
{
  methods:
      "mynamespace:my_bundle";

  reports:

    a_bundle_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I see 'a_bundle_scoped_class_in_my_namespaced_bundle::'";

    !a_bundle_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I do not see 'a_bundle_scoped_class_in_my_namespaced_bundle::'";

    a_namespace_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I see 'a_namespace_scoped_class_in_my_namespaced_bundle::'";

    !a_namespace_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I do not see 'a_namespace_scoped_class_in_my_namespaced_bundle::'";

    mynamespace:a_bundle_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I see 'mynamespace:a_bundle_scoped_class_in_my_namespaced_bundle::'";

    !mynamespace:a_bundle_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I do not see 'mynamespace:a_bundle_scoped_class_in_my_namespaced_bundle::'";

    mynamespace:a_namespace_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I see 'mynamespace:a_namespace_scoped_class_in_my_namespaced_bundle::'";
}

body file control
{
      namespace => "mynamespace";
}

bundle agent my_bundle
{
  classes:
      "a_bundle_scoped_class_in_my_namespaced_bundle";

      "a_namespace_scoped_class_in_my_namespaced_bundle"
        scope => "namespace";

  reports:

    a_bundle_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I see 'a_bundle_scoped_class_in_my_namespaced_bundle::'";

    !a_bundle_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I do not see 'a_bundle_scoped_class_in_my_namespaced_bundle::'";

    a_namespace_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I see 'a_namespace_scoped_class_in_my_namespaced_bundle::'";

    !a_namespace_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I do not see 'a_namespace_scoped_class_in_my_namespaced_bundle::'";

    mynamespace:a_bundle_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I see 'mynamespace:a_bundle_scoped_class_in_my_namespaced_bundle::'";

    !mynamespace:a_bundle_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I do not see 'mynamespace:a_bundle_scoped_class_in_my_namespaced_bundle::'";

    mynamespace:a_namespace_scoped_class_in_my_namespaced_bundle::
      "In $(this.namespace):$(this.bundle) I see 'mynamespace:a_namespace_scoped_class_in_my_namespaced_bundle::'";
}
R: In mynamespace:my_bundle I see 'a_bundle_scoped_class_in_my_namespaced_bundle::'
R: In mynamespace:my_bundle I see 'a_namespace_scoped_class_in_my_namespaced_bundle::'
R: In mynamespace:my_bundle I see 'mynamespace:a_bundle_scoped_class_in_my_namespaced_bundle::'
R: In mynamespace:my_bundle I see 'mynamespace:a_namespace_scoped_class_in_my_namespaced_bundle::'
R: In default:main I do not see 'a_bundle_scoped_class_in_my_namespaced_bundle::'
R: In default:main I do not see 'a_namespace_scoped_class_in_my_namespaced_bundle::'
R: In default:main I do not see 'mynamespace:a_bundle_scoped_class_in_my_namespaced_bundle::'
R: In default:main I see 'mynamespace:a_namespace_scoped_class_in_my_namespaced_bundle::'

This policy can be found in /var/cfengine/share/doc/examples/namespace_classes.cf and downloaded directly from github.

Hard classes exist in all namespaces and thus can be referred to from any namespace without qualification.

bundle agent __main__
{
  methods:
      "example:my_bundle";

  reports:
    cfengine::
      "From the '$(this.namespace)' namespace the class expression 'cfengine::' evaluates true";

    default:cfengine::
      "From the '$(this.namespace)' namespace the class expression 'default:cfengine::' evaluates true";

      "The class 'cfengine' has tags: $(with)"
        with => join( ", ", getclassmetatags( "cfengine" ) );
}

body file control
{
        namespace => "example";
}

bundle agent my_bundle
{
  reports:
    cfengine::
      "From the '$(this.namespace)' namespace the class expression 'cfengine::' evaluates true";

    default:cfengine::
      "From the '$(this.namespace)' namespace the class expression 'default:cfengine::' evaluates true";
}
R: From the 'example' namespace the class expression 'cfengine::' evaluates true
R: From the 'example' namespace the class expression 'default:cfengine::' evaluates true
R: From the 'default' namespace the class expression 'cfengine::' evaluates true
R: From the 'default' namespace the class expression 'default:cfengine::' evaluates true
R: The class 'cfengine' has tags: inventory, attribute_name=none, source=agent, hardclass

This policy can be found in /var/cfengine/share/doc/examples/namespace_hard_classes.cf and downloaded directly from github.