Cloud Diagram Suites: Hava, LucidScale and Holori

Published: Sep 12, 2024 by Isaac Johnson

I’ve always had a soft spot for Cloudcraft since I saw it prominently on display at Hashiconf 2018.

/content/images/2024/09/IMG_20181024_134609.jpg

Years ago, I was told by them that “GCP is coming” but it really never happened.

I recently had need for more cloud diagrams and thought it might be a good time to explore our options.

Today we’ll look at Hava (which I learned about from a vendor at a NewRelic user meetup), LusicScale from Lucid, and one I found just by way of a simple search, Holori.

I’ll look at the major clouds and terraform, but also generally focus on GCP as that is where I do most of my work presently. We’ll wrap with costs and touch on terraform to Graphviz.

Hava

We can signup for a new account at hava.io.

/content/images/2024/08/hava-01.png

Let’s now add an environment.

/content/images/2024/08/hava-02.png

Actually, that loaded a demo env, which was not what i wanted

/content/images/2024/08/hava-03.png

Instead, I’m going to add a Source and choose Google

/content/images/2024/08/hava-04.png

I need to create an SA and get it’s JSON for this:

$ gcloud iam service-accounts create havareadonly --display-name "HavaReadOnly" --project myanthosproject2
Created service account [havareadonly].

$ gcloud projects add-iam-policy-binding myanthosproject2 \
    --member serviceAccount:havareadonly@myanthosproject2.iam.gserviceaccount.com \
    --role roles/viewer
    Updated IAM policy for project [myanthosproject2].
bindings:
- members:
... snip ...

Lastly, i need to download the JSON key

$ gcloud iam service-accounts keys create key.json --iam-account havareadonly@myanthosproject2.iam.gserviceaccount.com
created key [4c788b065ca222755f50f9b7170b9a08cabc3120] of type [json] as [key.json] for [havareadonly@myanthosproject2.iam.gserviceaccount.com]

this saved a key.json locally so i’ll move that to windows so I can upload it to hava

builder@DESKTOP-QADGF36:~$ ls -ltra | tail -n1
-rw-------   1 builder builder      2366 Jul 31 08:20 key.json
builder@DESKTOP-QADGF36:~$ cp ./key.json /mnt/c/Users/isaac/Downloads/hava-key.json

I can now import it into Hava

/content/images/2024/08/hava-05.png

Which shows that Sync is now Queued

/content/images/2024/08/hava-06.png

It’s not perfect, but we get a general overview of our cloud resources with connections setup for our Dapr Services

/content/images/2024/08/hava-07.png

A Month later

I came back a month later to get an idea on costs.

Monthly it is $249

/content/images/2024/08/hava-08.png

or $2388/year

/content/images/2024/08/hava-09.png

LucidScale

A suite I use professionally is Lucidchart for diagrams.

They also have Lucidscale which should import diagrams of our cloud

/content/images/2024/08/lucid-01.png

It’s only a bit cheaper than Hava at $2000/year

/content/images/2024/08/lucid-02.png

I’ll create a new account

/content/images/2024/08/lucid-03.png

Once created, I can start with a given cloud. I’ll choose GCP for this

/content/images/2024/08/lucid-04.png

I get past more survey prompts

/content/images/2024/08/lucid-05.png

I’ll spare you the clippy-style wizard walk through, but I did like the fact I could easily kick this over to Lucidchart

/content/images/2024/08/lucid-06.png

I’m going to go to GCP and “Import New Project”

/content/images/2024/08/lucid-07.png

I’ll start with the GCP Service Account

/content/images/2024/08/lucid-08.png

In IAM, I’ll create a new SA for Lucidscale

/content/images/2024/08/lucid-09.png

I’ll grant “Viewer” from the Basic list

/content/images/2024/08/lucid-10.png

I don’t need to add anyone else for the “Grant users”, so I can click Done on the last step

/content/images/2024/08/lucid-11.png

I’ll now find it in the list of SAs and click “Manage keys” from the “…” menu

/content/images/2024/08/lucid-12.png

Click the “Add Key” drop down and choose to create a new key

/content/images/2024/08/lucid-13.png

We’ll leave the default “JSON” and click create

/content/images/2024/08/lucid-14.png

Back in my Lucidscale page, I can now import that downloaded JSON file and click next

/content/images/2024/08/lucid-15.png

I also need to verify the “Cloud Resource Manager API” is enabled

