pax_global_header00006660000000000000000000000064143507611030014512gustar00rootroot0000000000000052 comment=b51c2d1f1eab5f5e910a09fd959459f6a9f3b185 tfk8s-0.1.10/000077500000000000000000000000001435076110300126305ustar00rootroot00000000000000tfk8s-0.1.10/.github/000077500000000000000000000000001435076110300141705ustar00rootroot00000000000000tfk8s-0.1.10/.github/workflows/000077500000000000000000000000001435076110300162255ustar00rootroot00000000000000tfk8s-0.1.10/.github/workflows/lint.yaml000066400000000000000000000006751435076110300200670ustar00rootroot00000000000000name: lint permissions: contents: read on: push: branches: - main pull_request: branches: - main jobs: golangci: name: lint runs-on: ubuntu-latest timeout-minutes: 5 steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: go-version: '1.19' cache: true - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: version: v1.48 tfk8s-0.1.10/.github/workflows/test.yaml000066400000000000000000000005111435076110300200650ustar00rootroot00000000000000name: "Unit Tests" on: push: branches: - main pull_request: branches: - main jobs: unit_test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: go-version-file: '.go-version' cache: true - name: test run: make test tfk8s-0.1.10/.gitignore000066400000000000000000000000301435076110300146110ustar00rootroot00000000000000release/ scratch/ tfk8s tfk8s-0.1.10/.go-version000066400000000000000000000000051435076110300147140ustar00rootroot000000000000001.19 tfk8s-0.1.10/CHANGELOG.md000066400000000000000000000012211435076110300144350ustar00rootroot00000000000000# 0.1.10 - Fix generation field not being stripped when using --strip # 0.1.9 - Fix comma placement when formatting multi-line string values inside lists # 0.1.8 - Support resources using generateName - Add option to remove quotes from object/map keys when not needed - Match nested interpolation when escaping shell # 0.1.7 - Escape shell vars in HCL output # 0.1.6 - Fix crash when trying to use List resources - Catch panics and print friendly error message # 0.1.5 - Remove dependency on terraform in go.mod # 0.1.4 - Fix empty YAML crash (#21) # 0.1.3 - Ignore empty documents # 0.1.2 - Add heredoc syntax for multiline strings (#14) tfk8s-0.1.10/CODEOWNERS000066400000000000000000000000151435076110300142170ustar00rootroot00000000000000* @jrhouston tfk8s-0.1.10/Dockerfile000066400000000000000000000003451435076110300146240ustar00rootroot00000000000000FROM golang:1.19-alpine as build WORKDIR /build COPY go.* ./ RUN go mod download COPY . . RUN apk --no-cache add make RUN CGO_ENABLED=0 make build FROM scratch COPY --from=build /build/tfk8s /bin/tfk8s ENTRYPOINT ["/bin/tfk8s"] tfk8s-0.1.10/LICENSE000066400000000000000000000020611435076110300136340ustar00rootroot00000000000000The MIT License Copyright (c) 2020 John Houston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tfk8s-0.1.10/Makefile000066400000000000000000000032351435076110300142730ustar00rootroot00000000000000.PHONY: build docker docker-push release install test clean VERSION := 0.1.10 DOCKER_IMAGE_NAME := jrhouston/tfk8s build: go build -ldflags "-X main.toolVersion=${VERSION}" docker: docker build -t ${DOCKER_IMAGE_NAME}:${VERSION} . docker-push: docker docker push ${DOCKER_IMAGE_NAME}:${VERSION} release: clean mkdir -p release/ # FIXME use gox for this GOOS=linux GOOARCH=386 go build -ldflags "-X main.toolVersion=${VERSION}" -o release/tfk8s_${VERSION}_linux_386 zip -j release/tfk8s_${VERSION}_linux_386.zip release/tfk8s_${VERSION}_linux_386 GOOS=linux GOOARCH=amd64 go build -ldflags "-X main.toolVersion=${VERSION}" -o release/tfk8s_${VERSION}_linux_amd64 zip -j release/tfk8s_${VERSION}_linux_amd64.zip release/tfk8s_${VERSION}_linux_amd64 GOOS=linux GOOARCH=arm go build -ldflags "-X main.toolVersion=${VERSION}" -o release/tfk8s_${VERSION}_linux_arm zip -j release/tfk8s_${VERSION}_linux_arm.zip release/tfk8s_${VERSION}_linux_arm GOOS=darwin GOOARCH=amd64 go build -ldflags "-X main.toolVersion=${VERSION}" -o release/tfk8s_${VERSION}_darwin_amd64 zip -j release/tfk8s_${VERSION}_darwin_amd64.zip release/tfk8s_${VERSION}_darwin_amd64 GOOS=windows GOOARCH=amd64 go build -ldflags "-X main.toolVersion=${VERSION}" -o release/tfk8s_${VERSION}_windows_amd64 zip -j release/tfk8s_${VERSION}_windows_amd64.zip release/tfk8s_${VERSION}_windows_amd64 GOOS=windows GOOARCH=386 go build -ldflags "-X main.toolVersion=${VERSION}" -o release/tfk8s_${VERSION}_windows_386 zip -j release/tfk8s_${VERSION}_windows_386.zip release/tfk8s_${VERSION}_windows_386 install: go install -ldflags "-X main.toolVersion=${VERSION}" test: go test -v ./... clean: rm -rf release/* tfk8s-0.1.10/README.md000066400000000000000000000070061435076110300141120ustar00rootroot00000000000000tfk8s [![Go Report Card](https://goreportcard.com/badge/github.com/jrhouston/tfk8s)](https://goreportcard.com/report/github.com/jrhouston/tfk8s) ![tests](https://github.com/jrhouston/tfk8s/actions/workflows/test.yaml/badge.svg) --- ![](https://media.giphy.com/media/g8GfH3i5F0hby/giphy.gif) `tfk8s` is a tool that makes it easier to work with the [Terraform Kubernetes Provider](https://github.com/hashicorp/terraform-provider-kubernetes). If you want to copy examples from the Kubernetes documentation or migrate existing YAML manifests and use them with Terraform without having to convert YAML to HCL by hand, this tool is for you. - [Demo](#demo) - [Features](#features) - [Install](#install) - [Usage](#usage) - [Examples](#examples) - [Create Terraform configuration from YAML files](#create-terraform-configuration-from-yaml-files) - [Use with kubectl to output maps instead of YAML](#use-with-kubectl-to-output-maps-instead-of-yaml) - [Convert a Helm chart to Terraform](#convert-a-helm-chart-to-terraform) ## Demo [](https://asciinema.org/a/jSmyAg4Ar6EcwKCTCXN8iAJM2) ## Features - Convert a YAML file containing multiple manifests - Strip out server side fields when piping `kubectl get $R -o yaml | tfk8s --strip` ## Install ``` go install github.com/jrhouston/tfk8s@latest ``` Alternatively, clone this repo and run: ``` make install ``` If Go's bin directory is not in your `PATH` you will need to add it: ``` export PATH=$PATH:$(go env GOPATH)/bin ``` Or you can install via [brew](https://formulae.brew.sh/formula/tfk8s) for macOS/Linux: ``` brew install tfk8s ``` On macOS, you can also install via [MacPorts](https://www.macports.org): ``` sudo port install tfk8s ``` ## Usage ``` Usage of tfk8s: -f, --file string Input file containing Kubernetes YAML manifests (default "-") -M, --map-only Output only an HCL map structure -o, --output string Output file to write Terraform config (default "-") -p, --provider provider Provider alias to populate the provider attribute -s, --strip Strip out server side fields - use if you are piping from kubectl get -Q, --strip-key-quotes Strip out quotes from HCL map keys unless they are required. -V, --version Show tool version ``` ## Examples ### Create Terraform configuration from YAML files ``` tfk8s -f input.yaml -o output.tf ``` or, using pipes: ``` cat input.yaml | tfk8s > output.tf ``` **input.yaml**: ```yaml --- apiVersion: v1 kind: ConfigMap metadata: name: test data: TEST: test ``` ✨✨ magically becomes ✨✨ **output.tf**: ```hcl resource "kubernetes_manifest" "configmap_test" { manifest = { "apiVersion" = "v1" "data" = { "TEST" = "test" } "kind" = "ConfigMap" "metadata" = { "name" = "test" } } } ``` ### Use with kubectl to output maps instead of YAML ``` kubectl get ns default -o yaml | tfk8s -M ``` ```hcl { "apiVersion" = "v1" "kind" = "Namespace" "metadata" = { "creationTimestamp" = "2020-05-02T15:01:32Z" "name" = "default" "resourceVersion" = "147" "selfLink" = "/api/v1/namespaces/default" "uid" = "6ac3424c-07a4-4a69-86ae-cc7a4ae72be3" } "spec" = { "finalizers" = [ "kubernetes", ] } "status" = { "phase" = "Active" } } ``` ### Convert a Helm chart to Terraform You can use `helm template` to generate a manifest from the chart, then pipe it into tfk8s: ``` helm template ./chart-path -f values.yaml | tfk8s ``` tfk8s-0.1.10/contrib/000077500000000000000000000000001435076110300142705ustar00rootroot00000000000000tfk8s-0.1.10/contrib/hashicorp/000077500000000000000000000000001435076110300162505ustar00rootroot00000000000000tfk8s-0.1.10/contrib/hashicorp/terraform/000077500000000000000000000000001435076110300202515ustar00rootroot00000000000000tfk8s-0.1.10/contrib/hashicorp/terraform/format.go000066400000000000000000000122241435076110300220710ustar00rootroot00000000000000// NOTE this file was lifted verbatim from internal/repl in the terraform project // because the FormatValue function became internal in v1.0.0 // NOTE this file has since been modified so it has drifted from what was in // terraform core package terraform import ( "fmt" "regexp" "strconv" "strings" "github.com/zclconf/go-cty/cty" ) // FormatValue formats a value in a way that resembles Terraform language syntax // and uses the type conversion functions where necessary to indicate exactly // what type it is given, so that equality test failures can be quickly // understood. func FormatValue(v cty.Value, indent int, stripKeyQuotes bool) string { if !v.IsKnown() { return "(known after apply)" } if v.IsMarked() { return "(sensitive)" } if v.IsNull() { ty := v.Type() switch { case ty == cty.DynamicPseudoType: return "null" case ty == cty.String: return "tostring(null)" case ty == cty.Number: return "tonumber(null)" case ty == cty.Bool: return "tobool(null)" case ty.IsListType(): return fmt.Sprintf("tolist(null) /* of %s */", ty.ElementType().FriendlyName()) case ty.IsSetType(): return fmt.Sprintf("toset(null) /* of %s */", ty.ElementType().FriendlyName()) case ty.IsMapType(): return fmt.Sprintf("tomap(null) /* of %s */", ty.ElementType().FriendlyName()) default: return fmt.Sprintf("null /* %s */", ty.FriendlyName()) } } ty := v.Type() switch { case ty.IsPrimitiveType(): switch ty { case cty.String: if formatted, isMultiline := formatMultilineString(v, indent); isMultiline { return formatted } return strconv.Quote(v.AsString()) case cty.Number: bf := v.AsBigFloat() return bf.Text('f', -1) case cty.Bool: if v.True() { return "true" } else { return "false" } } case ty.IsObjectType(): return formatMappingValue(v, indent, stripKeyQuotes) case ty.IsTupleType(): return formatSequenceValue(v, indent, stripKeyQuotes) case ty.IsListType(): return fmt.Sprintf("tolist(%s)", formatSequenceValue(v, indent, stripKeyQuotes)) case ty.IsSetType(): return fmt.Sprintf("toset(%s)", formatSequenceValue(v, indent, stripKeyQuotes)) case ty.IsMapType(): return fmt.Sprintf("tomap(%s)", formatMappingValue(v, indent, stripKeyQuotes)) } // Should never get here because there are no other types return fmt.Sprintf("%#v", v) } // defaultDelimiter is "End Of Text" by convention const defaultDelimiter = "EOT" func formatMultilineString(v cty.Value, indent int) (string, bool) { str := v.AsString() lines := strings.Split(str, "\n") if len(lines) < 2 { return "", false } // If the value is indented, we use the indented form of heredoc for readability. operator := "<<" if indent > 0 { operator = "<<-" } delimiter := defaultDelimiter OUTER: for { // Check if any of the lines are in conflict with the delimiter. The // parser allows leading and trailing whitespace, so we must remove it // before comparison. for _, line := range lines { // If the delimiter matches a line, extend it and start again if strings.TrimSpace(line) == delimiter { delimiter = delimiter + "_" continue OUTER } } // None of the lines match the delimiter, so we're ready break } // Write the heredoc, with indentation as appropriate. var buf strings.Builder buf.WriteString(operator) buf.WriteString(delimiter) for _, line := range lines { buf.WriteByte('\n') buf.WriteString(strings.Repeat(" ", indent)) buf.WriteString(line) } buf.WriteByte('\n') buf.WriteString(strings.Repeat(" ", indent)) buf.WriteString(delimiter) return buf.String(), true } func formatMappingValue(v cty.Value, indent int, stripKeyQuotes bool) string { var buf strings.Builder count := 0 buf.WriteByte('{') indent += 2 for it := v.ElementIterator(); it.Next(); { count++ k, v := it.Element() buf.WriteByte('\n') buf.WriteString(strings.Repeat(" ", indent)) key := FormatValue(k, indent, stripKeyQuotes) if stripKeyQuotes { // they can be unquoted if it starts with a letter // and only contains alphanumeric characeters, dashes, and underlines m := regexp.MustCompile(`^"[A-Za-z][0-9A-Za-z-_]+"$`) if m.MatchString(key) { key = key[1 : len(key)-1] } } buf.WriteString(key) buf.WriteString(" = ") buf.WriteString(FormatValue(v, indent, stripKeyQuotes)) } indent -= 2 if count > 0 { buf.WriteByte('\n') buf.WriteString(strings.Repeat(" ", indent)) } buf.WriteByte('}') return buf.String() } func formatSequenceValue(v cty.Value, indent int, stripKeyQuotes bool) string { var buf strings.Builder count := 0 buf.WriteByte('[') indent += 2 for it := v.ElementIterator(); it.Next(); { count++ _, v := it.Element() buf.WriteByte('\n') buf.WriteString(strings.Repeat(" ", indent)) formattedValue := FormatValue(v, indent, stripKeyQuotes) buf.WriteString(formattedValue) if strings.HasSuffix(formattedValue, defaultDelimiter) { // write an additional newline if the value was a multiline string buf.WriteByte('\n') buf.WriteString(strings.Repeat(" ", indent)) } buf.WriteByte(',') } indent -= 2 if count > 0 { buf.WriteByte('\n') buf.WriteString(strings.Repeat(" ", indent)) } buf.WriteByte(']') return buf.String() } tfk8s-0.1.10/contrib/hashicorp/terraform/format_test.go000066400000000000000000000074711435076110300231400ustar00rootroot00000000000000// NOTE this file was lifted verbatim from internal/repl in the terraform project // because the FormatValue function became internal in v1.0.0 package terraform import ( "fmt" "testing" "github.com/zclconf/go-cty/cty" ) func TestFormatValue(t *testing.T) { tests := []struct { Val cty.Value Want string }{ { cty.NullVal(cty.DynamicPseudoType), `null`, }, { cty.NullVal(cty.String), `tostring(null)`, }, { cty.NullVal(cty.Number), `tonumber(null)`, }, { cty.NullVal(cty.Bool), `tobool(null)`, }, { cty.NullVal(cty.List(cty.String)), `tolist(null) /* of string */`, }, { cty.NullVal(cty.Set(cty.Number)), `toset(null) /* of number */`, }, { cty.NullVal(cty.Map(cty.Bool)), `tomap(null) /* of bool */`, }, { cty.NullVal(cty.Object(map[string]cty.Type{"a": cty.Bool})), `null /* object */`, // Ideally this would display the full object type, including its attributes }, { cty.UnknownVal(cty.DynamicPseudoType), `(known after apply)`, }, { cty.StringVal(""), `""`, }, { cty.StringVal("hello"), `"hello"`, }, { cty.StringVal("hello\nworld"), `< 0 { hcl += "\n" } hcl += formatted count++ } return hcl, nil } func capturePanic() { if r := recover(); r != nil { fmt.Printf( "panic: %s\n\n%s\n\n"+ "⚠️ Oh no! Looks like your manifest caused tfk8s to crash.\n\n"+ "Please open a GitHub issue and include your manifest YAML with the stack trace above,\n"+ "or ping me on slack and I'll try and fix it!\n\n"+ "GitHub: https://github.com/jrhouston/tfk8s/issues\n"+ "Slack: #terraform-providers on https://kubernetes.slack.com\n\n"+ "- Thanks, @jrhouston\n\n", r, debug.Stack()) } } func main() { defer capturePanic() infile := flag.StringP("file", "f", "-", "Input file containing Kubernetes YAML manifests") outfile := flag.StringP("output", "o", "-", "Output file to write Terraform config") providerAlias := flag.StringP("provider", "p", "", "Provider alias to populate the `provider` attribute") stripServerSide := flag.BoolP("strip", "s", false, "Strip out server side fields - use if you are piping from kubectl get") version := flag.BoolP("version", "V", false, "Show tool version") mapOnly := flag.BoolP("map-only", "M", false, "Output only an HCL map structure") stripKeyQuotes := flag.BoolP("strip-key-quotes", "Q", false, "Strip out quotes from HCL map keys unless they are required.") flag.Parse() if *version { fmt.Println(toolVersion) os.Exit(0) } var file *os.File if *infile == "-" { file = os.Stdin } else { var err error file, err = os.Open(*infile) if err != nil { fmt.Fprintf(os.Stderr, "error: %s\r\n", err.Error()) os.Exit(1) } } hcl, err := YAMLToTerraformResources( file, *providerAlias, *stripServerSide, *mapOnly, *stripKeyQuotes) if err != nil { fmt.Fprintf(os.Stderr, "error: %s\r\n", err.Error()) os.Exit(1) } if *outfile == "-" { fmt.Print(hcl) } else { err := os.WriteFile(*outfile, []byte(hcl), 0644) if err != nil { fmt.Fprintf(os.Stderr, "error: %s\r\n", err.Error()) os.Exit(1) } } } tfk8s-0.1.10/tfk8s_test.go000066400000000000000000000175661435076110300152740ustar00rootroot00000000000000package main import ( "strings" "testing" "github.com/stretchr/testify/assert" ) func TestYAMLToTerraformResourcesSingle(t *testing.T) { yaml := `--- apiVersion: v1 kind: ConfigMap metadata: name: test data: TEST: test` r := strings.NewReader(yaml) output, err := YAMLToTerraformResources(r, "", false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) } expected := ` resource "kubernetes_manifest" "configmap_test" { manifest = { "apiVersion" = "v1" "data" = { "TEST" = "test" } "kind" = "ConfigMap" "metadata" = { "name" = "test" } } }` assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(output)) } func TestYAMLToTerraformResourcesGenerateName(t *testing.T) { yaml := `--- apiVersion: v1 kind: ConfigMap metadata: generateName: test-name- data: TEST: test` r := strings.NewReader(yaml) output, err := YAMLToTerraformResources(r, "", false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) } expected := ` resource "kubernetes_manifest" "configmap_test_name" { manifest = { "apiVersion" = "v1" "data" = { "TEST" = "test" } "kind" = "ConfigMap" "metadata" = { "generateName" = "test-name-" } } }` assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(output)) } func TestYAMLToTerraformResourcesEscapeShell(t *testing.T) { yaml := `--- apiVersion: v1 kind: ConfigMap metadata: name: test data: SCRIPT: | echo "Hello, ${USER} your homedir is ${HOME}" echo "\${SHELL_ESCAPE${TF_ESCAPE}}"` r := strings.NewReader(yaml) output, err := YAMLToTerraformResources(r, "", false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) } expected := ` resource "kubernetes_manifest" "configmap_test" { manifest = { "apiVersion" = "v1" "data" = { "SCRIPT" = <<-EOT echo "Hello, $${USER} your homedir is $${HOME}" echo "\$${SHELL_ESCAPE$${TF_ESCAPE}}" EOT } "kind" = "ConfigMap" "metadata" = { "name" = "test" } } }` assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(output)) } func TestYAMLToTerraformResourcesMultiple(t *testing.T) { yaml := `--- apiVersion: v1 kind: ConfigMap metadata: name: one data: TEST: one --- # this empty # document # should be # skipped --- apiVersion: v1 kind: ConfigMap metadata: name: two data: TEST: two` r := strings.NewReader(yaml) output, err := YAMLToTerraformResources(r, "", false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) } expected := ` resource "kubernetes_manifest" "configmap_one" { manifest = { "apiVersion" = "v1" "data" = { "TEST" = "one" } "kind" = "ConfigMap" "metadata" = { "name" = "one" } } } resource "kubernetes_manifest" "configmap_two" { manifest = { "apiVersion" = "v1" "data" = { "TEST" = "two" } "kind" = "ConfigMap" "metadata" = { "name" = "two" } } }` assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(output)) } func TestYAMLToTerraformResourcesList(t *testing.T) { yaml := `--- apiVersion: v1 kind: ConfigMapList items: - apiVersion: v1 kind: ConfigMap metadata: name: one data: TEST: one - apiVersion: v1 kind: ConfigMap metadata: name: two data: TEST: two - apiVersion: v1 kind: ConfigMap metadata: name: two namespace: othernamespace data: TEST: two ` r := strings.NewReader(yaml) output, err := YAMLToTerraformResources(r, "", false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) } expected := ` resource "kubernetes_manifest" "configmap_one" { manifest = { "apiVersion" = "v1" "data" = { "TEST" = "one" } "kind" = "ConfigMap" "metadata" = { "name" = "one" } } } resource "kubernetes_manifest" "configmap_two" { manifest = { "apiVersion" = "v1" "data" = { "TEST" = "two" } "kind" = "ConfigMap" "metadata" = { "name" = "two" } } } resource "kubernetes_manifest" "configmap_othernamespace_two" { manifest = { "apiVersion" = "v1" "data" = { "TEST" = "two" } "kind" = "ConfigMap" "metadata" = { "name" = "two" "namespace" = "othernamespace" } } }` assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(output)) } func TestYAMLToTerraformResourcesProviderAlias(t *testing.T) { yaml := `--- apiVersion: v1 kind: ConfigMap metadata: name: test data: TEST: test` r := strings.NewReader(yaml) output, err := YAMLToTerraformResources(r, "kubernetes-alpha", false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) } expected := ` resource "kubernetes_manifest" "configmap_test" { provider = kubernetes-alpha manifest = { "apiVersion" = "v1" "data" = { "TEST" = "test" } "kind" = "ConfigMap" "metadata" = { "name" = "test" } } }` assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(output)) } func TestYAMLToTerraformResourcesProviderServerSideStrip(t *testing.T) { yaml := `--- apiVersion: v1 data: TEST: test kind: ConfigMap metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","data":{"TEST":"prod"},"test":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}} creationTimestamp: "2020-04-30T20:34:59Z" name: test namespace: default resourceVersion: "677134" selfLink: /api/v1/namespaces/default/configmaps/test uid: bea6500b-0637-4d2d-b726-e0bda0b595dd generation: 1 finalizers: - test` r := strings.NewReader(yaml) output, err := YAMLToTerraformResources(r, "", true, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) } expected := ` resource "kubernetes_manifest" "configmap_test" { manifest = { "apiVersion" = "v1" "data" = { "TEST" = "test" } "kind" = "ConfigMap" "metadata" = { "name" = "test" } } }` assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(output)) } func TestYAMLToTerraformResourcesMapOnly(t *testing.T) { yaml := `--- apiVersion: v1 data: TEST: test kind: ConfigMap metadata: name: test namespace: default resourceVersion: "677134" selfLink: /api/v1/namespaces/default/configmaps/test uid: bea6500b-0637-4d2d-b726-e0bda0b595dd` r := strings.NewReader(yaml) output, err := YAMLToTerraformResources(r, "", true, true, false) if err != nil { t.Fatal("Converting to HCL failed:", err) } expected := `{ "apiVersion" = "v1" "data" = { "TEST" = "test" } "kind" = "ConfigMap" "metadata" = { "name" = "test" } }` assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(output)) } func TestYAMLToTerraformResourcesEmptyDocSkip(t *testing.T) { yaml := `--- apiVersion: v1 data: TEST: test kind: ConfigMap metadata: name: test namespace: default resourceVersion: "677134" selfLink: /api/v1/namespaces/default/configmaps/test uid: bea6500b-0637-4d2d-b726-e0bda0b595dd --- --- apiVersion: v1 data: TEST: test kind: ConfigMap metadata: name: test2 namespace: default resourceVersion: "677134" selfLink: /api/v1/namespaces/default/configmaps/test uid: bea6500b-0637-4d2d-b726-e0bda0b595dd` r := strings.NewReader(yaml) output, err := YAMLToTerraformResources(r, "", true, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) } expected := `resource "kubernetes_manifest" "configmap_test" { manifest = { "apiVersion" = "v1" "data" = { "TEST" = "test" } "kind" = "ConfigMap" "metadata" = { "name" = "test" } } } resource "kubernetes_manifest" "configmap_test2" { manifest = { "apiVersion" = "v1" "data" = { "TEST" = "test" } "kind" = "ConfigMap" "metadata" = { "name" = "test2" } } } ` assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(output)) }