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   612 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   5871 use Moose;
  1         2  
  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   15404 my ($self, $path, $element) = @_;
51 8698 100       175419 if ($self->criteria->($element)) {
52 8695         40483 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   250 my $self = shift;
63              
64 93         204 my @results;
65              
66 93         2766 push @results, $self->resources;
67 93         3281 push @results, $self->outputs;
68 93         2703 push @results, $self->parameters;
69 93         2820 push @results, $self->mappings;
70 93         2614 push @results, $self->metadata;
71 93         2628 push @results, $self->conditions;
72              
73 93         2344 return \@results;
74             }
75              
76             sub _scan_conditions {
77 93     93   194 my $self = shift;
78 93         160 my @results;
79              
80 93         2221 foreach my $c_name (sort $self->_resolved_cfn->ConditionList) {
81 4         17 my $path = "Conditions.$c_name";
82 4         79 my $condition = $self->_resolved_cfn->Condition($c_name);
83              
84 4         17 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         4860 return \@results;
94             }
95              
96             sub _scan_metadata {
97 93     93   202 my $self = shift;
98 93         207 my @results;
99              
100 93         1925 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         2584 return \@results;
108             }
109              
110             sub _scan_mappings {
111 93     93   194 my $self = shift;
112 93         154 my @results;
113              
114 93         1903 foreach my $m_name (sort $self->_resolved_cfn->MappingList) {
115 98         31383 my $path = "Mappings.$m_name";
116 98         1969 my $mapping = $self->_resolved_cfn->Mapping($m_name);
117              
118 98         239 push @results, $self->_match($path, $mapping);
119             }
120              
121 93         25685 return \@results;
122             }
123              
124             sub _scan_parameters {
125 93     93   264 my $self = shift;
126 93         217 my @results;
127              
128 93         2256 foreach my $p_name (sort $self->_resolved_cfn->ParameterList) {
129 294         123434 my $path = "Parameters.$p_name";
130 294         6090 my $parameter = $self->_resolved_cfn->Parameter($p_name);
131              
132 294         659 push @results, $self->_match($path, $parameter);
133             }
134              
135 93         42613 return \@results;
136             }
137              
138             sub _scan_outputs {
139 93     93   287 my $self = shift;
140 93         220 my @results;
141              
142 93         1989 foreach my $o_name (sort $self->_resolved_cfn->OutputList) {
143 135         428 my $path = "Outputs.$o_name";
144 135         2814 my $output = $self->_resolved_cfn->Output($o_name);
145              
146 135         370 push @results, $self->_match($path, $output);
147              
148 135         78286 push @results, $self->_crawl_values("$path\.Value", $output->Value);
149             }
150              
151 93         2611 return \@results;
152             }
153              
154             sub _scan_resources {
155 93     93   303 my $self = shift;
156 93         194 my @results;
157              
158 93         2137 foreach my $r_name (sort $self->_resolved_cfn->ResourceList) {
159 591         1679 my $path = "Resources.$r_name";
160 591         12990 my $resource = $self->_resolved_cfn->Resource($r_name);
161              
162 591         1591 push @results, $self->_match($path, $resource);
163              
164 591 100       346434 next if (not defined $resource->Properties);
165              
166 563         14209 foreach my $prop ($resource->Properties->meta->get_all_attributes) {
167 5768         58033 my $prop_name = $prop->name;
168 5768         13342 my $prop_value = $resource->Property($prop_name);
169            
170 5768         17857 push @results, $self->_crawl_values("$path\.Properties\.$prop_name", $prop_value);
171             }
172             }
173              
174 93         2841 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 12455     12455   21439 my ($self, $path, $value) = @_;
184            
185 12455 100       39446 return if (not blessed $value);
186 7576 50       22364 die "Found something that isn't a Cfn::Value" if (not $value->isa('Cfn::Value'));
187              
188 7576         8732 my @results;
189              
190 7576         14145 push @results, $self->_match($path, $value);
191              
192 7576 100       4252456 if ($value->isa('Cfn::Value::Array')) {
    100          
    100          
    100          
    100          
    50          
193 960         1616 my $index = 0;
194 960         1418 foreach my $element (@{ $value->Value }) {
  960         18945  
195 2297         9231 push @results, $self->_crawl_values("$path\.$index", $element);
196 2297         4711 $index++;
197             }
198             } elsif ($value->isa('Cfn::Value::Function')) {
199 1672         35590 push @results, $self->_crawl_values("$path\." . $value->Function, $value->Value);
200             } elsif ($value->isa('Cfn::Value::Hash')) {
201 143         221 my $index;
202 143         214 foreach my $key (sort keys %{ $value->Value }){
  143         2947  
203 305         6242 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         1840 foreach my $property ($value->meta->get_all_attributes) {
209 2278         38351 my $prop_name = $property->name;
210 2278         72946 my $prop_value = $value->$prop_name;
211 2278         7594 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         19163 return @results;
220             }
221              
222             1;