6. Configuration¶
Revision: |
0.8 |
Status: |
Final Draft |
Repository: |
|
Project: |
ELT CII |
Document ID: |
|
File: |
config-ng.rst |
Owner: |
Marcus Schilling |
Last modification: |
March 17, 2022 |
Revision |
Date |
Changed/ Reviewed |
Section(s) |
Modification |
---|---|---|---|---|
0.8 |
15.03.2022 |
Jure Repinc Marcus Schilling |
All |
Document created / reviewed |
Confidentiality
This document is classified as a confidential document. As such, it or parts thereof must not be made accessible to anyone not listed in the Audience section, neither in electronic nor in any other form.
Scope
This document is manual for the configuration system used by applications in the ELT Core Integration Infrastructure Software.
Audience
This document is aimed at those Cosylab and ESO employees involved with the ELT Core Integration Infrastructure Software project, as well as other Users and Maintainers of the ELT Core Integration Infrastructure Software.
Glossary of Terms
API |
Application Programming Interface |
CII |
Core Integration Infrastructure |
MDI |
Metadata instance |
YAML |
YAML Ain’t Markup Language |
6.1. Overview¶
This is the user manual for the CII Configuration API (Config-ng API). All examples in this manual are also present in the cii-demo repository.
The Config-ng API is provided for C++ and Python. It provides support for parsing YAML documents (with support for additional information or directives via tags) into configuration documents. A Configuration document contains set of named instances with optional data type and metadata information.
A Configuration document allows access to its instances and supports additional operations like saving, merging with another configuration document and updating with programmatically prepared instance map.
6.2. Includes and imports¶
6.2.1. C++¶
To use the config-ng API from C++, the following directives are needed:
wscript (project)
cnf.check_wdep(wdep_name='config-ng.cpp.config-ng', uselib_store='config-ng')
# Transitive Dependencies:
cnf.check_cfg(package='log4cplus', uselib_store='log4cplus', args='--cflags --libs')
wscript (module)
use=[...,
'config-ng'
# Transitive Dependencies:
'log4cplus'
source
#include <config-ng/ciiConfigApi.hpp>
6.2.2. Python¶
To use the config-ng API from Python, the following directives are needed:
wscript (project)
cnf.check_wdep(wdep_name='config-ng.python.config-ng', uselib_store='config-ng')
wscript (module)
use=[..., 'config-ng' ]
source
import elt.configng
6.3. API Components¶
API provides the following basic components:
Client
Document
Node
Data type
Metadata
Client is the entry point to the API. It provides basic operations like loading document from provided filename/URI, retrieval or modification of config-ng search path.
Document represents a configuration object that was either loaded from file/stream or created in memory. Operations like loading produce a new document instance. Document itself offers additional operations (like merging, check, update and save).
Node represents an item (also known as instance) within a configuration object. Generally, it can have a name and can represent a scalar (single value), a list of items or a map (dictionary) of items. Access to nodes is available through the document instance interface desribed later.
Data type describes a data type assigned to the configuration instance (Node) if any. Data type of instance is optional. There is a set of built-in data types. Defining custom data types is supported by using a predefined yaml syntax. A data type definition can contain its own metadata attributes. Some predefined attributes are understood by the config-ng (when running the Check() operation on a document):
- default
Provides default value of the configuration item when its value is not explicitly provided.
- min
Allowed minimum value of the scalar configuration item.
- max
Allowed maximum value of the scalar configuration item.
- allowed_values
Provides list of allowed scalar values for scalar configuration item.
Metadata is associated with Node and can be seen as a map of attributes assigned to item. These attributes have a name and can be scalars, lists, or maps. There is no data type assigned to the attributes of the item. Some attributes are automatically generated by the config-ng at the time of the parsing of the initial yaml document. There are length for lists and rows and columns for matrices.
6.4. Creation of Documents¶
Documents can be created by parsing YAML source either from input/output stream or provided URI. Additionally documents can also be constructed programatically.
6.4.1. Parsing YAML source from input/output stream¶
Note that parsing document from YAML can cause exceptions either within config-ng or within the underlying YAML parser, therefore proper exception handling is needed (refer to config-ng examples).
6.4.1.1. C++¶
In C++, YAML source can be provided through a std::istream object as demonstrated below:
#include <iostream>
#include <sstream>
#include <config-ng/ciiConfigApi.hpp>
int main() {
const char *document_source = R"DOC(
a: 10
b: this is a string
)DOC";
std::stringstream document_source_stream;
document_source_stream << document_source;
::elt::configng::CiiConfigDocument document = ::elt::configng::CiiConfigClient::Load(document_source_stream);
std::cout << document.Instances()["a"].As<std::int>() << ", "
<< document.Instances()["b"].As<std::string>()
<< std::endl;
return 0;
}
6.4.1.2. Python¶
Loading from Python’s standard io objects is supported:
import io
import elt.configng
document_source = """
a: 10
b: this is a string
"""
document = elt.configng.CiiConfigClient.load_from_stream(io.StringIO(document_source))
print(document.instances.a.as_value())
print(document.instances.b.as_value())
6.4.2. Loading YAML source from file/URI¶
Documents can be loaded from a local file by specifying a URI or a filename. The supported URI syntax is cii.config://<authority>/<path> where:
- <authority>
can be either local, remote or *. Only local authority is currently supported.
- <path>
is path to the file. Note that path is always interpreted as relative regarding to the search path currently set in the client. Absolute paths are not supported.
In case a plain filename is provided, it is turned into a local URI:
my/path/filename.yaml -> cii.config://local/my/path/filename.yaml
6.4.2.1. Search Path¶
Client maintains a search path for files. The search path consists of a list of directories to be searched for a specific file. Directories are searched in the order they appear in the list. First match of the filename wins. From a user point of view, the search path is a string containing zero or more directories delimited by : (i.e. "/path/to/dir1:/path/to/dir2:path/to/dir3"
.
The search path can be set to the empty string. In this case, search for files is limited to only relative to current working directory of the process.
Client initializes the search path from CFGPATH environment variable, if defined. To obtain the current search path, it provides method GetSearchPath()
in C++ and get_search_path()
in Python. When the search path was initialized from CFGPATH, the current working directory is prepended to the search path defined in CFGPATH.
To modify the search path SetSearchPath(new_path)
is provided in C++ and set_search_path(new_path)
in Python.
The following examples demonstrate manipulation of the search path.
C++ example
// save current search path
std::string saved_search_path = ::elt::configng::CiiConfigClient::GetSearchPath();
std::string my_search_path = "/usr/local/conf:/local/conf";
// establish own search path
::elt::configng::CiiConfigClient::SetSearchPath(my_search_path);
// do something
...
// restore search path
::elt::configng::CiiConfigClient::SetSearchPath(saved_search_path);
Python example
# save current search path
saved_search_path = elt.configng.CiiConfigClient.get_search_path()
# establish own search path
my_search_path = '/usr/local/conf:/local/conf'
elt.configng.CiiConfigClient.set_search_path(my_search_path)
# do something
...
# restore search path
elt.configng.CiiConfigClient.set_search_path(saved_search_path)
6.4.3. Actual document loading¶
C++ Document is loaded by calling method ::elt::configng::CiiConfigClient::Load()
as demonstrated below. Note that parsing YAML and loading document can produce exceptions therefore exception handling is needed (refer to examples for more information):
// Load path/file.yaml using current search path
::elt::configng::CiiConfigDocument document = ::elt::configng::CiiConfigClient::Load("cii.config://local/path/file.yaml")
In the same manner as C++, Python version provides method elt.configng.CiiConfigClient.load()
:
# Load path/file.yaml usign current search path
::elt::configng::CiiConfigDocument document = elt.configng.CiiConfigClient.load('cii.config://local/path/file.yaml')
6.4.4. Building document programmatically¶
To construct a document programatically, a special helper class CiiConfigMapBuilder must be used to construct the ‘map’ of the instances to be added to document. CiiConfigMapBuilder provides a simple interface to add elements to the map. The general workflow is like this:
Create empty document instance
Use map builder to prepare an instance map of instances to be added to the document
Update document with prepared map. With C++, use method
`SetInstancesFromMap()
on the document instance. With Python, use methodset_instances_from_map()
on the document instance.
Note that on the API level there are slight differences between Python and C++ API (due of language differences), but the general workflow is the same.
C++ Example
// See programmatic example for more comprehensive information
#include <vector>
#include <string>
#include <iostream>
#include <config-ng/ciiConfigApi.hpp>
// NOTE: additional includes needed
#include <config-ng/ciiConfigMapBuilder.hpp>
#include <config-ng/ciiConfigValueConverter.hpp>
int main() {
// prepare empty document
::elt::configng::CiiConfigDocument document = ::elt::configng::CiiConfigDocument();
// Create CiiConfigMapBuilder
::elt::configng::CiiConfigMapBuilder builder;
// Builder provides operators to simplify construction of node hirearchy
// Note that values cannot directly be assigned to the builder items,
// factory method ::elt::config::CiiConfigInstanceNode::From() must be used
// to turn C++ value into correct node to be later assigned to document
// Create untyped instance a and assign value 3 to it
builder["a"] = ::elt::configng::CiiConfigInstanceNode::From(3);
// Create untyped instance b and assign list 1,2,3 to it
builder["b"] = ::elt::configng::CiiConfigInstanceNode::From(std::vector<int>{1,2,3});
// Create type instance c, using builtin type vector_int32
builder["c"] = ::elt::configng::CiiConfigInstanceNode::From(std::vector<int>{1,2,3},
"!cfg.type:vector_int32");
// Create map with untyped items a and b
builder["map"]["a"] = ::elt::configng::CiiConfigInstanceNode::From(3);
builder["map"]["b"] = ::elt::configng::CiiConfigInstanceNode::From("a string");
// Once map is constructed, document can be updated
document.SetInstancesFromMap(builder);
// Display instance a
std::cout << document.Instances()["a"].as<int>();
return 0;
}
Python Example
# See programmatic example for more comprehensive information
import elt.configng
# Prepare empty document
document = elt.configng.CiiConfigDocument()
# Create CiiConfigMapBuilder
builder = elt.configng.CiiConfigMapBuilder()
# Create untyped instance a and assign value 3 to it
builder['a'] = 3
# Create untyped instance b and assign list [1,2,3] to it
builder['b'] = [1,2,3]
# Create typed instance c and assign list [1,2,3] to it.
# Whenever typed instance is required, use of elt.confing.CiiConfigNodeFacory.make_from
# method must be used, as it takes additinal parameters optional tag denoting data type
# to be used when creating instance and optional converter method for custom
# value conversion when required
builder['c'] = elt.configng.CiiConfigNodeFactory.make_from([1,2,3], '!cfg.type:vector_int32')
# Crreate map with untyped items a and b
builder['map']['a'] = 3
builder['map']['b'] = 'a string'
# Once map is constructed, document can be updated
document.set_instances_from_map(builder)
# Display instance a
print(document.instances.a.as_value())
6.5. Access to YAML source tree of a document¶
Once a document is loaded from YAML stream or file, the original YAML node tree is available to the user
trough CiiConfigDocument::GetYamlSourceRootNode()
in C++ and CiiConfigDocument.get_yaml_source_root_node()
in Python.
To operate on the returned YAML root node in C++, yaml-cpp API must be used.
To operate on the returned YAML root node in Python, PyYAML API must be used.
Note that subsequent changes on the returned YAML node tree do not reflect on the config document, and vice versa, subsequent changes on the config document do not reflect on the YAML node tree. It is recommended that when dealing directly with the YAML node tree, the best course is to save the modified tree as YAML into file or stream, and then load it into another config document. The sample, analogously, applies to changes on the config document: save it to YAML stream/file, and then load it directly with a YAML parser.
6.6. Document instance interface¶
- Once the document is created or loaded, access to its instances is available via the document instance interface. The document instance interface allows access to specific configuration instances. Beside the value, instances contain additional information:
- name
Name of the instance (only valid with top level and Map member instances)
- type
Three user visible types are predefined: Scalar, Sequence, Map.
- metadata
Metadata atrributes of the instance.
- data type
Optional config ng data type associated with the instance
- origin
Source file location (line, column) of the YAML element from which the instance has been constructed.
Sequence and Map instances provide non recursive (by default) and recursive iterators and methods to access the instance value.
6.6.1. Accessing document instance interface¶
6.6.1.1. C++¶
The document instance interface is available through method ::elt::configng::CiiConfigDocument::Instances() method. i.e.:
::elt::configng::CiiConfigDocument document = ::elt::configng.CiiConfigClient::Load("cii.config://local/file.yaml");
// For reading only
const ::elt::configng::CiiConfigInstanceNamespace &instances = document.Instances();
Access to a specific instance is done through operator[]:
// Target type is known, instance value will be automatically
// converted to target type (note exception is thrown if conversion not possible)
double d = instances["theDouble"];
// Target type is not known, conversion method As() must be used
std::cout << instances["theDouble"].As<double>() << std::endl;
// Assign new value to the instance
instances["theDouble"].Assign(6.7);
Obtaining additional information:
::elt::configng::CiiConfigInstanceNamespace &theDouble = document.Instances()["theDouble"];
// Check the type
if (theDouble.IsScalar()) {
...
} else if (theDouble.IsSequence()) {
// Tterate non recursively over instance
for (const auto &item: instance) {
...
}
...
} else if (theDouble.IsMap()) {
...
}
// Obtain the origin
::elt::configng::CiiConfigItemOrigin origin = theDouble.GetOrigin();
// Display the origin
std::cout << "Filename: " << origin.source << " line: " << origin.line << " column: "
<< origin.column << std::endl;
// obtain config-ng data type of the instance
::elt::configng::CiiConfigDataType data_type = theDouble.GetDataType();
// access metadata of the instance
::elt::configng::CiiConfigMetadata &metadata = theDouble.GetMetadata();
// and metadata properties
if (metadata.Has("max")) {
std::cout << "theDouble has max property: " << metadata["max"].As<double>()
<< std::endl;
}
6.6.1.2. Python¶
The document instance interface is available through method elt.confing.CiiConfigDocument.get_instances(), or through the attribute accessor instances on the document object, i.e.:
document = elt.confing.CiiConfigClient.load('cii.config://local/file.yaml')
# Use attribute accessor instances to access instance 'theDouble'
theDouble = document.instances.theDouble
# Or the classic way
instances = document.get_instances()
theDouble = instances['theDouble']
# Print value of the instance
print(theDouble.get_value())
# Alternative to obtain the value
# is to use as_value() method which takes optional converter argument
# that is actually a function to call when instance value needs to be
# converted to python value
print(theDouble.as_value(lambda x: x.get_value() + 1))
# Assign new value to the instance
theDouble.assign(6.7)
Obtaining additional information:
theDouble = document.instances.theDouble
# Check the type
if theDouble.is_scalar():
...
elif theDouble.is_sequence():
# Iterate non recursively over instance
for item in theDouble:
print(item.get_value())
elif theDouble.is_map():
...
# Obtain origin of the instance
origin = theDouble.get_origin()
# Display the origin, get_info() method returns tuple (filename, line, column)
# indicating origin of the instance
print('Origin filename %s, line: %s, column: %s' % origin.get_info())
# Obtain config-ng data type of the instance
data_type = theDouble.get_data_type()
# When data type is not assigned to the instance, None is returned
if data_type is None:
print('Instance theDouble is untyped')
else:
print('Data type of the theDouble instance is ', data_type.get_name())
# Access metadata of the instance
metadata = theDouble.get_metadata()
# And metadata properties ...
if metadata.has('max'):
print('theDouble has max property: ', metadata['max'].get_value())
6.6.2. Iteration over document instances¶
The object returned by the document instance interface offers a recursive iterator over all document instances by default.
6.6.2.1. C++¶
const ::elt::configng::CiiConfigInstanceNamespace &instances = document.Instances();
for (const auto &[name, node]: instances) {
std::cout << "Name: " << name << ", Origin: " << node.GetOrigin() << std::cerr;
// Obtain associated metadata
::elt::configng::CiiConfigMetadata &metadata = node.GetMetadata();
// Obtain data type of the instance node from metadata
::elt::configng::CiiConfigDataType &data_type = metadata.GetDataType();
std::cout << " ... data type: " << data_type.GetName()
<< " originating: " << data_type.GetOrigin() << std::endl;
std::cout << " ... basic data type: "
<< elt::configng::util::ToString(data_type.GetBasicDataType()) << std::endl;
if (data_type.IsVector() || data_type.IsMatrix()) {
std::cout << ".... element data type: " << data_type.GetElementDataType().GetName();
}
}
6.6.2.2. Python¶
document = elt.configng.CiiConfigLoad('filename.yaml')
for name, item in document.instances:
# Data type can be None, indicating that config-ng data type is not assigned
# to the instance
data_type = item.get_data_type()
print(name, ' Data type: ', data_type)
print(name, ' Originating: ', item.get_origin()
if data_type is not None:
print('Basic data type: ', data_type.get_basic_data_type())
if data_type.is_matrix() or item.data_type.is_sequence():
print('..... element data type: ', data_type.get_element_data_type())
6.7. Document Validation¶
Metadata that is produced for each instance node is initially not validated, therefore it might not reflect the actual state of document.
To check the document validity against the schema (defined by elements with CII custom tags) and validity of the metadata, one must invoke check operation on the document. This validates the schema and all values of the document instances.
The Check operation returns an object describing the issues detected during document validation. In case this object does not contain any issues with error severity, the document is valid. This implies that the document is valid when only issues with warning severity were detected.
It is recommended to perform document validation after document loading or any operation that updates document like merge with another document or update with a programmaticaly built map of instances.
6.7.1. C++¶
The document validation operation is invoked by calling ::elt::configng::CiiConfigDocument::Check()
on the document instance.
// Load document
::elt::configng::CiiConfigDocument document = ::elt::configng::CiiConfigClient::Load("cii.local://file.yaml");
// Perform document validation
::elt::configng::CiiConfigDocumentIssues issues = document.Check();
// The following test returns true in case there was at least one issue with error severity
// was detected
if (issues) {
std::cerr << "Document is not valid! The following issues were detected: " << std::endl;
// One can iterate over issues. Each issue is instance of::elt::configng::CiiConfigDocumentIssue
// class.
for (auto &issue: issues) {
// Print out the issue
std::cerr << " " << issue << std::endl;
// Or examine it
if (issue.IsError()) {
std::cerr << "This is issue with code " << static_cast<int>(issue.GetCode())
<< " and message: " << issue.GetMessage() << std::endl;
}
} else {
// Document is valid at this point, but issues with warning severity can still be present
std::cout << "Document is valid." << std::endl;
if (issues.HasWarnings()) {
std::cout << "The following warnings were issued during validation: " << std::endl;
for (auto &issue: issues) {
std::cout << " " << issue << std::endl;
}
}
6.7.2. Python¶
Calling method check() on an elt.configng.CiiConfigDocument instance invokes the document validation operation.
# Load document
document = elt.configng.CiiConfigClient.load('cii.local://file.yaml')
# Perform document validation
issues = document.check()
if issues.has_errors():
print('Document is not valid! The following issues were detected:')
for issue in issues:
# Print the issue
print(' ', issue)
# Or examine it
if issue.is_error():
print('This is issue with code ', issue.get_code(), ' with message: ',
issue.get_message())
else:
# Document is valid, but issues with warning severity can still be present
print('Document is valid.')
if issues.has_warnings():
print('The following warnings were issued during validation:')
for issue in issues:
print(' ', issue)
6.8. Saving documents to YAML¶
A document can be emitted in YAML format to local files or streams. It is recommended that the documennt is validated before emitting it in YAML format. The Save operation supports additional options that can prevent overwriting existing file or inlining includes (meaning not generating !cfg.include directives in the emitted YAML document).
6.8.1. C++¶
// Load document
::elt::configng::CiiConfigDocument document = ::elt::configng::CiiConfigClient::Load('cii.local://file.yaml');
// Validate document
::elt::configng::CiiConfigDocumentIssues issues = document.Check();
// Only save valid document
if (!issues) {
// Save to file. Existing files are overwriten by default. Includes are not inlined
// Note that argument here is acutally file name not URI.
document.Save('file1.yaml');
// Save to file but prevent overwriting existing file.
// In case file already exists, ::elt::configng::CiiConfigExistError is thrown
try {
document.Save('file1.yaml,
{::elt::configng::CiiConfigDocument::SaveOptions::NO_OVERWRITE});
} catch (const ::elt::configng::CiiConfigExistsError &e) {
std::cerr << "Could not overwrite the file (" << e.what() << ")" << std::endl;
}
// Save to stream, inline includes
std::ostringstream stream;
document.Save(stream,
{::elt::configng::CiiConfigDocument::SaveOptions::INLINE_INCLUDES});
// Save to stream, generate !cfg.include directives for included files
std::ostringstream another_stream;
document.Save(another_stream);
}
6.8.2. Python¶
# Load document
document = elt.configng.CiiConfigClient.load('cii.local://file.yaml');
# Validate document
issues = document.check()
# Only save valid document
if not issues.has_errors():
# Save to file. Existing files are overwritten by default. Includes are not inlined.
# Note that argument here is actually file name not URI.
document.save('file1.yaml')
# Save to file but prevent overwriting existing file.
# In case file already exists, elt.configng.CiiConfigExistsError is raised.
try:
document.save('file1.yaml',
(elt.configng.CiiConfigDocument.SaveOptions.NO_OVERWRITE,))
except elt.configng.CiiConfigEistsError as e:
print('Could not overwrite the file %s' % e)
# Save to stream, inline includes
stream = io.StringIO()
document.Save(stream,
(elt.configng.CiiConfigDocument.SaveOptions.INLINE_INCLUDES,))
# Save to stream, generate !cfg.include directives for included files
another_stream = io.StringIO()
document.Save(another_stream)
6.9. Merging documents¶
One can request a merge of two documents via the merge operation. This operation modifies the target document in place.
The Merge operation does not modify target document in case it detects any issue that would prevent the merge from fully succeeding, unless explicitly permitted by the user.
It is recommended to validate both documents before attempting to execute merge operation. For clarity, validations are not performed in the following examples.
6.9.1. C++¶
// Load target document.
::elt::configng::CiiConfigDocument document = ::elt::configng::CiiConfigClient::Load("cii.config://local/document.yaml");
// Load document to merge
::elt::configng::CiiConfigDocument document_to_merge = ::elt::configng::CiiConfigClient::Load(
"cii.config://local/document_to_merge.yaml");
// Try merge operation. List of issues that prevented merge is returned. In case returned
// list is empty, merge succedded.
std::vector<::elt::configng::CiiConfigDocument::MergeIssue> merge_issues = document.Merge(document_to_merge);
if (merge_issues.empty()) {
std::cout << "Merge succeeded" << std::endl;
} else {
std::cerr << "Merge failed, the following issues were detected:" << std::endl;
for (const auto &issue: merge_issues) {
std::cerr << " " << issue << std::endl;
}
// Target document was not updated.
// Perform partial merge, only update those instances that can be safely merged.
// Partial merge is requested by supplying additinal boolean argument with true value.
// Merge issues for instances that could not be merged are still returned
merge_issues = document.Merge(document_to_merge, true)
}
6.9.2. Python¶
# Load target document
document = elt.configng.CiiConfigClient.load('cii.config://local/document.yaml')
# Load document to merge
document_to_merge = elt.configng.CiiConfigClient.load(
'cii.config://local/document_to_merge.yaml')
# Try merge operation. List of issues that prevented merge is returned. In case returned
# list is empty, merge succeeded.
merge_issues = document.merge(document_to_merge)
if not merge_issues:
print('Merge succeeded')
else:
print('Merge failed, the following issues were detected:')
for issue in merge_issues:
print(' ', issue)
# Target document was not updated.
# Perform partial merge, only update thos unstances that can be safely merged.
# Partial merge is requested by supplying additional bool argument with True value.
# Merge issues for instances that could not be merged are still returned
merge_issues = document.merge(document_to_merge, True)
6.10. Exceptions¶
Config-ng API calls can produce a number of exceptions. For details please refer to the API docs.
All exceptions generated by the config-ng API
have common basic class (::elt::configng::CiiConfigError
in C++ and
elt.configng.CiiConfigError
in Python).
List of config-ng exceptions that are defined in Python and C++:
- CiiConfigError
Base clas of config-ng exceptions.
- CiiConfigBuildError
Generated during process of building configuration document when major inconsistency is detected.
- CiiConfigTypeError
Indicates that argument with wrong data type was used.
- CiiConfigValueError
Indicates that argument with wrong value was used.
- CiiConfigNotFoundError
Item was not found
- CiiConfigExistsError
Item or file already exists.
- CiiConfigNotImplementedError
Feature was not implemented yet.
- CiiConfigIterationError
Inconsistency detected during iteration.
- CiiConfigIllegalUriError
Illegal URI was used.
An additional exception is defined in C++ implementation:
- CiiConfigDocumentNotFromFileError
Attempted to save document that was not loaded from file without providing file name.
6.11. YAML tags recognized by config-ng¶
Config-ng uses several specific tags in different contest. All tags recognized by config-ng have prefix cfg.
6.11.1. cfg.include¶
Request inclusion of another YAML file.
Syntax: !cfg.include <URI>: [NOERROR]
Where <URI> is file name or URI of the fle to include in the document. File is looked up according to the current search path of the client.
Optional NOERROR flag indicates that in case the file is not found, the operation should continue. Without this flag, an exception is thrown when search for a requested file failed.
Example:
# Include basic definitions
!cfg.include cii.config://local/basic_definitions.yaml:
# Include additional extensions, but do not fail if the file was not found
!cfg.include cii.config://local/extensions: NOERROR
6.11.2. cfg.type¶
Reference data type.
Syntax: !cfg.type:<TYPENAME>
<TYPENAME> is the name of a built-in data type or user-defined data type.
Example:
# Untyped instance
a: 10
# Typed instance, in this case b is of built in type int32
b: !cfg.type:int32 10
6.11.3. cfg.typedef¶
Define type alias or custom data type.
Syntax: !cfg.typedef <TYPENAME>[(<BASE>)]
<TYPENAME> is the name of the new data type. <BASE> is optional and must be the name of an existing built-in or user-defined data type. When specified, config-ng derives a new data type from the provided base data type.
Example:
# Type alias
!cfg.typedef myint(int32):
# Type alias with additional metadata
!cfg.typedef extint(int32):
min: 10
max: 100
default: 25
# User defined data type (like struct)
!cfg.typedef Point:
x: !cfg.type:double
y: !cfg.type:double
# Derived, inherits the members of the basic data type,
# in this case x and y. Adds new member z.
!cfg.typedef Point3D(Point):
z: !cfg.type:double
6.11.4. cfg.optional, cfg.required¶
Modifiers that can be used within user-defined data type member definition.
cfg.optional indicates that the value of this member needs not be present when initializing an instance of that data type.
cfg.required indicates that the value of this member must always be present when initializing an instance of this data type.
When neither of these modifiers are used, the value of the member is initialized from the default value, if not explicitly specified.
Example:
!cfg.typedef Point:
# x must be always specified
!cfg.required x: !cfg.type:double
# y is initialized from default not specified
y: !cfg.type:double
# z is optional
!cfg.optional z: !cfg.type:double
valid_point_1: !cfg.type:Point { x: 10 }
valid_point_2: !cfg.type:Point { x: 10, y: 55 }
valid_point_3: !cfg.type:Point { x: 10, z: 33 }
# The following instance is invalid, x is missing
invalid_point: !cfg.type:Point { y: 3, z: 3 }
6.12. List of built-in data types¶
List of built-in data types recognized by config-ng:
int8
uint8
int16
uint16
int32
uint32
int64
uint64
single
double
boolean
string
binary
vector_uint8
vector_int8
vector_uint16
vector_int16
vector_uint32
vector_int32
vector_uint64
vector_int64
vector_single
vector_double
vector_boolean
vector_string
matrix2d_uint8
matrix2d_int8
matrix2d_uint16
matrix2d_int16
matrix2d_uint32
matrix2d_int32
matrix2d_uint64
matrix2d_int64
matrix2d_single
matrix2d_double