mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 02:43:36 +00:00
vendor updates
This commit is contained in:
5
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/BUILD
generated
vendored
5
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/BUILD
generated
vendored
@ -10,7 +10,6 @@ go_library(
|
||||
srcs = [
|
||||
"configsync.go",
|
||||
"controller.go",
|
||||
"rollback.go",
|
||||
"watch.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubelet/kubeletconfig",
|
||||
@ -19,19 +18,21 @@ go_library(
|
||||
"//pkg/kubelet/apis/kubeletconfig/validation:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig/checkpoint:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig/checkpoint/store:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig/configfiles:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig/status:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig/util/equal:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig/util/log:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig/util/panic:go_default_library",
|
||||
"//pkg/util/filesystem:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
|
||||
],
|
||||
)
|
||||
|
5
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/BUILD
generated
vendored
5
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/BUILD
generated
vendored
@ -13,12 +13,11 @@ go_test(
|
||||
"configmap_test.go",
|
||||
"download_test.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint",
|
||||
library = ":go_default_library",
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig/scheme:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig/v1beta1:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig/util/codec:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig/util/test:go_default_library",
|
||||
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
|
||||
|
1
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/configmap.go
generated
vendored
1
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/configmap.go
generated
vendored
@ -65,7 +65,6 @@ func (c *configMapCheckpoint) Parse() (*kubeletconfig.KubeletConfiguration, erro
|
||||
return nil, fmt.Errorf(emptyCfgErr)
|
||||
}
|
||||
|
||||
// TODO(mtaufen): Once the KubeletConfiguration type is decomposed, extend this to a key for each sub-object
|
||||
config, ok := c.configMap.Data[configMapConfigKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("key %q not found in ConfigMap", configMapConfigKey)
|
||||
|
12
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/configmap_test.go
generated
vendored
12
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/configmap_test.go
generated
vendored
@ -28,7 +28,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
|
||||
kubeletscheme "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme"
|
||||
kubeletconfigv1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
|
||||
kubeletconfigv1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
|
||||
utiltest "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/test"
|
||||
)
|
||||
|
||||
@ -94,7 +94,7 @@ func TestConfigMapCheckpointParse(t *testing.T) {
|
||||
}
|
||||
|
||||
// get the built-in default configuration
|
||||
external := &kubeletconfigv1alpha1.KubeletConfiguration{}
|
||||
external := &kubeletconfigv1beta1.KubeletConfiguration{}
|
||||
kubeletScheme.Default(external)
|
||||
defaultConfig := &kubeletconfig.KubeletConfiguration{}
|
||||
err = kubeletScheme.Convert(external, defaultConfig, nil)
|
||||
@ -119,19 +119,19 @@ func TestConfigMapCheckpointParse(t *testing.T) {
|
||||
"kubelet": "{*"}}, nil, "failed to decode"},
|
||||
// invalid object
|
||||
{"missing kind", &apiv1.ConfigMap{Data: map[string]string{
|
||||
"kubelet": `{"apiVersion":"kubeletconfig/v1alpha1"}`}}, nil, "failed to decode"},
|
||||
"kubelet": `{"apiVersion":"kubelet.config.k8s.io/v1beta1"}`}}, nil, "failed to decode"},
|
||||
{"missing version", &apiv1.ConfigMap{Data: map[string]string{
|
||||
"kubelet": `{"kind":"KubeletConfiguration"}`}}, nil, "failed to decode"},
|
||||
{"unregistered kind", &apiv1.ConfigMap{Data: map[string]string{
|
||||
"kubelet": `{"kind":"BogusKind","apiVersion":"kubeletconfig/v1alpha1"}`}}, nil, "failed to decode"},
|
||||
"kubelet": `{"kind":"BogusKind","apiVersion":"kubelet.config.k8s.io/v1beta1"}`}}, nil, "failed to decode"},
|
||||
{"unregistered version", &apiv1.ConfigMap{Data: map[string]string{
|
||||
"kubelet": `{"kind":"KubeletConfiguration","apiVersion":"bogusversion"}`}}, nil, "failed to decode"},
|
||||
// empty object with correct kind and version should result in the defaults for that kind and version
|
||||
{"default from yaml", &apiv1.ConfigMap{Data: map[string]string{
|
||||
"kubelet": `kind: KubeletConfiguration
|
||||
apiVersion: kubeletconfig/v1alpha1`}}, defaultConfig, ""},
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1`}}, defaultConfig, ""},
|
||||
{"default from json", &apiv1.ConfigMap{Data: map[string]string{
|
||||
"kubelet": `{"kind":"KubeletConfiguration","apiVersion":"kubeletconfig/v1alpha1"}`}}, defaultConfig, ""},
|
||||
"kubelet": `{"kind":"KubeletConfiguration","apiVersion":"kubelet.config.k8s.io/v1beta1"}`}}, defaultConfig, ""},
|
||||
}
|
||||
for _, c := range cases {
|
||||
cpt := &configMapCheckpoint{kubeletCodecs, c.cm}
|
||||
|
13
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/download.go
generated
vendored
13
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/download.go
generated
vendored
@ -34,6 +34,8 @@ import (
|
||||
type RemoteConfigSource interface {
|
||||
// UID returns the UID of the remote config source object
|
||||
UID() string
|
||||
// APIPath returns the API path to the remote resource, e.g. its SelfLink
|
||||
APIPath() string
|
||||
// Download downloads the remote config source object returns a Checkpoint backed by the object,
|
||||
// or a sanitized failure reason and error if the download fails
|
||||
Download(client clientset.Interface) (Checkpoint, string, error)
|
||||
@ -110,6 +112,13 @@ func (r *remoteConfigMap) UID() string {
|
||||
return string(r.source.ConfigMapRef.UID)
|
||||
}
|
||||
|
||||
const configMapAPIPathFmt = "/api/v1/namespaces/%s/configmaps/%s"
|
||||
|
||||
func (r *remoteConfigMap) APIPath() string {
|
||||
ref := r.source.ConfigMapRef
|
||||
return fmt.Sprintf(configMapAPIPathFmt, ref.Namespace, ref.Name)
|
||||
}
|
||||
|
||||
func (r *remoteConfigMap) Download(client clientset.Interface) (Checkpoint, string, error) {
|
||||
var reason string
|
||||
uid := string(r.source.ConfigMapRef.UID)
|
||||
@ -119,13 +128,13 @@ func (r *remoteConfigMap) Download(client clientset.Interface) (Checkpoint, stri
|
||||
// get the ConfigMap via namespace/name, there doesn't seem to be a way to get it by UID
|
||||
cm, err := client.CoreV1().ConfigMaps(r.source.ConfigMapRef.Namespace).Get(r.source.ConfigMapRef.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
reason = fmt.Sprintf(status.FailSyncReasonDownloadFmt, r.source.ConfigMapRef.Name, r.source.ConfigMapRef.Namespace)
|
||||
reason = fmt.Sprintf(status.FailSyncReasonDownloadFmt, r.APIPath())
|
||||
return nil, reason, fmt.Errorf("%s, error: %v", reason, err)
|
||||
}
|
||||
|
||||
// ensure that UID matches the UID on the reference, the ObjectReference must be unambiguous
|
||||
if r.source.ConfigMapRef.UID != cm.UID {
|
||||
reason = fmt.Sprintf(status.FailSyncReasonUIDMismatchFmt, r.source.ConfigMapRef.UID, cm.UID)
|
||||
reason = fmt.Sprintf(status.FailSyncReasonUIDMismatchFmt, r.source.ConfigMapRef.UID, r.APIPath(), cm.UID)
|
||||
return nil, reason, fmt.Errorf(reason)
|
||||
}
|
||||
|
||||
|
19
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/download_test.go
generated
vendored
19
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/download_test.go
generated
vendored
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package checkpoint
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
@ -92,6 +93,20 @@ func TestRemoteConfigMapUID(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteConfigMapAPIPath(t *testing.T) {
|
||||
name := "name"
|
||||
namespace := "namespace"
|
||||
cpt := &remoteConfigMap{
|
||||
&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: name, Namespace: namespace, UID: ""}},
|
||||
}
|
||||
expect := fmt.Sprintf(configMapAPIPathFmt, cpt.source.ConfigMapRef.Namespace, cpt.source.ConfigMapRef.Name)
|
||||
// APIPath() method should return the correct path to the referenced resource
|
||||
path := cpt.APIPath()
|
||||
if expect != path {
|
||||
t.Errorf("expect APIPath() to return %q, but got %q", expect, namespace)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteConfigMapDownload(t *testing.T) {
|
||||
_, kubeletCodecs, err := kubeletscheme.NewSchemeAndCodecs()
|
||||
if err != nil {
|
||||
@ -116,11 +131,11 @@ func TestRemoteConfigMapDownload(t *testing.T) {
|
||||
// object doesn't exist
|
||||
{"object doesn't exist",
|
||||
&remoteConfigMap{&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "bogus", Namespace: "namespace", UID: "bogus"}}},
|
||||
nil, "failed to download ConfigMap"},
|
||||
nil, "not found"},
|
||||
// UID of downloaded object doesn't match UID of referent found via namespace/name
|
||||
{"UID is incorrect for namespace/name",
|
||||
&remoteConfigMap{&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "bogus"}}},
|
||||
nil, "does not match UID"},
|
||||
nil, "does not match"},
|
||||
// successful download
|
||||
{"object exists and reference is correct",
|
||||
&remoteConfigMap{&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "uid"}}},
|
||||
|
3
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/store/BUILD
generated
vendored
3
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/store/BUILD
generated
vendored
@ -12,8 +12,7 @@ go_test(
|
||||
"fsstore_test.go",
|
||||
"store_test.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/store",
|
||||
library = ":go_default_library",
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/kubelet/kubeletconfig/checkpoint:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig/util/files:go_default_library",
|
||||
|
5
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/configfiles/BUILD
generated
vendored
5
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/configfiles/BUILD
generated
vendored
@ -35,12 +35,11 @@ filegroup(
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["configfiles_test.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/configfiles",
|
||||
library = ":go_default_library",
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig/scheme:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig/v1beta1:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig/util/files:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig/util/test:go_default_library",
|
||||
"//pkg/util/filesystem:go_default_library",
|
||||
|
22
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/configfiles/configfiles.go
generated
vendored
22
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/configfiles/configfiles.go
generated
vendored
@ -27,8 +27,6 @@ import (
|
||||
utilfs "k8s.io/kubernetes/pkg/util/filesystem"
|
||||
)
|
||||
|
||||
const kubeletFile = "kubelet"
|
||||
|
||||
// Loader loads configuration from a storage layer
|
||||
type Loader interface {
|
||||
// Load loads and returns the KubeletConfiguration from the storage layer, or an error if a configuration could not be loaded
|
||||
@ -41,12 +39,12 @@ type fsLoader struct {
|
||||
fs utilfs.Filesystem
|
||||
// kubeletCodecs is the scheme used to decode config files
|
||||
kubeletCodecs *serializer.CodecFactory
|
||||
// configDir is the absolute path to the directory containing the configuration files
|
||||
configDir string
|
||||
// kubeletFile is an absolute path to the file containing a serialized KubeletConfiguration
|
||||
kubeletFile string
|
||||
}
|
||||
|
||||
// NewFsLoader returns a Loader that loads a KubeletConfiguration from the files in `configDir`
|
||||
func NewFsLoader(fs utilfs.Filesystem, configDir string) (Loader, error) {
|
||||
// NewFsLoader returns a Loader that loads a KubeletConfiguration from the `kubeletFile`
|
||||
func NewFsLoader(fs utilfs.Filesystem, kubeletFile string) (Loader, error) {
|
||||
_, kubeletCodecs, err := kubeletscheme.NewSchemeAndCodecs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -55,21 +53,19 @@ func NewFsLoader(fs utilfs.Filesystem, configDir string) (Loader, error) {
|
||||
return &fsLoader{
|
||||
fs: fs,
|
||||
kubeletCodecs: kubeletCodecs,
|
||||
configDir: configDir,
|
||||
kubeletFile: kubeletFile,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (loader *fsLoader) Load() (*kubeletconfig.KubeletConfiguration, error) {
|
||||
// require the config be in a file called "kubelet"
|
||||
path := filepath.Join(loader.configDir, kubeletFile)
|
||||
data, err := loader.fs.ReadFile(path)
|
||||
data, err := loader.fs.ReadFile(loader.kubeletFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read init config file %q, error: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to read kubelet config file %q, error: %v", loader.kubeletFile, err)
|
||||
}
|
||||
|
||||
// no configuration is an error, some parameters are required
|
||||
if len(data) == 0 {
|
||||
return nil, fmt.Errorf("init config file %q was empty, but some parameters are required", path)
|
||||
return nil, fmt.Errorf("kubelet config file %q was empty", loader.kubeletFile)
|
||||
}
|
||||
|
||||
kc, err := utilcodec.DecodeKubeletConfiguration(loader.kubeletCodecs, data)
|
||||
@ -78,7 +74,7 @@ func (loader *fsLoader) Load() (*kubeletconfig.KubeletConfiguration, error) {
|
||||
}
|
||||
|
||||
// make all paths absolute
|
||||
resolveRelativePaths(kubeletconfig.KubeletConfigurationPathRefs(kc), loader.configDir)
|
||||
resolveRelativePaths(kubeletconfig.KubeletConfigurationPathRefs(kc), filepath.Dir(loader.kubeletFile))
|
||||
return kc, nil
|
||||
}
|
||||
|
||||
|
29
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/configfiles/configfiles_test.go
generated
vendored
29
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/configfiles/configfiles_test.go
generated
vendored
@ -24,7 +24,7 @@ import (
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
|
||||
kubeletscheme "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme"
|
||||
kubeletconfigv1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
|
||||
kubeletconfigv1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
|
||||
utilfiles "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/files"
|
||||
utiltest "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/test"
|
||||
utilfs "k8s.io/kubernetes/pkg/util/filesystem"
|
||||
@ -32,6 +32,7 @@ import (
|
||||
|
||||
const configDir = "/test-config-dir"
|
||||
const relativePath = "relative/path/test"
|
||||
const kubeletFile = "kubelet"
|
||||
|
||||
func TestLoad(t *testing.T) {
|
||||
cases := []struct {
|
||||
@ -70,7 +71,7 @@ func TestLoad(t *testing.T) {
|
||||
// invalid object
|
||||
{
|
||||
"missing kind",
|
||||
newString(`{"apiVersion":"kubeletconfig/v1alpha1"}`),
|
||||
newString(`{"apiVersion":"kubelet.config.k8s.io/v1beta1"}`),
|
||||
nil,
|
||||
"failed to decode",
|
||||
},
|
||||
@ -82,7 +83,7 @@ func TestLoad(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"unregistered kind",
|
||||
newString(`{"kind":"BogusKind","apiVersion":"kubeletconfig/v1alpha1"}`),
|
||||
newString(`{"kind":"BogusKind","apiVersion":"kubelet.config.k8s.io/v1beta1"}`),
|
||||
nil,
|
||||
"failed to decode",
|
||||
},
|
||||
@ -97,13 +98,13 @@ func TestLoad(t *testing.T) {
|
||||
{
|
||||
"default from yaml",
|
||||
newString(`kind: KubeletConfiguration
|
||||
apiVersion: kubeletconfig/v1alpha1`),
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1`),
|
||||
newConfig(t),
|
||||
"",
|
||||
},
|
||||
{
|
||||
"default from json",
|
||||
newString(`{"kind":"KubeletConfiguration","apiVersion":"kubeletconfig/v1alpha1"}`),
|
||||
newString(`{"kind":"KubeletConfiguration","apiVersion":"kubelet.config.k8s.io/v1beta1"}`),
|
||||
newConfig(t),
|
||||
"",
|
||||
},
|
||||
@ -112,21 +113,21 @@ apiVersion: kubeletconfig/v1alpha1`),
|
||||
{
|
||||
"yaml, relative path is resolved",
|
||||
newString(fmt.Sprintf(`kind: KubeletConfiguration
|
||||
apiVersion: kubeletconfig/v1alpha1
|
||||
podManifestPath: %s`, relativePath)),
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
staticPodPath: %s`, relativePath)),
|
||||
func() *kubeletconfig.KubeletConfiguration {
|
||||
kc := newConfig(t)
|
||||
kc.PodManifestPath = filepath.Join(configDir, relativePath)
|
||||
kc.StaticPodPath = filepath.Join(configDir, relativePath)
|
||||
return kc
|
||||
}(),
|
||||
"",
|
||||
},
|
||||
{
|
||||
"json, relative path is resolved",
|
||||
newString(fmt.Sprintf(`{"kind":"KubeletConfiguration","apiVersion":"kubeletconfig/v1alpha1","podManifestPath":"%s"}`, relativePath)),
|
||||
newString(fmt.Sprintf(`{"kind":"KubeletConfiguration","apiVersion":"kubelet.config.k8s.io/v1beta1","staticPodPath":"%s"}`, relativePath)),
|
||||
func() *kubeletconfig.KubeletConfiguration {
|
||||
kc := newConfig(t)
|
||||
kc.PodManifestPath = filepath.Join(configDir, relativePath)
|
||||
kc.StaticPodPath = filepath.Join(configDir, relativePath)
|
||||
return kc
|
||||
}(),
|
||||
"",
|
||||
@ -136,12 +137,13 @@ podManifestPath: %s`, relativePath)),
|
||||
for _, c := range cases {
|
||||
t.Run(c.desc, func(t *testing.T) {
|
||||
fs := utilfs.NewFakeFs()
|
||||
path := filepath.Join(configDir, kubeletFile)
|
||||
if c.file != nil {
|
||||
if err := addFile(fs, filepath.Join(configDir, kubeletFile), *c.file); err != nil {
|
||||
if err := addFile(fs, path, *c.file); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
loader, err := NewFsLoader(fs, configDir)
|
||||
loader, err := NewFsLoader(fs, path)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@ -153,7 +155,6 @@ podManifestPath: %s`, relativePath)),
|
||||
t.Fatalf("expect %#v but got %#v", *c.expect, *kc)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,7 +203,7 @@ func newConfig(t *testing.T) *kubeletconfig.KubeletConfiguration {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
// get the built-in default configuration
|
||||
external := &kubeletconfigv1alpha1.KubeletConfiguration{}
|
||||
external := &kubeletconfigv1beta1.KubeletConfiguration{}
|
||||
kubeletScheme.Default(external)
|
||||
kc := &kubeletconfig.KubeletConfiguration{}
|
||||
err = kubeletScheme.Convert(external, kc, nil)
|
||||
|
100
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/configsync.go
generated
vendored
100
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/configsync.go
generated
vendored
@ -19,15 +19,30 @@ package kubeletconfig
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint"
|
||||
"k8s.io/kubernetes/pkg/kubelet/kubeletconfig/status"
|
||||
utillog "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/log"
|
||||
)
|
||||
|
||||
const (
|
||||
// KubeletConfigChangedEventReason identifies an event as a change of Kubelet configuration
|
||||
KubeletConfigChangedEventReason = "KubeletConfigChanged"
|
||||
// EventMessageFmt is the message format for Kubelet config change events
|
||||
EventMessageFmt = "Kubelet will restart to use: %s"
|
||||
// LocalConfigMessage is the text to apply to EventMessageFmt when the Kubelet has been configured to use its local config (init or defaults)
|
||||
LocalConfigMessage = "local config"
|
||||
)
|
||||
|
||||
// pokeConfiSourceWorker tells the worker thread that syncs config sources that work needs to be done
|
||||
func (cc *Controller) pokeConfigSourceWorker() {
|
||||
select {
|
||||
@ -37,7 +52,7 @@ func (cc *Controller) pokeConfigSourceWorker() {
|
||||
}
|
||||
|
||||
// syncConfigSource checks if work needs to be done to use a new configuration, and does that work if necessary
|
||||
func (cc *Controller) syncConfigSource(client clientset.Interface, nodeName string) {
|
||||
func (cc *Controller) syncConfigSource(client clientset.Interface, eventClient v1core.EventsGetter, nodeName string) {
|
||||
select {
|
||||
case <-cc.pendingConfigSource:
|
||||
default:
|
||||
@ -56,19 +71,28 @@ func (cc *Controller) syncConfigSource(client clientset.Interface, nodeName stri
|
||||
|
||||
node, err := latestNode(cc.informer.GetStore(), nodeName)
|
||||
if err != nil {
|
||||
cc.configOK.SetFailSyncCondition(status.FailSyncReasonInformer)
|
||||
cc.configOk.SetFailSyncCondition(status.FailSyncReasonInformer)
|
||||
syncerr = fmt.Errorf("%s, error: %v", status.FailSyncReasonInformer, err)
|
||||
return
|
||||
}
|
||||
|
||||
// check the Node and download any new config
|
||||
if updated, reason, err := cc.doSyncConfigSource(client, node.Spec.ConfigSource); err != nil {
|
||||
cc.configOK.SetFailSyncCondition(reason)
|
||||
if updated, cur, reason, err := cc.doSyncConfigSource(client, node.Spec.ConfigSource); err != nil {
|
||||
cc.configOk.SetFailSyncCondition(reason)
|
||||
syncerr = fmt.Errorf("%s, error: %v", reason, err)
|
||||
return
|
||||
} else if updated {
|
||||
// TODO(mtaufen): Consider adding a "currently restarting kubelet" ConfigOK message for this case
|
||||
utillog.Infof("config updated, Kubelet will restart to begin using new config")
|
||||
path := LocalConfigMessage
|
||||
if cur != nil {
|
||||
path = cur.APIPath()
|
||||
}
|
||||
// we directly log and send the event, instead of using the event recorder,
|
||||
// because the event recorder won't flush its queue before we exit (we'd lose the event)
|
||||
event := eventf(nodeName, apiv1.EventTypeNormal, KubeletConfigChangedEventReason, EventMessageFmt, path)
|
||||
glog.V(3).Infof("Event(%#v): type: '%v' reason: '%v' %v", event.InvolvedObject, event.Type, event.Reason, event.Message)
|
||||
if _, err := eventClient.Events(apiv1.NamespaceDefault).Create(event); err != nil {
|
||||
utillog.Errorf("failed to send event, error: %v", err)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
@ -76,36 +100,36 @@ func (cc *Controller) syncConfigSource(client clientset.Interface, nodeName stri
|
||||
// - there is no need to restart to update the current config
|
||||
// - there was no error trying to sync configuration
|
||||
// - if, previously, there was an error trying to sync configuration, we need to clear that error from the condition
|
||||
cc.configOK.ClearFailSyncCondition()
|
||||
cc.configOk.ClearFailSyncCondition()
|
||||
}
|
||||
|
||||
// doSyncConfigSource checkpoints and sets the store's current config to the new config or resets config,
|
||||
// depending on the `source`, and returns whether the current config in the checkpoint store was updated as a result
|
||||
func (cc *Controller) doSyncConfigSource(client clientset.Interface, source *apiv1.NodeConfigSource) (bool, string, error) {
|
||||
func (cc *Controller) doSyncConfigSource(client clientset.Interface, source *apiv1.NodeConfigSource) (bool, checkpoint.RemoteConfigSource, string, error) {
|
||||
if source == nil {
|
||||
utillog.Infof("Node.Spec.ConfigSource is empty, will reset current and last-known-good to defaults")
|
||||
updated, reason, err := cc.resetConfig()
|
||||
if err != nil {
|
||||
return false, reason, err
|
||||
return false, nil, reason, err
|
||||
}
|
||||
return updated, "", nil
|
||||
return updated, nil, "", nil
|
||||
}
|
||||
|
||||
// if the NodeConfigSource is non-nil, download the config
|
||||
utillog.Infof("Node.Spec.ConfigSource is non-empty, will checkpoint source and update config if necessary")
|
||||
remote, reason, err := checkpoint.NewRemoteConfigSource(source)
|
||||
if err != nil {
|
||||
return false, reason, err
|
||||
return false, nil, reason, err
|
||||
}
|
||||
reason, err = cc.checkpointConfigSource(client, remote)
|
||||
if err != nil {
|
||||
return false, reason, err
|
||||
return false, nil, reason, err
|
||||
}
|
||||
updated, reason, err := cc.setCurrentConfig(remote)
|
||||
if err != nil {
|
||||
return false, reason, err
|
||||
return false, nil, reason, err
|
||||
}
|
||||
return updated, "", nil
|
||||
return updated, remote, "", nil
|
||||
}
|
||||
|
||||
// checkpointConfigSource downloads and checkpoints the object referred to by `source` if the checkpoint does not already exist,
|
||||
@ -115,7 +139,7 @@ func (cc *Controller) checkpointConfigSource(client clientset.Interface, source
|
||||
|
||||
// if the checkpoint already exists, skip downloading
|
||||
if ok, err := cc.checkpointStore.Exists(uid); err != nil {
|
||||
reason := fmt.Sprintf(status.FailSyncReasonCheckpointExistenceFmt, uid)
|
||||
reason := fmt.Sprintf(status.FailSyncReasonCheckpointExistenceFmt, source.APIPath(), uid)
|
||||
return reason, fmt.Errorf("%s, error: %v", reason, err)
|
||||
} else if ok {
|
||||
utillog.Infof("checkpoint already exists for object with UID %q, skipping download", uid)
|
||||
@ -131,7 +155,7 @@ func (cc *Controller) checkpointConfigSource(client clientset.Interface, source
|
||||
// save
|
||||
err = cc.checkpointStore.Save(checkpoint)
|
||||
if err != nil {
|
||||
reason := fmt.Sprintf(status.FailSyncReasonSaveCheckpointFmt, checkpoint.UID())
|
||||
reason := fmt.Sprintf(status.FailSyncReasonSaveCheckpointFmt, source.APIPath(), checkpoint.UID())
|
||||
return reason, fmt.Errorf("%s, error: %v", reason, err)
|
||||
}
|
||||
|
||||
@ -144,9 +168,9 @@ func (cc *Controller) setCurrentConfig(source checkpoint.RemoteConfigSource) (bo
|
||||
updated, err := cc.checkpointStore.SetCurrentUpdated(source)
|
||||
if err != nil {
|
||||
if source == nil {
|
||||
return false, status.FailSyncReasonSetCurrentDefault, err
|
||||
return false, status.FailSyncReasonSetCurrentLocal, err
|
||||
}
|
||||
return false, fmt.Sprintf(status.FailSyncReasonSetCurrentUIDFmt, source.UID()), err
|
||||
return false, fmt.Sprintf(status.FailSyncReasonSetCurrentUIDFmt, source.APIPath(), source.UID()), err
|
||||
}
|
||||
return updated, "", nil
|
||||
}
|
||||
@ -181,3 +205,43 @@ func latestNode(store cache.Store, nodeName string) (*apiv1.Node, error) {
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// eventf constructs and returns an event containing a formatted message
|
||||
// similar to k8s.io/client-go/tools/record/event.go
|
||||
func eventf(nodeName, eventType, reason, messageFmt string, args ...interface{}) *apiv1.Event {
|
||||
return makeEvent(nodeName, eventType, reason, fmt.Sprintf(messageFmt, args...))
|
||||
}
|
||||
|
||||
// makeEvent constructs an event
|
||||
// similar to makeEvent in k8s.io/client-go/tools/record/event.go
|
||||
func makeEvent(nodeName, eventtype, reason, message string) *apiv1.Event {
|
||||
const componentKubelet = "kubelet"
|
||||
// NOTE(mtaufen): This is consistent with pkg/kubelet/kubelet.go. Even though setting the node
|
||||
// name as the UID looks strange, it appears to be conventional for events sent by the Kubelet.
|
||||
ref := apiv1.ObjectReference{
|
||||
Kind: "Node",
|
||||
Name: nodeName,
|
||||
UID: types.UID(nodeName),
|
||||
Namespace: "",
|
||||
}
|
||||
|
||||
t := metav1.Time{Time: time.Now()}
|
||||
namespace := ref.Namespace
|
||||
if namespace == "" {
|
||||
namespace = metav1.NamespaceDefault
|
||||
}
|
||||
return &apiv1.Event{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("%v.%x", ref.Name, t.UnixNano()),
|
||||
Namespace: namespace,
|
||||
},
|
||||
InvolvedObject: ref,
|
||||
Reason: reason,
|
||||
Message: message,
|
||||
FirstTimestamp: t,
|
||||
LastTimestamp: t,
|
||||
Count: 1,
|
||||
Type: eventtype,
|
||||
Source: apiv1.EventSource{Component: componentKubelet, Host: string(nodeName)},
|
||||
}
|
||||
}
|
||||
|
306
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/controller.go
generated
vendored
306
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/controller.go
generated
vendored
@ -24,12 +24,13 @@ import (
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/validation"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint"
|
||||
"k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint/store"
|
||||
"k8s.io/kubernetes/pkg/kubelet/kubeletconfig/configfiles"
|
||||
"k8s.io/kubernetes/pkg/kubelet/kubeletconfig/status"
|
||||
utillog "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/log"
|
||||
utilpanic "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/panic"
|
||||
@ -38,34 +39,22 @@ import (
|
||||
|
||||
const (
|
||||
checkpointsDir = "checkpoints"
|
||||
initConfigDir = "init"
|
||||
// TODO(mtaufen): We may expose this in a future API, but for the time being we use an internal default,
|
||||
// because it is not especially clear where this should live in the API.
|
||||
configTrialDuration = 10 * time.Minute
|
||||
)
|
||||
|
||||
// Controller is the controller which, among other things:
|
||||
// - loads configuration from disk
|
||||
// - checkpoints configuration to disk
|
||||
// - downloads new configuration from the API server
|
||||
// - validates configuration
|
||||
// - tracks the last-known-good configuration, and rolls-back to last-known-good when necessary
|
||||
// Controller manages syncing dynamic Kubelet configurations
|
||||
// For more information, see the proposal: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/dynamic-kubelet-configuration.md
|
||||
type Controller struct {
|
||||
// dynamicConfig, if true, indicates that we should sync config from the API server
|
||||
dynamicConfig bool
|
||||
|
||||
// defaultConfig is the configuration to use if no initConfig is provided
|
||||
defaultConfig *kubeletconfig.KubeletConfiguration
|
||||
|
||||
// initConfig is the unmarshaled init config, this will be loaded by the Controller if an initConfigDir is provided
|
||||
initConfig *kubeletconfig.KubeletConfiguration
|
||||
|
||||
// initLoader is for loading the Kubelet's init configuration files from disk
|
||||
initLoader configfiles.Loader
|
||||
|
||||
// pendingConfigSource; write to this channel to indicate that the config source needs to be synced from the API server
|
||||
pendingConfigSource chan bool
|
||||
|
||||
// configOK manages the ConfigOK condition that is reported in Node.Status.Conditions
|
||||
configOK status.ConfigOKCondition
|
||||
// configOk manages the KubeletConfigOk condition that is reported in Node.Status.Conditions
|
||||
configOk status.ConfigOkCondition
|
||||
|
||||
// informer is the informer that watches the Node object
|
||||
informer cache.SharedInformer
|
||||
@ -75,37 +64,14 @@ type Controller struct {
|
||||
}
|
||||
|
||||
// NewController constructs a new Controller object and returns it. Directory paths must be absolute.
|
||||
// If the `initConfigDir` is an empty string, skips trying to load the init config.
|
||||
// If the `dynamicConfigDir` is an empty string, skips trying to load checkpoints or download new config,
|
||||
// but will still sync the ConfigOK condition if you call StartSync with a non-nil client.
|
||||
func NewController(defaultConfig *kubeletconfig.KubeletConfiguration,
|
||||
initConfigDir string,
|
||||
dynamicConfigDir string) (*Controller, error) {
|
||||
var err error
|
||||
|
||||
fs := utilfs.DefaultFs{}
|
||||
|
||||
var initLoader configfiles.Loader
|
||||
if len(initConfigDir) > 0 {
|
||||
initLoader, err = configfiles.NewFsLoader(fs, initConfigDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dynamicConfig := false
|
||||
if len(dynamicConfigDir) > 0 {
|
||||
dynamicConfig = true
|
||||
}
|
||||
|
||||
func NewController(defaultConfig *kubeletconfig.KubeletConfiguration, dynamicConfigDir string) *Controller {
|
||||
return &Controller{
|
||||
dynamicConfig: dynamicConfig,
|
||||
defaultConfig: defaultConfig,
|
||||
// channels must have capacity at least 1, since we signal with non-blocking writes
|
||||
pendingConfigSource: make(chan bool, 1),
|
||||
configOK: status.NewConfigOKCondition(),
|
||||
checkpointStore: store.NewFsStore(fs, filepath.Join(dynamicConfigDir, checkpointsDir)),
|
||||
initLoader: initLoader,
|
||||
}, nil
|
||||
configOk: status.NewConfigOkCondition(),
|
||||
checkpointStore: store.NewFsStore(utilfs.DefaultFs{}, filepath.Join(dynamicConfigDir, checkpointsDir)),
|
||||
}
|
||||
}
|
||||
|
||||
// Bootstrap attempts to return a valid KubeletConfiguration based on the configuration of the Controller,
|
||||
@ -113,95 +79,65 @@ func NewController(defaultConfig *kubeletconfig.KubeletConfiguration,
|
||||
func (cc *Controller) Bootstrap() (*kubeletconfig.KubeletConfiguration, error) {
|
||||
utillog.Infof("starting controller")
|
||||
|
||||
// ALWAYS validate the local (default and init) configs. This makes incorrectly provisioned nodes an error.
|
||||
// These must be valid because they are the foundational last-known-good configs.
|
||||
utillog.Infof("validating combination of defaults and flags")
|
||||
// ALWAYS validate the local config. This makes incorrectly provisioned nodes an error.
|
||||
// It must be valid because it is the default last-known-good config.
|
||||
utillog.Infof("validating local config")
|
||||
if err := validation.ValidateKubeletConfiguration(cc.defaultConfig); err != nil {
|
||||
return nil, fmt.Errorf("combination of defaults and flags failed validation, error: %v", err)
|
||||
}
|
||||
// only attempt to load and validate the init config if the user provided a path
|
||||
if cc.initLoader != nil {
|
||||
utillog.Infof("loading init config")
|
||||
kc, err := cc.initLoader.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// validate the init config
|
||||
utillog.Infof("validating init config")
|
||||
if err := validation.ValidateKubeletConfiguration(kc); err != nil {
|
||||
return nil, fmt.Errorf("failed to validate the init config, error: %v", err)
|
||||
}
|
||||
cc.initConfig = kc
|
||||
}
|
||||
// Assert: the default and init configs are both valid
|
||||
|
||||
// if dynamic config is disabled, skip trying to load any checkpoints because they won't exist
|
||||
if !cc.dynamicConfig {
|
||||
return cc.localConfig(), nil
|
||||
return nil, fmt.Errorf("local config failed validation, error: %v", err)
|
||||
}
|
||||
|
||||
// assert: now we know that a dynamicConfigDir was provided, and we can rely on that existing
|
||||
|
||||
// make sure the filesystem is set up properly
|
||||
// TODO(mtaufen): rename this to initializeDynamicConfigDir
|
||||
if err := cc.initialize(); err != nil {
|
||||
// ensure the filesystem is initialized
|
||||
if err := cc.initializeDynamicConfigDir(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// determine UID of the current config source
|
||||
curUID := ""
|
||||
if curSource, err := cc.checkpointStore.Current(); err != nil {
|
||||
return nil, err
|
||||
} else if curSource != nil {
|
||||
curUID = curSource.UID()
|
||||
}
|
||||
assigned, curSource, reason, err := cc.loadAssignedConfig(cc.defaultConfig)
|
||||
if err == nil {
|
||||
// set the status to indicate we will use the assigned config
|
||||
if curSource != nil {
|
||||
cc.configOk.Set(fmt.Sprintf(status.CurRemoteMessageFmt, curSource.APIPath()), reason, apiv1.ConditionTrue)
|
||||
} else {
|
||||
cc.configOk.Set(status.CurLocalMessage, reason, apiv1.ConditionTrue)
|
||||
}
|
||||
|
||||
// if curUID indicates the local config should be used, return the correct one of those
|
||||
if len(curUID) == 0 {
|
||||
return cc.localConfig(), nil
|
||||
} // Assert: we will not use the local configurations, unless we roll back to lkg; curUID is non-empty
|
||||
// update the last-known-good config if necessary, and start a timer that
|
||||
// periodically checks whether the last-known good needs to be updated
|
||||
// we only do this when the assigned config loads and passes validation
|
||||
// wait.Forever will call the func once before starting the timer
|
||||
go wait.Forever(func() { cc.checkTrial(configTrialDuration) }, 10*time.Second)
|
||||
|
||||
// TODO(mtaufen): consider re-verifying integrity and re-attempting download when a load/verify/parse/validate
|
||||
return assigned, nil
|
||||
} // Assert: the assigned config failed to load, parse, or validate
|
||||
|
||||
// TODO(mtaufen): consider re-attempting download when a load/verify/parse/validate
|
||||
// error happens outside trial period, we already made it past the trial so it's probably filesystem corruption
|
||||
// or something else scary (unless someone is using a 0-length trial period)
|
||||
// load from checkpoint
|
||||
|
||||
// load the current config
|
||||
checkpoint, err := cc.checkpointStore.Load(curUID)
|
||||
// log the reason and error details for the failure to load the assigned config
|
||||
utillog.Errorf(fmt.Sprintf("%s, error: %v", reason, err))
|
||||
|
||||
// load the last-known-good config
|
||||
lkg, lkgSource, err := cc.loadLastKnownGoodConfig(cc.defaultConfig)
|
||||
if err != nil {
|
||||
// TODO(mtaufen): rollback for now, but this could reasonably be handled by re-attempting a download,
|
||||
// it probably indicates some sort of corruption
|
||||
return cc.lkgRollback(fmt.Sprintf(status.CurFailLoadReasonFmt, curUID), fmt.Sprintf("error: %v", err))
|
||||
}
|
||||
|
||||
// parse the checkpoint into a KubeletConfiguration
|
||||
cur, err := checkpoint.Parse()
|
||||
if err != nil {
|
||||
return cc.lkgRollback(fmt.Sprintf(status.CurFailParseReasonFmt, curUID), fmt.Sprintf("error: %v", err))
|
||||
}
|
||||
|
||||
// validate current config
|
||||
if err := validation.ValidateKubeletConfiguration(cur); err != nil {
|
||||
return cc.lkgRollback(fmt.Sprintf(status.CurFailValidateReasonFmt, curUID), fmt.Sprintf("error: %v", err))
|
||||
}
|
||||
|
||||
// when the trial period is over, the current config becomes the last-known-good
|
||||
if trial, err := cc.inTrial(cur.ConfigTrialDuration.Duration); err != nil {
|
||||
return nil, err
|
||||
} else if !trial {
|
||||
if err := cc.graduateCurrentToLastKnownGood(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// update the status to note that we will use the current config
|
||||
cc.configOK.Set(fmt.Sprintf(status.CurRemoteMessageFmt, curUID), status.CurRemoteOKReason, apiv1.ConditionTrue)
|
||||
return cur, nil
|
||||
// set the status to indicate that we had to roll back to the lkg for the reason reported when we tried to load the assigned config
|
||||
if lkgSource != nil {
|
||||
cc.configOk.Set(fmt.Sprintf(status.LkgRemoteMessageFmt, lkgSource.APIPath()), reason, apiv1.ConditionFalse)
|
||||
} else {
|
||||
cc.configOk.Set(status.LkgLocalMessage, reason, apiv1.ConditionFalse)
|
||||
}
|
||||
|
||||
// return the last-known-good config
|
||||
return lkg, nil
|
||||
}
|
||||
|
||||
// StartSync launches the controller's sync loops if `client` is non-nil and `nodeName` is non-empty.
|
||||
// It will always start the Node condition reporting loop, and will also start the dynamic conifg sync loops
|
||||
// if dynamic config is enabled on the controller. If `nodeName` is empty but `client` is non-nil, an error is logged.
|
||||
func (cc *Controller) StartSync(client clientset.Interface, nodeName string) {
|
||||
func (cc *Controller) StartSync(client clientset.Interface, eventClient v1core.EventsGetter, nodeName string) {
|
||||
if client == nil {
|
||||
utillog.Infof("nil client, will not start sync loops")
|
||||
return
|
||||
@ -210,56 +146,114 @@ func (cc *Controller) StartSync(client clientset.Interface, nodeName string) {
|
||||
return
|
||||
}
|
||||
|
||||
// start the ConfigOK condition sync loop
|
||||
// start the ConfigOk condition sync loop
|
||||
go utilpanic.HandlePanic(func() {
|
||||
utillog.Infof("starting ConfigOK condition sync loop")
|
||||
utillog.Infof("starting ConfigOk condition sync loop")
|
||||
wait.JitterUntil(func() {
|
||||
cc.configOK.Sync(client, nodeName)
|
||||
cc.configOk.Sync(client, nodeName)
|
||||
}, 10*time.Second, 0.2, true, wait.NeverStop)
|
||||
})()
|
||||
|
||||
// only sync to new, remotely provided configurations if dynamic config was enabled
|
||||
if cc.dynamicConfig {
|
||||
cc.informer = newSharedNodeInformer(client, nodeName,
|
||||
cc.onAddNodeEvent, cc.onUpdateNodeEvent, cc.onDeleteNodeEvent)
|
||||
// start the informer loop
|
||||
// Rather than use utilruntime.HandleCrash, which doesn't actually crash in the Kubelet,
|
||||
// we use HandlePanic to manually call the panic handlers and then crash.
|
||||
// We have a better chance of recovering normal operation if we just restart the Kubelet in the event
|
||||
// of a Go runtime error.
|
||||
go utilpanic.HandlePanic(func() {
|
||||
utillog.Infof("starting Node informer sync loop")
|
||||
cc.informer.Run(wait.NeverStop)
|
||||
})()
|
||||
cc.informer = newSharedNodeInformer(client, nodeName,
|
||||
cc.onAddNodeEvent, cc.onUpdateNodeEvent, cc.onDeleteNodeEvent)
|
||||
// start the informer loop
|
||||
// Rather than use utilruntime.HandleCrash, which doesn't actually crash in the Kubelet,
|
||||
// we use HandlePanic to manually call the panic handlers and then crash.
|
||||
// We have a better chance of recovering normal operation if we just restart the Kubelet in the event
|
||||
// of a Go runtime error.
|
||||
go utilpanic.HandlePanic(func() {
|
||||
utillog.Infof("starting Node informer sync loop")
|
||||
cc.informer.Run(wait.NeverStop)
|
||||
})()
|
||||
|
||||
// start the config source sync loop
|
||||
go utilpanic.HandlePanic(func() {
|
||||
utillog.Infof("starting config source sync loop")
|
||||
wait.JitterUntil(func() {
|
||||
cc.syncConfigSource(client, eventClient, nodeName)
|
||||
}, 10*time.Second, 0.2, true, wait.NeverStop)
|
||||
})()
|
||||
|
||||
// start the config source sync loop
|
||||
go utilpanic.HandlePanic(func() {
|
||||
utillog.Infof("starting config source sync loop")
|
||||
wait.JitterUntil(func() {
|
||||
cc.syncConfigSource(client, nodeName)
|
||||
}, 10*time.Second, 0.2, true, wait.NeverStop)
|
||||
})()
|
||||
} else {
|
||||
utillog.Infof("dynamic config not enabled, will not sync to remote config")
|
||||
}
|
||||
}
|
||||
|
||||
// initialize makes sure that the storage layers for various controller components are set up correctly
|
||||
func (cc *Controller) initialize() error {
|
||||
// loadAssignedConfig loads the Kubelet's currently assigned config,
|
||||
// based on the setting in the local checkpoint store.
|
||||
// It returns the loaded configuration, the checkpoint store's config source record,
|
||||
// a clean success or failure reason that can be reported in the status, and any error that occurs.
|
||||
// If the local config should be used, it will be returned. You should validate local before passing it to this function.
|
||||
func (cc *Controller) loadAssignedConfig(local *kubeletconfig.KubeletConfiguration) (*kubeletconfig.KubeletConfiguration, checkpoint.RemoteConfigSource, string, error) {
|
||||
src, err := cc.checkpointStore.Current()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Sprintf(status.CurFailLoadReasonFmt, "unknown"), err
|
||||
}
|
||||
// nil source is the signal to use the local config
|
||||
if src == nil {
|
||||
return local, src, status.CurLocalOkayReason, nil
|
||||
}
|
||||
curUID := src.UID()
|
||||
// load from checkpoint
|
||||
checkpoint, err := cc.checkpointStore.Load(curUID)
|
||||
if err != nil {
|
||||
return nil, src, fmt.Sprintf(status.CurFailLoadReasonFmt, src.APIPath()), err
|
||||
}
|
||||
cur, err := checkpoint.Parse()
|
||||
if err != nil {
|
||||
return nil, src, fmt.Sprintf(status.CurFailParseReasonFmt, src.APIPath()), err
|
||||
}
|
||||
if err := validation.ValidateKubeletConfiguration(cur); err != nil {
|
||||
return nil, src, fmt.Sprintf(status.CurFailValidateReasonFmt, src.APIPath()), err
|
||||
}
|
||||
return cur, src, status.CurRemoteOkayReason, nil
|
||||
}
|
||||
|
||||
// loadLastKnownGoodConfig loads the Kubelet's last-known-good config,
|
||||
// based on the setting in the local checkpoint store.
|
||||
// It returns the loaded configuration, the checkpoint store's config source record,
|
||||
// and any error that occurs.
|
||||
// If the local config should be used, it will be returned. You should validate local before passing it to this function.
|
||||
func (cc *Controller) loadLastKnownGoodConfig(local *kubeletconfig.KubeletConfiguration) (*kubeletconfig.KubeletConfiguration, checkpoint.RemoteConfigSource, error) {
|
||||
src, err := cc.checkpointStore.LastKnownGood()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to determine last-known-good config, error: %v", err)
|
||||
}
|
||||
// nil source is the signal to use the local config
|
||||
if src == nil {
|
||||
return local, src, nil
|
||||
}
|
||||
lkgUID := src.UID()
|
||||
// load from checkpoint
|
||||
checkpoint, err := cc.checkpointStore.Load(lkgUID)
|
||||
if err != nil {
|
||||
return nil, src, fmt.Errorf("%s, error: %v", fmt.Sprintf(status.LkgFailLoadReasonFmt, src.APIPath()), err)
|
||||
}
|
||||
lkg, err := checkpoint.Parse()
|
||||
if err != nil {
|
||||
return nil, src, fmt.Errorf("%s, error: %v", fmt.Sprintf(status.LkgFailParseReasonFmt, src.APIPath()), err)
|
||||
}
|
||||
if err := validation.ValidateKubeletConfiguration(lkg); err != nil {
|
||||
return nil, src, fmt.Errorf("%s, error: %v", fmt.Sprintf(status.LkgFailValidateReasonFmt, src.APIPath()), err)
|
||||
}
|
||||
return lkg, src, nil
|
||||
}
|
||||
|
||||
// initializeDynamicConfigDir makes sure that the storage layers for various controller components are set up correctly
|
||||
func (cc *Controller) initializeDynamicConfigDir() error {
|
||||
utillog.Infof("ensuring filesystem is set up correctly")
|
||||
// initialize local checkpoint storage location
|
||||
// initializeDynamicConfigDir local checkpoint storage location
|
||||
return cc.checkpointStore.Initialize()
|
||||
}
|
||||
|
||||
// localConfig returns the initConfig if it is loaded, otherwise returns the defaultConfig.
|
||||
// It also sets the local configOK condition to match the returned config.
|
||||
func (cc *Controller) localConfig() *kubeletconfig.KubeletConfiguration {
|
||||
if cc.initConfig != nil {
|
||||
cc.configOK.Set(status.CurInitMessage, status.CurInitOKReason, apiv1.ConditionTrue)
|
||||
return cc.initConfig
|
||||
// checkTrial checks whether the trial duration has passed, and updates the last-known-good config if necessary
|
||||
func (cc *Controller) checkTrial(duration time.Duration) {
|
||||
// when the trial period is over, the assigned config becomes the last-known-good
|
||||
if trial, err := cc.inTrial(duration); err != nil {
|
||||
utillog.Errorf("failed to check trial period for assigned config, error: %v", err)
|
||||
} else if !trial {
|
||||
utillog.Infof("assigned config passed trial period, will set as last-known-good")
|
||||
if err := cc.graduateAssignedToLastKnownGood(); err != nil {
|
||||
utillog.Errorf("failed to set last-known-good to assigned config, error: %v", err)
|
||||
}
|
||||
}
|
||||
cc.configOK.Set(status.CurDefaultMessage, status.CurDefaultOKReason, apiv1.ConditionTrue)
|
||||
return cc.defaultConfig
|
||||
}
|
||||
|
||||
// inTrial returns true if the time elapsed since the last modification of the current config does not exceed `trialDur`, false otherwise
|
||||
@ -275,16 +269,16 @@ func (cc *Controller) inTrial(trialDur time.Duration) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// graduateCurrentToLastKnownGood sets the last-known-good UID on the checkpointStore
|
||||
// graduateAssignedToLastKnownGood sets the last-known-good UID on the checkpointStore
|
||||
// to the same value as the current UID maintained by the checkpointStore
|
||||
func (cc *Controller) graduateCurrentToLastKnownGood() error {
|
||||
func (cc *Controller) graduateAssignedToLastKnownGood() error {
|
||||
curUID, err := cc.checkpointStore.Current()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not graduate last-known-good config to current config, error: %v", err)
|
||||
return err
|
||||
}
|
||||
err = cc.checkpointStore.SetLastKnownGood(curUID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not graduate last-known-good config to current config, error: %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
70
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/rollback.go
generated
vendored
70
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/rollback.go
generated
vendored
@ -1,70 +0,0 @@
|
||||
/*
|
||||
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 kubeletconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/validation"
|
||||
"k8s.io/kubernetes/pkg/kubelet/kubeletconfig/status"
|
||||
utillog "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/log"
|
||||
)
|
||||
|
||||
// lkgRollback returns a valid last-known-good configuration, and updates the `cc.configOK` condition
|
||||
// regarding the `reason` for the rollback, or returns an error if a valid last-known-good could not be produced
|
||||
func (cc *Controller) lkgRollback(reason, detail string) (*kubeletconfig.KubeletConfiguration, error) {
|
||||
utillog.Errorf(fmt.Sprintf("%s, %s", reason, detail))
|
||||
|
||||
lkgUID := ""
|
||||
if lkgSource, err := cc.checkpointStore.LastKnownGood(); err != nil {
|
||||
return nil, fmt.Errorf("unable to determine last-known-good config, error: %v", err)
|
||||
} else if lkgSource != nil {
|
||||
lkgUID = lkgSource.UID()
|
||||
}
|
||||
|
||||
// if lkgUID indicates the default should be used, return initConfig or defaultConfig
|
||||
if len(lkgUID) == 0 {
|
||||
if cc.initConfig != nil {
|
||||
cc.configOK.Set(status.LkgInitMessage, reason, apiv1.ConditionFalse)
|
||||
return cc.initConfig, nil
|
||||
}
|
||||
cc.configOK.Set(status.LkgDefaultMessage, reason, apiv1.ConditionFalse)
|
||||
return cc.defaultConfig, nil
|
||||
}
|
||||
|
||||
// load
|
||||
checkpoint, err := cc.checkpointStore.Load(lkgUID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s, error: %v", fmt.Sprintf(status.LkgFailLoadReasonFmt, lkgUID), err)
|
||||
}
|
||||
|
||||
// parse
|
||||
lkg, err := checkpoint.Parse()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s, error: %v", fmt.Sprintf(status.LkgFailParseReasonFmt, lkgUID), err)
|
||||
}
|
||||
|
||||
// validate
|
||||
if err := validation.ValidateKubeletConfiguration(lkg); err != nil {
|
||||
return nil, fmt.Errorf("%s, error: %v", fmt.Sprintf(status.LkgFailValidateReasonFmt, lkgUID), err)
|
||||
}
|
||||
|
||||
cc.configOK.Set(fmt.Sprintf(status.LkgRemoteMessageFmt, lkgUID), reason, apiv1.ConditionFalse)
|
||||
return lkg, nil
|
||||
}
|
183
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/status/status.go
generated
vendored
183
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/status/status.go
generated
vendored
@ -32,46 +32,38 @@ import (
|
||||
utillog "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/log"
|
||||
)
|
||||
|
||||
// TODO(mtaufen): s/current/assigned, as this is more accurate e.g. if you are using lkg, you aren't currently using "current" :)
|
||||
const (
|
||||
// CurDefaultMessage indicates the Kubelet is using it's current config, which is the default
|
||||
CurDefaultMessage = "using current (default)"
|
||||
// LkgDefaultMessage indicates the Kubelet is using it's last-known-good config, which is the default
|
||||
LkgDefaultMessage = "using last-known-good (default)"
|
||||
// CurLocalMessage indicates that the Kubelet is using its local config, which consists of defaults, flags, and/or local files
|
||||
CurLocalMessage = "using current: local"
|
||||
// LkgLocalMessage indicates that the Kubelet is using its local config, which consists of defaults, flags, and/or local files
|
||||
LkgLocalMessage = "using last-known-good: local"
|
||||
|
||||
// CurInitMessage indicates the Kubelet is using it's current config, which is from the init config files
|
||||
CurInitMessage = "using current (init)"
|
||||
// LkgInitMessage indicates the Kubelet is using it's last-known-good config, which is from the init config files
|
||||
LkgInitMessage = "using last-known-good (init)"
|
||||
// CurRemoteMessageFmt indicates the Kubelet is using its current config, which is from an API source
|
||||
CurRemoteMessageFmt = "using current: %s"
|
||||
// LkgRemoteMessageFmt indicates the Kubelet is using its last-known-good config, which is from an API source
|
||||
LkgRemoteMessageFmt = "using last-known-good: %s"
|
||||
|
||||
// CurRemoteMessageFmt indicates the Kubelet is usin it's current config, which is from an API source
|
||||
CurRemoteMessageFmt = "using current (UID: %q)"
|
||||
// LkgRemoteMessageFmt indicates the Kubelet is using it's last-known-good config, which is from an API source
|
||||
LkgRemoteMessageFmt = "using last-known-good (UID: %q)"
|
||||
|
||||
// CurDefaultOKReason indicates that no init config files were provided
|
||||
CurDefaultOKReason = "current is set to the local default, and no init config was provided"
|
||||
// CurInitOKReason indicates that init config files were provided
|
||||
CurInitOKReason = "current is set to the local default, and an init config was provided"
|
||||
// CurRemoteOKReason indicates that the config referenced by Node.ConfigSource is currently passing all checks
|
||||
CurRemoteOKReason = "passing all checks"
|
||||
// CurLocalOkayReason indicates that the Kubelet is using its local config
|
||||
CurLocalOkayReason = "when the config source is nil, the Kubelet uses its local config"
|
||||
// CurRemoteOkayReason indicates that the config referenced by Node.ConfigSource is currently passing all checks
|
||||
CurRemoteOkayReason = "passing all checks"
|
||||
|
||||
// CurFailLoadReasonFmt indicates that the Kubelet failed to load the current config checkpoint for an API source
|
||||
CurFailLoadReasonFmt = "failed to load current (UID: %q)"
|
||||
CurFailLoadReasonFmt = "failed to load current: %s"
|
||||
// CurFailParseReasonFmt indicates that the Kubelet failed to parse the current config checkpoint for an API source
|
||||
CurFailParseReasonFmt = "failed to parse current (UID: %q)"
|
||||
CurFailParseReasonFmt = "failed to parse current: %s"
|
||||
// CurFailValidateReasonFmt indicates that the Kubelet failed to validate the current config checkpoint for an API source
|
||||
CurFailValidateReasonFmt = "failed to validate current (UID: %q)"
|
||||
// CurFailCrashLoopReasonFmt indicates that the Kubelet experienced a crash loop while using the current config checkpoint for an API source
|
||||
CurFailCrashLoopReasonFmt = "current failed trial period due to crash loop (UID: %q)"
|
||||
CurFailValidateReasonFmt = "failed to validate current: %s"
|
||||
|
||||
// LkgFail*ReasonFmt reasons are currently used to print errors in the Kubelet log, but do not appear in Node.Status.Conditions
|
||||
|
||||
// LkgFailLoadReasonFmt indicates that the Kubelet failed to load the last-known-good config checkpoint for an API source
|
||||
LkgFailLoadReasonFmt = "failed to load last-known-good (UID: %q)"
|
||||
LkgFailLoadReasonFmt = "failed to load last-known-good: %s"
|
||||
// LkgFailParseReasonFmt indicates that the Kubelet failed to parse the last-known-good config checkpoint for an API source
|
||||
LkgFailParseReasonFmt = "failed to parse last-known-good (UID: %q)"
|
||||
LkgFailParseReasonFmt = "failed to parse last-known-good: %s"
|
||||
// LkgFailValidateReasonFmt indicates that the Kubelet failed to validate the last-known-good config checkpoint for an API source
|
||||
LkgFailValidateReasonFmt = "failed to validate last-known-good (UID: %q)"
|
||||
LkgFailValidateReasonFmt = "failed to validate last-known-good: %s"
|
||||
|
||||
// FailSyncReasonFmt is used when the system couldn't sync the config, due to a malformed Node.Spec.ConfigSource, a download failure, etc.
|
||||
FailSyncReasonFmt = "failed to sync, reason: %s"
|
||||
@ -81,21 +73,21 @@ const (
|
||||
FailSyncReasonPartialObjectReference = "invalid ObjectReference, all of UID, Name, and Namespace must be specified"
|
||||
// FailSyncReasonUIDMismatchFmt is used when there is a UID mismatch between the referenced and downloaded ConfigMaps,
|
||||
// this can happen because objects must be downloaded by namespace/name, rather than by UID
|
||||
FailSyncReasonUIDMismatchFmt = "invalid ObjectReference, UID %q does not match UID of downloaded ConfigMap %q"
|
||||
FailSyncReasonUIDMismatchFmt = "invalid ConfigSource.ConfigMapRef.UID: %s does not match %s.UID: %s"
|
||||
// FailSyncReasonDownloadFmt is used when the download fails, e.g. due to network issues
|
||||
FailSyncReasonDownloadFmt = "failed to download ConfigMap with name %q from namespace %q"
|
||||
FailSyncReasonDownloadFmt = "failed to download: %s"
|
||||
// FailSyncReasonInformer is used when the informer fails to report the Node object
|
||||
FailSyncReasonInformer = "failed to read Node from informer object cache"
|
||||
// FailSyncReasonReset is used when we can't reset the local configuration references, e.g. due to filesystem issues
|
||||
FailSyncReasonReset = "failed to reset to local (default or init) config"
|
||||
FailSyncReasonReset = "failed to reset to local config"
|
||||
// FailSyncReasonCheckpointExistenceFmt is used when we can't determine if a checkpoint already exists, e.g. due to filesystem issues
|
||||
FailSyncReasonCheckpointExistenceFmt = "failed to determine whether object with UID %q was already checkpointed"
|
||||
FailSyncReasonCheckpointExistenceFmt = "failed to determine whether object %s with UID %s was already checkpointed"
|
||||
// FailSyncReasonSaveCheckpointFmt is used when we can't save a checkpoint, e.g. due to filesystem issues
|
||||
FailSyncReasonSaveCheckpointFmt = "failed to save config checkpoint for object with UID %q"
|
||||
FailSyncReasonSaveCheckpointFmt = "failed to save config checkpoint for object %s with UID %s"
|
||||
// FailSyncReasonSetCurrentDefault is used when we can't set the current config checkpoint to the local default, e.g. due to filesystem issues
|
||||
FailSyncReasonSetCurrentDefault = "failed to set current config checkpoint to default"
|
||||
FailSyncReasonSetCurrentLocal = "failed to set current config checkpoint to local config"
|
||||
// FailSyncReasonSetCurrentUIDFmt is used when we can't set the current config checkpoint to a checkpointed object, e.g. due to filesystem issues
|
||||
FailSyncReasonSetCurrentUIDFmt = "failed to set current config checkpoint to object with UID %q"
|
||||
FailSyncReasonSetCurrentUIDFmt = "failed to set current config checkpoint to object %s with UID %s"
|
||||
|
||||
// EmptyMessage is a placeholder in the case that we accidentally set the condition's message to the empty string.
|
||||
// Doing so can result in a partial patch, and thus a confusing status; this makes it clear that the message was not provided.
|
||||
@ -105,8 +97,8 @@ const (
|
||||
EmptyReason = "unknown - reason not provided"
|
||||
)
|
||||
|
||||
// ConfigOKCondition represents a ConfigOK NodeCondition
|
||||
type ConfigOKCondition interface {
|
||||
// ConfigOkCondition represents a ConfigOk NodeCondition
|
||||
type ConfigOkCondition interface {
|
||||
// Set sets the Message, Reason, and Status of the condition
|
||||
Set(message, reason string, status apiv1.ConditionStatus)
|
||||
// SetFailSyncCondition sets the condition for when syncing Kubelet config fails
|
||||
@ -117,61 +109,68 @@ type ConfigOKCondition interface {
|
||||
Sync(client clientset.Interface, nodeName string)
|
||||
}
|
||||
|
||||
// configOKCondition implements ConfigOKCondition
|
||||
type configOKCondition struct {
|
||||
// configOkCondition implements ConfigOkCondition
|
||||
type configOkCondition struct {
|
||||
// conditionMux is a mutex on the condition, alternate between setting and syncing the condition
|
||||
conditionMux sync.Mutex
|
||||
// condition is the current ConfigOK node condition, which will be reported in the Node.status.conditions
|
||||
condition *apiv1.NodeCondition
|
||||
// message will appear as the condition's message
|
||||
message string
|
||||
// reason will appear as the condition's reason
|
||||
reason string
|
||||
// status will appear as the condition's status
|
||||
status apiv1.ConditionStatus
|
||||
// failedSyncReason is sent in place of the usual reason when the Kubelet is failing to sync the remote config
|
||||
failedSyncReason string
|
||||
// pendingCondition; write to this channel to indicate that ConfigOK needs to be synced to the API server
|
||||
// pendingCondition; write to this channel to indicate that ConfigOk needs to be synced to the API server
|
||||
pendingCondition chan bool
|
||||
}
|
||||
|
||||
// NewConfigOKCondition returns a new ConfigOKCondition
|
||||
func NewConfigOKCondition() ConfigOKCondition {
|
||||
return &configOKCondition{
|
||||
// NewConfigOkCondition returns a new ConfigOkCondition
|
||||
func NewConfigOkCondition() ConfigOkCondition {
|
||||
return &configOkCondition{
|
||||
message: EmptyMessage,
|
||||
reason: EmptyReason,
|
||||
status: apiv1.ConditionUnknown,
|
||||
// channels must have capacity at least 1, since we signal with non-blocking writes
|
||||
pendingCondition: make(chan bool, 1),
|
||||
}
|
||||
}
|
||||
|
||||
// unsafeSet sets the current state of the condition
|
||||
// it does not grab the conditionMux lock, so you should generally use setConfigOK unless you need to grab the lock
|
||||
// it does not grab the conditionMux lock, so you should generally use setConfigOk unless you need to grab the lock
|
||||
// at a higher level to synchronize additional operations
|
||||
func (c *configOKCondition) unsafeSet(message, reason string, status apiv1.ConditionStatus) {
|
||||
func (c *configOkCondition) unsafeSet(message, reason string, status apiv1.ConditionStatus) {
|
||||
// We avoid an empty Message, Reason, or Status on the condition. Since we use Patch to update conditions, an empty
|
||||
// field might cause a value from a previous condition to leak through, which can be very confusing.
|
||||
|
||||
// message
|
||||
if len(message) == 0 {
|
||||
message = EmptyMessage
|
||||
}
|
||||
c.message = message
|
||||
// reason
|
||||
if len(reason) == 0 {
|
||||
reason = EmptyReason
|
||||
}
|
||||
c.reason = reason
|
||||
// status
|
||||
if len(string(status)) == 0 {
|
||||
status = apiv1.ConditionUnknown
|
||||
}
|
||||
|
||||
c.condition = &apiv1.NodeCondition{
|
||||
Message: message,
|
||||
Reason: reason,
|
||||
Status: status,
|
||||
Type: apiv1.NodeConfigOK,
|
||||
}
|
||||
|
||||
c.status = status
|
||||
// always poke worker after update
|
||||
c.pokeSyncWorker()
|
||||
}
|
||||
|
||||
func (c *configOKCondition) Set(message, reason string, status apiv1.ConditionStatus) {
|
||||
func (c *configOkCondition) Set(message, reason string, status apiv1.ConditionStatus) {
|
||||
c.conditionMux.Lock()
|
||||
defer c.conditionMux.Unlock()
|
||||
c.unsafeSet(message, reason, status)
|
||||
}
|
||||
|
||||
// SetFailSyncCondition updates the ConfigOK status to reflect that we failed to sync to the latest config,
|
||||
// SetFailSyncCondition updates the ConfigOk status to reflect that we failed to sync to the latest config,
|
||||
// e.g. due to a malformed Node.Spec.ConfigSource, a download failure, etc.
|
||||
func (c *configOKCondition) SetFailSyncCondition(reason string) {
|
||||
func (c *configOkCondition) SetFailSyncCondition(reason string) {
|
||||
c.conditionMux.Lock()
|
||||
defer c.conditionMux.Unlock()
|
||||
// set the reason overlay and poke the sync worker to send the update
|
||||
@ -180,7 +179,7 @@ func (c *configOKCondition) SetFailSyncCondition(reason string) {
|
||||
}
|
||||
|
||||
// ClearFailSyncCondition removes the "failed to sync" reason overlay
|
||||
func (c *configOKCondition) ClearFailSyncCondition() {
|
||||
func (c *configOkCondition) ClearFailSyncCondition() {
|
||||
c.conditionMux.Lock()
|
||||
defer c.conditionMux.Unlock()
|
||||
// clear the reason overlay and poke the sync worker to send the update
|
||||
@ -188,8 +187,8 @@ func (c *configOKCondition) ClearFailSyncCondition() {
|
||||
c.pokeSyncWorker()
|
||||
}
|
||||
|
||||
// pokeSyncWorker notes that the ConfigOK condition needs to be synced to the API server
|
||||
func (c *configOKCondition) pokeSyncWorker() {
|
||||
// pokeSyncWorker notes that the ConfigOk condition needs to be synced to the API server
|
||||
func (c *configOkCondition) pokeSyncWorker() {
|
||||
select {
|
||||
case c.pendingCondition <- true:
|
||||
default:
|
||||
@ -198,7 +197,7 @@ func (c *configOKCondition) pokeSyncWorker() {
|
||||
|
||||
// Sync attempts to sync `c.condition` with the Node object for this Kubelet,
|
||||
// if syncing fails, an error is logged, and work is queued for retry.
|
||||
func (c *configOKCondition) Sync(client clientset.Interface, nodeName string) {
|
||||
func (c *configOkCondition) Sync(client clientset.Interface, nodeName string) {
|
||||
select {
|
||||
case <-c.pendingCondition:
|
||||
default:
|
||||
@ -219,41 +218,39 @@ func (c *configOKCondition) Sync(client clientset.Interface, nodeName string) {
|
||||
}
|
||||
}()
|
||||
|
||||
if c.condition == nil {
|
||||
utillog.Infof("ConfigOK condition is nil, skipping ConfigOK sync")
|
||||
return
|
||||
}
|
||||
|
||||
// get the Node so we can check the current condition
|
||||
node, err := client.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not get Node %q, will not sync ConfigOK condition, error: %v", nodeName, err)
|
||||
err = fmt.Errorf("could not get Node %q, will not sync ConfigOk condition, error: %v", nodeName, err)
|
||||
return
|
||||
}
|
||||
|
||||
// construct the node condition
|
||||
condition := &apiv1.NodeCondition{
|
||||
Type: apiv1.NodeKubeletConfigOk,
|
||||
Message: c.message,
|
||||
Reason: c.reason,
|
||||
Status: c.status,
|
||||
}
|
||||
|
||||
// overlay failed sync reason, if necessary
|
||||
if len(c.failedSyncReason) > 0 {
|
||||
condition.Reason = c.failedSyncReason
|
||||
condition.Status = apiv1.ConditionFalse
|
||||
}
|
||||
|
||||
// set timestamps
|
||||
syncTime := metav1.NewTime(time.Now())
|
||||
c.condition.LastHeartbeatTime = syncTime
|
||||
if remote := getConfigOK(node.Status.Conditions); remote == nil || !utilequal.ConfigOKEq(remote, c.condition) {
|
||||
condition.LastHeartbeatTime = syncTime
|
||||
if remote := getKubeletConfigOk(node.Status.Conditions); remote == nil || !utilequal.KubeletConfigOkEq(remote, condition) {
|
||||
// update transition time the first time we create the condition,
|
||||
// or if we are semantically changing the condition
|
||||
c.condition.LastTransitionTime = syncTime
|
||||
condition.LastTransitionTime = syncTime
|
||||
} else {
|
||||
// since the conditions are semantically equal, use lastTransitionTime from the condition currently on the Node
|
||||
// we need to do this because the field will always be represented in the patch generated below, and this copy
|
||||
// prevents nullifying the field during the patch operation
|
||||
c.condition.LastTransitionTime = remote.LastTransitionTime
|
||||
}
|
||||
|
||||
// overlay the failedSyncReason if necessary
|
||||
var condition *apiv1.NodeCondition
|
||||
if len(c.failedSyncReason) > 0 {
|
||||
// get a copy of the condition before we add the overlay
|
||||
condition = c.condition.DeepCopy()
|
||||
condition.Reason = c.failedSyncReason
|
||||
condition.Status = apiv1.ConditionFalse
|
||||
} else {
|
||||
condition = c.condition
|
||||
condition.LastTransitionTime = remote.LastTransitionTime
|
||||
}
|
||||
|
||||
// generate the patch
|
||||
@ -277,7 +274,7 @@ func (c *configOKCondition) Sync(client clientset.Interface, nodeName string) {
|
||||
return
|
||||
}
|
||||
|
||||
patchConfigOK(node, condition)
|
||||
patchConfigOk(node, condition)
|
||||
after, err := kuberuntime.Encode(encoder, node)
|
||||
if err != nil {
|
||||
err = fmt.Errorf(`failed to encode "after" node while generating patch, error: %v`, err)
|
||||
@ -286,36 +283,36 @@ func (c *configOKCondition) Sync(client clientset.Interface, nodeName string) {
|
||||
|
||||
patch, err := strategicpatch.CreateTwoWayMergePatch(before, after, apiv1.Node{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to generate patch for updating ConfigOK condition, error: %v", err)
|
||||
err = fmt.Errorf("failed to generate patch for updating ConfigOk condition, error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// patch the remote Node object
|
||||
_, err = client.CoreV1().Nodes().PatchStatus(nodeName, patch)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not update ConfigOK condition, error: %v", err)
|
||||
err = fmt.Errorf("could not update ConfigOk condition, error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// patchConfigOK replaces or adds the ConfigOK condition to the node
|
||||
func patchConfigOK(node *apiv1.Node, configOK *apiv1.NodeCondition) {
|
||||
// patchConfigOk replaces or adds the ConfigOk condition to the node
|
||||
func patchConfigOk(node *apiv1.Node, configOk *apiv1.NodeCondition) {
|
||||
for i := range node.Status.Conditions {
|
||||
if node.Status.Conditions[i].Type == apiv1.NodeConfigOK {
|
||||
if node.Status.Conditions[i].Type == apiv1.NodeKubeletConfigOk {
|
||||
// edit the condition
|
||||
node.Status.Conditions[i] = *configOK
|
||||
node.Status.Conditions[i] = *configOk
|
||||
return
|
||||
}
|
||||
}
|
||||
// append the condition
|
||||
node.Status.Conditions = append(node.Status.Conditions, *configOK)
|
||||
node.Status.Conditions = append(node.Status.Conditions, *configOk)
|
||||
}
|
||||
|
||||
// getConfigOK returns the first NodeCondition in `cs` with Type == apiv1.NodeConfigOK,
|
||||
// getKubeletConfigOk returns the first NodeCondition in `cs` with Type == apiv1.NodeKubeletConfigOk,
|
||||
// or if no such condition exists, returns nil.
|
||||
func getConfigOK(cs []apiv1.NodeCondition) *apiv1.NodeCondition {
|
||||
func getKubeletConfigOk(cs []apiv1.NodeCondition) *apiv1.NodeCondition {
|
||||
for i := range cs {
|
||||
if cs[i].Type == apiv1.NodeConfigOK {
|
||||
if cs[i].Type == apiv1.NodeKubeletConfigOk {
|
||||
return &cs[i]
|
||||
}
|
||||
}
|
||||
|
6
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/equal/equal.go
generated
vendored
6
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/equal/equal.go
generated
vendored
@ -30,7 +30,7 @@ func ConfigSourceEq(a, b *apiv1.NodeConfigSource) bool {
|
||||
if a.ConfigMapRef != b.ConfigMapRef {
|
||||
return ObjectRefEq(a.ConfigMapRef, b.ConfigMapRef)
|
||||
}
|
||||
// all internal subfields of the config soruce are equal
|
||||
// all internal subfields of the config source are equal
|
||||
return true
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ func ObjectRefEq(a, b *apiv1.ObjectReference) bool {
|
||||
return a.UID == b.UID && a.Namespace == b.Namespace && a.Name == b.Name
|
||||
}
|
||||
|
||||
// ConfigOKEq returns true if the two conditions are semantically equivalent in the context of dynamic config
|
||||
func ConfigOKEq(a, b *apiv1.NodeCondition) bool {
|
||||
// KubeletConfigOkEq returns true if the two conditions are semantically equivalent in the context of dynamic config
|
||||
func KubeletConfigOkEq(a, b *apiv1.NodeCondition) bool {
|
||||
return a.Message == b.Message && a.Reason == b.Reason && a.Status == b.Status
|
||||
}
|
||||
|
2
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/watch.go
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/kubelet/kubeletconfig/watch.go
generated
vendored
@ -103,7 +103,7 @@ func (cc *Controller) onUpdateNodeEvent(oldObj interface{}, newObj interface{})
|
||||
// if an unexpected DeletedFinalStateUnknown was received.
|
||||
// We allow the sync-loop to continue, because it is possible that the Kubelet detected
|
||||
// a Node with unexpected externalID and is attempting to delete and re-create the Node
|
||||
// (see pkg/kubelet/kubelet_node_status.go), or that someone accidently deleted the Node
|
||||
// (see pkg/kubelet/kubelet_node_status.go), or that someone accidentally deleted the Node
|
||||
// (the Kubelet will re-create it).
|
||||
func (cc *Controller) onDeleteNodeEvent(deletedObj interface{}) {
|
||||
node, ok := deletedObj.(*apiv1.Node)
|
||||
|
Reference in New Issue
Block a user