Merge pull request #51008 from kubernetes/revert-50789-fix-scheme

Revert "Don't register the kubeletconfig group with the default Scheme"
pull/6/head
Shyam JVS 2017-08-21 13:54:15 +02:00 committed by GitHub
commit f4afdecef8
23 changed files with 155 additions and 189 deletions

View File

@ -12,10 +12,11 @@ go_library(
"options.go",
],
deps = [
"//pkg/api:go_default_library",
"//pkg/apis/componentconfig:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/scheme:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/install:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/validation:go_default_library",
"//pkg/util/taints:go_default_library",

View File

@ -25,12 +25,14 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/pkg/util/flag"
utilflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/componentconfig"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
kubeletscheme "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme"
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
kubeletconfigvalidation "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/validation"
// Need to make sure the kubeletconfig api is installed so defaulting funcs work
_ "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/install"
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
utiltaints "k8s.io/kubernetes/pkg/util/taints"
"github.com/spf13/pflag"
@ -140,14 +142,10 @@ func ValidateKubeletFlags(f *KubeletFlags) error {
// NewKubeletConfiguration will create a new KubeletConfiguration with default values
func NewKubeletConfiguration() (*kubeletconfig.KubeletConfiguration, error) {
scheme, _, err := kubeletscheme.NewSchemeAndCodecs()
if err != nil {
return nil, err
}
versioned := &v1alpha1.KubeletConfiguration{}
scheme.Default(versioned)
api.Scheme.Default(versioned)
config := &kubeletconfig.KubeletConfiguration{}
if err := scheme.Convert(versioned, config, nil); err != nil {
if err := api.Scheme.Convert(versioned, config, nil); err != nil {
return nil, err
}
return config, nil

View File

@ -756,8 +756,7 @@ func parseResourceList(m kubeletconfiginternal.ConfigurationMap) (v1.ResourceLis
}
// BootstrapKubeletConfigController constructs and bootstrap a configuration controller
func BootstrapKubeletConfigController(
flags *options.KubeletFlags,
func BootstrapKubeletConfigController(flags *options.KubeletFlags,
defaultConfig *kubeletconfiginternal.KubeletConfiguration) (*kubeletconfiginternal.KubeletConfiguration, *kubeletconfig.Controller, error) {
var err error
// Alpha Dynamic Configuration Implementation; this section only loads config from disk, it does not contact the API server
@ -778,10 +777,7 @@ func BootstrapKubeletConfigController(
}
// get the latest KubeletConfiguration checkpoint from disk, or load the init or default config if no valid checkpoints exist
kubeletConfigController, err := kubeletconfig.NewController(initConfigDir, dynamicConfigDir, defaultConfig)
if err != nil {
return nil, nil, fmt.Errorf("failed to construct controller, error: %v", err)
}
kubeletConfigController := kubeletconfig.NewController(initConfigDir, dynamicConfigDir, defaultConfig)
kubeletConfig, err := kubeletConfigController.Bootstrap()
if err != nil {
return nil, nil, fmt.Errorf("failed to determine a valid configuration, error: %v", err)

View File

@ -89,10 +89,7 @@ func main() {
}
// construct a KubeletServer from kubeletFlags and kubeletConfig
kubeletServer := &options.KubeletServer{
KubeletFlags: *kubeletFlags,
KubeletConfiguration: *kubeletConfig,
}
kubeletServer := &options.KubeletServer{KubeletFlags: *kubeletFlags, KubeletConfiguration: *kubeletConfig}
// use kubeletServer to construct the default KubeletDeps
kubeletDeps, err := app.UnsecuredDependencies(kubeletServer)

View File

@ -36,7 +36,7 @@ filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/kubelet/apis/kubeletconfig/scheme:all-srcs",
"//pkg/kubelet/apis/kubeletconfig/install:all-srcs",
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:all-srcs",
"//pkg/kubelet/apis/kubeletconfig/validation:all-srcs",
],

View File

@ -1,14 +1,23 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["scheme.go"],
visibility = ["//visibility:public"],
srcs = ["install.go"],
tags = ["automanaged"],
deps = [
"//pkg/api:go_default_library",
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
],
)
@ -23,5 +32,4 @@ filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,49 @@
/*
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 install installs the experimental API group, making it available as
// an option to all of the API encoding/decoding machinery.
package install
import (
"k8s.io/apimachinery/pkg/apimachinery/announced"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
)
func init() {
// TODO(mtaufen): probably want to create a kubelet scheme rather than reusing the api scheme, but need to ask lavalamp
Install(api.GroupFactoryRegistry, api.Registry, api.Scheme)
}
// Install registers the API group and adds types to a scheme
func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme) {
if err := announced.NewGroupMetaFactory(
&announced.GroupMetaFactoryArgs{
GroupName: kubeletconfig.GroupName,
VersionPreferenceOrder: []string{v1alpha1.SchemeGroupVersion.Version},
AddInternalObjectsToScheme: kubeletconfig.AddToScheme,
},
announced.VersionToSchemeFunc{
v1alpha1.SchemeGroupVersion.Version: v1alpha1.AddToScheme,
},
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
panic(err)
}
}

View File

@ -1,40 +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 scheme
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
)
// Utility functions for the Kubelet's kubeletconfig API group
// NewSchemeAndCodecs is a utility funciton that returns a Scheme and CodecFactory
// that understand the types in the kubeletconfig API group.
func NewSchemeAndCodecs() (*runtime.Scheme, *serializer.CodecFactory, error) {
scheme := runtime.NewScheme()
if err := kubeletconfig.AddToScheme(scheme); err != nil {
return nil, nil, err
}
if err := v1alpha1.AddToScheme(scheme); err != nil {
return nil, nil, err
}
codecs := serializer.NewCodecFactory(scheme)
return scheme, &codecs, nil
}

View File

@ -15,8 +15,8 @@ go_test(
],
library = ":go_default_library",
deps = [
"//pkg/api:go_default_library",
"//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/kubeletconfig/util/codec:go_default_library",
"//pkg/kubelet/kubeletconfig/util/test:go_default_library",
@ -40,14 +40,12 @@ go_library(
deps = [
"//pkg/api:go_default_library",
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/scheme:go_default_library",
"//pkg/kubelet/kubeletconfig/util/codec:go_default_library",
"//pkg/kubelet/kubeletconfig/util/log:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
],
)

View File

@ -30,7 +30,7 @@ import (
type Checkpoint interface {
// UID returns the UID of the config source object behind the Checkpoint
UID() string
// Parse extracts the KubeletConfiguration from the checkpoint, applies defaults, and converts to the internal type
// Parse parses the checkpoint into the internal KubeletConfiguration type
Parse() (*kubeletconfig.KubeletConfiguration, error)
// Encode returns a []byte representation of the config source object behind the Checkpoint
Encode() ([]byte, error)
@ -56,7 +56,6 @@ func DecodeCheckpoint(data []byte) (Checkpoint, error) {
if err != nil {
return nil, fmt.Errorf("failed to convert decoded object into a v1 ConfigMap, error: %v", err)
}
return NewConfigMapCheckpoint(cm)
}

View File

@ -30,6 +30,20 @@ import (
utiltest "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/test"
)
// newUnsupportedEncoded returns an encoding of an object that does not have a Checkpoint implementation
func newUnsupportedEncoded(t *testing.T) []byte {
encoder, err := utilcodec.NewJSONEncoder(apiv1.GroupName)
if err != nil {
t.Fatalf("could not create an encoder, error: %v", err)
}
unsupported := &apiv1.Node{}
data, err := runtime.Encode(encoder, unsupported)
if err != nil {
t.Fatalf("could not encode object, error: %v", err)
}
return data
}
func TestDecodeCheckpoint(t *testing.T) {
// generate correct Checkpoint for v1/ConfigMap test case
cm, err := NewConfigMapCheckpoint(&apiv1.ConfigMap{ObjectMeta: metav1.ObjectMeta{UID: types.UID("uid")}})
@ -73,17 +87,3 @@ func TestDecodeCheckpoint(t *testing.T) {
}
}
}
// newUnsupportedEncoded returns an encoding of an object that does not have a Checkpoint implementation
func newUnsupportedEncoded(t *testing.T) []byte {
encoder, err := utilcodec.NewJSONEncoder(apiv1.GroupName)
if err != nil {
t.Fatalf("could not create an encoder, error: %v", err)
}
unsupported := &apiv1.Node{}
data, err := runtime.Encode(encoder, unsupported)
if err != nil {
t.Fatalf("could not encode object, error: %v", err)
}
return data
}

View File

@ -21,9 +21,7 @@ import (
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
kubeletscheme "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme"
utilcodec "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/codec"
)
@ -31,7 +29,6 @@ const configMapConfigKey = "kubelet"
// configMapCheckpoint implements Checkpoint, backed by a v1/ConfigMap config source object
type configMapCheckpoint struct {
kubeletCodecs *serializer.CodecFactory // codecs for the KubeletConfiguration
configMap *apiv1.ConfigMap
}
@ -43,13 +40,7 @@ func NewConfigMapCheckpoint(cm *apiv1.ConfigMap) (Checkpoint, error) {
} else if len(cm.ObjectMeta.UID) == 0 {
return nil, fmt.Errorf("ConfigMap must have a UID to be treated as a Checkpoint")
}
_, kubeletCodecs, err := kubeletscheme.NewSchemeAndCodecs()
if err != nil {
return nil, err
}
return &configMapCheckpoint{kubeletCodecs, cm}, nil
return &configMapCheckpoint{cm}, nil
}
// UID returns the UID of a configMapCheckpoint
@ -57,23 +48,25 @@ func (c *configMapCheckpoint) UID() string {
return string(c.configMap.UID)
}
// Parse extracts the KubeletConfiguration from v1/ConfigMap checkpoints, applies defaults, and converts to the internal type
// implements Parse for v1/ConfigMap checkpoints
func (c *configMapCheckpoint) Parse() (*kubeletconfig.KubeletConfiguration, error) {
const emptyCfgErr = "config was empty, but some parameters are required"
if len(c.configMap.Data) == 0 {
cm := c.configMap
if len(cm.Data) == 0 {
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]
config, ok := cm.Data[configMapConfigKey]
if !ok {
return nil, fmt.Errorf("key %q not found in ConfigMap", configMapConfigKey)
} else if len(config) == 0 {
return nil, fmt.Errorf(emptyCfgErr)
}
return utilcodec.DecodeKubeletConfiguration(c.kubeletCodecs, []byte(config))
return utilcodec.DecodeKubeletConfiguration([]byte(config))
}
// Encode encodes a configMapCheckpoint

View File

@ -26,8 +26,8 @@ import (
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/api"
"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"
utiltest "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/test"
)
@ -66,15 +66,9 @@ func TestNewConfigMapCheckpoint(t *testing.T) {
}
func TestConfigMapCheckpointUID(t *testing.T) {
_, kubeletCodecs, err := kubeletscheme.NewSchemeAndCodecs()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
cases := []string{"", "uid", "376dfb73-56db-11e7-a01e-42010a800002"}
for _, uidIn := range cases {
cpt := &configMapCheckpoint{
kubeletCodecs,
&apiv1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{UID: types.UID(uidIn)},
},
@ -88,16 +82,11 @@ func TestConfigMapCheckpointUID(t *testing.T) {
}
func TestConfigMapCheckpointParse(t *testing.T) {
kubeletScheme, kubeletCodecs, err := kubeletscheme.NewSchemeAndCodecs()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// get the built-in default configuration
external := &kubeletconfigv1alpha1.KubeletConfiguration{}
kubeletScheme.Default(external)
api.Scheme.Default(external)
defaultConfig := &kubeletconfig.KubeletConfiguration{}
err = kubeletScheme.Convert(external, defaultConfig, nil)
err := api.Scheme.Convert(external, defaultConfig, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -134,7 +123,7 @@ apiVersion: kubeletconfig/v1alpha1`}}, defaultConfig, ""},
"kubelet": `{"kind":"KubeletConfiguration","apiVersion":"kubeletconfig/v1alpha1"}`}}, defaultConfig, ""},
}
for _, c := range cases {
cpt := &configMapCheckpoint{kubeletCodecs, c.cm}
cpt := &configMapCheckpoint{c.cm}
kc, err := cpt.Parse()
if utiltest.SkipRest(t, c.desc, err, c.err) {
continue
@ -147,11 +136,6 @@ apiVersion: kubeletconfig/v1alpha1`}}, defaultConfig, ""},
}
func TestConfigMapCheckpointEncode(t *testing.T) {
_, kubeletCodecs, err := kubeletscheme.NewSchemeAndCodecs()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// only one case, based on output from the existing encoder, and since
// this is hard to test (key order isn't guaranteed), we should probably
// just stick to this test case and mostly rely on the round-trip test.
@ -162,7 +146,7 @@ func TestConfigMapCheckpointEncode(t *testing.T) {
}{
// we expect Checkpoints to be encoded as a json representation of the underlying API object
{"one-key",
&configMapCheckpoint{kubeletCodecs, &apiv1.ConfigMap{
&configMapCheckpoint{&apiv1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Name: "one-key"},
Data: map[string]string{"one": ""}}},
`{"kind":"ConfigMap","apiVersion":"v1","metadata":{"name":"one-key","creationTimestamp":null},"data":{"one":""}}
@ -182,11 +166,6 @@ func TestConfigMapCheckpointEncode(t *testing.T) {
}
func TestConfigMapCheckpointRoundTrip(t *testing.T) {
_, kubeletCodecs, err := kubeletscheme.NewSchemeAndCodecs()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
cases := []struct {
desc string
cpt *configMapCheckpoint
@ -194,7 +173,7 @@ func TestConfigMapCheckpointRoundTrip(t *testing.T) {
}{
// empty data
{"empty data",
&configMapCheckpoint{kubeletCodecs, &apiv1.ConfigMap{
&configMapCheckpoint{&apiv1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "empty-data-sha256-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
UID: "uid",
@ -203,7 +182,7 @@ func TestConfigMapCheckpointRoundTrip(t *testing.T) {
""},
// two keys
{"two keys",
&configMapCheckpoint{kubeletCodecs, &apiv1.ConfigMap{
&configMapCheckpoint{&apiv1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "two-keys-sha256-2bff03d6249c8a9dc9a1436d087c124741361ccfac6615b81b67afcff5c42431",
UID: "uid",
@ -212,7 +191,7 @@ func TestConfigMapCheckpointRoundTrip(t *testing.T) {
""},
// missing uid
{"missing uid",
&configMapCheckpoint{kubeletCodecs, &apiv1.ConfigMap{
&configMapCheckpoint{&apiv1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "two-keys-sha256-2bff03d6249c8a9dc9a1436d087c124741361ccfac6615b81b67afcff5c42431",
UID: "",

View File

@ -113,6 +113,7 @@ func (r *remoteConfigMap) UID() string {
func (r *remoteConfigMap) Download(client clientset.Interface) (Checkpoint, string, error) {
var reason string
uid := string(r.source.ConfigMapRef.UID)
utillog.Infof("attempting to download ConfigMap with UID %q", uid)
@ -130,14 +131,8 @@ func (r *remoteConfigMap) Download(client clientset.Interface) (Checkpoint, stri
return nil, reason, fmt.Errorf(reason)
}
checkpoint, err := NewConfigMapCheckpoint(cm)
if err != nil {
reason = fmt.Sprintf("invalid downloaded object")
return nil, reason, fmt.Errorf("%s, error: %v", reason, err)
}
utillog.Infof("successfully downloaded ConfigMap with UID %q", uid)
return checkpoint, "", nil
return &configMapCheckpoint{cm}, "", nil
}
func (r *remoteConfigMap) Encode() ([]byte, error) {

View File

@ -26,7 +26,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
fakeclient "k8s.io/client-go/kubernetes/fake"
kubeletscheme "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme"
utiltest "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/test"
)
@ -93,11 +92,6 @@ func TestRemoteConfigMapUID(t *testing.T) {
}
func TestRemoteConfigMapDownload(t *testing.T) {
_, kubeletCodecs, err := kubeletscheme.NewSchemeAndCodecs()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
cm := &apiv1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
@ -124,7 +118,7 @@ func TestRemoteConfigMapDownload(t *testing.T) {
// successful download
{"object exists and reference is correct",
&remoteConfigMap{&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "uid"}}},
&configMapCheckpoint{kubeletCodecs, cm}, ""},
&configMapCheckpoint{cm}, ""},
}
for _, c := range cases {

View File

@ -10,10 +10,8 @@ go_library(
srcs = ["configfiles.go"],
deps = [
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/scheme:go_default_library",
"//pkg/kubelet/kubeletconfig/util/codec:go_default_library",
"//pkg/kubelet/kubeletconfig/util/filesystem:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
],
)

View File

@ -20,9 +20,7 @@ import (
"fmt"
"path/filepath"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
kubeletscheme "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme"
utilcodec "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/codec"
utilfs "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/filesystem"
)
@ -37,24 +35,16 @@ type Loader interface {
type fsLoader struct {
// fs is the filesystem where the config files exist; can be mocked for testing
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
}
// NewFSLoader returns a Loader that loads a KubeletConfiguration from the files in `configDir`
func NewFSLoader(fs utilfs.Filesystem, configDir string) (Loader, error) {
_, kubeletCodecs, err := kubeletscheme.NewSchemeAndCodecs()
if err != nil {
return nil, err
}
func NewFSLoader(fs utilfs.Filesystem, configDir string) Loader {
return &fsLoader{
fs: fs,
kubeletCodecs: kubeletCodecs,
configDir: configDir,
}, nil
}
}
func (loader *fsLoader) Load() (*kubeletconfig.KubeletConfiguration, error) {
@ -72,5 +62,5 @@ func (loader *fsLoader) Load() (*kubeletconfig.KubeletConfiguration, error) {
return nil, fmt.Errorf(errfmt, fmt.Errorf("config file was empty, but some parameters are required"))
}
return utilcodec.DecodeKubeletConfiguration(loader.kubeletCodecs, data)
return utilcodec.DecodeKubeletConfiguration(data)
}

View File

@ -53,7 +53,7 @@ const (
// - validates configuration
// - monitors for potential crash-loops caused by new configurations
// - tracks the last-known-good configuration, and rolls-back to last-known-good when necessary
// For more information, see the proposal: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/dynamic-kubelet-configuration.md
// For more information, see the proposal: https://github.com/kubernetes/kubernetes/pull/29459
type Controller struct {
// dynamicConfig, if true, indicates that we should sync config from the API server
dynamicConfig bool
@ -90,19 +90,12 @@ type Controller struct {
// 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(initConfigDir string,
dynamicConfigDir string,
defaultConfig *kubeletconfig.KubeletConfiguration) (*Controller, error) {
var err error
func NewController(initConfigDir string, dynamicConfigDir string, defaultConfig *kubeletconfig.KubeletConfiguration) *Controller {
fs := utilfs.DefaultFs{}
var initLoader configfiles.Loader
if len(initConfigDir) > 0 {
initLoader, err = configfiles.NewFSLoader(fs, initConfigDir)
if err != nil {
return nil, err
}
initLoader = configfiles.NewFSLoader(fs, initConfigDir)
}
dynamicConfig := false
if len(dynamicConfigDir) > 0 {
@ -127,7 +120,7 @@ func NewController(initConfigDir string,
badConfigTracker: badconfig.NewFsTracker(fs, filepath.Join(dynamicConfigDir, badConfigTrackingDir, kubeletVersion)),
startupTracker: startups.NewFsTracker(fs, filepath.Join(dynamicConfigDir, startupTrackingDir, kubeletVersion)),
initLoader: initLoader,
}, nil
}
}
// Bootstrap attempts to return a valid KubeletConfiguration based on the configuration of the Controller,

View File

@ -12,8 +12,9 @@ go_library(
"//pkg/api:go_default_library",
"//pkg/api/install:go_default_library",
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/install:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
],
)

View File

@ -21,11 +21,13 @@ import (
// ensure the core apis are installed
_ "k8s.io/kubernetes/pkg/api/install"
// ensure the kubeletconfig apis are installed
_ "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/install"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
kubeletconfigv1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
)
// TODO(mtaufen): allow an encoder to be injected into checkpoint objects at creation time? (then we could ultimately instantiate only one encoder)
@ -48,18 +50,28 @@ func NewJSONEncoder(groupName string) (runtime.Encoder, error) {
return api.Codecs.EncoderForVersion(info.Serializer, versions[0]), nil
}
// DecodeKubeletConfiguration decodes a serialized KubeletConfiguration to the internal type
func DecodeKubeletConfiguration(kubeletCodecs *serializer.CodecFactory, data []byte) (*kubeletconfig.KubeletConfiguration, error) {
// the UniversalDecoder runs defaulting and returns the internal type by default
obj, gvk, err := kubeletCodecs.UniversalDecoder().Decode(data, nil, nil)
// DecodeKubeletConfiguration decodes an encoded (v1alpha1) KubeletConfiguration object to the internal type
func DecodeKubeletConfiguration(data []byte) (*kubeletconfig.KubeletConfiguration, error) {
// decode the object, note we use the external version scheme to decode, because users provide the external version
obj, err := runtime.Decode(api.Codecs.UniversalDecoder(kubeletconfigv1alpha1.SchemeGroupVersion), data)
if err != nil {
return nil, fmt.Errorf("failed to decode, error: %v", err)
}
internalKC, ok := obj.(*kubeletconfig.KubeletConfiguration)
externalKC, ok := obj.(*kubeletconfigv1alpha1.KubeletConfiguration)
if !ok {
return nil, fmt.Errorf("failed to cast object to KubeletConfiguration, unexpected type: %v", gvk)
return nil, fmt.Errorf("failed to cast object to KubeletConfiguration, object: %#v", obj)
}
// TODO(mtaufen): confirm whether api.Codecs.UniversalDecoder runs the defaulting, which would make this redundant
// run the defaulter on the decoded configuration before converting to internal type
api.Scheme.Default(externalKC)
// convert to internal type
internalKC := &kubeletconfig.KubeletConfiguration{}
err = api.Scheme.Convert(externalKC, internalKC, nil)
if err != nil {
return nil, err
}
return internalKC, nil
}

View File

@ -30,7 +30,6 @@ go_library(
"//pkg/kubelet/apis/cri:go_default_library",
"//pkg/kubelet/apis/cri/v1alpha1/runtime:go_default_library",
"//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/stats/v1alpha1:go_default_library",
"//pkg/kubelet/metrics:go_default_library",

View File

@ -37,7 +37,6 @@ import (
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/kubernetes/pkg/api"
"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"
stats "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1"
kubeletmetrics "k8s.io/kubernetes/pkg/kubelet/metrics"
@ -263,7 +262,7 @@ func makeKubeletConfigMap(internalKC *kubeletconfig.KubeletConfiguration) *v1.Co
externalKC := &kubeletconfigv1alpha1.KubeletConfiguration{}
api.Scheme.Convert(internalKC, externalKC, nil)
encoder, err := newKubeletConfigJSONEncoder()
encoder, err := newJSONEncoder(kubeletconfig.GroupName)
framework.ExpectNoError(err)
data, err := runtime.Encode(encoder, externalKC)
@ -311,18 +310,21 @@ func logKubeletMetrics(metricKeys ...string) {
}
}
func newKubeletConfigJSONEncoder() (runtime.Encoder, error) {
_, kubeletCodecs, err := kubeletscheme.NewSchemeAndCodecs()
if err != nil {
return nil, err
}
func newJSONEncoder(groupName string) (runtime.Encoder, error) {
// encode to json
mediaType := "application/json"
info, ok := runtime.SerializerInfoForMediaType(kubeletCodecs.SupportedMediaTypes(), mediaType)
info, ok := runtime.SerializerInfoForMediaType(api.Codecs.SupportedMediaTypes(), mediaType)
if !ok {
return nil, fmt.Errorf("unsupported media type %q", mediaType)
}
return kubeletCodecs.EncoderForVersion(info.Serializer, kubeletconfigv1alpha1.SchemeGroupVersion), nil
versions := api.Registry.EnabledVersionsForGroup(groupName)
if len(versions) == 0 {
return nil, fmt.Errorf("no enabled versions for group %q", groupName)
}
// the "best" version supposedly comes first in the list returned from api.Registry.EnabledVersionsForGroup
return api.Codecs.EncoderForVersion(info.Serializer, versions[0]), nil
}
// runCommand runs the cmd and returns the combined stdout and stderr, or an

View File

@ -434,6 +434,10 @@ var ephemeralWhiteList = createEphemeralWhiteList(
gvr("componentconfig", "v1alpha1", "kubeproxyconfigurations"), // not stored in etcd
// --
// k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1
gvr("kubeletconfig", "v1alpha1", "kubeletconfigurations"), // not stored in etcd
// --
// k8s.io/kubernetes/pkg/apis/extensions/v1beta1
gvr("extensions", "v1beta1", "deploymentrollbacks"), // used to rollback deployment, not stored in etcd
gvr("extensions", "v1beta1", "replicationcontrollerdummies"), // not stored in etcd