package main import ( "fmt" "strings" "github.com/Cadoles/goca" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/template/interpolate" ) // Config handles configuration options of the OpenNebula post-processor type Config struct { common.PackerConfig `mapstructure:",squash"` User string Password string Endpoint string ImageName string `mapstructure:"image_name"` ImageTemplate []string `mapstructure:"image_template"` DatastoreName string `mapstructure:"datastore_name"` MergeTemplate bool `mapstructure:"merge_template"` ctx interpolate.Context } // PostProcessor is an OpenNebula post processor for packer type PostProcessor struct { Conf *Config } // Configure configures the packer OpenNebula post-processor func (pp *PostProcessor) Configure(raws ...interface{}) error { conf := &Config{} err := config.Decode(conf, &config.DecodeOpts{ Interpolate: true, InterpolateContext: &conf.ctx, }, raws...) if err != nil { return err } pp.Conf = conf return nil } // PostProcess creates/updates your configured image to OpenNebula using the XML-RPC API func (pp *PostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, bool, error) { // Initialize OpenNebula XML-RPC API client config := goca.NewConfig(pp.Conf.User, pp.Conf.Password, pp.Conf.Endpoint) if err := goca.SetClient(config); err != nil { return a, true, err } // Search image template by its name img, err := goca.NewImageFromName(pp.Conf.ImageName) if err != nil && err.Error() != "resource not found" { return a, true, err } ui.Say(fmt.Sprintf("Connecting to OpenNebula RPC endpoint '%s' with provided credentials...", pp.Conf.Endpoint)) // Generate image template tmplStr := serializeImageTemplate(pp.Conf.ImageTemplate) // Fi the image template can not be found, we create it if img == nil { ui.Say(fmt.Sprintf("The OpenNebula image template '%s' could not be found. Creating it...", pp.Conf.ImageName)) // Search image datastore's ID datastore, err := goca.NewDatastoreFromName(pp.Conf.DatastoreName) if err != nil { return a, true, err } // Create image template if _, err = goca.CreateImage(tmplStr, datastore.ID); err != nil { return a, true, err } } else { ui.Say(fmt.Sprintf("The OpenNebula image template '%s' has been found. Updating it...", pp.Conf.ImageName)) // Update image template if err := img.Update(tmplStr, pp.Conf.MergeTemplate); err != nil { return a, true, err } } ui.Say("Operation completed.") return a, true, nil } func serializeImageTemplate(tmpl []string) string { return strings.Join(tmpl, "\n") }