shdsbilling/on-premise/main/rancher_v2.9.1/source/rancher-2.9.1/pkg/image/resolve.go

214 lines
6.7 KiB
Go

package image
import (
"fmt"
"path"
"sort"
"strings"
"github.com/Masterminds/semver/v3"
"github.com/pkg/errors"
util "github.com/rancher/rancher/pkg/cluster"
v1 "github.com/rancher/rancher/pkg/generated/norman/core/v1"
v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
"github.com/rancher/rancher/pkg/settings"
rketypes "github.com/rancher/rke/types"
img "github.com/rancher/rke/types/image"
)
// ExportConfig provides parameters you can define to configure image exporting for Rancher components
type ExportConfig struct {
RancherVersion string
OsType OSType
ChartsPath string
SystemChartsPath string
GithubEndpoints []GithubEndpoint
}
type OSType int
const (
Linux OSType = iota
Windows
)
const imageListDelimiter = "\n"
var osTypeImageListName = map[OSType]string{
Windows: "windows-rancher-images",
Linux: "rancher-images",
}
// Resolve calls ResolveWithCluster passing nil into the cluster argument.
// returns the image concatenated with the URL of the system default registry.
// if there is no system default registry it will return the image
func Resolve(image string) string {
return ResolveWithCluster(image, nil)
}
// ResolveWithCluster returns the image concatenated with the URL of the private registry specified, adding rancher/ if is a private repo.
// It will use the cluster level registry if one is found, or the system default registry if no cluster level registry is found.
// If either is not found, it returns the image.
func ResolveWithCluster(image string, cluster *v3.Cluster) string {
reg := util.GetPrivateRegistryURL(cluster)
if reg != "" && !strings.HasPrefix(image, reg) {
// Images from Dockerhub Library repo, we add rancher prefix when using private registry
if !strings.Contains(image, "/") {
image = "rancher/" + image
}
return path.Join(reg, image)
}
return image
}
// GetImages fetches the list of container images used in the sources provided in the exportConfig.
// Rancher charts, system charts, system images and extension images of Rancher are fetched.
// GetImages is called during runtime by Rancher catalog package which is deprecated.
// It is actually used for generation rancher-images.txt for airgap scenarios.
func GetImages(exportConfig ExportConfig, externalImages map[string][]string, imagesFromArgs []string, rkeSystemImages map[string]rketypes.RKESystemImages) ([]string, []string, error) {
imagesSet := make(map[string]map[string]struct{})
// fetch images from charts
charts := Charts{exportConfig}
if err := charts.FetchImages(imagesSet); err != nil {
return nil, nil, errors.Wrap(err, "failed to fetch images from charts")
}
// fetch images from system charts
systemCharts := SystemCharts{exportConfig}
if err := systemCharts.FetchImages(imagesSet); err != nil {
return nil, nil, errors.Wrap(err, "failed to fetch images from system charts")
}
// fetch images from system images
system := System{exportConfig}
if err := system.FetchImages(rkeSystemImages, imagesSet); err != nil {
return nil, nil, errors.Wrap(err, "failed to fetch images from system")
}
// fetch images from extension catalog images
extensions := ExtensionsConfig{exportConfig}
if err := extensions.FetchExtensionImages(imagesSet); err != nil {
return nil, nil, errors.Wrap(err, "failed to fetch images from extensions")
}
setRequirementImages(exportConfig.OsType, imagesSet)
// set rancher images from args
setImages("rancher", imagesFromArgs, imagesSet)
for source, sourceImages := range externalImages {
setImages(source, sourceImages, imagesSet)
}
convertMirroredImages(imagesSet)
imagesList, imagesAndSourcesList := generateImageAndSourceLists(imagesSet)
return imagesList, imagesAndSourcesList, nil
}
func AddImagesToImageListConfigMap(cm *v1.ConfigMap, rancherVersion, systemChartsPath string) error {
exportConfig := ExportConfig{
SystemChartsPath: systemChartsPath,
OsType: Windows,
RancherVersion: rancherVersion,
}
windowsImages, _, err := GetImages(exportConfig, nil, []string{}, nil)
if err != nil {
return err
}
exportConfig.OsType = Linux
linuxImages, _, err := GetImages(exportConfig, nil, []string{}, nil)
if err != nil {
return err
}
cm.Data = make(map[string]string, 2)
cm.Data[osTypeImageListName[Windows]] = strings.Join(windowsImages, imageListDelimiter)
cm.Data[osTypeImageListName[Linux]] = strings.Join(linuxImages, imageListDelimiter)
return nil
}
func ParseCatalogImageListConfigMap(cm *v1.ConfigMap) ([]string, []string) {
windowsImages := strings.Split(cm.Data[osTypeImageListName[Windows]], imageListDelimiter)
linuxImages := strings.Split(cm.Data[osTypeImageListName[Linux]], imageListDelimiter)
return windowsImages, linuxImages
}
func IsValidSemver(version string) bool {
_, err := semver.NewVersion(version)
return err == nil
}
func setRequirementImages(osType OSType, imagesSet map[string]map[string]struct{}) {
coreLabel := "core"
switch osType {
case Linux:
addSourceToImage(imagesSet, settings.ShellImage.Get(), coreLabel)
addSourceToImage(imagesSet, settings.MachineProvisionImage.Get(), coreLabel)
addSourceToImage(imagesSet, "rancher/mirrored-bci-busybox:15.4.11.2", coreLabel)
addSourceToImage(imagesSet, "rancher/mirrored-bci-micro:15.4.14.3", coreLabel)
}
}
func setImages(source string, imagesFromArgs []string, imagesSet map[string]map[string]struct{}) {
for _, image := range imagesFromArgs {
addSourceToImage(imagesSet, image, source)
}
}
func addSourceToImage(imagesSet map[string]map[string]struct{}, image string, sources ...string) {
if image == "" {
return
}
if imagesSet[image] == nil {
imagesSet[image] = make(map[string]struct{})
}
for _, source := range sources {
imagesSet[image][source] = struct{}{}
}
}
func convertMirroredImages(imagesSet map[string]map[string]struct{}) {
for image := range imagesSet {
convertedImage := img.Mirror(image)
if image == convertedImage {
continue
}
for source := range imagesSet[image] {
addSourceToImage(imagesSet, convertedImage, source)
}
delete(imagesSet, image)
}
}
func generateImageAndSourceLists(imagesSet map[string]map[string]struct{}) ([]string, []string) {
var images, imagesAndSources []string
// unique
for image := range imagesSet {
images = append(images, image)
}
// sort
sort.Slice(images, func(i, j int) bool {
return images[i] < images[j]
})
for _, image := range images {
imagesAndSources = append(imagesAndSources, fmt.Sprintf("%s %s", image, getSourcesList(imagesSet[image])))
}
return images, imagesAndSources
}
func getSourcesList(imageSources map[string]struct{}) string {
var sources []string
for source := range imageSources {
sources = append(sources, source)
}
sort.Strings(sources)
return strings.Join(sources, ",")
}