Terraform-provider-kubernetes: data.kubernetes_service fails with Unsupported attribute before it should

Created on 31 Oct 2020  路  8Comments  路  Source: hashicorp/terraform-provider-kubernetes

Terraform Version and Provider Version

Affected Resource(s)

  • Terraform v0.13.5
  • provider registry.terraform.io/hashicorp/aws v3.13.0
  • provider registry.terraform.io/hashicorp/helm v1.3.2
  • provider registry.terraform.io/hashicorp/kubernetes v1.13.3
  • provider registry.terraform.io/hashicorp/vault v2.15.0

Terraform Configuration Files

# some chart that creates a service
resource "helm_release" "some_service" {
  name = "some-service"
  chart = "nginx"
}
data "kubernetes_service" "some_service" {
  metadata {
    name      = "nginx-svc"
    namespace = helm_release.some_service.namespace
  }
}
locals {
  ports_map = {
    for port in data.kubernetes_service.some_service.spec.port :
    port.name => port.port
  }
}
output "nginx_ports" {
  value       = local.ports_map
}

Debug Output

Panic Output

Expected Behavior

Terraform should wait until the helm chart is deployed before reading the data.kubernetes_service data. It might return a null entry for ports or the service might not be created, but I wouldn't expect to see anything until then.

Actual Behavior

Some sort of modeling check is done and an error like

2020-10-31 03:23:09,139 INFO:Running Terraform plan
2020-10-31 03:23:15,939 WARNING:error: b'\nError: Unsupported attribute\n\n  on locals.tf line 16, in locals:\n  16:     for port in data.kubernetes_service.some_service.spec.port :\n\nThis value does not have any attributes.\n\n'
2020-10-31 03:23:15,941 INFO:
2020-10-31 03:23:15,942 ERROR:
Error: Unsupported attribute

  on locals.tf line 16, in locals:
  16:     for port in data.kubernetes_service.some_service.spec.port :

This value does not have any attributes.

occurs during the terraform plan stage

Steps to Reproduce

  1. terraform plan

Important Factoids

helm and kubernetes providers rely on variables and additional data sources (pulling info from EKS API)

2020-10-31T03:36:34.291Z [DEBUG] plugin: plugin process exited: path=.terraform/plugins/registry.terraform.io/hashicorp/kubernetes/1.13.3/linux_amd64/terraform-provider-kubernetes_v1.13.3_x4 pid=122
2020-10-31T03:36:34.291Z [DEBUG] plugin: plugin exited
2020/10/31 03:36:34 [TRACE] [walkValidate] Exiting eval tree: provider["registry.terraform.io/hashicorp/kubernetes"] (close)
2020/10/31 03:36:34 [TRACE] vertex "provider[\"registry.terraform.io/hashicorp/kubernetes\"] (close)": visit complete
2020/10/31 03:36:34 [TRACE] dag/walk: upstream of "root" errored, so skipping

References

https://github.com/hashicorp/terraform-provider-kubernetes/blob/master/kubernetes/data_source_kubernetes_service.go#L58 data.kubernetes_service schema

Community Note

  • Please vote on this issue by adding a 馃憤 reaction to the original issue to help the community and maintainers prioritize this request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment
documentation help wanted

Most helpful comment

I think y'all are correct. Can this be converted to a Documentation issue? The docs for the attributes for the kubernetes_service data source are...kinda bad (no indication spec is a collection, no example of accessing any subattribute from it, weird order that kinda implies port should be at the same level as spec and metadata).

Thanks a ton for your help, though

All 8 comments

I have tried a _lot_ of tricks to defer the local variable assignment or data rendering until post-plan stage, but nothing has worked. If anyone has a trick for simply not having terraform plan fail when (I guess) data.kubernetes_service.svc.spec is empty or missing, that'd probably be fine.

facing the same problem. I was trying to get the IP of an existing service.

Update: data.kubernetes_service.istiocoredns.spec[0]["cluster_ip"] worked for me. apparently spec is a collection

