├── README.md
├── output.png
└── terragraph
/README.md:
--------------------------------------------------------------------------------
1 | # terragraph
2 |
3 | a wee utility for converting terraform textual graph notation into graphviz dot
4 |
5 | ## example
6 |
7 | Given input file `input.tfgraph` with contents:
8 |
9 | ```
10 | aws_eip.foo_eip
11 | aws_instance.foo_instance
12 | aws_eip.foo_eip (destroy tainted)
13 | aws_internet_gateway.gw (destroy tainted)
14 | aws_eip.foo_eip (destroy)
15 | provider.aws
16 | aws_instance.foo_instance
17 | aws_security_group.tf_test_foo
18 | aws_subnet.foo
19 | aws_instance.foo_instance (destroy tainted)
20 | aws_eip.foo_eip (destroy tainted)
21 | aws_instance.foo_instance (destroy)
22 | aws_eip.foo_eip (destroy)
23 | aws_internet_gateway.gw
24 | aws_eip.foo_eip
25 | aws_internet_gateway.gw (destroy tainted)
26 | provider.aws
27 | aws_security_group.tf_test_foo
28 | aws_vpc.foo
29 | aws_security_group.tf_test_foo (destroy tainted)
30 | aws_instance.foo_instance (destroy tainted)
31 | aws_security_group.tf_test_foo (destroy)
32 | aws_instance.foo_instance (destroy)
33 | aws_subnet.foo
34 | aws_vpc.foo
35 | aws_subnet.foo (destroy tainted)
36 | aws_instance.foo_instance (destroy tainted)
37 | aws_subnet.foo (destroy)
38 | aws_instance.foo_instance (destroy)
39 | aws_vpc.foo
40 | aws_vpc.foo (destroy tainted)
41 | aws_vpc.foo (destroy)
42 | aws_vpc.foo (destroy tainted)
43 | aws_security_group.tf_test_foo (destroy tainted)
44 | aws_subnet.foo (destroy tainted)
45 | aws_vpc.foo (destroy)
46 | aws_security_group.tf_test_foo (destroy)
47 | aws_subnet.foo (destroy)
48 | provider.aws
49 | ```
50 |
51 | Run:
52 |
53 | ```
54 | ./terragraph input.tfgraph | dot -Tpng > output.png
55 | ```
56 |
57 | See:
58 |
59 | 
60 |
--------------------------------------------------------------------------------
/output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phinze/terragraph/1be4395118827fba0ab7d0150197b3d3679b9089/output.png
--------------------------------------------------------------------------------
/terragraph:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require 'set'
4 |
5 | class Terragraph
6 | class Graph
7 | attr_reader :edges
8 | attr_reader :vertices
9 |
10 | def initialize
11 | @edges = []
12 | @vertices = Set.new
13 | end
14 |
15 | def add_vertex(description)
16 | @vertices.add(description)
17 | end
18 |
19 | def add_edge(source, dest)
20 | @edges << [source, dest]
21 | end
22 |
23 | def to_dot
24 | dot = "digraph G {\n"
25 | edges.each do |(source, dest)|
26 | dot += %Q( "#{source}" -> "#{dest}"\n)
27 | end
28 | vertices.each do |description|
29 | elements = description.split(" - ")
30 | dot += %Q( "#{description}"[label=<#{elements[0]}
#{elements[1]}>];\n)
31 | end
32 | dot += "}\n"
33 |
34 | dot
35 | end
36 | end
37 |
38 | def input_lines
39 | return @input_lines if defined? @input_lines
40 |
41 | if input && File.readable?(input)
42 | @input_lines = File.readlines(input)
43 | elsif !STDIN.tty? && !STDIN.closed?
44 | @input_lines = STDIN.readlines
45 | else
46 | @input_lines = []
47 | end
48 | end
49 |
50 | def initialize(args=ARGV)
51 | @input, @output, *extra_args = args
52 | @graph = Graph.new
53 |
54 | if input_lines.empty? || extra_args.length > 0
55 | puts <<-USAGE.gsub(/^ /, '')
56 | NAME
57 | terragraph
58 |
59 | SYNOPSIS
60 | ./terragraph [options] [output]
61 |
62 | DESCRIPTION
63 | Converts textual graph notation output from terraform debug logs into
64 | graphviz dot notation
65 |
66 | Writes to output file if specified, otherwise writes to stdout.
67 |
68 | Example of the input format accepted:
69 |
70 | aws_instance.foo_instance
71 | aws_security_group.tf_test_foo
72 | aws_instance.foo_instance (destroy tainted)
73 | aws_instance.foo_instance (destroy)
74 | aws_security_group.tf_test_foo
75 | aws_security_group.tf_test_foo (destroy tainted)
76 | aws_instance.foo_instance (destroy tainted)
77 | aws_security_group.tf_test_foo (destroy)
78 | aws_instance.foo_instance (destroy)
79 | provider.aws
80 |
81 | OPTIONS
82 | --help Prints this output
83 |
84 | input: input tfgraph file to read from
85 | output: output dot file to write to
86 |
87 | USAGE
88 | exit 1
89 | end
90 | end
91 |
92 | attr_reader :input, :output, :graph
93 |
94 | def run
95 | source = nil
96 | input_lines.each do |line|
97 | if line =~ /^ /
98 | graph.add_edge(source, line.strip)
99 | graph.add_vertex(line.strip)
100 | else
101 | source = line.chomp
102 | end
103 | end
104 | if output
105 | File.write(output, graph.to_dot)
106 | else
107 | puts graph.to_dot
108 | end
109 | end
110 | end
111 |
112 | Terragraph.new.run
113 |
--------------------------------------------------------------------------------