From 4aceff52e49fbb5ac59b9134e11b2c150bb3e3ef Mon Sep 17 00:00:00 2001 From: Alexei Shevchenko Date: Sat, 10 Feb 2024 04:13:36 +0300 Subject: [PATCH] csv format, dependencies update (#67) * csv format, dependencies update --- .github/workflows/ci.yml | 12 +- .github/workflows/release.yml | 4 +- README.md | 1 + cmd/decompose/main.go | 12 +- go.mod | 18 ++- go.sum | 28 ++-- internal/builder/builder.go | 4 + internal/builder/csv.go | 72 ++++++++++ internal/builder/csv_test.go | 124 ++++++++++++++++++ internal/builder/dot.go | 19 ++- internal/builder/dot_test.go | 4 +- internal/builder/sdsl_test.go | 3 +- .../{yaml.golden => compose-yaml.golden} | 0 internal/builder/testdata/csv.golden | 9 ++ .../{dot.golden => graphviz-dot.golden} | 0 .../{sdsl.golden => structurizr-dsl.golden} | 0 .../{tree.golden => text-tree.golden} | 0 internal/builder/tree_test.go | 4 +- internal/builder/yaml_test.go | 4 +- internal/client/defaults.go | 6 +- internal/client/docker.go | 7 +- internal/structurizr/workspace.go | 10 ++ 22 files changed, 278 insertions(+), 63 deletions(-) create mode 100644 internal/builder/csv.go create mode 100644 internal/builder/csv_test.go rename internal/builder/testdata/{yaml.golden => compose-yaml.golden} (100%) create mode 100644 internal/builder/testdata/csv.golden rename internal/builder/testdata/{dot.golden => graphviz-dot.golden} (100%) rename internal/builder/testdata/{sdsl.golden => structurizr-dsl.golden} (100%) rename internal/builder/testdata/{tree.golden => text-tree.golden} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36f6e77..0961598 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,9 +18,9 @@ jobs: - name: checkout uses: actions/checkout@v4 - name: setup golang - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: - go-version: ^1.21 + go-version: ^1.22 - name: golangci-lint uses: golangci/golangci-lint-action@v3 - name: goreleaser-check @@ -36,9 +36,9 @@ jobs: - name: checkout uses: actions/checkout@v4 - name: setup golang - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: - go-version: ^1.21 + go-version: ^1.22 - name: tests-only if: ${{ github.event_name == 'pull_request' }} run: make test @@ -61,9 +61,9 @@ jobs: - name: checkout uses: actions/checkout@v4 - name: setup golang - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: - go-version: ^1.21 + go-version: ^1.22 - name: init codeql uses: github/codeql-action/init@v2 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8dabb2a..c799865 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,9 +16,9 @@ jobs: - name: checkout uses: actions/checkout@v4 - name: set up golang - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: - go-version: ^1.21 + go-version: ^1.22 - name: build uses: goreleaser/goreleaser-action@v5 with: diff --git a/README.md b/README.md index fdb9180..bbe47b3 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Takes all network connections from your docker containers and exports them as: - pseudographical tree - json stream - statistics - nodes, connections and listen ports counts +- CSV with columns: `name`, `listen` and `outbounds` ## rationale diff --git a/cmd/decompose/main.go b/cmd/decompose/main.go index 8bf1fb4..fd05ebd 100644 --- a/cmd/decompose/main.go +++ b/cmd/decompose/main.go @@ -4,6 +4,7 @@ package main import ( "bufio" + "bytes" "errors" "flag" "fmt" @@ -122,7 +123,10 @@ func setupFlags() { } func write(name string, writer func(io.Writer) error) error { - var out io.Writer = os.Stdout + var ( + out io.Writer = os.Stdout + buf bytes.Buffer + ) if name != defaultOutput { fd, err := os.Create(name) @@ -135,10 +139,14 @@ func write(name string, writer func(io.Writer) error) error { out = fd } - if err := writer(out); err != nil { + if err := writer(&buf); err != nil { return fmt.Errorf("write '%s': %w", name, err) } + if _, err := buf.WriteTo(out); err != nil { + return fmt.Errorf("write: %w", err) + } + return nil } diff --git a/go.mod b/go.mod index fbb0605..aa75cee 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,9 @@ module github.com/s0rg/decompose -go 1.21.0 - -toolchain go1.21.6 +go 1.22 require ( - github.com/docker/docker v25.0.1+incompatible + github.com/docker/docker v25.0.3+incompatible github.com/emicklei/dot v1.6.1 github.com/expr-lang/expr v1.16.0 github.com/otterize/go-procnet v0.1.1 @@ -30,14 +28,14 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pkg/errors v0.9.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect - go.opentelemetry.io/otel v1.22.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 // indirect + go.opentelemetry.io/otel v1.23.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 // indirect - go.opentelemetry.io/otel/metric v1.22.0 // indirect + go.opentelemetry.io/otel/metric v1.23.1 // indirect go.opentelemetry.io/otel/sdk v1.22.0 // indirect - go.opentelemetry.io/otel/trace v1.22.0 // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/sys v0.16.0 // indirect + go.opentelemetry.io/otel/trace v1.23.1 // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.17.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index 122d4df..75cf8ad 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v25.0.1+incompatible h1:k5TYd5rIVQRSqcTwCID+cyVA0yRg86+Pcrz1ls0/frA= -github.com/docker/docker v25.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v25.0.3+incompatible h1:D5fy/lYmY7bvZa0XTZ5/UJPljor41F+vdyJG5luQLfQ= +github.com/docker/docker v25.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -77,20 +77,20 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= -go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= -go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 h1:doUP+ExOpH3spVTLS0FcWGLnQrPct/hD/bCPbDRUEAU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0/go.mod h1:rdENBZMT2OE6Ne/KLwpiXudnAsbdrdBaqBvTN8M8BgA= +go.opentelemetry.io/otel v1.23.1 h1:Za4UzOqJYS+MUczKI320AtqZHZb7EqxO00jAHE0jmQY= +go.opentelemetry.io/otel v1.23.1/go.mod h1:Td0134eafDLcTS4y+zQ26GE8u3dEuRBiBCTUIRHaikA= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 h1:9M3+rhx7kZCIQQhQRYaZCdNu1V73tm4TvXs2ntl98C4= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0/go.mod h1:noq80iT8rrHP1SfybmPiRGc9dc5M8RPmGvtwo7Oo7tc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= -go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= -go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= +go.opentelemetry.io/otel/metric v1.23.1 h1:PQJmqJ9u2QaJLBOELl1cxIdPcpbwzbkjfEyelTl2rlo= +go.opentelemetry.io/otel/metric v1.23.1/go.mod h1:mpG2QPlAfnK8yNhNJAxDZruU9Y1/HubbC+KyH8FaCWI= go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= -go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= +go.opentelemetry.io/otel/trace v1.23.1 h1:4LrmmEd8AU2rFvU1zegmvqW7+kWarxtNOPyeL6HmYY8= +go.opentelemetry.io/otel/trace v1.23.1/go.mod h1:4IpnpJFwr1mo/6HL8XIPJaE9y0+u1KcVmuW7dwFSVrI= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -98,8 +98,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -114,8 +114,8 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= diff --git a/internal/builder/builder.go b/internal/builder/builder.go index 398b8a4..74ebc23 100644 --- a/internal/builder/builder.go +++ b/internal/builder/builder.go @@ -5,6 +5,7 @@ import ( ) const ( + KindCSV = "csv" KindDOT = "dot" KindJSON = "json" KindTREE = "tree" @@ -15,6 +16,8 @@ const ( func Create(kind string) (b graph.NamedBuilderWriter, ok bool) { switch kind { + case KindCSV: + return NewCSV(), true case KindDOT: return NewDOT(), true case KindJSON: @@ -43,6 +46,7 @@ func SupportCluster(n string) (yes bool) { func Names() (rv []string) { return []string{ + KindCSV, KindDOT, KindJSON, KindTREE, diff --git a/internal/builder/csv.go b/internal/builder/csv.go new file mode 100644 index 0000000..cccd6b2 --- /dev/null +++ b/internal/builder/csv.go @@ -0,0 +1,72 @@ +package builder + +import ( + "encoding/csv" + "fmt" + "io" + "strings" + + "github.com/s0rg/decompose/internal/node" +) + +var csvHeader = []string{ + "service", "listen", "outbounds", +} + +type CSV struct { + j *JSON +} + +func NewCSV() *CSV { + return &CSV{ + j: NewJSON(), + } +} + +func (c *CSV) Name() string { + return "csv" +} + +func (c *CSV) AddNode(n *node.Node) error { + return c.j.AddNode(n) +} + +func (c *CSV) AddEdge(srcID, dstID string, port *node.Port) { + c.j.AddEdge(srcID, dstID, port) +} + +func (c *CSV) Write(w io.Writer) error { + cw := csv.NewWriter(w) + cw.UseCRLF = true + + _ = cw.Write(csvHeader) + + c.j.Sorted(func(n *node.JSON, _ bool) { + _ = cw.Write([]string{ + n.Name, + strings.Join(n.Listen, "\r\n"), + renderOutbounds(n.Connected), + }) + }) + + cw.Flush() + + if err := cw.Error(); err != nil { + return fmt.Errorf("fail: %w", err) + } + + return nil +} + +func renderOutbounds(conns map[string][]string) (rv string) { + var b strings.Builder + + for k, v := range conns { + b.WriteString(k) + b.WriteString(": ") + b.WriteString(strings.Join(v, "; ")) + b.WriteString("\r\n") + } + + return b.String() +} diff --git a/internal/builder/csv_test.go b/internal/builder/csv_test.go new file mode 100644 index 0000000..119eef4 --- /dev/null +++ b/internal/builder/csv_test.go @@ -0,0 +1,124 @@ +package builder_test + +import ( + "bytes" + "errors" + "testing" + + "github.com/s0rg/decompose/internal/builder" + "github.com/s0rg/decompose/internal/node" +) + +func TestCSVGolden(t *testing.T) { + t.Parallel() + + bld := builder.NewCSV() + + _ = bld.AddNode(&node.Node{ + ID: "node-1", + Name: "1", + Image: "node-image", + Ports: node.Ports{ + {Kind: "tcp", Value: 1}, + {Kind: "tcp", Value: 2}, + }, + Networks: []string{"test-net"}, + Meta: &node.Meta{ + Info: "info 1", + Tags: []string{"1"}, + }, + Process: &node.Process{ + Cmd: []string{"echo", "'test 1'"}, + Env: []string{"FOO=1"}, + }, + }) + _ = bld.AddNode(&node.Node{ + ID: "node-2", + Name: "2", + Ports: node.Ports{ + {Kind: "tcp", Value: 2}, + }, + Networks: []string{"test-net"}, + Meta: &node.Meta{ + Info: "info 2", + Tags: []string{"2"}, + }, + Process: &node.Process{ + Cmd: []string{"echo", "'test 2'"}, + Env: []string{"FOO=2"}, + }, + }) + _ = bld.AddNode(&node.Node{ + ID: "node-3", + Name: "3", + Ports: node.Ports{ + {Kind: "tcp", Value: 3}, + }, + Networks: []string{"test-net"}, + Meta: &node.Meta{ + Info: "info 3", + Tags: []string{"3"}, + }, + Process: &node.Process{ + Cmd: []string{"echo", "'test 3'"}, + Env: []string{"FOO=3"}, + }, + }) + + bld.AddEdge("node-2", "node-1", &node.Port{Kind: "tcp", Value: 1}) + bld.AddEdge("node-2", "node-1", &node.Port{Kind: "tcp", Value: 2}) + bld.AddEdge("node-2", "node-1", &node.Port{Kind: "tcp", Value: 3}) + + bld.AddEdge("node-2", "node-3", &node.Port{Kind: "tcp", Value: 3}) + + bld.AddEdge("node-1", "node-3", &node.Port{Kind: "tcp", Value: 3}) + bld.AddEdge("node-1", "node-2", &node.Port{Kind: "tcp", Value: 2}) + + bld.AddEdge("node-1", "3", &node.Port{Kind: "tcp", Value: 3}) + bld.AddEdge("3", "node-1", &node.Port{Kind: "tcp", Value: 3}) + + var buf bytes.Buffer + + bld.Write(&buf) + + got := buf.String() + want := golden(t, bld.Name(), got) + + if got != want { + t.Errorf("Want:\n%s\nGot:\n%s", want, got) + } +} + +func TestCSVWriteError(t *testing.T) { + t.Parallel() + + bldr := builder.NewCSV() + testErr := errors.New("test-error") + errW := &errWriter{Err: testErr} + + _ = bldr.AddNode(&node.Node{ + ID: "#", + Name: "#", + Image: "node-image", + Ports: node.Ports{ + {Kind: "tcp", Value: 1}, + {Kind: "tcp", Value: 2}, + }, + Networks: []string{"test-net"}, + Meta: &node.Meta{ + Info: "info 1", + Tags: []string{"1"}, + }, + Process: &node.Process{ + Cmd: []string{"echo", "'test 1'"}, + Env: []string{"FOO=1"}, + }, + Volumes: []*node.Volume{ + {Type: "volume", Src: "src", Dst: "dst"}, + }, + }) + + if err := bldr.Write(errW); !errors.Is(err, testErr) { + t.Log(err) + } +} diff --git a/internal/builder/dot.go b/internal/builder/dot.go index 84708dd..74dbf6e 100644 --- a/internal/builder/dot.go +++ b/internal/builder/dot.go @@ -1,7 +1,6 @@ package builder import ( - "fmt" "hash/fnv" "io" "strings" @@ -11,7 +10,10 @@ import ( "github.com/s0rg/decompose/internal/node" ) -const outPort = "out" +const ( + outPort = "out" + dotLF = "\n" +) // dark28 color scheme from https://www.graphviz.org/doc/info/colors.html var colors = []string{ @@ -51,24 +53,19 @@ func (d *DOT) AddNode(n *node.Node) error { if n.IsExternal() { color = "red" - label = fmt.Sprintf("external: %s", n.Name) + label = "external: " + n.Name } else { color = "black" - label = fmt.Sprintf( - "%s\nimage: %s\nnet: %s", - n.Name, - n.Image, - strings.Join(n.Networks, ", "), - ) + label = n.Name + dotLF + "image: " + n.Image + dotLF + "net: " + strings.Join(n.Networks, ", ") } if n.Meta != nil { if lines, ok := n.FormatMeta(); ok { - label += "\ninfo:\n" + strings.Join(lines, "\n") + label += dotLF + "info:" + dotLF + strings.Join(lines, dotLF) } if len(n.Meta.Tags) > 0 { - label += "\ntags: " + strings.Join(n.Meta.Tags, ",") + label += dotLF + "tags: " + strings.Join(n.Meta.Tags, ",") } } diff --git a/internal/builder/dot_test.go b/internal/builder/dot_test.go index 73276ad..62fa25f 100644 --- a/internal/builder/dot_test.go +++ b/internal/builder/dot_test.go @@ -69,8 +69,6 @@ func TestDOTGolden(t *testing.T) { }, }) - _ = bld.Name() - bld.AddEdge("2", "node-1", &node.Port{Kind: "tcp", Value: 1}) bld.AddEdge("2", "node-1", &node.Port{Kind: "tcp", Value: 2}) bld.AddEdge("2", "node-1", &node.Port{Kind: "tcp", Value: 3}) @@ -101,7 +99,7 @@ func TestDOTGolden(t *testing.T) { bld.Write(&buf) got := buf.String() - want := golden(t, "dot", got) + want := golden(t, bld.Name(), got) if got != want { t.Errorf("Want:\n%s\nGot:\n%s", want, got) diff --git a/internal/builder/sdsl_test.go b/internal/builder/sdsl_test.go index 95e454c..4fdb11b 100644 --- a/internal/builder/sdsl_test.go +++ b/internal/builder/sdsl_test.go @@ -70,7 +70,6 @@ func TestSDSLGolden(t *testing.T) { }) _ = bld.AddNode(&node.Node{ID: "ext2", Name: "ext2", Cluster: "c2"}) - _ = bld.Name() bld.AddEdge("ext2", "node-1", &node.Port{Kind: "tcp", Value: 1}) bld.AddEdge("ext2", "node-1", &node.Port{Kind: "tcp", Value: 2}) @@ -114,7 +113,7 @@ func TestSDSLGolden(t *testing.T) { bld.Write(&buf) got := buf.String() - want := golden(t, "sdsl", got) + want := golden(t, bld.Name(), got) if got != want { t.Errorf("Want:\n%s\nGot:\n%s", want, got) diff --git a/internal/builder/testdata/yaml.golden b/internal/builder/testdata/compose-yaml.golden similarity index 100% rename from internal/builder/testdata/yaml.golden rename to internal/builder/testdata/compose-yaml.golden diff --git a/internal/builder/testdata/csv.golden b/internal/builder/testdata/csv.golden new file mode 100644 index 0000000..dc302fb --- /dev/null +++ b/internal/builder/testdata/csv.golden @@ -0,0 +1,9 @@ +service,listen,outbounds +1,"1/tcp +2/tcp","3: 3/tcp +2: 2/tcp +" +2,2/tcp,"1: 1/tcp; 2/tcp; 3/tcp +3: 3/tcp +" +3,3/tcp, diff --git a/internal/builder/testdata/dot.golden b/internal/builder/testdata/graphviz-dot.golden similarity index 100% rename from internal/builder/testdata/dot.golden rename to internal/builder/testdata/graphviz-dot.golden diff --git a/internal/builder/testdata/sdsl.golden b/internal/builder/testdata/structurizr-dsl.golden similarity index 100% rename from internal/builder/testdata/sdsl.golden rename to internal/builder/testdata/structurizr-dsl.golden diff --git a/internal/builder/testdata/tree.golden b/internal/builder/testdata/text-tree.golden similarity index 100% rename from internal/builder/testdata/tree.golden rename to internal/builder/testdata/text-tree.golden diff --git a/internal/builder/tree_test.go b/internal/builder/tree_test.go index 9489d94..5906943 100644 --- a/internal/builder/tree_test.go +++ b/internal/builder/tree_test.go @@ -64,8 +64,6 @@ func TestTreeGolden(t *testing.T) { }, }) - _ = bld.Name() - bld.AddEdge("node-2", "node-1", &node.Port{Kind: "tcp", Value: 1}) bld.AddEdge("node-2", "node-1", &node.Port{Kind: "tcp", Value: 2}) bld.AddEdge("node-2", "node-1", &node.Port{Kind: "tcp", Value: 3}) @@ -83,7 +81,7 @@ func TestTreeGolden(t *testing.T) { bld.Write(&buf) got := buf.String() - want := golden(t, "tree", got) + want := golden(t, bld.Name(), got) if got != want { t.Errorf("Want:\n%s\nGot:\n%s", want, got) diff --git a/internal/builder/yaml_test.go b/internal/builder/yaml_test.go index cd346aa..598a82a 100644 --- a/internal/builder/yaml_test.go +++ b/internal/builder/yaml_test.go @@ -65,8 +65,6 @@ func TestYAMLGolden(t *testing.T) { }, }) - _ = bld.Name() - bld.AddEdge("2", "node-1", &node.Port{Kind: "tcp", Value: 1}) bld.AddEdge("2", "node-1", &node.Port{Kind: "tcp", Value: 2}) bld.AddEdge("2", "node-1", &node.Port{Kind: "tcp", Value: 3}) @@ -85,7 +83,7 @@ func TestYAMLGolden(t *testing.T) { bld.Write(&buf) got := buf.String() - want := golden(t, "yaml", got) + want := golden(t, bld.Name(), got) if got != want { t.Errorf("Want:\n%s\nGot:\n%s", want, got) diff --git a/internal/client/defaults.go b/internal/client/defaults.go index ee80f0d..43ccc38 100644 --- a/internal/client/defaults.go +++ b/internal/client/defaults.go @@ -5,7 +5,6 @@ package client import ( "context" "fmt" - "net" "os" "path/filepath" "strconv" @@ -30,10 +29,7 @@ const ( var procROOT = procDefault -type ( - connCB = func(localIP, remoteIP net.IP, localPort, remotePort uint16, kind string) - sockCB func(s procnet.SockTabEntry) -) +type sockCB func(procnet.SockTabEntry) func Default() (rv DockerClient, err error) { var dc *client.Client diff --git a/internal/client/docker.go b/internal/client/docker.go index 38985c3..ef8fb1b 100644 --- a/internal/client/docker.go +++ b/internal/client/docker.go @@ -25,8 +25,11 @@ const ( var ErrModeNone = errors.New("mode not set") -type createClient func() (DockerClient, error) -type nsEnter func(int, graph.NetProto, func(localIP, remoteIP net.IP, localPort, remotePort uint16, kind string)) error +type ( + createClient func() (DockerClient, error) + connCB = func(localIP, remoteIP net.IP, localPort, remotePort uint16, kind string) + nsEnter func(int, graph.NetProto, connCB) error +) type DockerClient interface { ContainerList(context.Context, container.ListOptions) ([]types.Container, error) diff --git a/internal/structurizr/workspace.go b/internal/structurizr/workspace.go index 34c466e..b54e33e 100644 --- a/internal/structurizr/workspace.go +++ b/internal/structurizr/workspace.go @@ -161,12 +161,14 @@ func (ws *Workspace) writeDefaultIncludes(w io.Writer, level int) { func (ws *Workspace) writeViews(w io.Writer, level int) { putHeader(w, level, headerViews) + level++ for _, key := range ws.systemsOrder { system := ws.systems[key] putView(w, level, blockSystemCtx, system.ID) + level++ putRaw(w, level, "include *") @@ -178,34 +180,42 @@ func (ws *Workspace) writeViews(w io.Writer, level int) { putRaw(w, level, "autoLayout") level-- + putEnd(w, level) // system context putView(w, level, blockContainer, system.ID) + level++ putRaw(w, level, "include *") putRaw(w, level, "autoLayout") level-- + putEnd(w, level) // container } fmt.Fprintln(w, "") putHeader(w, level, "styles") + level++ putRaw(w, level, `element "Element" {`) + level++ putRaw(w, level, "metadata true") putRaw(w, level, "description true") level-- + putEnd(w, level) // element level-- + putEnd(w, level) // styles level-- + putEnd(w, level) // views }