IsReadOnly bool on builder

This commit is contained in:
markturansky 2015-06-29 12:54:43 -04:00
parent 124bb22f92
commit fae6759490
15 changed files with 118 additions and 6 deletions

View File

@ -240,6 +240,10 @@ func (ebs *awsElasticBlockStore) SetUpAt(dir string) error {
return nil return nil
} }
func (pd *awsElasticBlockStore) IsReadOnly() bool {
return pd.readOnly
}
func makeGlobalPDPath(host volume.VolumeHost, volumeID string) string { func makeGlobalPDPath(host volume.VolumeHost, volumeID string) string {
// Clean up the URI to be more fs-friendly // Clean up the URI to be more fs-friendly
name := volumeID name := volumeID

View File

@ -21,6 +21,8 @@ import (
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/testclient"
"github.com/GoogleCloudPlatform/kubernetes/pkg/types" "github.com/GoogleCloudPlatform/kubernetes/pkg/types"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/mount" "github.com/GoogleCloudPlatform/kubernetes/pkg/util/mount"
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume" "github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
@ -157,3 +159,50 @@ func TestPlugin(t *testing.T) {
t.Errorf("SetUp() failed: %v", err) t.Errorf("SetUp() failed: %v", err)
} }
} }
func TestPersistentClaimReadOnlyFlag(t *testing.T) {
pv := &api.PersistentVolume{
ObjectMeta: api.ObjectMeta{
Name: "pvA",
},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
AWSElasticBlockStore: &api.AWSElasticBlockStoreVolumeSource{},
},
ClaimRef: &api.ObjectReference{
Name: "claimA",
},
},
}
claim := &api.PersistentVolumeClaim{
ObjectMeta: api.ObjectMeta{
Name: "claimA",
Namespace: "nsA",
},
Spec: api.PersistentVolumeClaimSpec{
VolumeName: "pvA",
},
Status: api.PersistentVolumeClaimStatus{
Phase: api.ClaimBound,
},
}
o := testclient.NewObjects(api.Scheme, api.Scheme)
o.Add(pv)
o.Add(claim)
client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, latest.RESTMapper)}
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("/tmp/fake", client, nil))
plug, _ := plugMgr.FindPluginByName(awsElasticBlockStorePluginName)
spec := volume.NewSpecFromPersistentVolume(pv, false)
pod := &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("poduid")}}
builder, _ := plug.NewBuilder(spec, pod, volume.VolumeOptions{}, nil)
if builder.IsReadOnly() {
t.Errorf("Expected false for builder.IsReadOnly")
}
}

View File

@ -143,6 +143,10 @@ func (ed *emptyDir) SetUpAt(dir string) error {
} }
} }
func (ed *emptyDir) IsReadOnly() bool {
return false
}
func (ed *emptyDir) setupDefault(dir string) error { func (ed *emptyDir) setupDefault(dir string) error {
return os.MkdirAll(dir, 0750) return os.MkdirAll(dir, 0750)
} }

View File

@ -229,6 +229,10 @@ func (b *gcePersistentDiskBuilder) SetUpAt(dir string) error {
return nil return nil
} }
func (pd *gcePersistentDisk) IsReadOnly() bool {
return pd.readOnly
}
func makeGlobalPDName(host volume.VolumeHost, devName string) string { func makeGlobalPDName(host volume.VolumeHost, devName string) string {
return path.Join(host.GetPluginDir(gcePersistentDiskPluginName), "mounts", devName) return path.Join(host.GetPluginDir(gcePersistentDiskPluginName), "mounts", devName)
} }

View File

