Differences between revisions 9 and 10
Revision 9 as of 2009-04-14 16:29:26
Size: 12225
Comment: Added reader/writer section
Revision 10 as of 2009-04-15 11:18:47
Size: 12334
Comment: Added link to flash movie showing model creation through config-model-edit GUI
Deletions are marked like this. Additions are marked like this.
Line 70: Line 70:
This model creation process is shown in this [[attachment:approx-model-creation.swf|flash movie]]. In order to reduce the length of the movie, only 3 out of 10 configuration items were created in this movie. (Please do not mind the error message that pops in the middle of the movie, this bug has been fixed since ;-) ). This model creation process is shown in this [[http://config-model.sourceforge.net/approx/approx-model-creation.html|flash movie]]. In order to reduce the length of the movie, only 3 out of 10 configuration items were created in this movie. (Please do not mind the error message that pops in the middle of the movie, this bug has been fixed since ;-) ).
Line 158: Line 158:
First thing is to declare in Approx model how to read or write the configuration file using the [[http://search.cpan.org/dist/Config-Model/lib/Config/Model/AutoRead.pm|autoread]] feature (FIXME add link to flash movie). The reader writer class must be declared in Approx model: First thing is to declare in Approx model how to read or write the configuration file using the [[http://search.cpan.org/dist/Config-Model/lib/Config/Model/AutoRead.pm|autoread]] feature. For more detail see this [[ http://config-model.sourceforge.net/approx/approx-model-read-spec.html|movie]]. The reader writer class must be declared in Approx model:

Translation(s): none

(!) ?Discussion


This page contains a proposal for a way to handle upgrade where user's data and package maintainer data are merged with minimal interaction with user. The package approx will be used as an example.

Configuration upgrade by package

Status

This page is a proposal. It is not (yet?) accepted by Debian project. Stay tuned.

Introduction

For a casual user, the questions asked during package upgrades can be intimidating. Often, the user is faces with cryptic questions whether to keep his configuration, use the maintainers configuration or look at a diff. The casual user will seldom know what to do in this case.

This situation can be made worse if user's configuration was edited with a tool (e.g. cups configuration is edited through a web browser): the user has no knowledge of the syntax of the configuration file.

This proposal aims to provide a way for Debian package to minimize the number of questions raised to the user when upgrading packages. If questions are necessary, an interface will be provided to the user so that manual edition of configuration files will not be necessary.

Upgrades with Config::Model

Config-Model provides a framework for editing and validating the content of any configuration file or data. With a configuration model (expressed in a data structure), Config-Model provides a user interface and a tool to validate configuration.

The configuration model contains the following specifications :

  • The structure of the configuration model. This structure is a tree that can be flat (for simple files like approx.conf) or quite deep (for complex configuration like xorg.conf). The configuration tree nodes are instances of configuration class and the tree leaves contain the configuration values.

  • The constraints of the leaf values (i.e. integer, enum type, min values, max values ...)

  • the default values where the default value must be written in the configuration file.

  • the built-in default value where the value need not be written in the configuration file. This default value is built in the application.

This notion of default value versus built-in default value is important to distinguish:

  1. the values that were customized by the user (or sysadmin)
  2. the value that are recommended by the package maintainer (and specified as default in the model)

  3. the value that are built in the application.

During a package upgrade we want to propagate only the customized values from the old configuration file to the upgraded configuration file. The customized values are different from the built_in values (specified by upstream in the application) and different from the default values (specified by Debian maintainer in the configuration model).

So the idea is:

  • In old-prerm script, run config-edit to dump custom values (using old configuration model since we are at old-prerm phase) and store the result ( where ? ). This step does not modify user's configuration file (we may want to back it up though)

  • Upgrade the packages files as usual (including upgrade of configuration model)
  • In postinst, run config-edit to load user's customized data using new configuration model (but don't load data from user's configuration file) and write back the merged data in configuration file (i.e. merged values from user's data and data from new configuration model).

  • If the last step fails, we can either launch config-edit in interactive mode or fall-back to ucf.

Well, that was the theory. Let's experiment with Approx configuration file and work out the details.

Approx example

configuration analysis

From approx.conf(5) man page, we find that approx has a very simple configuration. Approx will need one configuration class that will have:

  • 10 configuration parameters, either boolean, integer or string. All of them have default built in approx.
  • a hash containing distribution names and their URL. These will be modeled with a hash of uniline values

The syntax of approx.conf is fairly simple but there's no Perl module available to read and write it. A dedicated parser/writer will be required.

Approx configuration model

To create the Approx configuration model, you can use the GUI provided by libconfig-model-itself-perl.

In a empty directory, run config-edit-model -model Approx and fill the fields as required. This model creation process is shown in this flash movie. In order to reduce the length of the movie, only 3 out of 10 configuration items were created in this movie. (Please do not mind the error message that pops in the middle of the movie, this bug has been fixed since ;-) ).

In the end you will get some kind of a translation of approx.conf(5) man page in this model (expunged of help text for brevity):

[
          {
            'name' => 'Approx',
            'element' => [
                           'max_rate',
                           {
                             'value_type' => 'uniline',
                             'type' => 'leaf',
                           },
                           'max_redirects',
                           {
                             'value_type' => 'integer',
                             'built_in' => '5',
                             'type' => 'leaf',
                           },
                           'user',
                           {
                             'value_type' => 'uniline',
                             'built_in' => 'approx',
                             'type' => 'leaf'
                           },
                           'group',
                           {
                             'value_type' => 'uniline',
                             'built_in' => 'approx',
                             'type' => 'leaf'
                           },
                           'syslog',
                           {
                             'value_type' => 'uniline',
                             'built_in' => 'daemon',
                             'type' => 'leaf'
                           },
                           'pdiffs',
                           {
                             'value_type' => 'boolean',
                             'built_in' => '1',
                             'type' => 'leaf'
                           },
                           'offline',
                           {
                             'value_type' => 'boolean',
                             'built_in' => '0',
                             'type' => 'leaf',
                           },
                           'max_wait',
                           {
                             'value_type' => 'integer',
                             'built_in' => '10',
                             'type' => 'leaf',
                           },
                           'verbose',
                           {
                             'value_type' => 'boolean',
                             'built_in' => '0',
                             'type' => 'leaf',
                           },
                           'debug',
                           {
                             'value_type' => 'boolean',
                             'built_in' => '0',
                             'type' => 'leaf',
                           },
                           'distributions',
                           {
                             'cargo' => {
                                          'value_type' => 'uniline',
                                          'type' => 'leaf'
                                        },
                             'type' => 'hash',
                             'index_type' => 'string'
                           }
                         ]
          }
        ]
;

You can view the actual model on Approx model SVN

Parsing and writing approx configuration file

First thing is to declare in Approx model how to read or write the configuration file using the autoread feature. For more detail see this movie. The reader writer class must be declared in Approx model:

   'read_config' => [
                     {
                      'file' => 'approx.conf',
                      'backend' => 'custom',
                      'class' => 'Config::Model::Approx',
                      'config_dir' => '/etc/approx'
                     }
                   ],

This indicates that a custom will be used to read /etc/approx/approx.conf. The class Config::Model::Approx must provide a read method. By default, the same setup is used to write back approx.conf with the write method.

These 2 methods are specified in Config::Model::Approx:

sub read {
    my %args = @_ ;

    foreach ($args{io_handle}->getlines) {
        chomp;
        s/#.*//;
        s/\s+/=/; # translate file in string loadable by C::M::Loader
        next unless $_; # skip empty lines
        my $load = s/^\$// ? $_ : "distributions:".$_;
        $args{object}->load($load) ;
    }

    return 1;
}

sub write {
    my %args = @_ ;
    my $node = $args{object} ;
    my $ioh  = $args{io_handle} ;

    # Using Config::Model::ObjTreeScanner would be overkill
    foreach my $elt ($node->get_element_name) {
        next if $elt eq 'distributions';
        my $v = $node->grab_value($elt) ;
        $ioh->printf("\$%-10s %s\n", $elt, $v) if defined $v ;
    }

    my $h = $node->fetch_element('distributions') ;
    foreach my $dname ($h->get_all_indexes) {
        $ioh->printf("%-10s %s\n", $dname, $node->grab_value("distributions:$dname")) ;
    }
    return 1;
}

Commands to manage upgrade

config-edit in dump mode, config-edit in load mode

Integrate upgrade command in package scripts

dump command in pre-uninstall , load user's data in post-install

What if Approx model is provided in a separate package (i.e. not in approx but in libconfig-model-approx-perl) ?

Fallback in case of upgrade failure

Fallback on ucf as usual.. Other ?



CategoryDebianDevelopment