Skip to content

Commit

Permalink
handle multi-document YAMLs without panic (#49)
Browse files Browse the repository at this point in the history
Signed-off-by: Nandor Kracser <bonifaido@gmail.com>
  • Loading branch information
bonifaido authored May 21, 2020
1 parent 44df98e commit b0f7285
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 21 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
terraform.tfstate
terraform.tfstate.backup
.terraform/
crash.log
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ provider "k8s" {
}
```

The k8s Terraform provider introduces a single Terraform resource, a `k8s_manifest`. The resource contains a `content` field, which contains a raw manifest.
The `k8s` Terraform provider introduces a single Terraform resource, a `k8s_manifest`. The resource contains a `content` field, which contains a raw manifest in JSON or YAML format.

```hcl
variable "replicas" {
Expand Down Expand Up @@ -125,6 +125,24 @@ $ kubectl get deployments
No resources found.
```

**NOTE**: If the YAML formatted `content` contains multiple documents (separated by `---`) only the first non-empty document is going to be parsed. This is because Terraform is mostly designed to represent a single resource on the provider side with a Terraform resource:

> resource types correspond to an infrastructure object type that is managed via a remote network API
> -- <cite>[Terraform Documentation](https://www.terraform.io/docs/configuration/resources.html)</cite>
You can workaround this easily with the following snippet (however we still suggest to use separate resources):

```hcl
locals {
resources = split("\n---\n", data.template_file.ngnix.rendered)
}
resource "k8s_manifest" "nginx-deployment" {
count = length(local.resources)
content = local.resources[count.index]
}
```

## Helm workflow

Expand Down
2 changes: 2 additions & 0 deletions examples/manifests/my-configmap.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
---

kind: ConfigMap
apiVersion: v1
metadata:
Expand Down
46 changes: 26 additions & 20 deletions k8s/resource_k8s_manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package k8s
import (
"context"
"fmt"
"io"
"log"
"strings"
"time"
Expand Down Expand Up @@ -51,9 +50,9 @@ func resourceK8sManifest() *schema.Resource {
},
},
Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(3 * time.Minute),
Update: schema.DefaultTimeout(3 * time.Minute),
Delete: schema.DefaultTimeout(3 * time.Minute),
Create: schema.DefaultTimeout(3 * time.Minute),
Update: schema.DefaultTimeout(3 * time.Minute),
Delete: schema.DefaultTimeout(3 * time.Minute),
},
}
}
Expand All @@ -63,14 +62,9 @@ func resourceK8sManifestCreate(d *schema.ResourceData, config interface{}) error
namespace := d.Get("namespace").(string)
content := d.Get("content").(string)

decoder := yaml.NewYAMLOrJSONDecoder(strings.NewReader(content), 4096)

var object *unstructured.Unstructured

// TODO: add support for a list of objects?
err := decoder.Decode(&object)
if err != nil && err != io.EOF {
return fmt.Errorf("Failed to unmarshal manifest: %s", err)
object, err := contentToObject(content)
if err != nil {
return err
}

objectNamespace := object.GetNamespace()
Expand Down Expand Up @@ -271,14 +265,9 @@ func resourceK8sManifestUpdate(d *schema.ResourceData, config interface{}) error

content := d.Get("content").(string)

decoder := yaml.NewYAMLOrJSONDecoder(strings.NewReader(content), 4096)

var object *unstructured.Unstructured

// TODO: add support for a list of objects?
err = decoder.Decode(&object)
if err != nil && err != io.EOF {
return fmt.Errorf("Failed to unmarshal manifest: %s", err)
object, err := contentToObject(content)
if err != nil {
return err
}

objectNamespace := object.GetNamespace()
Expand Down Expand Up @@ -429,3 +418,20 @@ func resourceK8sManifestImport(d *schema.ResourceData, config interface{}) ([]*s

return []*schema.ResourceData{&resource}, nil
}

func contentToObject(content string) (*unstructured.Unstructured, error) {
decoder := yaml.NewYAMLOrJSONDecoder(strings.NewReader(content), 4096)

var object *unstructured.Unstructured

for {
err := decoder.Decode(&object)
if err != nil {
return nil, fmt.Errorf("Failed to unmarshal manifest: %s", err)
}

if object != nil {
return object, nil
}
}
}

0 comments on commit b0f7285

Please sign in to comment.