terraform state show data.kubernetes_service.istiocoredns
# data.kubernetes_service.istiocoredns:
data "kubernetes_service" "istiocoredns" {
    id                    = "istio-system/istiocoredns"
    load_balancer_ingress = []
    spec                  = [
        {
            cluster_ip                  = "172.20.174.78"
            external_ips                = []
            external_name               = ""
            external_traffic_policy     = ""
            health_check_node_port      = 0
            load_balancer_ip            = ""
            load_balancer_source_ranges = []
            port                        = [
                {
                    name        = "dns"
                    node_port   = 0
                    port        = 53
                    protocol    = "UDP"
                    target_port = "53"
                },
                {
                    name        = "dns-tcp"
                    node_port   = 0
                    port        = 53
                    protocol    = "TCP"
                    target_port = "53"
                },
            ]
            publish_not_ready_addresses = false
            selector                    = {
                "app" = "istiocoredns"
            }
            session_affinity            = "None"
            type                        = "ClusterIP"
        },
    ]

    metadata {
        annotations      = {}
        generation       = 0
        labels           = {
            "app"                                                 = "istiocoredns"
            "install.operator.istio.io/owning-resource"           = "default"
            "install.operator.istio.io/owning-resource-namespace" = "istio-system"
            "istio.io/rev"                                        = "default"
            "operator.istio.io/component"                         = "AddonComponents"
            "operator.istio.io/managed"                           = "Reconcile"
            "operator.istio.io/version"                           = "1.7.3"
            "release"                                             = "istio"
        }
        name             = "istiocoredns"
        namespace        = "istio-system"
        resource_version = "1822"
        self_link        = "/api/v1/namespaces/istio-system/services/istiocoredns"
        uid              = "274de930-7b2b-4357-b525-1a300a15e12c"
    }
}

@mariadb-JeffBachtel does it work if you try adding the 0 after spec, like @ishansd94 showed us? That worked for me.

Here is the reproducer I used, which includes a resource containing a spec (the contents are unknown until after terraform plan):

resource "kubernetes_persistent_volume_claim" "test" {
  metadata {
    name = "testpv"
  }
  spec {
    access_modes = ["ReadWriteOnce"]
    resources {
      requests = {
        storage = "1Gi"
      }
    }
  }
}

data "kubernetes_persistent_volume_claim" "test" {
  metadata {
    name      = kubernetes_persistent_volume_claim.test.metadata[0].name
  }
}

output "volume_name" {
  value = kubernetes_persistent_volume_claim.test.spec.0.volume_name
}

As you can see in the output below, it creates the resource first, and then reads it, since the field I'm referencing is unknown at plan time. By referencing a field that doesn't exist until the resource is created, we can effectively defer the data source read (otherwise the data source would be evaluated before the resource is created):

$ terraform apply --auto-approve
kubernetes_persistent_volume_claim.test: Creating...
kubernetes_persistent_volume_claim.test: Creation complete after 0s [id=default/testpv]
data.kubernetes_persistent_volume_claim.test: Reading...
data.kubernetes_persistent_volume_claim.test: Read complete after 0s [id=default/testpv]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

volume_name = "pvc-2bf2fd0b-9fd1-43bd-9aaf-1c9623351f67"

I think this is already what you're doing. Offhand, I'm guessing the field name just needs to be changed from data.kubernetes_service.some_service.spec.port to data.kubernetes_service.some_service.spec.0.port.0.port.

I got that specific path by looking at one of the tests that checks for that field:

https://github.com/hashicorp/terraform-provider-kubernetes/blob/aae2fefb5bbe8fde1c2083d11ab2eaaaa63de657/kubernetes/resource_kubernetes_service_test.go#L144

Which is created by this terraform config:

https://github.com/hashicorp/terraform-provider-kubernetes/blob/aae2fefb5bbe8fde1c2083d11ab2eaaaa63de657/kubernetes/resource_kubernetes_service_test.go#L793

(Using terraform show on a resource can also help to construct that path).

I think y'all are correct. Can this be converted to a Documentation issue? The docs for the attributes for the kubernetes_service data source are...kinda bad (no indication spec is a collection, no example of accessing any subattribute from it, weird order that kinda implies port should be at the same level as spec and metadata).

Thanks a ton for your help, though

Related upstream docs issue. https://github.com/hashicorp/terraform-website/issues/1495 (But we still want to create our own docs for this too).

@dak1n1 , I would like to help with the documentation, but I'm not sure how to process the Markdown files in order to produce the result that we can see at https://registry.terraform.io. I quickly went through contributing guidelines but couldn't find further information.
I suppose that part of this documentation is extracted from the *.go files since there is this kubernetes.erb file in the repo, but that's it. :-)

@glasswalk3r Thanks for your interest in this! Here's where you can find the docs file for the service data source: https://github.com/hashicorp/terraform-provider-kubernetes/blob/main/website/docs/d/service.html.markdown

The service resource lives here:

https://github.com/hashicorp/terraform-provider-kubernetes/blob/main/website/docs/r/service.html.markdown

It should show you a preview in github, which can help check that your markdown syntax is correct. Another way to check is by running make website-lint and make website-lint-fix. (That linter will also run when you open a PR).

Other than that, it's just magic on the release engineering side that will deploy it to the Terraform Registry website. That will happen automatically when a new version of the provider is released (which happens at most once per week).

@dak1n1 , since this is my first PR for this project, I created it as a draft. Please review and let me know if I need to change something else.

Was this page helpful?
0 / 5 - 0 ratings