mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-29 21:54:13 +01:00
Flattening repository path components excepting the last one
Flattening repository path components excepting the last one in replication Fixes #15072 Signed-off-by: Wenkai Yin <yinw@vmware.com>
This commit is contained in:
parent
1f9ab2b735
commit
120be22988
@ -17,13 +17,13 @@ package flow
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/goharbor/harbor/src/lib/errors"
|
"github.com/goharbor/harbor/src/lib/errors"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
repctlmodel "github.com/goharbor/harbor/src/controller/replication/model"
|
repctlmodel "github.com/goharbor/harbor/src/controller/replication/model"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
adp "github.com/goharbor/harbor/src/pkg/reg/adapter"
|
adp "github.com/goharbor/harbor/src/pkg/reg/adapter"
|
||||||
"github.com/goharbor/harbor/src/pkg/reg/model"
|
"github.com/goharbor/harbor/src/pkg/reg/model"
|
||||||
"github.com/goharbor/harbor/src/pkg/reg/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// get/create the source registry, destination registry, source adapter and destination adapter
|
// get/create the source registry, destination registry, source adapter and destination adapter
|
||||||
@ -192,38 +192,34 @@ func getResourceName(res *model.Resource) string {
|
|||||||
return fmt.Sprintf("%s [%d item(s) in total]", meta.Repository.Name, n)
|
return fmt.Sprintf("%s [%d item(s) in total]", meta.Repository.Name, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// repository:a/b/c namespace:n replaceCount: -1 -> n/c
|
// repository:a/b/c/image namespace:n replaceCount: -1 -> n/image
|
||||||
// repository:a/b/c namespace:n replaceCount: 0 -> n/a/b/c
|
// repository:a/b/c/image namespace:n replaceCount: 0 -> n/a/b/c/image
|
||||||
// repository:a/b/c namespace:n replaceCount: 1 -> n/b/c
|
// repository:a/b/c/image namespace:n replaceCount: 1 -> n/b/c/image
|
||||||
// repository:a/b/c namespace:n replaceCount: 2 -> n/c
|
// repository:a/b/c/image namespace:n replaceCount: 2 -> n/c/image
|
||||||
// repository:a/b/c namespace:n replaceCount: 3 -> n
|
// repository:a/b/c/image namespace:n replaceCount: 3 -> n/image
|
||||||
|
// repository:a/b/c/image namespace:n replaceCount: 4 -> error
|
||||||
func replaceNamespace(repository string, namespace string, replaceCount int8, dstRepoComponentPathType string) (string, error) {
|
func replaceNamespace(repository string, namespace string, replaceCount int8, dstRepoComponentPathType string) (string, error) {
|
||||||
if len(namespace) == 0 {
|
if len(namespace) == 0 {
|
||||||
return repository, nil
|
return repository, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// legacy logic to keep backward compatibility
|
|
||||||
if replaceCount < 0 {
|
|
||||||
_, rest := util.ParseRepository(repository)
|
|
||||||
return fmt.Sprintf("%s/%s", namespace, rest), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var dstRepo string
|
|
||||||
srcRepoPathComponents := strings.Split(repository, "/")
|
srcRepoPathComponents := strings.Split(repository, "/")
|
||||||
srcLength := len(srcRepoPathComponents)
|
srcLength := len(srcRepoPathComponents)
|
||||||
|
|
||||||
|
var dstRepoPrefix string
|
||||||
switch {
|
switch {
|
||||||
case replaceCount == 0:
|
case replaceCount < 0: // legacy logic to keep backward compatibility
|
||||||
dstRepo = fmt.Sprintf("%s/%s", namespace, repository)
|
dstRepoPrefix = namespace
|
||||||
case int(replaceCount) == srcLength:
|
case int(replaceCount) > srcLength-1: // invalid replace count
|
||||||
dstRepo = namespace
|
|
||||||
case int(replaceCount) > srcLength:
|
|
||||||
return "", errors.New(nil).WithCode(errors.BadRequestCode).
|
return "", errors.New(nil).WithCode(errors.BadRequestCode).
|
||||||
WithMessage("the source repository %q contains only %d path components %v, but the destination namespace flattening level is %d",
|
WithMessage("the source repository %q contains only %d path components %v excepting the last one, but the destination namespace flattening level is %d",
|
||||||
repository, srcLength, srcRepoPathComponents, replaceCount)
|
repository, srcLength-1, srcRepoPathComponents[:srcLength-1], replaceCount)
|
||||||
default:
|
default:
|
||||||
dstRepo = fmt.Sprintf("%s/%s", namespace, strings.Join(srcRepoPathComponents[replaceCount:], "/"))
|
dstRepoPrefix = namespace + "/" + strings.Join(srcRepoPathComponents[replaceCount:srcLength-1], "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name := srcRepoPathComponents[srcLength-1] // the last part of the repository path components, we'll keep it as the same with the source
|
||||||
|
dstRepo := path.Join(dstRepoPrefix, name)
|
||||||
dstRepoPathComponents := strings.Split(dstRepo, "/")
|
dstRepoPathComponents := strings.Split(dstRepo, "/")
|
||||||
dstLength := len(dstRepoPathComponents)
|
dstLength := len(dstRepoPathComponents)
|
||||||
switch dstRepoComponentPathType {
|
switch dstRepoComponentPathType {
|
||||||
|
@ -157,7 +157,7 @@ func (s *stageTestSuite) TestReplaceNamespace() {
|
|||||||
// replace count > actual sub strings
|
// replace count > actual sub strings
|
||||||
repository = "a/b"
|
repository = "a/b"
|
||||||
namespace = "n"
|
namespace = "n"
|
||||||
replaceCount = 3
|
replaceCount = 2
|
||||||
result, err = replaceNamespace(repository, namespace, replaceCount, "")
|
result, err = replaceNamespace(repository, namespace, replaceCount, "")
|
||||||
s.Require().NotNil(err)
|
s.Require().NotNil(err)
|
||||||
|
|
||||||
@ -185,20 +185,20 @@ func (s *stageTestSuite) TestReplaceNamespace() {
|
|||||||
s.Require().Nil(err)
|
s.Require().Nil(err)
|
||||||
s.Equal("n/c", result)
|
s.Equal("n/c", result)
|
||||||
|
|
||||||
// replace count = 3
|
// the generated destination namespace contains 3 path component, but the destination registry requires only 2
|
||||||
repository = "a/b/c"
|
repository = "a/b/c"
|
||||||
namespace = "n"
|
namespace = "n"
|
||||||
replaceCount = 3
|
replaceCount = 1
|
||||||
|
result, err = replaceNamespace(repository, namespace, replaceCount, model.RepositoryPathComponentTypeOnlyTwo)
|
||||||
|
s.Require().NotNil(err)
|
||||||
|
|
||||||
|
// replace count =0, repository contains no "/"
|
||||||
|
repository = "a"
|
||||||
|
namespace = "n"
|
||||||
|
replaceCount = 0
|
||||||
result, err = replaceNamespace(repository, namespace, replaceCount, "")
|
result, err = replaceNamespace(repository, namespace, replaceCount, "")
|
||||||
s.Require().Nil(err)
|
s.Require().Nil(err)
|
||||||
s.Equal("n", result)
|
s.Equal("n/a", result)
|
||||||
|
|
||||||
// the generated destination namespace contains 1 path component, but the destination registry requires at least 2
|
|
||||||
repository = "a/b/c"
|
|
||||||
namespace = "n"
|
|
||||||
replaceCount = 3
|
|
||||||
result, err = replaceNamespace(repository, namespace, replaceCount, model.RepositoryPathComponentTypeAtLeastTwo)
|
|
||||||
s.Require().NotNil(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStage(t *testing.T) {
|
func TestStage(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user