/content/images/2024/08/lucid-16.png

Note: Once I fixed that API, i could see it show up on the right in the Credentials tab

/content/images/2024/08/lucid-17.png

And it also was now listed in the “Projects to import” page (was blank prior)

/content/images/2024/08/lucid-18.png

I’ll leave all the types selected then choose to “Import GCP Projects”

/content/images/2024/08/lucid-19.png

I then see notices that is importing on the bottom right

/content/images/2024/08/lucid-20.png

I did see a note that not all my resources were imported

/content/images/2024/08/lucid-21.png

I guess only BigTable was missed (could be a lack of an API as I don’t use BigTable in this project)

/content/images/2024/08/lucid-22.png

I can now create a new model, and choose the project

/content/images/2024/08/lucid-23.png

Only a few were checked, but I wanted to see it all so I checked all the types of documentation

/content/images/2024/08/lucid-24.png

This kicked off another run

/content/images/2024/08/lucid-25.png

It created an “Untitled GCP Project” diagram

I love Lucid because I can fetch out details from metadata, something I sorely miss when having to use Miro

/content/images/2024/08/lucid-26.png

This is handy from an InfoSec point of view since I can, for example, look at the Firewall rules and see I (foolishly) left open 3389 (RDP) and 22 (SSH) for the world (0.0.0.0/0)

/content/images/2024/08/lucid-27.png

In the “Compliance Insights” we can see this even more clearly with our rules listed out in the diagram

/content/images/2024/08/lucid-28.png

Since this project is empty (at the moment), there is not much to say for Cost Savings, GKE Clusters or Infrastructure. But I can show the Network Topology view which, again, shows clearly those open rules for RDP and SSH

/content/images/2024/08/lucid-29.png

I can update the Chart at any time

/content/images/2024/09/lucid-01.png

Azure

Let’s pull in our P-A-Y-G subscription from Azure.

We’ll use “New Subscription” under Data Hub/Azure

/content/images/2024/09/lucid-02.png

Next, I’ll use Azure AD

/content/images/2024/09/lucid-03.png

I’ll click “Register AD Application”

/content/images/2024/09/lucid-04.png

I’ll name it “LucidImport” and click Register

/content/images/2024/09/lucid-05.png

I’ll search it up under All Applications in EntraAD (AAD)

/content/images/2024/09/lucid-06.png

Three of the four values Lucid desires we can copy from the Application page in Azure

/content/images/2024/09/lucid-07.png

You’ll need to go to “Certificates & Secrets” to generate the Client secret

/content/images/2024/09/lucid-08.png

At first I saw no subscriptions, but that is because I skipped the step to assign a role

/content/images/2024/09/lucid-09.png

I’ll just go to Subscriptions, pick my Subscription and assign Roles to add the “Reader” role to LucidImport

/content/images/2024/09/lucid-10.png

After I closed and re-opened the Azure Subscription import in LucidScale, I could see my subscription

/content/images/2024/09/lucid-11.png

I can select everything Lucid can diagram

/content/images/2024/09/lucid-12.png

And click Import to start the process

/content/images/2024/09/lucid-13.png

After import, I need to create a Model from the imported data if I want to view it

/content/images/2024/09/lucid-14.png

As before, I’ll ask for all of the types of documentation

/content/images/2024/09/lucid-15.png

which kicks off a diagraming run

/content/images/2024/09/lucid-16.png

Holori

Let’s look at one more - Holori. They have a decent free option and their pricing seems reasonable.

I opted to signup with Google and the first screen we encounter is the basic “tell us more about you” page

/content/images/2024/09/holori-01.png

The next screen caught my eye because it prompted me to use AWS, GCP or actually upload my OpenToFu files (terraform).

/content/images/2024/09/holori-02.png

I’m super curious how well it can handle TF of various ages. I have a project I whipped up for a client 5 years ago but I still have the Azure Repo with the sample TF handy

/content/images/2024/09/holori-03.png

I’ll download that as a zip

/content/images/2024/09/holori-04.png

I chose to Import from the Zip and it flashed this import screen for just a few seconds

/content/images/2024/09/holori-05.png

Before showing me a “Import” project

/content/images/2024/09/holori-06.png

That is basically right - an Azure AKS cluster with ACR and a logging workspace

/content/images/2024/09/holori-07.png

And they have a nice isometric 3d view as well

/content/images/2024/09/holori-08.png

I gave it a full night to come back on my old Terraform, but it never did render anything

