File Coverage

blib/lib/Config/Model/BackendMgr.pm
Criterion Covered Total %
statement 225 238 94.5
branch 76 108 70.3
condition 30 53 56.6
subroutine 26 26 100.0
pod 1 12 8.3
total 358 437 81.9


line stmt bran cond sub pod time code
1             #
2             # This file is part of Config-Model
3             #
4             # This software is Copyright (c) 2005-2022 by Dominique Dumont.
5             #
6             # This is free software, licensed under:
7             #
8             # The GNU Lesser General Public License, Version 2.1, February 1999
9             #
10              
11             use Mouse;
12 59     59   419 use strict;
  59         132  
  59         387  
13 59     59   21538 use warnings;
  59         155  
  59         1219  
14 59     59   296  
  59         128  
  59         1527  
15             use Carp;
16 59     59   303 use 5.10.1;
  59         136  
  59         3194  
17 59     59   879  
  59         209  
18             use Config::Model::Exception;
19 59     59   356 use Data::Dumper;
  59         141  
  59         1402  
20 59     59   305 use Storable qw/dclone/;
  59         138  
  59         3312  
21 59     59   384 use Scalar::Util qw/weaken reftype/;
  59         191  
  59         2738  
22 59     59   371 use Log::Log4perl qw(get_logger :levels);
  59         137  
  59         3001  
23 59     59   376 use Path::Tiny 0.070;
  59         119  
  59         431  
24 59     59   7513  
  59         1306  
  59         12564  
25             my $logger = get_logger('BackendMgr');
26             my $user_logger = get_logger('User');
27              
28             # one BackendMgr per file
29              
30             has 'node' => (
31             is => 'ro',
32             isa => 'Config::Model::Node',
33             weak_ref => 1,
34             required => 1
35             );
36             has 'file_backup' => ( is => 'rw', isa => 'ArrayRef', default => sub { [] } );
37              
38             has 'rw_config' => (
39             is => 'ro',
40             isa => 'HashRef',
41             required => 1
42             );
43              
44             has 'backend_obj' => (
45             is => 'rw',
46             isa => 'Config::Model::Backend::Any',
47             lazy => 1 ,
48             builder => '_build_backend_obj',
49             );
50              
51             my $self = shift;
52              
53 93     93   203 my $backend = $self->rw_config->{backend};
54             $logger->warn("function parameter for a backend is deprecated. Please implement 'read' method in backend $backend")
55 93         325 if $self->rw_config->{function};
56             # try to load a specific Backend class
57 93 50       357 my $f = $self->rw_config->{function} || 'read';
58             my $c = $self->load_backend_class( $backend, $f );
59 93   50     404  
60 93         311 no strict 'refs'; ## no critic (ProhibitNoStrict)
61             return $c->new(
62 59     59   407 node => $self->node,
  59         134  
  59         139032  
63             name => $backend,
64             auto_create => $self->rw_config->{auto_create},
65             auto_delete => $self->rw_config->{auto_delete},
66             );
67             }
68 93         2252  
69             has support_annotation => (
70             is => 'ro',
71             isa => 'Bool',
72             default => 0,
73             );
74              
75             with "Config::Model::Role::ComputeFunction";
76             with "Config::Model::Role::FileHandler";
77              
78             # check if dir is present. May create it in auto_create write mode
79             my $self = shift;
80             my %args = @_;
81              
82 117     117 0 201 my $w = $args{write} || 0;
83 117         499 my $dir = $self->get_tuned_config_dir(%args);
84              
85 117   100     448 if ( not $dir->is_dir and $w and $args{auto_create} ) {
86 117         518 $logger->info("creating directory $dir");
87             $dir->mkpath;
88 117 50 100     5409 }
      66        
