Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
*.json
*.exe
!example/example.json
!example/example.drawio
!example/example.drawio
.cloudsketch
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,15 @@ Ensure the executable has been added to your PATH, and run it with the ID of the
```terminal
cloudsketch <subscription_id>
```

## Filtering unwanted resource

To remove unwanted resources from the final diagram, it is possible to provide a configuration file that must be placed in the same directory as the Cloudsketch executable. This configuration file must be called `.cloudsketch.json` and should be structured as follows:

```json
{
"blacklist": []
}
```

In the `blacklist` property it is possible to specify resources that should not be included in the final diagram. Accepted values can be found [here](https://github.com/fremartini/cloudsketch/blob/main/internal/drawio/types/types.go)
15 changes: 15 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package config

import "cloudsketch/internal/marshall"

const (
CONFIG_FILE = ".cloudsketch.json"
)

type config struct {
Blacklist []string
}

func Read() (*config, bool) {
return marshall.UnmarshalIfExists[config](CONFIG_FILE)
}
39 changes: 28 additions & 11 deletions internal/drawio/drawio.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package drawio

import (
"cloudsketch/internal/config"
"cloudsketch/internal/datastructures/build_graph"
"cloudsketch/internal/datastructures/set"
"cloudsketch/internal/drawio/handlers/ai_services"
"cloudsketch/internal/drawio/handlers/app_service"
"cloudsketch/internal/drawio/handlers/app_service_plan"
"cloudsketch/internal/drawio/handlers/application_gateway"
Expand All @@ -23,6 +25,7 @@ import (
"cloudsketch/internal/drawio/handlers/load_balancer_frontend"
"cloudsketch/internal/drawio/handlers/log_analytics"
"cloudsketch/internal/drawio/handlers/logic_app"
"cloudsketch/internal/drawio/handlers/machine_learning_workspace"
"cloudsketch/internal/drawio/handlers/nat_gateway"
"cloudsketch/internal/drawio/handlers/network_interface"
"cloudsketch/internal/drawio/handlers/network_security_group"
Expand All @@ -35,6 +38,7 @@ import (
"cloudsketch/internal/drawio/handlers/recovery_service_vault"
"cloudsketch/internal/drawio/handlers/redis"
"cloudsketch/internal/drawio/handlers/route_table"
"cloudsketch/internal/drawio/handlers/search_service"
"cloudsketch/internal/drawio/handlers/signalr"
"cloudsketch/internal/drawio/handlers/sql_database"
"cloudsketch/internal/drawio/handlers/sql_server"
Expand Down Expand Up @@ -63,6 +67,7 @@ type handler interface {

var (
commands handleFuncMap = handleFuncMap{
ai_services.TYPE: ai_services.New(),
app_service.TYPE: app_service.New(),
app_service_plan.TYPE: app_service_plan.New(),
application_gateway.TYPE: application_gateway.New(),
Expand All @@ -82,6 +87,7 @@ var (
load_balancer_frontend.TYPE: load_balancer_frontend.New(),
log_analytics.TYPE: log_analytics.New(),
logic_app.TYPE: logic_app.New(),
machine_learning_workspace.TYPE: machine_learning_workspace.New(),
nat_gateway.TYPE: nat_gateway.New(),
network_interface.TYPE: network_interface.New(),
network_security_group.TYPE: network_security_group.New(),
Expand All @@ -93,6 +99,7 @@ var (
recovery_service_vault.TYPE: recovery_service_vault.New(),
redis.TYPE: redis.New(),
route_table.TYPE: route_table.New(),
search_service.TYPE: search_service.New(),
signalr.TYPE: signalr.New(),
sql_database.TYPE: sql_database.New(),
sql_server.TYPE: sql_server.New(),
Expand All @@ -113,7 +120,22 @@ func New() *drawio {
return &drawio{}
}

func removeBlacklistedHandlers() {
config, ok := config.Read()

if !ok {
return
}

// remove entries on the blacklist
for _, blacklistedItem := range config.Blacklist {
delete(commands, blacklistedItem)
}
}

func (d *drawio) WriteDiagram(filename string, resources []*models.Resource) error {
removeBlacklistedHandlers()

// at this point only the Azure resources are known - this function adds the corresponding DrawIO icons
resource_map, err := populateResourceMap(resources)

Expand All @@ -135,14 +157,9 @@ func (d *drawio) WriteDiagram(filename string, resources []*models.Resource) err
allResources = append(allResources, resource)
}

// private endpoints and NICs are typically used as icons attached to other icons and should therefore be rendered in front
// TODO: implement a better solution?
allResourcesThatShouldGoInBack := list.Filter(allResources, func(n *node.ResourceAndNode) bool {
return n.Resource.Type != types.PRIVATE_ENDPOINT && n.Resource.Type != types.NETWORK_INTERFACE && n.Resource.Type != types.PUBLIC_IP_ADDRESS
})

allResourcesThatShouldGoInFront := list.Filter(allResources, func(n *node.ResourceAndNode) bool {
return n.Resource.Type == types.PRIVATE_ENDPOINT || n.Resource.Type == types.NETWORK_INTERFACE || n.Resource.Type == types.PUBLIC_IP_ADDRESS
// private endpoints, NICs, PIPs and NSGs are typically used as icons attached to other icons and should therefore be rendered in front of them
allResourcesThatShouldGoInFront, allResourcesThatShouldGoInBack := list.GroupBy(allResources, func(n *node.ResourceAndNode) bool {
return n.Resource.Type == types.PRIVATE_ENDPOINT || n.Resource.Type == types.NETWORK_INTERFACE || n.Resource.Type == types.PUBLIC_IP_ADDRESS || n.Resource.Type == types.NETWORK_SECURITY_GROUP
})

allResources = append(allResourcesThatShouldGoInBack, allResourcesThatShouldGoInFront...)
Expand Down Expand Up @@ -296,16 +313,16 @@ func addBoxes(resource_map *map[string]*node.ResourceAndNode) []*node.Node {
})

// virtual netwoks and subnets needs to be handled last since they "depend" on all other resources
subnets := DrawGroupForResourceType(resources, types.SUBNET, resource_map)
vnets := DrawGroupForResourceType(resources, types.VIRTUAL_NETWORK, resource_map)
subnets := drawGroupForResourceType(resources, types.SUBNET, resource_map)
vnets := drawGroupForResourceType(resources, types.VIRTUAL_NETWORK, resource_map)

// return vnets first so they are rendered in the background
nodes := append(vnets, append(subnets, boxes...)...)

return nodes
}

func DrawGroupForResourceType(resources []*models.Resource, typ string, resource_map *map[string]*node.ResourceAndNode) []*node.Node {
func drawGroupForResourceType(resources []*models.Resource, typ string, resource_map *map[string]*node.ResourceAndNode) []*node.Node {
nodes := []*node.Node{}

resourcesWithType := list.Filter(resources, func(r *models.Resource) bool {
Expand Down
46 changes: 46 additions & 0 deletions internal/drawio/handlers/ai_services/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package ai_services

import (
"cloudsketch/internal/drawio/handlers/node"
"cloudsketch/internal/drawio/images"
"cloudsketch/internal/drawio/models"
"cloudsketch/internal/drawio/types"
)

type handler struct{}

const (
TYPE = types.AI_SERVICES
IMAGE = images.AI_SERVICES
WIDTH = 64
HEIGHT = 68
)

func New() *handler {
return &handler{}
}

func (*handler) MapResource(resource *models.Resource) *node.Node {
geometry := node.Geometry{
X: 0,
Y: 0,
Width: WIDTH,
Height: HEIGHT,
}

link := resource.GetLinkOrDefault()

return node.NewIcon(IMAGE, resource.Name, &geometry, link)
}

func (*handler) PostProcessIcon(resource *node.ResourceAndNode, resource_map *map[string]*node.ResourceAndNode) *node.Node {
return nil
}

func (*handler) DrawDependency(source *models.Resource, targets []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Arrow {
return node.DrawDependencyArrowsToTarget(source, targets, resource_map, []string{})
}

func (*handler) GroupResources(_ *models.Resource, resources []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Node {
return []*node.Node{}
}
24 changes: 1 addition & 23 deletions internal/drawio/handlers/app_service/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,7 @@ func (*handler) PostProcessIcon(resource *node.ResourceAndNode, resource_map *ma
}

func (*handler) DrawDependency(source *models.Resource, targets []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Arrow {
arrows := []*node.Arrow{}

sourceNode := (*resource_map)[source.Id].Node

for _, target := range targets {
// don't draw arrows to subnets
if target.Type == types.SUBNET {
continue
}

targetNode := (*resource_map)[target.Id].Node

// if they are in the same group, don't draw the arrow
if sourceNode.ContainedIn != nil && targetNode.ContainedIn != nil {
if sourceNode.GetParentOrThis() == targetNode.GetParentOrThis() {
continue
}
}

arrows = append(arrows, node.NewArrow(sourceNode.Id(), targetNode.Id(), nil))
}

return arrows
return node.DrawDependencyArrowsToTarget(source, targets, resource_map, []string{types.SUBNET})
}

func (*handler) GroupResources(_ *models.Resource, resources []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Node {
Expand Down
18 changes: 2 additions & 16 deletions internal/drawio/handlers/app_service_plan/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,8 @@ func (*handler) PostProcessIcon(resource *node.ResourceAndNode, resource_map *ma
}

func (*handler) DrawDependency(source *models.Resource, targets []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Arrow {
arrows := []*node.Arrow{}

sourceId := (*resource_map)[source.Id].Node.Id()

for _, target := range targets {
// app service plans have an implicit dependency to a subnet. Don't draw these
if target.Type == types.SUBNET {
continue
}

targetId := (*resource_map)[target.Id].Node.Id()

arrows = append(arrows, node.NewArrow(sourceId, targetId, nil))
}

return arrows
// app service plans have an implicit dependency to a subnet. Don't draw these
return node.DrawDependencyArrowsToTarget(source, targets, resource_map, []string{types.SUBNET})
}

func (*handler) GroupResources(appServicePlan *models.Resource, resources []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Node {
Expand Down
23 changes: 1 addition & 22 deletions internal/drawio/handlers/application_gateway/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,28 +54,7 @@ func (*handler) PostProcessIcon(resource *node.ResourceAndNode, resource_map *ma
}

func (*handler) DrawDependency(source *models.Resource, targets []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Arrow {
arrows := []*node.Arrow{}

sourceId := (*resource_map)[source.Id].Node.Id()

for _, target := range targets {
// don't draw arrows to subnets
if target.Type == types.SUBNET {
continue
}

// don't draw arrows to public ips
if target.Type == types.PUBLIC_IP_ADDRESS {
continue
}

targetId := (*resource_map)[target.Id].Node.Id()

arrows = append(arrows, node.NewArrow(sourceId, targetId, nil))
}

return arrows

return node.DrawDependencyArrowsToTarget(source, targets, resource_map, []string{types.SUBNET, types.PUBLIC_IP_ADDRESS})
}

func (*handler) GroupResources(_ *models.Resource, resources []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Node {
Expand Down
12 changes: 1 addition & 11 deletions internal/drawio/handlers/application_insights/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,7 @@ func (*handler) PostProcessIcon(resource *node.ResourceAndNode, resource_map *ma
}

func (*handler) DrawDependency(source *models.Resource, targets []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Arrow {
arrows := []*node.Arrow{}

sourceId := (*resource_map)[source.Id].Node.Id()

for _, target := range targets {
targetId := (*resource_map)[target.Id].Node.Id()

arrows = append(arrows, node.NewArrow(sourceId, targetId, nil))
}

return arrows
return node.DrawDependencyArrowsToTarget(source, targets, resource_map, []string{})
}

func (*handler) GroupResources(_ *models.Resource, resources []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Node {
Expand Down
13 changes: 1 addition & 12 deletions internal/drawio/handlers/application_security_group/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,7 @@ func (*handler) PostProcessIcon(resource *node.ResourceAndNode, resource_map *ma
}

func (*handler) DrawDependency(source *models.Resource, targets []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Arrow {
arrows := []*node.Arrow{}

sourceId := (*resource_map)[source.Id].Node.Id()

for _, target := range targets {

targetId := (*resource_map)[target.Id].Node.Id()

arrows = append(arrows, node.NewArrow(sourceId, targetId, nil))
}

return arrows
return node.DrawDependencyArrowsToTarget(source, targets, resource_map, []string{})
}

func (*handler) GroupResources(_ *models.Resource, resources []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Node {
Expand Down
22 changes: 1 addition & 21 deletions internal/drawio/handlers/bastion/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,27 +54,7 @@ func (*handler) PostProcessIcon(resource *node.ResourceAndNode, resource_map *ma
}

func (*handler) DrawDependency(source *models.Resource, targets []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Arrow {
arrows := []*node.Arrow{}

sourceId := (*resource_map)[source.Id].Node.Id()

for _, target := range targets {
// don't draw arrows to subnets
if target.Type == types.SUBNET {
continue
}

// don't draw arrows to public ips
if target.Type == types.PUBLIC_IP_ADDRESS {
continue
}

targetId := (*resource_map)[target.Id].Node.Id()

arrows = append(arrows, node.NewArrow(sourceId, targetId, nil))
}

return arrows
return node.DrawDependencyArrowsToTarget(source, targets, resource_map, []string{types.SUBNET, types.PUBLIC_IP_ADDRESS})
}

func (*handler) GroupResources(_ *models.Resource, resources []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Node {
Expand Down
12 changes: 1 addition & 11 deletions internal/drawio/handlers/container_registry/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,7 @@ func (*handler) PostProcessIcon(resource *node.ResourceAndNode, resource_map *ma
}

func (*handler) DrawDependency(source *models.Resource, targets []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Arrow {
arrows := []*node.Arrow{}

sourceId := (*resource_map)[source.Id].Node.Id()

for _, target := range targets {
targetId := (*resource_map)[target.Id].Node.Id()

arrows = append(arrows, node.NewArrow(sourceId, targetId, nil))
}

return arrows
return node.DrawDependencyArrowsToTarget(source, targets, resource_map, []string{})
}

func (*handler) GroupResources(_ *models.Resource, resources []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Node {
Expand Down
12 changes: 1 addition & 11 deletions internal/drawio/handlers/cosmos/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,7 @@ func (*handler) PostProcessIcon(resource *node.ResourceAndNode, resource_map *ma
}

func (*handler) DrawDependency(source *models.Resource, targets []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Arrow {
arrows := []*node.Arrow{}

sourceId := (*resource_map)[source.Id].Node.Id()

for _, target := range targets {
targetId := (*resource_map)[target.Id].Node.Id()

arrows = append(arrows, node.NewArrow(sourceId, targetId, nil))
}

return arrows
return node.DrawDependencyArrowsToTarget(source, targets, resource_map, []string{})
}

func (*handler) GroupResources(_ *models.Resource, resources []*models.Resource, resource_map *map[string]*node.ResourceAndNode) []*node.Node {
Expand Down
Loading