@ -118,6 +118,10 @@ func (b *gitRepoVolumeBuilder) SetUp() error {
return b.SetUpAt(b.GetPath()) return b.SetUpAt(b.GetPath())
} }
func (gr *gitRepo) IsReadOnly() bool {
return false
}
// This is the spec for the volume that this plugin wraps. // This is the spec for the volume that this plugin wraps.
var wrappedVolumeSpec = &volume.Spec{ var wrappedVolumeSpec = &volume.Spec{
Name: "not-used", Name: "not-used",

View File

@ -99,7 +99,7 @@ func (plugin *glusterfsPlugin) newBuilderInternal(spec *volume.Spec, ep *api.End
}, },
hosts: ep, hosts: ep,
path: source.Path, path: source.Path,
readonly: readOnly, readOnly: readOnly,
exe: exe}, nil exe: exe}, nil
} }
@ -128,7 +128,8 @@ type glusterfsBuilder struct {
*glusterfs *glusterfs
hosts *api.Endpoints hosts *api.Endpoints
path string path string
readonly bool readOnly bool
mounter mount.Interface
exe exec.Interface exe exec.Interface
} }
@ -161,6 +162,10 @@ func (b *glusterfsBuilder) SetUpAt(dir string) error {
return err return err
} }
func (glusterfsVolume *glusterfs) IsReadOnly() bool {
return glusterfsVolume.readOnly
}
func (glusterfsVolume *glusterfs) GetPath() string { func (glusterfsVolume *glusterfs) GetPath() string {
name := glusterfsPluginName name := glusterfsPluginName
return glusterfsVolume.plugin.host.GetPodVolumeDir(glusterfsVolume.pod.UID, util.EscapeQualifiedNameForDisk(name), glusterfsVolume.volName) return glusterfsVolume.plugin.host.GetPodVolumeDir(glusterfsVolume.pod.UID, util.EscapeQualifiedNameForDisk(name), glusterfsVolume.volName)
@ -212,7 +217,7 @@ func (b *glusterfsBuilder) setUpAtInternal(dir string) error {
var errs error var errs error
options := []string{} options := []string{}
if b.readonly { if glusterfsVolume.readOnly {
options = append(options, "ro") options = append(options, "ro")
} }

View File

@ -119,6 +119,14 @@ func (b *hostPathBuilder) SetUpAt(dir string) error {
return fmt.Errorf("SetUpAt() does not make sense for host paths") return fmt.Errorf("SetUpAt() does not make sense for host paths")
} }
func (b *hostPathBuilder) IsReadOnly() bool {
return false
}
func (b *hostPathBuilder) GetPath() string {
return b.path
}
type hostPathCleaner struct { type hostPathCleaner struct {
*hostPath *hostPath
} }

View File

@ -183,6 +183,10 @@ type iscsiDiskCleaner struct {
var _ volume.Cleaner = &iscsiDiskCleaner{} var _ volume.Cleaner = &iscsiDiskCleaner{}
func (b *iscsiDiskBuilder) IsReadOnly() bool {
return b.readOnly
}
// Unmounts the bind mount, and detaches the disk only if the disk // Unmounts the bind mount, and detaches the disk only if the disk
// resource was the last reference to that disk on the kubelet. // resource was the last reference to that disk on the kubelet.
func (c *iscsiDiskCleaner) TearDown() error { func (c *iscsiDiskCleaner) TearDown() error {

View File

@ -188,6 +188,15 @@ type nfsCleaner struct {
*nfs *nfs
} }
func (nfsVolume *nfs) IsReadOnly() bool {
return nfsVolume.readOnly
}
func (nfsVolume *nfs) GetPath() string {
name := nfsPluginName
return nfsVolume.plugin.host.GetPodVolumeDir(nfsVolume.pod.UID, util.EscapeQualifiedNameForDisk(name), nfsVolume.volName)
}
var _ volume.Cleaner = &nfsCleaner{} var _ volume.Cleaner = &nfsCleaner{}
func (c *nfsCleaner) TearDown() error { func (c *nfsCleaner) TearDown() error {

View File

@ -26,11 +26,12 @@ import (
) )
func ProbeVolumePlugins() []volume.VolumePlugin { func ProbeVolumePlugins() []volume.VolumePlugin {
return []volume.VolumePlugin{&persistentClaimPlugin{nil}} return []volume.VolumePlugin{&persistentClaimPlugin{host: nil}}
} }
type persistentClaimPlugin struct { type persistentClaimPlugin struct {
host volume.VolumeHost host volume.VolumeHost
readOnly bool
} }
var _ volume.VolumePlugin = &persistentClaimPlugin{} var _ volume.VolumePlugin = &persistentClaimPlugin{}
@ -52,6 +53,7 @@ func (plugin *persistentClaimPlugin) CanSupport(spec *volume.Spec) bool {
} }
func (plugin *persistentClaimPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions, mounter mount.Interface) (volume.Builder, error) { func (plugin *persistentClaimPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions, mounter mount.Interface) (volume.Builder, error) {
plugin.readOnly = spec.ReadOnly
claim, err := plugin.host.GetKubeClient().PersistentVolumeClaims(pod.Namespace).Get(spec.VolumeSource.PersistentVolumeClaim.ClaimName) claim, err := plugin.host.GetKubeClient().PersistentVolumeClaims(pod.Namespace).Get(spec.VolumeSource.PersistentVolumeClaim.ClaimName)
if err != nil { if err != nil {
glog.Errorf("Error finding claim: %+v\n", spec.VolumeSource.PersistentVolumeClaim.ClaimName) glog.Errorf("Error finding claim: %+v\n", spec.VolumeSource.PersistentVolumeClaim.ClaimName)
@ -87,6 +89,10 @@ func (plugin *persistentClaimPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod,
return builder, nil return builder, nil
} }
func (plugin *persistentClaimPlugin) IsReadOnly() bool {
return plugin.readOnly
}
func (plugin *persistentClaimPlugin) NewCleaner(_ string, _ types.UID, _ mount.Interface) (volume.Cleaner, error) { func (plugin *persistentClaimPlugin) NewCleaner(_ string, _ types.UID, _ mount.Interface) (volume.Cleaner, error) {
return nil, fmt.Errorf("This will never be called directly. The PV backing this claim has a cleaner. Kubelet uses that cleaner, not this one, when removing orphaned volumes.") return nil, fmt.Errorf("This will never be called directly. The PV backing this claim has a cleaner. Kubelet uses that cleaner, not this one, when removing orphaned volumes.")
} }

View File

@ -216,6 +216,10 @@ type rbdCleaner struct {
var _ volume.Cleaner = &rbdCleaner{} var _ volume.Cleaner = &rbdCleaner{}
func (b *rbd) IsReadOnly() bool {
return b.ReadOnly
}
// Unmounts the bind mount, and detaches the disk only if the disk // Unmounts the bind mount, and detaches the disk only if the disk
// resource was the last reference to that disk on the kubelet. // resource was the last reference to that disk on the kubelet.
func (c *rbdCleaner) TearDown() error { func (c *rbdCleaner) TearDown() error {

View File

@ -168,6 +168,10 @@ func (b *secretVolumeBuilder) SetUpAt(dir string) error {
return nil return nil
} }
func (sv *secretVolume) IsReadOnly() bool {
return false
}
func totalSecretBytes(secret *api.Secret) int { func totalSecretBytes(secret *api.Secret) int {
totalSize := 0 totalSize := 0
for _, bytes := range secret.Data { for _, bytes := range secret.Data {

View File

@ -127,6 +127,10 @@ func (fv *FakeVolume) SetUpAt(dir string) error {
return os.MkdirAll(dir, 0750) return os.MkdirAll(dir, 0750)
} }
func (fv *FakeVolume) IsReadOnly() bool {
return false
}
func (fv *FakeVolume) GetPath() string { func (fv *FakeVolume) GetPath() string {
return path.Join(fv.Plugin.Host.GetPodVolumeDir(fv.PodUID, util.EscapeQualifiedNameForDisk(fv.Plugin.PluginName), fv.VolName)) return path.Join(fv.Plugin.Host.GetPodVolumeDir(fv.PodUID, util.EscapeQualifiedNameForDisk(fv.Plugin.PluginName), fv.VolName))
} }

View File

@ -41,6 +41,9 @@ type Builder interface {
// directory path, which may or may not exist yet. This may be called // directory path, which may or may not exist yet. This may be called
// more than once, so implementations must be idempotent. // more than once, so implementations must be idempotent.
SetUpAt(dir string) error SetUpAt(dir string) error
// IsReadOnly is a flag that gives the builder's ReadOnly attribute.
// All persistent volumes have a private readOnly flag in their builders.
IsReadOnly() bool
} }
// Cleaner interface provides methods to cleanup/unmount the volumes. // Cleaner interface provides methods to cleanup/unmount the volumes.

View File

@ -123,7 +123,7 @@ func (recycler *PersistentVolumeRecycler) handleRecycle(pv *api.PersistentVolume
currentPhase := pv.Status.Phase currentPhase := pv.Status.Phase
nextPhase := currentPhase nextPhase := currentPhase
spec := volume.NewSpecFromPersistentVolume(pv) spec := volume.NewSpecFromPersistentVolume(pv, false)
plugin, err := recycler.pluginMgr.FindRecyclablePluginBySpec(spec) plugin, err := recycler.pluginMgr.FindRecyclablePluginBySpec(spec)
if err != nil { if err != nil {
return fmt.Errorf("Could not find recyclable volume plugin for spec: %+v", err) return fmt.Errorf("Could not find recyclable volume plugin for spec: %+v", err)