Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imported prefect_work_pool's base_job_template is overwritten on initial plan/apply when it's the same #259

Open
kevingrismore opened this issue Sep 19, 2024 · 1 comment
Labels
bug Something isn't working development open-source

Comments

@kevingrismore
Copy link

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request.
  • Please do not leave +1 or me too comments, they generate extra noise for issue followers and do not help prioritize the request.
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment.

Terraform Version

Terraform v1.9.5
on darwin_arm64
+ provider registry.terraform.io/prefecthq/prefect v2.2.2

Affected Resource(s)

  • prefect_work_pool

Terraform Configuration Files

resource "prefect_work_pool" "k8s-demo" {
  name              = "k8s-demo"
  type              = "kubernetes"
  workspace_id      = "<workspace-id>"
  paused            = false
  base_job_template = file("./k8s-demo-template.json")
}

Debug Output

Panic Output

Expected Behavior

When importing an existing work pool with terraform import prefect_work_pool.k8s-demo <workspace-id>,k8s-demo, if my work pool resource in the .tf above and the contents of the base template JSON in the referenced file are the same, plan should detect no changes and apply should do nothing.

Actual Behavior

terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # prefect_work_pool.k8s-demo will be updated in-place
  ~ resource "prefect_work_pool" "k8s-demo" {
      + base_job_template = jsonencode(
            {
              + job_configuration = {
                  + cluster_config            = "{{ cluster_config }}"
                  + command                   = "{{ command }}"
                  + env                       = "{{ env }}"
                  + job_manifest              = {
                      + apiVersion = "batch/v1"
                      + kind       = "Job"
                      + metadata   = {
                          + generateName = "{{ name }}-"
                          + labels       = "{{ labels }}"
                          + namespace    = "{{ namespace }}"
                        }
                      + spec       = {
                          + backoffLimit            = 0
                          + template                = {
                              + spec = {
                                  + completions        = 1
                                  + containers         = [
                                      + {
                                          + args            = "{{ command }}"
                                          + env             = "{{ env }}"
                                          + image           = "{{ image }}"
                                          + imagePullPolicy = "{{ image_pull_policy }}"
                                          + name            = "prefect-job"
                                          + resources       = "{{ resources }}"
                                        },
                                    ]
                                  + nodeSelector       = "{{ node_selector }}"
                                  + parallelism        = 1
                                  + restartPolicy      = "Never"
                                  + serviceAccountName = "{{ service_account_name }}"
                                }
                            }
                          + ttlSecondsAfterFinished = "{{ finished_job_ttl }}"
                        }
                    }
                  + job_watch_timeout_seconds = "{{ job_watch_timeout_seconds }}"
                  + labels                    = "{{ labels }}"
                  + name                      = "{{ name }}"
                  + namespace                 = "{{ namespace }}"
                  + pod_watch_timeout_seconds = "{{ pod_watch_timeout_seconds }}"
                  + stream_output             = "{{ stream_output }}"
                }
              + variables         = {
                  + definitions = {
                      + KubernetesClusterConfig = {
                          + block_schema_references = {}
                          + block_type_slug         = "kubernetes-cluster-config"
                          + description             = <<-EOT
                                Stores configuration for interaction with Kubernetes clusters.
                                
                                See `from_file` for creation.
                            EOT
                          + properties              = {
                              + config       = {
                                  + description = "The entire contents of a kubectl config file."
                                  + title       = "Config"
                                  + type        = "object"
                                }
                              + context_name = {
                                  + description = "The name of the kubectl context to use."
                                  + title       = "Context Name"
                                  + type        = "string"
                                }
                            }
                          + required                = [
                              + "config",
                              + "context_name",
                            ]
                          + secret_fields           = []
                          + title                   = "KubernetesClusterConfig"
                          + type                    = "object"
                        }
                    }
                  + description = <<-EOT
                        Default variables for the Kubernetes worker.
                        
                        The schema for this class is used to populate the `variables` section of the default
                        base job template.
                    EOT
                  + properties  = {
                      + base_name                 = {
                          + description = "Base Name given to infrastructure created by a worker. {flow_name}-{deployment_name}"
                          + title       = "Base Name"
                          + type        = "string"
                        }
                      + cluster_config            = {
                          + allOf       = [
                              + {
                                  + "$ref" = "#/definitions/KubernetesClusterConfig"
                                },
                            ]
                          + description = "The Kubernetes cluster config to use for job creation."
                          + title       = "Cluster Config"
                        }
                      + command                   = {
                          + description = "The command to use when starting a flow run. In most cases, this should be left blank and the command will be automatically generated by the worker."
                          + title       = "Command"
                          + type        = "string"
                        }
                      + env                       = {
                          + additionalProperties = {
                              + type = "string"
                            }
                          + description          = "Environment variables to set when starting a flow run."
                          + title                = "Environment Variables"
                          + type                 = "object"
                        }
                      + finished_job_ttl          = {
                          + description = "The number of seconds to retain jobs after completion. If set, finished jobs will be cleaned up by Kubernetes after the given delay. If not set, jobs will be retained indefinitely."
                          + title       = "Finished Job TTL"
                          + type        = "integer"
                        }
                      + image                     = {
                          + description = "The image reference of a container image to use for created jobs. If not set, the latest Prefect image will be used."
                          + example     = "docker.io/prefecthq/prefect:2-latest"
                          + title       = "Image"
                          + type        = "string"
                        }
                      + image_pull_policy         = {
                          + default     = "IfNotPresent"
                          + description = "The Kubernetes image pull policy to use for job containers."
                          + enum        = [
                              + "IfNotPresent",
                              + "Always",
                              + "Never",
                            ]
                          + title       = "Image Pull Policy"
                          + type        = "string"
                        }
                      + job_watch_timeout_seconds = {
                          + description = "Number of seconds to wait for each event emitted by a job before timing out. If not set, the worker will wait for each event indefinitely."
                          + title       = "Job Watch Timeout Seconds"
                          + type        = "integer"
                        }
                      + labels                    = {
                          + additionalProperties = {
                              + type = "string"
                            }
                          + description          = "Labels applied to infrastructure created by a worker."
                          + title                = "Labels"
                          + type                 = "object"
                        }
                      + name                      = {
                          + description = "Name given to infrastructure created by a worker."
                          + title       = "Name"
                          + type        = "string"
                        }
                      + namespace                 = {
                          + default     = "default"
                          + description = "The Kubernetes namespace to create jobs within."
                          + title       = "Namespace"
                          + type        = "string"
                        }
                      + node_selector             = {
                          + description = "a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/"
                          + title       = "Node Selector"
                          + type        = "object"
                        }
                      + pod_watch_timeout_seconds = {
                          + default     = 60
                          + description = "Number of seconds to watch for pod creation before timing out."
                          + title       = "Pod Watch Timeout Seconds"
                          + type        = "integer"
                        }
                      + resources                 = {
                          + title = "Resources"
                          + type  = "object"
                        }
                      + service_account_name      = {
                          + description = "The Kubernetes service account to use for job creation."
                          + title       = "Service Account Name"
                          + type        = "string"
                        }
                      + stream_output             = {
                          + default     = true
                          + description = "If set, output will be streamed from the job to local standard output."
                          + title       = "Stream Output"
                          + type        = "boolean"
                        }
                    }
                  + type        = "object"
                }
            }
        )
        id                = "757d7c42-2f21-4138-b499-c1b924159d30"
        name              = "k8s-demo"
      ~ updated           = "2024-08-27T17:03:36Z" -> (known after apply)
        # (6 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Steps to Reproduce

  1. Add prefect_work_pool "k8s-demo" resource with matching definition and reference to base job template to .tf
  2. terraform import prefect_work_pool.k8s-demo <workspace-id>,k8s-demo
  3. terraform plan

Important Factoids

References

@kevingrismore kevingrismore added the bug Something isn't working label Sep 19, 2024
@kevingrismore kevingrismore changed the title Imported prefect_work_pool's base_job_template is overwritten on plan/apply when it's the same Imported prefect_work_pool's base_job_template is overwritten on initial plan/apply when it's the same Sep 19, 2024
@mitchnielsen
Copy link
Contributor

Hmm, will need to dig into this further but this does seem related to #249. The JSON object gets rearranged a bit between what a user defines and what's actually stored in Prefect, causing Terraform to think the object is different. That PR helps account for the difference, but this might be an edge case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working development open-source
Projects
None yet
Development

No branches or pull requests

3 participants