pkg: storage: fix additional registries
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
a81e90a9c9
commit
1f908f0890
2 changed files with 114 additions and 8 deletions
|
@ -319,6 +319,19 @@
|
||||||
replace: 'storage_driver = "overlay2"'
|
replace: 'storage_driver = "overlay2"'
|
||||||
name: /etc/crio/crio.conf
|
name: /etc/crio/crio.conf
|
||||||
backup: yes
|
backup: yes
|
||||||
|
- name: run with systemd cgroup manager
|
||||||
|
replace:
|
||||||
|
regexp: 'cgroup_manager = "cgroupfs"'
|
||||||
|
replace: 'cgroup_manager = "systemd"'
|
||||||
|
name: /etc/crio/crio.conf
|
||||||
|
backup: yes
|
||||||
|
- name: add docker.io default registry
|
||||||
|
lineinfile:
|
||||||
|
dest: /etc/crio/crio.conf
|
||||||
|
line: '"docker.io"'
|
||||||
|
insertafter: 'registries = \['
|
||||||
|
regexp: 'docker\.io'
|
||||||
|
state: present
|
||||||
- name: add overlay2 storage opts on RHEL/CentOS
|
- name: add overlay2 storage opts on RHEL/CentOS
|
||||||
lineinfile:
|
lineinfile:
|
||||||
dest: /etc/crio/crio.conf
|
dest: /etc/crio/crio.conf
|
||||||
|
|
|
@ -2,8 +2,10 @@ package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/image/copy"
|
"github.com/containers/image/copy"
|
||||||
|
@ -14,6 +16,7 @@ import (
|
||||||
"github.com/containers/image/transports/alltransports"
|
"github.com/containers/image/transports/alltransports"
|
||||||
"github.com/containers/image/types"
|
"github.com/containers/image/types"
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
|
distreference "github.com/docker/distribution/reference"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageResult wraps a subset of information about an image: its ID, its names,
|
// ImageResult wraps a subset of information about an image: its ID, its names,
|
||||||
|
@ -310,13 +313,107 @@ func isValidHostname(hostname string) bool {
|
||||||
strings.Contains(hostname, ":") || hostname == "localhost")
|
strings.Contains(hostname, ":") || hostname == "localhost")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isReferenceFullyQualified(reposName reference.Named) bool {
|
||||||
|
indexName, _, _ := splitReposName(reposName)
|
||||||
|
return indexName != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// defaultHostname is the default built-in hostname
|
||||||
|
defaultHostname = "docker.io"
|
||||||
|
// legacyDefaultHostname is automatically converted to DefaultHostname
|
||||||
|
legacyDefaultHostname = "index.docker.io"
|
||||||
|
// defaultRepoPrefix is the prefix used for default repositories in default host
|
||||||
|
defaultRepoPrefix = "library/"
|
||||||
|
)
|
||||||
|
|
||||||
|
// splitReposName breaks a reposName into an index name and remote name
|
||||||
|
func splitReposName(reposName reference.Named) (indexName string, remoteName reference.Named, err error) {
|
||||||
|
var remoteNameStr string
|
||||||
|
indexName, remoteNameStr = distreference.SplitHostname(reposName)
|
||||||
|
if !isValidHostname(indexName) {
|
||||||
|
// This is a Docker Index repos (ex: samalba/hipache or ubuntu)
|
||||||
|
// 'docker.io'
|
||||||
|
indexName = ""
|
||||||
|
remoteName = reposName
|
||||||
|
} else {
|
||||||
|
remoteName, err = withName(remoteNameStr)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateName(name string) error {
|
||||||
|
if err := validateID(strings.TrimPrefix(name, defaultHostname+"/")); err == nil {
|
||||||
|
return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var validHex = regexp.MustCompile(`^([a-f0-9]{64})$`)
|
||||||
|
|
||||||
|
// validateID checks whether an ID string is a valid image ID.
|
||||||
|
func validateID(id string) error {
|
||||||
|
if ok := validHex.MatchString(id); !ok {
|
||||||
|
return fmt.Errorf("image ID %q is invalid", id)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// withName returns a named object representing the given string. If the input
|
||||||
|
// is invalid ErrReferenceInvalidFormat will be returned.
|
||||||
|
func withName(name string) (reference.Named, error) {
|
||||||
|
name, err := normalize(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateName(name); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r, err := distreference.WithName(name)
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitHostname splits a repository name to hostname and remotename string.
|
||||||
|
// If no valid hostname is found, empty string will be returned as a resulting
|
||||||
|
// hostname. Repository name needs to be already validated before.
|
||||||
|
func splitHostname(name string) (hostname, remoteName string) {
|
||||||
|
i := strings.IndexRune(name, '/')
|
||||||
|
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
|
||||||
|
hostname, remoteName = "", name
|
||||||
|
} else {
|
||||||
|
hostname, remoteName = name[:i], name[i+1:]
|
||||||
|
}
|
||||||
|
if hostname == legacyDefaultHostname {
|
||||||
|
hostname = defaultHostname
|
||||||
|
}
|
||||||
|
if hostname == defaultHostname && !strings.ContainsRune(remoteName, '/') {
|
||||||
|
remoteName = defaultRepoPrefix + remoteName
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize returns a repository name in its normalized form, meaning it
|
||||||
|
// will contain library/ prefix for official images.
|
||||||
|
func normalize(name string) (string, error) {
|
||||||
|
host, remoteName := splitHostname(name)
|
||||||
|
if strings.ToLower(remoteName) != remoteName {
|
||||||
|
return "", errors.New("invalid reference format: repository name must be lowercase")
|
||||||
|
}
|
||||||
|
if host == defaultHostname {
|
||||||
|
if strings.HasPrefix(remoteName, defaultRepoPrefix) {
|
||||||
|
remoteName = strings.TrimPrefix(remoteName, defaultRepoPrefix)
|
||||||
|
}
|
||||||
|
return host + "/" + remoteName, nil
|
||||||
|
}
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (svc *imageService) ResolveNames(imageName string) ([]string, error) {
|
func (svc *imageService) ResolveNames(imageName string) ([]string, error) {
|
||||||
r, err := reference.ParseNormalizedNamed(imageName)
|
r, err := reference.ParseNormalizedNamed(imageName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
domain, rest := splitDomain(r.Name())
|
if isReferenceFullyQualified(r) {
|
||||||
if len(domain) != 0 && isValidHostname(domain) {
|
|
||||||
// this means the image is already fully qualified
|
// this means the image is already fully qualified
|
||||||
return []string{imageName}, nil
|
return []string{imageName}, nil
|
||||||
}
|
}
|
||||||
|
@ -328,14 +425,10 @@ func (svc *imageService) ResolveNames(imageName string) ([]string, error) {
|
||||||
// this means we got an image in the form of "busybox"
|
// this means we got an image in the form of "busybox"
|
||||||
// we need to use additional registries...
|
// we need to use additional registries...
|
||||||
// normalize the unqualified image to be domain/repo/image...
|
// normalize the unqualified image to be domain/repo/image...
|
||||||
|
_, rest := splitDomain(r.Name())
|
||||||
images := []string{}
|
images := []string{}
|
||||||
for _, r := range svc.registries {
|
for _, r := range svc.registries {
|
||||||
path := rest
|
images = append(images, filepath.Join(r, rest))
|
||||||
if !isValidHostname(domain) {
|
|
||||||
// This is the case where we have an image like "runcom/busybox"
|
|
||||||
path = imageName
|
|
||||||
}
|
|
||||||
images = append(images, filepath.Join(r, path))
|
|
||||||
}
|
}
|
||||||
return images, nil
|
return images, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue