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

Add ability to append Container Linux snippets #22

Merged
merged 1 commit into from
Apr 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 45 additions & 12 deletions ct/datasource_ct_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package ct

import (
"encoding/json"
"errors"
"fmt"
"strconv"

"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"

ct "github.com/coreos/container-linux-config-transpiler/config"
ignition "github.com/coreos/ignition/config/v2_1"
ignitionTypesV2_1 "github.com/coreos/ignition/config/v2_1/types"
)

func dataSourceCTConfig() *schema.Resource {
Expand All @@ -26,6 +28,14 @@ func dataSourceCTConfig() *schema.Resource {
Default: "",
ForceNew: true,
},
"snippets": &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Optional: true,
ForceNew: true,
},
"pretty_print": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Expand All @@ -52,27 +62,50 @@ func dataSourceCTConfigRead(d *schema.ResourceData, meta interface{}) error {
}

func renderCTConfig(d *schema.ResourceData) (string, error) {
config := d.Get("content").(string)
// unchecked assertions seem to be the norm in Terraform :S
content := d.Get("content").(string)
platform := d.Get("platform").(string)
snippetsIface := d.Get("snippets").([]interface{})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with terraform libraries, but why not assert this to be a []string? It feels like if the input doesn't match that it would be an error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did try that originally. The underlying data Terraform Get gives here is actually a slice of interfaces so the assertion to []string fails. I'll look into this again, the rampant use of assertions is saddening.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, Go doesn't let you assert a []interface{} to a []string, but it does let you iterate over a []interface and assert each thing individually to a string. What a great type system.

pretty := d.Get("pretty_print").(bool)

// parse bytes int a Container Linux Config
cfg, ast, rpt := ct.Parse([]byte(config))
if rpt.IsFatal() {
return "", errors.New(rpt.String())
snippets := make([]string, len(snippetsIface))
for i := range snippetsIface {
snippets[i] = snippetsIface[i].(string)
}

// convert Container Linux Config to an Ignition Config
ignition, rpt := ct.Convert(cfg, platform, ast)
if rpt.IsFatal() {
return "", errors.New(rpt.String())
ign, err := clcToIgnition([]byte(content), platform)
if err != nil {
return "", err
}

for _, content := range snippets {
ignext, err := clcToIgnition([]byte(content), platform)
if err != nil {
return "", err
}
ign = ignition.Append(ign, ignext)
}

if pretty {
ignitionJSON, err := json.MarshalIndent(&ignition, "", " ")
ignitionJSON, err := json.MarshalIndent(ign, "", " ")
return string(ignitionJSON), err
}

ignitionJSON, err := json.Marshal(&ignition)
ignitionJSON, err := json.Marshal(ign)
return string(ignitionJSON), err
}

// Parse Container Linux config and convert to Ignition v2.1.0 format.
func clcToIgnition(data []byte, platform string) (ignitionTypesV2_1.Config, error) {
// parse bytes into a Container Linux Config
clc, ast, report := ct.Parse([]byte(data))
if report.IsFatal() {
return ignitionTypesV2_1.Config{}, fmt.Errorf("error parsing Container Linux Config: %v", report.String())
}
// convert Container Linux Config to an Ignition Config
ign, report := ct.Convert(clc, platform, ast)
if report.IsFatal() {
return ignitionTypesV2_1.Config{}, fmt.Errorf("error converting to Ignition: %v", report.String())
}
return ign, nil
}
58 changes: 58 additions & 0 deletions ct/datasource_ct_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,58 @@ const ec2Expected = `{
}
}`

const snippetsResource = `
data "ct_config" "combine" {
pretty_print = true
content = <<EOT
---
storage:
filesystems:
- name: "rootfs"
mount:
device: "/dev/disk/by-label/ROOT"
format: "ext4"
EOT
snippets = [
<<EOT
---
systemd:
units:
- name: docker.service
enable: true
EOT
]
}
`
const snippetsExpected = `{
"ignition": {
"config": {},
"timeouts": {},
"version": "2.1.0"
},
"networkd": {},
"passwd": {},
"storage": {
"filesystems": [
{
"mount": {
"device": "/dev/disk/by-label/ROOT",
"format": "ext4"
},
"name": "rootfs"
}
]
},
"systemd": {
"units": [
{
"enable": true,
"name": "docker.service"
}
]
}
}`

func TestRender(t *testing.T) {
r.UnitTest(t, r.TestCase{
Providers: testProviders,
Expand All @@ -147,6 +199,12 @@ func TestRender(t *testing.T) {
r.TestCheckResourceAttr("data.ct_config.ec2", "rendered", ec2Expected),
),
},
r.TestStep{
Config: snippetsResource,
Check: r.ComposeTestCheckFunc(
r.TestCheckResourceAttr("data.ct_config.combine", "rendered", snippetsExpected),
),
},
},
})
}
5 changes: 5 additions & 0 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 73 additions & 0 deletions vendor/github.com/coreos/ignition/config/validate/astjson/node.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading