From 28d1037864e8d6ded8aef0f0d994a1cf4fe8b564 Mon Sep 17 00:00:00 2001 From: Kevin Gunn Date: Tue, 26 Nov 2019 00:57:17 -0500 Subject: [PATCH] change galaxycommand to galaxy_command and add fixer --- fix/fixer.go | 2 + fix/fixer_galaxy_command.go | 76 ++++++++++++++++++ fix/fixer_galaxy_command_test.go | 79 +++++++++++++++++++ provisioner/ansible-local/provisioner.go | 2 +- .../ansible-local/provisioner.hcl2spec.go | 2 +- 5 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 fix/fixer_galaxy_command.go create mode 100644 fix/fixer_galaxy_command_test.go diff --git a/fix/fixer.go b/fix/fixer.go index dceb866fb..fc82642da 100644 --- a/fix/fixer.go +++ b/fix/fixer.go @@ -45,6 +45,7 @@ func init() { "clean-image-name": new(FixerCleanImageName), "spot-price-auto-product": new(FixerAmazonSpotPriceProductDeprecation), "qemu-disk-size": new(FixerQEMUDiskSize), + "galaxy-command": new(FixerGalaxyCommand), } FixerOrder = []string{ @@ -73,5 +74,6 @@ func init() { "clean-image-name", "spot-price-auto-product", "qemu-disk-size", + "galaxy-command", } } diff --git a/fix/fixer_galaxy_command.go b/fix/fixer_galaxy_command.go new file mode 100644 index 000000000..781ae216e --- /dev/null +++ b/fix/fixer_galaxy_command.go @@ -0,0 +1,76 @@ +package fix + +import ( + "strings" + + "github.com/mitchellh/mapstructure" +) + +// FixerGalaxyCommand removes the escape character from user +// environment variables and replace galaxycommand with galaxy_command +type FixerGalaxyCommand struct{} + +func (FixerGalaxyCommand) Fix(input map[string]interface{}) (map[string]interface{}, error) { + type template struct { + Provisioners []interface{} + } + + var gcUnescape = strings.NewReplacer( + "`$", "$", + "`\"", "\"", + "``", "`", + "`'", "'", + ) + + // Decode the input into our structure, if we can + var tpl template + if err := mapstructure.WeakDecode(input, &tpl); err != nil { + return nil, err + } + + for i, raw := range tpl.Provisioners { + var provisioners map[string]interface{} + if err := mapstructure.Decode(raw, &provisioners); err != nil { + // Ignore errors, could be a non-map + continue + } + + if ok := provisioners["type"] == "ansible*" || provisioners["type"] == "ansible-local"; !ok { + continue + } + + if _, ok := provisioners["galaxy_command"]; ok { + provisioners["galaxy_command"] = gcUnescape.Replace(provisioners["galaxy_command"].(string)) + + // drop galaxycommand if it is also included + if _, galaxyCommandIncluded := provisioners["galaxycommand"]; galaxyCommandIncluded { + delete(provisioners, "galaxycommand") + } + + } else { + + // replace galaxycommand with galaxy_command if it exists + galaxyCommandRaw, ok := provisioners["galaxycommand"] + if !ok { + continue + } + galaxyCommandString := gcUnescape.Replace(galaxyCommandRaw.(string)) + + delete(provisioners, "galaxycommand") + provisioners["galaxy_command"] = galaxyCommandString + } + + // Write all changes back to template + tpl.Provisioners[i] = provisioners + } + + if len(tpl.Provisioners) > 0 { + input["provisioners"] = tpl.Provisioners + } + + return input, nil +} + +func (FixerGalaxyCommand) Synopsis() string { + return `Removes escapes from user env vars and updates provisioners to use "galaxy_command" rather than "galaxycommand"` +} diff --git a/fix/fixer_galaxy_command_test.go b/fix/fixer_galaxy_command_test.go new file mode 100644 index 000000000..6d965142e --- /dev/null +++ b/fix/fixer_galaxy_command_test.go @@ -0,0 +1,79 @@ +package fix + +import ( + "reflect" + "testing" +) + +func TestFixerGalaxyCommand_Impl(t *testing.T) { + var _ Fixer = new(FixerGalaxyCommand) +} + +func TestFixerGalaxyCommand_Fix(t *testing.T) { + cases := []struct { + Input map[string]interface{} + Expected map[string]interface{} + }{ + // set galaxy_command + { + Input: map[string]interface{}{ + "type": "ansible", + "galaxy_command": "/usr/local/bin/ansible-galaxy", + }, + + Expected: map[string]interface{}{ + "type": "ansible", + "galaxy_command": "/usr/local/bin/ansible-galaxy", + }, + }, + + // set galaxycommand (old key) + { + Input: map[string]interface{}{ + "type": "ansible-local", + "galaxycommand": "/usr/bin/ansible-galaxy", + }, + + Expected: map[string]interface{}{ + "type": "ansible-local", + "galaxy_command": "/usr/bin/ansible-galaxy", + }, + }, + + // set galaxy_command and galaxycommand + // galaxy_command takes precedence + { + Input: map[string]interface{}{ + "type": "ansible-local", + "galaxy_command": "ansible_galaxy_command", + "galaxycommand": "ansible_galaxycommand", + }, + + Expected: map[string]interface{}{ + "type": "ansible-local", + "galaxy_command": "ansible_galaxy_command", + }, + }, + } + + for _, tc := range cases { + var f FixerGalaxyCommand + + input := map[string]interface{}{ + "provisioners": []interface{}{tc.Input}, + } + + expected := map[string]interface{}{ + "provisioners": []interface{}{tc.Expected}, + } + + output, err := f.Fix(input) + if err != nil { + t.Fatalf("err: %s", err) + } + + if !reflect.DeepEqual(output, expected) { + t.Fatalf("unexpected: %#v\nexpected: %#v\n", output, expected) + } + } +} diff --git a/provisioner/ansible-local/provisioner.go b/provisioner/ansible-local/provisioner.go index c3c6a6e37..a2906f9aa 100644 --- a/provisioner/ansible-local/provisioner.go +++ b/provisioner/ansible-local/provisioner.go @@ -67,7 +67,7 @@ type Config struct { GalaxyFile string `mapstructure:"galaxy_file"` // The command to run ansible-galaxy - GalaxyCommand string + GalaxyCommand string `mapstructure:"galaxy_command"` } type Provisioner struct { diff --git a/provisioner/ansible-local/provisioner.hcl2spec.go b/provisioner/ansible-local/provisioner.hcl2spec.go index 0362930e6..7424c095f 100644 --- a/provisioner/ansible-local/provisioner.hcl2spec.go +++ b/provisioner/ansible-local/provisioner.hcl2spec.go @@ -30,7 +30,7 @@ type FlatConfig struct { InventoryFile *string `mapstructure:"inventory_file" cty:"inventory_file"` InventoryGroups []string `mapstructure:"inventory_groups" cty:"inventory_groups"` GalaxyFile *string `mapstructure:"galaxy_file" cty:"galaxy_file"` - GalaxyCommand *string `cty:"galaxy_command"` + GalaxyCommand *string `mapstructure:"galaxy_command" cty:"galaxy_command"` } // FlatMapstructure returns a new FlatConfig.