dynatrace-oss / terraform-provider-dynatrace

Apache License 2.0
71 stars 33 forks source link

Unable to create multiple custom and predefined filters using "dynatrace_alerting" resource #470

Closed Vijayalakshmi-Yolbhavi closed 5 months ago

Vijayalakshmi-Yolbhavi commented 5 months ago

Describe the bug Unable to create multiple custom and predefined filters using "dynatrace_alerting" resource

Please help with the code which will handle multiple inputs for custom and predefined filters. To Reproduce Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior A clear and concise description of what you expected to happen.

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Smartphone (please complete the following information):

Additional context Add any other context about the problem here.

Dynatrace-Reinhard-Pilz commented 5 months ago

Hello @Vijayalakshmi-Yolbhavi

Do you have an example for the dynatrace_alerting resource you're trying to configure?

Based on your description I've tested out an Alerting Profile that contains multiple filters (code below), and that works out well.

resource "dynatrace_alerting" "Issue470" {
  name = "Issue470"
  filters {
    filter {
      custom {
        description {
          enabled        = true
          case_sensitive = true
          operator       = "CONTAINS"
          value          = "cd"
        }
      }
    }
    filter {
      custom {
        metadata {
          items {
            filter {
              key    = "k2"
              negate = true
              value  = "v2"
            }
            filter {
              key    = "k1"
              negate = false
              value  = "v1"
            }
          }
        }
      }
    }
    filter {
      predefined {
        type   = "PROCESS_NA_HIGH_CONN_FAIL_RATE"
        negate = true
      }
    }
    filter {
      predefined {
        type   = "OSI_HIGH_CPU"
        negate = true
      }
    }
  }
  rules {
    rule {
      delay_in_minutes = 0
      include_mode     = "NONE"
      severity_level   = "AVAILABILITY"
    }
  }
}
Vijayalakshmi-Yolbhavi commented 5 months ago

Hi @Dynatrace-Reinhard-Pilz,

Thanks for your quick response.

I'm using below code for creating the alerting profile. The code is working perfectly for single event filter. I tried making some changes using dynamic block feature but getting too many filter blocks configured and only block allowed. It would be great if you can assist me to overcome this issue.

Thanks, Vijayalakshmi

Code:

resource "dynatrace_alerting" "custom_alert_profile" {
  for_each        = var.dt_alerts
  name            = each.value.name
  management_zone = var.management_zone
  legacy_id       = each.value.legacy_id

  dynamic "filters" {
    for_each = each.value.filters) && length(each.value.filters) > 0 ? [1] : []
    content {
      dynamic "filter" {
        for_each = each.value.filters != null ? each.value.filters : []
        content {
          custom {
            description {
              operator       = try(filter.value.custom.description.operator, "BEGINS_WITH")
              value          = try(filter.value.custom.description.value, null)
              case_sensitive = try(filter.value.custom.description.case_sensitive, false)
              enabled        = try(filter.value.custom.description.enabled, true)
              negate         = try(filter.value.custom.description.negate, false)
            }
            dynamic "metadata" {
              for_each = can(filter.value.custom.metadata) && length(filter.value.custom.metadata) > 0 ? [1] : []
              content {
                dynamic "items" {
                  for_each = filter.value.custom.metadata != null ? filter.value.custom.metadata : []
                  content {
                    filter {
                      key    = try(items.value.key, null)
                      value  = try(items.value.value, null)
                      negate = try(items.value.negate, false)
                    }
                  }
                }
              }
            }
            title {
              operator       = try(filter.value.custom.title.operator, "CONTAINS")
              value          = try(filter.value.custom.title.value, null)
              case_sensitive = try(filter.value.custom.title.case_sensitive, false)
              enabled        = try(filter.value.custom.title.enabled, true)
              negate         = try(filter.value.custom.title.negate, false)
            }
          }
          predefined {
            type   = try(filter.value.predefined.type, null)
            negate = try(filter.value.predefined.negate, false)
          }
        }
      }
    }
  }

  dynamic "rules" {
    for_each = can(each.value.rules) && length(each.value.rules) > 0 ? [1] : []
    content {
      dynamic "rule" {
        for_each = each.value.rules != null ? each.value.rules : []
        content {
          delay_in_minutes = try(rule.value.delay_in_minutes, 0)
          include_mode     = try(rule.value.include_mode, "NONE")
          severity_level   = try(rule.value.severity_level, "CUSTOM_ALERT")
          tags             = try(rule.value.tags, [])
        }
      }
    }
  }
}
Dynatrace-Reinhard-Pilz commented 5 months ago

