The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/3041

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===

From 6f3d99613ec5ff412c83eca6e7c022cb4ac9d2c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Wed, 8 Mar 2017 01:34:21 -0500
Subject: [PATCH 1/4] images: Refactor code a bit
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 lxd/daemon_images.go |   6 +-
 lxd/images.go        | 212 ++++++++++++++++++++++-----------------------------
 2 files changed, 97 insertions(+), 121 deletions(-)

diff --git a/lxd/daemon_images.go b/lxd/daemon_images.go
index b2bd825..9e9d164 100644
--- a/lxd/daemon_images.go
+++ b/lxd/daemon_images.go
@@ -371,7 +371,8 @@ func (d *Daemon) ImageDownload(op *operation, server 
string, protocol string, ce
                        }
                }
 
-               _, err = imageBuildFromInfo(d, info)
+               // Create the database entry
+               err = dbImageInsert(d.db, info.Fingerprint, info.Filename, 
info.Size, info.Public, info.AutoUpdate, info.Architecture, info.CreatedAt, 
info.ExpiresAt, info.Properties)
                if err != nil {
                        return "", err
                }
@@ -546,7 +547,8 @@ func (d *Daemon) ImageDownload(op *operation, server 
string, protocol string, ce
                }
        }
 
-       _, err = imageBuildFromInfo(d, &info)
+       // Create the database entry
+       err = dbImageInsert(d.db, info.Fingerprint, info.Filename, info.Size, 
info.Public, info.AutoUpdate, info.Architecture, info.CreatedAt, 
info.ExpiresAt, info.Properties)
        if err != nil {
                shared.LogError(
                        "Failed to create image",
diff --git a/lxd/images.go b/lxd/images.go
index c203289..06ac683 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -221,27 +221,26 @@ type imageMetadata struct {
  * This function takes a container or snapshot from the local image server and
  * exports it as an image.
  */
-func imgPostContInfo(d *Daemon, r *http.Request, req api.ImagesPost,
-       builddir string) (info api.Image, err error) {
-
+func imgPostContInfo(d *Daemon, r *http.Request, req api.ImagesPost, builddir 
string) (*api.Image, error) {
+       info := api.Image{}
        info.Properties = map[string]string{}
        name := req.Source["name"]
        ctype := req.Source["type"]
        if ctype == "" || name == "" {
-               return info, fmt.Errorf("No source provided")
+               return nil, fmt.Errorf("No source provided")
        }
 
        switch ctype {
        case "snapshot":
                if !shared.IsSnapshot(name) {
-                       return info, fmt.Errorf("Not a snapshot")
+                       return nil, fmt.Errorf("Not a snapshot")
                }
        case "container":
                if shared.IsSnapshot(name) {
-                       return info, fmt.Errorf("This is a snapshot")
+                       return nil, fmt.Errorf("This is a snapshot")
                }
        default:
-               return info, fmt.Errorf("Bad type")
+               return nil, fmt.Errorf("Bad type")
        }
 
        info.Filename = req.Filename
@@ -254,19 +253,19 @@ func imgPostContInfo(d *Daemon, r *http.Request, req 
api.ImagesPost,
 
        c, err := containerLoadByName(d, name)
        if err != nil {
-               return info, err
+               return nil, err
        }
 
        // Build the actual image file
        tarfile, err := ioutil.TempFile(builddir, "lxd_build_tar_")
        if err != nil {
-               return info, err
+               return nil, err
        }
        defer os.Remove(tarfile.Name())
 
        if err := c.Export(tarfile, req.Properties); err != nil {
                tarfile.Close()
-               return info, err
+               return nil, err
        }
        tarfile.Close()
 
@@ -282,7 +281,7 @@ func imgPostContInfo(d *Daemon, r *http.Request, req 
api.ImagesPost,
        if compress != "none" {
                compressedPath, err = compressFile(tarfile.Name(), compress)
                if err != nil {
-                       return info, err
+                       return nil, err
                }
        } else {
                compressedPath = tarfile.Name()
@@ -292,34 +291,42 @@ func imgPostContInfo(d *Daemon, r *http.Request, req 
api.ImagesPost,
        sha256 := sha256.New()
        tarf, err := os.Open(compressedPath)
        if err != nil {
-               return info, err
+               return nil, err
        }
+
        info.Size, err = io.Copy(sha256, tarf)
        tarf.Close()
        if err != nil {
-               return info, err
+               return nil, err
        }
+
        info.Fingerprint = fmt.Sprintf("%x", sha256.Sum(nil))
 
        _, _, err = dbImageGet(d.db, info.Fingerprint, false, true)
        if err == nil {
-               return info, fmt.Errorf("The image already exists: %s", 
info.Fingerprint)
+               return nil, fmt.Errorf("The image already exists: %s", 
info.Fingerprint)
        }
 
        /* rename the the file to the expected name so our caller can use it */
        finalName := shared.VarPath("images", info.Fingerprint)
        err = shared.FileMove(compressedPath, finalName)
        if err != nil {
-               return info, err
+               return nil, err
        }
 
        info.Architecture, _ = osarch.ArchitectureName(c.Architecture())
        info.Properties = req.Properties
 
-       return info, nil
+       // Create the database entry
+       err = dbImageInsert(d.db, info.Fingerprint, info.Filename, info.Size, 
info.Public, info.AutoUpdate, info.Architecture, info.CreatedAt, 
info.ExpiresAt, info.Properties)
+       if err != nil {
+               return nil, err
+       }
+
+       return &info, nil
 }
 
-func imgPostRemoteInfo(d *Daemon, req api.ImagesPost, op *operation) error {
+func imgPostRemoteInfo(d *Daemon, req api.ImagesPost, op *operation) 
(*api.Image, error) {
        var err error
        var hash string
 
@@ -328,17 +335,17 @@ func imgPostRemoteInfo(d *Daemon, req api.ImagesPost, op 
*operation) error {
        } else if req.Source["alias"] != "" {
                hash = req.Source["alias"]
        } else {
-               return fmt.Errorf("must specify one of alias or fingerprint for 
init from image")
+               return nil, fmt.Errorf("must specify one of alias or 
fingerprint for init from image")
        }
 
        hash, err = d.ImageDownload(op, req.Source["server"], 
req.Source["protocol"], req.Source["certificate"], req.Source["secret"], hash, 
false, req.AutoUpdate, "")
        if err != nil {
-               return err
+               return nil, err
        }
 
        id, info, err := dbImageGet(d.db, hash, false, false)
        if err != nil {
-               return err
+               return nil, err
        }
 
        // Allow overriding or adding properties
@@ -350,34 +357,29 @@ func imgPostRemoteInfo(d *Daemon, req api.ImagesPost, op 
*operation) error {
        if req.Public || req.AutoUpdate || req.Filename != "" || 
len(req.Properties) > 0 {
                err = dbImageUpdate(d.db, id, req.Filename, info.Size, 
req.Public, req.AutoUpdate, info.Architecture, info.CreatedAt, info.ExpiresAt, 
info.Properties)
                if err != nil {
-                       return err
+                       return nil, err
                }
        }
 
-       metadata := make(map[string]string)
-       metadata["fingerprint"] = info.Fingerprint
-       metadata["size"] = strconv.FormatInt(info.Size, 10)
-       op.UpdateMetadata(metadata)
-
-       return nil
+       return info, nil
 }
 
-func imgPostURLInfo(d *Daemon, req api.ImagesPost, op *operation) error {
+func imgPostURLInfo(d *Daemon, req api.ImagesPost, op *operation) (*api.Image, 
error) {
        var err error
 
        if req.Source["url"] == "" {
-               return fmt.Errorf("Missing URL")
+               return nil, fmt.Errorf("Missing URL")
        }
 
        myhttp, err := d.httpClient("")
        if err != nil {
-               return err
+               return nil, err
        }
 
        // Resolve the image URL
        head, err := http.NewRequest("HEAD", req.Source["url"], nil)
        if err != nil {
-               return err
+               return nil, err
        }
 
        architecturesStr := []string{}
@@ -391,28 +393,28 @@ func imgPostURLInfo(d *Daemon, req api.ImagesPost, op 
*operation) error {
 
        raw, err := myhttp.Do(head)
        if err != nil {
-               return err
+               return nil, err
        }
 
        hash := raw.Header.Get("LXD-Image-Hash")
        if hash == "" {
-               return fmt.Errorf("Missing LXD-Image-Hash header")
+               return nil, fmt.Errorf("Missing LXD-Image-Hash header")
        }
 
        url := raw.Header.Get("LXD-Image-URL")
        if url == "" {
-               return fmt.Errorf("Missing LXD-Image-URL header")
+               return nil, fmt.Errorf("Missing LXD-Image-URL header")
        }
 
        // Import the image
        hash, err = d.ImageDownload(op, url, "direct", "", "", hash, false, 
req.AutoUpdate, "")
        if err != nil {
-               return err
+               return nil, err
        }
 
        id, info, err := dbImageGet(d.db, hash, false, false)
        if err != nil {
-               return err
+               return nil, err
        }
 
        // Allow overriding or adding properties
@@ -423,21 +425,15 @@ func imgPostURLInfo(d *Daemon, req api.ImagesPost, op 
*operation) error {
        if req.Public || req.AutoUpdate || req.Filename != "" || 
len(req.Properties) > 0 {
                err = dbImageUpdate(d.db, id, req.Filename, info.Size, 
req.Public, req.AutoUpdate, info.Architecture, info.CreatedAt, info.ExpiresAt, 
info.Properties)
                if err != nil {
-                       return err
+                       return nil, err
                }
        }
 
-       metadata := make(map[string]string)
-       metadata["fingerprint"] = info.Fingerprint
-       metadata["size"] = strconv.FormatInt(info.Size, 10)
-       op.UpdateMetadata(metadata)
-
-       return nil
+       return info, nil
 }
 
-func getImgPostInfo(d *Daemon, r *http.Request,
-       builddir string, post *os.File) (info api.Image, err error) {
-
+func getImgPostInfo(d *Daemon, r *http.Request, builddir string, post 
*os.File) (*api.Image, error) {
+       info := api.Image{}
        var imageMeta *imageMetadata
        logger := logging.AddContext(shared.Log, log.Ctx{"function": 
"getImgPostInfo"})
 
@@ -456,7 +452,7 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                // Create a temporary file for the image tarball
                imageTarf, err := ioutil.TempFile(builddir, "lxd_tar_")
                if err != nil {
-                       return info, err
+                       return nil, err
                }
                defer os.Remove(imageTarf.Name())
 
@@ -467,11 +463,11 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                // Get the metadata tarball
                part, err := mr.NextPart()
                if err != nil {
-                       return info, err
+                       return nil, err
                }
 
                if part.FormName() != "metadata" {
-                       return info, fmt.Errorf("Invalid multipart image")
+                       return nil, fmt.Errorf("Invalid multipart image")
                }
 
                size, err = io.Copy(io.MultiWriter(imageTarf, sha256), part)
@@ -482,7 +478,7 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                        logger.Error(
                                "Failed to copy the image tarfile",
                                log.Ctx{"err": err})
-                       return info, err
+                       return nil, err
                }
 
                // Get the rootfs tarball
@@ -491,20 +487,20 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                        logger.Error(
                                "Failed to get the next part",
                                log.Ctx{"err": err})
-                       return info, err
+                       return nil, err
                }
 
                if part.FormName() != "rootfs" {
                        logger.Error(
                                "Invalid multipart image")
 
-                       return info, fmt.Errorf("Invalid multipart image")
+                       return nil, fmt.Errorf("Invalid multipart image")
                }
 
                // Create a temporary file for the rootfs tarball
                rootfsTarf, err := ioutil.TempFile(builddir, "lxd_tar_")
                if err != nil {
-                       return info, err
+                       return nil, err
                }
                defer os.Remove(rootfsTarf.Name())
 
@@ -516,7 +512,7 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                        logger.Error(
                                "Failed to copy the rootfs tarfile",
                                log.Ctx{"err": err})
-                       return info, err
+                       return nil, err
                }
 
                info.Filename = part.FileName()
@@ -525,7 +521,7 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                expectedFingerprint := r.Header.Get("X-LXD-fingerprint")
                if expectedFingerprint != "" && info.Fingerprint != 
expectedFingerprint {
                        err = fmt.Errorf("fingerprints don't match, got %s 
expected %s", info.Fingerprint, expectedFingerprint)
-                       return info, err
+                       return nil, err
                }
 
                imageMeta, err = getImageMetadata(imageTarf.Name())
@@ -533,7 +529,7 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                        logger.Error(
                                "Failed to get image metadata",
                                log.Ctx{"err": err})
-                       return info, err
+                       return nil, err
                }
 
                imgfname := shared.VarPath("images", info.Fingerprint)
@@ -545,7 +541,7 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                                        "err":    err,
                                        "source": imageTarf.Name(),
                                        "dest":   imgfname})
-                       return info, err
+                       return nil, err
                }
 
                rootfsfname := shared.VarPath("images", 
info.Fingerprint+".rootfs")
@@ -557,7 +553,7 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                                        "err":    err,
                                        "source": rootfsTarf.Name(),
                                        "dest":   imgfname})
-                       return info, err
+                       return nil, err
                }
        } else {
                post.Seek(0, 0)
@@ -568,7 +564,7 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                        logger.Error(
                                "Failed to copy the tarfile",
                                log.Ctx{"err": err})
-                       return info, err
+                       return nil, err
                }
 
                info.Filename = r.Header.Get("X-LXD-filename")
@@ -585,7 +581,7 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                                "fingerprints don't match, got %s expected %s",
                                info.Fingerprint,
                                expectedFingerprint)
-                       return info, err
+                       return nil, err
                }
 
                imageMeta, err = getImageMetadata(post.Name())
@@ -593,7 +589,7 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                        logger.Error(
                                "Failed to get image metadata",
                                log.Ctx{"err": err})
-                       return info, err
+                       return nil, err
                }
 
                imgfname := shared.VarPath("images", info.Fingerprint)
@@ -605,7 +601,7 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                                        "err":    err,
                                        "source": post.Name(),
                                        "dest":   imgfname})
-                       return info, err
+                       return nil, err
                }
        }
 
