vendor files

This commit is contained in:
Serguei Bezverkhi
2018-01-09 13:57:14 -05:00
parent 558bc6c02a
commit 7b24313bd6
16547 changed files with 4527373 additions and 0 deletions

View File

@ -0,0 +1,59 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"expand_controller.go",
"pvc_populator.go",
"sync_volume_resize.go",
],
importpath = "k8s.io/kubernetes/pkg/controller/volume/expand",
deps = [
"//pkg/cloudprovider:go_default_library",
"//pkg/controller:go_default_library",
"//pkg/controller/volume/expand/cache:go_default_library",
"//pkg/controller/volume/expand/util:go_default_library",
"//pkg/util/goroutinemap/exponentialbackoff:go_default_library",
"//pkg/util/io:go_default_library",
"//pkg/util/mount:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/util:go_default_library",
"//pkg/volume/util/operationexecutor: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/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/client-go/informers/core/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
"//vendor/k8s.io/client-go/listers/core/v1:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/k8s.io/client-go/tools/record:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/controller/volume/expand/cache:all-srcs",
"//pkg/controller/volume/expand/util:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -0,0 +1,4 @@
approvers:
- saad-ali
- jsafrane
- gnufied

View File

@ -0,0 +1,52 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["volume_resize_map.go"],
importpath = "k8s.io/kubernetes/pkg/controller/volume/expand/cache",
deps = [
"//pkg/controller/volume/expand/util:go_default_library",
"//pkg/util/strings:go_default_library",
"//pkg/volume/util/types: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/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
go_test(
name = "go_default_test",
srcs = ["volume_resize_map_test.go"],
importpath = "k8s.io/kubernetes/pkg/controller/volume/expand/cache",
library = ":go_default_library",
deps = [
"//pkg/volume/util/types:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
],
)

View File

@ -0,0 +1,216 @@
/*
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 cache
import (
"encoding/json"
"fmt"
"sync"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
commontypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/pkg/controller/volume/expand/util"
"k8s.io/kubernetes/pkg/util/strings"
"k8s.io/kubernetes/pkg/volume/util/types"
)
// VolumeResizeMap defines an interface that serves as a cache for holding pending resizing requests
type VolumeResizeMap interface {
// AddPVCUpdate adds pvc for resizing
AddPVCUpdate(pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume)
// DeletePVC deletes pvc that is scheduled for resizing
DeletePVC(pvc *v1.PersistentVolumeClaim)
// GetPVCsWithResizeRequest returns all pending pvc resize requests
GetPVCsWithResizeRequest() []*PVCWithResizeRequest
// MarkAsResized marks a pvc as fully resized
MarkAsResized(*PVCWithResizeRequest, resource.Quantity) error
// UpdatePVSize updates just pv size after cloudprovider resizing is successful
UpdatePVSize(*PVCWithResizeRequest, resource.Quantity) error
}
type volumeResizeMap struct {
// map of unique pvc name and resize requests that are pending or inflight
pvcrs map[types.UniquePVCName]*PVCWithResizeRequest
// kube client for making API calls
kubeClient clientset.Interface
// for guarding access to pvcrs map
sync.RWMutex
}
// PVCWithResizeRequest struct defines data structure that stores state needed for
// performing file system resize
type PVCWithResizeRequest struct {
// PVC that needs to be resized
PVC *v1.PersistentVolumeClaim
// persistentvolume
PersistentVolume *v1.PersistentVolume
// Current volume size
CurrentSize resource.Quantity
// Expended volume size
ExpectedSize resource.Quantity
}
// UniquePVCKey returns unique key of the PVC based on its UID
func (pvcr *PVCWithResizeRequest) UniquePVCKey() types.UniquePVCName {
return types.UniquePVCName(pvcr.PVC.UID)
}
// QualifiedName returns namespace and name combination of the PVC
func (pvcr *PVCWithResizeRequest) QualifiedName() string {
return strings.JoinQualifiedName(pvcr.PVC.Namespace, pvcr.PVC.Name)
}
// NewVolumeResizeMap returns new VolumeResizeMap which acts as a cache
// for holding pending resize requests.
func NewVolumeResizeMap(kubeClient clientset.Interface) VolumeResizeMap {
resizeMap := &volumeResizeMap{}
resizeMap.pvcrs = make(map[types.UniquePVCName]*PVCWithResizeRequest)
resizeMap.kubeClient = kubeClient
return resizeMap
}
// AddPVCUpdate adds pvc for resizing
// This function intentionally allows addition of PVCs for which pv.Spec.Size >= pvc.Spec.Size,
// the reason being - lack of transaction in k8s means after successful resize, we can't guarantee that when we update PV,
// pvc update will be successful too and after resize we alyways update PV first.
// If for some reason we weren't able to update PVC after successful resize, then we are going to reprocess
// the PVC and hopefully after a no-op resize in volume plugin, PVC will be updated with right values as well.
func (resizeMap *volumeResizeMap) AddPVCUpdate(pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume) {
if pv.Spec.ClaimRef == nil || pvc.Namespace != pv.Spec.ClaimRef.Namespace || pvc.Name != pv.Spec.ClaimRef.Name {
glog.V(4).Infof("Persistent Volume is not bound to PVC being updated : %s", util.ClaimToClaimKey(pvc))
return
}
if pvc.Status.Phase != v1.ClaimBound {
return
}
resizeMap.Lock()
defer resizeMap.Unlock()
pvcSize := pvc.Spec.Resources.Requests[v1.ResourceStorage]
pvcStatusSize := pvc.Status.Capacity[v1.ResourceStorage]
if pvcStatusSize.Cmp(pvcSize) >= 0 {
return
}
glog.V(4).Infof("Adding pvc %s with Size %s/%s for resizing", util.ClaimToClaimKey(pvc), pvcSize.String(), pvcStatusSize.String())
pvcRequest := &PVCWithResizeRequest{
PVC: pvc,
CurrentSize: pvcStatusSize,
ExpectedSize: pvcSize,
PersistentVolume: pv,
}
resizeMap.pvcrs[types.UniquePVCName(pvc.UID)] = pvcRequest
}
// GetPVCsWithResizeRequest returns all pending pvc resize requests
func (resizeMap *volumeResizeMap) GetPVCsWithResizeRequest() []*PVCWithResizeRequest {
resizeMap.Lock()
defer resizeMap.Unlock()
pvcrs := []*PVCWithResizeRequest{}
for _, pvcr := range resizeMap.pvcrs {
pvcrs = append(pvcrs, pvcr)
}
// Empty out pvcrs map, we will add back failed resize requests later
resizeMap.pvcrs = map[types.UniquePVCName]*PVCWithResizeRequest{}
return pvcrs
}
// DeletePVC removes given pvc object from list of pvcs that needs resizing.
// deleting a pvc in this map doesn't affect operations that are already inflight.
func (resizeMap *volumeResizeMap) DeletePVC(pvc *v1.PersistentVolumeClaim) {
resizeMap.Lock()
defer resizeMap.Unlock()
pvcUniqueName := types.UniquePVCName(pvc.UID)
glog.V(5).Infof("Removing PVC %v from resize map", pvcUniqueName)
delete(resizeMap.pvcrs, pvcUniqueName)
}
// MarkAsResized marks a pvc as fully resized
func (resizeMap *volumeResizeMap) MarkAsResized(pvcr *PVCWithResizeRequest, newSize resource.Quantity) error {
resizeMap.Lock()
defer resizeMap.Unlock()
emptyCondition := []v1.PersistentVolumeClaimCondition{}
err := resizeMap.updatePVCCapacityAndConditions(pvcr, newSize, emptyCondition)
if err != nil {
glog.V(4).Infof("Error updating PV spec capacity for volume %q with : %v", pvcr.QualifiedName(), err)
return err
}
return nil
}
// UpdatePVSize updates just pv size after cloudprovider resizing is successful
func (resizeMap *volumeResizeMap) UpdatePVSize(pvcr *PVCWithResizeRequest, newSize resource.Quantity) error {
resizeMap.Lock()
defer resizeMap.Unlock()
oldPv := pvcr.PersistentVolume
pvClone := oldPv.DeepCopy()
oldData, err := json.Marshal(pvClone)
if err != nil {
return fmt.Errorf("Unexpected error marshaling PV : %q with error %v", pvClone.Name, err)
}
pvClone.Spec.Capacity[v1.ResourceStorage] = newSize
newData, err := json.Marshal(pvClone)
if err != nil {
return fmt.Errorf("Unexpected error marshaling PV : %q with error %v", pvClone.Name, err)
}
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, pvClone)
if err != nil {
return fmt.Errorf("Error Creating two way merge patch for PV : %q with error %v", pvClone.Name, err)
}
_, updateErr := resizeMap.kubeClient.CoreV1().PersistentVolumes().Patch(pvClone.Name, commontypes.StrategicMergePatchType, patchBytes)
if updateErr != nil {
glog.V(4).Infof("Error updating pv %q with error : %v", pvClone.Name, updateErr)
return updateErr
}
return nil
}
func (resizeMap *volumeResizeMap) updatePVCCapacityAndConditions(pvcr *PVCWithResizeRequest, newSize resource.Quantity, pvcConditions []v1.PersistentVolumeClaimCondition) error {
claimClone := pvcr.PVC.DeepCopy()
claimClone.Status.Capacity[v1.ResourceStorage] = newSize
claimClone.Status.Conditions = pvcConditions
_, updateErr := resizeMap.kubeClient.CoreV1().PersistentVolumeClaims(claimClone.Namespace).UpdateStatus(claimClone)
if updateErr != nil {
glog.V(4).Infof("updating PersistentVolumeClaim[%s] status: failed: %v", pvcr.QualifiedName(), updateErr)
return updateErr
}
return nil
}

View File

@ -0,0 +1,147 @@
/*
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 cache
import (
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/kubernetes/pkg/volume/util/types"
)
func Test_AddValidPVCUpdate(t *testing.T) {
claim := testVolumeClaim("foo", "ns", v1.PersistentVolumeClaimSpec{
AccessModes: []v1.PersistentVolumeAccessMode{
v1.ReadWriteOnce,
v1.ReadOnlyMany,
},
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): resource.MustParse("12G"),
},
},
VolumeName: "foo",
})
unboundClaim := claim.DeepCopy()
unboundClaim.Status.Phase = v1.ClaimPending
noResizeClaim := claim.DeepCopy()
noResizeClaim.Status.Capacity = v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): resource.MustParse("12G"),
}
boundPV := getPersistentVolume("foo", resource.MustParse("10G"), claim)
unboundPV := getPersistentVolume("foo", resource.MustParse("10G"), nil)
misboundPV := getPersistentVolume("foo", resource.MustParse("10G"), nil)
misboundPV.Spec.ClaimRef = &v1.ObjectReference{
Namespace: "someOtherNamespace",
Name: "someOtherName",
}
tests := []struct {
name string
pvc *v1.PersistentVolumeClaim
pv *v1.PersistentVolume
expectedPVCs int
}{
{
"validPVCUpdate",
claim,
boundPV,
1,
},
{
"noResizeRequired",
noResizeClaim,
boundPV,
0,
},
{
"unboundPVC",
unboundClaim,
boundPV,
0,
},
{
"unboundPV",
claim,
unboundPV,
0,
},
{
"misboundPV",
claim,
misboundPV,
0,
},
}
for _, test := range tests {
resizeMap := createTestVolumeResizeMap()
pvc := test.pvc.DeepCopy()
pv := test.pv.DeepCopy()
resizeMap.AddPVCUpdate(pvc, pv)
pvcr := resizeMap.GetPVCsWithResizeRequest()
if len(pvcr) != test.expectedPVCs {
t.Errorf("Test %q expected %d pvc resize request got %d", test.name, test.expectedPVCs, len(pvcr))
}
if test.expectedPVCs > 0 {
assert.Equal(t, resource.MustParse("12G"), pvcr[0].ExpectedSize, test.name)
}
assert.Equal(t, 0, len(resizeMap.pvcrs), test.name)
}
}
func createTestVolumeResizeMap() *volumeResizeMap {
fakeClient := &fake.Clientset{}
resizeMap := &volumeResizeMap{}
resizeMap.pvcrs = make(map[types.UniquePVCName]*PVCWithResizeRequest)
resizeMap.kubeClient = fakeClient
return resizeMap
}
func testVolumeClaim(name string, namespace string, spec v1.PersistentVolumeClaimSpec) *v1.PersistentVolumeClaim {
return &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace},
Spec: spec,
Status: v1.PersistentVolumeClaimStatus{
Phase: v1.ClaimBound,
},
}
}
func getPersistentVolume(volumeName string, capacity resource.Quantity, pvc *v1.PersistentVolumeClaim) *v1.PersistentVolume {
volume := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: volumeName},
Spec: v1.PersistentVolumeSpec{
Capacity: v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): capacity,
},
},
}
if pvc != nil {
volume.Spec.ClaimRef = &v1.ObjectReference{
Namespace: pvc.Namespace,
Name: pvc.Name,
}
}
return volume
}

View File

@ -0,0 +1,283 @@
/*
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 expand implements interfaces that attempt to resize a pvc
// by adding pvc to a volume resize map from which PVCs are picked and
// resized
package expand
import (
"fmt"
"net"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/runtime"
coreinformers "k8s.io/client-go/informers/core/v1"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
corelisters "k8s.io/client-go/listers/core/v1"
kcache "k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/kubernetes/pkg/cloudprovider"
"k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/controller/volume/expand/cache"
"k8s.io/kubernetes/pkg/util/io"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util/operationexecutor"
)
const (
// How often resizing loop runs
syncLoopPeriod time.Duration = 30 * time.Second
// How often pvc populator runs
populatorLoopPeriod time.Duration = 2 * time.Minute
)
// ExpandController expands the pvs
type ExpandController interface {
Run(stopCh <-chan struct{})
}
type expandController struct {
// kubeClient is the kube API client used by volumehost to communicate with
// the API server.
kubeClient clientset.Interface
// pvcLister is the shared PVC lister used to fetch and store PVC
// objects from the API server. It is shared with other controllers and
// therefore the PVC objects in its store should be treated as immutable.
pvcLister corelisters.PersistentVolumeClaimLister
pvcsSynced kcache.InformerSynced
pvLister corelisters.PersistentVolumeLister
pvSynced kcache.InformerSynced
// cloud provider used by volume host
cloud cloudprovider.Interface
// volumePluginMgr used to initialize and fetch volume plugins
volumePluginMgr volume.VolumePluginMgr
// recorder is used to record events in the API server
recorder record.EventRecorder
// Volume resize map of volumes that needs resizing
resizeMap cache.VolumeResizeMap
// Worker goroutine to process resize requests from resizeMap
syncResize SyncVolumeResize
// Operation executor
opExecutor operationexecutor.OperationExecutor
// populator for periodically polling all PVCs
pvcPopulator PVCPopulator
}
func NewExpandController(
kubeClient clientset.Interface,
pvcInformer coreinformers.PersistentVolumeClaimInformer,
pvInformer coreinformers.PersistentVolumeInformer,
cloud cloudprovider.Interface,
plugins []volume.VolumePlugin) (ExpandController, error) {
expc := &expandController{
kubeClient: kubeClient,
cloud: cloud,
pvcLister: pvcInformer.Lister(),
pvcsSynced: pvcInformer.Informer().HasSynced,
pvLister: pvInformer.Lister(),
pvSynced: pvInformer.Informer().HasSynced,
}
if err := expc.volumePluginMgr.InitPlugins(plugins, nil, expc); err != nil {
return nil, fmt.Errorf("Could not initialize volume plugins for Expand Controller : %+v", err)
}
eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(glog.Infof)
eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: v1core.New(kubeClient.CoreV1().RESTClient()).Events("")})
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "volume_expand"})
blkutil := util.NewBlockVolumePathHandler()
expc.opExecutor = operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
kubeClient,
&expc.volumePluginMgr,
recorder,
false,
blkutil))
expc.resizeMap = cache.NewVolumeResizeMap(expc.kubeClient)
pvcInformer.Informer().AddEventHandler(kcache.ResourceEventHandlerFuncs{
UpdateFunc: expc.pvcUpdate,
DeleteFunc: expc.deletePVC,
})
expc.syncResize = NewSyncVolumeResize(syncLoopPeriod, expc.opExecutor, expc.resizeMap, kubeClient)
expc.pvcPopulator = NewPVCPopulator(
populatorLoopPeriod,
expc.resizeMap,
expc.pvcLister,
expc.pvLister,
kubeClient)
return expc, nil
}
func (expc *expandController) Run(stopCh <-chan struct{}) {
defer runtime.HandleCrash()
glog.Infof("Starting expand controller")
defer glog.Infof("Shutting down expand controller")
if !controller.WaitForCacheSync("expand", stopCh, expc.pvcsSynced, expc.pvSynced) {
return
}
// Run volume sync work goroutine
go expc.syncResize.Run(stopCh)
// Start the pvc populator loop
go expc.pvcPopulator.Run(stopCh)
<-stopCh
}
func (expc *expandController) deletePVC(obj interface{}) {
pvc, ok := obj.(*v1.PersistentVolumeClaim)
if pvc == nil || !ok {
return
}
expc.resizeMap.DeletePVC(pvc)
}
func (expc *expandController) pvcUpdate(oldObj, newObj interface{}) {
oldPvc, ok := oldObj.(*v1.PersistentVolumeClaim)
if oldPvc == nil || !ok {
return
}
newPVC, ok := newObj.(*v1.PersistentVolumeClaim)
if newPVC == nil || !ok {
return
}
pv, err := getPersistentVolume(newPVC, expc.pvLister)
if err != nil {
glog.V(5).Infof("Error getting Persistent Volume for pvc %q : %v", newPVC.UID, err)
return
}
expc.resizeMap.AddPVCUpdate(newPVC, pv)
}
func getPersistentVolume(pvc *v1.PersistentVolumeClaim, pvLister corelisters.PersistentVolumeLister) (*v1.PersistentVolume, error) {
volumeName := pvc.Spec.VolumeName
pv, err := pvLister.Get(volumeName)
if err != nil {
return nil, fmt.Errorf("failed to find PV %q in PV informer cache with error : %v", volumeName, err)
}
return pv.DeepCopy(), nil
}
// Implementing VolumeHost interface
func (expc *expandController) GetPluginDir(pluginName string) string {
return ""
}
func (expc *expandController) GetVolumeDevicePluginDir(pluginName string) string {
return ""
}
func (expc *expandController) GetPodVolumeDir(podUID types.UID, pluginName string, volumeName string) string {
return ""
}
func (expc *expandController) GetPodVolumeDeviceDir(podUID types.UID, pluginName string) string {
return ""
}
func (expc *expandController) GetPodPluginDir(podUID types.UID, pluginName string) string {
return ""
}
func (expc *expandController) GetKubeClient() clientset.Interface {
return expc.kubeClient
}
func (expc *expandController) NewWrapperMounter(volName string, spec volume.Spec, pod *v1.Pod, opts volume.VolumeOptions) (volume.Mounter, error) {
return nil, fmt.Errorf("NewWrapperMounter not supported by expand controller's VolumeHost implementation")
}
func (expc *expandController) NewWrapperUnmounter(volName string, spec volume.Spec, podUID types.UID) (volume.Unmounter, error) {
return nil, fmt.Errorf("NewWrapperUnmounter not supported by expand controller's VolumeHost implementation")
}
func (expc *expandController) GetCloudProvider() cloudprovider.Interface {
return expc.cloud
}
func (expc *expandController) GetMounter(pluginName string) mount.Interface {
return nil
}
func (expc *expandController) GetExec(pluginName string) mount.Exec {
return mount.NewOsExec()
}
func (expc *expandController) GetWriter() io.Writer {
return nil
}
func (expc *expandController) GetHostName() string {
return ""
}
func (expc *expandController) GetHostIP() (net.IP, error) {
return nil, fmt.Errorf("GetHostIP not supported by expand controller's VolumeHost implementation")
}
func (expc *expandController) GetNodeAllocatable() (v1.ResourceList, error) {
return v1.ResourceList{}, nil
}
func (expc *expandController) GetSecretFunc() func(namespace, name string) (*v1.Secret, error) {
return func(_, _ string) (*v1.Secret, error) {
return nil, fmt.Errorf("GetSecret unsupported in expandController")
}
}
func (expc *expandController) GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error) {
return func(_, _ string) (*v1.ConfigMap, error) {
return nil, fmt.Errorf("GetConfigMap unsupported in expandController")
}
}
func (expc *expandController) GetNodeLabels() (map[string]string, error) {
return nil, fmt.Errorf("GetNodeLabels unsupported in expandController")
}
func (expc *expandController) GetNodeName() types.NodeName {
return ""
}

View File

@ -0,0 +1,90 @@
/*
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 reconciler implements interfaces that attempt to reconcile the
// desired state of the with the actual state of the world by triggering
// actions.
package expand
import (
"time"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/wait"
clientset "k8s.io/client-go/kubernetes"
corelisters "k8s.io/client-go/listers/core/v1"
"k8s.io/kubernetes/pkg/controller/volume/expand/cache"
)
// PVCPopulator iterates through PVCs and checks if for bound PVCs
// their size doesn't match with Persistent Volume size
type PVCPopulator interface {
Run(stopCh <-chan struct{})
}
type pvcPopulator struct {
loopPeriod time.Duration
resizeMap cache.VolumeResizeMap
pvcLister corelisters.PersistentVolumeClaimLister
pvLister corelisters.PersistentVolumeLister
kubeClient clientset.Interface
}
func NewPVCPopulator(
loopPeriod time.Duration,
resizeMap cache.VolumeResizeMap,
pvcLister corelisters.PersistentVolumeClaimLister,
pvLister corelisters.PersistentVolumeLister,
kubeClient clientset.Interface) PVCPopulator {
populator := &pvcPopulator{
loopPeriod: loopPeriod,
pvcLister: pvcLister,
pvLister: pvLister,
resizeMap: resizeMap,
kubeClient: kubeClient,
}
return populator
}
func (populator *pvcPopulator) Run(stopCh <-chan struct{}) {
wait.Until(populator.Sync, populator.loopPeriod, stopCh)
}
func (populator *pvcPopulator) Sync() {
pvcs, err := populator.pvcLister.List(labels.Everything())
if err != nil {
glog.Errorf("Listing PVCs failed in populator : %v", err)
return
}
for _, pvc := range pvcs {
pv, err := getPersistentVolume(pvc, populator.pvLister)
if err != nil {
glog.V(5).Infof("Error getting persistent volume for pvc %q : %v", pvc.UID, err)
continue
}
// We are only going to add PVCs which are:
// - bound
// - pvc.Spec.Size > pvc.Status.Size
// These 2 checks are already performed in AddPVCUpdate function before adding pvc for resize
// and hence we do not repeat those checks here.
populator.resizeMap.AddPVCUpdate(pvc, pv)
}
}

View File

@ -0,0 +1,101 @@
/*
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 expand
import (
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/pkg/controller/volume/expand/cache"
"k8s.io/kubernetes/pkg/controller/volume/expand/util"
"k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff"
"k8s.io/kubernetes/pkg/volume/util/operationexecutor"
)
type SyncVolumeResize interface {
Run(stopCh <-chan struct{})
}
type syncResize struct {
loopPeriod time.Duration
resizeMap cache.VolumeResizeMap
opsExecutor operationexecutor.OperationExecutor
kubeClient clientset.Interface
}
// NewSyncVolumeResize returns actual volume resize handler
func NewSyncVolumeResize(
loopPeriod time.Duration,
opsExecutor operationexecutor.OperationExecutor,
resizeMap cache.VolumeResizeMap,
kubeClient clientset.Interface) SyncVolumeResize {
rc := &syncResize{
loopPeriod: loopPeriod,
opsExecutor: opsExecutor,
resizeMap: resizeMap,
kubeClient: kubeClient,
}
return rc
}
func (rc *syncResize) Run(stopCh <-chan struct{}) {
wait.Until(rc.Sync, rc.loopPeriod, stopCh)
}
func (rc *syncResize) Sync() {
// Resize PVCs that require resize
for _, pvcWithResizeRequest := range rc.resizeMap.GetPVCsWithResizeRequest() {
uniqueVolumeKey := v1.UniqueVolumeName(pvcWithResizeRequest.UniquePVCKey())
updatedClaim, err := markPVCResizeInProgress(pvcWithResizeRequest, rc.kubeClient)
if err != nil {
glog.V(5).Infof("Error setting PVC %s in progress with error : %v", pvcWithResizeRequest.QualifiedName(), err)
continue
}
if updatedClaim != nil {
pvcWithResizeRequest.PVC = updatedClaim
}
if rc.opsExecutor.IsOperationPending(uniqueVolumeKey, "") {
glog.V(10).Infof("Operation for PVC %v is already pending", pvcWithResizeRequest.QualifiedName())
continue
}
glog.V(5).Infof("Starting opsExecutor.ExpandVolume for volume %s", pvcWithResizeRequest.QualifiedName())
growFuncError := rc.opsExecutor.ExpandVolume(pvcWithResizeRequest, rc.resizeMap)
if growFuncError != nil && !exponentialbackoff.IsExponentialBackoff(growFuncError) {
glog.Errorf("Error growing pvc %s with %v", pvcWithResizeRequest.QualifiedName(), growFuncError)
}
if growFuncError == nil {
glog.V(5).Infof("Started opsExecutor.ExpandVolume for volume %s", pvcWithResizeRequest.QualifiedName())
}
}
}
func markPVCResizeInProgress(pvcWithResizeRequest *cache.PVCWithResizeRequest, kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) {
// Mark PVC as Resize Started
progressCondition := v1.PersistentVolumeClaimCondition{
Type: v1.PersistentVolumeClaimResizing,
Status: v1.ConditionTrue,
LastTransitionTime: metav1.Now(),
}
conditions := []v1.PersistentVolumeClaimCondition{progressCondition}
return util.UpdatePVCCondition(pvcWithResizeRequest.PVC, conditions, kubeClient)
}

View File

@ -0,0 +1,27 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["util.go"],
importpath = "k8s.io/kubernetes/pkg/controller/volume/expand/util",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,46 @@
/*
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 util
import (
"fmt"
"github.com/golang/glog"
"k8s.io/api/core/v1"
clientset "k8s.io/client-go/kubernetes"
)
// ClaimToClaimKey return namespace/name string for pvc
func ClaimToClaimKey(claim *v1.PersistentVolumeClaim) string {
return fmt.Sprintf("%s/%s", claim.Namespace, claim.Name)
}
// UpdatePVCCondition updates pvc with given condition status
func UpdatePVCCondition(pvc *v1.PersistentVolumeClaim,
pvcConditions []v1.PersistentVolumeClaimCondition,
kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) {
claimClone := pvc.DeepCopy()
claimClone.Status.Conditions = pvcConditions
updatedClaim, updateErr := kubeClient.CoreV1().PersistentVolumeClaims(claimClone.Namespace).UpdateStatus(claimClone)
if updateErr != nil {
glog.V(4).Infof("updating PersistentVolumeClaim[%s] status: failed: %v", ClaimToClaimKey(pvc), updateErr)
return nil, updateErr
}
return updatedClaim, nil
}