Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ Usage of k8s-image-availability-exporter:
namespace label for checks
-skip-registry-cert-verification
whether to skip registries' certificate verification
-mirror-scheme value
Add a mirror scheme (format: mirror=scheme). Beware allow-plain-http is a overriding option.
```

## Metrics
Expand Down
30 changes: 30 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
func main() {
cp := newCaPaths()
mirrors := newMirrorMap()
mirrorSchemes := newMirrorSchemeMap()
forceCheckDisabledControllerKindsParser := cli.NewForceCheckDisabledControllerKindsParser()

imageCheckInterval := flag.Duration("check-interval", time.Minute, "image re-check interval")
Expand All @@ -43,6 +44,7 @@ func main() {
defaultRegistry := flag.String("default-registry", "", fmt.Sprintf("default registry to use in absence of a fully qualified image name, defaults to %q", name.DefaultRegistry))
flag.Var(&cp, "capath", "path to a file that contains CA certificates in the PEM format") // named after the curl cli flag
flag.Var(&mirrors, "image-mirror", "Add a mirror repository (format: original=mirror)")
flag.Var(&mirrorSchemes, "mirror-scheme", "Add a mirror scheme (format: mirror=scheme). Beware: allow-plain-http is a overriding option.")
flag.Func("force-check-disabled-controllers", `comma-separated list of controller kinds for which image is forcibly checked, even when workloads are disabled or suspended. Acceptable values include "Deployment", "StatefulSet", "DaemonSet", "Cronjob" or "*" for all kinds (this option is case-insensitive)`, forceCheckDisabledControllerKindsParser.Parse)

flag.Parse()
Expand Down Expand Up @@ -103,6 +105,7 @@ func main() {
*defaultRegistry,
*namespaceLabels,
mirrors,
mirrorSchemes,
)
prometheus.MustRegister(registryChecker)

Expand All @@ -125,6 +128,7 @@ func main() {
var (
_ flag.Value = (*caPaths)(nil)
_ flag.Value = (*mirrorMap)(nil)
_ flag.Value = (*mirrorSchemeMap)(nil)
)

// caPaths is a custom flag type for a list of paths to CA certificates
Expand Down Expand Up @@ -162,3 +166,29 @@ func (m *mirrorMap) Set(value string) error {
(*m)[result[0]] = result[1]
return nil
}

type mirrorSchemeMap map[string]string

func newMirrorSchemeMap() mirrorSchemeMap {
return make(mirrorSchemeMap)
}

func (m *mirrorSchemeMap) String() string {
return fmt.Sprintf("%v", *m)
}

func (m *mirrorSchemeMap) Set(value string) error {
parts := strings.Split(value, "=")
if len(parts) != 2 {
return errors.New("invalid format for mirror scheme, must be mirror=scheme")
}

mirror := parts[0]
scheme := strings.ToUpper(parts[1])
if scheme != "HTTP" && scheme != "HTTPS" {
return errors.New("invalid scheme, must be HTTP or HTTPS")
}

(*m)[mirror] = scheme
return nil
}
49 changes: 33 additions & 16 deletions pkg/registry/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import (
"crypto/x509"
"errors"
"fmt"
"net/http"
"os"
"regexp"
"strings"
"time"

"github.com/flant/k8s-image-availability-exporter/pkg/providers"
"github.com/flant/k8s-image-availability-exporter/pkg/providers/amazon"
"github.com/flant/k8s-image-availability-exporter/pkg/providers/k8s"
Expand All @@ -14,11 +20,6 @@ import (
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/tools/cache"
"net/http"
"os"
"regexp"
"strings"
"time"

"github.com/prometheus/client_golang/prometheus"

Expand All @@ -45,9 +46,10 @@ const (
)

type registryCheckerConfig struct {
defaultRegistry string
plainHTTP bool
mirrorsMap map[string]string
defaultRegistry string
plainHTTP bool
mirrorsMap map[string]string
mirrorsSchemeMap map[string]string
}

type Checker struct {
Expand Down Expand Up @@ -87,6 +89,7 @@ func NewChecker(
defaultRegistry string,
namespaceLabel string,
mirrorsMap map[string]string,
mirrorsSchemeMap map[string]string,
) *Checker {
informerFactory := informers.NewSharedInformerFactory(kubeClient, time.Hour)

Expand Down Expand Up @@ -129,9 +132,10 @@ func NewChecker(
kubeClient: kubeClient,

config: registryCheckerConfig{
defaultRegistry: defaultRegistry,
plainHTTP: plainHTTP,
mirrorsMap: mirrorsMap,
defaultRegistry: defaultRegistry,
plainHTTP: plainHTTP,
mirrorsMap: mirrorsMap,
mirrorsSchemeMap: mirrorsSchemeMap,
},
}

Expand Down Expand Up @@ -317,22 +321,35 @@ func (rc *Checker) Check(imageName string) store.AvailabilityMode {
return rc.checkImageAvailability(log, imageName, keyChain)
}

func getImageWithMirror(originalImage string, mirrors map[string]string) string {
func getImageWithMirror(originalImage string, mirrors map[string]string, mirrorsSchemes map[string]string) (image string, allowPlainHTTP bool) {
for originalRepo, mirrorRepo := range mirrors {
if strings.HasPrefix(originalImage, originalRepo) {
return strings.Replace(originalImage, originalRepo, mirrorRepo, 1)
mirroredImage := strings.Replace(originalImage, originalRepo, mirrorRepo, 1)

if scheme, ok := mirrorsSchemes[mirrorRepo]; ok && scheme != "" {
allowPlainHTTP = (scheme == "HTTP")
}

return mirroredImage, allowPlainHTTP
}
}

return originalImage
return originalImage, false
}

func (rc *Checker) checkImageAvailability(log *logrus.Entry, imageName string, kc authn.Keychain) (availMode store.AvailabilityMode) {
allowPlainHTTP := rc.config.plainHTTP

if len(rc.config.mirrorsMap) > 0 {
imageName = getImageWithMirror(imageName, rc.config.mirrorsMap)
var mirrorAllowsPlainHTTP bool
imageName, mirrorAllowsPlainHTTP = getImageWithMirror(imageName, rc.config.mirrorsMap, rc.config.mirrorsSchemeMap)

if !rc.config.plainHTTP && mirrorAllowsPlainHTTP {
allowPlainHTTP = true
}
}

ref, err := parseImageName(imageName, rc.config.defaultRegistry, rc.config.plainHTTP)
ref, err := parseImageName(imageName, rc.config.defaultRegistry, allowPlainHTTP)
if err != nil {
return checkImageNameParseErr(log, err)
}
Expand Down
Loading