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   460 use strict;
  59         119  
  59         465  
13 59     59   21747 use warnings;
  59         145  
  59         1201  
14 59     59   317  
  59         138  
  59         1533  
15             use Carp;
16 59     59   310 use 5.10.1;
  59         135  
  59         3165  
17 59     59   810  
  59         214  
18             use Config::Model::Exception;
19 59     59   359 use Data::Dumper;
  59         124  
  59         1337  
20 59     59   334 use Storable qw/dclone/;
  59         125  
  59         3145  
21 59     59   670 use Scalar::Util qw/weaken reftype/;
  59         161  
  59         2783  
22 59     59   435 use Log::Log4perl qw(get_logger :levels);
  59         143  
  59         2912  
23 59     59   407 use Path::Tiny 0.070;
  59         118  
  59         472  
24 59     59   7652  
  59         1299  
  59         12242  
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   174 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         283 if $self->rw_config->{function};
56             # try to load a specific Backend class
57 93 50       306 my $f = $self->rw_config->{function} || 'read';
58             my $c = $self->load_backend_class( $backend, $f );
59 93   50     434  
60 93         345 no strict 'refs'; ## no critic (ProhibitNoStrict)
61             return $c->new(
62 59     59   412 node => $self->node,
  59         157  
  59         137305  
63             name => $backend,
64             auto_create => $self->rw_config->{auto_create},
65             auto_delete => $self->rw_config->{auto_delete},
66             );
67             }
68 93         2022  
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 184 my $w = $args{write} || 0;
83 117         443 my $dir = $self->get_tuned_config_dir(%args);
84              
85 117   100     437 if ( not $dir->is_dir and $w and $args{auto_create} ) {
86 117         524 $logger->info("creating directory $dir");
87             $dir->mkpath;
88 117 50 100     5124 }
      66        
89 1         21  
90 1         14 unless ( $dir->is_dir ) {
91             my $mode = $w ? 'write' : 'read';
92             $logger->info( "$args{backend}: missing directory $dir ($mode mode)" );
93 117 100       3594 return ( 0, $dir );
94 4 50       42 }
95 4         16  
96 4         57 $logger->trace( "dir: " . $dir // '<undef>' );
97              
98             return ( 1, $dir );
99 113   50     1631 }
100              
101 113         1742 # 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 219  
108 142         869 # config file override
109             my $cfo = $args{config_file};
110 142   100     555  
111             if ( defined $cfo) {
112             my $override
113 142         222 = $args{root} ? $args{root}->child($cfo)
114             : $cfo =~ m!^/! ? path($cfo)
115 142 100       350 : path('.')->child($cfo);
116              
117 25 100       213 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       1066  
122 25         84 my ( $dir_ok, $dir ) = $self->get_cfg_dir_path(%args);
123 25         353  
124             if ( defined $args{file} ) {
125             my $file = $args{skip_compute} ? $args{file} : $self->node->compute_string($args{file});
126 117         485 my $res = $dir->child($file);
127             $logger->trace("get_cfg_file_path: returns $res");
128 117 100       378 return ( $dir_ok, $res );
129 101 100       730 }
130 101         296  
131 101         3136 return 0;
132 101         1177 }
133              
134             my ($self, $file_path) = @_;
135 16         59  
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 169 $self->file_backup( [ $file_path->lines_utf8 ] );
140             return $file_path->filehandle("<", ":utf8");
141 69 100       230 }
142 66         1853 else {
143             return;
144 66         851 }
145 66         25670 }
146              
147             # called at configuration node creation
148 3         113 #
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 301  
158 186         282 my $k = "Config::Model::Backend::" . ucfirst($backend);
159 186         258 my $f = $k . '.pm';
160             $f =~ s!::!/!g;
161 186         683 $c{$k} = $f;
162 186         1167  
163             # try another class
164 186         534 $k =~ s/_(\w)/uc($1)/ge;
165 186         435 $f =~ s/_(\w)/uc($1)/ge;
166 186         841 $c{$k} = $f;
167 186         581  
168             foreach my $c ( sort keys %c ) {
169             if ( $c->can($function) ) {
170 186         495  
  46         172  
171 186         416 # no need to load class
  46         107  
172 186         359 $logger->debug("load_backend_class: $c is already loaded (can $function)");
173             return $c;
174 186         631 }
175 192 100       1612 }
176              
177             # look for file to load
178 169         737 my $class_to_load;
179 169         1320 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         101 }
185 17         48 }
186 23         92  
187 23         160 if (not defined $class_to_load) {
188 246         591 Config::Model::Exception::Model->throw(
189 246 100       2372 object => $self->node,
190             error => "backend error: cannot find Perl class for backend: '$backend'",
191             );
192             };
193 17 50       86 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         43 die "Error with backend $backend: could not parse $file_to_load: $@\n";
200             }
201 17         101 return $class_to_load;
202 17         139 }
  17         7988  
