├── 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 | ![](https://raw.github.com/phinze/terragraph/master/output.png) 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 | --------------------------------------------------------------------------------