mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 21:47:07 +00:00
do not query the metadata server to find out if running on GCE. Retry docker registry fetches on GCP
Signed-off-by: Vishnu kannan <vishnuk@google.com>
This commit is contained in:
parent
6193335bd9
commit
ee9cded79a
@ -18,6 +18,7 @@ package gcp_credentials
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -36,8 +37,12 @@ const (
|
|||||||
metadataEmail = metadataUrl + "instance/service-accounts/default/email"
|
metadataEmail = metadataUrl + "instance/service-accounts/default/email"
|
||||||
storageScopePrefix = "https://www.googleapis.com/auth/devstorage"
|
storageScopePrefix = "https://www.googleapis.com/auth/devstorage"
|
||||||
cloudPlatformScopePrefix = "https://www.googleapis.com/auth/cloud-platform"
|
cloudPlatformScopePrefix = "https://www.googleapis.com/auth/cloud-platform"
|
||||||
|
googleProductName = "Google"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A variable to enable testing
|
||||||
|
var gceProductNameFile = "/sys/class/dmi/id/product_name"
|
||||||
|
|
||||||
// For these urls, the parts of the host name can be glob, for example '*.gcr.io" will match
|
// For these urls, the parts of the host name can be glob, for example '*.gcr.io" will match
|
||||||
// "foo.gcr.io" and "bar.gcr.io".
|
// "foo.gcr.io" and "bar.gcr.io".
|
||||||
var containerRegistryUrls = []string{"container.cloud.google.com", "gcr.io", "*.gcr.io"}
|
var containerRegistryUrls = []string{"container.cloud.google.com", "gcr.io", "*.gcr.io"}
|
||||||
@ -98,10 +103,19 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if it finds a local GCE VM
|
||||||
|
func onGCEVM() bool {
|
||||||
|
data, err := ioutil.ReadFile(gceProductNameFile)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(2).Infof("Error while reading product_name: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return strings.Contains(string(data), googleProductName)
|
||||||
|
}
|
||||||
|
|
||||||
// Enabled implements DockerConfigProvider for all of the Google implementations.
|
// Enabled implements DockerConfigProvider for all of the Google implementations.
|
||||||
func (g *metadataProvider) Enabled() bool {
|
func (g *metadataProvider) Enabled() bool {
|
||||||
_, err := credentialprovider.ReadUrl(metadataUrl, g.Client, metadataHeader)
|
return onGCEVM()
|
||||||
return err == nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LazyProvide implements DockerConfigProvider. Should never be called.
|
// LazyProvide implements DockerConfigProvider. Should never be called.
|
||||||
@ -151,12 +165,30 @@ func (g *dockerConfigUrlKeyProvider) Provide() credentialprovider.DockerConfig {
|
|||||||
// Enabled implements a special metadata-based check, which verifies the
|
// Enabled implements a special metadata-based check, which verifies the
|
||||||
// storage scope is available on the GCE VM.
|
// storage scope is available on the GCE VM.
|
||||||
func (g *containerRegistryProvider) Enabled() bool {
|
func (g *containerRegistryProvider) Enabled() bool {
|
||||||
value, err := credentialprovider.ReadUrl(metadataScopes+"?alt=json", g.Client, metadataHeader)
|
if !onGCEVM() {
|
||||||
if err != nil {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
// Given that we are on GCE, we should keep retrying until the metadata server responds.
|
||||||
|
var (
|
||||||
|
value []byte
|
||||||
|
err error
|
||||||
|
backoff = time.Millisecond
|
||||||
|
)
|
||||||
|
const maxBackoff = time.Minute
|
||||||
|
for {
|
||||||
|
value, err = credentialprovider.ReadUrl(metadataScopes+"?alt=json", g.Client, metadataHeader)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
glog.Errorf("failed to Get %q: %v", metadataScopes+"?alt=json", err)
|
||||||
|
time.Sleep(backoff)
|
||||||
|
backoff = backoff * 2
|
||||||
|
if backoff > maxBackoff {
|
||||||
|
backoff = maxBackoff
|
||||||
|
}
|
||||||
|
}
|
||||||
var scopes []string
|
var scopes []string
|
||||||
if err := json.Unmarshal([]byte(value), &scopes); err != nil {
|
if err := json.Unmarshal(value, &scopes); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,9 +20,11 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -31,6 +33,14 @@ import (
|
|||||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func createProductNameFile() (string, error) {
|
||||||
|
file, err := ioutil.TempFile("", "")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to create temporary test file: %v", err)
|
||||||
|
}
|
||||||
|
return file.Name(), ioutil.WriteFile(file.Name(), []byte("Google"), 0600)
|
||||||
|
}
|
||||||
|
|
||||||
func TestDockerKeyringFromGoogleDockerConfigMetadata(t *testing.T) {
|
func TestDockerKeyringFromGoogleDockerConfigMetadata(t *testing.T) {
|
||||||
registryUrl := "hello.kubernetes.io"
|
registryUrl := "hello.kubernetes.io"
|
||||||
email := "foo@bar.baz"
|
email := "foo@bar.baz"
|
||||||
@ -44,6 +54,12 @@ func TestDockerKeyringFromGoogleDockerConfigMetadata(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`, registryUrl, email, auth)
|
}`, registryUrl, email, auth)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
gceProductNameFile, err = createProductNameFile()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to create gce product name file: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(gceProductNameFile)
|
||||||
const probeEndpoint = "/computeMetadata/v1/"
|
const probeEndpoint = "/computeMetadata/v1/"
|
||||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// Only serve the one metadata key.
|
// Only serve the one metadata key.
|
||||||
@ -111,6 +127,12 @@ func TestDockerKeyringFromGoogleDockerConfigMetadataUrl(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`, registryUrl, email, auth)
|
}`, registryUrl, email, auth)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
gceProductNameFile, err = createProductNameFile()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to create gce product name file: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(gceProductNameFile)
|
||||||
const probeEndpoint = "/computeMetadata/v1/"
|
const probeEndpoint = "/computeMetadata/v1/"
|
||||||
const valueEndpoint = "/my/value"
|
const valueEndpoint = "/my/value"
|
||||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -181,6 +203,13 @@ func TestContainerRegistryBasics(t *testing.T) {
|
|||||||
emailEndpoint = defaultEndpoint + "email"
|
emailEndpoint = defaultEndpoint + "email"
|
||||||
tokenEndpoint = defaultEndpoint + "token"
|
tokenEndpoint = defaultEndpoint + "token"
|
||||||
)
|
)
|
||||||
|
var err error
|
||||||
|
gceProductNameFile, err = createProductNameFile()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to create gce product name file: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(gceProductNameFile)
|
||||||
|
|
||||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// Only serve the URL key and the value endpoint
|
// Only serve the URL key and the value endpoint
|
||||||
if scopeEndpoint == r.URL.Path {
|
if scopeEndpoint == r.URL.Path {
|
||||||
@ -260,6 +289,13 @@ func TestContainerRegistryNoStorageScope(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
gceProductNameFile, err = createProductNameFile()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to create gce product name file: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(gceProductNameFile)
|
||||||
|
|
||||||
// Make a transport that reroutes all traffic to the example server
|
// Make a transport that reroutes all traffic to the example server
|
||||||
transport := utilnet.SetTransportDefaults(&http.Transport{
|
transport := utilnet.SetTransportDefaults(&http.Transport{
|
||||||
Proxy: func(req *http.Request) (*url.URL, error) {
|
Proxy: func(req *http.Request) (*url.URL, error) {
|
||||||
@ -293,6 +329,13 @@ func TestComputePlatformScopeSubstitutesStorageScope(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
gceProductNameFile, err = createProductNameFile()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to create gce product name file: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(gceProductNameFile)
|
||||||
|
|
||||||
// Make a transport that reroutes all traffic to the example server
|
// Make a transport that reroutes all traffic to the example server
|
||||||
transport := utilnet.SetTransportDefaults(&http.Transport{
|
transport := utilnet.SetTransportDefaults(&http.Transport{
|
||||||
Proxy: func(req *http.Request) (*url.URL, error) {
|
Proxy: func(req *http.Request) (*url.URL, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user