From c315bcf66b27d734c8eb66327218b1f0171804c1 Mon Sep 17 00:00:00 2001 From: William Petit Date: Fri, 9 Mar 2018 12:08:34 +0100 Subject: [PATCH] =?UTF-8?q?Ajout=20mise=20=C3=A0=20jour=20des=20ACL,=20du?= =?UTF-8?q?=20propri=C3=A9taire=20du=20template=20et=20suppression=20de=20?= =?UTF-8?q?l'image=20si=20elle=20existe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../image-template/image_template.go | 136 ++++++++++++++++-- 1 file changed, 126 insertions(+), 10 deletions(-) diff --git a/cmd/post-processor/image-template/image_template.go b/cmd/post-processor/image-template/image_template.go index bf3d334..c87e215 100644 --- a/cmd/post-processor/image-template/image_template.go +++ b/cmd/post-processor/image-template/image_template.go @@ -3,6 +3,7 @@ package main import ( "fmt" "strings" + "time" "github.com/Cadoles/goca" "github.com/hashicorp/packer/common" @@ -17,11 +18,17 @@ type Config struct { 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 + ImageName string `mapstructure:"image_name"` + ImageTemplate []string `mapstructure:"image_template"` + DatastoreName string `mapstructure:"datastore_name"` + MergeTemplate int `mapstructure:"merge_template"` + DeleteIfExists bool `mapstructure:"delete_if_exists"` + ACL map[string]int `mapstructure:"acl"` + Owner *struct { + User string + Group string + } `mapstructure:"owner"` + ctx interpolate.Context } // PostProcessor is an OpenNebula post processor for packer @@ -52,21 +59,53 @@ func (pp *PostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Ar return a, true, err } + ui.Say(fmt.Sprintf("Connecting to OpenNebula RPC endpoint '%s' with provided credentials...", pp.Conf.Endpoint)) + // 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)) + if img != nil { + + // Retreive info about the template + if err := img.Info(); err != nil { + return a, true, err + } + + state, err := img.State() + if err != nil { + return a, true, err + } + + inUse := state == goca.ImageUsed || state == goca.ImageLockUsed + + if inUse { + ui.Say(fmt.Sprintf("Template '%s' is in use. Cannot delete it.", pp.Conf.ImageName)) + } + + if pp.Conf.DeleteIfExists && !inUse { + + ui.Say(fmt.Sprintf("Deleting template '%s'...", pp.Conf.ImageName)) + + if err := img.Delete(); err != nil { + return a, true, err + } + time.Sleep(1 * time.Second) + img = nil + + } + + } // Generate image template tmplStr := serializeImageTemplate(pp.Conf.ImageTemplate) - // Fi the image template can not be found, we create it + // If 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)) + ui.Say(fmt.Sprintf("Creating template '%s'...", pp.Conf.ImageName)) // Search image datastore's ID datastore, err := goca.NewDatastoreFromName(pp.Conf.DatastoreName) @@ -75,13 +114,21 @@ func (pp *PostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Ar } // Create image template - if _, err = goca.CreateImage(tmplStr, datastore.ID); err != nil { + imageID, err := goca.CreateImage(tmplStr, datastore.ID) + if err != nil { + return a, true, err + } + + img = goca.NewImage(imageID) + + // Retreive info about the template + if err := img.Info(); err != nil { return a, true, err } } else { - ui.Say(fmt.Sprintf("The OpenNebula image template '%s' has been found. Updating it...", pp.Conf.ImageName)) + ui.Say(fmt.Sprintf("Updating template '%s'...", pp.Conf.ImageName)) // Update image template if err := img.Update(tmplStr, pp.Conf.MergeTemplate); err != nil { @@ -90,6 +137,48 @@ func (pp *PostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Ar } + if pp.Conf.Owner != nil { + + currentUserName, userFound := img.XPath("/IMAGE/UNAME") + currentGroupName, groupFound := img.XPath("/IMAGE/GNAME") + + isSameUser := userFound && currentUserName == pp.Conf.Owner.User + isSameGroup := groupFound && currentGroupName == pp.Conf.Owner.Group + + userID := -1 + groupID := -1 + + if pp.Conf.Owner.User != "" && !isSameUser { + user, err := goca.NewUserFromName(pp.Conf.Owner.User) + if err != nil { + return a, true, err + } + userID = int(user.ID) + } + + if pp.Conf.Owner.Group != "" && !isSameGroup { + group, err := goca.NewGroupFromName(pp.Conf.Owner.Group) + if err != nil { + return a, true, err + } + groupID = int(group.ID) + } + + ui.Say(fmt.Sprintf("Updating template '%s' owner...", pp.Conf.ImageName)) + if err := img.Chown(userID, groupID); err != nil { + return a, true, err + } + + } + + if pp.Conf.ACL != nil { + ui.Say(fmt.Sprintf("Updating template '%s' ACL...", pp.Conf.ImageName)) + chmodOptions := aclToChmodOptions(pp.Conf.ACL) + if err := img.Chmod(chmodOptions); err != nil { + return a, true, err + } + } + ui.Say("Operation completed.") return a, true, nil @@ -99,3 +188,30 @@ func (pp *PostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Ar func serializeImageTemplate(tmpl []string) string { return strings.Join(tmpl, "\n") } + +func aclToChmodOptions(acl map[string]int) goca.ImageChmodOptions { + chmodOptions := goca.NewImageChmodOptions() + for key, val := range acl { + switch key { + case "user_use": + chmodOptions.UserUse = val + case "user_manage": + chmodOptions.UserManage = val + case "user_admin": + chmodOptions.UserAdmin = val + case "group_use": + chmodOptions.GroupUse = val + case "group_manage": + chmodOptions.GroupManage = val + case "group_admin": + chmodOptions.GroupAdmin = val + case "other_use": + chmodOptions.OtherUse = val + case "other_manage": + chmodOptions.OtherManage = val + case "other_admin": + chmodOptions.OtherAdmin = val + } + } + return chmodOptions +}