Namespaces
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 themain
bundle of thedata
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.