@@ -623,7 +619,13 @@ func getImgPostInfo(d *Daemon, r *http.Request,
                }
        }
 
-       return info, nil
+       // Create the database entry
+       err = dbImageInsert(d.db, info.Fingerprint, info.Filename, info.Size, 
info.Public, info.AutoUpdate, info.Architecture, info.CreatedAt, 
info.ExpiresAt, info.Properties)
+       if err != nil {
+               return nil, err
+       }
+
+       return &info, nil
 }
 
 // imageCreateInPool() creates a new storage volume in a given storage pool for
@@ -651,29 +653,6 @@ func imageCreateInPool(d *Daemon, info *api.Image, 
storagePool string) error {
        return nil
 }
 
-func imageBuildFromInfo(d *Daemon, info *api.Image) (metadata 
map[string]string, err error) {
-       err = dbImageInsert(
-               d.db,
-               info.Fingerprint,
-               info.Filename,
-               info.Size,
-               info.Public,
-               info.AutoUpdate,
-               info.Architecture,
-               info.CreatedAt,
-               info.ExpiresAt,
-               info.Properties)
-       if err != nil {
-               return metadata, err
-       }
-
-       metadata = make(map[string]string)
-       metadata["fingerprint"] = info.Fingerprint
-       metadata["size"] = strconv.FormatInt(info.Size, 10)
-
-       return metadata, nil
-}
-
 func imagesPost(d *Daemon, r *http.Request) Response {
        var err error
 
@@ -727,51 +706,46 @@ func imagesPost(d *Daemon, r *http.Request) Response {
 
        // Begin background operation
        run := func(op *operation) error {
-               var info api.Image
+               var info *api.Image
 
                // Setup the cleanup function
                defer cleanup(builddir, post)
 
-               /* Processing image copy from remote */
-               if !imageUpload && req.Source["type"] == "image" {
-                       err := imgPostRemoteInfo(d, req, op)
-                       if err != nil {
-                               return err
-                       }
-                       return nil
-               }
-
-               /* Processing image copy from URL */
-               if !imageUpload && req.Source["type"] == "url" {
-                       err := imgPostURLInfo(d, req, op)
-                       if err != nil {
-                               return err
+               if !imageUpload {
+                       if req.Source["type"] == "image" {
+                               /* Processing image copy from remote */
+                               info, err = imgPostRemoteInfo(d, req, op)
+                               if err != nil {
+                                       return err
+                               }
+                       } else if req.Source["type"] == "url" {
+                               /* Processing image copy from URL */
+                               info, err = imgPostURLInfo(d, req, op)
+                               if err != nil {
+                                       return err
+                               }
+                       } else {
+                               /* Processing image creation from container */
+                               imagePublishLock.Lock()
+                               info, err = imgPostContInfo(d, r, req, builddir)
+                               if err != nil {
+                                       imagePublishLock.Unlock()
+                                       return err
+                               }
+                               imagePublishLock.Unlock()
                        }
-                       return nil
-               }
-
-               if imageUpload {
+               } else {
                        /* Processing image upload */
                        info, err = getImgPostInfo(d, r, builddir, post)
                        if err != nil {
                                return err
                        }
-               } else {
-                       /* Processing image creation from container */
-                       imagePublishLock.Lock()
-                       info, err = imgPostContInfo(d, r, req, builddir)
-                       if err != nil {
-                               imagePublishLock.Unlock()
-                               return err
-                       }
-                       imagePublishLock.Unlock()
-               }
-
-               metadata, err := imageBuildFromInfo(d, &info)
-               if err != nil {
-                       return err
                }
 
+               // Set the metadata
+               metadata := make(map[string]string)
+               metadata["fingerprint"] = info.Fingerprint
+               metadata["size"] = strconv.FormatInt(info.Size, 10)
                op.UpdateMetadata(metadata)
                return nil
        }

From 240d86caea7a25e1c93516ee408a50335a85b23d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Wed, 8 Mar 2017 01:49:07 -0500
Subject: [PATCH 2/4] images: Properly return the alias description
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 lxd/db_images.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/db_images.go b/lxd/db_images.go
index 5bd4f11..19f4269 100644
--- a/lxd/db_images.go
+++ b/lxd/db_images.go
@@ -227,7 +227,7 @@ func dbImageGet(db *sql.DB, fingerprint string, public 
bool, strictMatching bool
        aliases := []api.ImageAlias{}
        for _, r := range results {
                name = r[0].(string)
-               desc = r[0].(string)
+               desc = r[1].(string)
                a := api.ImageAlias{Name: name, Description: desc}
                aliases = append(aliases, a)
        }

From 276d61a6df414c8b2f375117aa8868b24ee14634 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Wed, 8 Mar 2017 01:49:31 -0500
Subject: [PATCH 3/4] image: Show the alias description
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 lxc/image.go | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lxc/image.go b/lxc/image.go
index ba47e98..b996f32 100644
--- a/lxc/image.go
+++ b/lxc/image.go
@@ -335,7 +335,11 @@ func (c *imageCmd) run(config *lxd.Config, args []string) 
error {
                }
                fmt.Println(i18n.G("Aliases:"))
                for _, alias := range info.Aliases {
-                       fmt.Printf("    - %s\n", alias.Name)
+                       if alias.Description != "" {
+                               fmt.Printf("    - %s (%s)\n", alias.Name, 
alias.Description)
+                       } else {
+                               fmt.Printf("    - %s\n", alias.Name)
+                       }
                }
                fmt.Printf(i18n.G("Auto update: %s")+"\n", autoUpdate)
                if info.UpdateSource != nil {

From e1bf66c098bc70532e5260603736adcedf070df6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Wed, 8 Mar 2017 01:53:18 -0500
Subject: [PATCH 4/4] images: Allow setting aliases on creation/import
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #2870

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 doc/api-extensions.md |  4 ++++
 doc/rest-api.md       | 12 ++++++++++++
 lxd/api_1.0.go        |  1 +
 lxd/images.go         | 18 ++++++++++++++++++
 shared/api/image.go   |  3 +++
 5 files changed, 38 insertions(+)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 22c7f4a..702fac9 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -225,3 +225,7 @@ When set, this will instruct LXD to attach to the specified 
VLAN. LXD
 will look for an existing interface for that VLAN on the host. If one
 can't be found it will create one itself and then use that as the
 macvlan parent.
+
+## image\_create\_aliases
+Adds a new "aliases" field to POST /1.0/images allowing for aliases to
+be set at image creation/import time.
diff --git a/doc/rest-api.md b/doc/rest-api.md
index 349b7b3..ba8a609 100644
--- a/doc/rest-api.md
+++ b/doc/rest-api.md
@@ -1253,6 +1253,10 @@ In the source image case, the following dict must be 
used:
         "properties": {                         # Image properties (optional, 
applied on top of source properties)
             "os": "Ubuntu"
         },
+        "aliases": [                            # Set initial aliases 
("image_create_aliases" API extension)
+            {"name": "my-alias",
+             "description: "A description"
+        },
         "source": {
             "type": "image",
             "mode": "pull",                     # Only pull is supported for 
now
@@ -1274,6 +1278,10 @@ In the source container case, the following dict must be 
used:
         "properties": {                 # Image properties (optional)
             "os": "Ubuntu"
         },
+        "aliases": [                    # Set initial aliases 
("image_create_aliases" API extension)
+            {"name": "my-alias",
+             "description: "A description"
+        },
         "source": {
             "type": "container",        # One of "container" or "snapshot"
             "name": "abc"
@@ -1288,6 +1296,10 @@ In the remote image URL case, the following dict must be 
used:
         "properties": {                                 # Image properties 
(optional)
             "os": "Ubuntu"
         },
+        "aliases": [                                    # Set initial aliases 
("image_create_aliases" API extension)
+            {"name": "my-alias",
+             "description: "A description"
+        },
         "source": {
             "type": "url",
             "url": "https://www.some-server.com/image";  # URL for the image
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index 9dfe7b5..a3fdd46 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -96,6 +96,7 @@ func api10Get(d *Daemon, r *http.Request) Response {
                        "storage_lvm_vg_rename",
                        "storage_lvm_thinpool_rename",
                        "network_vlan",
+                       "image_create_aliases",
                },
                APIStatus:  "stable",
                APIVersion: version.APIVersion,
diff --git a/lxd/images.go b/lxd/images.go
index 06ac683..f869e96 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -742,6 +742,24 @@ func imagesPost(d *Daemon, r *http.Request) Response {
                        }
                }
 
+               // Apply any provided alias
+               for _, alias := range req.Aliases {
+                       _, _, err := dbImageAliasGet(d.db, alias.Name, true)
+                       if err == nil {
+                               return fmt.Errorf("Alias already exists: %s", 
alias.Name)
+                       }
+
+                       id, _, err := dbImageGet(d.db, info.Fingerprint, false, 
false)
+                       if err != nil {
+                               return err
+                       }
+
+                       err = dbImageAliasAdd(d.db, alias.Name, id, 
alias.Description)
+                       if err != nil {
+                               return err
+                       }
+               }
+
                // Set the metadata
                metadata := make(map[string]string)
                metadata["fingerprint"] = info.Fingerprint
diff --git a/shared/api/image.go b/shared/api/image.go
index b162b82..789e887 100644
--- a/shared/api/image.go
+++ b/shared/api/image.go
@@ -13,6 +13,9 @@ type ImagesPost struct {
 
        // API extension: image_compression_algorithm
        CompressionAlgorithm string `json:"compression_algorithm" 
yaml:"compression_algorithm"`
+
+       // API extension: image_create_aliases
+       Aliases []ImageAlias `json:"aliases" yaml:"aliases"`
 }
 
 // ImagePut represents the modifiable fields of a LXD image
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to