diff --git a/pkg/controller/volume/attachdetach/attach_detach_controller.go b/pkg/controller/volume/attachdetach/attach_detach_controller.go index fd49f0f470e..8db08392418 100644 --- a/pkg/controller/volume/attachdetach/attach_detach_controller.go +++ b/pkg/controller/volume/attachdetach/attach_detach_controller.go @@ -552,6 +552,12 @@ func (adc *attachDetachController) GetSecretFunc() func(namespace, name string) } } +func (adc *attachDetachController) GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error) { + return func(_, _ string) (*v1.ConfigMap, error) { + return nil, fmt.Errorf("GetConfigMap unsupported in attachDetachController") + } +} + func (adc *attachDetachController) addNodeToDswp(node *v1.Node, nodeName types.NodeName) { if _, exists := node.Annotations[volumehelper.ControllerManagedAttachAnnotation]; exists { keepTerminatedPodVolumes := false diff --git a/pkg/controller/volume/persistentvolume/volume_host.go b/pkg/controller/volume/persistentvolume/volume_host.go index 111c2c0d8d5..f545f546391 100644 --- a/pkg/controller/volume/persistentvolume/volume_host.go +++ b/pkg/controller/volume/persistentvolume/volume_host.go @@ -87,6 +87,12 @@ func (adc *PersistentVolumeController) GetSecretFunc() func(namespace, name stri } } +func (adc *PersistentVolumeController) GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error) { + return func(_, _ string) (*v1.ConfigMap, error) { + return nil, fmt.Errorf("GetConfigMap unsupported in PersistentVolumeController") + } +} + func (ctrl *PersistentVolumeController) GetNodeLabels() (map[string]string, error) { return nil, fmt.Errorf("GetNodeLabels() unsupported in PersistentVolumeController") } diff --git a/pkg/kubelet/BUILD b/pkg/kubelet/BUILD index 1ae7c962341..1c732d19e09 100644 --- a/pkg/kubelet/BUILD +++ b/pkg/kubelet/BUILD @@ -57,6 +57,7 @@ go_library( "//pkg/kubelet/certificate:go_default_library", "//pkg/kubelet/cm:go_default_library", "//pkg/kubelet/config:go_default_library", + "//pkg/kubelet/configmap:go_default_library", "//pkg/kubelet/container:go_default_library", "//pkg/kubelet/dockershim:go_default_library", "//pkg/kubelet/dockershim/libdocker:go_default_library", @@ -174,6 +175,7 @@ go_test( "//pkg/kubelet/cadvisor/testing:go_default_library", "//pkg/kubelet/cm:go_default_library", "//pkg/kubelet/config:go_default_library", + "//pkg/kubelet/configmap:go_default_library", "//pkg/kubelet/container:go_default_library", "//pkg/kubelet/container/testing:go_default_library", "//pkg/kubelet/eviction:go_default_library", @@ -249,6 +251,7 @@ filegroup( "//pkg/kubelet/client:all-srcs", "//pkg/kubelet/cm:all-srcs", "//pkg/kubelet/config:all-srcs", + "//pkg/kubelet/configmap:all-srcs", "//pkg/kubelet/container:all-srcs", "//pkg/kubelet/custommetrics:all-srcs", "//pkg/kubelet/dockershim:all-srcs", diff --git a/pkg/kubelet/configmap/BUILD b/pkg/kubelet/configmap/BUILD new file mode 100644 index 00000000000..983ddcb3c33 --- /dev/null +++ b/pkg/kubelet/configmap/BUILD @@ -0,0 +1,35 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = [ + "configmap_manager.go", + "fake_manager.go", + ], + tags = ["automanaged"], + deps = [ + "//pkg/api/v1:go_default_library", + "//pkg/client/clientset_generated/clientset:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/pkg/kubelet/configmap/configmap_manager.go b/pkg/kubelet/configmap/configmap_manager.go new file mode 100644 index 00000000000..2d69c51080a --- /dev/null +++ b/pkg/kubelet/configmap/configmap_manager.go @@ -0,0 +1,61 @@ +/* +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 configmap + +import ( + "time" + + "k8s.io/kubernetes/pkg/api/v1" + clientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type Manager interface { + // Get configmap by configmap namespace and name. + GetConfigMap(namespace, name string) (*v1.ConfigMap, error) + + // WARNING: Register/UnregisterPod functions should be efficient, + // i.e. should not block on network operations. + + // RegisterPod registers all configmaps from a given pod. + RegisterPod(pod *v1.Pod) + + // UnregisterPod unregisters configmaps from a given pod that are not + // used by any other registered pod. + UnregisterPod(pod *v1.Pod) +} + +// simpleConfigMapManager implements ConfigMap Manager interface with +// simple operations to apiserver. +type simpleConfigMapManager struct { + kubeClient clientset.Interface +} + +func NewSimpleConfigMapManager(kubeClient clientset.Interface) Manager { + return &simpleConfigMapManager{kubeClient: kubeClient} +} + +func (s *simpleConfigMapManager) GetConfigMap(namespace, name string) (*v1.ConfigMap, error) { + return s.kubeClient.Core().ConfigMaps(namespace).Get(name, metav1.GetOptions{}) +} + +func (s *simpleConfigMapManager) RegisterPod(pod *v1.Pod) { +} + +func (s *simpleConfigMapManager) UnregisterPod(pod *v1.Pod) { +} diff --git a/pkg/kubelet/configmap/fake_manager.go b/pkg/kubelet/configmap/fake_manager.go new file mode 100644 index 00000000000..d1a4b85a6f9 --- /dev/null +++ b/pkg/kubelet/configmap/fake_manager.go @@ -0,0 +1,40 @@ +/* +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 configmap + +import ( + "k8s.io/kubernetes/pkg/api/v1" +) + +// fakeManager implements Manager interface for testing purposes. +// simple operations to apiserver. +type fakeManager struct { +} + +func NewFakeManager() Manager { + return &fakeManager{} +} + +func (s *fakeManager) GetConfigMap(namespace, name string) (*v1.ConfigMap, error) { + return nil, nil +} + +func (s *fakeManager) RegisterPod(pod *v1.Pod) { +} + +func (s *fakeManager) UnregisterPod(pod *v1.Pod) { +} diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index c87641c2c46..637af615847 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -68,6 +68,7 @@ import ( "k8s.io/kubernetes/pkg/kubelet/certificate" "k8s.io/kubernetes/pkg/kubelet/cm" "k8s.io/kubernetes/pkg/kubelet/config" + "k8s.io/kubernetes/pkg/kubelet/configmap" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" "k8s.io/kubernetes/pkg/kubelet/dockershim" "k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker" @@ -487,9 +488,11 @@ func NewMainKubelet(kubeCfg *componentconfig.KubeletConfiguration, kubeDeps *Kub secretManager := secret.NewCachingSecretManager( kubeDeps.KubeClient, secret.GetObjectTTLFromNodeFunc(klet.GetNode)) - klet.secretManager = secretManager + configMapManager := configmap.NewSimpleConfigMapManager(kubeDeps.KubeClient) + klet.configMapManager = configMapManager + if klet.experimentalHostUserNamespaceDefaulting { glog.Infof("Experimental host user namespace defaulting is enabled.") } @@ -518,8 +521,8 @@ func NewMainKubelet(kubeCfg *componentconfig.KubeletConfiguration, kubeDeps *Kub klet.livenessManager = proberesults.NewManager() klet.podCache = kubecontainer.NewCache() - // podManager is also responsible for keeping secretManager contents up-to-date. - klet.podManager = kubepod.NewBasicPodManager(kubepod.NewBasicMirrorClient(klet.kubeClient), secretManager) + // podManager is also responsible for keeping secretManager and configMapManager contents up-to-date. + klet.podManager = kubepod.NewBasicPodManager(kubepod.NewBasicMirrorClient(klet.kubeClient), secretManager, configMapManager) if kubeCfg.RemoteRuntimeEndpoint != "" { // kubeCfg.RemoteImageEndpoint is same as kubeCfg.RemoteRuntimeEndpoint if not explicitly specified @@ -717,7 +720,7 @@ func NewMainKubelet(kubeCfg *componentconfig.KubeletConfiguration, kubeDeps *Kub kubeDeps.Recorder) klet.volumePluginMgr, err = - NewInitializedVolumePluginMgr(klet, secretManager, kubeDeps.VolumePlugins) + NewInitializedVolumePluginMgr(klet, secretManager, configMapManager, kubeDeps.VolumePlugins) if err != nil { return nil, err } @@ -917,6 +920,9 @@ type Kubelet struct { // Secret manager. secretManager secret.Manager + // ConfigMap manager. + configMapManager configmap.Manager + // Cached MachineInfo returned by cadvisor. machineInfo *cadvisorapi.MachineInfo diff --git a/pkg/kubelet/kubelet_pods.go b/pkg/kubelet/kubelet_pods.go index b26449e954f..e4c1aa57380 100644 --- a/pkg/kubelet/kubelet_pods.go +++ b/pkg/kubelet/kubelet_pods.go @@ -446,7 +446,7 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container return result, fmt.Errorf("Couldn't get configMap %v/%v, no kubeClient defined", pod.Namespace, name) } optional := cm.Optional != nil && *cm.Optional - configMap, err = kl.kubeClient.Core().ConfigMaps(pod.Namespace).Get(name, metav1.GetOptions{}) + configMap, err = kl.configMapManager.GetConfigMap(pod.Namespace, name) if err != nil { if errors.IsNotFound(err) && optional { // ignore error when marked optional @@ -554,7 +554,7 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container if kl.kubeClient == nil { return result, fmt.Errorf("Couldn't get configMap %v/%v, no kubeClient defined", pod.Namespace, name) } - configMap, err = kl.kubeClient.Core().ConfigMaps(pod.Namespace).Get(name, metav1.GetOptions{}) + configMap, err = kl.configMapManager.GetConfigMap(pod.Namespace, name) if err != nil { if errors.IsNotFound(err) && optional { // ignore error when marked optional diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index 00e3a9340ca..a2c63c30d8a 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -46,6 +46,7 @@ import ( cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing" "k8s.io/kubernetes/pkg/kubelet/cm" "k8s.io/kubernetes/pkg/kubelet/config" + "k8s.io/kubernetes/pkg/kubelet/configmap" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" containertest "k8s.io/kubernetes/pkg/kubelet/container/testing" "k8s.io/kubernetes/pkg/kubelet/eviction" @@ -208,7 +209,9 @@ func newTestKubeletWithImageList( fakeMirrorClient := podtest.NewFakeMirrorClient() secretManager := secret.NewSimpleSecretManager(kubelet.kubeClient) kubelet.secretManager = secretManager - kubelet.podManager = kubepod.NewBasicPodManager(fakeMirrorClient, kubelet.secretManager) + configMapManager := configmap.NewSimpleConfigMapManager(kubelet.kubeClient) + kubelet.configMapManager = configMapManager + kubelet.podManager = kubepod.NewBasicPodManager(fakeMirrorClient, kubelet.secretManager, kubelet.configMapManager) kubelet.statusManager = status.NewManager(fakeKubeClient, kubelet.podManager, &statustest.FakePodDeletionSafetyProvider{}) diskSpaceManager, err := newDiskSpaceManager(mockCadvisor, DiskSpacePolicy{}) if err != nil { @@ -276,7 +279,7 @@ func newTestKubeletWithImageList( plug := &volumetest.FakeVolumePlugin{PluginName: "fake", Host: nil} kubelet.volumePluginMgr, err = - NewInitializedVolumePluginMgr(kubelet, kubelet.secretManager, []volume.VolumePlugin{plug}) + NewInitializedVolumePluginMgr(kubelet, kubelet.secretManager, kubelet.configMapManager, []volume.VolumePlugin{plug}) require.NoError(t, err, "Failed to initialize VolumePluginMgr") kubelet.mounter = &mount.FakeMounter{} diff --git a/pkg/kubelet/pod/BUILD b/pkg/kubelet/pod/BUILD index 999d6dfeada..48e9e30b827 100644 --- a/pkg/kubelet/pod/BUILD +++ b/pkg/kubelet/pod/BUILD @@ -18,6 +18,7 @@ go_library( deps = [ "//pkg/api/v1:go_default_library", "//pkg/client/clientset_generated/clientset:go_default_library", + "//pkg/kubelet/configmap:go_default_library", "//pkg/kubelet/container:go_default_library", "//pkg/kubelet/secret:go_default_library", "//pkg/kubelet/types:go_default_library", @@ -38,6 +39,7 @@ go_test( tags = ["automanaged"], deps = [ "//pkg/api/v1:go_default_library", + "//pkg/kubelet/configmap:go_default_library", "//pkg/kubelet/container:go_default_library", "//pkg/kubelet/pod/testing:go_default_library", "//pkg/kubelet/secret:go_default_library", diff --git a/pkg/kubelet/pod/pod_manager.go b/pkg/kubelet/pod/pod_manager.go index dd069b0fa3e..f2a3f94470b 100644 --- a/pkg/kubelet/pod/pod_manager.go +++ b/pkg/kubelet/pod/pod_manager.go @@ -21,6 +21,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/kubelet/configmap" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" "k8s.io/kubernetes/pkg/kubelet/secret" ) @@ -113,17 +114,19 @@ type basicManager struct { // Mirror pod UID to pod UID map. translationByUID map[types.UID]types.UID - // basicManager is keeping secretManager up-to-date. - secretManager secret.Manager + // basicManager is keeping secretManager and configMapManager up-to-date. + secretManager secret.Manager + configMapManager configmap.Manager // A mirror pod client to create/delete mirror pods. MirrorClient } // NewBasicPodManager returns a functional Manager. -func NewBasicPodManager(client MirrorClient, secretManager secret.Manager) Manager { +func NewBasicPodManager(client MirrorClient, secretManager secret.Manager, configMapManager configmap.Manager) Manager { pm := &basicManager{} pm.secretManager = secretManager + pm.configMapManager = configMapManager pm.MirrorClient = client pm.SetPods(nil) return pm @@ -163,6 +166,11 @@ func (pm *basicManager) updatePodsInternal(pods ...*v1.Pod) { // not register pod, as it doesn't really matter. pm.secretManager.RegisterPod(pod) } + if pm.configMapManager != nil { + // TODO: Consider detecting only status update and in such case do + // not register pod, as it doesn't really matter. + pm.configMapManager.RegisterPod(pod) + } podFullName := kubecontainer.GetPodFullName(pod) if IsMirrorPod(pod) { pm.mirrorPodByUID[pod.UID] = pod @@ -186,6 +194,9 @@ func (pm *basicManager) DeletePod(pod *v1.Pod) { if pm.secretManager != nil { pm.secretManager.UnregisterPod(pod) } + if pm.configMapManager != nil { + pm.configMapManager.UnregisterPod(pod) + } podFullName := kubecontainer.GetPodFullName(pod) if IsMirrorPod(pod) { delete(pm.mirrorPodByUID, pod.UID) diff --git a/pkg/kubelet/pod/pod_manager_test.go b/pkg/kubelet/pod/pod_manager_test.go index 06dab024b5d..cb17725d528 100644 --- a/pkg/kubelet/pod/pod_manager_test.go +++ b/pkg/kubelet/pod/pod_manager_test.go @@ -23,6 +23,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/kubelet/configmap" podtest "k8s.io/kubernetes/pkg/kubelet/pod/testing" "k8s.io/kubernetes/pkg/kubelet/secret" kubetypes "k8s.io/kubernetes/pkg/kubelet/types" @@ -32,7 +33,8 @@ import ( func newTestManager() (*basicManager, *podtest.FakeMirrorClient) { fakeMirrorClient := podtest.NewFakeMirrorClient() secretManager := secret.NewFakeManager() - manager := NewBasicPodManager(fakeMirrorClient, secretManager).(*basicManager) + configMapManager := configmap.NewFakeManager() + manager := NewBasicPodManager(fakeMirrorClient, secretManager, configMapManager).(*basicManager) return manager, fakeMirrorClient } diff --git a/pkg/kubelet/prober/common_test.go b/pkg/kubelet/prober/common_test.go index 409dbdf4236..0dc4e70bf05 100644 --- a/pkg/kubelet/prober/common_test.go +++ b/pkg/kubelet/prober/common_test.go @@ -99,7 +99,7 @@ func setTestProbe(pod *v1.Pod, probeType probeType, probeSpec v1.Probe) { func newTestManager() *manager { refManager := kubecontainer.NewRefManager() refManager.SetRef(testContainerID, &v1.ObjectReference{}) // Suppress prober warnings. - podManager := kubepod.NewBasicPodManager(nil, nil) + podManager := kubepod.NewBasicPodManager(nil, nil, nil) // Add test pod to pod manager, so that status manager can get the pod from pod manager if needed. podManager.AddPod(getTestPod()) m := NewManager( diff --git a/pkg/kubelet/prober/worker_test.go b/pkg/kubelet/prober/worker_test.go index da4a523a1dc..ccb21556fab 100644 --- a/pkg/kubelet/prober/worker_test.go +++ b/pkg/kubelet/prober/worker_test.go @@ -118,7 +118,7 @@ func TestDoProbe(t *testing.T) { } // Clean up. - m.statusManager = status.NewManager(&fake.Clientset{}, kubepod.NewBasicPodManager(nil, nil), &statustest.FakePodDeletionSafetyProvider{}) + m.statusManager = status.NewManager(&fake.Clientset{}, kubepod.NewBasicPodManager(nil, nil, nil), &statustest.FakePodDeletionSafetyProvider{}) resultsManager(m, probeType).Remove(testContainerID) } } diff --git a/pkg/kubelet/runonce_test.go b/pkg/kubelet/runonce_test.go index 99d932b7ac8..d23a79f3a7a 100644 --- a/pkg/kubelet/runonce_test.go +++ b/pkg/kubelet/runonce_test.go @@ -34,6 +34,7 @@ import ( "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake" cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing" "k8s.io/kubernetes/pkg/kubelet/cm" + "k8s.io/kubernetes/pkg/kubelet/configmap" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" containertest "k8s.io/kubernetes/pkg/kubelet/container/testing" "k8s.io/kubernetes/pkg/kubelet/eviction" @@ -63,8 +64,9 @@ func TestRunOnce(t *testing.T) { Capacity: 10 * mb, }, nil) fakeSecretManager := secret.NewFakeManager() + fakeConfigMapManager := configmap.NewFakeManager() podManager := kubepod.NewBasicPodManager( - podtest.NewFakeMirrorClient(), fakeSecretManager) + podtest.NewFakeMirrorClient(), fakeSecretManager, fakeConfigMapManager) diskSpaceManager, _ := newDiskSpaceManager(cadvisor, DiskSpacePolicy{}) fakeRuntime := &containertest.FakeRuntime{} basePath, err := utiltesting.MkTmpdir("kubelet") @@ -93,7 +95,7 @@ func TestRunOnce(t *testing.T) { plug := &volumetest.FakeVolumePlugin{PluginName: "fake", Host: nil} kb.volumePluginMgr, err = - NewInitializedVolumePluginMgr(kb, fakeSecretManager, []volume.VolumePlugin{plug}) + NewInitializedVolumePluginMgr(kb, fakeSecretManager, fakeConfigMapManager, []volume.VolumePlugin{plug}) if err != nil { t.Fatalf("failed to initialize VolumePluginMgr: %v", err) } diff --git a/pkg/kubelet/status/BUILD b/pkg/kubelet/status/BUILD index 20ef87777a1..0c2a9a01734 100644 --- a/pkg/kubelet/status/BUILD +++ b/pkg/kubelet/status/BUILD @@ -48,6 +48,7 @@ go_test( "//pkg/api/v1/pod:go_default_library", "//pkg/client/clientset_generated/clientset:go_default_library", "//pkg/client/clientset_generated/clientset/fake:go_default_library", + "//pkg/kubelet/configmap:go_default_library", "//pkg/kubelet/container:go_default_library", "//pkg/kubelet/pod:go_default_library", "//pkg/kubelet/pod/testing:go_default_library", diff --git a/pkg/kubelet/status/status_manager_test.go b/pkg/kubelet/status/status_manager_test.go index b51d1ced28d..3c1bc7f91d3 100644 --- a/pkg/kubelet/status/status_manager_test.go +++ b/pkg/kubelet/status/status_manager_test.go @@ -36,6 +36,7 @@ import ( podutil "k8s.io/kubernetes/pkg/api/v1/pod" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake" + kubeconfigmap "k8s.io/kubernetes/pkg/kubelet/configmap" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" kubepod "k8s.io/kubernetes/pkg/kubelet/pod" podtest "k8s.io/kubernetes/pkg/kubelet/pod/testing" @@ -74,7 +75,7 @@ func (m *manager) testSyncBatch() { } func newTestManager(kubeClient clientset.Interface) *manager { - podManager := kubepod.NewBasicPodManager(podtest.NewFakeMirrorClient(), kubesecret.NewFakeManager()) + podManager := kubepod.NewBasicPodManager(podtest.NewFakeMirrorClient(), kubesecret.NewFakeManager(), kubeconfigmap.NewFakeManager()) podManager.AddPod(getTestPod()) return NewManager(kubeClient, podManager, &statustest.FakePodDeletionSafetyProvider{}).(*manager) } diff --git a/pkg/kubelet/volume_host.go b/pkg/kubelet/volume_host.go index 87d625f33a3..24f3acf8513 100644 --- a/pkg/kubelet/volume_host.go +++ b/pkg/kubelet/volume_host.go @@ -24,6 +24,7 @@ import ( "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" "k8s.io/kubernetes/pkg/cloudprovider" + "k8s.io/kubernetes/pkg/kubelet/configmap" "k8s.io/kubernetes/pkg/kubelet/secret" "k8s.io/kubernetes/pkg/util/io" "k8s.io/kubernetes/pkg/util/mount" @@ -39,11 +40,13 @@ import ( func NewInitializedVolumePluginMgr( kubelet *Kubelet, secretManager secret.Manager, + configMapManager configmap.Manager, plugins []volume.VolumePlugin) (*volume.VolumePluginMgr, error) { kvh := &kubeletVolumeHost{ - kubelet: kubelet, - volumePluginMgr: volume.VolumePluginMgr{}, - secretManager: secretManager, + kubelet: kubelet, + volumePluginMgr: volume.VolumePluginMgr{}, + secretManager: secretManager, + configMapManager: configMapManager, } if err := kvh.volumePluginMgr.InitPlugins(plugins, kvh); err != nil { @@ -63,9 +66,10 @@ func (kvh *kubeletVolumeHost) GetPluginDir(pluginName string) string { } type kubeletVolumeHost struct { - kubelet *Kubelet - volumePluginMgr volume.VolumePluginMgr - secretManager secret.Manager + kubelet *Kubelet + volumePluginMgr volume.VolumePluginMgr + secretManager secret.Manager + configMapManager configmap.Manager } func (kvh *kubeletVolumeHost) GetPodVolumeDir(podUID types.UID, pluginName string, volumeName string) string { @@ -141,6 +145,10 @@ func (kvh *kubeletVolumeHost) GetSecretFunc() func(namespace, name string) (*v1. return kvh.secretManager.GetSecret } +func (kvh *kubeletVolumeHost) GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error) { + return kvh.configMapManager.GetConfigMap +} + func (kvh *kubeletVolumeHost) GetNodeLabels() (map[string]string, error) { node, err := kvh.kubelet.GetNode() if err != nil { diff --git a/pkg/kubelet/volumemanager/BUILD b/pkg/kubelet/volumemanager/BUILD index 855089f3a87..46ee7c04cce 100644 --- a/pkg/kubelet/volumemanager/BUILD +++ b/pkg/kubelet/volumemanager/BUILD @@ -47,6 +47,7 @@ go_test( "//pkg/client/clientset_generated/clientset:go_default_library", "//pkg/client/clientset_generated/clientset/fake:go_default_library", "//pkg/kubelet/config:go_default_library", + "//pkg/kubelet/configmap:go_default_library", "//pkg/kubelet/container/testing:go_default_library", "//pkg/kubelet/pod:go_default_library", "//pkg/kubelet/pod/testing:go_default_library", diff --git a/pkg/kubelet/volumemanager/populator/BUILD b/pkg/kubelet/volumemanager/populator/BUILD index e4596291bd8..b1b85188e05 100644 --- a/pkg/kubelet/volumemanager/populator/BUILD +++ b/pkg/kubelet/volumemanager/populator/BUILD @@ -53,6 +53,7 @@ go_test( deps = [ "//pkg/api/v1:go_default_library", "//pkg/client/clientset_generated/clientset/fake:go_default_library", + "//pkg/kubelet/configmap:go_default_library", "//pkg/kubelet/container/testing:go_default_library", "//pkg/kubelet/pod:go_default_library", "//pkg/kubelet/pod/testing:go_default_library", diff --git a/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go b/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go index 66d74ed0e71..79d6da5ae76 100644 --- a/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go +++ b/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go @@ -23,6 +23,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake" + "k8s.io/kubernetes/pkg/kubelet/configmap" containertest "k8s.io/kubernetes/pkg/kubelet/container/testing" kubepod "k8s.io/kubernetes/pkg/kubelet/pod" podtest "k8s.io/kubernetes/pkg/kubelet/pod/testing" @@ -40,8 +41,9 @@ func TestFindAndAddNewPods_FindAndRemoveDeletedPods(t *testing.T) { fakeClient := &fake.Clientset{} fakeSecretManager := secret.NewFakeManager() + fakeConfigMapManager := configmap.NewFakeManager() fakePodManager := kubepod.NewBasicPodManager( - podtest.NewFakeMirrorClient(), fakeSecretManager) + podtest.NewFakeMirrorClient(), fakeSecretManager, fakeConfigMapManager) fakesDSW := cache.NewDesiredStateOfWorld(fakeVolumePluginMgr) fakeRuntime := &containertest.FakeRuntime{} diff --git a/pkg/kubelet/volumemanager/volume_manager_test.go b/pkg/kubelet/volumemanager/volume_manager_test.go index 0f523c90593..4794ceaa7d4 100644 --- a/pkg/kubelet/volumemanager/volume_manager_test.go +++ b/pkg/kubelet/volumemanager/volume_manager_test.go @@ -32,6 +32,7 @@ import ( "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake" "k8s.io/kubernetes/pkg/kubelet/config" + "k8s.io/kubernetes/pkg/kubelet/configmap" containertest "k8s.io/kubernetes/pkg/kubelet/container/testing" "k8s.io/kubernetes/pkg/kubelet/pod" kubepod "k8s.io/kubernetes/pkg/kubelet/pod" @@ -56,7 +57,7 @@ func TestGetMountedVolumesForPodAndGetVolumesInUse(t *testing.T) { t.Fatalf("can't make a temp dir: %v", err) } defer os.RemoveAll(tmpDir) - podManager := kubepod.NewBasicPodManager(podtest.NewFakeMirrorClient(), secret.NewFakeManager()) + podManager := kubepod.NewBasicPodManager(podtest.NewFakeMirrorClient(), secret.NewFakeManager(), configmap.NewFakeManager()) node, pod, pv, claim := createObjects() kubeClient := fake.NewSimpleClientset(node, pod, pv, claim) @@ -101,7 +102,7 @@ func TestGetExtraSupplementalGroupsForPod(t *testing.T) { t.Fatalf("can't make a temp dir: %v", err) } defer os.RemoveAll(tmpDir) - podManager := kubepod.NewBasicPodManager(podtest.NewFakeMirrorClient(), secret.NewFakeManager()) + podManager := kubepod.NewBasicPodManager(podtest.NewFakeMirrorClient(), secret.NewFakeManager(), configmap.NewFakeManager()) node, pod, _, claim := createObjects() diff --git a/pkg/volume/configmap/configmap.go b/pkg/volume/configmap/configmap.go index 1134a068b6a..4e869293bd7 100644 --- a/pkg/volume/configmap/configmap.go +++ b/pkg/volume/configmap/configmap.go @@ -42,13 +42,15 @@ const ( // configMapPlugin implements the VolumePlugin interface. type configMapPlugin struct { - host volume.VolumeHost + host volume.VolumeHost + getConfigMap func(namespace, name string) (*v1.ConfigMap, error) } var _ volume.VolumePlugin = &configMapPlugin{} func (plugin *configMapPlugin) Init(host volume.VolumeHost) error { plugin.host = host + plugin.getConfigMap = host.GetConfigMapFunc() return nil } @@ -86,14 +88,32 @@ func (plugin *configMapPlugin) SupportsBulkVolumeVerification() bool { func (plugin *configMapPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, opts volume.VolumeOptions) (volume.Mounter, error) { return &configMapVolumeMounter{ - configMapVolume: &configMapVolume{spec.Name(), pod.UID, plugin, plugin.host.GetMounter(), plugin.host.GetWriter(), volume.MetricsNil{}}, - source: *spec.Volume.ConfigMap, - pod: *pod, - opts: &opts}, nil + configMapVolume: &configMapVolume{ + spec.Name(), + pod.UID, + plugin, + plugin.host.GetMounter(), + plugin.host.GetWriter(), + volume.MetricsNil{}, + }, + source: *spec.Volume.ConfigMap, + pod: *pod, + opts: &opts, + getConfigMap: plugin.getConfigMap, + }, nil } func (plugin *configMapPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) { - return &configMapVolumeUnmounter{&configMapVolume{volName, podUID, plugin, plugin.host.GetMounter(), plugin.host.GetWriter(), volume.MetricsNil{}}}, nil + return &configMapVolumeUnmounter{ + &configMapVolume{ + volName, + podUID, + plugin, + plugin.host.GetMounter(), + plugin.host.GetWriter(), + volume.MetricsNil{}, + }, + }, nil } func (plugin *configMapPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { @@ -126,9 +146,10 @@ func (sv *configMapVolume) GetPath() string { type configMapVolumeMounter struct { *configMapVolume - source v1.ConfigMapVolumeSource - pod v1.Pod - opts *volume.VolumeOptions + source v1.ConfigMapVolumeSource + pod v1.Pod + opts *volume.VolumeOptions + getConfigMap func(namespace, name string) (*v1.ConfigMap, error) } var _ volume.Mounter = &configMapVolumeMounter{} @@ -174,13 +195,8 @@ func (b *configMapVolumeMounter) SetUpAt(dir string, fsGroup *types.UnixGroupID) return err } - kubeClient := b.plugin.host.GetKubeClient() - if kubeClient == nil { - return fmt.Errorf("Cannot setup configMap volume %v because kube client is not configured", b.volName) - } - optional := b.source.Optional != nil && *b.source.Optional - configMap, err := kubeClient.Core().ConfigMaps(b.pod.Namespace).Get(b.source.Name, metav1.GetOptions{}) + configMap, err := b.getConfigMap(b.pod.Namespace, b.source.Name) if err != nil { if !(errors.IsNotFound(err) && optional) { glog.Errorf("Couldn't get configMap %v/%v: %v", b.pod.Namespace, b.source.Name, err) diff --git a/pkg/volume/plugins.go b/pkg/volume/plugins.go index a6abfd3cd2d..41721d1eeaf 100644 --- a/pkg/volume/plugins.go +++ b/pkg/volume/plugins.go @@ -233,6 +233,9 @@ type VolumeHost interface { // Returns a function that returns a secret. GetSecretFunc() func(namespace, name string) (*v1.Secret, error) + // Returns a function that returns a configmap. + GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error) + // Returns the labels on the node GetNodeLabels() (map[string]string, error) } diff --git a/pkg/volume/projected/projected.go b/pkg/volume/projected/projected.go index 310d8674361..390e6eea2d3 100644 --- a/pkg/volume/projected/projected.go +++ b/pkg/volume/projected/projected.go @@ -45,8 +45,9 @@ const ( ) type projectedPlugin struct { - host volume.VolumeHost - getSecret func(namespace, name string) (*v1.Secret, error) + host volume.VolumeHost + getSecret func(namespace, name string) (*v1.Secret, error) + getConfigMap func(namespace, name string) (*v1.ConfigMap, error) } var _ volume.VolumePlugin = &projectedPlugin{} @@ -68,6 +69,7 @@ func getPath(uid types.UID, volName string, host volume.VolumeHost) string { func (plugin *projectedPlugin) Init(host volume.VolumeHost) error { plugin.host = host plugin.getSecret = host.GetSecretFunc() + plugin.getConfigMap = host.GetConfigMapFunc() return nil } @@ -235,10 +237,10 @@ func (s *projectedVolumeMounter) collectData() (map[string]volumeutil.FileProjec secretapi, err := s.plugin.getSecret(s.pod.Namespace, source.Secret.Name) if err != nil { if !(errors.IsNotFound(err) && optional) { - glog.Errorf("Couldn't get secret %v/%v", s.pod.Namespace, source.Secret.Name) + glog.Errorf("Couldn't get secret %v/%v: %v", s.pod.Namespace, source.Secret.Name, err) errlist = append(errlist, err) + continue } - secretapi = &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ Namespace: s.pod.Namespace, @@ -248,17 +250,16 @@ func (s *projectedVolumeMounter) collectData() (map[string]volumeutil.FileProjec } secretPayload, err := secret.MakePayload(source.Secret.Items, secretapi, s.source.DefaultMode, optional) if err != nil { - glog.Errorf("Couldn't get secret %v/%v: %v", s.pod.Namespace, source.Secret.Name, err) + glog.Errorf("Couldn't get secret payload %v/%v: %v", s.pod.Namespace, source.Secret.Name, err) errlist = append(errlist, err) continue } - for k, v := range secretPayload { payload[k] = v } } else if source.ConfigMap != nil { optional := source.ConfigMap.Optional != nil && *source.ConfigMap.Optional - configMap, err := kubeClient.Core().ConfigMaps(s.pod.Namespace).Get(source.ConfigMap.Name, metav1.GetOptions{}) + configMap, err := s.plugin.getConfigMap(s.pod.Namespace, source.ConfigMap.Name) if err != nil { if !(errors.IsNotFound(err) && optional) { glog.Errorf("Couldn't get configMap %v/%v: %v", s.pod.Namespace, source.ConfigMap.Name, err) @@ -274,6 +275,7 @@ func (s *projectedVolumeMounter) collectData() (map[string]volumeutil.FileProjec } configMapPayload, err := configmap.MakePayload(source.ConfigMap.Items, configMap, s.source.DefaultMode, optional) if err != nil { + glog.Errorf("Couldn't get configMap payload %v/%v: %v", s.pod.Namespace, source.ConfigMap.Name, err) errlist = append(errlist, err) continue } diff --git a/pkg/volume/projected/projected_test.go b/pkg/volume/projected/projected_test.go index a8d1f4a8377..131ff907516 100644 --- a/pkg/volume/projected/projected_test.go +++ b/pkg/volume/projected/projected_test.go @@ -505,7 +505,8 @@ func TestCollectDataWithConfigMap(t *testing.T) { sources: source.Sources, podUID: pod.UID, plugin: &projectedPlugin{ - host: host, + host: host, + getConfigMap: host.GetConfigMapFunc(), }, }, source: *source, diff --git a/pkg/volume/secret/secret.go b/pkg/volume/secret/secret.go index ae638bb4f08..40af0d20280 100644 --- a/pkg/volume/secret/secret.go +++ b/pkg/volume/secret/secret.go @@ -198,7 +198,7 @@ func (b *secretVolumeMounter) SetUpAt(dir string, fsGroup *types.UnixGroupID) er secret, err := b.getSecret(b.pod.Namespace, b.source.SecretName) if err != nil { if !(errors.IsNotFound(err) && optional) { - glog.Errorf("Couldn't get secret %v/%v", b.pod.Namespace, b.source.SecretName) + glog.Errorf("Couldn't get secret %v/%v: %v", b.pod.Namespace, b.source.SecretName, err) return err } secret = &v1.Secret{ diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index 2e489b7a4b8..e80a8a5271d 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -134,6 +134,12 @@ func (f *fakeVolumeHost) GetSecretFunc() func(namespace, name string) (*v1.Secre } } +func (f *fakeVolumeHost) GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error) { + return func(namespace, name string) (*v1.ConfigMap, error) { + return f.kubeClient.Core().ConfigMaps(namespace).Get(name, metav1.GetOptions{}) + } +} + func (f *fakeVolumeHost) GetNodeLabels() (map[string]string, error) { return map[string]string{"test-label": "test-value"}, nil }