File Coverage

blib/lib/Cfn/Crawler.pm
Criterion Covered Total %
statement 85 89 95.5
branch 18 20 90.0
condition n/a
subroutine 11 11 100.0
pod n/a
total 114 120 95.0


line stmt bran cond sub pod time code
1             package Cfn::Crawler::Path;
2 1     1   681 use Moose;
  1         2  
  1         7  
3              
4             has path => (is => 'ro', isa => 'Str', required => 1);
5             has element => (is => 'ro', required => 1);
6              
7             package Cfn::Crawler;
8 1     1   7340 use Moose;
  1         3  
  1         4  
9              
10             has resolve_dynamicvalues => (is => 'ro', isa => 'Bool', default => 0);
11              
12             has cfn => (is => 'ro', isa => 'Cfn', required => 1);
13              
14             has _resolved_cfn => (is => 'ro', isa => 'Cfn', lazy => 1, default => sub {
15             my $self = shift;
16             if ($self->resolve_dynamicvalues) {
17             return $self->cfn->resolve_dynamicvalues;
18             } else {
19             return $self->cfn;
20             }
21             });
22              
23             has criteria => (is => 'ro', isa => 'CodeRef', required => 1);
24              
25             has _all => (
26             is => 'ro',
27             lazy => 1,
28             builder => '_scan_all',
29             isa => 'ArrayRef',
30             traits => ['Array'],
31             handles => {
32             all => 'elements'
33             },
34             );
35             for my $property (qw/resources outputs parameters
36             metadata mappings conditions/){
37             has "_$property" => (
38             is => 'ro',
39             lazy => 1,
40             builder => "_scan_$property",
41             isa => 'ArrayRef',
42             traits => [ 'Array' ],
43             handles => {
44             $property => 'elements',
45             }
46             );
47             }
48              
49             sub _match {
50 8698     8698   17078 my ($self, $path, $element) = @_;
51 8698 100       192587 if ($self->criteria->($element)) {
52 8695         44677 return Cfn::Crawler::Path->new(
53             path => $path,
54             element => $element,
55             );
56             } else {
57 3         24 return ();
58             }
59             }
60              
61             sub _scan_all {
62 93     93   287 my $self = shift;
63              
64 93         246 my @results;
65              
66 93         3146 push @results, $self->resources;
67 93         3509 push @results, $self->outputs;
68 93         3184 push @results, $self->parameters;
69 93         3063 push @results, $self->mappings;
70 93         3058 push @results, $self->metadata;
71 93         2989 push @results, $self->conditions;
72              
73 93         2543 return \@results;
74             }
75              
76             sub _scan_conditions {
77 93     93   209 my $self = shift;
78 93         180 my @results;
79              
80 93         2299 foreach my $c_name (sort $self->_resolved_cfn->ConditionList) {
81 4         19 my $path = "Conditions.$c_name";
82 4         91 my $condition = $self->_resolved_cfn->Condition($c_name);
83              
84 4         19 push @results, $self->_match($path, $condition);
85              
86             #TODO: Can't crawl into conditions, because they are not proper
87             # objects yet
88             #foreach my $cond_key (keys %$condition) {
89             # push @results, $self->_crawl_values("$path\.$cond_key", $condition->{ $cond_key });
90             #}
91             }
92              
93 93         5416 return \@results;
94             }
95              
96             sub _scan_metadata {
97 93     93   241 my $self = shift;
98 93         168 my @results;
99              
100 93         2054 foreach my $md_name (sort $self->_resolved_cfn->MetadataList) {
101 0         0 my $path = "Metadata.$md_name";
102 0         0 my $metadata = $self->_resolved_cfn->MetadataItem($md_name);
103              
104 0         0 push @results, $self->_match($path, $metadata);
105             }
106              
107 93         2812 return \@results;
108             }
109              
110             sub _scan_mappings {
111 93     93   178 my $self = shift;
112 93         172 my @results;
113              
114 93         2138 foreach my $m_name (sort $self->_resolved_cfn->MappingList) {
115 98         36349 my $path = "Mappings.$m_name";
116 98         2226 my $mapping = $self->_resolved_cfn->Mapping($m_name);
117              
118 98         303 push @results, $self->_match($path, $mapping);
119             }
120              
121 93         29507 return \@results;
122             }
123              
124             sub _scan_parameters {
125 93     93   215 my $self = shift;
126 93         185 my @results;
127              
128 93         2221 foreach my $p_name (sort $self->_resolved_cfn->ParameterList) {
129 294         140018 my $path = "Parameters.$p_name";
130 294         6616 my $parameter = $self->_resolved_cfn->Parameter($p_name);
131              
132 294         912 push @results, $self->_match($path, $parameter);
133             }
134              
135 93         49061 return \@results;
136             }
137              
138             sub _scan_outputs {
139 93     93   184 my $self = shift;
140 93         331 my @results;
141              
142 93         2160 foreach my $o_name (sort $self->_resolved_cfn->OutputList) {
143 135         455 my $path = "Outputs.$o_name";
144 135         3207 my $output = $self->_resolved_cfn->Output($o_name);
145              
146 135         518 push @results, $self->_match($path, $output);
147              
148 135         89246 push @results, $self->_crawl_values("$path\.Value", $output->Value);
149             }
150              
151 93         2931 return \@results;
152             }
153              
154             sub _scan_resources {
155 93     93   225 my $self = shift;
156 93         217 my @results;
157              
158 93         2249 foreach my $r_name (sort $self->_resolved_cfn->ResourceList) {
159 591         1957 my $path = "Resources.$r_name";
160 591         14385 my $resource = $self->_resolved_cfn->Resource($r_name);
161              
162 591         2393 push @results, $self->_match($path, $resource);
163              
164 591 100       402469 next if (not defined $resource->Properties);
165              
166 563         16952 foreach my $prop ($resource->Properties->meta->get_all_attributes) {
167 5680         66432 my $prop_name = $prop->name;
168 5680         16820 my $prop_value = $resource->Property($prop_name);
169            
170 5680         20793 push @results, $self->_crawl_values("$path\.Properties\.$prop_name", $prop_value);
171             }
172             }
173              
174 93         3109 return \@results;
175             }
176              
177             #
178             # since Cfn::Values are recursive (can contain other Cfn::Values)
179             # this guy will recurse over them, and for the ones matching the
180             # criteria, will give you a path to them
181             #
182             sub _crawl_values {
183 12361     12361   25666 my ($self, $path, $value) = @_;
184            
185 12361 100       45101 return if (not blessed $value);
186 7576 50       25154 die "Found something that isn't a Cfn::Value" if (not $value->isa('Cfn::Value'));
187              
188 7576         9960 my @results;
189              
190 7576         18649 push @results, $self->_match($path, $value);
191              
192 7576 100       4908081 if ($value->isa('Cfn::Value::Array')) {
    100          
    100          
    100          
    100          
    50          
193 960         2460 my $index = 0;
194 960         1615 foreach my $element (@{ $value->Value }) {
  960         21481  
195 2297         10297 push @results, $self->_crawl_values("$path\.$index", $element);
196 2297         5237 $index++;
197             }
198             } elsif ($value->isa('Cfn::Value::Function')) {
199 1672         41531 push @results, $self->_crawl_values("$path\." . $value->Function, $value->Value);
200             } elsif ($value->isa('Cfn::Value::Hash')) {
201 143         258 my $index;
202 143         215 foreach my $key (sort keys %{ $value->Value }){
  143         3207  
203 305         6833 push @results, $self->_crawl_values("$path\.$key", $value->Value->{ $key });
204             }
205             } elsif ($value->isa('Cfn::Value::Primitive')) {
206             # A primitives value is not traversable
207             } elsif ($value->isa('Cfn::Value::TypedValue')) {
208 445         2618 foreach my $property ($value->meta->get_all_attributes) {
209 2272         45515 my $prop_name = $property->name;
210 2272         83786 my $prop_value = $value->$prop_name;
211 2272         8581 push @results, $self->_crawl_values("$path\.$prop_name", $prop_value);
212             }
213             } elsif ($value->isa('Cfn::DynamicValue')) {
214             # A DynamicValue is not traversable
215             } else {
216 0         0 die "Unknown $value at $path";
217             }
218              
219 7576         22783 return @results;
220             }
221              
222             1;