89 1         46  
90 1         18 unless ( $dir->is_dir ) {
91             my $mode = $w ? 'write' : 'read';
92             $logger->info( "$args{backend}: missing directory $dir ($mode mode)" );
93 117 100       4197 return ( 0, $dir );
94 4 50       52 }
95 4         21  
96 4         72 $logger->trace( "dir: " . $dir // '<undef>' );
97              
98             return ( 1, $dir );
99 113   50     1737 }
100              
101 113         1882 # return (1, config file path) constructed from arguments or return
102             # (0). May create directory in auto_create write mode.
103             my $self = shift;
104             my %args = @_;
105              
106             my $w = $args{write} || 0;
107 142     142 0 320  
108 142         905 # config file override
109             my $cfo = $args{config_file};
110 142   100     598  
111             if ( defined $cfo) {
112             my $override
113 142         242 = $args{root} ? $args{root}->child($cfo)
114             : $cfo =~ m!^/! ? path($cfo)
115 142 100       343 : path('.')->child($cfo);
116              
117 25 100       174 my $mode = $w ? 'write' : 'read';
    100          
118             $logger->trace("$args{backend} override target file is $override ($mode mode)");
119             return ( 1, $override );
120             }
121 25 100       1053  
122 25         92 my ( $dir_ok, $dir ) = $self->get_cfg_dir_path(%args);
123 25         342  
124             if ( defined $args{file} ) {
125             my $file = $args{skip_compute} ? $args{file} : $self->node->compute_string($args{file});
126 117         549 my $res = $dir->child($file);
127             $logger->trace("get_cfg_file_path: returns $res");
128 117 100       490 return ( $dir_ok, $res );
129 101 100       700 }
130 101         283  
131 101         3304 return 0;
132 101         1243 }
133              
134             my ($self, $file_path) = @_;
135 16         75  
136             if ( $file_path->is_file ) {
137             $logger->debug("open_read_file: open $file_path for read");
138             # store a backup in memory in case there's a problem
139 69     69 0 192 $self->file_backup( [ $file_path->lines_utf8 ] );
140             return $file_path->filehandle("<", ":utf8");
141 69 100       221 }
142 66         1502 else {
143             return;
144 66         971 }
145 66         26179 }
146              
147             # called at configuration node creation
148 3         68 #
149             # New subroutine "load_backend_class" extracted - Thu Aug 12 18:32:37 2010.
150             #
151             my $self = shift;
152             my $backend = shift;
153             my $function = shift;
154              
155             $logger->trace("load_backend_class: called with backend $backend, function $function");
156             my %c;
157 186     186 0 371  
158 186         345 my $k = "Config::Model::Backend::" . ucfirst($backend);
159 186         281 my $f = $k . '.pm';
160             $f =~ s!::!/!g;
161 186         1136 $c{$k} = $f;
162 186         1203  
163             # try another class
164 186         609 $k =~ s/_(\w)/uc($1)/ge;
165 186         507 $f =~ s/_(\w)/uc($1)/ge;
166 186         871 $c{$k} = $f;
167 186         559  
168             foreach my $c ( sort keys %c ) {
169             if ( $c->can($function) ) {
170 186         598  
  46         202  
171 186         472 # no need to load class
  46         118  
172 186         403 $logger->debug("load_backend_class: $c is already loaded (can $function)");
173             return $c;
174 186         724 }
175 192 100       1736 }
176              
177             # look for file to load
178 169         805 my $class_to_load;
179 169         1435 foreach my $c ( sort keys %c ) {
180             $logger->trace("load_backend_class: looking to load class $c");
181             foreach my $prefix (@INC) {
182             my $realfilename = "$prefix/$c{$c}";
183             $class_to_load = $c if -f $realfilename;
184 17         41 }
185 17         56 }
186 23         101  
187 23         170 if (not defined $class_to_load) {
188 246         630 Config::Model::Exception::Model->throw(
189 246 100       2736 object => $self->node,
190             error => "backend error: cannot find Perl class for backend: '$backend'",
191             );
192             };
193 17 50       88 my $file_to_load = $c{$class_to_load};
194 0         0  
195             $logger->trace("load_backend_class: loading class $class_to_load, $file_to_load");
196             eval { require $file_to_load; };
197              
198             if ($@) {
199 17         57 die "Error with backend $backend: could not parse $file_to_load: $@\n";
200             }
201 17         130 return $class_to_load;
202 17         144 }
  17         9376  