203              
204 17 50       1577 my ( $self, %args ) = @_;
205 0         0  
206             $logger->trace( "called for node ", $self->node->location );
207 17         68  
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 389  
212             croak "unexpected args " . join( ' ', keys %args ) . "\n" if %args;
213 99         524  
214             my $rw_config = dclone $self->rw_config ;
215 99         806  
216 99         210 my $instance = $self->node->instance();
217 99         151  
218             # root override is passed by the instance
219 99 50       247 my $root_dir = $instance->root_dir ;
220              
221 99         2509 my $auto_create = $rw_config->{auto_create};
222             my $backend = $rw_config->{backend};
223 99         444  
224             if ( $rw_config->{default_layer} ) {
225             $self->read_config_sub_layer( $rw_config, $root_dir, $config_file_override, $check,
226 99         285 $backend );
227             }
228 99         187  
229 99         167 my ( $res, $file ) =
230             $self->try_read_backend( $rw_config, $root_dir, $config_file_override, $check, $backend );
231 99 100       224  
232 2         9 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         333  
237             }
238              
239 99 50 0     905 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 9 }
248              
249 2         6 Config::Model::Exception::Model->throw(
250 2         22 error => "backend error: unexpected default_layer parameters: "
251             . join( ' ', sort keys %$layered_config ),
252 2         7 object => $self->node,
253 6         12 ) if %$layered_config;
254 6 100       16  
255             my $i = $self->node->instance;
256             my $already_in_layered = $i->layered;
257              
258 2 50       8 # layered stuff here
259             if ( not $already_in_layered ) {
260             $i->layered_clear;
261             $i->layered_start;
262             }
263 2         10  
264 2         8 $self->try_read_backend( $layered_read, $root_dir, $config_file_override, $check, $backend );
265              
266             if ( not $already_in_layered ) {
267 2 50       8 $i->layered_stop;
268 2         12 }
269 2         10 }
270              
271             # called at configuration node creation, NOT when writing
272 2         13 #
273             # New subroutine "try_read_backend" extracted - Sun Jul 14 11:52:58 2013.
274 2 50       10 #
275 2         14 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 177 my @read_args = (
285 101         154 %$rw_config,
286 101         143 root => $root_dir,
287 101         149 config_dir => $read_dir,
288 101         152 backend => $backend,
289 101         160 check => $check,
290             config_file => $config_file_override
291 101         603 );
292              
293 101         3473 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         617 );
303              
304 101 50       2375 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         463  
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         184 }
314 101 100 100     324  
315 69         205 my $res;
316              
317             eval {
318 101   50     5473 $res = $backend_obj->$f(
319 101 100       378 @read_args,
320 2 50       19 file_path => $file_path,
321 2         27 object => $self->node,
322             );
323             };
324 101         775 my $error = $@;
325              
326 101         184 # catch eval error
327 101         653 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         439 $error->rethrow ;
334             }
335             elsif ( ref $error ) {
336 101 50 33     746 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       496 croak "auto_write_init: unexpected args " . join( ' ', sort keys %args ) . "\n"
353 101         318 if %args;
354              
355             my $rw_config = dclone $self->rw_config ;
356 101         2165  
357             my $instance = $self->node->instance();
358              
359             # root override is passed by the instance
360 93     93 0 209 my $root_dir = $instance->root_dir;
361              
362 93 50       217 my $backend = $rw_config->{backend};
363              
364             my $write_dir = $self->get_tuned_config_dir(%$rw_config);
365 93         2847  
366             $logger->trace( "auto_write_init creating write cb ($backend) for ", $self->node->name );
367 93         429  
368             my @wr_args = (
369             %$rw_config, # model data
370 93         341 config_dir => $write_dir, # override from instance
371             write => 1, # for get_cfg_file_path
372 93         196 root => $root_dir, # override from instance
373             );
374 93         519  
375             # used bby C::M::Dumper and C::M::DumpAsData
376 93         3397 # TODO: is this needed once multi backend are removed
377             $self->{auto_write}{$backend} = 1;
378 93         948  
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         331 my %cb_args = @_;
388              
389 93         136 my $force_delete = delete $cb_args{force_delete} ;
390 93   50     333 $logger->debug( "write cb ($backend) called for $location ", $force_delete ? '' : ' (deleted)' );
391 93         260 my $backend_obj = $self->backend_obj();
392 93         325  
393 93         218 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   188 }
398              
399 52         140 if ($file_ok) {
400 52 100       335 $fh = $self->open_file_to_write( $backend, $file_path, delete $cb_args{backup} );
401 52         499 }
402              
403 52         91 # override needed for "save as" button
404             my %backend_args = (
405 52 100       293 @wr_args,
406 41         216 file_path => $file_path,
407             object => $node,
408             %cb_args # override from user
409 52 100       156 );
410 37         171  
411             my $res;
412             if ($force_delete) {
413             $backend_obj->delete(%backend_args);
414 52         6625 }
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         111  
422 52 100       170 $self->auto_delete($file_path, \%backend_args)
423 1         6 if $rw_config->{auto_delete} and not $backend_class->skip_open ;
424             }
425              
426 51         116 return defined $res ? $res : $@ ? 0 : 1;
  51         420  
