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

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) ===
This makes the CLI explicitly remove existing aliases that conflict with the ones of the image being copied/imported, and recreate them.

Closes #3560
From e8e0b4be39f609231e5f5f3894f688f203605c09 Mon Sep 17 00:00:00 2001
From: Alberto Donato <[email protected]>
Date: Mon, 17 Jul 2017 15:17:24 +0200
Subject: [PATCH] Update image aliases when they already exist

Signed-off-by: Alberto Donato <[email protected]>
---
 lxc/image.go             | 75 ++++++++++++++++++++++++++++++++++++------------
 lxc/publish.go           |  8 ++++--
 shared/api/image.go      | 14 +++++++++
 shared/api/image_test.go | 40 ++++++++++++++++++++++++++
 test/suites/basic.sh     |  7 +++++
 test/suites/image.sh     | 12 ++++++++
 6 files changed, 135 insertions(+), 21 deletions(-)
 create mode 100644 shared/api/image_test.go

diff --git a/lxc/image.go b/lxc/image.go
index 6c0558504..7de983dfb 100644
--- a/lxc/image.go
+++ b/lxc/image.go
@@ -398,18 +398,8 @@ func (c *imageCmd) run(conf *config.Config, args []string) 
error {
                        return err
                }
 
-               // Setup the copy arguments
-               aliases := []api.ImageAlias{}
-               for _, entry := range c.addAliases {
-                       alias := api.ImageAlias{}
-                       alias.Name = entry
-                       aliases = append(aliases, alias)
-               }
-
                args := lxd.ImageCopyArgs{
-                       Aliases:     aliases,
                        AutoUpdate:  c.autoUpdate,
-                       CopyAliases: c.copyAliases,
                        Public:      c.publicImage,
                }
 
@@ -435,7 +425,20 @@ func (c *imageCmd) run(conf *config.Config, args []string) 
error {
                }
 
                progress.Done(i18n.G("Image copied successfully!"))
-               return nil
+
+               // Ensure aliases
+               aliases := make([]api.ImageAlias, len(c.addAliases))
+               for i, entry := range c.addAliases {
+                       aliases[i].Name = entry
+               }
+               if c.copyAliases {
+                       // Also add the original aliases
+                       for _, alias := range image.Aliases {
+                               aliases = append(aliases, alias)
+                       }
+               }
+               err = ensureImageAliases(dest, aliases, image.Fingerprint)
+               return err
 
        case "delete":
                /* delete [<remote>:]<image> [<remote>:][<image>...] */
