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