Config::Model::Manual::ModelCreationAdvanced - Creating a model with advanced
features
version 2.152
The page Config::Model::Manual::ModelCreationIntroduction explains what is a
configuration tree and a configuration model and how to create a simple
configuration model.
But a configuration model can be more complex and define interactions between
elements with the following features:
- •
- Model warp. For instance, Xorg driver options change
depending on driver name ("nvidia", "radeon"...)
- •
- Simple computation from other elements (used for
upgrades)
- •
- References. For instance, in
"Xorg::Device::Radeon", "Monitor-DVI-0" name must
refer to one of the monitors declared in "Monitor" section.
Caveat: Xorg examples are based on Xorg 1.4 and may not be valid for Xorg 1.5 or
1.6
Config::Model can also use model plugins. Each model can be augmented by model
snippets stored into directory "<model_name>.d". All files
found there are merged to existing model.
For instance, this model in file
".../Config/Model/models/Fstab/Fsline.pl":
{
name => "Fstab::Fsline",
element => [
fs_vfstype => {
type => 'leaf',
value_type => 'enum',
choice => [ qw/ext2 ext3/ ],
},
fs_mntopts => {
type => 'warped_node',
follow => { 'f1' => '- fs_vfstype' },
rules => [
'$f1 eq \'ext2\'', { 'config_class_name' => 'Fstab::Ext2FsOpt' },
'$f1 eq \'ext3\'', { 'config_class_name' => 'Fstab::Ext3FsOpt' },
],
}
]
}
can be augmented with the content of
".../Config/Model/models/Fstab/Fsline.d/addext4.pl":
{
name => "Fstab::Fsline",
element => [
fs_vfstype => { choice => [ qw/ext4/ ], },
fs_mntopts => {
rules => [
q!$f1 eq 'ext4'!, { 'config_class_name' => 'Fstab::Ext4FsOpt' },
],
},
]
} ;
Then, the merged model will feature "fs_vfstype" with choice
"ext2 ext4 ext4". Likewise, "fs_mntopts" will feature
rules for the 3 filesystems.
Under the hood, "augment_config_class" in Config::Model method is used
to load model snippets.
From a user's point of view, model warp looks like the structure or properties
of the configuration is changing (or adapting) dynamically depending on the
values being entered. For instance, when changing a driver name from
"fglrx" to "radeon", some options disappear from the GUI
and some other options pop-in.
Model warping need not be that spectacular and can have more subtle effect like
changing a default value.
Of course, there's no magic, model warp properties needs to be prepared and
declared in the model.
Let's start simple with value warp: the properties of a single value is changed
dynamically. Let's imagine a configuration file with 2 values:
size
which can be set to
big or
small and
length whose maximum
value is 10 when size is small and 50 when size is big. (this may be dumb, but
it's for the sake of the example).
So the basic model without warp is
element => [
size => { type => 'leaf',
value_type => 'enum',
choice => ['big','small'],
},
length => { type => 'leaf',
value_type => 'integer',
max => '10',
},
]
Now we need to declare the relationship between
size and
length to
be able to change dynamically the
max property.
This setup is made of 2 specifications:
- •
- what is the element that triggers the change (called
warp master in the doc)
- •
- what is the effect of the warp master change
The first is done with a declaration of the
path to
follow to find
the warp master (associated to a variable). The second is a set of value
properties:
element => [
size => {
type => 'leaf',
value_type => 'enum',
choice => ['big','small'],
},
length => {
type => 'leaf',
value_type => 'integer',
warp => { # change specification
follow => { # declare what trigger the change
size_type => '- size' # size_type: go 1 level above and fetch
# size value
},
rules => { # how to apply change
'$size_type eq "small"' => { # set max to 10 when size is small
max => 10
},
'$size_type eq "big" ' => { # set max to 50 when size is big
max => 50 },
},
},
}
]
Here's a real use case scenario from OpenSsh.
"ssh_config" enables a user to set up a tunnel through ssh. The input
of this tunnel can listen to localhost (default) or to other hosts. These
other hosts are specified by the
bind_adress part of the
"LocalForward" parameter.
But this bind address is ignored if "GatewayPorts" is false (which is
the default).
In order to present only meaningful parameters to the user,
bind_address
parameter must be hidden when "GatewayPorts" is false and shown when
"GatewayPorts" is true.
Here's the recipe. First create a boolean element for "GatewayPorts":
GatewayPorts => {
type => 'leaf',
value_type => 'boolean',
upstream_default => 0,
},
And "LocalForward" that provides
bind_address parameter:
LocalForward => {
type => 'list',
cargo => {
type => 'node',
config_class_name => 'Ssh::PortForward'
},
summary => 'Local port forwarding',
}
In "Ssh::PortForward" configuration class, declare
bind_address
with the warp instructions:
bind_address => {
type => 'leaf',
value_type => 'uniline',
level => 'hidden', # by default, is hidden from user
warp => { # instructions to show bind_address
follow => { # specify what does trigger the change
gp => '- - GatewayPorts' # gp: go to 2 levels above in tree ('- -') and
# fetch GatewayPorts value
},
rules => [ # specify how to apply the change triggered by gp
'$gp' => { # apply change when $gp is true
level => 'normal' # set level to normal (instead of 'hidden'). This change
# will show this parameter in the UI
}
]
},
},
Sometimes, warping a value line by line is not practical. For instance, in
"/etc/fstab" the mount options of a file system change drastically
from one file system to another. In this case, it's better to swap a
configuration class with another.
For instance, swap "vfat" mount options with "ext3" mount
options when a file system is changed from "vfat" to
"ext3".
Here's how this can be done. First declare the "fstype" parameter:
fs_vfstype => {
type => 'leaf',
mandatory => 1,
value_type => 'enum',
choice => [ 'auto', 'davfs', 'vfat', 'ext2', 'ext3', ] , # etc ...
}
Then declare "mntopts" as a
warped_node (not a simple
"node")) that uses "fs_vfstype" to swap one config class
with another:
fs_mntopts => {
type => 'warped_node', # a shape-shifting node
follow => {
f1 => '- fs_vfstype' , # use fs_vfstype as a trigger
},
rules => [
# condition => effect: config class to swap in
"$f1 eq 'proc'" => { config_class_name => 'Fstab::CommonOptions' },
"$f1 eq 'auto'" => { config_class_name => 'Fstab::CommonOptions' },
"$f1 eq 'vfat'" => { config_class_name => 'Fstab::CommonOptions' },
"$f1 eq 'swap'" => { config_class_name => 'Fstab::SwapOptions' },
"$f1 eq 'ext3'" => { config_class_name => 'Fstab::Ext3FsOpt' },
# etc ...
]
}
Config::Model also supports cascaded warps: A warped value is dependent on
another value which is itself a warped value.
Feel free to send comments and suggestion about this page at
config-model-users at lists dot sourceforge dot net.
Dominique Dumont <ddumont at cpan.org>
Dominique Dumont
This software is Copyright (c) 2005-2022 by Dominique Dumont.
This is free software, licensed under:
The GNU Lesser General Public License, Version 2.1, February 1999