github.com/askholme/packer@v0.7.2-0.20140924152349-70d9566a6852/builder/virtualbox/ovf/config.go (about) 1 package ovf 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 8 vboxcommon "github.com/mitchellh/packer/builder/virtualbox/common" 9 "github.com/mitchellh/packer/common" 10 "github.com/mitchellh/packer/packer" 11 ) 12 13 // Config is the configuration structure for the builder. 14 type Config struct { 15 common.PackerConfig `mapstructure:",squash"` 16 vboxcommon.ExportConfig `mapstructure:",squash"` 17 vboxcommon.ExportOpts `mapstructure:",squash"` 18 vboxcommon.FloppyConfig `mapstructure:",squash"` 19 vboxcommon.OutputConfig `mapstructure:",squash"` 20 vboxcommon.RunConfig `mapstructure:",squash"` 21 vboxcommon.SSHConfig `mapstructure:",squash"` 22 vboxcommon.ShutdownConfig `mapstructure:",squash"` 23 vboxcommon.VBoxManageConfig `mapstructure:",squash"` 24 vboxcommon.VBoxManagePostConfig `mapstructure:",squash"` 25 vboxcommon.VBoxVersionConfig `mapstructure:",squash"` 26 27 BootCommand []string `mapstructure:"boot_command"` 28 SourcePath string `mapstructure:"source_path"` 29 GuestAdditionsMode string `mapstructure:"guest_additions_mode"` 30 GuestAdditionsPath string `mapstructure:"guest_additions_path"` 31 GuestAdditionsURL string `mapstructure:"guest_additions_url"` 32 GuestAdditionsSHA256 string `mapstructure:"guest_additions_sha256"` 33 VMName string `mapstructure:"vm_name"` 34 ImportOpts string `mapstructure:"import_opts"` 35 ImportFlags []string `mapstructure:"import_flags"` 36 37 tpl *packer.ConfigTemplate 38 } 39 40 func NewConfig(raws ...interface{}) (*Config, []string, error) { 41 c := new(Config) 42 md, err := common.DecodeConfig(c, raws...) 43 if err != nil { 44 return nil, nil, err 45 } 46 47 c.tpl, err = packer.NewConfigTemplate() 48 if err != nil { 49 return nil, nil, err 50 } 51 c.tpl.UserVars = c.PackerUserVars 52 53 // Defaults 54 if c.GuestAdditionsMode == "" { 55 c.GuestAdditionsMode = "upload" 56 } 57 58 if c.GuestAdditionsPath == "" { 59 c.GuestAdditionsPath = "VBoxGuestAdditions.iso" 60 } 61 if c.VMName == "" { 62 c.VMName = fmt.Sprintf("packer-%s-{{timestamp}}", c.PackerBuildName) 63 } 64 65 // Prepare the errors 66 errs := common.CheckUnusedConfig(md) 67 errs = packer.MultiErrorAppend(errs, c.ExportConfig.Prepare(c.tpl)...) 68 errs = packer.MultiErrorAppend(errs, c.ExportOpts.Prepare(c.tpl)...) 69 errs = packer.MultiErrorAppend(errs, c.FloppyConfig.Prepare(c.tpl)...) 70 errs = packer.MultiErrorAppend(errs, c.OutputConfig.Prepare(c.tpl, &c.PackerConfig)...) 71 errs = packer.MultiErrorAppend(errs, c.RunConfig.Prepare(c.tpl)...) 72 errs = packer.MultiErrorAppend(errs, c.ShutdownConfig.Prepare(c.tpl)...) 73 errs = packer.MultiErrorAppend(errs, c.SSHConfig.Prepare(c.tpl)...) 74 errs = packer.MultiErrorAppend(errs, c.VBoxManageConfig.Prepare(c.tpl)...) 75 errs = packer.MultiErrorAppend(errs, c.VBoxManagePostConfig.Prepare(c.tpl)...) 76 errs = packer.MultiErrorAppend(errs, c.VBoxVersionConfig.Prepare(c.tpl)...) 77 78 templates := map[string]*string{ 79 "guest_additions_mode": &c.GuestAdditionsMode, 80 "guest_additions_sha256": &c.GuestAdditionsSHA256, 81 "source_path": &c.SourcePath, 82 "vm_name": &c.VMName, 83 "import_opts": &c.ImportOpts, 84 } 85 86 for n, ptr := range templates { 87 var err error 88 *ptr, err = c.tpl.Process(*ptr, nil) 89 if err != nil { 90 errs = packer.MultiErrorAppend( 91 errs, fmt.Errorf("Error processing %s: %s", n, err)) 92 } 93 } 94 95 sliceTemplates := map[string][]string{ 96 "import_flags": c.ImportFlags, 97 } 98 99 for n, slice := range sliceTemplates { 100 for i, elem := range slice { 101 var err error 102 slice[i], err = c.tpl.Process(elem, nil) 103 if err != nil { 104 errs = packer.MultiErrorAppend( 105 errs, fmt.Errorf("Error processing %s[%d]: %s", n, i, err)) 106 } 107 } 108 } 109 110 if c.SourcePath == "" { 111 errs = packer.MultiErrorAppend(errs, fmt.Errorf("source_path is required")) 112 } else { 113 if _, err := os.Stat(c.SourcePath); err != nil { 114 errs = packer.MultiErrorAppend(errs, 115 fmt.Errorf("source_path is invalid: %s", err)) 116 } 117 } 118 119 for i, command := range c.BootCommand { 120 if err := c.tpl.Validate(command); err != nil { 121 errs = packer.MultiErrorAppend(errs, 122 fmt.Errorf("Error processing boot_command[%d]: %s", i, err)) 123 } 124 } 125 126 validates := map[string]*string{ 127 "guest_additions_path": &c.GuestAdditionsPath, 128 "guest_additions_url": &c.GuestAdditionsURL, 129 } 130 131 for n, ptr := range validates { 132 if err := c.tpl.Validate(*ptr); err != nil { 133 errs = packer.MultiErrorAppend( 134 errs, fmt.Errorf("Error parsing %s: %s", n, err)) 135 } 136 } 137 138 validMode := false 139 validModes := []string{ 140 vboxcommon.GuestAdditionsModeDisable, 141 vboxcommon.GuestAdditionsModeAttach, 142 vboxcommon.GuestAdditionsModeUpload, 143 } 144 145 for _, mode := range validModes { 146 if c.GuestAdditionsMode == mode { 147 validMode = true 148 break 149 } 150 } 151 152 if !validMode { 153 errs = packer.MultiErrorAppend(errs, 154 fmt.Errorf("guest_additions_mode is invalid. Must be one of: %v", validModes)) 155 } 156 157 if c.GuestAdditionsSHA256 != "" { 158 c.GuestAdditionsSHA256 = strings.ToLower(c.GuestAdditionsSHA256) 159 } 160 161 // Warnings 162 var warnings []string 163 if c.ShutdownCommand == "" { 164 warnings = append(warnings, 165 "A shutdown_command was not specified. Without a shutdown command, Packer\n"+ 166 "will forcibly halt the virtual machine, which may result in data loss.") 167 } 168 169 // Check for any errors. 170 if errs != nil && len(errs.Errors) > 0 { 171 return nil, warnings, errs 172 } 173 174 // TODO: Write a packer fix and just remove import_opts 175 if c.ImportOpts != "" { 176 c.ImportFlags = append(c.ImportFlags, "--options", c.ImportOpts) 177 } 178 179 return c, warnings, nil 180 }