mirror of https://github.com/k3s-io/k3s
PVClaim volume plugin
parent
afd7d77a24
commit
d904e747e3
|
@ -33,6 +33,7 @@ import (
|
|||
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume/host_path"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume/iscsi"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume/nfs"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume/persistent_claim"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume/secret"
|
||||
//Cloud providers
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/aws"
|
||||
|
@ -59,6 +60,7 @@ func ProbeVolumePlugins() []volume.VolumePlugin {
|
|||
allPlugins = append(allPlugins, secret.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, iscsi.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, glusterfs.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, persistent_claim.ProbeVolumePlugins()...)
|
||||
|
||||
return allPlugins
|
||||
}
|
||||
|
|
|
@ -203,6 +203,8 @@ type VolumeSource struct {
|
|||
ISCSI *ISCSIVolumeSource `json:"iscsi"`
|
||||
// Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime
|
||||
Glusterfs *GlusterfsVolumeSource `json:"glusterfs"`
|
||||
// PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace
|
||||
PersistentVolumeClaimVolumeSource *PersistentVolumeClaimVolumeSource `json:"persistentVolumeClaim,omitempty"`
|
||||
}
|
||||
|
||||
// Similar to VolumeSource but meant for the administrator who creates PVs.
|
||||
|
@ -222,6 +224,14 @@ type PersistentVolumeSource struct {
|
|||
Glusterfs *GlusterfsVolumeSource `json:"glusterfs"`
|
||||
}
|
||||
|
||||
type PersistentVolumeClaimVolumeSource struct {
|
||||
// ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume
|
||||
ClaimName string `json:"claimName,omitempty" description:"the name of the claim in the same namespace to be mounted as a volume"`
|
||||
// Optional: Defaults to false (read/write). ReadOnly here
|
||||
// will force the ReadOnly setting in VolumeMounts
|
||||
ReadOnly bool `json:"readOnly,omitempty"`
|
||||
}
|
||||
|
||||
type PersistentVolume struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ObjectMeta `json:"metadata,omitempty"`
|
||||
|
|
|
@ -1185,6 +1185,9 @@ func init() {
|
|||
if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.PersistentVolumeClaimVolumeSource, &out.PersistentVolumeClaimVolumeSource, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(in *VolumeSource, out *newer.VolumeSource, s conversion.Scope) error {
|
||||
|
@ -1212,6 +1215,9 @@ func init() {
|
|||
if err := s.Convert(&in.NFS, &out.NFS, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.PersistentVolumeClaimVolumeSource, &out.PersistentVolumeClaimVolumeSource, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -119,6 +119,8 @@ type VolumeSource struct {
|
|||
ISCSI *ISCSIVolumeSource `json:"iscsi" description:"iSCSI disk attached to host machine on demand"`
|
||||
// Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime
|
||||
Glusterfs *GlusterfsVolumeSource `json:"glusterfs" description:"Glusterfs volume that will be mounted on the host machine "`
|
||||
// PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace
|
||||
PersistentVolumeClaimVolumeSource *PersistentVolumeClaimVolumeSource `json:"persistentVolumeClaim,omitempty" description:"a reference to a PersistentVolumeClaim in the same namespace"`
|
||||
}
|
||||
|
||||
// Similar to VolumeSource but meant for the administrator who creates PVs.
|
||||
|
@ -138,6 +140,14 @@ type PersistentVolumeSource struct {
|
|||
Glusterfs *GlusterfsVolumeSource `json:"glusterfs" description:"Glusterfs volume resource provisioned by an admin"`
|
||||
}
|
||||
|
||||
type PersistentVolumeClaimVolumeSource struct {
|
||||
// ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume
|
||||
ClaimName string `json:"claimName,omitempty" description:"the name of the claim in the same namespace to be mounted as a volume"`
|
||||
// Optional: Defaults to false (read/write). ReadOnly here
|
||||
// will force the ReadOnly setting in VolumeMounts
|
||||
ReadOnly bool `json:"readOnly,omitempty" description:"mount volume as read-only when true; default false"`
|
||||
}
|
||||
|
||||
type PersistentVolume struct {
|
||||
TypeMeta `json:",inline"`
|
||||
|
||||
|
|
|
@ -1112,6 +1112,9 @@ func init() {
|
|||
if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.PersistentVolumeClaimVolumeSource, &out.PersistentVolumeClaimVolumeSource, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(in *VolumeSource, out *newer.VolumeSource, s conversion.Scope) error {
|
||||
|
@ -1139,6 +1142,9 @@ func init() {
|
|||
if err := s.Convert(&in.NFS, &out.NFS, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.PersistentVolumeClaimVolumeSource, &out.PersistentVolumeClaimVolumeSource, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -88,6 +88,8 @@ type VolumeSource struct {
|
|||
ISCSI *ISCSIVolumeSource `json:"iscsi" description:"iSCSI disk attached to host machine on demand"`
|
||||
// Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime
|
||||
Glusterfs *GlusterfsVolumeSource `json:"glusterfs" description:"Glusterfs volume that will be mounted on the host machine "`
|
||||
// PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace
|
||||
PersistentVolumeClaimVolumeSource *PersistentVolumeClaimVolumeSource `json:"persistentVolumeClaim,omitempty" description:"a reference to a PersistentVolumeClaim in the same namespace"`
|
||||
}
|
||||
|
||||
// Similar to VolumeSource but meant for the administrator who creates PVs.
|
||||
|
@ -107,6 +109,14 @@ type PersistentVolumeSource struct {
|
|||
Glusterfs *GlusterfsVolumeSource `json:"glusterfs" description:"Glusterfs volume resource provisioned by an admin"`
|
||||
}
|
||||
|
||||
type PersistentVolumeClaimVolumeSource struct {
|
||||
// ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume
|
||||
ClaimName string `json:"claimName,omitempty" description:"the name of the claim in the same namespace to be mounted as a volume"`
|
||||
// Optional: Defaults to false (read/write). ReadOnly here
|
||||
// will force the ReadOnly setting in VolumeMounts
|
||||
ReadOnly bool `json:"readOnly,omitempty" description:"mount volume as read-only when true; default false"`
|
||||
}
|
||||
|
||||
type PersistentVolume struct {
|
||||
TypeMeta `json:",inline"`
|
||||
|
||||
|
|
|
@ -220,6 +220,16 @@ type VolumeSource struct {
|
|||
ISCSI *ISCSIVolumeSource `json:"iscsi" description:"iSCSI disk attached to host machine on demand"`
|
||||
// Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime
|
||||
Glusterfs *GlusterfsVolumeSource `json:"glusterfs" description:"Glusterfs volume that will be mounted on the host machine "`
|
||||
// PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace
|
||||
PersistentVolumeClaimVolumeSource *PersistentVolumeClaimVolumeSource `json:"persistentVolumeClaim,omitempty" description:"a reference to a PersistentVolumeClaim in the same namespace"`
|
||||
}
|
||||
|
||||
type PersistentVolumeClaimVolumeSource struct {
|
||||
// ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume
|
||||
ClaimName string `json:"claimName,omitempty" description:"the name of the claim in the same namespace to be mounted as a volume"`
|
||||
// Optional: Defaults to false (read/write). ReadOnly here
|
||||
// will force the ReadOnly setting in VolumeMounts
|
||||
ReadOnly bool `json:"readOnly,omitempty" description:"mount volume as read-only when true; default false"`
|
||||
}
|
||||
|
||||
// Similar to VolumeSource but meant for the administrator who creates PVs.
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
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 persistent_claim
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
func ProbeVolumePlugins() []volume.VolumePlugin {
|
||||
return []volume.VolumePlugin{&persistentClaimPlugin{nil}}
|
||||
}
|
||||
|
||||
type persistentClaimPlugin struct {
|
||||
host volume.VolumeHost
|
||||
}
|
||||
|
||||
var _ volume.VolumePlugin = &persistentClaimPlugin{}
|
||||
|
||||
const (
|
||||
persistentClaimPluginName = "kubernetes.io/persistent-claim"
|
||||
)
|
||||
|
||||
func (plugin *persistentClaimPlugin) Init(host volume.VolumeHost) {
|
||||
plugin.host = host
|
||||
}
|
||||
|
||||
func (plugin *persistentClaimPlugin) Name() string {
|
||||
return persistentClaimPluginName
|
||||
}
|
||||
|
||||
func (plugin *persistentClaimPlugin) CanSupport(spec *volume.Spec) bool {
|
||||
return spec.VolumeSource.PersistentVolumeClaimVolumeSource != nil
|
||||
}
|
||||
|
||||
func (plugin *persistentClaimPlugin) NewBuilder(spec *volume.Spec, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
|
||||
claim, err := plugin.host.GetKubeClient().PersistentVolumeClaims(podRef.Namespace).Get(spec.VolumeSource.PersistentVolumeClaimVolumeSource.ClaimName)
|
||||
if err != nil {
|
||||
glog.Errorf("Error finding claim: %+v\n", spec.VolumeSource.PersistentVolumeClaimVolumeSource.ClaimName)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pv, err := plugin.host.GetKubeClient().PersistentVolumes().Get(claim.Status.VolumeRef.Name)
|
||||
if err != nil {
|
||||
glog.Errorf("Error finding persistent volume for claim: %+v\n", claim.Name)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
builder, err := plugin.host.NewWrapperBuilder(volume.NewSpecFromPersistentVolume(pv), podRef, opts)
|
||||
if err != nil {
|
||||
glog.Errorf("Error creating builder for claim: %+v\n", claim.Name)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return builder, nil
|
||||
}
|
||||
|
||||
func (plugin *persistentClaimPlugin) NewCleaner(volName string, podUID types.UID) (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.")
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
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 persistent_claim
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/testclient"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume/gce_pd"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume/host_path"
|
||||
)
|
||||
|
||||
func newTestHost(t *testing.T, fakeKubeClient client.Interface) volume.VolumeHost {
|
||||
tempDir, err := ioutil.TempDir("/tmp", "persistent_volume_test.")
|
||||
if err != nil {
|
||||
t.Fatalf("can't make a temp rootdir: %v", err)
|
||||
}
|
||||
return volume.NewFakeVolumeHost(tempDir, fakeKubeClient, testProbeVolumePlugins())
|
||||
}
|
||||
|
||||
func TestCanSupport(t *testing.T) {
|
||||
plugMgr := volume.VolumePluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("/tmp/fake", nil, ProbeVolumePlugins()))
|
||||
|
||||
plug, err := plugMgr.FindPluginByName("kubernetes.io/persistent-claim")
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
if plug.Name() != "kubernetes.io/persistent-claim" {
|
||||
t.Errorf("Wrong name: %s", plug.Name())
|
||||
}
|
||||
if !plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{PersistentVolumeClaimVolumeSource: &api.PersistentVolumeClaimVolumeSource{}}}) {
|
||||
t.Errorf("Expected true")
|
||||
}
|
||||
if plug.CanSupport(&volume.Spec{VolumeSource: api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{}}}) {
|
||||
t.Errorf("Expected false")
|
||||
}
|
||||
if plug.CanSupport(&volume.Spec{VolumeSource: api.VolumeSource{}}) {
|
||||
t.Errorf("Expected false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewBuilder(t *testing.T) {
|
||||
tests := []struct {
|
||||
pv *api.PersistentVolume
|
||||
claim *api.PersistentVolumeClaim
|
||||
plugin volume.VolumePlugin
|
||||
podVolume api.VolumeSource
|
||||
testFunc func(builder volume.Builder, plugin volume.VolumePlugin) error
|
||||
}{
|
||||
{
|
||||
pv: &api.PersistentVolume{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "pvA",
|
||||
},
|
||||
Spec: api.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||
GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{},
|
||||
},
|
||||
ClaimRef: &api.ObjectReference{
|
||||
Name: "claimA",
|
||||
},
|
||||
},
|
||||
},
|
||||
claim: &api.PersistentVolumeClaim{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "claimA",
|
||||
Namespace: "nsA",
|
||||
},
|
||||
Status: api.PersistentVolumeClaimStatus{
|
||||
Phase: api.ClaimBound,
|
||||
VolumeRef: &api.ObjectReference{
|
||||
Name: "pvA",
|
||||
},
|
||||
},
|
||||
},
|
||||
podVolume: api.VolumeSource{
|
||||
PersistentVolumeClaimVolumeSource: &api.PersistentVolumeClaimVolumeSource{
|
||||
ReadOnly: false,
|
||||
ClaimName: "claimA",
|
||||
},
|
||||
},
|
||||
plugin: gce_pd.ProbeVolumePlugins()[0],
|
||||
testFunc: func(builder volume.Builder, plugin volume.VolumePlugin) error {
|
||||
if !strings.Contains(builder.GetPath(), util.EscapeQualifiedNameForDisk(plugin.Name())) {
|
||||
return fmt.Errorf("builder path expected to contain plugin name. Got: %s", builder.GetPath())
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
pv: &api.PersistentVolume{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "pvB",
|
||||
},
|
||||
Spec: api.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||
HostPath: &api.HostPathVolumeSource{Path: "/tmp"},
|
||||
},
|
||||
ClaimRef: &api.ObjectReference{
|
||||
Name: "claimB",
|
||||
},
|
||||
},
|
||||
},
|
||||
claim: &api.PersistentVolumeClaim{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "claimB",
|
||||
Namespace: "nsB",
|
||||
},
|
||||
Status: api.PersistentVolumeClaimStatus{
|
||||
VolumeRef: &api.ObjectReference{
|
||||
Name: "pvB",
|
||||
},
|
||||
},
|
||||
},
|
||||
podVolume: api.VolumeSource{
|
||||
PersistentVolumeClaimVolumeSource: &api.PersistentVolumeClaimVolumeSource{
|
||||
ReadOnly: false,
|
||||
ClaimName: "claimB",
|
||||
},
|
||||
},
|
||||
plugin: host_path.ProbeVolumePlugins()[0],
|
||||
testFunc: func(builder volume.Builder, plugin volume.VolumePlugin) error {
|
||||
if builder.GetPath() != "/tmp" {
|
||||
return fmt.Errorf("Expected HostPath.Path /tmp, got: %s", builder.GetPath())
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, item := range tests {
|
||||
o := testclient.NewObjects(api.Scheme)
|
||||
o.Add(item.pv)
|
||||
o.Add(item.claim)
|
||||
client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, latest.RESTMapper)}
|
||||
|
||||
plugMgr := volume.VolumePluginMgr{}
|
||||
plugMgr.InitPlugins(testProbeVolumePlugins(), newTestHost(t, client))
|
||||
|
||||
plug, err := plugMgr.FindPluginByName("kubernetes.io/persistent-claim")
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
spec := &volume.Spec{
|
||||
Name: "vol1",
|
||||
VolumeSource: item.podVolume,
|
||||
}
|
||||
builder, err := plug.NewBuilder(spec, &api.ObjectReference{UID: types.UID("poduid")}, volume.VolumeOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("Failed to make a new Builder: %v", err)
|
||||
}
|
||||
if builder == nil {
|
||||
t.Errorf("Got a nil Builder: %v", builder)
|
||||
}
|
||||
|
||||
if builder != nil {
|
||||
if err := item.testFunc(builder, item.plugin); err != nil {
|
||||
t.Errorf("Unexpected error %+v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testProbeVolumePlugins() []volume.VolumePlugin {
|
||||
allPlugins := []volume.VolumePlugin{}
|
||||
allPlugins = append(allPlugins, gce_pd.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, host_path.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, ProbeVolumePlugins()...)
|
||||
return allPlugins
|
||||
}
|
Loading…
Reference in New Issue