2019-05-31 09:45:11 +00:00
/ *
Copyright 2017 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package image
import (
2021-06-25 04:59:51 +00:00
"crypto/sha256"
"encoding/base64"
2019-05-31 09:45:11 +00:00
"fmt"
"io/ioutil"
"os"
2021-06-25 04:59:51 +00:00
"regexp"
2020-01-14 10:38:55 +00:00
"strings"
2019-05-31 09:45:11 +00:00
yaml "gopkg.in/yaml.v2"
)
// RegistryList holds public and private image registries
type RegistryList struct {
2020-01-14 10:38:55 +00:00
GcAuthenticatedRegistry string ` yaml:"gcAuthenticatedRegistry" `
E2eRegistry string ` yaml:"e2eRegistry" `
2020-04-14 07:04:33 +00:00
PromoterE2eRegistry string ` yaml:"promoterE2eRegistry" `
2020-12-17 12:28:29 +00:00
BuildImageRegistry string ` yaml:"buildImageRegistry" `
2020-01-14 10:38:55 +00:00
InvalidRegistry string ` yaml:"invalidRegistry" `
2021-06-25 04:59:51 +00:00
GcEtcdRegistry string ` yaml:"gcEtcdRegistry" `
2020-01-14 10:38:55 +00:00
GcRegistry string ` yaml:"gcRegistry" `
2020-12-17 12:28:29 +00:00
SigStorageRegistry string ` yaml:"sigStorageRegistry" `
2020-01-14 10:38:55 +00:00
GcrReleaseRegistry string ` yaml:"gcrReleaseRegistry" `
PrivateRegistry string ` yaml:"privateRegistry" `
SampleRegistry string ` yaml:"sampleRegistry" `
2021-06-25 04:59:51 +00:00
MicrosoftRegistry string ` yaml:"microsoftRegistry" `
2019-05-31 09:45:11 +00:00
}
// Config holds an images registry, name, and version
type Config struct {
registry string
name string
version string
}
// SetRegistry sets an image registry in a Config struct
func ( i * Config ) SetRegistry ( registry string ) {
i . registry = registry
}
// SetName sets an image name in a Config struct
func ( i * Config ) SetName ( name string ) {
i . name = name
}
// SetVersion sets an image version in a Config struct
func ( i * Config ) SetVersion ( version string ) {
i . version = version
}
func initReg ( ) RegistryList {
registry := RegistryList {
2020-01-14 10:38:55 +00:00
GcAuthenticatedRegistry : "gcr.io/authenticated-image-pulling" ,
E2eRegistry : "gcr.io/kubernetes-e2e-test-images" ,
2020-12-17 12:28:29 +00:00
PromoterE2eRegistry : "k8s.gcr.io/e2e-test-images" ,
BuildImageRegistry : "k8s.gcr.io/build-image" ,
2020-01-14 10:38:55 +00:00
InvalidRegistry : "invalid.com/invalid" ,
2021-06-25 04:59:51 +00:00
GcEtcdRegistry : "k8s.gcr.io" ,
2020-01-14 10:38:55 +00:00
GcRegistry : "k8s.gcr.io" ,
2020-12-17 12:28:29 +00:00
SigStorageRegistry : "k8s.gcr.io/sig-storage" ,
2020-01-14 10:38:55 +00:00
PrivateRegistry : "gcr.io/k8s-authenticated-test" ,
SampleRegistry : "gcr.io/google-samples" ,
2021-06-25 04:59:51 +00:00
GcrReleaseRegistry : "gcr.io/gke-release" ,
MicrosoftRegistry : "mcr.microsoft.com" ,
2019-05-31 09:45:11 +00:00
}
repoList := os . Getenv ( "KUBE_TEST_REPO_LIST" )
if repoList == "" {
return registry
}
fileContent , err := ioutil . ReadFile ( repoList )
if err != nil {
panic ( fmt . Errorf ( "Error reading '%v' file contents: %v" , repoList , err ) )
}
err = yaml . Unmarshal ( fileContent , & registry )
if err != nil {
panic ( fmt . Errorf ( "Error unmarshalling '%v' YAML file: %v" , repoList , err ) )
}
return registry
}
var (
2021-06-25 04:59:51 +00:00
registry = initReg ( )
// PrivateRegistry is an image repository that requires authentication
PrivateRegistry = registry . PrivateRegistry
// Preconfigured image configs
dockerLibraryRegistry = "docker.io/library"
2020-01-14 10:38:55 +00:00
e2eRegistry = registry . E2eRegistry
2020-04-14 07:04:33 +00:00
promoterE2eRegistry = registry . PromoterE2eRegistry
2020-12-17 12:28:29 +00:00
buildImageRegistry = registry . BuildImageRegistry
2020-01-14 10:38:55 +00:00
gcAuthenticatedRegistry = registry . GcAuthenticatedRegistry
2021-06-25 04:59:51 +00:00
gcEtcdRegistry = registry . GcEtcdRegistry
2020-01-14 10:38:55 +00:00
gcRegistry = registry . GcRegistry
2020-12-17 12:28:29 +00:00
sigStorageRegistry = registry . SigStorageRegistry
2020-01-14 10:38:55 +00:00
gcrReleaseRegistry = registry . GcrReleaseRegistry
invalidRegistry = registry . InvalidRegistry
2021-06-25 04:59:51 +00:00
sampleRegistry = registry . SampleRegistry
microsoftRegistry = registry . MicrosoftRegistry
2019-05-31 09:45:11 +00:00
2021-06-25 04:59:51 +00:00
imageConfigs , originalImageConfigs = initImageConfigs ( )
2019-05-31 09:45:11 +00:00
)
const (
2020-12-17 12:28:29 +00:00
// None is to be used for unset/default images
None = iota
2019-06-24 09:08:09 +00:00
// Agnhost image
2020-12-17 12:28:29 +00:00
Agnhost
2020-01-14 10:38:55 +00:00
// AgnhostPrivate image
AgnhostPrivate
2019-05-31 09:45:11 +00:00
// APIServer image
APIServer
// AppArmorLoader image
AppArmorLoader
2020-01-14 10:38:55 +00:00
// AuthenticatedAlpine image
AuthenticatedAlpine
// AuthenticatedWindowsNanoServer image
AuthenticatedWindowsNanoServer
2019-05-31 09:45:11 +00:00
// BusyBox image
BusyBox
// CheckMetadataConcealment image
CheckMetadataConcealment
// CudaVectorAdd image
CudaVectorAdd
// CudaVectorAdd2 image
CudaVectorAdd2
2020-12-17 12:28:29 +00:00
// DebianIptables Image
DebianIptables
2019-05-31 09:45:11 +00:00
// EchoServer image
EchoServer
// Etcd image
Etcd
2020-01-14 10:38:55 +00:00
// GlusterDynamicProvisioner image
GlusterDynamicProvisioner
// Httpd image
Httpd
// HttpdNew image
HttpdNew
// InvalidRegistryImage image
InvalidRegistryImage
2019-05-31 09:45:11 +00:00
// IpcUtils image
IpcUtils
// JessieDnsutils image
JessieDnsutils
// Kitten image
Kitten
// Nautilus image
Nautilus
2020-01-14 10:38:55 +00:00
// NFSProvisioner image
NFSProvisioner
2019-05-31 09:45:11 +00:00
// Nginx image
Nginx
// NginxNew image
NginxNew
2021-06-25 04:59:51 +00:00
// NodePerfNpbEp image
NodePerfNpbEp
// NodePerfNpbIs image
NodePerfNpbIs
// NodePerfTfWideDeep image
NodePerfTfWideDeep
2019-05-31 09:45:11 +00:00
// Nonewprivs image
Nonewprivs
2019-06-24 09:08:09 +00:00
// NonRoot runs with a default user of 1234
NonRoot
2019-05-31 09:45:11 +00:00
// Pause - when these values are updated, also update cmd/kubelet/app/options/container_runtime.go
// Pause image
Pause
2019-06-24 09:08:09 +00:00
// Perl image
Perl
2020-01-14 10:38:55 +00:00
// PrometheusDummyExporter image
PrometheusDummyExporter
// PrometheusToSd image
PrometheusToSd
2019-05-31 09:45:11 +00:00
// Redis image
Redis
2020-01-14 10:38:55 +00:00
// RegressionIssue74839 image
RegressionIssue74839
2019-05-31 09:45:11 +00:00
// ResourceConsumer image
ResourceConsumer
2020-01-14 10:38:55 +00:00
// SdDummyExporter image
SdDummyExporter
2019-05-31 09:45:11 +00:00
// VolumeNFSServer image
VolumeNFSServer
// VolumeISCSIServer image
VolumeISCSIServer
// VolumeGlusterServer image
VolumeGlusterServer
// VolumeRBDServer image
VolumeRBDServer
2021-06-25 04:59:51 +00:00
// WindowsServer image
WindowsServer
2019-05-31 09:45:11 +00:00
)
2021-06-25 04:59:51 +00:00
func initImageConfigs ( ) ( map [ int ] Config , map [ int ] Config ) {
2019-05-31 09:45:11 +00:00
configs := map [ int ] Config { }
2021-06-25 04:59:51 +00:00
configs [ Agnhost ] = Config { promoterE2eRegistry , "agnhost" , "2.32" }
2020-01-14 10:38:55 +00:00
configs [ AgnhostPrivate ] = Config { PrivateRegistry , "agnhost" , "2.6" }
configs [ AuthenticatedAlpine ] = Config { gcAuthenticatedRegistry , "alpine" , "3.7" }
configs [ AuthenticatedWindowsNanoServer ] = Config { gcAuthenticatedRegistry , "windows-nanoserver" , "v1" }
2021-06-25 04:59:51 +00:00
configs [ APIServer ] = Config { promoterE2eRegistry , "sample-apiserver" , "1.17.4" }
configs [ AppArmorLoader ] = Config { promoterE2eRegistry , "apparmor-loader" , "1.3" }
configs [ BusyBox ] = Config { promoterE2eRegistry , "busybox" , "1.29-1" }
2021-05-10 10:45:47 +00:00
configs [ CheckMetadataConcealment ] = Config { promoterE2eRegistry , "metadata-concealment" , "1.6" }
2019-05-31 09:45:11 +00:00
configs [ CudaVectorAdd ] = Config { e2eRegistry , "cuda-vector-add" , "1.0" }
2021-06-25 04:59:51 +00:00
configs [ CudaVectorAdd2 ] = Config { promoterE2eRegistry , "cuda-vector-add" , "2.2" }
configs [ DebianIptables ] = Config { buildImageRegistry , "debian-iptables" , "buster-v1.6.2" }
configs [ EchoServer ] = Config { promoterE2eRegistry , "echoserver" , "2.3" }
configs [ Etcd ] = Config { gcEtcdRegistry , "etcd" , "3.4.13-0" }
configs [ GlusterDynamicProvisioner ] = Config { promoterE2eRegistry , "glusterdynamic-provisioner" , "v1.0" }
configs [ Httpd ] = Config { promoterE2eRegistry , "httpd" , "2.4.38-1" }
configs [ HttpdNew ] = Config { promoterE2eRegistry , "httpd" , "2.4.39-1" }
2020-01-14 10:38:55 +00:00
configs [ InvalidRegistryImage ] = Config { invalidRegistry , "alpine" , "3.1" }
2021-06-25 04:59:51 +00:00
configs [ IpcUtils ] = Config { promoterE2eRegistry , "ipc-utils" , "1.2" }
configs [ JessieDnsutils ] = Config { promoterE2eRegistry , "jessie-dnsutils" , "1.4" }
configs [ Kitten ] = Config { promoterE2eRegistry , "kitten" , "1.4" }
configs [ Nautilus ] = Config { promoterE2eRegistry , "nautilus" , "1.4" }
2020-12-17 12:28:29 +00:00
configs [ NFSProvisioner ] = Config { sigStorageRegistry , "nfs-provisioner" , "v2.2.2" }
2021-06-25 04:59:51 +00:00
configs [ Nginx ] = Config { promoterE2eRegistry , "nginx" , "1.14-1" }
configs [ NginxNew ] = Config { promoterE2eRegistry , "nginx" , "1.15-1" }
configs [ NodePerfNpbEp ] = Config { promoterE2eRegistry , "node-perf/npb-ep" , "1.1" }
configs [ NodePerfNpbIs ] = Config { promoterE2eRegistry , "node-perf/npb-is" , "1.1" }
configs [ NodePerfTfWideDeep ] = Config { promoterE2eRegistry , "node-perf/tf-wide-deep" , "1.1" }
configs [ Nonewprivs ] = Config { promoterE2eRegistry , "nonewprivs" , "1.3" }
configs [ NonRoot ] = Config { promoterE2eRegistry , "nonroot" , "1.1" }
2019-05-31 09:45:11 +00:00
// Pause - when these values are updated, also update cmd/kubelet/app/options/container_runtime.go
2021-06-25 04:59:51 +00:00
configs [ Pause ] = Config { gcRegistry , "pause" , "3.4.1" }
configs [ Perl ] = Config { promoterE2eRegistry , "perl" , "5.26" }
2020-01-14 10:38:55 +00:00
configs [ PrometheusDummyExporter ] = Config { gcRegistry , "prometheus-dummy-exporter" , "v0.1.0" }
configs [ PrometheusToSd ] = Config { gcRegistry , "prometheus-to-sd" , "v0.5.0" }
2021-06-25 04:59:51 +00:00
configs [ Redis ] = Config { promoterE2eRegistry , "redis" , "5.0.5-alpine" }
configs [ RegressionIssue74839 ] = Config { promoterE2eRegistry , "regression-issue-74839" , "1.2" }
configs [ ResourceConsumer ] = Config { promoterE2eRegistry , "resource-consumer" , "1.9" }
2020-01-14 10:38:55 +00:00
configs [ SdDummyExporter ] = Config { gcRegistry , "sd-dummy-exporter" , "v0.2.0" }
2021-06-25 04:59:51 +00:00
configs [ VolumeNFSServer ] = Config { promoterE2eRegistry , "volume/nfs" , "1.2" }
configs [ VolumeISCSIServer ] = Config { promoterE2eRegistry , "volume/iscsi" , "2.2" }
configs [ VolumeGlusterServer ] = Config { promoterE2eRegistry , "volume/gluster" , "1.2" }
configs [ VolumeRBDServer ] = Config { promoterE2eRegistry , "volume/rbd" , "1.0.3" }
configs [ WindowsServer ] = Config { microsoftRegistry , "windows" , "1809" }
// if requested, map all the SHAs into a known format based on the input
originalImageConfigs := configs
if repo := os . Getenv ( "KUBE_TEST_REPO" ) ; len ( repo ) > 0 {
configs = GetMappedImageConfigs ( originalImageConfigs , repo )
}
return configs , originalImageConfigs
}
// GetMappedImageConfigs returns the images if they were mapped to the provided
// image repository.
func GetMappedImageConfigs ( originalImageConfigs map [ int ] Config , repo string ) map [ int ] Config {
configs := make ( map [ int ] Config )
for i , config := range originalImageConfigs {
switch i {
case InvalidRegistryImage , AuthenticatedAlpine ,
AuthenticatedWindowsNanoServer , AgnhostPrivate :
// These images are special and can't be run out of the cloud - some because they
// are authenticated, and others because they are not real images. Tests that depend
// on these images can't be run without access to the public internet.
configs [ i ] = config
continue
}
// Build a new tag with a the index, a hash of the image spec (to be unique) and
// shorten and make the pull spec "safe" so it will fit in the tag
configs [ i ] = getRepositoryMappedConfig ( i , config , repo )
}
2019-05-31 09:45:11 +00:00
return configs
}
2021-06-25 04:59:51 +00:00
var (
reCharSafe = regexp . MustCompile ( ` [^\w] ` )
reDashes = regexp . MustCompile ( ` -+ ` )
)
// getRepositoryMappedConfig maps an existing image to the provided repo, generating a
// tag that is unique with the input config. The tag will contain the index, a hash of
// the image spec (to be unique) and shorten and make the pull spec "safe" so it will
// fit in the tag to allow a human to recognize the value. If index is -1, then no
// index will be added to the tag.
func getRepositoryMappedConfig ( index int , config Config , repo string ) Config {
parts := strings . SplitN ( repo , "/" , 2 )
registry , name := parts [ 0 ] , parts [ 1 ]
pullSpec := config . GetE2EImage ( )
h := sha256 . New ( )
h . Write ( [ ] byte ( pullSpec ) )
hash := base64 . RawURLEncoding . EncodeToString ( h . Sum ( nil ) [ : 16 ] )
shortName := reCharSafe . ReplaceAllLiteralString ( pullSpec , "-" )
shortName = reDashes . ReplaceAllLiteralString ( shortName , "-" )
maxLength := 127 - 16 - 6 - 10
if len ( shortName ) > maxLength {
shortName = shortName [ len ( shortName ) - maxLength : ]
}
var version string
if index == - 1 {
version = fmt . Sprintf ( "e2e-%s-%s" , shortName , hash )
} else {
version = fmt . Sprintf ( "e2e-%d-%s-%s" , index , shortName , hash )
}
return Config {
registry : registry ,
name : name ,
version : version ,
}
}
// GetOriginalImageConfigs returns the configuration before any mapping rules.
func GetOriginalImageConfigs ( ) map [ int ] Config {
return originalImageConfigs
}
2019-05-31 09:45:11 +00:00
// GetImageConfigs returns the map of imageConfigs
func GetImageConfigs ( ) map [ int ] Config {
return imageConfigs
}
// GetConfig returns the Config object for an image
func GetConfig ( image int ) Config {
return imageConfigs [ image ]
}
// GetE2EImage returns the fully qualified URI to an image (including version)
func GetE2EImage ( image int ) string {
return fmt . Sprintf ( "%s/%s:%s" , imageConfigs [ image ] . registry , imageConfigs [ image ] . name , imageConfigs [ image ] . version )
}
// GetE2EImage returns the fully qualified URI to an image (including version)
func ( i * Config ) GetE2EImage ( ) string {
return fmt . Sprintf ( "%s/%s:%s" , i . registry , i . name , i . version )
}
// GetPauseImageName returns the pause image name with proper version
func GetPauseImageName ( ) string {
return GetE2EImage ( Pause )
}
2020-01-14 10:38:55 +00:00
// ReplaceRegistryInImageURL replaces the registry in the image URL with a custom one
func ReplaceRegistryInImageURL ( imageURL string ) ( string , error ) {
parts := strings . Split ( imageURL , "/" )
countParts := len ( parts )
registryAndUser := strings . Join ( parts [ : countParts - 1 ] , "/" )
2021-06-25 04:59:51 +00:00
if repo := os . Getenv ( "KUBE_TEST_REPO" ) ; len ( repo ) > 0 {
index := - 1
for i , v := range originalImageConfigs {
if v . GetE2EImage ( ) == imageURL {
index = i
break
}
}
last := strings . SplitN ( parts [ countParts - 1 ] , ":" , 2 )
config := getRepositoryMappedConfig ( index , Config {
registry : parts [ 0 ] ,
name : strings . Join ( [ ] string { strings . Join ( parts [ 1 : countParts - 1 ] , "/" ) , last [ 0 ] } , "/" ) ,
version : last [ 1 ] ,
} , repo )
return config . GetE2EImage ( ) , nil
}
2020-01-14 10:38:55 +00:00
switch registryAndUser {
case "gcr.io/kubernetes-e2e-test-images" :
registryAndUser = e2eRegistry
case "k8s.gcr.io" :
registryAndUser = gcRegistry
2020-12-17 12:28:29 +00:00
case "k8s.gcr.io/sig-storage" :
registryAndUser = sigStorageRegistry
2020-01-14 10:38:55 +00:00
case "gcr.io/k8s-authenticated-test" :
registryAndUser = PrivateRegistry
case "gcr.io/google-samples" :
registryAndUser = sampleRegistry
case "gcr.io/gke-release" :
registryAndUser = gcrReleaseRegistry
case "docker.io/library" :
registryAndUser = dockerLibraryRegistry
default :
if countParts == 1 {
// We assume we found an image from docker hub library
// e.g. openjdk -> docker.io/library/openjdk
registryAndUser = dockerLibraryRegistry
break
}
return "" , fmt . Errorf ( "Registry: %s is missing in test/utils/image/manifest.go, please add the registry, otherwise the test will fail on air-gapped clusters" , registryAndUser )
}
return fmt . Sprintf ( "%s/%s" , registryAndUser , parts [ countParts - 1 ] ) , nil
}