Skip to content

Commit 9fc8e27

Browse files
authored
Merge pull request #382 from 0xdabbad00/redshift_and_es_support
Redshift and es support
2 parents 4e3483b + 63207ad commit 9fc8e27

File tree

6 files changed

+230
-3
lines changed

6 files changed

+230
-3
lines changed

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.4"
34+
__version__ = "2.5.5"
3535

3636

3737
def show_help(commands):

commands/prepare.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from netaddr import IPNetwork, IPAddress
3333
from shared.common import get_account, get_regions, is_external_cidr
3434
from shared.query import query_aws, get_parameter_file
35-
from shared.nodes import Account, Region, Vpc, Az, Subnet, Ec2, Elb, Elbv2, Rds, VpcEndpoint, Ecs, Lambda, Cidr, Connection
35+
from shared.nodes import Account, Region, Vpc, Az, Subnet, Ec2, Elb, Elbv2, Rds, VpcEndpoint, Ecs, Lambda, Redshift, ElasticSearch, Cidr, Connection
3636

3737
__description__ = "Generate network connection information file"
3838

@@ -117,6 +117,22 @@ def get_lambda_functions(region):
117117
return pyjq.all('.Functions[]|select(.VpcConfig!=null)', functions)
118118

119119

120+
def get_redshift(region):
121+
clusters = query_aws(region.account, "redshift-describe-clusters", region.region)
122+
return pyjq.all('.Clusters[]', clusters)
123+
124+
125+
def get_elasticsearch(region):
126+
es_domains = []
127+
domain_json = query_aws(region.account, "es-list-domain-names", region.region)
128+
domains = pyjq.all('.DomainNames[]', domain_json)
129+
for domain in domains:
130+
es = get_parameter_file(region, 'es', 'describe-elasticsearch-domain', domain['DomainName'])['DomainStatus']
131+
if 'VPCOptions' in es:
132+
es_domains.append(es)
133+
return es_domains
134+
135+
120136
def get_sgs(vpc):
121137
sgs = query_aws(vpc.account, "ec2-describe-security-groups", vpc.region)
122138
return pyjq.all('.SecurityGroups[] | select(.VpcId == "{}")'.format(vpc.local_id), sgs)
@@ -351,6 +367,16 @@ def build_data_structure(account_data, config, outputfilter):
351367
node = Lambda(region, lambda_json)
352368
nodes[node.arn] = node
353369

370+
# Redshift clusters
371+
for node_json in get_redshift(region):
372+
node = Redshift(region, node_json)
373+
nodes[node.arn] = node
374+
375+
# ElasticSearch clusters
376+
for node_json in get_elasticsearch(region):
377+
node = ElasticSearch(region, node_json)
378+
nodes[node.arn] = node
379+
354380
# Filter out nodes based on tags
355381
if len(outputfilter.get("tags", [])) > 0:
356382
for node_id in list(nodes):
@@ -374,7 +400,7 @@ def build_data_structure(account_data, config, outputfilter):
374400
# If there were no matches, remove the node
375401
if not has_match:
376402
del nodes[node_id]
377-
403+
378404
# Add the nodes to their respective subnets
379405
for node_arn in list(nodes):
380406
node = nodes[node_arn]

shared/nodes.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,90 @@ def __init__(self, parent, json_blob):
653653
super(Lambda, self).__init__(parent, json_blob)
654654

655655

656+
class Redshift(Leaf):
657+
@property
658+
def ips(self):
659+
ips = []
660+
for cluster_node in self._json_blob['ClusterNodes']:
661+
ips.append(cluster_node['PrivateIPAddress'])
662+
ips.append(cluster_node['PublicIPAddress'])
663+
return ips
664+
665+
@property
666+
def can_egress(self):
667+
return False
668+
669+
@property
670+
def subnets(self):
671+
return []
672+
673+
@property
674+
def tags(self):
675+
return pyjq.all('.Tags[]', self._json_blob)
676+
677+
@property
678+
def is_public(self):
679+
for ip in self.ips:
680+
if is_public_ip(ip):
681+
return True
682+
return False
683+
684+
@property
685+
def security_groups(self):
686+
return pyjq.all('.VpcSecurityGroups[].VpcSecurityGroupId', self._json_blob)
687+
688+
def __init__(self, parent, json_blob):
689+
self._type = "redshift"
690+
691+
# Set the parent to a VPC
692+
# Redshift has no subnet
693+
assert(parent._type == "region")
694+
for vpc in parent.children:
695+
if vpc.local_id == json_blob['VpcId']:
696+
self._parent = vpc
697+
698+
self._local_id = json_blob['ClusterIdentifier']
699+
self._arn = json_blob['Endpoint']['Address']
700+
self._name = truncate(json_blob['ClusterIdentifier'])
701+
super(Redshift, self).__init__(self._parent, json_blob)
702+
703+
704+
class ElasticSearch(Leaf):
705+
@property
706+
def ips(self):
707+
return []
708+
709+
@property
710+
def can_egress(self):
711+
return False
712+
713+
@property
714+
def subnets(self):
715+
return pyjq.all('.VPCOptions.SubnetIds[]', self._json_blob)
716+
717+
@property
718+
def tags(self):
719+
# TODO Custom collection is required for the tags because list-domains returns a domain name,
720+
# but getting the tags requires calling `es list-tags --arn ARN` and you get the ARN from
721+
# the `es-describe-elasticsearch-domain` files
722+
return []
723+
724+
@property
725+
def is_public(self):
726+
return False
727+
728+
@property
729+
def security_groups(self):
730+
return pyjq.all('.VPCOptions.SecurityGroupIds[]', self._json_blob)
731+
732+
def __init__(self, parent, json_blob):
733+
self._type = "elasticsearch"
734+
735+
self._local_id = json_blob['ARN']
736+
self._arn = json_blob['ARN']
737+
self._name = truncate(json_blob['DomainName'])
738+
super(ElasticSearch, self).__init__(parent, json_blob)
739+
656740
class Cidr(Leaf):
657741
def ips(self):
658742
return [self._local_id]

shared/public.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ def get_public_nodes(account, config, use_cache=False):
122122
for ip in target_node['node_data']['ips']:
123123
if is_public_ip(ip):
124124
target['hostname'] = ip
125+
elif target_node['type'] == 'redshift':
126+
target['type'] = 'redshift'
127+
target['hostname'] = target_node['node_data'].get('Endpoint', {}).get('Address', '')
125128
else:
126129
# Unknown node
127130
raise Exception('Unknown type: {}'.format(target_node['type']))

web/icons/aws/elasticsearch.svg

Lines changed: 105 additions & 0 deletions
Loading

web/style.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,15 @@
265265
"background-clip": "none"
266266
}
267267
},
268+
{
269+
"selector": "[type = \"elasticsearch\"]",
270+
"css": {
271+
"background-opacity": 0,
272+
"background-image": "./icons/aws/elasticsearch.svg",
273+
"background-fit": "contain",
274+
"background-clip": "none"
275+
}
276+
},
268277
{
269278
"selector": "[type = \"kinesis\"]",
270279
"css": {

0 commit comments

Comments
 (0)