Provided by: libconfig-model-perl_2.153-3_all bug

NAME

       Config::Model::Manual::ModelCreationAdvanced - Creating a model with advanced features

VERSION

       version 2.153

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 in "Monitor" section.

       Caveat: Xorg examples are based on Xorg 1.4 and may not be valid for Xorg 1.5 or 1.6

Model plugin

       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.

Model warp

       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.

   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 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 },
                },
              },
            }
         ]

   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 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
              }
            ]
          },
        },

   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 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 ...
          ]
         }

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>

AUTHOR

       Dominique Dumont

COPYRIGHT AND LICENSE

       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

perl v5.36.0                                2023Config::Model::Manual::ModelCreationAdvanced(3pm)