@@ -722,17 +725,16 @@ func (c *imageCmd) run(conf *config.Config, args 
[]string) error {
                progress.Done(fmt.Sprintf(i18n.G("Image imported with 
fingerprint: %s"), fingerprint))
 
                // Add the aliases
-               for _, entry := range c.addAliases {
-                       alias := api.ImageAliasesPost{}
-                       alias.Name = entry
-                       alias.Target = fingerprint
-
-                       err = d.CreateImageAlias(alias)
+               if len(c.addAliases) > 0 {
+                       aliases := make([]api.ImageAlias, len(c.addAliases))
+                       for i, entry := range c.addAliases {
+                               aliases[i].Name = entry
+                       }
+                       err = ensureImageAliases(d, aliases, fingerprint)
                        if err != nil {
                                return err
                        }
                }
-
                return nil
 
        case "list":
@@ -1236,3 +1238,40 @@ func packImageDir(path string) (string, error) {
        shared.RunCommand("tar", "-C", path, "--numeric-owner", "-cJf", 
outFileName, "rootfs", "templates", "metadata.yaml")
        return outFileName, nil
 }
+
+// Create the specified image alises, updating those that already exist
+func ensureImageAliases(client lxd.ContainerServer, aliases []api.ImageAlias, 
fingerprint string) error {
+       if len(aliases) == 0 {
+               return nil
+       }
+
+       names := make([]string, len(aliases))
+       for i, alias := range aliases {
+               names[i] = alias.Name
+       }
+       sort.Strings(names)
+
+       resp, err := client.GetImageAliases()
+       if err != nil {
+               return err
+       }
+
+       // Delete existing aliases that match provided ones
+       for _, alias := range api.GetExistingAliases(names, resp) {
+               err := client.DeleteImageAlias(alias.Name)
+               if err != nil {
+                       fmt.Println(i18n.G("Failed to remove alias %s"), 
alias.Name)
+               }
+       }
+       // Create new aliases
+       for _, alias := range aliases {
+               aliasPost := api.ImageAliasesPost{}
+               aliasPost.Name = alias.Name
+               aliasPost.Target = fingerprint
+               err := client.CreateImageAlias(aliasPost)
+               if err != nil {
+                       fmt.Println(i18n.G("Failed to create alias %s"), 
alias.Name)
+               }
+       }
+       return nil
+}
diff --git a/lxc/publish.go b/lxc/publish.go
index 2d4a9e121..24fa8ab28 100644
--- a/lxc/publish.go
+++ b/lxc/publish.go
@@ -200,7 +200,6 @@ func (c *publishCmd) run(conf *config.Config, args 
[]string) error {
        }
 
        if cRemote == iRemote {
-               req.Aliases = aliases
                req.Public = c.makePublic
        }
 
@@ -229,8 +228,7 @@ func (c *publishCmd) run(conf *config.Config, args 
[]string) error {
 
                // Image copy arguments
                args := lxd.ImageCopyArgs{
-                       Aliases: aliases,
-                       Public:  c.makePublic,
+                       Public: c.makePublic,
                }
 
                // Copy the image to the destination host
@@ -245,6 +243,10 @@ func (c *publishCmd) run(conf *config.Config, args 
[]string) error {
                }
        }
 
+       err = ensureImageAliases(d, aliases, fingerprint)
+       if err != nil {
+               return err
+       }
        fmt.Printf(i18n.G("Container published with fingerprint: %s")+"\n", 
fingerprint)
 
        return nil
diff --git a/shared/api/image.go b/shared/api/image.go
index 814c0981d..aeeecc17b 100644
--- a/shared/api/image.go
+++ b/shared/api/image.go
@@ -1,6 +1,7 @@
 package api
 
 import (
+       "sort"
        "time"
 )
 
@@ -102,3 +103,16 @@ type ImageAliasesEntry struct {
 
        Name string `json:"name" yaml:"name"`
 }
+
+// GetExistingAliases returns the intersection between a list of aliases and 
all the existing ones.
+func GetExistingAliases(aliases []string, allAliases []ImageAliasesEntry) 
[]ImageAliasesEntry {
+       existing := []ImageAliasesEntry{}
+       for _, alias := range allAliases {
+               name := alias.Name
+               pos := sort.SearchStrings(aliases, name)
+               if pos < len(aliases) && aliases[pos] == name {
+                       existing = append(existing, alias)
+               }
+       }
+       return existing
+}
diff --git a/shared/api/image_test.go b/shared/api/image_test.go
new file mode 100644
index 000000000..9bc8a59f7
--- /dev/null
+++ b/shared/api/image_test.go
@@ -0,0 +1,40 @@
+package api
+
+import (
+       "testing"
+
+       "github.com/stretchr/testify/suite"
+)
+
+type imageTestSuite struct {
+       suite.Suite
+       images *[]ImageAliasesEntry
+}
+
+func TestImageTestSuite(t *testing.T) {
+       suite.Run(t, new(imageTestSuite))
+}
+
+func (s *imageTestSuite) SetupTest() {
+       s.images = &[]ImageAliasesEntry{
+               ImageAliasesEntry{
+                       Name: "foo",
+               },
+               ImageAliasesEntry{
+                       Name: "bar",
+               },
+               ImageAliasesEntry{
+                       Name: "baz",
+               },
+       }
+}
+
+func (s *imageTestSuite) TestGetExistingAliases() {
+       aliases := GetExistingAliases([]string{"bar", "foo", "other"}, 
*s.images)
+       s.Exactly([]ImageAliasesEntry{(*s.images)[0], (*s.images)[1]}, aliases)
+}
+
+func (s *imageTestSuite) TestGetExistingAliasesEmpty() {
+       aliases := GetExistingAliases([]string{"other1", "other2"}, *s.images)
+       s.Exactly([]ImageAliasesEntry{}, aliases)
+}
diff --git a/test/suites/basic.sh b/test/suites/basic.sh
index e3ad787a5..4993ffa72 100644
--- a/test/suites/basic.sh
+++ b/test/suites/basic.sh
@@ -115,6 +115,13 @@ test_basic_usage() {
   curl -k -s --cert "${LXD_CONF}/client3.crt" --key "${LXD_CONF}/client3.key" 
-X GET "https://${LXD_ADDR}/1.0/images"; | grep "/1.0/images/" && false
   lxc image delete foo-image
 
+  # Test container publish with existing alias
+  lxc init testimage baz
+  lxc publish bar --alias=foo-image --alias=foo-image2
+  # publishing another image with same alias doesn't fail
+  lxc publish baz --alias=foo-image
+  lxc image delete foo-image foo-image2
+
   # Test image compression on publish
   lxc publish bar --alias=foo-image-compressed --compression=bzip2 prop=val1
   lxc image show foo-image-compressed | grep val1
diff --git a/test/suites/image.sh b/test/suites/image.sh
index 89007d4f3..a28913abc 100644
--- a/test/suites/image.sh
+++ b/test/suites/image.sh
@@ -69,3 +69,15 @@ test_image_import_dir() {
     tar tvf "$exported" | fgrep -q metadata.yaml
     rm "$exported"
 }
+
+test_image_import_existing_alias() {
+    ensure_import_testimage
+    lxc init testimage c
+    lxc publish c --alias newimage --alias image2
+    lxc delete c
+    lxc image export testimage testimage.file
+    lxc image delete testimage
+    # the image can be imported with an existing alias
+    lxc image import testimage.file --alias newimage
+    lxc image delete newimage image2
+}
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to