Files
zot/pkg/extensions/sync/utils.go
T
Petu Eusebiu 19003e8a71 Added new extension "sync"
Periodically poll registries and pull images according to sync's config
Added sync on demand, syncing when clients asks for an image which
zot doesn't have.

Signed-off-by: Petu Eusebiu <peusebiu@cisco.com>
2021-10-21 10:32:46 -07:00

167 lines
3.8 KiB
Go

package sync
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"strings"
"github.com/anuvu/zot/errors"
"github.com/anuvu/zot/pkg/log"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/types"
)
var certsDir = fmt.Sprintf("%s/zot-certs-dir/", os.TempDir()) //nolint: gochecknoglobals
func copyFile(sourceFilePath, destFilePath string) error {
destFile, err := os.Create(destFilePath)
if err != nil {
return err
}
defer destFile.Close()
// should never get error because server certs are already handled by zot, by the time
// it gets here
sourceFile, _ := os.Open(sourceFilePath)
defer sourceFile.Close()
if _, err := io.Copy(destFile, sourceFile); err != nil {
return err
}
return nil
}
func copyLocalCerts(serverCert, serverKey, caCert string, log log.Logger) (string, error) {
log.Debug().Msgf("Creating certs directory: %s", certsDir)
err := os.Mkdir(certsDir, 0755)
if err != nil && !os.IsExist(err) {
return "", err
}
if serverCert != "" {
log.Debug().Msgf("Copying server cert: %s", serverCert)
err := copyFile(serverCert, path.Join(certsDir, "server.cert"))
if err != nil {
return "", err
}
}
if serverKey != "" {
log.Debug().Msgf("Copying server key: %s", serverKey)
err := copyFile(serverKey, path.Join(certsDir, "server.key"))
if err != nil {
return "", err
}
}
if caCert != "" {
log.Debug().Msgf("Copying CA cert: %s", caCert)
err := copyFile(caCert, path.Join(certsDir, "ca.crt"))
if err != nil {
return "", err
}
}
return certsDir, nil
}
// getTagFromRef returns a tagged reference from an image reference.
func getTagFromRef(ref types.ImageReference, log log.Logger) reference.Tagged {
tagged, isTagged := ref.DockerReference().(reference.Tagged)
if !isTagged {
log.Warn().Msgf("internal server error, reference %s does not have a tag, skipping", ref.DockerReference())
return nil
}
return tagged
}
// parseRepositoryReference parses input into a reference.Named, and verifies that it names a repository, not an image.
func parseRepositoryReference(input string) (reference.Named, error) {
ref, err := reference.ParseNormalizedNamed(input)
if err != nil {
return nil, err
}
if !reference.IsNameOnly(ref) {
return nil, errors.ErrInvalidRepositoryName
}
return ref, nil
}
// filterRepos filters repos based on prefix given in the config.
func filterRepos(repos []string, content []Content) map[int][]string {
// prefix: repo
filtered := make(map[int][]string)
for _, repo := range repos {
matched := false
// we use contentID to figure out tags filtering
for contentID, c := range content {
// handle prefixes starting with '/'
var prefix string
if strings.HasPrefix(c.Prefix, "/") {
prefix = c.Prefix[1:]
} else {
prefix = c.Prefix
}
// split both prefix and repository and compare each part
splittedPrefix := strings.Split(prefix, "/")
// split at most n + 1
splittedRepo := strings.SplitN(repo, "/", len(splittedPrefix)+1)
// if prefix is longer than a repository, no match
if len(splittedPrefix) > len(splittedRepo) {
continue
}
// check if matched each part of prefix and repository
for i := 0; i < len(splittedPrefix); i++ {
if splittedRepo[i] == splittedPrefix[i] {
matched = true
} else {
// if a part doesn't match, check next prefix
matched = false
break
}
}
// if matched no need to check the next prefixes
if matched {
filtered[contentID] = append(filtered[contentID], repo)
break
}
}
}
return filtered
}
// Get sync.FileCredentials from file.
func getFileCredentials(filepath string) (CredentialsFile, error) {
f, err := ioutil.ReadFile(filepath)
if err != nil {
return nil, err
}
var creds CredentialsFile
err = json.Unmarshal(f, &creds)
if err != nil {
return nil, err
}
return creds, nil
}