2014-10-27 23:34:49 -04:00
|
|
|
package command
|
2013-07-14 02:29:19 -04:00
|
|
|
|
|
|
|
import (
|
2013-07-14 04:05:26 -04:00
|
|
|
"bytes"
|
2013-07-14 02:29:19 -04:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2013-08-08 20:12:04 -04:00
|
|
|
"log"
|
2013-07-14 02:29:19 -04:00
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
|
2017-04-04 16:39:01 -04:00
|
|
|
"github.com/hashicorp/packer/fix"
|
|
|
|
"github.com/hashicorp/packer/template"
|
2017-10-13 14:42:22 -04:00
|
|
|
|
|
|
|
"github.com/posener/complete"
|
2014-10-27 23:34:49 -04:00
|
|
|
)
|
2013-07-14 02:29:19 -04:00
|
|
|
|
2014-10-27 23:34:49 -04:00
|
|
|
type FixCommand struct {
|
|
|
|
Meta
|
2013-07-14 02:29:19 -04:00
|
|
|
}
|
|
|
|
|
2014-10-27 23:34:49 -04:00
|
|
|
func (c *FixCommand) Run(args []string) int {
|
2015-06-13 13:56:09 -04:00
|
|
|
var flagValidate bool
|
2015-05-25 20:29:10 -04:00
|
|
|
flags := c.Meta.FlagSet("fix", FlagSetNone)
|
2015-06-13 13:56:09 -04:00
|
|
|
flags.BoolVar(&flagValidate, "validate", true, "")
|
2015-05-25 20:29:10 -04:00
|
|
|
flags.Usage = func() { c.Ui.Say(c.Help()) }
|
|
|
|
if err := flags.Parse(args); err != nil {
|
2013-07-14 02:29:19 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2015-05-25 20:29:10 -04:00
|
|
|
args = flags.Args()
|
2013-07-14 02:29:19 -04:00
|
|
|
if len(args) != 1 {
|
2015-05-25 20:29:10 -04:00
|
|
|
flags.Usage()
|
2013-07-14 02:29:19 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read the file for decoding
|
|
|
|
tplF, err := os.Open(args[0])
|
|
|
|
if err != nil {
|
2015-05-25 20:29:10 -04:00
|
|
|
c.Ui.Error(fmt.Sprintf("Error opening template: %s", err))
|
2013-07-14 02:29:19 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
defer tplF.Close()
|
|
|
|
|
|
|
|
// Decode the JSON into a generic map structure
|
|
|
|
var templateData map[string]interface{}
|
|
|
|
decoder := json.NewDecoder(tplF)
|
|
|
|
if err := decoder.Decode(&templateData); err != nil {
|
2015-05-25 20:29:10 -04:00
|
|
|
c.Ui.Error(fmt.Sprintf("Error parsing template: %s", err))
|
2013-07-14 02:29:19 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close the file since we're done with that
|
|
|
|
tplF.Close()
|
|
|
|
|
2013-07-14 04:05:26 -04:00
|
|
|
input := templateData
|
2014-10-27 23:34:49 -04:00
|
|
|
for _, name := range fix.FixerOrder {
|
2013-07-14 04:05:26 -04:00
|
|
|
var err error
|
2014-10-27 23:34:49 -04:00
|
|
|
fixer, ok := fix.Fixers[name]
|
2013-08-08 20:11:39 -04:00
|
|
|
if !ok {
|
|
|
|
panic("fixer not found: " + name)
|
|
|
|
}
|
|
|
|
|
2013-08-08 20:12:04 -04:00
|
|
|
log.Printf("Running fixer: %s", name)
|
2013-07-14 04:05:26 -04:00
|
|
|
input, err = fixer.Fix(input)
|
|
|
|
if err != nil {
|
2015-05-25 20:29:10 -04:00
|
|
|
c.Ui.Error(fmt.Sprintf("Error fixing: %s", err))
|
2013-07-14 04:05:26 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var output bytes.Buffer
|
|
|
|
encoder := json.NewEncoder(&output)
|
|
|
|
if err := encoder.Encode(input); err != nil {
|
2015-05-25 20:29:10 -04:00
|
|
|
c.Ui.Error(fmt.Sprintf("Error encoding: %s", err))
|
2013-07-14 04:05:26 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
var indented bytes.Buffer
|
|
|
|
if err := json.Indent(&indented, output.Bytes(), "", " "); err != nil {
|
2015-05-25 20:29:10 -04:00
|
|
|
c.Ui.Error(fmt.Sprintf("Error encoding: %s", err))
|
2013-07-14 04:05:26 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2013-07-14 04:10:50 -04:00
|
|
|
result := indented.String()
|
|
|
|
result = strings.Replace(result, `\u003c`, "<", -1)
|
|
|
|
result = strings.Replace(result, `\u003e`, ">", -1)
|
2015-05-25 20:29:10 -04:00
|
|
|
c.Ui.Say(result)
|
2015-06-13 13:56:09 -04:00
|
|
|
|
|
|
|
if flagValidate {
|
2018-03-13 03:11:42 -04:00
|
|
|
// Attempt to parse and validate the template
|
2015-06-13 13:56:09 -04:00
|
|
|
tpl, err := template.Parse(strings.NewReader(result))
|
|
|
|
if err != nil {
|
|
|
|
c.Ui.Error(fmt.Sprintf(
|
|
|
|
"Error! Fixed template fails to parse: %s\n\n"+
|
|
|
|
"This is usually caused by an error in the input template.\n"+
|
|
|
|
"Please fix the error and try again.",
|
|
|
|
err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
if err := tpl.Validate(); err != nil {
|
|
|
|
c.Ui.Error(fmt.Sprintf(
|
|
|
|
"Error! Fixed template failed to validate: %s\n\n"+
|
|
|
|
"This is usually caused by an error in the input template.\n"+
|
|
|
|
"Please fix the error and try again.",
|
|
|
|
err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-14 02:29:19 -04:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2014-10-27 23:34:49 -04:00
|
|
|
func (*FixCommand) Help() string {
|
|
|
|
helpText := `
|
|
|
|
Usage: packer fix [options] TEMPLATE
|
|
|
|
|
|
|
|
Reads the JSON template and attempts to fix known backwards
|
|
|
|
incompatibilities. The fixed template will be outputted to standard out.
|
|
|
|
|
|
|
|
If the template cannot be fixed due to an error, the command will exit
|
|
|
|
with a non-zero exit status. Error messages will appear on standard error.
|
|
|
|
|
|
|
|
Fixes that are run:
|
|
|
|
|
2018-07-10 11:59:26 -04:00
|
|
|
iso-md5 Replaces "iso_md5" in builders with newer
|
|
|
|
"iso_checksum"
|
|
|
|
createtime Replaces ".CreateTime" in builder configs with
|
|
|
|
"{{timestamp}}"
|
|
|
|
virtualbox-gaattach Updates VirtualBox builders using
|
|
|
|
"guest_additions_attach" to use
|
|
|
|
"guest_additions_mode"
|
|
|
|
pp-vagrant-override Replaces old-style provider overrides for the
|
|
|
|
Vagrant post-processor to new-style as of Packer
|
|
|
|
0.5.0.
|
|
|
|
virtualbox-rename Updates "virtualbox" builders to "virtualbox-iso"
|
|
|
|
vmware-rename Updates "vmware" builders to "vmware-iso"
|
|
|
|
parallels-headless Removes unused "headless" setting from Parallels
|
|
|
|
builders
|
|
|
|
parallels-deprecations Removes deprecated "parallels_tools_host_path" from
|
|
|
|
Parallels builders
|
|
|
|
sshkeypath Updates builders using "ssh_key_path" to use
|
|
|
|
"ssh_private_key_file"
|
|
|
|
sshdisableagent Updates builders using "ssh_disable_agent" to use
|
|
|
|
"ssh_disable_agent_forwarding"
|
|
|
|
manifest-filename Updates "manifest" post-processor so any "filename"
|
|
|
|
field is renamed to "output"
|
|
|
|
amazon-shutdown_behavior Changes "shutdown_behaviour" to "shutdown_behavior"
|
|
|
|
in Amazon builders
|
|
|
|
amazon-enhanced-networking Replaces "enhanced_networking" in builders with
|
|
|
|
"ena_support"
|
|
|
|
amazon-private-ip Replaces "ssh_private_ip": true in amazon builders
|
|
|
|
with "ssh_interface": "private_ip"
|
|
|
|
docker-email Removes "login_email" from the Docker builder
|
|
|
|
powershell-escapes Removes PowerShell escapes from user env vars and
|
|
|
|
elevated username and password strings
|
2015-06-13 13:56:09 -04:00
|
|
|
|
|
|
|
Options:
|
|
|
|
|
|
|
|
-validate=true If true (default), validates the fixed template.
|
2014-10-27 23:34:49 -04:00
|
|
|
`
|
|
|
|
|
|
|
|
return strings.TrimSpace(helpText)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *FixCommand) Synopsis() string {
|
2013-07-14 02:29:19 -04:00
|
|
|
return "fixes templates from old versions of packer"
|
|
|
|
}
|
2017-10-13 14:42:22 -04:00
|
|
|
|
|
|
|
func (c *FixCommand) AutocompleteArgs() complete.Predictor {
|
|
|
|
return complete.PredictNothing
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *FixCommand) AutocompleteFlags() complete.Flags {
|
|
|
|
return complete.Flags{
|
|
|
|
"-validate": complete.PredictNothing,
|
|
|
|
}
|
|
|
|
}
|