427 51         2548 };
428 51 50       183  
429             $logger->trace( "registering write $backend in node " . $self->node->name );
430 51         331  
431             $instance->register_write_back( $self->node->location, $backend, $wb );
432             }
433 51 100 100     952  
434             my ($self, $file_path, $args) = @_;
435              
436 52 50       1761 return unless $file_path;
    100          
437 93         594  
438             my $perl_data;
439 93         346 $perl_data = $self->node->dump_as_data( full_dump => $args->{full_dump} // 0)
440             if defined $self->node;
441 93         912  
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         7 }
450 3 50 50     45  
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         21  
458 2         41 # 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 124  
465             $logger->debug("$backend backend opened file $file_path to write");
466 37         79 return $file_path->filehandle(">",":utf8");
467 37   50     241 }
468 37 50       142  
469             my ( $self, $error, $file_path, $file_mode ) = @_;
470              
471 37         173 return unless defined $file_path;
472              
473 37 50 33     5239 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         181 $error->rethrow if ref($error) and $error->can('rethrow');
478 37         555 die $error;
479             }
480              
481             # TODO: move chmod in a backend role
482 51     51 0 210 $file_path->chmod($file_mode) if $file_mode;
483              
484 51 100       167 # TODO: move in a backend role
485             # check file size and remove empty files
486 37 50       110 $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       105  
496             1;
497              
498             # ABSTRACT: Load configuration node on demand
499 37 50 33     7181  
500              
501             =pod
502              
503 1     1 0 2 =encoding UTF-8
504 1         2  
505 1   50     10 =head1 NAME
506              
507             Config::Model::BackendMgr - Load configuration node on demand
508              
509             =head1 VERSION
510              
511             version 2.151
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