NAME
Config::Model::Manual::ModelCreationAdvanced - Creating a model with advanced features
VERSION
version 1.258
Introduction
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 inMonitor
section.
Caveat: Xorg examples are based on Xorg 1.4 and may not be valid for Xorg 1.5 or 1.6
Model warp
From a user's point of view, model warp will look 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 will disappear from the GUI and some other options will 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.
Warped value
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 will be
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 will trigger 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 },
},
},
}
]
Warp in or warp out an element
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 will provide bind_address parameter:
LocalForward => {
type => 'list',
cargo => {
type => 'node',
config_class_name => 'Ssh::PortForward'
},
summary => 'Local port forwarding',
experience => 'advanced',
}
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
}
]
},
},
warped node
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 will use 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 ...
]
}
References
Computation and migrations
Cascaded warp
Config::Model also supports cascaded warps: A warped value is dependent on another value which is itself a warped value.
Feedback welcome
Feel free to send comments and suggestion about this page at
config-model-users at lists dot sourceforge dot net.
AUTHORS
Dominique Dumont <ddumont at cpan.org>