File Coverage

blib/lib/Rex/CMDB/TOML.pm
Criterion Covered Total %
statement 26 132 19.7
branch 0 44 0.0
condition 0 9 0.0
subroutine 9 21 42.8
pod 0 2 0.0
total 35 208 16.8


line stmt bran cond sub pod time code
1             # (c) Jan Gehring
2             # (c) Zane C. Bowers-Hadley
3              
4             package Rex::CMDB::TOML;
5              
6 1     1   140502 use 5.010001;
  1         4  
7 1     1   15 use strict;
  1         2  
  1         45  
8 1     1   6 use warnings;
  1         2  
  1         98  
9              
10             our $VERSION = '0.0.2'; # VERSION
11              
12 1     1   8 use base qw(Rex::CMDB::Base);
  1         4  
  1         853  
13              
14 1     1   226086 use Rex::Commands -no => [qw/get/];
  1         2  
  1         9  
15 1     1   3125 use Rex::Logger;
  1         3  
  1         77  
16 1     1   14 use TOML qw(from_toml);
  1         45484  
  1         84  
17 1     1   16 use Data::Dumper;
  1         2  
  1         64  
18 1     1   13 use Hash::Merge qw/merge/;
  1         13792  
  1         2116  
19              
20             require Rex::Commands::File;
21              
22             sub new {
23 0     0 0   my $that = shift;
24 0   0       my $proto = ref($that) || $that;
25 0           my $self = {@_};
26              
27 0           $self->{merger} = Hash::Merge->new();
28              
29 0 0         if ( !defined $self->{merge_behavior} ) {
30             $self->{merger}->specify_behavior(
31             {
32             SCALAR => {
33 0     0     SCALAR => sub { $_[0] },
34 0     0     ARRAY => sub { $_[0] },
35 0     0     HASH => sub { $_[0] },
36             },
37             ARRAY => {
38 0     0     SCALAR => sub { $_[0] },
39 0     0     ARRAY => sub { $_[0] },
40 0     0     HASH => sub { $_[0] },
41             },
42             HASH => {
43 0     0     SCALAR => sub { $_[0] },
44 0     0     ARRAY => sub { $_[0] },
45 0     0     HASH => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) },
46             },
47             },
48 0           'REX_DEFAULT',
49             ); # first found value always wins
50              
51 0           $self->{merger}->set_behavior('REX_DEFAULT');
52             }
53             else {
54 0 0         if ( ref $self->{merge_behavior} eq 'HASH' ) {
55 0           $self->{merger}->specify_behavior( $self->{merge_behavior}, 'USER_DEFINED' );
56 0           $self->{merger}->set_behavior('USER_DEFINED');
57             }
58             else {
59 0           $self->{merger}->set_behavior( $self->{merge_behavior} );
60             }
61             }
62              
63 0           bless( $self, $proto );
64              
65             # turn roles off by default
66 0 0         if ( !defined( $self->{use_roles} ) ) {
67 0           $self->{use_roles} = 0;
68             }
69              
70             # set the default role path ro 'cmdb/roles'
71 0 0         if ( !defined( $self->{roles_path} ) ) {
72 0           $self->{roles_path} = File::Spec->join( $self->{path},'roles');
73             }
74              
75             # if parsing failure should be fatal
76             # default true
77 0 0         if ( !defined( $self->{parse_error_fatal} ) ) {
78 0           $self->{parse_error_fatal} = 1;
79             }
80              
81             # die if the role does not exist
82             # default true
83 0 0         if ( !defined( $self->{missing_role_fatal} ) ) {
84 0           $self->{missing_role_fatal} = 1;
85             }
86              
87             # default to false, config overwrites role settings
88 0 0         if ( !defined( $self->{roles_merge_after} ) ) {
89 0           $self->{roles_merge_after} = 0;
90             }
91              
92 0           return $self;
93             }
94              
95             sub get {
96 0     0 0   my ( $self, $item, $server ) = @_;
97              
98 0           $server = $self->__get_hostname_for($server);
99              
100 0           my $result = {};
101              
102             # keep this out here so generated when the files are loaded
103             # keep it around later for role processing
104 0           my %template_vars;
105              
106 0 0         if ( $self->__cache->valid( $self->__cache_key() ) ) {
107 0           $result = $self->__cache->get( $self->__cache_key() );
108             }
109             else {
110              
111 0           my @files = $self->_get_cmdb_files( $item, $server );
112              
113 0           Rex::Logger::debug( Dumper( \@files ) );
114              
115             # configuration variables
116 0           my $config_values = Rex::Config->get_all;
117 0           for my $key ( keys %{$config_values} ) {
  0            
118 0 0         if ( !exists $template_vars{$key} ) {
119 0           $template_vars{$key} = $config_values->{$key};
120             }
121             }
122 0           $template_vars{environment} = Rex::Commands::environment();
123              
124 0           for my $file (@files) {
125 0           Rex::Logger::debug("CMDB - Opening $file");
126 0 0         if ( -f $file ) {
127              
128 0           my $content = eval { local ( @ARGV, $/ ) = ($file); <>; };
  0            
  0            
129 0           my $t = Rex::Config->get_template_function();
130 0           $content .= "\n"; # for safety
131 0           $content = $t->( $content, \%template_vars );
132              
133 0           my ( $ref, $parse_error ) = from_toml($content);
134              
135             # only merge it if we have a actual result
136 0 0         if ( defined($ref) ) {
137 0           $result = $self->{merger}->merge( $result, $ref );
138             }
139             else {
140 0           my $error = 'Failed to parse TOML config file "' . $file . '" with error... ' . $parse_error;
141 0 0         if ( $self->{parse_error_fatal} ) {
142 0           die($error);
143             }
144             else {
145 0           warn($error);
146             }
147             }
148             }
149             }
150             }
151              
152             # if use_roles is true, process the roles variablesif set
153             # the item has roles and that the roles is a array
154 0 0 0       if ( $self->{use_roles}
      0        
155             && ( defined( $result->{roles} ) )
156             && ( ref( $result->{roles} ) eq 'ARRAY' ) )
157             {
158 0           Rex::Logger::debug("CMDB - Starting role processing");
159              
160             # load each role
161 0           foreach my $role ( @{ $result->{roles} } ) {
  0            
162 0           Rex::Logger::debug( "CMDB - Processing role '" . $role . "'" );
163 0           my $role_file = File::Spec->join( $self->{roles_path}, $role . '.toml' );
164              
165             # if the file exists, load it
166 0 0         if ( -f $role_file ) {
167 0           my $content = eval { local ( @ARGV, $/ ) = ($role_file); <>; };
  0            
  0            
168 0           my $t = Rex::Config->get_template_function();
169 0           $content .= "\n"; # for safety
170 0           $content = $t->( $content, \%template_vars );
171              
172 0           my ( $ref, $parse_error ) = from_toml($content);
173              
174             # only merge it if we have a actual result
175             # undef causes the merge feature to wipe it all out
176             # that and it did error... so we need to handle the error
177 0 0         if ( defined($ref) ) {
178              
179             # don't let host variables override the role if
180             # roles_merge_after is true
181 0 0         if ( $self->{roles_merge_after} ) {
182 0           $result = $self->{merger}->merge( $ref, $result );
183             }
184             else {
185 0           $result = $self->{merger}->merge( $result, $ref );
186             }
187             }
188             else {
189 0           my $error = 'Failed to parse TOML role file "' . $role_file . '" with error... ' . $parse_error;
190 0 0         if ( $self->{parse_error_fatal} ) {
191 0           die($error);
192             }
193             else {
194 0           warn($error);
195             }
196             }
197             }
198             else {
199 0           my $error = "The role '" . $role . "' is specified by the file '" . $role_file . "' does not eixst";
200 0 0         if ( $self->{missing_role_fatal} ) {
201 0           die($error);
202             }
203             else {
204 0           warn($error);
205             }
206             }
207             }
208             }
209              
210 0 0         if ( defined $item ) {
211 0           return $result->{$item};
212             }
213 0           return $result;
214             }
215              
216             sub _get_cmdb_files {
217 0     0     my ( $self, $item, $server ) = @_;
218              
219 0           $server = $self->__get_hostname_for($server);
220              
221 0           my @files;
222              
223 0 0         if ( !ref $self->{path} ) {
    0          
    0          
224 0           my $env = Rex::Commands::environment();
225 0           my $server_file = "$server.toml";
226 0           my $default_file = 'default.toml';
227             @files = (
228             File::Spec->join( $self->{path}, $env, $server_file ),
229             File::Spec->join( $self->{path}, $env, $default_file ),
230             File::Spec->join( $self->{path}, $server_file ),
231 0           File::Spec->join( $self->{path}, $default_file ),
232             );
233             }
234             elsif ( ref $self->{path} eq "CODE" ) {
235 0           @files = $self->{path}->( $self, $item, $server );
236             }
237             elsif ( ref $self->{path} eq "ARRAY" ) {
238 0           @files = @{ $self->{path} };
  0            
239             }
240              
241 0           my $os = Rex::Hardware::Host->get_operating_system();
242              
243 0           @files = map { $self->_parse_path( $_, { hostname => $server, operatingsystem => $os, } ) } @files;
  0            
244              
245 0           return @files;
246             }
247              
248             1;
249              
250             __END__