Skip to content

Commit

Permalink
feat: Generate a Graphviz DOT diagram of an Organization (#13)
Browse files Browse the repository at this point in the history
### Added

- Adds support for generating a Graphviz diagram of an Organization with the new
  `OrganizationDataBuilder.to_dot()` function
- Adds `DOT` as a supported output format for the `organization dump-all` command

### Changed

- breaking: Renames `organization dump-json` CLI command to `organization dump-all`
  • Loading branch information
timoguin authored Jun 16, 2021
1 parent 848e0c4 commit 4fa1772
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 12 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ the unreleased section to the section for the new release.

No unreleased changes.

### Added

- Adds support for generating a Graphviz diagram of an Organization with the new
`OrganizationDataBuilder.to_dot()` function
- Adds `DOT` as a supported output format for the `organization dump-all` command

### Changed

- breaking: Renames `organization dump-json` CLI command to `organization dump-all`

## [0.1.0-beta2] - 2021-06-16

### Added
Expand Down
30 changes: 30 additions & 0 deletions aws_data_tools/builders/organizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from dataclasses import dataclass, field, InitVar
from typing import Any, Dict, List, Union

from graphviz import Digraph, unflatten

from ..client import APIClient
from ..models.base import ModelBase
from ..utils import query_tags
Expand Down Expand Up @@ -78,6 +80,34 @@ def api(self, func: str, **kwargs) -> Union[List[Dict[str, Any]], Dict[str, Any]
self.Connect()
return self.client.api(func, **kwargs)

def to_dot(self) -> str:
"""Return the organization as a GraphViz DOT diagram"""
graph = Digraph("Organization", filename="organization.dot")
nodes = []
nodes.append(self.dm.root)
nodes.extend(self.dm.organizational_units)
nodes.extend(self.dm.accounts)
for node in nodes:
if getattr(node, "parent", None) is None:
continue
shape = None
if isinstance(node, Root):
shape = "circle"
elif isinstance(node, OrganizationalUnit):
shape = "box"
elif isinstance(node, Account):
shape = "ellipse"
else:
continue
graph.node(node.id, label=node.name, shape=shape)
graph.edge(node.parent.id, node.id)
return unflatten(
graph.source,
stagger=10,
fanout=10,
chain=10,
)

def __e_organization(self) -> Dict[str, str]:
"""Extract org description data from the DescribeOrganization API"""
return self.api("describe_organization").get("organization")
Expand Down
24 changes: 13 additions & 11 deletions aws_data_tools/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ def handle_error(ctx, err_msg, tb=None):


@organization.command(short_help="Dump org data as JSON")
@option(
"--format",
"-f",
"format_",
default="JSON",
type=Choice(["DOT", "JSON", "YAML"], case_sensitive=False),
help="The output format for the data",
)
@option(
"--no-accounts",
default=False,
Expand All @@ -76,24 +84,16 @@ def handle_error(ctx, err_msg, tb=None):
is_flag=True,
help="Exclude policy data from the model",
)
@option(
"--format",
"-f",
"format_",
default="JSON",
type=Choice(["JSON", "YAML"], case_sensitive=False),
help="The output format for the data",
)
@option("--out-file", "-o", help="File path to write data instead of stdout")
@pass_context
def dump_json(
def dump_all(
ctx: Dict[str, Any],
format_: str,
no_accounts: bool,
no_policies: bool,
format_: str,
out_file: str,
) -> None:
"""Dump a JSON representation of the organization"""
"""Dump a data representation of the organization"""
err_msg = None
tb = None
try:
Expand All @@ -114,6 +114,8 @@ def dump_json(
s_func = odb.to_json
elif format_ == "YAML":
s_func = odb.to_yaml
elif format_ == "DOT":
s_func = odb.to_dot
if out_file is None:
out_file = "-"
with open_file(out_file, mode="wb") as f:
Expand Down
19 changes: 18 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ mkdocs = {version = "^1.1.2", optional = true, extras = ["docs"]}
mkdocs-git-revision-date-localized-plugin = {version = "^0.9.2", optional = true, extras = ["docs"]}
mkdocs-macros-plugin = {version = "^0.5.5", optional = true, extras = ["docs"]}
mkdocs-material = {version = "^7.1.5", optional = true, extras = ["docs"]}
graphviz = "^0.16"

[tool.poetry.dev-dependencies]
black = "^21.5b1"
Expand Down

0 comments on commit 4fa1772

Please sign in to comment.