diff --git a/CHANGELOG.md b/CHANGELOG.md index fbd4183..dd92944 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.5.0] - 2020-06-15 +### Added +- new component _Block Storage_ (kind: `bst`) +- new component _Object Storage_ (kind: `ost`) +- new component _File Storage_ (kind: `fst`) +- new component _RDBMS_ (kind: `rdb`) +- new component _No SQL_ (kind: `doc`) +- new component _Caching_ (kind: `mem`) +- new commandline flag `--impl=[aws,gcp,azure]` to auto fill components implementations according to the specified provider + +### Changed +- autogenerated id prefix now is equal to the _kind_ value (see [./README.md](README.md)) **breaking change** + - modified YAML schema +- connection info (see [./README.md](README.md)) **breaking change** + - modified YAML schema +### Removed +- generic html component ## [0.4.0] - 2020-06-11 ### Added diff --git a/README.md b/README.md index 0203130..79504e2 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ type Component struct { ID string `yaml:"id,omitempty"` // optional - autogenerated if omitted (read more for details...) Kind string `yaml:"kind"` // required - see the table below Label string `yaml:"label,omitempty"` // optional - works only for: 'queue', 'service', 'storage', 'function', 'database', 'client' - Provider string `yaml:"provider,omitempty"` // optional - you can use this to specify the cloud provider + Outline string `yaml:"outline,omitempty"` // optional - you can use this to groups some components Impl string `yaml:"impl,omitempty"` // optional - you can use this to specify the implementation FillColor string `yaml:"fillColor,omitempty"` // optional - the hex code for the background color FontColor string `yaml:"fontColor,omitempty"` // optional - the hex code for the foreground color @@ -62,27 +62,38 @@ Eventually you can describe... Below is a list of all the components currently implemented. -| Component | Kind | YAML | Output | -|:----------------------|:------------|:--------------------------------------------------------------|:---------------------------------:| -| **Client** | `client` | πŸ‘‰ [examples/client.yml](./examples/client.yml) | ![](./examples/client.png) | -| **Microservice** | `service` | πŸ‘‰ [examples/service.yml](./examples/service.yml) | ![](./examples/service.png) | -| **Gateway** | `gateway` | πŸ‘‰ [examples/gateway.yml](./examples/gateway.yml) | ![](./examples/gateway.png) | -| **Firewall** | `waf` | πŸ‘‰ [examples/waf.yml](./examples/waf.yml) | ![](./examples/waf.png) | -| **Container Service** | `cos` | πŸ‘‰ [examples/waf.yml](./examples/cos.yml) | ![](./examples/cos.png) | -| **Message Broker** | `broker` | πŸ‘‰ [examples/broker.yml](./examples/broker.yml) | ![](./examples/broker.png) | -| **Queue Service** | `queue` | πŸ‘‰ [examples/queue.yml](./examples/queue.yml) | ![](./examples/queue.png) | -| **Object Storage** | `storage` | πŸ‘‰ [examples/storage.yml](./examples/storage.yml) | ![](./examples/storage.png) | -| **Function** | `function` | πŸ‘‰ [examples/function.yml](./examples/function.yml) | ![](./examples/function.png) | -| **Database** | `database` | πŸ‘‰ [examples/database.yml](./examples/database.yml) | ![](./examples/database.png) | -| **Load Balancer** | `balancer` | πŸ‘‰ [examples/balancer.yml](./examples/balancer.yml) | ![](./examples/balancer.png) | -| **CDN** | `cdn` | πŸ‘‰ [examples/cdn.yml](./examples/cdn.yml) | ![](./examples/cdn.png) | -| **DNS** | `dns` | πŸ‘‰ [examples/dns.yml](./examples/dns.yml) | ![](./examples/dns.png) | -| **Custom Html** | `html` | πŸ‘‰ [examples/custom_image.yml](./examples/custom_image.yml) | ![](./examples/custom_image.png) | - -For custom HTML components (_kind: html_) only these tags are supported: - -- ``, `
`, ``, `
`, ``, ` (in … only)` -- ``, ``, ``, ``, ``, ``, `` +| Component | Kind | YAML | Output | +|:---------------------|:------|:--------------------------------------------|:------------------------:| +| **Client** | `cli` | πŸ‘‰ [examples/cli.yml](./examples/cli.yml) | ![](./examples/cli.png) | +| **Microservice** | `ser` | πŸ‘‰ [examples/ser.yml](./examples/ser.yml) | ![](./examples/ser.png) | +| **API Gateway** | `gtw` | πŸ‘‰ [examples/gtw.yml](./examples/gtw.yml) | ![](./examples/gtw.png) | +| **Firewall** | `waf` | πŸ‘‰ [examples/waf.yml](./examples/waf.yml) | ![](./examples/waf.png) | +| **K8s Engine** | `kub` | πŸ‘‰ [examples/kub.yml](./examples/kub.yml) | ![](./examples/kub.png) | +| **Pub / Sub** | `msg` | πŸ‘‰ [examples/msg.yml](./examples/msg.yml) | ![](./examples/msg.png) | +| **Queue** | `que` | πŸ‘‰ [examples/que.yml](./examples/que.yml) | ![](./examples/que.png) | +| **Function** | `fun` | πŸ‘‰ [examples/fun.yml](./examples/fun.yml) | ![](./examples/fun.png) | +| **Relational DB** | `rdb` | πŸ‘‰ [examples/rdb.yml](./examples/rdb.yml) | ![](./examples/rdb.png) | +| **Document DB** | `doc` | πŸ‘‰ [examples/doc.yml](./examples/doc.yml) | ![](./examples/doc.png) | +| **Caching** | `mem` | πŸ‘‰ [examples/mem.yml](./examples/mem.yml) | ![](./examples/mem.png) | +| **Load Balancer** | `lba` | πŸ‘‰ [examples/lba.yml](./examples/lba.yml) | ![](./examples/lba.png) | +| **CDN** | `cdn` | πŸ‘‰ [examples/cdn.yml](./examples/cdn.yml) | ![](./examples/cdn.png) | +| **DNS** | `dns` | πŸ‘‰ [examples/dns.yml](./examples/dns.yml) | ![](./examples/dns.png) | +| **Block Store** | `bst` | πŸ‘‰ [examples/bst.yml](./examples/bst.yml) | ![](./examples/bst.png) | +| **Object Store** | `ost` | πŸ‘‰ [examples/ost.yml](./examples/ost.yml) | ![](./examples/ost.png) | +| **File Store** | `fst` | πŸ‘‰ [examples/fst.yml](./examples/fst.yml) | ![](./examples/fst.png) | + +## Auto filling the component implementation + +Leave the `impl` fields empty and run [draft](https://github.com/lucasepe/draft/releases/latest) with the `-impl` flag to let [draft](https://github.com/lucasepe/draft/releases/latest) found the implementation by provider. + +| example command | output | +|:------------------------------------------------------------------------------|:------------------------------:| +| draft -impl aws ./examples/dns.yml | dot -Tpng > test.png | ![](./examples/dns_aws.png) | +| draft -impl azure ./examples/dns.yml | dot -Tpng > test.png | ![](./examples/dns_azure.png) | +| draft -impl gcp ./examples/kub.yml | dot -Tpng > test.png | ![](./examples/kub_gcp.png) | +| draft -impl aws ./examples/kub.yml | dot -Tpng > test.png | ![](./examples/kub_aws.png) | + +... and so on for each kind of component! ### Notes about a component `id` @@ -94,23 +105,7 @@ For custom HTML components (_kind: html_) only these tags are supported: An auto-generated component `id` has a prefix and a sequential number - the prefix is related to the component `kind` - -| a kind of... | will generate an `id` prefix with... | example | -|:-------------|:-------------------------------------|:-----------------| -| `client` | cl | _cl1, cl2,..._ | -| `service` | ms | _ms1, ms2,..._ | -| `gateway` | gt | _gt1, gt2,..._ | -| `gateway` | waf | _waf1, waf2,..._ | -| `broker` | br | _br1, br2,..._ | -| `queue` | qs | _qs1, qs2,..._ | -| `storage` | st | _st1, st2,..._ | -| `function` | fn | _fn1, fn2,..._ | -| `database` | db | _db1, db2,..._ | -| `balancer` | lb | _lb1, lb2,..._ | -| `cdn` | cn | _cn1, cn2,..._ | -| `dns` | dn | _dn1, dn2,..._ | -| `html` | htm | _htm1, htm2,..._ | -| `cos` | cos | _cos1, cos2,..._ | + - examples _waf1, ..., wafN_ or _ser1, ..., serN_ etc. ## Connections @@ -122,11 +117,9 @@ A `connection` has the following properties: ```go type Connection struct { - Origin struct { - ComponentID string `yaml:"componentId"` - } `yaml:"origin"` + Origin string `yaml:"origin"` Targets []struct { - ComponentID string `yaml:"componentId"` + ID string `yaml:"id"` Label string `yaml:"label,omitempty"` Color string `yaml:"color,omitempty"` Dashed bool `yaml:"dashed,omitempty"` diff --git a/broker.go b/broker.go deleted file mode 100644 index 1141d3c..0000000 --- a/broker.go +++ /dev/null @@ -1,50 +0,0 @@ -package draft - -import ( - "fmt" - "strings" - - "github.com/emicklei/dot" - "github.com/lucasepe/draft/pkg/cluster" - "github.com/lucasepe/draft/pkg/node" -) - -type broker struct { - seq int16 -} - -func (rcv *broker) nextID() string { - rcv.seq++ - return fmt.Sprintf("br%d", rcv.seq) -} - -func (rcv *broker) sketch(graph *dot.Graph, comp Component) { - id := comp.ID - if strings.TrimSpace(comp.ID) == "" { - id = rcv.nextID() - } - - cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) - - el := node.New(cl, id, - node.Label("Message Broker", false), - node.Rounded(comp.Rounded), - node.FontSize(7), - node.FontColor(comp.FontColor, "#000000ff"), - node.FillColor(comp.FillColor, "#e0eeeeff"), - node.Shape("cds"), - ) - el.Attr("width", "1.4") -} - -/** Alternative - -label=
- - - - -
 topic 1 
 topic 2 
 ... 
 topic N 
> -shape="plain" - -**/ diff --git a/broker_test.go b/broker_test.go deleted file mode 100644 index 5588ad4..0000000 --- a/broker_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package draft - -import ( - "testing" - - "github.com/emicklei/dot" -) - -func TestBrokerComponentNextID(t *testing.T) { - tests := []struct { - want string - }{ - {"br1"}, - {"br2"}, - {"br3"}, - {"br4"}, - } - - s := broker{} - - for _, tt := range tests { - t.Run(tt.want, func(t *testing.T) { - if got := s.nextID(); got != tt.want { - t.Errorf("got [%v] want [%v]", got, tt.want) - } - }) - } -} - -func TestBrokerComponent(t *testing.T) { - want := `label="Message Broker",shape="cds",style="filled"` - g := dot.NewGraph(dot.Directed) - - sketcher := broker{} - sketcher.sketch(g, Component{}) - - if got := flatten(g.String()); !verify(got, want) { - t.Errorf("got [%v] want [%v]", got, want) - } -} diff --git a/bst.go b/bst.go new file mode 100644 index 0000000..64fd4ac --- /dev/null +++ b/bst.go @@ -0,0 +1,55 @@ +package draft + +import ( + "fmt" + "strings" + + "github.com/emicklei/dot" + "github.com/lucasepe/draft/pkg/cluster" + "github.com/lucasepe/draft/pkg/node" +) + +type bst struct { + seq int16 +} + +func (rcv *bst) nextID() string { + rcv.seq++ + return fmt.Sprintf("bst%d", rcv.seq) +} + +func (rcv *bst) sketch(graph *dot.Graph, comp Component) { + id := comp.ID + if strings.TrimSpace(comp.ID) == "" { + id = rcv.nextID() + } + + fillColor := comp.FillColor + if strings.TrimSpace(comp.FillColor) == "" { + fillColor = "#606f5cff" + } + + label := strings.Replace(` + + + + + + + + +
`, "{{BGCOLOR}}", fillColor, -1) + + cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) + + node.New(cl, id, + node.Label(label, true), + node.FontColor("#000000ff"), + node.FontSize(7), + node.FillColor("transparent"), + // ^^^ hack to set a transparent background + // color since we will use the HTML table. + node.Shape("plain"), + ) +} diff --git a/balancer_test.go b/bst_test.go similarity index 50% rename from balancer_test.go rename to bst_test.go index b2e01f2..d1d33df 100644 --- a/balancer_test.go +++ b/bst_test.go @@ -6,17 +6,17 @@ import ( "github.com/emicklei/dot" ) -func TestLoadBalancerComponentNextID(t *testing.T) { +func TestBlockStorageNextID(t *testing.T) { tests := []struct { want string }{ - {"lb1"}, - {"lb2"}, - {"lb3"}, - {"lb4"}, + {"bst1"}, + {"bst2"}, + {"bst3"}, + {"bst4"}, } - s := balancer{} + s := bst{} for _, tt := range tests { t.Run(tt.want, func(t *testing.T) { @@ -27,11 +27,11 @@ func TestLoadBalancerComponentNextID(t *testing.T) { } } -func TestLoadBalancerComponent(t *testing.T) { - want := `label="LB",shape="Mdiamond",style="filled"` +func TestBlockStorageShape(t *testing.T) { + want := `label=<
>` g := dot.NewGraph(dot.Directed) - sketcher := balancer{} + sketcher := bst{} sketcher.sketch(g, Component{}) if got := flatten(g.String()); !verify(got, want) { diff --git a/cdn.go b/cdn.go index cc2ef49..b3536cc 100644 --- a/cdn.go +++ b/cdn.go @@ -15,7 +15,7 @@ type cdn struct { func (rcv *cdn) nextID() string { rcv.seq++ - return fmt.Sprintf("cn%d", rcv.seq) + return fmt.Sprintf("cdn%d", rcv.seq) } func (rcv *cdn) sketch(graph *dot.Graph, comp Component) { @@ -25,12 +25,14 @@ func (rcv *cdn) sketch(graph *dot.Graph, comp Component) { } cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) el := node.New(cl, id, - node.Label("CDN", false), - node.FontColor(comp.FontColor, "#000000ff"), - node.FillColor(comp.FillColor, "#47df9aff"), + node.Label("CDN", true), + node.FontColor("#000000ff"), + node.FillColor("#47df9aff"), node.Shape("Mcircle"), ) el.Attr("height", "0.5") + el.Attr("color", "#f5f5f5ff") } diff --git a/cdn_test.go b/cdn_test.go index 7ee67bd..e9b3be6 100644 --- a/cdn_test.go +++ b/cdn_test.go @@ -6,14 +6,14 @@ import ( "github.com/emicklei/dot" ) -func TestCDNComponentNextID(t *testing.T) { +func TestCDNCNextID(t *testing.T) { tests := []struct { want string }{ - {"cn1"}, - {"cn2"}, - {"cn3"}, - {"cn4"}, + {"cdn1"}, + {"cdn2"}, + {"cdn3"}, + {"cdn4"}, } s := cdn{} @@ -27,8 +27,8 @@ func TestCDNComponentNextID(t *testing.T) { } } -func TestCDNComponent(t *testing.T) { - want := `label="CDN",shape="Mcircle",style="filled"` +func TestCDNShape(t *testing.T) { + want := `shape="Mcircle",style="filled"` g := dot.NewGraph(dot.Directed) sketcher := cdn{} diff --git a/client.go b/cli.go similarity index 59% rename from client.go rename to cli.go index 680c1f8..a601963 100644 --- a/client.go +++ b/cli.go @@ -9,30 +9,35 @@ import ( "github.com/lucasepe/draft/pkg/node" ) -type client struct { +type cli struct { seq int16 } -func (rcv *client) nextID() string { +func (rcv *cli) nextID() string { rcv.seq++ - return fmt.Sprintf("cl%d", rcv.seq) + return fmt.Sprintf("cli%d", rcv.seq) } -func (rcv *client) sketch(graph *dot.Graph, comp Component) { +func (rcv *cli) sketch(graph *dot.Graph, comp Component) { id := comp.ID if strings.TrimSpace(comp.ID) == "" { id = rcv.nextID() } + fontColor := "#000000ff" + if fc := strings.TrimSpace(comp.FontColor); len(fc) > 0 { + fontColor = fc + } + cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) el := node.New(cl, id, node.Label(comp.Label, false), node.Rounded(comp.Rounded), - node.FontColor(comp.FontColor, "#000000ff"), - node.FillColor(comp.FillColor, "#90ee90ff"), + node.FontColor(fontColor), + node.FillColor("transparent"), node.Shape("underline"), ) el.Attr("fontsize", "8") - el.Attr("height", "0.3") + el.Attr("height", "0.4") } diff --git a/client_test.go b/cli_test.go similarity index 87% rename from client_test.go rename to cli_test.go index 4bd8c8c..adf70ac 100644 --- a/client_test.go +++ b/cli_test.go @@ -10,13 +10,13 @@ func TestClientComponentNextID(t *testing.T) { tests := []struct { want string }{ - {"cl1"}, - {"cl2"}, - {"cl3"}, - {"cl4"}, + {"cli1"}, + {"cli2"}, + {"cli3"}, + {"cli4"}, } - s := client{} + s := cli{} for _, tt := range tests { t.Run(tt.want, func(t *testing.T) { @@ -31,7 +31,7 @@ func TestClientComponent(t *testing.T) { want := `shape="underline",style="filled"` g := dot.NewGraph(dot.Directed) - sketcher := client{} + sketcher := cli{} sketcher.sketch(g, Component{}) if got := flatten(g.String()); !verify(got, want) { diff --git a/cmd/draft-all.sh b/cmd/draft-all.sh index 0a88d59..149e683 100755 --- a/cmd/draft-all.sh +++ b/cmd/draft-all.sh @@ -5,20 +5,23 @@ DPI=120 EXE=./dist/draft_linux_amd64/draft ## declare an array of files -declare -a arr=("$SRC_DIR/client.yml" - "$SRC_DIR/service.yml" - "$SRC_DIR/broker.yml" - "$SRC_DIR/gateway.yml" - "$SRC_DIR/queue.yml" - "$SRC_DIR/function.yml" - "$SRC_DIR/database.yml" - "$SRC_DIR/storage.yml" - "$SRC_DIR/balancer.yml" +declare -a arr=("$SRC_DIR/cli.yml" + "$SRC_DIR/ser.yml" + "$SRC_DIR/msg.yml" + "$SRC_DIR/gtw.yml" + "$SRC_DIR/que.yml" + "$SRC_DIR/fun.yml" + "$SRC_DIR/rdb.yml" + "$SRC_DIR/doc.yml" + "$SRC_DIR/bst.yml" + "$SRC_DIR/ost.yml" + "$SRC_DIR/fst.yml" + "$SRC_DIR/lba.yml" "$SRC_DIR/cdn.yml" "$SRC_DIR/dns.yml" "$SRC_DIR/waf.yml" - "$SRC_DIR/cos.yml" - "$SRC_DIR/custom_image.yml" + "$SRC_DIR/kub.yml" + "$SRC_DIR/mem.yml" "$SRC_DIR/system-view.yml" "$SRC_DIR/message-bus-pattern.yml" "$SRC_DIR/aws-cognito-custom-auth-flow.yml" @@ -32,4 +35,9 @@ do filename=$(basename -- "$i") # run draft...run! "$EXE" "$i" | dot -Tpng -Gdpi=$DPI > "$SRC_DIR/${filename%.*}.png" + + "$EXE" -impl aws "$i" | dot -Tpng -Gdpi=$DPI > "$SRC_DIR/${filename%.*}_aws.png" + "$EXE" -impl gcp "$i" | dot -Tpng -Gdpi=$DPI > "$SRC_DIR/${filename%.*}_gcp.png" + "$EXE" -impl azure "$i" | dot -Tpng -Gdpi=$DPI > "$SRC_DIR/${filename%.*}_azure.png" + done \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go index a509a5a..05d3ee7 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -21,7 +21,7 @@ ______ __ _ | | | | _ __ __ _ | |_ | |_ | | | || '__| / _' || _|| __| https://github.com/lucasepe/draft | |/ / | | | (_| || | | |_ -|___/ |_| \__,_||_| \__| {{VERSION}}` +|___/ |_| \__,_||_| \__| v{{VERSION}}` ) var ( @@ -31,6 +31,7 @@ var ( flagBottomTop bool flagOrtho bool + flagImpl string ) func main() { @@ -42,29 +43,30 @@ func main() { } fn, err := filepath.Abs(flag.Args()[0]) - handleErr(err) + handleErr(err, fn) file, err := os.Open(fn) - handleErr(err) + handleErr(err, fn) defer file.Close() ark, err := draft.NewDraft(file) - handleErr(err) + handleErr(err, fn) ark.BottomTop(flagBottomTop) ark.Ortho(flagOrtho) + ark.Provider(flagImpl) str, err := ark.Sketch() - handleErr(err) + handleErr(err, fn) fmt.Println(str) } // handleErr check for an error and eventually exit -func handleErr(err error) { +func handleErr(err error, src string) { if err != nil { - fmt.Fprintf(os.Stderr, "error: %s\n", err.Error()) + fmt.Fprintf(os.Stderr, "error: %s @ %s\n", err.Error(), src) os.Exit(1) } } @@ -95,6 +97,7 @@ func configureFlags() { flag.CommandLine.BoolVar(&flagBottomTop, "bottom-top", false, "if true sets layout dir as bottom top") flag.CommandLine.BoolVar(&flagOrtho, "ortho", false, "if true edges are drawn as line segments") + flag.CommandLine.StringVar(&flagImpl, "impl", "", "auto fill the specific provider services (aws, gcp or azure)") flag.CommandLine.Parse(os.Args[1:]) } diff --git a/dns.go b/dns.go index 5806768..1156d67 100644 --- a/dns.go +++ b/dns.go @@ -26,12 +26,14 @@ func (rcv *dns) sketch(graph *dot.Graph, comp Component) { } cl := cluster.New(graph, id, cluster.BottomTop(rcv.bottomTop), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) el := node.New(cl, id, - node.Label("DNS", false), - node.FontColor(comp.FontColor, "#000000ff"), - node.FillColor(comp.FillColor, "#854eadff"), + node.Label("DNS", true), + node.FontColor("#f5f5f5ff"), + node.FillColor("#854eadff"), node.Shape("Msquare"), ) el.Attr("height", "0.3") + el.Attr("color", "#f5f5f5ff") } diff --git a/dns_test.go b/dns_test.go index cd9a66e..402dbb3 100644 --- a/dns_test.go +++ b/dns_test.go @@ -28,7 +28,7 @@ func TestDNSComponentNextID(t *testing.T) { } func TestDNSComponent(t *testing.T) { - want := `label="DNS",shape="Msquare",style="filled"` + want := `label=<DNS>,shape="Msquare",style="filled"` g := dot.NewGraph(dot.Directed) sketcher := dns{} diff --git a/database.go b/doc.go similarity index 60% rename from database.go rename to doc.go index 54bda08..ed7855a 100644 --- a/database.go +++ b/doc.go @@ -9,30 +9,30 @@ import ( "github.com/lucasepe/draft/pkg/node" ) -type database struct { +type doc struct { seq int16 } -func (rcv *database) nextID() string { +func (rcv *doc) nextID() string { rcv.seq++ - return fmt.Sprintf("db%d", rcv.seq) + return fmt.Sprintf("doc%d", rcv.seq) } -func (rcv *database) sketch(graph *dot.Graph, comp Component) { +func (rcv *doc) sketch(graph *dot.Graph, comp Component) { id := comp.ID if strings.TrimSpace(comp.ID) == "" { id = rcv.nextID() } cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) el := node.New(cl, id, node.Label(comp.Label, false), node.Rounded(comp.Rounded), - node.FontColor(comp.FontColor, "#000000ff"), - node.FillColor(comp.FillColor, "#f5f5dcff"), - node.Shape("cylinder"), + node.FontColor("#000000ff"), + node.FillColor("#d1c8d4ff"), + node.Shape("note"), ) el.Attr("height", "0.5") - el.Attr("fontsize", "6") } diff --git a/container_service_test.go b/doc_test.go similarity index 66% rename from container_service_test.go rename to doc_test.go index e95abd0..40b2e01 100644 --- a/container_service_test.go +++ b/doc_test.go @@ -6,17 +6,17 @@ import ( "github.com/emicklei/dot" ) -func TestCSComponentNextID(t *testing.T) { +func TestNoSQLNextID(t *testing.T) { tests := []struct { want string }{ - {"cos1"}, - {"cos2"}, - {"cos3"}, - {"cos4"}, + {"doc1"}, + {"doc2"}, + {"doc3"}, + {"doc4"}, } - s := containerService{} + s := doc{} for _, tt := range tests { t.Run(tt.want, func(t *testing.T) { @@ -27,11 +27,11 @@ func TestCSComponentNextID(t *testing.T) { } } -func TestCSComponent(t *testing.T) { - want := `shape="component",style="filled"` +func TestNoSQLShape(t *testing.T) { + want := `shape="note",style="filled"` g := dot.NewGraph(dot.Directed) - sketcher := containerService{} + sketcher := doc{} sketcher.sketch(g, Component{}) if got := flatten(g.String()); !verify(got, want) { diff --git a/draft.go b/draft.go index f9a6666..857326c 100644 --- a/draft.go +++ b/draft.go @@ -13,34 +13,36 @@ import ( ) const ( - kindHTML = "html" - kindClient = "client" - kindGateway = "gateway" - kindService = "service" - kindQueue = "queue" - kindBroker = "broker" - kindStorage = "storage" - kindDatabase = "database" - kindFunction = "function" - kindBalancer = "balancer" - kindCDN = "cdn" - kindDNS = "dns" - kindFirewall = "waf" - kindContainerService = "cos" + kindHTML = "html" + kindClient = "cli" + kindGateway = "gtw" + kindService = "ser" + kindQueue = "que" + kindPubSub = "msg" + kindObjectStore = "ost" + kindRDB = "rdb" + kindNoSQL = "doc" + kindFunction = "fun" + kindLBA = "lba" + kindCDN = "cdn" + kindDNS = "dns" + kindFirewall = "waf" + kindContainersManager = "kub" + kindBlockStore = "bst" + kindCache = "mem" + kindFileStore = "fst" ) // Connection is a link between two components. type Connection struct { - Origin struct { - ComponentID string `yaml:"componentId"` - } `yaml:"origin"` + Origin string `yaml:"origin"` Targets []struct { - ComponentID string `yaml:"componentId"` - Label string `yaml:"label,omitempty"` - Color string `yaml:"color,omitempty"` - Dashed bool `yaml:"dashed,omitempty"` - Dir string `yaml:"dir,omitempty"` - Highlight bool `yaml:"highlight,omitempty"` + ID string `yaml:"id"` + Label string `yaml:"label,omitempty"` + Color string `yaml:"color,omitempty"` + Dashed bool `yaml:"dashed,omitempty"` + Dir string `yaml:"dir,omitempty"` + Highlight bool `yaml:"highlight,omitempty"` } `yaml:"targets"` } @@ -50,12 +52,13 @@ type Component struct { Kind string `yaml:"kind"` Label string `yaml:"label,omitempty"` Impl string `yaml:"impl,omitempty"` - Provider string `yaml:"provider,omitempty"` + Outline string `yaml:"outline,omitempty"` FillColor string `yaml:"fillColor,omitempty"` FontColor string `yaml:"fontColor,omitempty"` Rounded bool `yaml:"rounded,omitempty"` bottomTop bool + provider string } // Draft represents a whole diagram. @@ -75,6 +78,7 @@ type Draft struct { bottomTop bool ortho bool + provider string } // BottomTop return true if this component @@ -89,20 +93,24 @@ func NewDraft(r io.Reader) (*Draft, error) { sketchers: map[string]interface { sketch(*dot.Graph, Component) }{ - kindHTML: &html{}, - kindClient: &client{}, - kindGateway: &gateway{}, - kindService: &service{}, - kindBroker: &broker{}, - kindQueue: &queue{}, - kindFunction: &function{}, - kindStorage: &storage{}, - kindDatabase: &database{}, - kindBalancer: &balancer{}, - kindCDN: &cdn{}, - kindDNS: &dns{}, - kindFirewall: &waf{}, - kindContainerService: &containerService{}, + kindHTML: &html{}, + kindClient: &cli{}, + kindGateway: >w{}, + kindService: &ser{}, + kindPubSub: &msg{}, + kindQueue: &que{}, + kindFunction: &fun{}, + kindRDB: &rdb{}, + kindLBA: &lba{}, + kindBlockStore: &bst{}, + kindCDN: &cdn{}, + kindDNS: &dns{}, + kindFirewall: &waf{}, + kindContainersManager: &kub{}, + kindCache: &mem{}, + kindNoSQL: &doc{}, + kindObjectStore: &ost{}, + kindFileStore: &fst{}, }, } @@ -127,6 +135,11 @@ func (ark *Draft) Ortho(val bool) { ark.ortho = val } +// Provider sets the Cloud Provider name (one of: aws, gcp, azure). +func (ark *Draft) Provider(name string) { + ark.provider = name +} + // Sketch generates the GraphViz definition for this architecture diagram. func (ark *Draft) Sketch() (string, error) { g := graph.New(graph.BackgroundColor(ark.BackgroundColor), @@ -150,6 +163,7 @@ func (ark *Draft) Sketch() (string, error) { func sketchComponents(graph *dot.Graph, draft *Draft) error { for _, el := range draft.Components { el.bottomTop = draft.bottomTop + el.provider = draft.provider sketcher, ok := draft.sketchers[el.Kind] if !ok { @@ -157,8 +171,8 @@ func sketchComponents(graph *dot.Graph, draft *Draft) error { } parent := graph - if strings.TrimSpace(el.Provider) != "" { - parent = cluster.New(graph, el.Provider, + if strings.TrimSpace(el.Outline) != "" { + parent = cluster.New(graph, el.Outline, cluster.PenColor("#d9cc31"), cluster.FontName("Fira Mono"), cluster.FontSize(10), @@ -173,10 +187,9 @@ func sketchComponents(graph *dot.Graph, draft *Draft) error { func sketchConnections(graph *dot.Graph, draft *Draft) error { for _, el := range draft.Connections { - var from = el.Origin.ComponentID for _, x := range el.Targets { - err := edge.New(graph, from, x.ComponentID, + err := edge.New(graph, el.Origin, x.ID, edge.Label(x.Label), edge.Dir(x.Dir), edge.Color(x.Color), diff --git a/examples/amazon-appsync.png b/examples/amazon-appsync.png deleted file mode 100644 index c3ab7a6..0000000 Binary files a/examples/amazon-appsync.png and /dev/null differ diff --git a/examples/aws-cognito-custom-auth-flow.png b/examples/aws-cognito-custom-auth-flow.png index 3e5310b..0036e7e 100644 Binary files a/examples/aws-cognito-custom-auth-flow.png and b/examples/aws-cognito-custom-auth-flow.png differ diff --git a/examples/aws-cognito-custom-auth-flow.yml b/examples/aws-cognito-custom-auth-flow.yml index 3420d58..6e3107e 100644 --- a/examples/aws-cognito-custom-auth-flow.yml +++ b/examples/aws-cognito-custom-auth-flow.yml @@ -2,68 +2,62 @@ title: Amazon Cognito Custom Authentication Flow with external database backgroundColor: '#ffffff' components: - - kind: client + kind: cli label: "Web App" - provider: Internet impl: SPA - - kind: client + kind: cli label: "Mobile App" - provider: Internet impl: "Android & iOS" - - kind: service + kind: ser label: "OAuth 2.0\nAuth Service" provider: AWS impl: "Cognito" fillColor: '#991919' fontColor: '#fafafa' - - kind: function + kind: fun label: "Define\nAuthChallange" provider: AWS impl: Lambda - - kind: function + kind: fun label: "Create\nAuthChallange" provider: AWS impl: Lambda - - kind: function + kind: fun label: "Verify\nAuthChallange" provider: AWS impl: Lambda - - kind: database + kind: rdb label: "Users\nRepository" provider: AWS impl: RDS connections: - - origin: - componentId: cl1 + origin: cli1 targets: - - componentId: ms1 + id: ser1 - - origin: - componentId: cl2 + origin: cli2 targets: - - componentId: ms1 + id: ser1 - - origin: - componentId: ms1 + origin: ser1 targets: - - componentId: fn1 + id: fun1 - - componentId: fn2 + id: fun2 - - componentId: fn3 + id: fun3 - - origin: - componentId: fn2 + origin: fun2 targets: - - componentId: db1 \ No newline at end of file + id: rdb1 \ No newline at end of file diff --git a/examples/aws-cognito-custom-auth-flow_aws.png b/examples/aws-cognito-custom-auth-flow_aws.png new file mode 100644 index 0000000..0036e7e Binary files /dev/null and b/examples/aws-cognito-custom-auth-flow_aws.png differ diff --git a/examples/aws-cognito-custom-auth-flow_azure.png b/examples/aws-cognito-custom-auth-flow_azure.png new file mode 100644 index 0000000..0036e7e Binary files /dev/null and b/examples/aws-cognito-custom-auth-flow_azure.png differ diff --git a/examples/aws-cognito-custom-auth-flow_gcp.png b/examples/aws-cognito-custom-auth-flow_gcp.png new file mode 100644 index 0000000..0036e7e Binary files /dev/null and b/examples/aws-cognito-custom-auth-flow_gcp.png differ diff --git a/examples/backend-for-frontend.png b/examples/backend-for-frontend.png index 31da7d2..31401d2 100644 Binary files a/examples/backend-for-frontend.png and b/examples/backend-for-frontend.png differ diff --git a/examples/backend-for-frontend.yml b/examples/backend-for-frontend.yml index c6cb0ab..565efe2 100644 --- a/examples/backend-for-frontend.yml +++ b/examples/backend-for-frontend.yml @@ -2,82 +2,76 @@ title: Backend For Frontend (BFF) backgroundColor: '#ffffff' components: - - kind: client + kind: cli label: Web App - fillColor: '#ee82ee' - - kind: client + kind: cli label: Mobile App - fillColor: '#708090' - - kind: gateway + kind: gtw impl: | Web BFF API Gateway - - kind: gateway + kind: gtw impl: | Mobile BFF API Gateway - - kind: service + kind: ser label: ΞΌService A fillColor: '#b0e0e6' - - kind: service + kind: ser label: ΞΌService B - - kind: service + kind: ser label: ΞΌService C fillColor: '#00ff7f' - - kind: service + kind: ser label: ΞΌService D fillColor: '#00007f' fontColor: '#fafafa' connections: - - origin: - componentId: cl1 + origin: cli1 targets: - - componentId: gt1 + id: gtw1 color: '#ee82ee' - - origin: - componentId: cl2 + origin: cli2 targets: - - componentId: gt2 + id: gtw2 - - origin: - componentId: gt1 + origin: gtw1 targets: - - componentId: ms1 + id: ser1 color: '#ee82ee' - - componentId: ms2 + id: ser2 color: '#ee82ee' - - componentId: ms3 + id: ser3 color: '#ee82ee' - - componentId: ms4 + id: ser4 color: '#ee82ee' - - origin: - componentId: gt2 + origin: gtw2 targets: - - componentId: ms1 + id: ser1 highlight: true - - componentId: ms2 + id: ser2 highlight: true - - componentId: ms3 + id: ser3 highlight: true - - componentId: ms4 + id: ser4 highlight: true \ No newline at end of file diff --git a/examples/backend-for-frontend_aws.png b/examples/backend-for-frontend_aws.png new file mode 100644 index 0000000..31401d2 Binary files /dev/null and b/examples/backend-for-frontend_aws.png differ diff --git a/examples/backend-for-frontend_azure.png b/examples/backend-for-frontend_azure.png new file mode 100644 index 0000000..31401d2 Binary files /dev/null and b/examples/backend-for-frontend_azure.png differ diff --git a/examples/backend-for-frontend_gcp.png b/examples/backend-for-frontend_gcp.png new file mode 100644 index 0000000..31401d2 Binary files /dev/null and b/examples/backend-for-frontend_gcp.png differ diff --git a/examples/balancer.png b/examples/balancer.png deleted file mode 100644 index f2601eb..0000000 Binary files a/examples/balancer.png and /dev/null differ diff --git a/examples/broker.png b/examples/broker.png deleted file mode 100644 index 66efc2e..0000000 Binary files a/examples/broker.png and /dev/null differ diff --git a/examples/bst.png b/examples/bst.png new file mode 100644 index 0000000..48c3c77 Binary files /dev/null and b/examples/bst.png differ diff --git a/examples/cos.yml b/examples/bst.yml similarity index 63% rename from examples/cos.yml rename to examples/bst.yml index 9177e72..860f13a 100644 --- a/examples/cos.yml +++ b/examples/bst.yml @@ -1,4 +1,4 @@ --- components: - - kind: cos \ No newline at end of file + kind: bst \ No newline at end of file diff --git a/examples/bst_aws.png b/examples/bst_aws.png new file mode 100644 index 0000000..0cbf790 Binary files /dev/null and b/examples/bst_aws.png differ diff --git a/examples/bst_azure.png b/examples/bst_azure.png new file mode 100644 index 0000000..43920b6 Binary files /dev/null and b/examples/bst_azure.png differ diff --git a/examples/bst_gcp.png b/examples/bst_gcp.png new file mode 100644 index 0000000..2d0428f Binary files /dev/null and b/examples/bst_gcp.png differ diff --git a/examples/cdn.png b/examples/cdn.png index 0bffc4a..7a05a77 100644 Binary files a/examples/cdn.png and b/examples/cdn.png differ diff --git a/examples/cdn_aws.png b/examples/cdn_aws.png new file mode 100644 index 0000000..3131326 Binary files /dev/null and b/examples/cdn_aws.png differ diff --git a/examples/cdn_azure.png b/examples/cdn_azure.png new file mode 100644 index 0000000..6074ea2 Binary files /dev/null and b/examples/cdn_azure.png differ diff --git a/examples/cdn_gcp.png b/examples/cdn_gcp.png new file mode 100644 index 0000000..2cef52e Binary files /dev/null and b/examples/cdn_gcp.png differ diff --git a/examples/cl.jpg b/examples/cl.jpg deleted file mode 100644 index 9859aeb..0000000 Binary files a/examples/cl.jpg and /dev/null differ diff --git a/examples/cli.png b/examples/cli.png new file mode 100644 index 0000000..5b304e1 Binary files /dev/null and b/examples/cli.png differ diff --git a/examples/cli.yml b/examples/cli.yml new file mode 100644 index 0000000..df5363f --- /dev/null +++ b/examples/cli.yml @@ -0,0 +1,6 @@ +--- +components: + - + kind: cli + label: Web App + fontColor: '#8b33ac' diff --git a/examples/cli_aws.png b/examples/cli_aws.png new file mode 100644 index 0000000..5b304e1 Binary files /dev/null and b/examples/cli_aws.png differ diff --git a/examples/cli_azure.png b/examples/cli_azure.png new file mode 100644 index 0000000..5b304e1 Binary files /dev/null and b/examples/cli_azure.png differ diff --git a/examples/cli_gcp.png b/examples/cli_gcp.png new file mode 100644 index 0000000..5b304e1 Binary files /dev/null and b/examples/cli_gcp.png differ diff --git a/examples/client.png b/examples/client.png deleted file mode 100644 index 2dfdcd4..0000000 Binary files a/examples/client.png and /dev/null differ diff --git a/examples/client.yml b/examples/client.yml deleted file mode 100644 index a656f77..0000000 --- a/examples/client.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -components: - - - kind: client - label: "Web App" - fillColor: '#ee82ee' diff --git a/examples/cos.png b/examples/cos.png deleted file mode 100644 index b72e09b..0000000 Binary files a/examples/cos.png and /dev/null differ diff --git a/examples/custom_image.png b/examples/custom_image.png index 908fc21..e3d40dc 100644 Binary files a/examples/custom_image.png and b/examples/custom_image.png differ diff --git a/examples/database.png b/examples/database.png deleted file mode 100644 index dc1ab32..0000000 Binary files a/examples/database.png and /dev/null differ diff --git a/examples/database.yml b/examples/database.yml deleted file mode 100644 index 55060fb..0000000 --- a/examples/database.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -components: - - - kind: database - label: "Users\nRepository" diff --git a/examples/db.jpg b/examples/db.jpg deleted file mode 100644 index dedfdea..0000000 Binary files a/examples/db.jpg and /dev/null differ diff --git a/examples/dns.png b/examples/dns.png index 7d874b7..66256c8 100644 Binary files a/examples/dns.png and b/examples/dns.png differ diff --git a/examples/dns_aws.png b/examples/dns_aws.png new file mode 100644 index 0000000..2e667d4 Binary files /dev/null and b/examples/dns_aws.png differ diff --git a/examples/dns_azure.png b/examples/dns_azure.png new file mode 100644 index 0000000..1ee974f Binary files /dev/null and b/examples/dns_azure.png differ diff --git a/examples/dns_gcp.png b/examples/dns_gcp.png new file mode 100644 index 0000000..9d48e91 Binary files /dev/null and b/examples/dns_gcp.png differ diff --git a/examples/doc.png b/examples/doc.png new file mode 100644 index 0000000..194eda2 Binary files /dev/null and b/examples/doc.png differ diff --git a/examples/doc.yml b/examples/doc.yml new file mode 100644 index 0000000..a8ee87f --- /dev/null +++ b/examples/doc.yml @@ -0,0 +1,7 @@ +--- +components: + - + kind: doc + label: | + Users + Repository diff --git a/examples/doc_aws.png b/examples/doc_aws.png new file mode 100644 index 0000000..f7c3c99 Binary files /dev/null and b/examples/doc_aws.png differ diff --git a/examples/doc_azure.png b/examples/doc_azure.png new file mode 100644 index 0000000..edff1d6 Binary files /dev/null and b/examples/doc_azure.png differ diff --git a/examples/doc_gcp.png b/examples/doc_gcp.png new file mode 100644 index 0000000..0706bcc Binary files /dev/null and b/examples/doc_gcp.png differ diff --git a/examples/fn.jpg b/examples/fn.jpg deleted file mode 100644 index d5b33d4..0000000 Binary files a/examples/fn.jpg and /dev/null differ diff --git a/examples/fst.png b/examples/fst.png new file mode 100644 index 0000000..9002c43 Binary files /dev/null and b/examples/fst.png differ diff --git a/examples/broker.yml b/examples/fst.yml similarity index 58% rename from examples/broker.yml rename to examples/fst.yml index c86e9cd..5753b83 100644 --- a/examples/broker.yml +++ b/examples/fst.yml @@ -1,4 +1,4 @@ --- components: - - kind: broker \ No newline at end of file + kind: fst \ No newline at end of file diff --git a/examples/fst_aws.png b/examples/fst_aws.png new file mode 100644 index 0000000..6c76b53 Binary files /dev/null and b/examples/fst_aws.png differ diff --git a/examples/fst_azure.png b/examples/fst_azure.png new file mode 100644 index 0000000..26c168b Binary files /dev/null and b/examples/fst_azure.png differ diff --git a/examples/fst_gcp.png b/examples/fst_gcp.png new file mode 100644 index 0000000..4623b66 Binary files /dev/null and b/examples/fst_gcp.png differ diff --git a/examples/function.png b/examples/fun.png similarity index 100% rename from examples/function.png rename to examples/fun.png diff --git a/examples/function.yml b/examples/fun.yml similarity index 75% rename from examples/function.yml rename to examples/fun.yml index 06dbe4c..09f367a 100644 --- a/examples/function.yml +++ b/examples/fun.yml @@ -1,5 +1,5 @@ --- components: - - kind: function + kind: fun label: "Create\nAuth Challange" diff --git a/examples/fun_aws.png b/examples/fun_aws.png new file mode 100644 index 0000000..bef471e Binary files /dev/null and b/examples/fun_aws.png differ diff --git a/examples/fun_azure.png b/examples/fun_azure.png new file mode 100644 index 0000000..df5a21c Binary files /dev/null and b/examples/fun_azure.png differ diff --git a/examples/fun_gcp.png b/examples/fun_gcp.png new file mode 100644 index 0000000..b2d4229 Binary files /dev/null and b/examples/fun_gcp.png differ diff --git a/examples/gateway.png b/examples/gateway.png deleted file mode 100644 index dc956a9..0000000 Binary files a/examples/gateway.png and /dev/null differ diff --git a/examples/gateway.yml b/examples/gateway.yml deleted file mode 100644 index c669810..0000000 --- a/examples/gateway.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -components: - - - kind: gateway - label: "API Gateway" - fontColor: '#fafafaff' \ No newline at end of file diff --git a/examples/gt.jpg b/examples/gt.jpg deleted file mode 100644 index 27631b5..0000000 Binary files a/examples/gt.jpg and /dev/null differ diff --git a/examples/gtw.png b/examples/gtw.png new file mode 100644 index 0000000..28eeb5a Binary files /dev/null and b/examples/gtw.png differ diff --git a/examples/balancer.yml b/examples/gtw.yml similarity index 56% rename from examples/balancer.yml rename to examples/gtw.yml index 0f03975..33e1097 100644 --- a/examples/balancer.yml +++ b/examples/gtw.yml @@ -1,4 +1,4 @@ --- components: - - kind: balancer \ No newline at end of file + kind: gtw \ No newline at end of file diff --git a/examples/gtw_aws.png b/examples/gtw_aws.png new file mode 100644 index 0000000..877e697 Binary files /dev/null and b/examples/gtw_aws.png differ diff --git a/examples/gtw_azure.png b/examples/gtw_azure.png new file mode 100644 index 0000000..811ec64 Binary files /dev/null and b/examples/gtw_azure.png differ diff --git a/examples/gtw_gcp.png b/examples/gtw_gcp.png new file mode 100644 index 0000000..6644053 Binary files /dev/null and b/examples/gtw_gcp.png differ diff --git a/examples/kub.png b/examples/kub.png new file mode 100644 index 0000000..fc584d5 Binary files /dev/null and b/examples/kub.png differ diff --git a/examples/kub.yml b/examples/kub.yml new file mode 100644 index 0000000..2e8afe0 --- /dev/null +++ b/examples/kub.yml @@ -0,0 +1,4 @@ +--- +components: + - + kind: kub \ No newline at end of file diff --git a/examples/kub_aws.png b/examples/kub_aws.png new file mode 100644 index 0000000..936bf53 Binary files /dev/null and b/examples/kub_aws.png differ diff --git a/examples/kub_azure.png b/examples/kub_azure.png new file mode 100644 index 0000000..cb6a830 Binary files /dev/null and b/examples/kub_azure.png differ diff --git a/examples/kub_gcp.png b/examples/kub_gcp.png new file mode 100644 index 0000000..034bfc2 Binary files /dev/null and b/examples/kub_gcp.png differ diff --git a/examples/lba.png b/examples/lba.png new file mode 100644 index 0000000..91cf895 Binary files /dev/null and b/examples/lba.png differ diff --git a/examples/lba.yml b/examples/lba.yml new file mode 100644 index 0000000..20013bd --- /dev/null +++ b/examples/lba.yml @@ -0,0 +1,4 @@ +--- +components: + - + kind: lba \ No newline at end of file diff --git a/examples/lba_aws.png b/examples/lba_aws.png new file mode 100644 index 0000000..323acad Binary files /dev/null and b/examples/lba_aws.png differ diff --git a/examples/lba_azure.png b/examples/lba_azure.png new file mode 100644 index 0000000..6ef7e30 Binary files /dev/null and b/examples/lba_azure.png differ diff --git a/examples/lba_gcp.png b/examples/lba_gcp.png new file mode 100644 index 0000000..5583a50 Binary files /dev/null and b/examples/lba_gcp.png differ diff --git a/examples/mem.png b/examples/mem.png new file mode 100644 index 0000000..9e302b8 Binary files /dev/null and b/examples/mem.png differ diff --git a/examples/mem.yml b/examples/mem.yml new file mode 100644 index 0000000..40befd7 --- /dev/null +++ b/examples/mem.yml @@ -0,0 +1,4 @@ +--- +components: + - + kind: mem \ No newline at end of file diff --git a/examples/mem_aws.png b/examples/mem_aws.png new file mode 100644 index 0000000..298768a Binary files /dev/null and b/examples/mem_aws.png differ diff --git a/examples/mem_azure.png b/examples/mem_azure.png new file mode 100644 index 0000000..81eba95 Binary files /dev/null and b/examples/mem_azure.png differ diff --git a/examples/mem_gcp.png b/examples/mem_gcp.png new file mode 100644 index 0000000..0fb12ab Binary files /dev/null and b/examples/mem_gcp.png differ diff --git a/examples/message-bus-pattern-with-icons.yml b/examples/message-bus-pattern-with-icons.yml new file mode 100644 index 0000000..4582fab --- /dev/null +++ b/examples/message-bus-pattern-with-icons.yml @@ -0,0 +1,55 @@ +title: message bus pattern +backgroundColor: '#ffffff' +components: + - + kind: service + label: Producer + - + id: br1 + kind: icon + label: aws-sns.png + - + id: qs1 + kind: icon + label: aws-sns.png + - + id: qs2 + kind: icon + label: aws-sns.png + - + kind: service + label: "Consumer\n@ topic 1" + - + kind: service + label: "Consumer\n@ topic 2" +connections: + - + origin: + componentId: ms1 + targets: + - + componentId: br1 + - + origin: + componentId: br1 + targets: + - + componentId: qs1 + dashed: true + - + componentId: qs2 + dashed: true + - + origin: + componentId: qs1 + targets: + - + componentId: ms2 + dir: back + - + origin: + componentId: qs2 + targets: + - + componentId: ms3 + dir: back diff --git a/examples/message-bus-pattern.png b/examples/message-bus-pattern.png index f9bd06f..5242324 100644 Binary files a/examples/message-bus-pattern.png and b/examples/message-bus-pattern.png differ diff --git a/examples/message-bus-pattern.yml b/examples/message-bus-pattern.yml index 8d555e8..d4c4f3d 100644 --- a/examples/message-bus-pattern.yml +++ b/examples/message-bus-pattern.yml @@ -2,51 +2,38 @@ title: message bus pattern backgroundColor: '#ffffff' components: - - kind: service + kind: ser label: Producer - - - kind: broker - label: "Notification\nService" - - - kind: queue - label: "event queue @ topic 1" - - - kind: queue - label: "event queue @ topic 2" - - - kind: service - label: "Consumer\n@ topic 1" - - - kind: service - label: "Consumer\n@ topic 2" + fillColor: '#4e8393' + - + kind: msg + label: | + Notification + Service + - + kind: ser + label: | + Subscriber + @ topic 1 + fillColor: '#b8422d' + - + kind: ser + label: | + Subscriber + @ topic 2 + fillColor: '#53934e' connections: - - origin: - componentId: ms1 + origin: ser1 targets: - - componentId: br1 + id: msg1 - - origin: - componentId: br1 + origin: msg1 targets: - - componentId: qs1 + id: ser2 dashed: true - - componentId: qs2 + id: ser3 dashed: true - - - origin: - componentId: qs1 - targets: - - - componentId: ms2 - dir: back - - - origin: - componentId: qs2 - targets: - - - componentId: ms3 - dir: back diff --git a/examples/message-bus-pattern_aws.png b/examples/message-bus-pattern_aws.png new file mode 100644 index 0000000..b30422b Binary files /dev/null and b/examples/message-bus-pattern_aws.png differ diff --git a/examples/message-bus-pattern_azure.png b/examples/message-bus-pattern_azure.png new file mode 100644 index 0000000..dce9a88 Binary files /dev/null and b/examples/message-bus-pattern_azure.png differ diff --git a/examples/message-bus-pattern_gcp.png b/examples/message-bus-pattern_gcp.png new file mode 100644 index 0000000..26bc7a1 Binary files /dev/null and b/examples/message-bus-pattern_gcp.png differ diff --git a/examples/ms.jpg b/examples/ms.jpg deleted file mode 100644 index d48fe24..0000000 Binary files a/examples/ms.jpg and /dev/null differ diff --git a/examples/msg.png b/examples/msg.png new file mode 100644 index 0000000..0166eaf Binary files /dev/null and b/examples/msg.png differ diff --git a/examples/msg.yml b/examples/msg.yml new file mode 100644 index 0000000..36586b6 --- /dev/null +++ b/examples/msg.yml @@ -0,0 +1,4 @@ +--- +components: + - + kind: msg \ No newline at end of file diff --git a/examples/msg_aws.png b/examples/msg_aws.png new file mode 100644 index 0000000..830f204 Binary files /dev/null and b/examples/msg_aws.png differ diff --git a/examples/msg_azure.png b/examples/msg_azure.png new file mode 100644 index 0000000..061410b Binary files /dev/null and b/examples/msg_azure.png differ diff --git a/examples/msg_gcp.png b/examples/msg_gcp.png new file mode 100644 index 0000000..e910d64 Binary files /dev/null and b/examples/msg_gcp.png differ diff --git a/examples/ost.png b/examples/ost.png new file mode 100644 index 0000000..9ef1c02 Binary files /dev/null and b/examples/ost.png differ diff --git a/examples/ost.yml b/examples/ost.yml new file mode 100644 index 0000000..c3ac254 --- /dev/null +++ b/examples/ost.yml @@ -0,0 +1,4 @@ +--- +components: + - + kind: ost \ No newline at end of file diff --git a/examples/ost_aws.png b/examples/ost_aws.png new file mode 100644 index 0000000..b911fa1 Binary files /dev/null and b/examples/ost_aws.png differ diff --git a/examples/ost_azure.png b/examples/ost_azure.png new file mode 100644 index 0000000..5a9e2e8 Binary files /dev/null and b/examples/ost_azure.png differ diff --git a/examples/ost_gcp.png b/examples/ost_gcp.png new file mode 100644 index 0000000..db8f696 Binary files /dev/null and b/examples/ost_gcp.png differ diff --git a/examples/qs.jpg b/examples/qs.jpg deleted file mode 100644 index ffaf71b..0000000 Binary files a/examples/qs.jpg and /dev/null differ diff --git a/examples/que.png b/examples/que.png new file mode 100644 index 0000000..a22b4f2 Binary files /dev/null and b/examples/que.png differ diff --git a/examples/queue.yml b/examples/que.yml similarity index 74% rename from examples/queue.yml rename to examples/que.yml index 1b3baab..7650640 100644 --- a/examples/queue.yml +++ b/examples/que.yml @@ -1,5 +1,5 @@ --- components: - - kind: queue + kind: que label: "event queue" \ No newline at end of file diff --git a/examples/que_aws.png b/examples/que_aws.png new file mode 100644 index 0000000..a22b4f2 Binary files /dev/null and b/examples/que_aws.png differ diff --git a/examples/que_azure.png b/examples/que_azure.png new file mode 100644 index 0000000..a22b4f2 Binary files /dev/null and b/examples/que_azure.png differ diff --git a/examples/que_gcp.png b/examples/que_gcp.png new file mode 100644 index 0000000..a22b4f2 Binary files /dev/null and b/examples/que_gcp.png differ diff --git a/examples/queue.png b/examples/queue.png deleted file mode 100644 index 76c456d..0000000 Binary files a/examples/queue.png and /dev/null differ diff --git a/examples/rdb.png b/examples/rdb.png new file mode 100644 index 0000000..e5897e2 Binary files /dev/null and b/examples/rdb.png differ diff --git a/examples/rdb.yml b/examples/rdb.yml new file mode 100644 index 0000000..f8d173d --- /dev/null +++ b/examples/rdb.yml @@ -0,0 +1,5 @@ +--- +components: + - + kind: rdb + label: Orders diff --git a/examples/rdb_aws.png b/examples/rdb_aws.png new file mode 100644 index 0000000..caaf95a Binary files /dev/null and b/examples/rdb_aws.png differ diff --git a/examples/rdb_azure.png b/examples/rdb_azure.png new file mode 100644 index 0000000..af6ec73 Binary files /dev/null and b/examples/rdb_azure.png differ diff --git a/examples/rdb_gcp.png b/examples/rdb_gcp.png new file mode 100644 index 0000000..1f7c48b Binary files /dev/null and b/examples/rdb_gcp.png differ diff --git a/examples/s3-upload-presigned-url.png b/examples/s3-upload-presigned-url.png index 67bde34..452d791 100644 Binary files a/examples/s3-upload-presigned-url.png and b/examples/s3-upload-presigned-url.png differ diff --git a/examples/s3-upload-presigned-url.yml b/examples/s3-upload-presigned-url.yml index ff09ec6..7979700 100644 --- a/examples/s3-upload-presigned-url.yml +++ b/examples/s3-upload-presigned-url.yml @@ -2,40 +2,36 @@ title: Upload file to S3 using Lambda for pre-signed URL backgroundColor: '#ffffff' components: - - kind: client + kind: cli label: "Web App" - provider: Internet impl: SPA - - kind: gateway + kind: gtw provider: AWS impl: "API Gateway" - - kind: function + kind: fun label: "Get\nPre-Signed URL" provider: AWS impl: Lambda - - kind: storage + kind: ost label: "*.jpg\n*.png" provider: AWS impl: S3 connections: - - origin: - componentId: cl1 + origin: cli1 targets: - - componentId: gt1 + id: gtw1 - - origin: - componentId: gt1 + origin: gtw1 targets: - - componentId: fn1 + id: fun1 - - origin: - componentId: fn1 + origin: fun1 targets: - - componentId: st1 \ No newline at end of file + id: ost1 \ No newline at end of file diff --git a/examples/s3-upload-presigned-url_aws.png b/examples/s3-upload-presigned-url_aws.png new file mode 100644 index 0000000..452d791 Binary files /dev/null and b/examples/s3-upload-presigned-url_aws.png differ diff --git a/examples/s3-upload-presigned-url_azure.png b/examples/s3-upload-presigned-url_azure.png new file mode 100644 index 0000000..452d791 Binary files /dev/null and b/examples/s3-upload-presigned-url_azure.png differ diff --git a/examples/s3-upload-presigned-url_gcp.png b/examples/s3-upload-presigned-url_gcp.png new file mode 100644 index 0000000..452d791 Binary files /dev/null and b/examples/s3-upload-presigned-url_gcp.png differ diff --git a/examples/ser.png b/examples/ser.png new file mode 100644 index 0000000..f8973fe Binary files /dev/null and b/examples/ser.png differ diff --git a/examples/service.yml b/examples/ser.yml similarity index 71% rename from examples/service.yml rename to examples/ser.yml index 705a759..57d965c 100644 --- a/examples/service.yml +++ b/examples/ser.yml @@ -1,5 +1,5 @@ --- components: - - kind: service + kind: ser label: "ΞΌService" diff --git a/examples/ser_aws.png b/examples/ser_aws.png new file mode 100644 index 0000000..f8973fe Binary files /dev/null and b/examples/ser_aws.png differ diff --git a/examples/ser_azure.png b/examples/ser_azure.png new file mode 100644 index 0000000..f8973fe Binary files /dev/null and b/examples/ser_azure.png differ diff --git a/examples/ser_gcp.png b/examples/ser_gcp.png new file mode 100644 index 0000000..f8973fe Binary files /dev/null and b/examples/ser_gcp.png differ diff --git a/examples/service.png b/examples/service.png deleted file mode 100644 index 17e6df2..0000000 Binary files a/examples/service.png and /dev/null differ diff --git a/examples/st.jpg b/examples/st.jpg deleted file mode 100644 index 3e103a1..0000000 Binary files a/examples/st.jpg and /dev/null differ diff --git a/examples/storage.png b/examples/storage.png deleted file mode 100644 index 547ae8f..0000000 Binary files a/examples/storage.png and /dev/null differ diff --git a/examples/storage.yml b/examples/storage.yml deleted file mode 100644 index 8a0870e..0000000 --- a/examples/storage.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -components: - - - kind: storage - label: "*.jpg\n*.png" \ No newline at end of file diff --git a/examples/system-view.png b/examples/system-view.png index 39d3034..5bb5453 100644 Binary files a/examples/system-view.png and b/examples/system-view.png differ diff --git a/examples/system-view.yml b/examples/system-view.yml index 7684abf..4af7090 100644 --- a/examples/system-view.yml +++ b/examples/system-view.yml @@ -2,7 +2,7 @@ title: System View - Token Manager backgroundColor: '#ffffff' components: - - kind: client + kind: cli impl: SPA / iOS / Android label: Client App - @@ -14,50 +14,48 @@ components: impl: AWS Cloudfront provider: AWS - - kind: gateway + kind: gtw impl: API Gateway provider: AWS - - kind: balancer + kind: lba impl: AWS NLB provider: AWS - - kind: function + kind: fun label: Verify JWT impl: AWS Lambda provider: AWS - - kind: function + kind: fun label: Verify OTP impl: AWS Lambda provider: AWS - - kind: cos + kind: kub impl: AWS ECS provider: AWS - - kind: service + kind: ser label: Token Manager impl: AWS EC2 provider: AWS - - kind: database + kind: mem label: Redis impl: Amazon ElastiCache provider: AWS fillColor: '#d82a0b' fontColor: '#ffffff' - - kind: storage - label: | - Object - Store + kind: ost + label: Bucket impl: AWS S3 provider: AWS fillColor: '#571307' fontColor: '#ffffff' - - kind: database + kind: rdb label: MySQL impl: Amazon RDS provider: AWS @@ -65,59 +63,52 @@ components: fontColor: '#ffffff' connections: - - origin: - componentId: cl1 + origin: cli1 targets: - - componentId: waf1 + id: waf1 - - origin: - componentId: waf1 + origin: waf1 targets: - - componentId: cn1 + id: cdn1 - - origin: - componentId: cn1 + origin: cdn1 targets: - - componentId: gt1 + id: gtw1 - - origin: - componentId: gt1 + origin: gtw1 targets: - - componentId: lb1 + id: lba1 - - componentId: fn1 + id: fun1 - - componentId: fn2 + id: fun2 - - origin: - componentId: lb1 + origin: lba1 targets: - - componentId: cos1 + id: kub1 - - origin: - componentId: cos1 + origin: kub1 targets: - - componentId: ms1 + id: ser1 - - origin: - componentId: ms1 + origin: ser1 targets: - - componentId: db1 + id: mem1 - - componentId: st1 + id: ost1 - - componentId: db2 + id: rdb1 ranks: - name: rank1 components: - - gt1 - - lb1 - - cos1 \ No newline at end of file + - gtw1 + - lba1 + - kub1 \ No newline at end of file diff --git a/examples/system-view_aws.png b/examples/system-view_aws.png new file mode 100644 index 0000000..5bb5453 Binary files /dev/null and b/examples/system-view_aws.png differ diff --git a/examples/system-view_azure.png b/examples/system-view_azure.png new file mode 100644 index 0000000..5bb5453 Binary files /dev/null and b/examples/system-view_azure.png differ diff --git a/examples/system-view_gcp.png b/examples/system-view_gcp.png new file mode 100644 index 0000000..5bb5453 Binary files /dev/null and b/examples/system-view_gcp.png differ diff --git a/examples/waf.png b/examples/waf.png index abd2a0c..f0d7c6d 100644 Binary files a/examples/waf.png and b/examples/waf.png differ diff --git a/examples/waf_aws.png b/examples/waf_aws.png new file mode 100644 index 0000000..b258b19 Binary files /dev/null and b/examples/waf_aws.png differ diff --git a/examples/waf_azure.png b/examples/waf_azure.png new file mode 100644 index 0000000..4e6a1a9 Binary files /dev/null and b/examples/waf_azure.png differ diff --git a/examples/waf_gcp.png b/examples/waf_gcp.png new file mode 100644 index 0000000..ac1f056 Binary files /dev/null and b/examples/waf_gcp.png differ diff --git a/storage.go b/fst.go similarity index 50% rename from storage.go rename to fst.go index db73739..82dae45 100644 --- a/storage.go +++ b/fst.go @@ -9,30 +9,40 @@ import ( "github.com/lucasepe/draft/pkg/node" ) -type storage struct { +type fst struct { seq int16 } -func (rcv *storage) nextID() string { +func (rcv *fst) nextID() string { rcv.seq++ - return fmt.Sprintf("st%d", rcv.seq) + return fmt.Sprintf("fst%d", rcv.seq) } -func (rcv *storage) sketch(graph *dot.Graph, comp Component) { +func (rcv *fst) sketch(graph *dot.Graph, comp Component) { id := comp.ID if strings.TrimSpace(comp.ID) == "" { id = rcv.nextID() } + fontColor := "#000000ff" + if fc := strings.TrimSpace(comp.FontColor); fc != "" { + fontColor = fc + } + + fillColor := "#dadd29ff" + if fc := strings.TrimSpace(comp.FillColor); len(fc) > 0 { + fillColor = fc + } + cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) el := node.New(cl, id, node.Label(comp.Label, false), node.Rounded(comp.Rounded), - node.FontColor(comp.FontColor, "#000000ff"), - node.FillColor(comp.FillColor, "#f0e77fff"), - node.FontSize(8), + node.FontColor(fontColor), + node.FillColor(fillColor), node.Shape("folder"), ) - el.Attr("height", "0.4") + el.Attr("width", "0.7") } diff --git a/storage_test.go b/fst_test.go similarity index 73% rename from storage_test.go rename to fst_test.go index 6370b6f..cc33a1c 100644 --- a/storage_test.go +++ b/fst_test.go @@ -6,17 +6,17 @@ import ( "github.com/emicklei/dot" ) -func TestStorageComponentNextID(t *testing.T) { +func TestFileStoreNextID(t *testing.T) { tests := []struct { want string }{ - {"st1"}, - {"st2"}, - {"st3"}, - {"st4"}, + {"fst1"}, + {"fst2"}, + {"fst3"}, + {"fst4"}, } - s := storage{} + s := fst{} for _, tt := range tests { t.Run(tt.want, func(t *testing.T) { @@ -27,10 +27,10 @@ func TestStorageComponentNextID(t *testing.T) { } } -func TestStorageComponent(t *testing.T) { +func TestFileStoreShape(t *testing.T) { g := dot.NewGraph(dot.Directed) - sketcher := storage{} + sketcher := fst{} sketcher.sketch(g, Component{}) if got, want := flatten(g.String()), `shape="folder",style="filled"`; !verify(got, want) { diff --git a/function.go b/fun.go similarity index 63% rename from function.go rename to fun.go index bcd8bb5..2990bdd 100644 --- a/function.go +++ b/fun.go @@ -9,16 +9,16 @@ import ( "github.com/lucasepe/draft/pkg/node" ) -type function struct { +type fun struct { seq int16 } -func (rcv *function) nextID() string { +func (rcv *fun) nextID() string { rcv.seq++ - return fmt.Sprintf("fn%d", rcv.seq) + return fmt.Sprintf("fun%d", rcv.seq) } -func (rcv *function) sketch(graph *dot.Graph, comp Component) { +func (rcv *fun) sketch(graph *dot.Graph, comp Component) { id := comp.ID if strings.TrimSpace(comp.ID) == "" { id = rcv.nextID() @@ -29,13 +29,19 @@ func (rcv *function) sketch(graph *dot.Graph, comp Component) { label = comp.Label } + fillColor := "#abd9e9ff" + if fc := strings.TrimSpace(comp.FillColor); len(fc) > 0 { + fillColor = fc + } + cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) el := node.New(cl, id, node.Label(label, false), node.Rounded(comp.Rounded), - node.FontColor(comp.FontColor, "#000000ff"), - node.FillColor(comp.FillColor, "#abd9e9ff"), + node.FontColor("#000000ff"), + node.FillColor(fillColor), node.Shape("signature"), ) el.Attr("fontsize", "6") diff --git a/function_test.go b/fun_test.go similarity index 73% rename from function_test.go rename to fun_test.go index 34f6ab1..a51d3cc 100644 --- a/function_test.go +++ b/fun_test.go @@ -6,17 +6,17 @@ import ( "github.com/emicklei/dot" ) -func TestFunctionComponentNextID(t *testing.T) { +func TestFunctionNextID(t *testing.T) { tests := []struct { want string }{ - {"fn1"}, - {"fn2"}, - {"fn3"}, - {"fn4"}, + {"fun1"}, + {"fun2"}, + {"fun3"}, + {"fun4"}, } - s := function{} + s := fun{} for _, tt := range tests { t.Run(tt.want, func(t *testing.T) { @@ -27,11 +27,11 @@ func TestFunctionComponentNextID(t *testing.T) { } } -func TestFunctionComponent(t *testing.T) { +func TestFunctionShape(t *testing.T) { want := `shape="signature",style="filled"` g := dot.NewGraph(dot.Directed) - sketcher := function{} + sketcher := fun{} sketcher.sketch(g, Component{}) if got := flatten(g.String()); !verify(got, want) { diff --git a/gateway_test.go b/gateway_test.go deleted file mode 100644 index ab42cdc..0000000 --- a/gateway_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package draft - -import ( - "testing" - - "github.com/emicklei/dot" -) - -func TestGatewayComponentNextID(t *testing.T) { - tests := []struct { - want string - }{ - {"gt1"}, - {"gt2"}, - {"gt3"}, - {"gt4"}, - } - - s := gateway{} - - for _, tt := range tests { - t.Run(tt.want, func(t *testing.T) { - if got := s.nextID(); got != tt.want { - t.Errorf("got [%v] want [%v]", got, tt.want) - } - }) - } -} - -func TestGatewayComponent(t *testing.T) { - want := `label="GW",shape="doublecircle",style="filled"` - g := dot.NewGraph(dot.Directed) - - sketcher := gateway{} - sketcher.sketch(g, Component{}) - - if got := flatten(g.String()); !verify(got, want) { - t.Errorf("got [%v] want [%v]", got, want) - } -} diff --git a/gateway.go b/gtw.go similarity index 57% rename from gateway.go rename to gtw.go index d215919..7ed8881 100644 --- a/gateway.go +++ b/gtw.go @@ -9,29 +9,31 @@ import ( "github.com/lucasepe/draft/pkg/node" ) -type gateway struct { +type gtw struct { seq int16 } -func (rcv *gateway) nextID() string { +func (rcv *gtw) nextID() string { rcv.seq++ - return fmt.Sprintf("gt%d", rcv.seq) + return fmt.Sprintf("gtw%d", rcv.seq) } -func (rcv *gateway) sketch(graph *dot.Graph, comp Component) { +func (rcv *gtw) sketch(graph *dot.Graph, comp Component) { id := comp.ID if strings.TrimSpace(comp.ID) == "" { id = rcv.nextID() } cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) el := node.New(cl, id, - node.Label("GW", false), + node.Label("GTW", true), node.Rounded(comp.Rounded), - node.FontColor(comp.FontColor, "#000000ff"), - node.FillColor(comp.FillColor, "#ff7f00ff"), + node.FontColor("#f5f5f5ff"), + node.FillColor("#ff7f00ff"), node.Shape("doublecircle"), ) - el.Attr("width", "0.2") + el.Attr("width", "0.1") + el.Attr("color", "#ff7f00ff") } diff --git a/gtw_test.go b/gtw_test.go new file mode 100644 index 0000000..f0c1776 --- /dev/null +++ b/gtw_test.go @@ -0,0 +1,40 @@ +package draft + +import ( + "testing" + + "github.com/emicklei/dot" +) + +func TestGatewayNextID(t *testing.T) { + tests := []struct { + want string + }{ + {"gtw1"}, + {"gtw2"}, + {"gtw3"}, + {"gtw4"}, + } + + s := gtw{} + + for _, tt := range tests { + t.Run(tt.want, func(t *testing.T) { + if got := s.nextID(); got != tt.want { + t.Errorf("got [%v] want [%v]", got, tt.want) + } + }) + } +} + +func TestGatewayShape(t *testing.T) { + want := `label=<GTW>,shape="doublecircle",style="filled"` + g := dot.NewGraph(dot.Directed) + + sketcher := gtw{} + sketcher.sketch(g, Component{}) + + if got := flatten(g.String()); !verify(got, want) { + t.Errorf("got [%v] want [%v]", got, want) + } +} diff --git a/html.go b/html.go index 99b78db..f6a9d9b 100644 --- a/html.go +++ b/html.go @@ -24,12 +24,17 @@ func (rcv *html) sketch(graph *dot.Graph, comp Component) { id = rcv.nextID() } + fontColor := "#000000ff" + if fc := strings.TrimSpace(comp.FontColor); fc != "" { + fontColor = fc + } + cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) node.New(cl, id, node.Label(comp.Label, true), - node.FontColor(comp.FontColor, "#000000ff"), - node.FillColor("", "transparent"), + node.FontColor(fontColor), + node.FillColor("transparent"), node.FontSize(7), node.Shape("plain"), ) diff --git a/icon.go b/icon.go new file mode 100644 index 0000000..72ff113 --- /dev/null +++ b/icon.go @@ -0,0 +1,49 @@ +package draft + +import ( + "fmt" + "os" + "path" + "strings" + + "github.com/emicklei/dot" + "github.com/lucasepe/draft/pkg/cluster" + "github.com/lucasepe/draft/pkg/node" +) + +type icon struct { + seq int16 +} + +func (rcv *icon) nextID() string { + rcv.seq++ + return fmt.Sprintf("ico%d", rcv.seq) +} + +func (rcv *icon) sketch(graph *dot.Graph, comp Component) { + if strings.TrimSpace(comp.Label) == "" { + return + } + + id := comp.ID + if strings.TrimSpace(comp.ID) == "" { + id = rcv.nextID() + } + + iconsPath := os.Getenv("DRAFT_ICONS_PATH") + img := path.Join(iconsPath, comp.Label) + + label := fmt.Sprintf(` + + + +
`, img) + + cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + + node.New(cl, id, + node.Label(label, true), + node.FillColor("transparent"), + node.Shape("plain"), + ) +} diff --git a/impl.go b/impl.go new file mode 100644 index 0000000..5e48830 --- /dev/null +++ b/impl.go @@ -0,0 +1,100 @@ +package draft + +import ( + "strings" + + "github.com/emicklei/dot" +) + +func getCloudImpl(provider, kind string) string { + switch strings.TrimSpace(strings.ToLower(provider)) { + case "aws": + return awsImpl()(kind) + case "gcp": + return gcpImpl()(kind) + case "azure": + return azureImpl()(kind) + default: + return "" + } +} + +func awsImpl() func(string) string { + dict := map[string]string{ + "bst": "Elastic Block\nStore (EBS)", + "cdn": "Cloudfront", + "dns": "Route 53", + "doc": "DynamoDB", + "fst": "Elastic\nFile System (EFS)", + "fun": "Lambda", + "gtw": "API Gateway", + "lba": "Elastic\nLoad Balancer", + "kub": "Elastic Container Service\nfor Kubernetes (EKS)", + "mem": "ElastiCache", + "msg": "SNS", + "ost": "Simple Storage\nService (S3)", + "rdb": "Relational Database\nService (RDS)", + "waf": "AWS WAF", + } + + return func(key string) string { + return dict[key] + } +} + +func gcpImpl() func(string) string { + dict := map[string]string{ + "bst": "Persistent Disk", + "cdn": "Cloud CDN", + "dns": "Cloud DNS", + "doc": "Cloud Datastore", + "fst": "Cloud Filestore", + "fun": "Cloud Functions", + "gtw": "Cloud Endpoints", + "lba": "Cloud Load Balancing", + "kub": "Google Kubernetes\nEngine", + "mem": "Cloud Memorystore", + "msg": "Cloud Pub/Sub", + "ost": "Cloud Storage", + "rdb": "Cloud SQL", + "waf": "Google Armor", + } + + return func(key string) string { + return dict[key] + } +} + +func azureImpl() func(string) string { + dict := map[string]string{ + "bst": "Disk Storage", + "cdn": "Azure CDN", + "dns": "Azure DNS", + "doc": "Cosmos DB", + "fst": "Azure File Storage", + "fun": "Azure Functions", + "gtw": "Azure API Management", + "lba": "Load Balancer", + "kub": "Azure Kubernetes\nService (AKS)", + "mem": "Redis Caches", + "msg": "Notification Hubs", + "ost": "Blob Storage", + "rdb": "SQL Database", + "waf": "Azure Firewall", + } + + return func(key string) string { + return dict[key] + } +} + +func guessImpl(cmp *Component, cluster *dot.Graph) { + if s := strings.TrimSpace(cmp.Impl); len(s) > 0 { + return + } + + impl := getCloudImpl(cmp.provider, cmp.Kind) + if len(impl) > 0 { + cluster.Attr("label", impl) + } +} diff --git a/impl_test.go b/impl_test.go new file mode 100644 index 0000000..d8ec41d --- /dev/null +++ b/impl_test.go @@ -0,0 +1,94 @@ +package draft + +import ( + "testing" + + "github.com/lucasepe/draft/pkg/cluster" + "github.com/lucasepe/draft/pkg/graph" +) + +func TestCloudImpl(t *testing.T) { + tests := []struct { + provider string + key string + want string + }{ + {"aws", "bst", "Elastic Block\nStore (EBS)"}, + {"aws", "lba", "Elastic\nLoad Balancer"}, + {"aws", "ost", "Simple Storage\nService (S3)"}, + + {"gcp", "kub", "Google Kubernetes\nEngine"}, + {"gcp", "mem", "Cloud Memorystore"}, + {"gcp", "ost", "Cloud Storage"}, + + {"azure", "dns", "Azure DNS"}, + {"azure", "mem", "Redis Caches"}, + {"azure", "waf", "Azure Firewall"}, + } + + for _, tt := range tests { + t.Run(tt.want, func(t *testing.T) { + if got := getCloudImpl(tt.provider, tt.key); got != tt.want { + t.Errorf("got [%v] want [%v]", got, tt.want) + } + }) + } +} + +func TestGuessImpl(t *testing.T) { + tests := []struct { + comp Component + want string + }{ + { + Component{provider: "aws", Kind: "bst"}, + "Elastic Block\nStore (EBS)", + }, + { + Component{provider: "aws", Kind: "lba"}, + "Elastic\nLoad Balancer", + }, + { + Component{provider: "aws", Kind: "ost"}, + "Simple Storage\nService (S3)", + }, + + { + Component{provider: "gcp", Kind: "kub"}, + "Google Kubernetes\nEngine", + }, + { + Component{provider: "gcp", Kind: "mem"}, + "Cloud Memorystore", + }, + { + Component{provider: "gcp", Kind: "ost"}, + "Cloud Storage", + }, + + { + Component{provider: "azure", Kind: "dns"}, + "Azure DNS", + }, + { + Component{provider: "azure", Kind: "mem"}, + "Redis Caches", + }, + { + Component{provider: "azure", Kind: "waf"}, + "Azure Firewall", + }, + } + + gr := graph.New() + cl := cluster.New(gr, "DUMMY") + + for _, tt := range tests { + t.Run(tt.want, func(t *testing.T) { + guessImpl(&tt.comp, cl) + if got := cl.AttributesMap.Value("label"); got != tt.want { + t.Errorf("got [%v] want [%v]", got, tt.want) + } + }) + } +} diff --git a/kub.go b/kub.go new file mode 100644 index 0000000..13b99fe --- /dev/null +++ b/kub.go @@ -0,0 +1,36 @@ +package draft + +import ( + "fmt" + "strings" + + "github.com/emicklei/dot" + "github.com/lucasepe/draft/pkg/cluster" + "github.com/lucasepe/draft/pkg/node" +) + +type kub struct { + seq int16 +} + +func (rcv *kub) nextID() string { + rcv.seq++ + return fmt.Sprintf("kub%d", rcv.seq) +} + +func (rcv *kub) sketch(graph *dot.Graph, comp Component) { + id := comp.ID + if strings.TrimSpace(comp.ID) == "" { + id = rcv.nextID() + } + + cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) + + node.New(cl, id, + node.Label("K8s
Engine
", true), + node.FontColor("#fafafaff"), + node.FillColor("#64a365"), + node.Shape("square"), + ) +} diff --git a/kub_test.go b/kub_test.go new file mode 100644 index 0000000..28272fc --- /dev/null +++ b/kub_test.go @@ -0,0 +1,40 @@ +package draft + +import ( + "testing" + + "github.com/emicklei/dot" +) + +func TestContainerManagerNextID(t *testing.T) { + tests := []struct { + want string + }{ + {"kub1"}, + {"kub2"}, + {"kub3"}, + {"kub4"}, + } + + s := kub{} + + for _, tt := range tests { + t.Run(tt.want, func(t *testing.T) { + if got := s.nextID(); got != tt.want { + t.Errorf("got [%v] want [%v]", got, tt.want) + } + }) + } +} + +func TestContainerManagerShape(t *testing.T) { + want := `shape="square",style="filled"` + g := dot.NewGraph(dot.Directed) + + sketcher := kub{} + sketcher.sketch(g, Component{}) + + if got := flatten(g.String()); !verify(got, want) { + t.Errorf("got [%v] want [%v]", got, want) + } +} diff --git a/balancer.go b/lba.go similarity index 62% rename from balancer.go rename to lba.go index c475be0..eb0a41d 100644 --- a/balancer.go +++ b/lba.go @@ -9,30 +9,32 @@ import ( "github.com/lucasepe/draft/pkg/node" ) -type balancer struct { +type lba struct { seq int16 } -func (rcv *balancer) nextID() string { +func (rcv *lba) nextID() string { rcv.seq++ - return fmt.Sprintf("lb%d", rcv.seq) + return fmt.Sprintf("lba%d", rcv.seq) } -func (rcv *balancer) sketch(graph *dot.Graph, comp Component) { +func (rcv *lba) sketch(graph *dot.Graph, comp Component) { id := comp.ID if strings.TrimSpace(comp.ID) == "" { id = rcv.nextID() } cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) el := node.New(cl, id, - node.Label("LB", false), + node.Label("LB", true), node.Rounded(comp.Rounded), - node.FontColor(comp.FontColor, "#000000ff"), - node.FillColor(comp.FillColor, "#1a5276ff"), + node.FontColor("#f5f5f5ff"), + node.FillColor("#1a5276ff"), node.Shape("Mdiamond"), ) el.Attr("width", "0.3") el.Attr("height", "0.3") + el.Attr("color", "#f5f5f5ff") } diff --git a/lba_test.go b/lba_test.go new file mode 100644 index 0000000..7085397 --- /dev/null +++ b/lba_test.go @@ -0,0 +1,40 @@ +package draft + +import ( + "testing" + + "github.com/emicklei/dot" +) + +func TestLoadBalancerNextID(t *testing.T) { + tests := []struct { + want string + }{ + {"lba1"}, + {"lba2"}, + {"lba3"}, + {"lba4"}, + } + + s := lba{} + + for _, tt := range tests { + t.Run(tt.want, func(t *testing.T) { + if got := s.nextID(); got != tt.want { + t.Errorf("got [%v] want [%v]", got, tt.want) + } + }) + } +} + +func TestLoadBalancerShape(t *testing.T) { + want := `label=<LB>,shape="Mdiamond",style="filled"` + g := dot.NewGraph(dot.Directed) + + sketcher := lba{} + sketcher.sketch(g, Component{}) + + if got := flatten(g.String()); !verify(got, want) { + t.Errorf("got [%v] want [%v]", got, want) + } +} diff --git a/mem.go b/mem.go new file mode 100644 index 0000000..c7339a0 --- /dev/null +++ b/mem.go @@ -0,0 +1,70 @@ +package draft + +import ( + "fmt" + "strings" + + "github.com/emicklei/dot" + "github.com/lucasepe/draft/pkg/cluster" + "github.com/lucasepe/draft/pkg/node" +) + +type mem struct { + seq int16 +} + +func (rcv *mem) nextID() string { + rcv.seq++ + return fmt.Sprintf("mem%d", rcv.seq) +} + +func (rcv *mem) sketch(graph *dot.Graph, comp Component) { + id := comp.ID + if strings.TrimSpace(comp.ID) == "" { + id = rcv.nextID() + } + + caption := strings.TrimSpace(comp.Label) + if len(caption) == 0 { + caption = " " + } + + fillColor := comp.FillColor + if strings.TrimSpace(comp.FillColor) == "" { + fillColor = "#f04d30ff" + } + + label := strings.Replace(` + + + + + + + + + + + + + + + + +
 
keyval
%s
`, "{{BGCOLOR}}", fillColor, -1) + + label = fmt.Sprintf(label, caption) + + cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) + + el := node.New(cl, id, + node.Label(label, true), + node.FontColor("#000000ff"), + node.FillColor("transparent"), + // ^^^ hack to set a transparent background + // color since we will use the HTML table. + node.Shape("plain"), + ) + el.Attr("color", "#f5f5f5ff") +} diff --git a/mem_test.go b/mem_test.go new file mode 100644 index 0000000..de76774 --- /dev/null +++ b/mem_test.go @@ -0,0 +1,40 @@ +package draft + +import ( + "testing" + + "github.com/emicklei/dot" +) + +func TestCacheNextID(t *testing.T) { + tests := []struct { + want string + }{ + {"mem1"}, + {"mem2"}, + {"mem3"}, + {"mem4"}, + } + + s := mem{} + + for _, tt := range tests { + t.Run(tt.want, func(t *testing.T) { + if got := s.nextID(); got != tt.want { + t.Errorf("got [%v] want [%v]", got, tt.want) + } + }) + } +} + +func TestCacheShape(t *testing.T) { + want := `label=<
 
key val
 
>` + g := dot.NewGraph(dot.Directed) + + sketcher := mem{} + sketcher.sketch(g, Component{}) + + if got := flatten(g.String()); !verify(got, want) { + t.Errorf("got [%v] want [%v]", got, want) + } +} diff --git a/container_service.go b/msg.go similarity index 50% rename from container_service.go rename to msg.go index 862b041..9f7ffac 100644 --- a/container_service.go +++ b/msg.go @@ -9,28 +9,30 @@ import ( "github.com/lucasepe/draft/pkg/node" ) -type containerService struct { +type msg struct { seq int16 } -func (rcv *containerService) nextID() string { +func (rcv *msg) nextID() string { rcv.seq++ - return fmt.Sprintf("cos%d", rcv.seq) + return fmt.Sprintf("msg%d", rcv.seq) } -func (rcv *containerService) sketch(graph *dot.Graph, comp Component) { +func (rcv *msg) sketch(graph *dot.Graph, comp Component) { id := comp.ID if strings.TrimSpace(comp.ID) == "" { id = rcv.nextID() } cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) el := node.New(cl, id, - node.Label("Container\nService", false), - node.FontColor(comp.FontColor, "#fafafaff"), - node.FillColor(comp.FillColor, "#64a365"), - node.Shape("component"), + node.Label("Pub / Sub", true), + node.FontColor("#000000ff"), + node.FillColor("#e0eeeeff"), + node.Shape("cds"), ) - el.Attr("height", "0.3") + el.Attr("height", "0.6") + el.Attr("width", "1.3") } diff --git a/msg_test.go b/msg_test.go new file mode 100644 index 0000000..086dc2b --- /dev/null +++ b/msg_test.go @@ -0,0 +1,40 @@ +package draft + +import ( + "testing" + + "github.com/emicklei/dot" +) + +func TestPubSubNextID(t *testing.T) { + tests := []struct { + want string + }{ + {"msg1"}, + {"msg2"}, + {"msg3"}, + {"msg4"}, + } + + s := msg{} + + for _, tt := range tests { + t.Run(tt.want, func(t *testing.T) { + if got := s.nextID(); got != tt.want { + t.Errorf("got [%v] want [%v]", got, tt.want) + } + }) + } +} + +func TestPubSubShape(t *testing.T) { + want := `label=<Pub / Sub>,shape="cds",style="filled"` + g := dot.NewGraph(dot.Directed) + + sketcher := msg{} + sketcher.sketch(g, Component{}) + + if got := flatten(g.String()); !verify(got, want) { + t.Errorf("got [%v] want [%v]", got, want) + } +} diff --git a/ost.go b/ost.go new file mode 100644 index 0000000..a021856 --- /dev/null +++ b/ost.go @@ -0,0 +1,48 @@ +package draft + +import ( + "fmt" + "strings" + + "github.com/emicklei/dot" + "github.com/lucasepe/draft/pkg/cluster" + "github.com/lucasepe/draft/pkg/node" +) + +type ost struct { + seq int16 +} + +func (rcv *ost) nextID() string { + rcv.seq++ + return fmt.Sprintf("ost%d", rcv.seq) +} + +func (rcv *ost) sketch(graph *dot.Graph, comp Component) { + id := comp.ID + if strings.TrimSpace(comp.ID) == "" { + id = rcv.nextID() + } + + fontColor := "#000000ff" + if fc := strings.TrimSpace(comp.FontColor); fc != "" { + fontColor = fc + } + + fillColor := "#f5f5dcff" + if fc := strings.TrimSpace(comp.FillColor); len(fc) > 0 { + fillColor = fc + } + + cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) + + el := node.New(cl, id, + node.Label(comp.Label, false), + node.Rounded(comp.Rounded), + node.FontColor(fontColor), + node.FillColor(fillColor), + node.Shape("invtrapezium"), + ) + el.Attr("width", "0.6") +} diff --git a/ost_test.go b/ost_test.go new file mode 100644 index 0000000..b7c796e --- /dev/null +++ b/ost_test.go @@ -0,0 +1,39 @@ +package draft + +import ( + "testing" + + "github.com/emicklei/dot" +) + +func TestObjectStoreNextID(t *testing.T) { + tests := []struct { + want string + }{ + {"ost1"}, + {"ost2"}, + {"ost3"}, + {"ost4"}, + } + + s := ost{} + + for _, tt := range tests { + t.Run(tt.want, func(t *testing.T) { + if got := s.nextID(); got != tt.want { + t.Errorf("got [%v] want [%v]", got, tt.want) + } + }) + } +} + +func TestObjectStoreShape(t *testing.T) { + g := dot.NewGraph(dot.Directed) + + sketcher := ost{} + sketcher.sketch(g, Component{}) + + if got, want := flatten(g.String()), `shape="invtrapezium",style="filled"`; !verify(got, want) { + t.Errorf("got [%v] want [%v]", got, want) + } +} diff --git a/pkg/node/node.go b/pkg/node/node.go index 0481309..0d1d760 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -41,23 +41,19 @@ func Rounded(rounded bool) Attribute { } // FillColor sets the node fill color. -func FillColor(color, fallback string) Attribute { +func FillColor(color string) Attribute { return func(el *dot.Node) { if strings.TrimSpace(color) != "" { el.Attr("fillcolor", color) - } else { - el.Attr("fillcolor", fallback) } } } // FontColor specify the text color. -func FontColor(color, fallback string) Attribute { +func FontColor(color string) Attribute { return func(el *dot.Node) { if strings.TrimSpace(color) != "" { el.Attr("fontcolor", color) - } else { - el.Attr("fontcolor", fallback) } } } diff --git a/pkg/node/node_test.go b/pkg/node/node_test.go index faad68e..1b9a19f 100644 --- a/pkg/node/node_test.go +++ b/pkg/node/node_test.go @@ -17,19 +17,9 @@ func TestDefaultAttributes(t *testing.T) { } } -func TestFontColorFallback(t *testing.T) { - di := dot.NewGraph(dot.Directed) - New(di, "NODE_1", FontColor("", "#000000ff")) - - want := `digraph {n1[fontcolor="#000000ff",fontname="Fira Mono",fontsize="9.00",label="NODE_1",style="filled"];}` - if got := flatten(di.String()); got != want { - t.Errorf("got [%v] want [%v]", got, want) - } -} - func TestFontColor(t *testing.T) { di := dot.NewGraph(dot.Directed) - New(di, "NODE_1", FontColor("#fafafaff", "#000000")) + New(di, "NODE_1", FontColor("#fafafaff")) want := `digraph {n1[fontcolor="#fafafaff",fontname="Fira Mono",fontsize="9.00",label="NODE_1",style="filled"];}` if got := flatten(di.String()); got != want { @@ -37,9 +27,9 @@ func TestFontColor(t *testing.T) { } } -func TestFillColorFallback(t *testing.T) { +func TestFillColor(t *testing.T) { di := dot.NewGraph(dot.Directed) - New(di, "NODE_1", FillColor("", "#ff0000ff")) + New(di, "NODE_1", FillColor("#ff0000ff")) want := `digraph {n1[fillcolor="#ff0000ff",fontname="Fira Mono",fontsize="9.00",label="NODE_1",style="filled"];}` if got := flatten(di.String()); got != want { diff --git a/queue.go b/que.go similarity index 53% rename from queue.go rename to que.go index 5f7020b..6a51a07 100644 --- a/queue.go +++ b/que.go @@ -9,50 +9,51 @@ import ( "github.com/lucasepe/draft/pkg/node" ) -type queue struct { +type que struct { seq int16 } -func (rcv *queue) nextID() string { +func (rcv *que) nextID() string { rcv.seq++ - return fmt.Sprintf("qs%d", rcv.seq) + return fmt.Sprintf("que%d", rcv.seq) } -func (rcv *queue) sketch(graph *dot.Graph, comp Component) { +func (rcv *que) sketch(graph *dot.Graph, comp Component) { id := comp.ID if strings.TrimSpace(comp.ID) == "" { id = rcv.nextID() } - cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) - - el := node.New(cl, id, - node.Rounded(comp.Rounded), - node.FontColor(comp.FontColor, "#000000ff"), - node.FontSize(7), - node.FillColor("", "transparent"), - // ^^^ hack to set a transparent background - // color since we will use the HTML table. - node.Shape("plain"), - ) + fillColor := comp.FillColor + if strings.TrimSpace(comp.FillColor) == "" { + fillColor = "#bdb76bff" + } caption := strings.TrimSpace(comp.Label) if len(caption) == 0 { caption = " " } - fillColor := comp.FillColor - if strings.TrimSpace(comp.FillColor) == "" { - fillColor = "#bdb76bff" - } - - label := fmt.Sprintf(` + label := strings.Replace(`
- - - + + + -
 
msg N...msg 1
msg N...msg 1
%s
`, fillColor, fillColor, fillColor, caption) + `, "{{BGCOLOR}}", fillColor, -1) + + label = fmt.Sprintf(label, caption) - el.Attr("label", dot.HTML(label)) + cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) + + node.New(cl, id, + node.Label(label, true), + node.FontColor("#000000ff"), + node.FontSize(8), + node.FillColor("transparent"), + // ^^^ hack to set a transparent background + // color since we will use the HTML table. + node.Shape("plain"), + ) } diff --git a/queue_test.go b/que_test.go similarity index 63% rename from queue_test.go rename to que_test.go index 28e3c38..52d9618 100644 --- a/queue_test.go +++ b/que_test.go @@ -10,13 +10,13 @@ func TestQueueComponentNextID(t *testing.T) { tests := []struct { want string }{ - {"qs1"}, - {"qs2"}, - {"qs3"}, - {"qs4"}, + {"que1"}, + {"que2"}, + {"que3"}, + {"que4"}, } - s := queue{} + s := que{} for _, tt := range tests { t.Run(tt.want, func(t *testing.T) { @@ -28,10 +28,10 @@ func TestQueueComponentNextID(t *testing.T) { } func TestQueueComponent(t *testing.T) { - want := `label=<
 
msg N...msg 1
 
>,shape="plain"` + want := `label=<
 
msg N...msg 1
 
>` g := dot.NewGraph(dot.Directed) - sketcher := queue{} + sketcher := que{} sketcher.sketch(g, Component{}) if got := flatten(g.String()); !verify(got, want) { diff --git a/service.go b/rdb.go similarity index 58% rename from service.go rename to rdb.go index 146b0d9..45ed131 100644 --- a/service.go +++ b/rdb.go @@ -9,29 +9,30 @@ import ( "github.com/lucasepe/draft/pkg/node" ) -type service struct { +type rdb struct { seq int16 } -func (rcv *service) nextID() string { +func (rcv *rdb) nextID() string { rcv.seq++ - return fmt.Sprintf("ms%d", rcv.seq) + return fmt.Sprintf("rdb%d", rcv.seq) } -func (rcv *service) sketch(graph *dot.Graph, comp Component) { +func (rcv *rdb) sketch(graph *dot.Graph, comp Component) { id := comp.ID if strings.TrimSpace(comp.ID) == "" { id = rcv.nextID() } cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) el := node.New(cl, id, node.Label(comp.Label, false), node.Rounded(comp.Rounded), - node.FontColor(comp.FontColor, "#000000ff"), - node.FillColor(comp.FillColor, "#f5f5dcff"), - node.Shape("doubleoctagon"), + node.FontColor("#000000ff"), + node.FillColor("#f5f5dcff"), + node.Shape("tab"), ) - el.Attr("width", "0.8") + el.Attr("height", "0.5") } diff --git a/database_test.go b/rdb_test.go similarity index 80% rename from database_test.go rename to rdb_test.go index 80f2d6e..80614ab 100644 --- a/database_test.go +++ b/rdb_test.go @@ -10,13 +10,13 @@ func TestDatabaseComponentNextID(t *testing.T) { tests := []struct { want string }{ - {"db1"}, - {"db2"}, - {"db3"}, - {"db4"}, + {"rdb1"}, + {"rdb2"}, + {"rdb3"}, + {"rdb4"}, } - s := database{} + s := rdb{} for _, tt := range tests { t.Run(tt.want, func(t *testing.T) { @@ -28,10 +28,10 @@ func TestDatabaseComponentNextID(t *testing.T) { } func TestDatabaseComponent(t *testing.T) { - want := `shape="cylinder",style="filled"` + want := `shape="tab",style="filled"` g := dot.NewGraph(dot.Directed) - sketcher := database{} + sketcher := rdb{} sketcher.sketch(g, Component{}) if got := flatten(g.String()); !verify(got, want) { diff --git a/ser.go b/ser.go new file mode 100644 index 0000000..6a6cbbe --- /dev/null +++ b/ser.go @@ -0,0 +1,48 @@ +package draft + +import ( + "fmt" + "strings" + + "github.com/emicklei/dot" + "github.com/lucasepe/draft/pkg/cluster" + "github.com/lucasepe/draft/pkg/node" +) + +type ser struct { + seq int16 +} + +func (rcv *ser) nextID() string { + rcv.seq++ + return fmt.Sprintf("ser%d", rcv.seq) +} + +func (rcv *ser) sketch(graph *dot.Graph, comp Component) { + id := comp.ID + if strings.TrimSpace(comp.ID) == "" { + id = rcv.nextID() + } + + fontColor := "#000000ff" + if fc := strings.TrimSpace(comp.FontColor); fc != "" { + fontColor = fc + } + + fillColor := "#f5f5dcff" + if fc := strings.TrimSpace(comp.FillColor); len(fc) > 0 { + fillColor = fc + } + + cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + + el := node.New(cl, id, + node.Label(comp.Label, false), + node.Rounded(comp.Rounded), + node.FontColor(fontColor), + node.FillColor(fillColor), + node.Shape("doubleoctagon"), + ) + el.Attr("width", "0.7") + el.Attr("color", fillColor) +} diff --git a/service_test.go b/ser_test.go similarity index 87% rename from service_test.go rename to ser_test.go index 4e27105..a642ca3 100644 --- a/service_test.go +++ b/ser_test.go @@ -10,13 +10,13 @@ func TestServiceComponentNextID(t *testing.T) { tests := []struct { want string }{ - {"ms1"}, - {"ms2"}, - {"ms3"}, - {"ms4"}, + {"ser1"}, + {"ser2"}, + {"ser3"}, + {"ser4"}, } - s := service{} + s := ser{} for _, tt := range tests { t.Run(tt.want, func(t *testing.T) { @@ -30,7 +30,7 @@ func TestServiceComponentNextID(t *testing.T) { func TestServiceComponent(t *testing.T) { g := dot.NewGraph(dot.Directed) - sketcher := service{} + sketcher := ser{} sketcher.sketch(g, Component{}) if got, want := flatten(g.String()), `shape="doubleoctagon",style="filled"`; !verify(got, want) { diff --git a/waf.go b/waf.go index 1bd93d7..f4a3020 100644 --- a/waf.go +++ b/waf.go @@ -25,11 +25,12 @@ func (rcv *waf) sketch(graph *dot.Graph, comp Component) { } cl := cluster.New(graph, id, cluster.BottomTop(comp.BottomTop()), cluster.Label(comp.Impl)) + guessImpl(&comp, cl) el := node.New(cl, id, - node.Label("FW", false), - node.FontColor(comp.FontColor, "#fafafaff"), - node.FillColor(comp.FillColor, "#f3190b"), + node.Label("WAF", true), + node.FontColor("#fafafaff"), + node.FillColor("#f3190b"), node.Shape("invhouse"), ) el.Attr("width", "0.3") diff --git a/waf_test.go b/waf_test.go index 59b423f..ba41acf 100644 --- a/waf_test.go +++ b/waf_test.go @@ -8,7 +8,7 @@ import ( "github.com/emicklei/dot" ) -func TestWAFComponentNextID(t *testing.T) { +func TestWAFNextID(t *testing.T) { tests := []struct { want string }{ @@ -29,7 +29,7 @@ func TestWAFComponentNextID(t *testing.T) { } } -func TestWAFComponent(t *testing.T) { +func TestWAFShape(t *testing.T) { g := dot.NewGraph(dot.Directed) sketcher := waf{}