Skip to content

Commit 8c21581

Browse files
authored
Merge pull request #361 from 0xdabbad00/tags_for_rds_and_elb
Tags for rds and elb
2 parents f3c79c4 + 2021671 commit 8c21581

File tree

6 files changed

+92
-10
lines changed

6 files changed

+92
-10
lines changed

Pipfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ autoflake = "==0.7"
2222
nose = "==1.3.7"
2323
coverage = "==4.4.2"
2424
mock = "==2.0.0"
25-
pylint = "==1.8.1"
25+
pylint = "==2.3.1"
2626

2727
[requires]
2828
python_version = "3.7"

cloudmapper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import importlib
3232
import commands
3333

34-
__version__ = "2.5.2"
34+
__version__ = "2.5.3"
3535

3636
def show_help(commands):
3737
print("CloudMapper {}".format(__version__))

collect_commands.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,20 @@
109109
Parameters:
110110
- Name: DBSnapshotIdentifier
111111
Value: rds-describe-db-snapshots.json|.DBSnapshots[]?|.DBSnapshotIdentifier
112+
- Service: rds
113+
Request: list-tags-for-resource
114+
Parameters:
115+
- Name: ResourceName
116+
Value: rds-describe-db-instances.json|.DBInstances[]?|.DBInstanceArn
112117
- Service: elb
113118
Request: describe-load-balancers
114119
- Service: elb
115120
Request: describe-load-balancer-policies
121+
- Service: elb
122+
Request: describe-tags
123+
Parameters:
124+
- Name: LoadBalancerNames
125+
Value: elb-describe-load-balancers.json|.LoadBalancerDescriptions[]?|[[.LoadBalancerName]]
116126
- Service: elbv2
117127
Request: describe-load-balancers
118128
- Service: elbv2
@@ -125,6 +135,11 @@
125135
Parameters:
126136
- Name: TargetGroupArn
127137
Value: elbv2-describe-target-groups/*|.TargetGroups[].TargetGroupArn
138+
- Service: elbv2
139+
Request: describe-tags
140+
Parameters:
141+
- Name: ResourceArns
142+
Value: elbv2-describe-load-balancers.json|.LoadBalancers[]?|[[.LoadBalancerArn]]
128143
- Service: redshift
129144
Request: describe-clusters
130145
- Service: sqs

commands/collect.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,14 @@ def get_identifier_from_parameter(parameter):
3131

3232
def get_filename_from_parameter(parameter):
3333
if isinstance(parameter, list):
34-
filename = parameter[1]
34+
if len(parameter) > 1:
35+
filename = parameter[1]
36+
elif isinstance(parameter[0], list):
37+
# For elbv2:describe-tags we need ResourceArns as a list like `[Arn]`
38+
# the yaml file specifies `[[.LoadBalancerArn]]` because just doing
39+
# `[.LoadBalancerArn]` presents other issues, so this extracts out the inner, inner value.
40+
# Similar issue for elb:describe-tags
41+
filename = parameter[0][0]
3542
else:
3643
filename = parameter
3744

commands/prepare.py

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import argparse
2929
import pyjq
3030
from netaddr import IPNetwork, IPAddress
31-
from shared.common import get_account, query_aws, get_regions, is_external_cidr
31+
from shared.common import get_account, query_aws, get_parameter_file, get_regions, is_external_cidr
3232
from shared.nodes import Account, Region, Vpc, Az, Subnet, Ec2, Elb, Rds, Cidr, Connection
3333

3434
__description__ = "Generate network connection information file"
@@ -70,6 +70,7 @@ def get_subnets(az):
7070

7171

7272
def get_ec2s(subnet, outputfilter):
73+
# Filter the EC2s by the `tags`
7374
tag_filter = ""
7475
tag_set_conditions = []
7576
for tag_set in outputfilter.get("tags", []):
@@ -88,7 +89,7 @@ def get_ec2s(subnet, outputfilter):
8889
return pyjq.all(resource_filter.format(subnet.local_id), instances)
8990

9091

91-
def get_elbs(subnet):
92+
def get_elbs(subnet, outputfilter):
9293
# ELBs
9394
elb_instances = query_aws(subnet.account, "elb-describe-load-balancers", subnet.region)
9495
elb_resource_filter = '.LoadBalancerDescriptions[] | select(.VPCId == "{}") | select(.Subnets[] == "{}")'
@@ -99,13 +100,71 @@ def get_elbs(subnet):
99100
alb_resource_filter = '.LoadBalancers[] | select(.VpcId == "{}") | select(.AvailabilityZones[].SubnetId == "{}")'
100101
albs = pyjq.all(alb_resource_filter.format(subnet.vpc.local_id, subnet.local_id), alb_instances)
101102

102-
return elbs + albs
103+
if 'tags' not in outputfilter:
104+
return elbs + albs
105+
106+
# There are tags requested, so we need to filter these
107+
tag_filter = ""
108+
tag_set_conditions = []
109+
for tag_set in outputfilter.get("tags", []):
110+
conditions = [c.split("=") for c in tag_set.split(",")]
111+
condition_queries = []
112+
for pair in conditions:
113+
if len(pair) == 2:
114+
condition_queries.append('.{} == "{}"'.format(pair[0], pair[1]))
115+
tag_set_conditions.append('(' + ' and '.join(condition_queries) + ')')
116+
tag_filter = 'select(.TagDescriptions[0].Tags | from_entries | ' + ' or '.join(tag_set_conditions) + ')'
117+
118+
filtered_elbs = []
119+
for elb in elbs:
120+
tags = get_parameter_file(subnet.region, 'elb', 'describe-tags', elb['LoadBalancerName'])
121+
if tags is None:
122+
continue
123+
124+
if pyjq.first(tag_filter, tags) is not None:
125+
filtered_elbs.append(elb)
126+
127+
for elb in albs:
128+
tags = get_parameter_file(subnet.region, 'elbv2', 'describe-tags', elb['LoadBalancerArn'])
129+
if tags is None:
130+
continue
131+
132+
if pyjq.first(tag_filter, tags) is not None:
133+
filtered_elbs.append(elb)
134+
135+
return filtered_elbs
103136

104137

105-
def get_rds_instances(subnet):
138+
def get_rds_instances(subnet, outputfilter):
106139
instances = query_aws(subnet.account, "rds-describe-db-instances", subnet.region)
107140
resource_filter = '.DBInstances[] | select(.DBSubnetGroup.Subnets != null and .DBSubnetGroup.Subnets[].SubnetIdentifier == "{}")'
108-
return pyjq.all(resource_filter.format(subnet.local_id), instances)
141+
rds_instances = pyjq.all(resource_filter.format(subnet.local_id), instances)
142+
143+
if 'tags' not in outputfilter:
144+
return rds_instances
145+
146+
# There are tags requested, so we need to filter these
147+
tag_filter = ""
148+
tag_set_conditions = []
149+
for tag_set in outputfilter.get("tags", []):
150+
conditions = [c.split("=") for c in tag_set.split(",")]
151+
condition_queries = []
152+
for pair in conditions:
153+
if len(pair) == 2:
154+
condition_queries.append('.{} == "{}"'.format(pair[0], pair[1]))
155+
tag_set_conditions.append('(' + ' and '.join(condition_queries) + ')')
156+
tag_filter = 'select(.TagList | from_entries | ' + ' or '.join(tag_set_conditions) + ')'
157+
158+
filtered_instances = []
159+
for rds in rds_instances:
160+
tags = get_parameter_file(subnet.region, 'rds', 'list-tags-for-resource', rds['DBInstanceArn'])
161+
if tags is None:
162+
continue
163+
164+
if pyjq.first(tag_filter, tags) is not None:
165+
filtered_instances.append(rds)
166+
167+
return filtered_instances
109168

110169

111170
def get_sgs(vpc):
@@ -254,14 +313,14 @@ def build_data_structure(account_data, config, outputfilter):
254313
subnet.addChild(ec2)
255314

256315
# Get RDS's
257-
for rds_json in get_rds_instances(subnet):
316+
for rds_json in get_rds_instances(subnet, outputfilter):
258317
rds = Rds(subnet, rds_json)
259318
if not outputfilter["read_replicas"] and rds.node_type == "rds_rr":
260319
continue
261320
subnet.addChild(rds)
262321

263322
# Get ELB's
264-
for elb_json in get_elbs(subnet):
323+
for elb_json in get_elbs(subnet, outputfilter):
265324
elb = Elb(subnet, elb_json)
266325
subnet.addChild(elb)
267326

docs/network_visualizations.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ There are a number of filtering options that can be applied here to reduce the n
1414
The most useful filtering options:
1515
* `--regions`: Restrict the diagram to a set regions, ex. `us-east-1,us-east-2`
1616
* `--vpc-ids` and `--vpc-names`: Restrict the diagram to a set of VPCs.
17+
* `--tags`: Filter by tags, for exmaple `--tags Env=Prod --tags Env=Test,Name=Bastion` will filter to all resources tagged with a key `Env` that has value `Prod`, or where `Env=Test` and `Name=Bastion`. In this way, a the tags in a set are AND'd, and the tag sets are OR'd.
1718
* `--collapse-by-tag`: This is very useful to provide a tag name, and all nodes with that tag will be reduced to a single displayed node.
1819

1920
The other filtering options are:

0 commit comments

Comments
 (0)