You didn't include how you're getting to the variable dt_alerts - therefore I had to make a few assumptions and build that structure locally.

The HCL code below produces the dynamic blocks correctly. I didn't put any focus on the rules section, because handling that would work essentially the same way.

One additional note: You were trying to specify the attribute legacy_id. That's actually a computed attribute. You don't have to specify it.

variable "management_zone" {
  type    = string
  default = "########"
}

variable "dt_alerts" {
  type = map(object({
    name = string
    filters = list(object({
      custom = optional(object({
        description = optional(object({
          operator       = optional(string)
          value          = optional(string)
          case_sensitive = optional(bool)
          enabled        = optional(bool)
          negate         = optional(bool)
        }))
        title = optional(object({
          operator       = optional(string)
          value          = optional(string)
          case_sensitive = optional(bool)
          enabled        = optional(bool)
          negate         = optional(bool)
        }))
        metadata = optional(object({
          items = list(object({
            key    = optional(string)
            value  = optional(string)
            negate = optional(bool)
          }))
        }))
      }))
      predefined = optional(object({
        type   = optional(string)
        negate = optional(bool)
      }))
    }))
    rules = list(object({
    }))
  }))
  default = {
    profile = {
      name = "tf_alert_01"
      filters = [
        {
          custom = {
            description = {
              operator = "BEGINS_WITH"
              value    = "something"
            }
            title = {
              operator       = "BEGINS_WITH"
              value          = "something"
              case_sensitive = true
            }
          }
        },
        {
          custom = {
            metadata = {
              items = [
                {
                  key    = "key-a"
                  value  = "value-a"
                  negate = true
                }
              ]
            }
          }
        },
        {
          custom = {
            metadata = {
              items = [
                {
                  key    = "key-b"
                  value  = "value-b"
                  negate = false
                }
              ]
            }
          }
        },
        {
          predefined = {
            type   = "APPLICATION_SLOWDOWN"
            negate = true
          }
        }
      ]
      rules = []
    }
  }
}

resource "dynatrace_alerting" "custom_alert_profile" {
  for_each        = var.dt_alerts
  name            = each.value.name
  management_zone = var.management_zone
  # legacy_id       = each.value.legacy_id

  dynamic "filters" {
    for_each = can(each.value.filters) && length(each.value.filters) > 0 ? [1] : []
    content {
      dynamic "filter" {
        for_each = each.value.filters != null ? each.value.filters : []
        content {
          dynamic "custom" {
            for_each = try(filter.value.custom != null, false) ? [1] : []
            content {
              dynamic "description" {
                for_each = try(filter.value.custom.description != null, false) ? [1] : []
                content {
                  operator       = try(filter.value.custom.description.operator, "BEGINS_WITH")
                  value          = try(filter.value.custom.description.value, null)
                  case_sensitive = try(filter.value.custom.description.case_sensitive, false)
                  enabled        = try(filter.value.custom.description.enabled, true)
                  negate         = try(filter.value.custom.description.negate, false)
                }
              }
              dynamic "metadata" {
                for_each = try(filter.value.custom.metadata != null, false) ? [1] : []
                content {
                  items {
                    dynamic "filter" {
                      for_each = filter.value.custom.metadata.items
                      iterator = item
                      content {
                        key    = try(item.value.key, "")
                        value  = try(item.value.value, "")
                        negate = try(item.value.negate, false)
                      }
                    }
                  }
                }
              }
              dynamic "title" {
                for_each = try(filter.value.custom.title != null, false) ? [1] : []
                content {
                  operator       = try(filter.value.custom.title.operator, "CONTAINS")
                  value          = try(filter.value.custom.title.value, null)
                  case_sensitive = try(filter.value.custom.title.case_sensitive, false)
                  enabled        = try(filter.value.custom.title.enabled, true)
                  negate         = try(filter.value.custom.title.negate, false)
                }
              }
            }
          }
          dynamic "predefined" {
            for_each = try(filter.value.predefined != null, false) ? [1] : []
            content {
              type   = try(filter.value.predefined.type, "no type")
              negate = try(filter.value.predefined.negate, false)
            }
          }
        }
      }
    }
  }

  dynamic "rules" {
    for_each = can(each.value.rules) && length(each.value.rules) > 0 ? [1] : []
    content {
      dynamic "rule" {
        for_each = each.value.rules != null ? each.value.rules : []
        content {
          delay_in_minutes = try(rule.value.delay_in_minutes, 0)
          include_mode     = try(rule.value.include_mode, "NONE")
          severity_level   = try(rule.value.severity_level, "CUSTOM_ALERT")
          tags             = try(rule.value.tags, [])
        }
      }
    }
  }
}