/content/images/2024/09/holori-11.png

I decided to ask Copilot to build me a basic three-tier app in Terraform with some parameters like GKE and CloudRun

/content/images/2024/09/holori-12.png

I created some files with the Copilot answers in a new directory with VS Code

/content/images/2024/09/holori-13.png

I then zipped it and imported it

/content/images/2024/09/holori-14.png

While that one seemed to time out (still waiting), I did pull in the TF from my public GCPIMExample repo.

which rendered it in less than a minute

/content/images/2024/09/holori-15.png

and in 3d

/content/images/2024/09/holori-16.png

Graphviz and Terraform

We can get some basic diagrams using Terraform as wel.

I first need Graphviz if not installed already

builder@DESKTOP-QADGF36:/mnt/c/Users/isaac/Workspaces/TfExample$ sudo apt install graphviz
[sudo] password for builder:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
  aspnetcore-runtime-3.1 aspnetcore-targeting-pack-3.1 aspnetcore-targeting-pack-6.0 dotnet-apphost-pack-3.1 dotnet-apphost-pack-6.0
  dotnet-targeting-pack-3.1 dotnet-targeting-pack-6.0 fluent-bit libappstream-glib8 libdbus-glib-1-2 libfwupdplugin1 liblttng-ust-ctl4
  liblttng-ust0 libxmlb1 python3-crcmod td-agent-bit
Use 'sudo apt autoremove' to remove them.
The following additional packages will be installed:
  fonts-liberation libann0 libcdt5 libcgraph6 libgts-0.7-5 libgts-bin libgvc6 libgvpr2 liblab-gamut1 libpathplan4
Suggested packages:
  graphviz-doc
The following NEW packages will be installed:
  fonts-liberation graphviz libann0 libcdt5 libcgraph6 libgts-0.7-5 libgts-bin libgvc6 libgvpr2 liblab-gamut1 libpathplan4
