minikube/hack/update/registry.go

135 lines
4.4 KiB
Go

/*
Copyright 2020 The Kubernetes Authors All rights reserved.
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 update
import (
"context"
"fmt"
"os"
"os/exec"
"strings"
"time"
"k8s.io/klog/v2"
)
var (
// keep list of registries in sync with those in "pkg/drivers/kic/types.go"
registries = []registry{
{
name: "Google Cloud Container Registry",
image: "gcr.io/k8s-minikube/kicbase",
username: os.Getenv("GCR_USERNAME"),
password: os.Getenv("GCR_TOKEN"),
},
{
name: "Docker Hub Container Registry",
image: "docker.io/kicbase/stable",
username: os.Getenv("DOCKER_USERNAME"),
password: os.Getenv("DOCKER_TOKEN"),
},
{
name: "GitHub Packages Registry",
image: "docker.pkg.github.com/kubernetes/minikube/kicbase",
username: os.Getenv("GITHUB_USERNAME"),
password: os.Getenv("GITHUB_TOKEN"),
},
}
)
// container registry name, image path, credentials, and updated flag
type registry struct {
name string
image string
username string
password string
}
// crUpdate tags image with version, pushes it to container registry, and returns any error
func crUpdate(ctx context.Context, reg registry, image, version string) error {
login := exec.CommandContext(ctx, "docker", "login", "--username", reg.username, "--password-stdin", reg.image)
if err := RunWithRetryNotify(ctx, login, strings.NewReader(reg.password), 1*time.Minute, 10); err != nil {
return fmt.Errorf("failed logging in to %s: %w", reg.name, err)
}
klog.Infof("successfully logged in to %s", reg.name)
tag := exec.CommandContext(ctx, "docker", "tag", image+":"+version, reg.image+":"+version)
if err := RunWithRetryNotify(ctx, tag, nil, 1*time.Minute, 10); err != nil {
return fmt.Errorf("failed tagging %s for %s: %w", reg.image+":"+version, reg.name, err)
}
klog.Infof("successfully tagged %s for %s", reg.image+":"+version, reg.name)
push := exec.CommandContext(ctx, "docker", "push", reg.image+":"+version)
if err := RunWithRetryNotify(ctx, push, nil, 2*time.Minute, 10); err != nil {
return fmt.Errorf("failed pushing %s to %s: %w", reg.image+":"+version, reg.name, err)
}
klog.Infof("successfully pushed %s to %s", reg.image+":"+version, reg.name)
return nil
}
// CRUpdateAll calls crUpdate for each available registry, and returns if at least one got updated
func CRUpdateAll(ctx context.Context, image, version string) (updated bool) {
for _, reg := range registries {
if err := crUpdate(ctx, reg, image, version); err != nil {
klog.Errorf("failed updating %s", reg.name)
continue
}
klog.Infof("successfully updated %s", reg.name)
updated = true
}
return updated
}
// PullImage checks if current image exists locally, tries to pull it if not, and
// returns reference image url and any error
func PullImage(ctx context.Context, current, release string) (image string, err error) {
// check if image exists locally
for _, reg := range registries {
inspect := exec.CommandContext(ctx, "docker", "inspect", reg.image+":"+current, "--format", "{{.Id}}")
if err := RunWithRetryNotify(ctx, inspect, nil, 1*time.Second, 10); err != nil {
continue
}
image = reg.image
break
}
if image == "" {
// try to pull image locally
for _, reg := range registries {
pull := exec.CommandContext(ctx, "docker", "pull", reg.image+":"+current)
if err := RunWithRetryNotify(ctx, pull, nil, 2*time.Minute, 10); err != nil {
continue
}
image = reg.image
break
}
}
if image == "" {
return "", fmt.Errorf("cannot find current image version tag %s locally nor in any registry", current)
}
return image, nil
}
// TagImage tags local image:current with stable version, and returns any error
func TagImage(ctx context.Context, image, current, stable string) error {
tag := exec.CommandContext(ctx, "docker", "tag", image+":"+current, image+":"+stable)
if err := RunWithRetryNotify(ctx, tag, nil, 1*time.Second, 10); err != nil {
return err
}
return nil
}