Skip to content

Commit

Permalink
CDConfig: Add cd_content for file templating (#61)
Browse files Browse the repository at this point in the history
* CDConfig: Add cd_content for file templating + tests

Co-authored-by: Adrien Delorme <[email protected]>
  • Loading branch information
saleemrashid and azr authored May 26, 2021
1 parent 7aedbfb commit 2da2de8
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,22 @@
* hdiutil (normally found in macOS)
* oscdimg (normally found in Windows as part of the Windows ADK)

- `cd_content` (map[string]string) - Key/Values to add to the CD. The keys represent the paths, and the values
contents. It can be used alongside `cd_files`, which is useful to add large
files without loading them into memory. If any paths are specified by both,
the contents in `cd_content` will take precedence.

Usage example (HCL):

```hcl
cd_files = ["vendor-data"]
cd_content = {
"meta-data" = jsonencode(local.instance_data)
"user-data" = templatefile("user-data", { packages = ["nginx"] })
}
cd_label = "cidata"
```

- `cd_label` (string) - CD Label

<!-- End of code generated from the comments of the CDConfig struct in multistep/commonsteps/extra_iso_config.go; -->
18 changes: 17 additions & 1 deletion multistep/commonsteps/extra_iso_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,23 @@ type CDConfig struct {
// * hdiutil (normally found in macOS)
// * oscdimg (normally found in Windows as part of the Windows ADK)
CDFiles []string `mapstructure:"cd_files"`
CDLabel string `mapstructure:"cd_label"`
// Key/Values to add to the CD. The keys represent the paths, and the values
// contents. It can be used alongside `cd_files`, which is useful to add large
// files without loading them into memory. If any paths are specified by both,
// the contents in `cd_content` will take precedence.
//
// Usage example (HCL):
//
// ```hcl
// cd_files = ["vendor-data"]
// cd_content = {
// "meta-data" = jsonencode(local.instance_data)
// "user-data" = templatefile("user-data", { packages = ["nginx"] })
// }
// cd_label = "cidata"
// ```
CDContent map[string]string `mapstructure:"cd_content"`
CDLabel string `mapstructure:"cd_label"`
}

func (c *CDConfig) Prepare(ctx *interpolate.Context) []error {
Expand Down
32 changes: 29 additions & 3 deletions multistep/commonsteps/step_create_cdrom.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
Expand All @@ -22,16 +23,17 @@ type StepCreateCD struct {
// Files can be either files or directories. Any files provided here will
// be written to the root of the CD. Directories will be written to the
// root of the CD as well, but will retain their subdirectory structure.
Files []string
Label string
Files []string
Content map[string]string
Label string

CDPath string

rootFolder string
}

func (s *StepCreateCD) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
if len(s.Files) == 0 {
if len(s.Files) == 0 && len(s.Content) == 0 {
log.Println("No CD files specified. CD disk will not be made.")
return multistep.ActionContinue
}
Expand Down Expand Up @@ -79,6 +81,15 @@ func (s *StepCreateCD) Run(ctx context.Context, state multistep.StateBag) multis
}
}

for path, content := range s.Content {
err = s.AddContent(rootFolder, path, content)
if err != nil {
state.Put("error",
fmt.Errorf("Error creating temporary file for CD: %s", err))
return multistep.ActionHalt
}
}

cmd, err := retrieveCDISOCreationCommand(s.Label, rootFolder, CDPath)
if err != nil {
state.Put("error", err)
Expand Down Expand Up @@ -291,3 +302,18 @@ func (s *StepCreateCD) AddFile(dst, src string) error {

return filepath.Walk(src, visit)
}

func (s *StepCreateCD) AddContent(dst, path, content string) error {
// Join Cleans the path so we can join it without path traversal issues.
dstPath := filepath.Join(dst, path)
dstDir := filepath.Dir(dstPath)
err := os.MkdirAll(dstDir, 0777)
if err != nil {
return fmt.Errorf("error creating new directory %s: %s", dstDir, err)
}
err = ioutil.WriteFile(dstPath, []byte(content), 0666)
if err != nil {
return fmt.Errorf("Error writing file %s on CD: %s", path, err)
}
return nil
}
31 changes: 27 additions & 4 deletions multistep/commonsteps/step_create_cdrom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,25 @@ func TestStepCreateCD(t *testing.T) {
}
defer os.RemoveAll(dir)

expected := map[string]string{
createFiles(t, dir, map[string]string{
"test folder/b/test1": "1",
"test folder/b/test2": "2",
"test folder 2/x": "3",
"test_cd_roms.tmp": "4",
"test cd files.tmp": "5",
"Test-Test-Test5.tmp": "6",
"subfolder/meta-data": "subfolder/meta-data from files",
"subfolder/user-data": "subfolder/user-data from files",
"user-data": "user-data from files",
"vendor-data": "vendor-data from files",
})
step.Content = map[string]string{
"subfolder not created by files/test.tmp": "test",
"subfolder/meta-data": "subfolder/meta-data from content",
"user-data": "user-data from content",
}

createFiles(t, dir, expected)
files := []string{"test folder", "test folder 2/", "test_cd_roms.tmp", "test cd files.tmp", "Test-Test-Test5.tmp"}
files := []string{"test folder", "test folder 2/", "test_cd_roms.tmp", "test cd files.tmp", "Test-Test-Test5.tmp", "subfolder", "user-data", "vendor-data"}

step.Files = make([]string, len(files))
for i, fname := range files {
Expand All @@ -124,7 +132,19 @@ func TestStepCreateCD(t *testing.T) {
t.Fatalf("file not found: %s for %v", CD_path, step.Files)
}

checkFiles(t, step.rootFolder, expected)
checkFiles(t, step.rootFolder, map[string]string{
"test folder/b/test1": "1",
"test folder/b/test2": "2",
"test folder 2/x": "3",
"test_cd_roms.tmp": "4",
"test cd files.tmp": "5",
"Test-Test-Test5.tmp": "6",
"subfolder not created by files/test.tmp": "test",
"subfolder/meta-data": "subfolder/meta-data from content",
"subfolder/user-data": "subfolder/user-data from files",
"user-data": "user-data from content",
"vendor-data": "vendor-data from files",
})

step.Cleanup(state)

Expand All @@ -150,6 +170,9 @@ func TestStepCreateCD_missing(t *testing.T) {
defer os.RemoveAll(dir)

step.Files = []string{"missing file.tmp"}
step.Content = map[string]string{
"test_cd_roms.tmp": "should not be created",
}
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
t.Fatalf("bad action: %#v for %v", action, step.Files)
}
Expand Down

0 comments on commit 2da2de8

Please sign in to comment.