203              
204 17 50       2227 my ( $self, %args ) = @_;
205 0         0  
206             $logger->trace( "called for node ", $self->node->location );
207 17         94  
208             my $check = delete $args{check};
209             my $config_file_override = delete $args{config_file};
210             my $auto_create_override = delete $args{auto_create};
211 99     99 0 428  
212             croak "unexpected args " . join( ' ', keys %args ) . "\n" if %args;
213 99         572  
214             my $rw_config = dclone $self->rw_config ;
215 99         906  
216 99         258 my $instance = $self->node->instance();
217 99         218  
218             # root override is passed by the instance
219 99 50       274 my $root_dir = $instance->root_dir ;
220              
221 99         2841 my $auto_create = $rw_config->{auto_create};
222             my $backend = $rw_config->{backend};
223 99         450  
224             if ( $rw_config->{default_layer} ) {
225             $self->read_config_sub_layer( $rw_config, $root_dir, $config_file_override, $check,
226 99         319 $backend );
227             }
228 99         239  
229 99         193 my ( $res, $file ) =
230             $self->try_read_backend( $rw_config, $root_dir, $config_file_override, $check, $backend );
231 99 100       276  
232 2         8 Config::Model::Exception::ConfigFile::Missing->throw (
233             file => $file || "<unknown>",
234             object => $self->node,
235             ) unless $res or $auto_create_override or $auto_create;
236 99         419  
237             }
238              
239 99 50 0     1029 my ( $self, $rw_config, $root_dir, $config_file_override, $check, $backend ) = @_;
      66        
      66        
