This repository has been archived by the owner on Oct 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathdocker-compose-dot.go
179 lines (159 loc) · 4.64 KB
/
docker-compose-dot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
"log"
"github.com/awalterschulze/gographviz"
yaml "gopkg.in/yaml.v2"
)
type config struct {
Version string
Networks map[string]network
Volumes map[string]volume
Services map[string]service
}
type network struct {
Driver, External string
DriverOpts map[string]string "driver_opts"
}
type volume struct {
Driver, External string
DriverOpts map[string]string "driver_opts"
}
type MapOrArrayWrapper []string
type service struct {
ContainerName string "container_name"
Image string
Networks, Ports, Volumes, Command, Links []string
VolumesFrom []string "volumes_from"
DependsOn []string "depends_on"
CapAdd []string "cap_add"
Build struct{ Context, Dockerfile string }
Environment MapOrArrayWrapper
}
func (w *MapOrArrayWrapper) UnmarshalYAML(unmarshal func(interface{}) error) error {
var envsArray []string
var envsMap map[string]string
if err := unmarshal(&envsMap); err == nil {
for key, val := range envsMap {
envsArray = append(envsArray, key + "=" + val)
}
}
if len(envsArray) == 0 {
if err := unmarshal(&envsArray); err != nil {
return err
}
}
*w = envsArray
return nil
}
func nodify(s string) string {
return strings.Replace(s, "-", "_", -1)
}
func main() {
var (
bytes []byte
err error
graph *gographviz.Graph
project string
)
if len(os.Args) < 2 {
log.Fatal("Need input file!")
}
bytes, err = ioutil.ReadFile(os.Args[1])
if err != nil {
log.Fatal(err)
}
// Parse it as YML
data := &config{}
err = yaml.Unmarshal(bytes, &data)
if err != nil {
log.Fatal(err)
}
// Create directed graph
graph = gographviz.NewGraph()
graph.SetName(project)
graph.SetDir(true)
// Add legend
graph.AddSubGraph(project, "cluster_legend", map[string]string{"label": "Legend"})
graph.AddNode("cluster_legend", "legend_service",
map[string]string{"shape": "plaintext",
"label": "<<TABLE BORDER='0'>" +
"<TR><TD BGCOLOR='lightblue'><B>container_name</B></TD></TR>" +
"<TR><TD BGCOLOR='lightgrey'><FONT POINT-SIZE='9'>ports ext:int</FONT></TD></TR>" +
"<TR><TD BGCOLOR='orange'><FONT POINT-SIZE='9'>volumes host:container</FONT></TD></TR>" +
"<TR><TD BGCOLOR='pink'><FONT POINT-SIZE='9'>environment</FONT></TD></TR>" +
"</TABLE>>",
})
/** NETWORK NODES **/
for name := range data.Networks {
graph.AddNode(project, nodify(name), map[string]string{
"label": fmt.Sprintf("\"Network: %s\"", name),
"style": "filled",
"shape": "box",
"fillcolor": "palegreen",
})
}
/** SERVICE NODES **/
for name, service := range data.Services {
var attrs = map[string]string{"shape": "plaintext", "label": "<<TABLE BORDER='0'>"}
attrs["label"] += fmt.Sprintf("<TR><TD BGCOLOR='lightblue'><B>%s</B></TD></TR>", name)
if service.Ports != nil {
for _, port := range service.Ports {
attrs["label"] += fmt.Sprintf("<TR><TD BGCOLOR='lightgrey'><FONT POINT-SIZE='9'>%s</FONT></TD></TR>", port)
}
}
if service.Volumes != nil {
for _, vol := range service.Volumes {
attrs["label"] += fmt.Sprintf("<TR><TD BGCOLOR='orange'><FONT POINT-SIZE='9'>%s</FONT></TD></TR>", vol)
}
}
if service.Environment != nil {
for _, v := range service.Environment {
attrs["label"] += fmt.Sprintf("<TR><TD BGCOLOR='pink'><FONT POINT-SIZE='9'>%s</FONT></TD></TR>", v)
}
}
attrs["label"] += "</TABLE>>"
graph.AddNode(project, nodify(name), attrs)
}
/** EDGES **/
for name, service := range data.Services {
// Links to networks
if service.Networks != nil {
for _, linkTo := range service.Networks {
if strings.Contains(linkTo, ":") {
linkTo = strings.Split(linkTo, ":")[0]
}
graph.AddEdge(nodify(name), nodify(linkTo), true,
map[string]string{"dir": "none"})
}
}
// volumes_from
if service.VolumesFrom != nil {
for _, linkTo := range service.VolumesFrom {
graph.AddEdge(nodify(name), nodify(linkTo), true,
map[string]string{"style": "dashed", "label": "volumes_from"})
}
}
// depends_on
if service.DependsOn != nil {
for _, linkTo := range service.DependsOn {
graph.AddEdge(nodify(name), nodify(linkTo), true,
map[string]string{"style": "dashed", "label": "depends_on"})
}
}
// links
if service.Links != nil {
for _, linkTo := range service.Links {
if strings.Contains(linkTo, ":") {
linkTo = strings.Split(linkTo, ":")[0]
}
graph.AddEdge(nodify(name), nodify(linkTo), true,
map[string]string{"style": "dashed", "label": "links"})
}
}
}
fmt.Print(graph)
}