Skip to content

Commit e1ecc8b

Browse files
committed
blast-radius extended inital commit
1 parent a7ec4ef commit e1ecc8b

39 files changed

Lines changed: 1640 additions & 509 deletions

README.md

Lines changed: 75 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,82 @@
11
# Blast Radius
22

3-
[![CircleCI](https://circleci.com/gh/28mm/blast-radius/tree/master.svg?style=svg)](https://circleci.com/gh/28mm/blast-radius/tree/master)
43
[![PyPI version](https://badge.fury.io/py/BlastRadius.svg)](https://badge.fury.io/py/BlastRadius)
54

65
[terraform]: https://www.terraform.io/
76
[examples]: https://28mm.github.io/blast-radius-docs/
7+
[overlayfs]:
88

9-
_Blast Radius_ is a tool for reasoning about [Terraform][] dependency graphs
10-
with interactive visualizations.
9+
_Blast Radius_ is a tool for reasoning about [Terraform][] dependency graphs with interactive visualizations.
1110

1211
Use _Blast Radius_ to:
1312

1413
* __Learn__ about *Terraform* or one of its providers through real [examples][]
1514
* __Document__ your infrastructure
1615
* __Reason__ about relationships between resources and evaluate changes to them
17-
* __Interact__ with the diagram below (and many others) [in the docs][examples]
16+
* __Interact__ with the diagrams below (and many others) [in the docs][examples]
1817

19-
![screenshot](doc/blastradius-interactive.png)
18+
---
19+
20+
## Blast Radius
21+
![screenshot](doc/blastradiusext.png)
22+
23+
---
2024

2125
## Prerequisites
2226

23-
* [Graphviz](https://www.graphviz.org/)
2427
* [Python](https://www.python.org/) 3.7 or newer
28+
* [Terraform][] 0.12.x or newer
2529

26-
> __Note:__ For macOS you can `brew install graphviz`
30+
---
2731

2832
## Quickstart
2933

30-
The fastest way to get up and running with *Blast Radius* is to install it with
31-
`pip` to your pre-existing environment:
34+
For fastest way to get up and running with blast-radius is as follows:
3235

33-
```sh
34-
pip install blastradius
35-
```
36+
* Download and install the wheel files from the [release](https://github.com/nishubharti/blast-radius/releases)
3637

37-
Once installed just point *Blast Radius* at any initialized *Terraform*
38-
directory:
38+
```
39+
copy the blastradius/server/static/images folder to the terraform directory
40+
```
41+
install the wheel file
42+
```
43+
easy_install blastradius-0.1.25.1-py3-none-any.whl
44+
```
45+
or
46+
```
47+
pip3 blastradius-0.1.25.1-py3-none-any.whl
48+
```
3949

40-
```sh
41-
blast-radius --serve /path/to/terraform/directory
42-
```
50+
* Enrich the Blast Radius diagrams with the outcome of Terraform plan actions:
51+
```
52+
terraform plan --out tfplan.binary
53+
terraform show -json tfplan.binary > tfplan.json
54+
```
55+
for including cost and policy information into blast-radius cost.json and policy.json file need to be stored into the working directory.
56+
57+
* Once installed just point Blast Radius at any initialized Terraform directory:
58+
```sh
59+
blast-radius --serve /path/to/terraform/directory
60+
```
61+
62+
* Go to the browser link http://127.0.0.1:5000/ to view the Blast Radius diagram for the terraform file.
63+
64+
![BlastRadius](doc/blastradiusext.png)
65+
66+
The enrichments include - information from the Plan file, State file , cost file and time file .
67+
Click the columns adjacent to the Resource Names to view these enrichment in the side panel view.
68+
69+
![BlastRadiusExt](doc/blast-radius-ext.png)
4370

44-
And you will shortly be rewarded with a browser link http://127.0.0.1:5000/.
71+
---
72+
73+
## Build your own wheel file
74+
75+
* Create wheel file of this repo
76+
```sh
77+
python3 setup.py sdist bdist_wheel
78+
```
79+
---
4580

4681
## Docker
4782

@@ -50,34 +85,28 @@ And you will shortly be rewarded with a browser link http://127.0.0.1:5000/.
5085

5186
To launch *Blast Radius* for a local directory by manually running:
5287

53-
```sh
54-
docker run --rm -it -p 5000:5000 \
55-
-v $(pwd):/data:ro \
56-
--security-opt apparmor:unconfined \
57-
--cap-add=SYS_ADMIN \
58-
28mm/blast-radius
59-
```
88+
* create a dockerhub account
89+
```sh
90+
docker build -t <dockerhub_username>/blast-radius:v1 .
91+
docker push <dockerhub_username>/blast-radius:v1
92+
```
6093

61-
A slightly more customized variant of this is also available as an example
62-
[docker-compose.yml](./examples/docker-compose.yml) usecase for Workspaces.
94+
```sh
95+
docker run --cap-add=SYS_ADMIN -dit -p 5000:5000 -v <path>:/data:ro <dockerhub_username>/blast-radius:v1
96+
```
6397

6498
### Docker configurations
6599

66100
*Terraform* module links are saved as _absolute_ paths in relative to the
67101
project root (note `.terraform/modules/<uuid>`). Given these paths will vary
68-
betwen Docker and the host, we mount the volume as read-only, assuring we don't
69-
ever interfere with your real environment.
102+
betwen Docker and the host, we mount the volume as read-only, assuring we don't ever interfere with your real environment.
70103

71-
However, in order for *Blast Radius* to actually work with *Terraform*, it needs
72-
to be initialized. To accomplish this, the container creates an [overlayfs][]
73-
that exists within the container, overlaying your own, so that it can operate
104+
However, in order for *Blast Radius* to actually work with *Terraform*, it needs to be initialized as well as planned compulsory. To accomplish this, the container creates an [overlayfs][] that exists within the container, overlaying your own, so that it can operate
74105
independently. To do this, certain runtime privileges are required --
75106
specifically `--cap-add=SYS_ADMIN`.
76107

77-
For more information on how this works and what it means for your host, check
78-
out the [runtime privileges][privileges] documentation.
79108

80-
#### Docker & Subdirectories
109+
### Docker & Subdirectories
81110

82111
If you organized your *Terraform* project using stacks and modules,
83112
*Blast Radius* must be called from the project root and reference them as
@@ -101,14 +130,12 @@ It consists of 3 modules `foo`, `bar` and `dead`, followed by one `beef` stack.
101130
To apply *Blast Radius* to the `beef` stack, you would want to run the container
102131
with the following:
103132

104-
```sh
105-
$ cd project
106-
$ docker run --rm -it -p 5000:5000 \
107-
-v $(pwd):/data:ro \
108-
--security-opt apparmor:unconfined \
109-
--cap-add=SYS_ADMIN \
110-
28mm/blast-radius --serve stacks/beef
111-
```
133+
```sh
134+
$ cd project
135+
$ docker run --cap-add=SYS_ADMIN -dit -p 5000:5000 -v <pathofdirectory>:/data:ro <dockerhub_username>/blast-radius:v1
136+
```
137+
138+
---
112139

113140
## Embedded Figures
114141

@@ -121,11 +148,14 @@ You will need the following:
121148

122149
You can read more details in the [documentation](doc/embedded.md)
123150

151+
---
152+
124153
## Implementation Details
125154

126155
*Blast Radius* uses the [Graphviz][] package to layout graph diagrams,
127-
[PyHCL](https://github.com/virtuald/pyhcl) to parse [Terraform][] configuration,
128-
and [d3.js](https://d3js.org/) to implement interactive features and animations.
156+
[hcl] to parse [Terraform][] configuration, and [d3.js](https://d3js.org/) to implement interactive features and animations.
157+
158+
---
129159

130160
## Further Reading
131161

bin/blast-radius

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ from blastradius.handlers.apply import Apply
1717
from blastradius.handlers.terraform import Terraform
1818
from blastradius.server.server import app
1919

20+
from blastradius.server.server import simple_graph
21+
2022
def main():
2123

2224
parser = parser = argparse.ArgumentParser(description='blast-radius: Interactive Terraform Graph Visualizations')
@@ -28,7 +30,8 @@ def main():
2830
output_group.add_argument('--dot', action='store_const', const=True, default=False, help='print the graphviz/dot representation of the Terraform graph')
2931
output_group.add_argument('--svg', action='store_const', const=True, default=False, help='print the svg representation of the Terraform graph')
3032
output_group.add_argument('--serve', action='store_const', const=True, default=False, help='spins up a webserver with an interactive Terraform graph')
31-
33+
output_group.add_argument('--svg-ext', action='store_const', const=True, default=False, help='download the simple svg of modified svg representation of the Terraform graph')
34+
3235
parser.add_argument('--graph', type=str, help='`terraform graph` output (defaults to stdin)', default=sys.stdin)
3336

3437
# options to limit, re-focus, and re-center presentation of larger graphs.
@@ -49,11 +52,11 @@ def main():
4952
app.run(host='0.0.0.0',port=args.port)
5053
sys.exit(0)
5154

52-
elif args.json or args.dot or args.svg:
55+
elif args.json or args.dot or args.svg or args.svg_ext:
5356
if args.graph is sys.stdin:
5457
dot = DotGraph('', file_contents=sys.stdin.read())
5558
else:
56-
dot = DotGraph(args.graph)
59+
dot = DotGraph('',file_contents=simple_graph())
5760

5861
# we might not want to show every node in the depedency graph
5962
# specifying --module-depth is an easy way to limit detail
@@ -76,18 +79,22 @@ def main():
7679
parser.print_help()
7780
sys.exit(1)
7881
dot.focus(f_node)
79-
82+
8083
if args.json:
8184
tf = Terraform(args.directory)
8285
for node in dot.nodes:
8386
node.definition = tf.get_def(node)
84-
85-
if args.json:
86-
print(dot.json())
87+
f = open("visualization.json", "a")
88+
f.write(dot.json())
89+
f.close()
8790
elif args.dot:
8891
print(dot.dot())
8992
elif args.svg:
9093
print(dot.svg())
94+
elif args.svg_ext:
95+
f = open("visualization.svg", "a")
96+
f.write(dot.svg())
97+
f.close()
9198
else:
9299
parser.print_help()
93100

blastradius/handlers/apply.py

Lines changed: 34 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,35 @@
1-
# standard libraries
2-
import re
1+
from __future__ import print_function
32
import json
4-
5-
# 1st party libraries
6-
from blastradius.graph import Graph, Node, Edge
7-
from blastradius.handlers.dot import DotNode
8-
from blastradius.util import Re
9-
10-
class Apply(Graph):
11-
def __init__(self, filename):
12-
self.filename = filename
13-
self.contents = ''
14-
self.nodes = [] # we can populate this,
15-
self.edges = [] # but not this!
16-
17-
ansi_escape = re.compile(r'\x1b[^m]*m')
18-
with open(filename, 'r') as f:
19-
self.contents = ansi_escape.sub('', f.read())
20-
21-
# example output:
22-
#
23-
# aws_vpc.default: Creation complete after 4s (ID: vpc-024f7a64)
24-
# ...
25-
# aws_key_pair.auth: Creating...
26-
# fingerprint: "" => "<computed>"
27-
# key_name: "" => "default-key"
28-
# ...
29-
# aws_instance.web: Still creating... (10s elapsed)
30-
# aws_instance.web: Still creating... (20s elapsed)
31-
# aws_instance.web (remote-exec): Connecting to remote host via SSH...
32-
# aws_instance.web (remote-exec): Host: 1.2.3.4
33-
# aws_instance.web (remote-exec): User: ubuntu
34-
# ...
35-
36-
node_begin_re =r'(?P<name>\S+)\:\s+Creating...'
37-
node_compl_re = r'(?P<name>\S+)\:\s+Creation\s+complete\s+after\s+(?P<duration>\S+)\s+'
38-
node_still_re = r'(?P<name>\S+)\:\s+Still\s+creating\.\.\.\s+\((?P<duration>\S+)\s+'
39-
40-
for line in self.contents.splitlines():
41-
42-
r = Re()
43-
if r.match(node_begin_re, line):
44-
45-
46-
47-
48-
break
49-
50-
51-
52-
53-
print(self.contents)
54-
55-
3+
import sys
4+
import jinja2
5+
import json
6+
import subprocess
7+
import os.path
8+
from os import path
9+
10+
class Apply():
11+
def __init__(self,filename=None):
12+
self.apply_resource_info = []
13+
#reading from state file
14+
if filename == None:
15+
if(path.exists("terraform.tfstate")):
16+
with open("terraform.tfstate", 'r') as f:
17+
data = json.load(f)
18+
else:
19+
data = ""
20+
else:
21+
with open(filename, 'r') as f:
22+
data = json.load(f)
23+
24+
if (data) :
25+
for _, var in enumerate(data["resources"]):
26+
temp_data = dict()
27+
temp_data = var
28+
self.apply_resource_info.append(temp_data)
29+
30+
else:
31+
self.apply_resource_info.append("not applied")
32+
33+
def json(self):
34+
my_json_string = json.dumps(self.apply_resource_info,indent=4, sort_keys=True)
35+
return my_json_string

blastradius/handlers/controls.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import json
2+
import os.path
3+
from os import path
4+
5+
class Controls():
6+
def __init__(self,filename=None):
7+
self.resource_controls_info = []
8+
if filename == None:
9+
if(path.exists("policy.json")):
10+
with open("policy.json", 'r') as f:
11+
data = json.load(f)
12+
else:
13+
data = ""
14+
else:
15+
with open(filename, 'r') as f:
16+
data = json.load(f)
17+
18+
if (data) :
19+
for _, var in enumerate(data["resources"]):
20+
temp_data = dict()
21+
temp_data = var
22+
self.resource_controls_info.append(temp_data)
23+
24+
else:
25+
self.resource_controls_info.append("not available")
26+
27+
28+
def json(self):
29+
controls_json = json.dumps(self.resource_controls_info,indent=4, sort_keys=True)
30+
return controls_json

0 commit comments

Comments
 (0)