240              
241             my $layered_config = delete $rw_config->{default_layer};
242             my $layered_read = dclone $rw_config ;
243              
244             foreach my $item ( qw/file config_dir os_config_dir/ ) {
245             my $lc = delete $layered_config->{$item};
246             $layered_read->{$item} = $lc if $lc;
247 2     2 0 7 }
248              
249 2         5 Config::Model::Exception::Model->throw(
250 2         19 error => "backend error: unexpected default_layer parameters: "
251             . join( ' ', sort keys %$layered_config ),
252 2         7 object => $self->node,
253 6         16 ) if %$layered_config;
254 6 100       14  
255             my $i = $self->node->instance;
256             my $already_in_layered = $i->layered;
257              
258 2 50       6 # layered stuff here
259             if ( not $already_in_layered ) {
260             $i->layered_clear;
261             $i->layered_start;
262             }
263 2         8  
264 2         7 $self->try_read_backend( $layered_read, $root_dir, $config_file_override, $check, $backend );
265              
266             if ( not $already_in_layered ) {
267 2 50       6 $i->layered_stop;
268 2         13 }
269 2         9 }
270              
271             # called at configuration node creation, NOT when writing
272 2         8 #
273             # New subroutine "try_read_backend" extracted - Sun Jul 14 11:52:58 2013.
274 2 50       18 #
275 2         10 my $self = shift;
276             my $rw_config = shift;
277             my $root_dir = shift;
278             my $config_file_override = shift;
279             my $check = shift;
280             my $backend = shift;
281              
282             my $read_dir = $self->get_tuned_config_dir(%$rw_config);
283              
284 101     101 0 215 my @read_args = (
285 101         185 %$rw_config,
286 101         165 root => $root_dir,
287 101         178 config_dir => $read_dir,
288 101         188 backend => $backend,
289 101         171 check => $check,
290             config_file => $config_file_override
291 101         568 );
292              
293 101         3396 my $backend_obj = $self->backend_obj();
294              
295             if ($backend_obj->can('suffix')) {
296             $logger->warn("suffix method is deprecated. you can remove it from backend $backend");
297             }
298              
299             my ( $file_ok, $file_path ) = $self->get_cfg_file_path(
300             @read_args,
301             skip_compute => $backend_obj->skip_open,
302 101         736 );
303              
304 101 50       2560 my $fh;
305 0         0 if (not $backend_obj->skip_open and $file_ok) {
306             $fh = $self->open_read_file($file_path) ;
307             }
308 101         471  
309             my $f = $self->rw_config->{function} || 'read';
310             if ($logger->is_info) {
311             my $fp = defined $file_path ? " on $file_path":'' ;
312             $logger->info( "Read with $backend " . reftype($backend_obj) . "::$f".$fp);
313 101         205 }
314 101 100 100     302  
315 69         219 my $res;
316              
317             eval {
318 101   50     5693 $res = $backend_obj->$f(
319 101 100       441 @read_args,
320 2 50       18 file_path => $file_path,
321 2         23 object => $self->node,
322             );
323             };
324 101         841 my $error = $@;
325              
326 101         207 # catch eval error
327 101         628 if ( ref($error) and $error->isa('Config::Model::Exception::Syntax') ) {
328              
329             $error->parsed_file( $file_path) unless $error->parsed_file;
330             $error->rethrow;
331             }
332             elsif ( ref $error and $error->isa('Config::Model::Exception') ) {
333 101         474 $error->rethrow ;
334             }
335             elsif ( ref $error ) {
336 101 50 33     788 die $error ;
    50 33        
    50          
    50          
337             }
338 0 0       0 elsif ( $error ) {
339 0         0 die "Backend $backend failed to read $file_path: $error";
340             }
341              
342 0         0 # only backend based on C::M::Backend::Any can support annotations
343             if ($backend_obj->can('annotation')) {
344             $self->{support_annotation} = $backend_obj->annotation ;
345 0         0 }
346              
347             return ( $res, $file_path );
348 0         0 }
349              
350             my ( $self, %args ) = @_;
351              
352 101 50       584 croak "auto_write_init: unexpected args " . join( ' ', sort keys %args ) . "\n"
353 101         339 if %args;
354              
355             my $rw_config = dclone $self->rw_config ;
356 101         2037  
357             my $instance = $self->node->instance();
358              
359             # root override is passed by the instance
360 93     93 0 273 my $root_dir = $instance->root_dir;
361              
362 93 50       239 my $backend = $rw_config->{backend};
363              
364             my $write_dir = $self->get_tuned_config_dir(%$rw_config);
365 93         2747  
366             $logger->trace( "auto_write_init creating write cb ($backend) for ", $self->node->name );
367 93         556  
368             my @wr_args = (
369             %$rw_config, # model data
370 93         300 config_dir => $write_dir, # override from instance
371             write => 1, # for get_cfg_file_path
372 93         232 root => $root_dir, # override from instance
373             );
374 93         503  
375             # used bby C::M::Dumper and C::M::DumpAsData
376 93         3542 # TODO: is this needed once multi backend are removed
377             $self->{auto_write}{$backend} = 1;
378 93         1150  
379             my $wb;
380             my $f = $rw_config->{function} || 'write';
381             my $backend_class = $self->load_backend_class( $backend, $f );
382             my $location = $self->node->name;
383             my $node = $self->node; # closure
384              
385             # provide a proper write back function
386             $wb = sub {
387 93         340 my %cb_args = @_;
388              
389 93         166 my $force_delete = delete $cb_args{force_delete} ;
390 93   50     392 $logger->debug( "write cb ($backend) called for $location ", $force_delete ? '' : ' (deleted)' );
391 93         338 my $backend_obj = $self->backend_obj();
392 93         396  
393 93         293 my ($fh, $file_ok, $file_path );
394              
395             if (not $backend_class->skip_open) {
396             ( $file_ok, $file_path ) = $self->get_cfg_file_path( @wr_args, %cb_args);
397 52     52   212 }
398              
399 52         127 if ($file_ok) {
400 52 100       354 $fh = $self->open_file_to_write( $backend, $file_path, delete $cb_args{backup} );
401 52         534 }
402              
403 52         112 # override needed for "save as" button
404             my %backend_args = (
405 52 100       312 @wr_args,
406 41         215 file_path => $file_path,
407             object => $node,
408             %cb_args # override from user
409 52 100       164 );
410 37         178  
411             my $res;
412             if ($force_delete) {
413             $backend_obj->delete(%backend_args);
414 52         10927 }
415             else {
416             $res = eval { $backend_obj->$f( %backend_args ); };
417             my $error = $@;
418             $logger->error( "write backend $backend $backend_class" . '::' . "$f failed: $error" )
419             if $error;
420             $self->close_file_to_write( $error, $file_path, $rw_config->{file_mode} );
421 52         134  
422 52 100       181 $self->auto_delete($file_path, \%backend_args)
423 1         7 if $rw_config->{auto_delete} and not $backend_class->skip_open ;
424             }
425              
426 51         105 return defined $res ? $res : $@ ? 0 : 1;
  51         428  
427 51         3823 };
428 51 50       190  
429             $logger->trace( "registering write $backend in node " . $self->node->name );
430 51         342  
431             $instance->register_write_back( $self->node->location, $backend, $wb );
432             }
433 51 100 100     940  
434             my ($self, $file_path, $args) = @_;
435              
436 52 50       1886 return unless $file_path;
    100          
