-
Notifications
You must be signed in to change notification settings - Fork 9.6k
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
Support multi-document YAML files with yamldecode() #29729
Comments
Would the teraform be open for a PR? |
@mvoitko how difficult would it be to implement something like this? I think such simple functionality is likely to be accepted by the TF core team, but of course it could also result in a wasted efforts (hopefully not). |
Discussing and validating a potential solution (even if it seems fairly straight-forward on the surface) will increase the chances a PR gets accepted. I'd recommended writing up a description of the proposed changes before starting work, and verifying there aren't any hidden reasons the functionality exists in its current form. I hope this helps! |
Documentation on yamldecode() states clearly that:
This contributor, tells a way to do it with locals, split function (based on --- separator of new document), and a count inside the kubernetes_manifest. Your way is more refined when we look at the regex (spaces, comments that might be found around ---). |
You can use https://github.com/patrickdappollonio/kubectl-slice as a workaround curl -sL https://github.com/patrickdappollonio/kubectl-slice/releases/download/v1.2.1/kubectl-slice_1.2.1_linux_x86_64.tar.gz | tar -xvzf -;
rm -rf slices hcl;
./kubectl-slice -f document.yaml -o slices 2>&1 | grep -oP "Wrote \K.+yaml" | while read yamlfile; do echo 'yamldecode(file("'$yamlfile'"))' | terraform console >>hcl; done;
cat hcl |
@AndreiBanaruTakeda that simple split example is not very good because it ignores a lot of corner cases. See the example above in the |
@feczo We already have a workaround I am talking about more robust solution. |
Instead of string splitting, a nice way of traversing multi-doc yaml https://registry.terraform.io/providers/gavinbunney/kubectl/latest/docs/data-sources/kubectl_file_documents. |
Instead of one function, this workaround suggests using a new provider. |
It really feels like this provider should support this use case, without relying on another provider to parse the multi-YAML document |
@brettjacobson we are not talking about "another provider" -- instead this issue is about the built-in terraform function to parse YAML, without any specific provider's support. |
terraform-multidecoder-yaml_jsonAccess multiple YAML and/or JSON files with their relative paths in one step. Documentantion can be found here: GitHub: Terraform Registry: UsagePlace this module in the location where you need to access multiple different YAML and/or JSON files (different paths possible) and pass
Patterns to access YAML and/or JSON files from relative paths:To be able to access all YAML and/or JSON files in a folder entern your path as follows To be able to access a specific YAML and/or a JSON file in a folder structure use this If you like to select all YAML and/or JSON files within a folder, then you should use "*.yml", "*.yaml", "*.json" format notation. (see above in the USAGE section) YAML delimiter support is available from version 0.1.0!WARNING: Only the relative path must be specified. The path.root (it is included in the module by default) should not be passed, but everything after it. Access YAML and JSON entriesNow you can access all entries within all the YAML and/or JSON files you've selected like that: "module.yaml_json_decoder.files.[name of your YAML or JSON file].entry". If the name of your YAML or JSON file is "name_of_your_config_file" then access it as follows "module.yaml_json_decoder.files.name_of_your_config_file.entry". Example of multi YAML and JSON file accesses from different paths (directories)first YAML file:routes/nsg_rules.yml
second YAML file:services/logging/monitoring.yml
first JSON file:test/config/json_history.json
main.tf
Changes to Outputs:
|
@levmel Does this support multiple yaml objects in the same yaml file, delimited by
Then parses 2 YAML objects? |
@brandongallagher-tag Not yet to be honest, because I split up my configuration always logically into different config files. That is why I never use delimiters in my config. I can add it to the next release. For now it supports multiple YAML objects that are located in the same file, but without the delimiter. Edit: |
i think this is the best solution, my implementation tin install kubectl documents with multi document yaml is as follows
But this is to apply kubectl files, not for general usecases |
I found a way to do it w/o any additional providers. Let me know if it works for your particular use case. # Assign to a local after splitting by "---"
locals { my_manifests = split("---", templatefile("multiple-manifests.yaml") }
# Iterate by mapping with a range
resource "kubernetes_manifest" "many_objects" {
for_each = zipmap(range(0,length(local.my_manifests)),local.my_manifests)
manifest = yamldecode(each.value)
} |
Hi. I was facing this exact question at this moment, when trying to process (via templates) multiple kubernetes files, converting them to HCL map/objects/... |
Following algorithm works well for me:
|
Please don't propose to address this by splitting multipart documents using antipatterns such as a string split "---". Yes - maybe that solves your immediate need today, and maybe it works fine for 99% of the cases, but what about the tomorrow case, where your HCL falls into the 1% .. where the string split solution doesn't work, .. such as where the strings --- are embedded (but properly escaped) in the file body, such as having markdown tables "|---|---|" in the YAML, or a multiplart MIME (ex: PEM encoded public certificates ---- BEGIN CERTIFICATE ---) inside the YAML in a text block. String split is an antipattern, don't use that, your program will break in the future in a non-obvious way, possibly at a critical moment |
@elasticdotventures its a hacky workaround to a pressing problem that unfortunately was never addressed. The community clearly needs a solution to this, and in the mean time... uses horribly-unstable crutches - simply because bad solution is better than no solution. |
Thank you for your continued interest in this issue. Terraform version 1.8 launches with support of provider-defined functions. It is now possible to implement your own functions! We would love to see this implemented as a provider-defined function. Please see the provider-defined functions documentation to learn how to implement functions in your providers. If you are new to provider development, learn how to create a new provider with the Terraform Plugin Framework. If you have any questions, please visit the Terraform Plugin Development category in our official forum. We hope this feature unblocks future function development and provides more flexibility for the Terraform community. Thank you for your continued support of Terraform! |
@crw I read through some of the documentation but the docs don't really indicate what this looks like from the user's perspective. They really need a full example going from "here's your provider code" => "here's the actual HCL using that provider". Do you build a custom function into your provider and it becomes available in the global HCL namespace? So I could create a "better yaml" provider, users add it like any other provider ( I think the docs need to explain this better- maybe I'm dumb though lol. |
@red8888 tutorials are being developed, and should be available "soon." The reference docs do not have really have usage information, but check out the usage docs for a random function I happened to have open, it will show naming conventions and usage conventions: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/functions/arn_build |
We are working on a provider defined function for this particular use-case in the Kubernetes provider here: hashicorp/terraform-provider-kubernetes#2428. |
The To use it you'll need to be using Terraform v1.8.0 or later (because that was the first release to support provider-contributed functions) and Here's an adaptation of the example in the original issue comment to use the new function: terraform {
required_version = ">= 1.8.0"
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = ">= 2.28.0"
}
}
}
locals {
crds = provider::kubernetes::manifest_decode_multi(data.http.crd.body)
}
resource "kubernetes_manifest" "crd" {
for_each = {
for manifest in local.crds :
"${manifest.kind}--${manifest.metadata.name}" => manifest
}
manifest = each.value
} The reported use-case therefore seems to be met now, albeit using a Kubernetes provider feature instead of a builtin. Terraform's built-in functions aim to meet broad use-cases; multi-document YAML is less common but broadly used in the Kubernetes community, so the Kubernetes provider is a reasonable home for that functionality when used in conjunction with Kubernetes. If there are other prominent use-cases for multi-document YAML beyond Kubernetes then it might be worthwhile to have a separate functions-only provider that's focused primarily on YAML without any Kubernetes-specific assumptions, but since all of the examples in this issue were Kubernetes-related we'll wait to see if that generalization is warranted. Thanks! |
@dcshiman thanks, tried this yesterday and worked like a charm 👍🏼 |
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. |
yamldecode causes an error if YAML contains more than one document, causing significant complications when working with Kubernetes. Please remove this restriction, returning a list of objects in case of a multidocument yaml. Alternatively, you could introduce a
yamllistdecode()
function that always assumes the yaml to be multidocument, and always returns a list of objects.Current Terraform Version
Use-cases
GIven an arbitrary Kubernetes YAML manifest, e.g. a CRD manifest downloaded from a site, one would be able to apply it using this code. Related stack overflow questions: 1 and 2
Attempted Solutions
This solution works ok, but is obviously very brittle with all the regex yaml manipulations
Proposal
Per above, allow
yamldecode(...)
to decode multi-document yaml files, or introduce an additional parameter or a new function to handle them.See also
The 3rd party
kubectl
provider even introduced a dedicated kubectl_file_documents data source to handle this specific case.The text was updated successfully, but these errors were encountered: