From 7b40b5c466da4dcc5fd4cca1f0c9db72df56e8fc Mon Sep 17 00:00:00 2001 From: Matt Moore Date: Wed, 20 Dec 2023 10:20:59 -0500 Subject: [PATCH] Restructure the dashboards to leverage `mosaicLayout` This layout is more cumbersome because of the requirement to explicitly lay things out, however, this change introduces a number of helper modules to make this a bit more tolerable. At a high-level, "sections" (our own intermediate concept) produce groupings of tiles laid out relative to `(0, 0)` with a width of `module.swidth.size` (see below). The modules in `./dashboard/sections` group our "widgets" into arrangements of "tiles" (e.g. logs, http, resources) with several special helper modules: 1. `width`: This module exists to define a global constant for the dashboard width, 1. `collapsible`: This wraps a list of tiles in a "collapsible" region with a title (it automagically figures out the bounding box, to avoid human error here), 1. `layout`: This takes a list of "sections" (defined above) and rebases them so that the `yPos` of each section starts after the preceding section. Signed-off-by: Matt Moore --- dashboard/job/dashboard.tf | 70 ++++----------- dashboard/sections/collapsible/main.tf | 24 +++++ dashboard/sections/http/main.tf | 60 +++++++++++++ dashboard/sections/layout/main.tf | 28 ++++++ dashboard/sections/logs/main.tf | 33 +++++++ dashboard/sections/resources/main.tf | 119 +++++++++++++++++++++++++ dashboard/sections/width/main.tf | 3 + dashboard/service/dashboard.tf | 101 +++++---------------- networking/dns.tf | 10 ++- 9 files changed, 317 insertions(+), 131 deletions(-) create mode 100644 dashboard/sections/collapsible/main.tf create mode 100644 dashboard/sections/http/main.tf create mode 100644 dashboard/sections/layout/main.tf create mode 100644 dashboard/sections/logs/main.tf create mode 100644 dashboard/sections/resources/main.tf create mode 100644 dashboard/sections/width/main.tf diff --git a/dashboard/job/dashboard.tf b/dashboard/job/dashboard.tf index c31216b9..e6f952d9 100644 --- a/dashboard/job/dashboard.tf +++ b/dashboard/job/dashboard.tf @@ -1,49 +1,23 @@ -locals { common_filter = ["resource.type=\"cloud_run_job\""] } - module "logs" { - source = "../widgets/logs" - title = "Service Logs" - filter = local.common_filter -} - -module "cpu_utilization" { - source = "../widgets/xy" - title = "CPU utilization" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/container/cpu/utilizations\""]) - primary_align = "ALIGN_DELTA" - primary_reduce = "REDUCE_MEAN" + source = "../sections/logs" + title = "Job Logs" + filter = ["resource.type=\"cloud_run_job\""] } -module "memory_utilization" { - source = "../widgets/xy" - title = "Memory utilization" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/container/memory/utilizations\""]) - primary_align = "ALIGN_DELTA" - primary_reduce = "REDUCE_MEAN" +module "resources" { + source = "../sections/resources" + title = "Resources" + filter = ["resource.type=\"cloud_run_job\""] } -module "startup_latency" { - source = "../widgets/xy" - title = "Startup latency" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/container/startup_latencies\""]) - primary_align = "ALIGN_DELTA" - primary_reduce = "REDUCE_MEAN" -} +module "width" { source = "../sections/width" } -module "sent_bytes" { - source = "../widgets/xy" - title = "Sent bytes" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/container/network/sent_bytes_count\""]) - primary_align = "ALIGN_MEAN" - primary_reduce = "REDUCE_NONE" -} - -module "received_bytes" { - source = "../widgets/xy" - title = "Received bytes" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/container/network/received_bytes_count\""]) - primary_align = "ALIGN_MEAN" - primary_reduce = "REDUCE_NONE" +module "layout" { + source = "../sections/layout" + sections = [ + module.logs.section, + module.resources.section, + ] } resource "google_monitoring_dashboard" "dashboard" { @@ -54,17 +28,11 @@ resource "google_monitoring_dashboard" "dashboard" { stringValue = var.job_name labelKey = "job_name" }] - // https://cloud.google.com/monitoring/api/ref_v3/rest/v1/projects.dashboards#GridLayout - gridLayout = { - columns = 3 - widgets = [ - module.logs.widget, - module.cpu_utilization.widget, - module.memory_utilization.widget, - module.startup_latency.widget, - module.sent_bytes.widget, - module.received_bytes.widget, - ] + + // https://cloud.google.com/monitoring/api/ref_v3/rest/v1/projects.dashboards#mosaiclayout + mosaicLayout = { + columns = module.width.size + tiles = module.layout.tiles, } }) } diff --git a/dashboard/sections/collapsible/main.tf b/dashboard/sections/collapsible/main.tf new file mode 100644 index 00000000..66a0d3b3 --- /dev/null +++ b/dashboard/sections/collapsible/main.tf @@ -0,0 +1,24 @@ +variable "title" { type = string } +variable "tiles" {} +variable "collapsed" { default = false } + +locals { + start_row = min([for s in var.tiles : s.yPos]...) +} + +module "width" { source = "../width" } + +output "section" { + value = concat([{ + yPos = local.start_row + xPos = 0, + height = max([for s in var.tiles : s.yPos + s.height - local.start_row]...), + width = module.width.size, + widget = { + title = var.title + collapsibleGroup = { + collapsed = var.collapsed + } + }, + }], var.tiles) +} \ No newline at end of file diff --git a/dashboard/sections/http/main.tf b/dashboard/sections/http/main.tf new file mode 100644 index 00000000..7ee26758 --- /dev/null +++ b/dashboard/sections/http/main.tf @@ -0,0 +1,60 @@ +variable "title" { type = string } +variable "filter" { type = list(string) } +variable "collapsed" { default = false } + +module "width" { source = "../width" } + +module "request_count" { + source = "../../widgets/xy" + title = "Request count" + filter = concat(var.filter, ["metric.type=\"run.googleapis.com/request_count\""]) + group_by_fields = ["metric.label.\"response_code_class\""] + primary_align = "ALIGN_RATE" + primary_reduce = "REDUCE_NONE" + secondary_align = "ALIGN_NONE" + secondary_reduce = "REDUCE_SUM" +} + +module "incoming_latency" { + source = "../../widgets/latency" + title = "Incoming request latency" + filter = concat(var.filter, ["metric.type=\"run.googleapis.com/request_latencies\""]) +} + +// TODO(mattmoor): output HTTP charts. + +locals { + columns = 2 + unit = module.width.size / local.columns + + // https://www.terraform.io/language/functions/range + // N columns, unit width each ([0, unit, 2 * unit, ...]) + col = range(0, local.columns * local.unit, local.unit) + + tiles = [{ + yPos = 0 + xPos = local.col[0], + height = local.unit, + width = local.unit, + widget = module.request_count.widget, + }, + { + yPos = 0 + xPos = local.col[1], + height = local.unit, + width = local.unit, + widget = module.incoming_latency.widget, + }] +} + +module "collapsible" { + source = "../collapsible" + + title = var.title + tiles = local.tiles + collapsed = var.collapsed +} + +output "section" { + value = module.collapsible.section +} diff --git a/dashboard/sections/layout/main.tf b/dashboard/sections/layout/main.tf new file mode 100644 index 00000000..e1790616 --- /dev/null +++ b/dashboard/sections/layout/main.tf @@ -0,0 +1,28 @@ +variable "sections" {} + +module "width" { source = "../width" } + +locals { + // The maximum height of a tile in each section. + max_heights = [for s in var.sections : max([for t in s : t.yPos + t.height]...)] + + // The sum of the maximum tile heights in all of the sections prior to this one. + // Note: sum doesn't work on an empty list, so we concatenate with 0 for the base case. + sum_heights = [for s in var.sections : sum(concat([0], slice(local.max_heights, 0, index(var.sections, s))))] + + // Rebase the yPos of each tile in each section to be relative to the top of + // the section, which starts after the topmost tile of the preceding section. + rebased = [for s in var.sections : [ + for t in s : { + yPos = t.yPos + local.sum_heights[index(var.sections, s)] + xPos = t.xPos + height = t.height + width = t.width + widget = t.widget + }] + ] +} + +output "tiles" { + value = concat(local.rebased...) +} \ No newline at end of file diff --git a/dashboard/sections/logs/main.tf b/dashboard/sections/logs/main.tf new file mode 100644 index 00000000..8ec9765b --- /dev/null +++ b/dashboard/sections/logs/main.tf @@ -0,0 +1,33 @@ +variable "title" { type = string } +variable "filter" { type = list(string) } +variable "collapsed" { default = true } + +module "width" { source = "../width" } + +module "logs" { + source = "../../widgets/logs" + title = var.title + filter = var.filter +} + +locals { + tiles = [{ + yPos = 0 + xPos = 0, + height = module.width.size, + width = module.width.size, + widget = module.logs.widget, + }] +} + +module "collapsible" { + source = "../collapsible" + + title = var.title + tiles = local.tiles + collapsed = var.collapsed +} + +output "section" { + value = module.collapsible.section +} diff --git a/dashboard/sections/resources/main.tf b/dashboard/sections/resources/main.tf new file mode 100644 index 00000000..097b144b --- /dev/null +++ b/dashboard/sections/resources/main.tf @@ -0,0 +1,119 @@ +variable "title" { type = string } +variable "filter" { type = list(string) } +variable "collapsed" { default = false } + +module "width" { source = "../width" } + +module "instance_count" { + source = "../../widgets/xy" + title = "Instance count + revisions" + filter = concat(var.filter, ["metric.type=\"run.googleapis.com/container/instance_count\""]) + group_by_fields = ["resource.label.\"revision_name\""] + primary_align = "ALIGN_MEAN" + primary_reduce = "REDUCE_SUM" + plot_type = "STACKED_AREA" +} + +module "cpu_utilization" { + source = "../../widgets/xy" + title = "CPU utilization" + filter = concat(var.filter, ["metric.type=\"run.googleapis.com/container/cpu/utilizations\""]) + primary_align = "ALIGN_DELTA" + primary_reduce = "REDUCE_MEAN" +} + +module "memory_utilization" { + source = "../../widgets/xy" + title = "Memory utilization" + filter = concat(var.filter, ["metric.type=\"run.googleapis.com/container/memory/utilizations\""]) + primary_align = "ALIGN_DELTA" + primary_reduce = "REDUCE_MEAN" +} + +module "startup_latency" { + source = "../../widgets/xy" + title = "Startup latency" + filter = concat(var.filter, ["metric.type=\"run.googleapis.com/container/startup_latencies\""]) + primary_align = "ALIGN_DELTA" + primary_reduce = "REDUCE_MEAN" +} + +module "sent_bytes" { + source = "../../widgets/xy" + title = "Sent bytes" + filter = concat(var.filter, ["metric.type=\"run.googleapis.com/container/network/sent_bytes_count\""]) + primary_align = "ALIGN_MEAN" + primary_reduce = "REDUCE_NONE" +} + +module "received_bytes" { + source = "../../widgets/xy" + title = "Received bytes" + filter = concat(var.filter, ["metric.type=\"run.googleapis.com/container/network/received_bytes_count\""]) + primary_align = "ALIGN_MEAN" + primary_reduce = "REDUCE_NONE" +} + +locals { + columns = 3 + unit = module.width.size / local.columns + + // https://www.terraform.io/language/functions/range + // N columns, unit width each ([0, unit, 2 * unit, ...]) + col = range(0, local.columns * local.unit, local.unit) + + tiles = [{ + yPos = 0, + xPos = local.col[0], + height = local.unit, + width = local.unit, + widget = module.cpu_utilization.widget, + }, + { + yPos = 0, + xPos = local.col[1], + height = local.unit, + width = local.unit, + widget = module.memory_utilization.widget, + }, + { + yPos = 0, + xPos = local.col[2], + height = local.unit, + width = local.unit, + widget = module.instance_count.widget, + }, + { + yPos = local.unit, + xPos = local.col[0], + height = local.unit, + width = local.unit, + widget = module.startup_latency.widget, + }, + { + yPos = local.unit, + xPos = local.col[1], + height = local.unit, + width = local.unit, + widget = module.sent_bytes.widget, + }, + { + yPos = local.unit, + xPos = local.col[2], + height = local.unit, + width = local.unit, + widget = module.received_bytes.widget, + }] +} + +module "collapsible" { + source = "../collapsible" + + title = var.title + tiles = local.tiles + collapsed = var.collapsed +} + +output "section" { + value = module.collapsible.section +} diff --git a/dashboard/sections/width/main.tf b/dashboard/sections/width/main.tf new file mode 100644 index 00000000..db638394 --- /dev/null +++ b/dashboard/sections/width/main.tf @@ -0,0 +1,3 @@ +output "size" { + value = 12 +} \ No newline at end of file diff --git a/dashboard/service/dashboard.tf b/dashboard/service/dashboard.tf index 4f87b722..9386a7fe 100644 --- a/dashboard/service/dashboard.tf +++ b/dashboard/service/dashboard.tf @@ -1,76 +1,30 @@ -locals { common_filter = ["resource.type=\"cloud_run_revision\""] } - module "logs" { - source = "../widgets/logs" + source = "../sections/logs" title = "Service Logs" - filter = local.common_filter -} - -module "request_count" { - source = "../widgets/xy" - title = "Request count" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/request_count\""]) - group_by_fields = ["metric.label.\"response_code_class\""] - primary_align = "ALIGN_RATE" - primary_reduce = "REDUCE_NONE" - secondary_align = "ALIGN_NONE" - secondary_reduce = "REDUCE_SUM" + filter = ["resource.type=\"cloud_run_revision\""] } -module "incoming_latency" { - source = "../widgets/latency" - title = "Incoming request latency" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/request_latencies\""]) +module "http" { + source = "../sections/http" + title = "HTTP" + filter = ["resource.type=\"cloud_run_revision\""] } -module "instance_count" { - source = "../widgets/xy" - title = "Instance count + revisions" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/container/instance_count\""]) - group_by_fields = ["resource.label.\"revision_name\""] - primary_align = "ALIGN_MEAN" - primary_reduce = "REDUCE_SUM" - plot_type = "STACKED_AREA" +module "resources" { + source = "../sections/resources" + title = "Resources" + filter = ["resource.type=\"cloud_run_revision\""] } -module "cpu_utilization" { - source = "../widgets/xy" - title = "CPU utilization" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/container/cpu/utilizations\""]) - primary_align = "ALIGN_DELTA" - primary_reduce = "REDUCE_MEAN" -} - -module "memory_utilization" { - source = "../widgets/xy" - title = "Memory utilization" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/container/memory/utilizations\""]) - primary_align = "ALIGN_DELTA" - primary_reduce = "REDUCE_MEAN" -} +module "width" { source = "../sections/width" } -module "startup_latency" { - source = "../widgets/xy" - title = "Startup latency" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/container/startup_latencies\""]) - primary_align = "ALIGN_DELTA" - primary_reduce = "REDUCE_MEAN" -} - -module "sent_bytes" { - source = "../widgets/xy" - title = "Sent bytes" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/container/network/sent_bytes_count\""]) - primary_align = "ALIGN_MEAN" - primary_reduce = "REDUCE_NONE" -} - -module "received_bytes" { - source = "../widgets/xy" - title = "Received bytes" - filter = concat(local.common_filter, ["metric.type=\"run.googleapis.com/container/network/received_bytes_count\""]) - primary_align = "ALIGN_MEAN" - primary_reduce = "REDUCE_NONE" +module "layout" { + source = "../sections/layout" + sections = [ + module.logs.section, + module.http.section, + module.resources.section, + ] } resource "google_monitoring_dashboard" "dashboard" { @@ -81,20 +35,11 @@ resource "google_monitoring_dashboard" "dashboard" { stringValue = var.service_name labelKey = "service_name" }] - // https://cloud.google.com/monitoring/api/ref_v3/rest/v1/projects.dashboards#GridLayout - gridLayout = { - columns = 3 - widgets = [ - module.logs.widget, - module.request_count.widget, - module.incoming_latency.widget, - module.instance_count.widget, - module.cpu_utilization.widget, - module.memory_utilization.widget, - module.startup_latency.widget, - module.sent_bytes.widget, - module.received_bytes.widget, - ] + + // https://cloud.google.com/monitoring/api/ref_v3/rest/v1/projects.dashboards#mosaiclayout + mosaicLayout = { + columns = module.width.size + tiles = module.layout.tiles, } }) } diff --git a/networking/dns.tf b/networking/dns.tf index 20806a4d..28707f7d 100644 --- a/networking/dns.tf +++ b/networking/dns.tf @@ -1,9 +1,15 @@ +resource "random_string" "suffix" { + length = 4 + upper = false + special = false +} + // Create a special DNS zone attached to the network in which // we will operate our services that reroutes *.run.app to records // that we control. resource "google_dns_managed_zone" "cloud-run-internal" { project = var.project_id - name = "cloud-run-internal" + name = "cloud-run-internal-${random_string.suffix.result}" dns_name = "run.app." description = "This reroutes run.app requests to private.googleapis.com" @@ -32,7 +38,7 @@ resource "google_dns_record_set" "cloud-run-cname" { // to records that we control. resource "google_dns_managed_zone" "private-google-apis" { project = var.project_id - name = "private-google-apis" + name = "private-google-apis-${random_string.suffix.result}" dns_name = "private.googleapis.com." description = "This maps DNS for private.googleapis.com"