437 93         655  
438             my $perl_data;
439 93         384 $perl_data = $self->node->dump_as_data( full_dump => $args->{full_dump} // 0)
440             if defined $self->node;
441 93         990  
442             my $size = ref($perl_data) eq 'HASH' ? scalar keys %$perl_data
443             : ref($perl_data) eq 'ARRAY' ? scalar @$perl_data
444             : $perl_data ;
445 7     7 1 24 if (not $size) {
446             $logger->info( "Removing $file_path (no data to store)" );
447 7 100       29 unlink($file_path);
448             }
449 3         6 }
450 3 50 50     41  
451              
452             my ( $self, $backend, $file_path, $backup ) = @_;
453 3 50       19  
    100          
454             my $do_backup = defined $backup;
455             $backup ||= 'old'; # use old only if defined
456 3 100       13 $backup = '.' . $backup unless $backup =~ /^\./;
457 2         9  
458 2         27 # make sure that parent dir exists before creating file
459             $file_path->parent->mkpath;
460              
461             if ( $do_backup and $file_path->is_file ) {
462             $file_path->copy( $file_path.$backup ) or die "Backup copy failed: $!";
463             }
464 37     37 0 115  
465             $logger->debug("$backend backend opened file $file_path to write");
466 37         74 return $file_path->filehandle(">",":utf8");
467 37   50     201 }
468 37 50       144  
469             my ( $self, $error, $file_path, $file_mode ) = @_;
470              
471 37         177 return unless defined $file_path;
472              
473 37 50 33     5353 if ($error) {
474 0 0       0 # restore backup and display error
475             $logger->warn("Error during write, restoring backup data in $file_path" );
476             $file_path->append_utf8({ truncate => 1 }, $self->file_backup );
477 37         173 $error->rethrow if ref($error) and $error->can('rethrow');
478 37         507 die $error;
479             }
480              
481             # TODO: move chmod in a backend role
482 51     51 0 215 $file_path->chmod($file_mode) if $file_mode;
483              
484 51 100       172 # TODO: move in a backend role
485             # check file size and remove empty files
486 37 50       115 $file_path->remove if -z $file_path and not -l $file_path;
487             }
488 0         0  
489 0         0 my $self = shift;
490 0 0 0     0 my $type = shift;
491 0         0 return $self->{auto_write}{$type} || 0;
492             }
493              
494             __PACKAGE__->meta->make_immutable;
495 37 100       108  
496             1;
497              
498             # ABSTRACT: Load configuration node on demand
499 37 50 33     7229  
500              
501             =pod
502              
503 1     1 0 2 =encoding UTF-8
504 1         2  
505 1   50     9 =head1 NAME
506              
507             Config::Model::BackendMgr - Load configuration node on demand
508              
509             =head1 VERSION
510              
511             version 2.152
512              
513             =head1 SYNOPSIS
514              
515             # Use BackendMgr to write data in Yaml file
516             # This example requires Config::Model::Backend::Yaml which is now
517             # shipped outside of Config::Model. Please get it on CPAN
518             use Config::Model;
519              
520             # define configuration tree object
521             my $model = Config::Model->new;
522             $model->create_config_class(
523             name => "Foo",
524             element => [
525             [qw/foo bar/] => {
526             type => 'leaf',
527             value_type => 'string'
528             },
529             ]
530             );
531              
532             $model->create_config_class(
533             name => "MyClass",
534              
535             # rw_config spec is used by Config::Model::BackendMgr
536             rw_config => {
537             backend => 'yaml',
538             config_dir => '/tmp/',
539             file => 'my_class.yml',
540             auto_create => 1,
541             },
542              
543             element => [
544             [qw/foo bar/] => {
545             type => 'leaf',
546             value_type => 'string'
547             },
548             hash_of_nodes => {
549             type => 'hash', # hash id
550             index_type => 'string',
551             cargo => {
552             type => 'node',
553             config_class_name => 'Foo'
554             },
555             },
556             ],
557             );
558              
559             my $inst = $model->instance( root_class_name => 'MyClass' );
560              
561             my $root = $inst->config_root;
562              
563             # put data
564             my $steps = 'foo=FOO hash_of_nodes:fr foo=bonjour -
565             hash_of_nodes:en foo=hello ';
566             $root->load( steps => $steps );
567              
568             $inst->write_back;
569              
570             # now look at file /tmp/my_class.yml
571              
572             =head1 DESCRIPTION
573              
574             This class provides a way to specify how to load or store
575             configuration data within the model.
576              
577             With these specifications, all configuration information is read
578             during creation of a node (which triggers the creation of a backend
579             manager object) and written back when L<write_back|Config::Model::Instance/write_back>
580             method is called either on the instance.
581              
582             =begin comment
583              
584             This feature is also useful if you want to read configuration class
585             declarations at run time. (For instance in a C</etc> directory like
586             C</etc/some_config.d>). In this case, each configuration class must
587             specify how to read and write configuration information.
588              
589             Idea: sub-files name could be <instance>%<location>.cds
590              
591             =end comment
592              
593             This load/store can be done with different backends:
594              
595             =over
596              
597             =item *
598              
599             Any of the C<Config::Model::Backend::*> classes available on your system.
600             For instance C<Config::Model::Backend::Yaml>.
601              
602             =item *
603              
604             C<cds_file>: Config dump string (cds) in a file. I.e. a string that describes the
605             content of a configuration tree is loaded from or saved in a text
606             file. This format is defined by this project. See
607             L<Config::Model::Loader/"load string syntax">.
608              
609             =item *
610              
611             C<perl_file>: Perl data structure (perl) in a file. See L<Config::Model::DumpAsData>
612             for details on the data structure. Now handled by L<Config::Model::Backend::PerlFile>
613              
614             =back
615              
616             When needed, C<write_back> method can be called on the instance (See
617             L<Config::Model::Instance>) to store back all configuration information.
618              
619             =head1 Backend specification
620              
621             The backend specification is provided as an attribute of a
622             L<Config::Model::Node> specification. These attributes are optional:
623             A node without C<rw_config> attribute must rely on another node to
624             read or save its data.
625              
626             When needed (usually for the root node), the configuration class is
627             declared with a C<rw_config> parameter which specifies the read/write
628             backend configuration.
629              
630             =head2 Parameters available for all backends
631              
632             The following parameters are accepted by all backends:
633              
634             =over 4
635              
636             =item config_dir
637              
638             Specify configuration directory. This parameter is optional as the
639             directory can be hardcoded in the backend class. C<config_dir> beginning
640             with 'C<~>' is munged so C<~> is replaced by C<< File::HomeDir->my_data >>.
641             See L<File::HomeDir> for details.
642              
643             =item file
644              
645             Specify configuration file name (without the path). This parameter is
646             optional as the file name can be hardcoded in the backend class.
647              
648             The configuration file name can be specified with C<&index> keyword
649             when a backend is associated to a node contained in a hash. For instance,
650             with C<file> set to C<&index.conf>:
651              
652             service # hash element
653             foo # hash index
654             nodeA # values of nodeA are stored in foo.conf
655             bar # hash index
656             nodeB # values of nodeB are stored in bar.conf
657              
658             Likewise, the keyword C<&element> can be used to specify the file
659             name. For instance, with C<file> set to C<&element-&index.conf>:
660              
661             service # hash element
662             foo # hash index
663             nodeA # values of nodeA are stored in service.foo.conf
664             bar # hash index
665             nodeB # values of nodeB are stored in service.bar.conf
666              
667             =item file_mode
668              
669             C<file_mode> parameter can be used to set the mode of the written
670             file(s). C<file_mode> value can be in any form supported by
671             L<Path::Tiny/chmod>. Example:
672              
673             file_mode => 0664,
674             file_mode => '0664',
675             file_mode => 'g+w'
676              
677             =item os_config_dir
678              
679             Specify alternate location of a configuration directory depending on the OS
680             (as returned by C<$^O>, see L<perlport/PLATFORMS>).
681             For instance:
682              
683             config_dir => '/etc/ssh',
684             os_config_dir => { darwin => '/etc' }
685              
686             =item default_layer
687              
688             Optional. Specifies where to find a global configuration file that
689             specifies default values. For instance, this is used by OpenSSH to
690             specify a global configuration file (C</etc/ssh/ssh_config>) that is
691             overridden by user's file:
692              
693             default_layer => {
694             os_config_dir => { 'darwin' => '/etc' },
695             config_dir => '/etc/ssh',
696             file => 'ssh_config'
697             }
698              
699             Only the 3 above parameters can be specified in C<default_layer>.
700              
701             =item auto_create
702              
703             By default, an exception is thrown if no read was
704             successful. This behavior can be overridden by specifying
705             C<< auto_create => 1 >> in one of the backend specification. For instance:
706              
707             rw_config => {
708             backend => 'IniFile',
709             config_dir => '/tmp',
710             file => 'foo.conf',
711             auto_create => 1
712             },
713              
714             Setting C<auto_create> to 1 is necessary to create a configuration
715             from scratch
716              
717             =item auto_delete
718              
719             Delete configuration files that contains no data. (default is to leave an empty file)
720              
721             =back
722              
723             =head2 Config::Model::Backend::* backends
724              
725             Specify the backend name and the parameters of the backend defined
726             in their documentation.
727              
728             For instance:
729              
730             rw_config => {
731             backend => 'yaml',
732             config_dir => '/tmp/',
733             file => 'my_class.yml',
734             },
735              
736             See L<Config::Model::Backend::Yaml> for more details for this backend.
737              
738             =head2 Your own backend
739              
740             You can also write a dedicated backend. See
741             L<How to write your own backend|Config::Model::Backend::Any/"How to write your own backend">
742             for details.
743              
744             =head1 Test setup
745              
746             By default, configurations files are read from the directory specified
747             by C<config_dir> parameter specified in the model. You may override the
748             C<root> directory for test.
749              
750             =head1 Methods
751              
752             =head2 support_annotation
753              
754             Returns 1 if at least the backend supports read and write annotations
755             (aka comments) in the configuration file.
756              
757             =head1 AUTHOR
758              
759             Dominique Dumont, (ddumont at cpan dot org)
760              
761             =head1 SEE ALSO
762              
763             L<Config::Model>, L<Config::Model::Instance>,
764             L<Config::Model::Node>, L<Config::Model::Dumper>
765              
766             =head1 AUTHOR
767              
768             Dominique Dumont
769              
770             =head1 COPYRIGHT AND LICENSE
771              
772             This software is Copyright (c) 2005-2022 by Dominique Dumont.
773              
774             This is free software, licensed under:
775              
776             The GNU Lesser General Public License, Version 2.1, February 1999
777              
778             =cut