From 72ad963049d4b2edbca236990c47e27f166c2e82 Mon Sep 17 00:00:00 2001 From: John Houston Date: Thu, 23 Sep 2021 00:19:05 -0400 Subject: [PATCH 1/2] Add --import command to add terraform import syntax --- tfk8s.go | 19 +++++++++++++----- tfk8s_test.go | 53 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/tfk8s.go b/tfk8s.go index 2a1ef5f..41537b4 100644 --- a/tfk8s.go +++ b/tfk8s.go @@ -97,7 +97,7 @@ func escapeShellVars(s string) string { // yamlToHCL converts a single YAML document Terraform HCL func yamlToHCL( doc cty.Value, providerAlias string, - stripServerSide bool, mapOnly bool, stripKeyQuotes bool) (string, error) { + stripServerSide bool, mapOnly bool, stripKeyQuotes bool, importComment bool) (string, error) { m := doc.AsValueMap() docs := []cty.Value{doc} if strings.HasSuffix(m["kind"].AsString(), "List") { @@ -108,6 +108,7 @@ func yamlToHCL( for i, doc := range docs { mm := doc.AsValueMap() kind := mm["kind"].AsString() + apiVersion := mm["apiVersion"].AsString() metadata := mm["metadata"].AsValueMap() var namespace string if v, ok := metadata["namespace"]; ok { @@ -140,6 +141,13 @@ func yamlToHCL( if mapOnly { hcl += fmt.Sprintf("%v\n", s) } else { + if importComment { + importID := fmt.Sprintf("apiVersion=%s,kind=%s,name=%s", apiVersion, kind, name) + if namespace != "" { + importID += ",namespace=" + namespace + } + hcl += fmt.Sprintf("# terraform import %s.%s %q\n", resourceType, resourceName, importID) + } hcl += fmt.Sprintf("resource %q %q {\n", resourceType, resourceName) if providerAlias != "" { hcl += fmt.Sprintf(" provider = %v\n\n", providerAlias) @@ -163,7 +171,7 @@ var yamlSeparator = "\n---" // FIXME this function has too many arguments now, use functional options instead func YAMLToTerraformResources( r io.Reader, providerAlias string, stripServerSide bool, - mapOnly bool, stripKeyQuotes bool) (string, error) { + mapOnly bool, stripKeyQuotes bool, importComment bool) (string, error) { hcl := "" buf := bytes.Buffer{} @@ -206,7 +214,7 @@ func YAMLToTerraformResources( return "", fmt.Errorf("the manifest must be a YAML document") } - formatted, err := yamlToHCL(doc, providerAlias, stripServerSide, mapOnly, stripKeyQuotes) + formatted, err := yamlToHCL(doc, providerAlias, stripServerSide, mapOnly, stripKeyQuotes, importComment) if err != nil { return "", fmt.Errorf("error converting YAML to HCL: %s", err) } @@ -244,7 +252,8 @@ func main() { 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.") + stripKeyQuotes := flag.BoolP("strip-key-quotes", "Q", false, "Strip out quotes from HCL map keys unless they are required") + importComment := flag.BoolP("import", "I", false, "Add a comment above each resource with the terraform import command") flag.Parse() if *version { @@ -265,7 +274,7 @@ func main() { } hcl, err := YAMLToTerraformResources( - file, *providerAlias, *stripServerSide, *mapOnly, *stripKeyQuotes) + file, *providerAlias, *stripServerSide, *mapOnly, *stripKeyQuotes, *importComment) if err != nil { fmt.Println("error:", err) os.Exit(1) diff --git a/tfk8s_test.go b/tfk8s_test.go index 8d6c6e2..43e12c1 100644 --- a/tfk8s_test.go +++ b/tfk8s_test.go @@ -17,7 +17,7 @@ data: TEST: test` r := strings.NewReader(yaml) - output, err := YAMLToTerraformResources(r, "", false, false, false) + output, err := YAMLToTerraformResources(r, "", false, false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) @@ -50,7 +50,7 @@ data: TEST: test` r := strings.NewReader(yaml) - output, err := YAMLToTerraformResources(r, "", false, false, false) + output, err := YAMLToTerraformResources(r, "", false, false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) @@ -73,6 +73,41 @@ resource "kubernetes_manifest" "configmap_test_name" { assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(output)) } +func TestYAMLToTerraformResourcesImportComment(t *testing.T) { + yaml := `--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: test + namespace: test-ns +data: + TEST: test` + + r := strings.NewReader(yaml) + output, err := YAMLToTerraformResources(r, "", false, false, false, true) + + if err != nil { + t.Fatal("Converting to HCL failed:", err) + } + + expected := `# terraform import kubernetes_manifest.configmap_test_ns_test "apiVersion=v1,kind=ConfigMap,name=test,namespace=test-ns" +resource "kubernetes_manifest" "configmap_test_ns_test" { + manifest = { + "apiVersion" = "v1" + "data" = { + "TEST" = "test" + } + "kind" = "ConfigMap" + "metadata" = { + "name" = "test" + "namespace" = "test-ns" + } + } +}` + + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(output)) +} + func TestYAMLToTerraformResourcesEscapeShell(t *testing.T) { yaml := `--- apiVersion: v1 @@ -84,7 +119,7 @@ data: echo Hello, ${USER} your homedir is ${HOME}` r := strings.NewReader(yaml) - output, err := YAMLToTerraformResources(r, "", false, false, false) + output, err := YAMLToTerraformResources(r, "", false, false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) @@ -129,7 +164,7 @@ data: TEST: two` r := strings.NewReader(yaml) - output, err := YAMLToTerraformResources(r, "", false, false, false) + output, err := YAMLToTerraformResources(r, "", false, false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) @@ -192,7 +227,7 @@ items: ` r := strings.NewReader(yaml) - output, err := YAMLToTerraformResources(r, "", false, false, false) + output, err := YAMLToTerraformResources(r, "", false, false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) @@ -252,7 +287,7 @@ data: TEST: test` r := strings.NewReader(yaml) - output, err := YAMLToTerraformResources(r, "kubernetes-alpha", false, false, false) + output, err := YAMLToTerraformResources(r, "kubernetes-alpha", false, false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) @@ -297,7 +332,7 @@ metadata: - test` r := strings.NewReader(yaml) - output, err := YAMLToTerraformResources(r, "", true, false, false) + output, err := YAMLToTerraformResources(r, "", true, false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) @@ -334,7 +369,7 @@ metadata: uid: bea6500b-0637-4d2d-b726-e0bda0b595dd` r := strings.NewReader(yaml) - output, err := YAMLToTerraformResources(r, "", true, true, false) + output, err := YAMLToTerraformResources(r, "", true, true, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) @@ -381,7 +416,7 @@ metadata: uid: bea6500b-0637-4d2d-b726-e0bda0b595dd` r := strings.NewReader(yaml) - output, err := YAMLToTerraformResources(r, "", true, false, false) + output, err := YAMLToTerraformResources(r, "", true, false, false, false) if err != nil { t.Fatal("Converting to HCL failed:", err) From a1b1b8f4349e50d62fe79af2dbfe269b36bd4441 Mon Sep 17 00:00:00 2001 From: John Houston Date: Thu, 23 Sep 2021 00:22:52 -0400 Subject: [PATCH 2/2] Update CHANGELOG and README --- CHANGELOG.md | 1 + README.md | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38cc765..79064c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Support resources using generateName - Add option to remove quotes from object/map keys when not needed +- Add option to add a comment with the import syntax # 0.1.7 diff --git a/README.md b/README.md index a447a03..f3babc9 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,12 @@ export PATH=$PATH:$(go env GOPATH)/bin ``` Usage of tfk8s: -f, --file string Input file containing Kubernetes YAML manifests (default "-") + -I, --import Add a comment above each resource with the terraform import command -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. + -Q, --strip-key-quotes Strip out quotes from HCL map keys unless they are required -V, --version Show tool version ```