0 upgraded, 11 newly installed, 0 to remove and 0 not upgraded.
Need to get 2701 kB of archives.
After this operation, 11.3 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 http://archive.ubuntu.com/ubuntu focal/main amd64 fonts-liberation all 1:1.07.4-11 [822 kB]
Get:2 http://archive.ubuntu.com/ubuntu focal/universe amd64 libann0 amd64 1.1.2+doc-7build1 [26.0 kB]
Get:3 http://archive.ubuntu.com/ubuntu focal/universe amd64 libcdt5 amd64 2.42.2-3build2 [18.7 kB]
Get:4 http://archive.ubuntu.com/ubuntu focal/universe amd64 libcgraph6 amd64 2.42.2-3build2 [41.3 kB]
Get:5 http://archive.ubuntu.com/ubuntu focal/universe amd64 libgts-0.7-5 amd64 0.7.6+darcs121130-4 [150 kB]
Get:6 http://archive.ubuntu.com/ubuntu focal/universe amd64 libpathplan4 amd64 2.42.2-3build2 [21.9 kB]
Get:7 http://archive.ubuntu.com/ubuntu focal/universe amd64 libgvc6 amd64 2.42.2-3build2 [647 kB]
Get:8 http://archive.ubuntu.com/ubuntu focal/universe amd64 libgvpr2 amd64 2.42.2-3build2 [167 kB]
Get:9 http://archive.ubuntu.com/ubuntu focal/universe amd64 liblab-gamut1 amd64 2.42.2-3build2 [177 kB]
Get:10 http://archive.ubuntu.com/ubuntu focal/universe amd64 graphviz amd64 2.42.2-3build2 [590 kB]
Get:11 http://archive.ubuntu.com/ubuntu focal/universe amd64 libgts-bin amd64 0.7.6+darcs121130-4 [41.3 kB]
Fetched 2701 kB in 1s (4435 kB/s)
Selecting previously unselected package fonts-liberation.
(Reading database ... 239202 files and directories currently installed.)
Preparing to unpack .../00-fonts-liberation_1%3a1.07.4-11_all.deb ...
Unpacking fonts-liberation (1:1.07.4-11) ...
Selecting previously unselected package libann0.
Preparing to unpack .../01-libann0_1.1.2+doc-7build1_amd64.deb ...
Unpacking libann0 (1.1.2+doc-7build1) ...
Selecting previously unselected package libcdt5:amd64.
Preparing to unpack .../02-libcdt5_2.42.2-3build2_amd64.deb ...
Unpacking libcdt5:amd64 (2.42.2-3build2) ...
Selecting previously unselected package libcgraph6:amd64.
Preparing to unpack .../03-libcgraph6_2.42.2-3build2_amd64.deb ...
Unpacking libcgraph6:amd64 (2.42.2-3build2) ...
Selecting previously unselected package libgts-0.7-5:amd64.
Preparing to unpack .../04-libgts-0.7-5_0.7.6+darcs121130-4_amd64.deb ...
Unpacking libgts-0.7-5:amd64 (0.7.6+darcs121130-4) ...
Selecting previously unselected package libpathplan4:amd64.
Preparing to unpack .../05-libpathplan4_2.42.2-3build2_amd64.deb ...
Unpacking libpathplan4:amd64 (2.42.2-3build2) ...
Selecting previously unselected package libgvc6.
Preparing to unpack .../06-libgvc6_2.42.2-3build2_amd64.deb ...
Unpacking libgvc6 (2.42.2-3build2) ...
Selecting previously unselected package libgvpr2:amd64.
Preparing to unpack .../07-libgvpr2_2.42.2-3build2_amd64.deb ...
Unpacking libgvpr2:amd64 (2.42.2-3build2) ...
Selecting previously unselected package liblab-gamut1:amd64.
Preparing to unpack .../08-liblab-gamut1_2.42.2-3build2_amd64.deb ...
Unpacking liblab-gamut1:amd64 (2.42.2-3build2) ...
Selecting previously unselected package graphviz.
Preparing to unpack .../09-graphviz_2.42.2-3build2_amd64.deb ...
Unpacking graphviz (2.42.2-3build2) ...
Selecting previously unselected package libgts-bin.
Preparing to unpack .../10-libgts-bin_0.7.6+darcs121130-4_amd64.deb ...
Unpacking libgts-bin (0.7.6+darcs121130-4) ...
Setting up liblab-gamut1:amd64 (2.42.2-3build2) ...
Setting up libgts-0.7-5:amd64 (0.7.6+darcs121130-4) ...
Setting up libpathplan4:amd64 (2.42.2-3build2) ...
Setting up libann0 (1.1.2+doc-7build1) ...
Setting up fonts-liberation (1:1.07.4-11) ...
Setting up libcdt5:amd64 (2.42.2-3build2) ...
Setting up libcgraph6:amd64 (2.42.2-3build2) ...
Setting up libgts-bin (0.7.6+darcs121130-4) ...
Setting up libgvc6 (2.42.2-3build2) ...
Setting up libgvpr2:amd64 (2.42.2-3build2) ...
Setting up graphviz (2.42.2-3build2) ...
Processing triggers for libc-bin (2.31-0ubuntu9.16) ...
/sbin/ldconfig.real: /usr/lib/wsl/lib/libcuda.so.1 is not a symbolic link

Processing triggers for man-db (2.9.1-1) ...
Processing triggers for fontconfig (2.13.1-2ubuntu3) ...

I can then dump a plan to a graphviz digram

builder@DESKTOP-QADGF36:/mnt/c/Users/isaac/Workspaces/TfExample$ terraform graph -type=plan | dot -Tpng > graph.png

/content/images/2024/09/graphviz-01.png

The raw output looks easy enough to manipulate. Here is a different TF repo with raw graph output:

builder@DESKTOP-QADGF36:~/Workspaces/gcpimexample$ terraform graph -type=plan
digraph {
        compound = "true"
        newrank = "true"
        subgraph "root" {
                "[root] google_container_cluster.primary (expand)" [label = "google_container_cluster.primary", shape = "box"]
                "[root] google_container_node_pool.primary_preemptible_nodes (expand)" [label = "google_container_node_pool.primary_preemptible_nodes", shape = "box"]
                "[root] google_service_account.default (expand)" [label = "google_service_account.default", shape = "box"]
                "[root] google_storage_bucket.auto-expire (expand)" [label = "google_storage_bucket.auto-expire", shape = "box"]
                "[root] google_storage_bucket.default (expand)" [label = "google_storage_bucket.default", shape = "box"]
                "[root] provider[\"registry.terraform.io/hashicorp/google\"]" [label = "provider[\"registry.terraform.io/hashicorp/google\"]", shape = "diamond"]
                "[root] provider[\"registry.terraform.io/hashicorp/random\"]" [label = "provider[\"registry.terraform.io/hashicorp/random\"]", shape = "diamond"]
                "[root] random_id.bucket_prefix (expand)" [label = "random_id.bucket_prefix", shape = "box"]
                "[root] var.bucketname" [label = "var.bucketname", shape = "note"]
                "[root] var.projectid" [label = "var.projectid", shape = "note"]
                "[root] google_container_cluster.primary (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/google\"]"
                "[root] google_container_cluster.primary (expand)" -> "[root] var.projectid"
                "[root] google_container_node_pool.primary_preemptible_nodes (expand)" -> "[root] google_container_cluster.primary (expand)"
                "[root] google_container_node_pool.primary_preemptible_nodes (expand)" -> "[root] google_service_account.default (expand)"
                "[root] google_service_account.default (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/google\"]"
                "[root] google_service_account.default (expand)" -> "[root] var.projectid"
                "[root] google_storage_bucket.auto-expire (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/google\"]"
                "[root] google_storage_bucket.auto-expire (expand)" -> "[root] var.bucketname"
                "[root] google_storage_bucket.auto-expire (expand)" -> "[root] var.projectid"
                "[root] google_storage_bucket.default (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/google\"]"
                "[root] google_storage_bucket.default (expand)" -> "[root] random_id.bucket_prefix (expand)"
                "[root] google_storage_bucket.default (expand)" -> "[root] var.projectid"
                "[root] provider[\"registry.terraform.io/hashicorp/google\"] (close)" -> "[root] google_container_node_pool.primary_preemptible_nodes (expand)"
                "[root] provider[\"registry.terraform.io/hashicorp/google\"] (close)" -> "[root] google_storage_bucket.auto-expire (expand)"
                "[root] provider[\"registry.terraform.io/hashicorp/google\"] (close)" -> "[root] google_storage_bucket.default (expand)"
                "[root] provider[\"registry.terraform.io/hashicorp/random\"] (close)" -> "[root] random_id.bucket_prefix (expand)"
                "[root] random_id.bucket_prefix (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/random\"]"
                "[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/google\"] (close)"
                "[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/random\"] (close)"
        }
}

Pricing

Let’s first look at LucidScale which does all three major clouds. I really just see an annual option for $2000/year (avg $167/mo)

/content/images/2024/09/lucid-17.png

Hava, as we mentioned earlier is $249/mo

/content/images/2024/09/hava-01.png

or $2390/annually

/content/images/2024/09/hava-02.png

Cloudcraft has continued to tweak pricing post-Datadog acquisition. I was told that GCP was coming, but that was a long time ago and I still don’t see it. It’s $99/mo or $490/year (averages $40.83/mo if paid annually).

/content/images/2024/09/cloudcraft-01.png

Holori Pricing is the cheapest at $49/mo or $470/year. Since this is on-par with CloudCraft, if Cloudcraft would get GCP support out the door, it would be a close call

/content/images/2024/09/holori-09.png

/content/images/2024/09/holori-10.png

We also have to consider Holori has Terraform/OpenToFu support.

Summary

Today we looked at a few cloud diagramming solutions such as Hava.io, LucidScale and Holori. The other big one out there is CloudCraft.co, but as they still do not support GCP, I didn’t explore it this time.

The fact that Lucid and Hava time out and then are locked down until one pays a very large sum mean I likely won’t come back, even if I think LucidScale is amazing (i would need some cheaper plan than $2000). However, Holori with it’s very reasonable free tier and $50/mo - I could easily see myself turning it on for a month or two to build a series of presentations.

If CloudCraft had a more reasonable per-month, I would consider it, but the lack of GCP is a real hassle (I have created GCP Diagrams in Cloudcraft manually just because I like it’s Isometric view).

Lastly, I touched on Graphviz. In July I did a whole post about Python Diagrams and Graphviz which I still use today. I’ve also written posts on MermaidJS which is natively supported in various GIT tooling including Azure Repos and Github. Graphviz, Python Diagrams (an extension thereof), and MermaidJS are nice open standards to “build it yourself”.

Cloud Diagram Hava CloudCraft Lucid LucidScale Holori GCP Azure

Have something to add? Feedback? You can use the feedback form

Isaac Johnson

Isaac Johnson

Cloud Solutions Architect

Isaac is a CSA and DevOps engineer who focuses on cloud migrations and devops processes. He also is a dad to three wonderful daughters (hence the references to Princess King sprinkled throughout the blog).

Theme built by C.S. Rhymes