Skip to content

Commit

Permalink
Merge pull request kubernetes#6002 from markturansky/yoko_pv_client
Browse files Browse the repository at this point in the history
PersistentVolume & PersistentVolumeClaim Client
  • Loading branch information
derekwaynecarr committed Apr 6, 2015
2 parents c048e6f + ff86ae0 commit 9bf35e0
Show file tree
Hide file tree
Showing 39 changed files with 2,191 additions and 32 deletions.
15 changes: 15 additions & 0 deletions examples/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ func validateObject(obj runtime.Object) (errors []error) {
for i := range t.Items {
errors = append(errors, validateObject(&t.Items[i])...)
}
case *api.PersistentVolume:
errors = validation.ValidatePersistentVolume(t)
case *api.PersistentVolumeClaim:
api.ValidNamespace(ctx, &t.ObjectMeta)
errors = validation.ValidatePersistentVolumeClaim(t)
default:
return []error{fmt.Errorf("no validation defined for %#v", obj)}
}
Expand Down Expand Up @@ -160,6 +165,16 @@ func TestExampleObjectSchemas(t *testing.T) {
"kitten-rc": &api.ReplicationController{},
"nautilus-rc": &api.ReplicationController{},
},
"../examples/persistent-volumes/volumes": {
"local-01": &api.PersistentVolume{},
"local-02": &api.PersistentVolume{},
"gce": &api.PersistentVolume{},
},
"../examples/persistent-volumes/claims": {
"claim-01": &api.PersistentVolumeClaim{},
"claim-02": &api.PersistentVolumeClaim{},
"claim-03": &api.PersistentVolumeClaim{},
},
}

for path, expected := range cases {
Expand Down
10 changes: 10 additions & 0 deletions examples/persistent-volumes/claims/claim-01.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
kind: PersistentVolumeClaim
apiVersion: v1beta3
metadata:
name: myclaim-1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3
10 changes: 10 additions & 0 deletions examples/persistent-volumes/claims/claim-02.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
kind: PersistentVolumeClaim
apiVersion: v1beta3
metadata:
name: myclaim-2
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 8
17 changes: 17 additions & 0 deletions examples/persistent-volumes/claims/claim-03.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"kind": "PersistentVolumeClaim",
"apiVersion": "v1beta3",
"metadata": {
"name": "myclaim-3"
}, "spec": {
"accessModes": [
"ReadWriteOnce",
"ReadOnlyMany"
],
"resources": {
"requests": {
"storage": "10G"
}
}
}
}
69 changes: 69 additions & 0 deletions examples/persistent-volumes/simpletest/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# How To Use Persistent Volumes

This guide assumes knowledge of Kubernetes fundamentals and that a user has a cluster up and running.

## Create volumes

Persistent Volumes are intended for "network volumes", such as GCE Persistent Disks, NFS shares, and AWS EBS volumes.

The `HostPath` VolumeSource was included in the Persistent Volumes implementation for ease of testing.

Create persistent volumes by posting them to the API server:

```
cluster/kubectl.sh create -f examples/persistent-volumes/volumes/local-01.yaml
cluster/kubectl.sh create -f examples/persistent-volumes/volumes/local-02.yaml
cluster/kubectl.sh get pv
NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM
pv0001 map[] 10737418240 RWO
pv0002 map[] 5368709120 RWO
In the log:
I0302 10:20:45.663225 1920 persistent_volume_manager.go:115] Managing PersistentVolume[UID=b16e91d6-c0ef-11e4-8be4-80e6500a981e]
I0302 10:20:55.667945 1920 persistent_volume_manager.go:115] Managing PersistentVolume[UID=b41f4f0e-c0ef-11e4-8be4-80e6500a981e]
```

## Create claims

You must be in a namespace to create claims.

```
cluster/kubectl.sh create -f examples/persistent-volumes/claims/claim-01.yaml
cluster/kubectl.sh create -f examples/persistent-volumes/claims/claim-02.yaml
NAME LABELS STATUS VOLUME
myclaim-1 map[]
myclaim-2 map[]
```


## Matching and binding

```
PersistentVolumeClaim[UID=f4b3d283-c0ef-11e4-8be4-80e6500a981e] bound to PersistentVolume[UID=b16e91d6-c0ef-11e4-8be4-80e6500a981e]
cluster/kubectl.sh get pv
NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM
pv0001 map[] 10737418240 RWO myclaim-1 / f4b3d283-c0ef-11e4-8be4-80e6500a981e
pv0002 map[] 5368709120 RWO myclaim-2 / f70da891-c0ef-11e4-8be4-80e6500a981e
cluster/kubectl.sh get pvc
NAME LABELS STATUS VOLUME
myclaim-1 map[] b16e91d6-c0ef-11e4-8be4-80e6500a981e
myclaim-2 map[] b41f4f0e-c0ef-11e4-8be4-80e6500a981e
```
10 changes: 10 additions & 0 deletions examples/persistent-volumes/simpletest/namespace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"kind": "Namespace",
"apiVersion":"v1beta3",
"metadata": {
"name": "myns",
"labels": {
"name": "development"
}
}
}
18 changes: 18 additions & 0 deletions examples/persistent-volumes/simpletest/pod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
kind: Pod
apiVersion: v1beta3
metadata:
name: mypod
spec:
containers:
- image: dockerfile/nginx
name: myfrontend
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
source:
persistentVolumeClaim:
accessMode: ReadWriteOnce
claimRef:
name: myclaim-1
10 changes: 10 additions & 0 deletions examples/persistent-volumes/volumes/gce.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
kind: PersistentVolume
apiVersion: v1beta3
metadata:
name: pv0003
spec:
capacity:
storage: 10
gcePersistentDisk:
pdName: "abc123"
fsType: "ext4"
11 changes: 11 additions & 0 deletions examples/persistent-volumes/volumes/local-01.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
kind: PersistentVolume
apiVersion: v1beta3
metadata:
name: pv0001
labels:
type: local
spec:
capacity:
storage: 10Gi
hostPath:
path: "/tmp/data01"
11 changes: 11 additions & 0 deletions examples/persistent-volumes/volumes/local-02.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
kind: PersistentVolume
apiVersion: v1beta3
metadata:
name: pv0002
labels:
type: local
spec:
capacity:
storage: 5Gi
hostPath:
path: "/tmp/data02"
43 changes: 43 additions & 0 deletions hack/test-cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,49 @@ __EOF__
# Post-condition: no replication controller is running
kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" ''

######################
# Persistent Volumes #
######################

### Create and delete persistent volume examples
# Pre-condition: no persistent volumes currently exist
kube::test::get_object_assert pv "{{range.items}}{{.$id_field}}:{{end}}" ''
# Command
kubectl create -f examples/persistent-volumes/volumes/local-01.yaml "${kube_flags[@]}"
kube::test::get_object_assert pv "{{range.items}}{{.$id_field}}:{{end}}" 'pv0001:'
kubectl delete pv pv0001 "${kube_flags[@]}"
kubectl create -f examples/persistent-volumes/volumes/local-02.yaml "${kube_flags[@]}"
kube::test::get_object_assert pv "{{range.items}}{{.$id_field}}:{{end}}" 'pv0002:'
kubectl delete pv pv0002 "${kube_flags[@]}"
kubectl create -f examples/persistent-volumes/volumes/gce.yaml "${kube_flags[@]}"
kube::test::get_object_assert pv "{{range.items}}{{.$id_field}}:{{end}}" 'pv0003:'
kubectl delete pv pv0003 "${kube_flags[@]}"
# Post-condition: no PVs
kube::test::get_object_assert pv "{{range.items}}{{.$id_field}}:{{end}}" ''

############################
# Persistent Volume Claims #
############################

### Create and delete persistent volume claim examples
# Pre-condition: no persistent volume claims currently exist
kube::test::get_object_assert pvc "{{range.items}}{{.$id_field}}:{{end}}" ''
# Command
kubectl create -f examples/persistent-volumes/claims/claim-01.yaml "${kube_flags[@]}"
kube::test::get_object_assert pvc "{{range.items}}{{.$id_field}}:{{end}}" 'myclaim-1:'
kubectl delete pvc myclaim-1 "${kube_flags[@]}"

kubectl create -f examples/persistent-volumes/claims/claim-02.yaml "${kube_flags[@]}"
kube::test::get_object_assert pvc "{{range.items}}{{.$id_field}}:{{end}}" 'myclaim-2:'
kubectl delete pvc myclaim-2 "${kube_flags[@]}"

kubectl create -f examples/persistent-volumes/claims/claim-03.json "${kube_flags[@]}"
kube::test::get_object_assert pvc "{{range.items}}{{.$id_field}}:{{end}}" 'myclaim-3:'
kubectl delete pvc myclaim-3 "${kube_flags[@]}"
# Post-condition: no PVCs
kube::test::get_object_assert pvc "{{range.items}}{{.$id_field}}:{{end}}" ''



#########
# Nodes #
Expand Down
3 changes: 2 additions & 1 deletion pkg/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,9 @@ type PersistentVolumeSpec struct {
// Resources represents the actual resources of the volume
Capacity ResourceList `json:"capacity`
// Source represents the location and type of a volume to mount.
// AccessModeTypes are inferred from the Source.
PersistentVolumeSource `json:",inline"`
// AccessModes contains all ways the volume can be mounted
AccessModes []AccessModeType `json:"accessModes,omitempty"`
// holds the binding reference to a PersistentVolumeClaim
ClaimRef *ObjectReference `json:"claimRef,omitempty"`
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/api/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,9 @@ type PersistentVolumeSpec struct {
// Resources represents the actual resources of the volume
Capacity ResourceList `json:"capacity,omitempty" description:"a description of the persistent volume's resources and capacity"`
// Source represents the location and type of a volume to mount.
// AccessModeTypes are inferred from the Source.
PersistentVolumeSource `json:",inline" description:"the actual volume backing the persistent volume"`
// AccessModes contains all ways the volume can be mounted
AccessModes []AccessModeType `json:"accessModes,omitempty" description:"all ways the volume can be mounted"`
// holds the binding reference to a PersistentVolumeClaim
ClaimRef *ObjectReference `json:"claimRef,omitempty" description:"the binding reference to a persistent volume claim"`
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/api/v1beta2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,9 @@ type PersistentVolumeSpec struct {
// Resources represents the actual resources of the volume
Capacity ResourceList `json:"capacity,omitempty" description:"a description of the persistent volume's resources and capacity"`
// Source represents the location and type of a volume to mount.
// AccessModeTypes are inferred from the Source.
PersistentVolumeSource `json:",inline" description:"the actual volume backing the persistent volume"`
// AccessModes contains all ways the volume can be mounted
AccessModes []AccessModeType `json:"accessModes,omitempty" description:"all ways the volume can be mounted"`
// holds the binding reference to a PersistentVolumeClaim
ClaimRef *ObjectReference `json:"claimRef,omitempty" description:"the binding reference to a persistent volume claim"`
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/api/v1beta3/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,9 @@ type PersistentVolumeSpec struct {
// Resources represents the actual resources of the volume
Capacity ResourceList `json:"capacity,omitempty" description:"a description of the persistent volume's resources and capacity"`
// Source represents the location and type of a volume to mount.
// AccessModeTypes are inferred from the Source.
PersistentVolumeSource `json:",inline" description:"the actual volume backing the persistent volume"`
// AccessModes contains all ways the volume can be mounted
AccessModes []AccessModeType `json:"accessModes,omitempty" description:"all ways the volume can be mounted"`
// holds the binding reference to a PersistentVolumeClaim
ClaimRef *ObjectReference `json:"claimRef,omitempty" description:"the binding reference to a persistent volume claim"`
}
Expand Down
59 changes: 55 additions & 4 deletions pkg/api/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"net"
"path"
"reflect"
"strings"

"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
Expand All @@ -28,6 +29,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
errs "github.com/GoogleCloudPlatform/kubernetes/pkg/util/fielderrors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"

"github.com/golang/glog"
)
Expand Down Expand Up @@ -364,11 +366,12 @@ func validateNFS(nfs *api.NFSVolumeSource) errs.ValidationErrorList {
}

func ValidatePersistentVolumeName(name string, prefix bool) (bool, string) {
return util.IsDNS1123Label(name), name
return nameIsDNSSubdomain(name, prefix)
}

func ValidatePersistentVolume(pv *api.PersistentVolume) errs.ValidationErrorList {
allErrs := ValidateObjectMeta(&pv.ObjectMeta, false, ValidatePersistentVolumeName)
allErrs := errs.ValidationErrorList{}
allErrs = append(allErrs, ValidateObjectMeta(&pv.ObjectMeta, false, ValidatePersistentVolumeName).Prefix("metadata")...)

if len(pv.Spec.Capacity) == 0 {
allErrs = append(allErrs, errs.NewFieldRequired("persistentVolume.Capacity"))
Expand All @@ -393,14 +396,62 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) errs.ValidationErrorList
return allErrs
}

// ValidatePersistentVolumeUpdate tests to see if the update is legal for an end user to make.
// newPv is updated with fields that cannot be changed.
func ValidatePersistentVolumeUpdate(newPv, oldPv *api.PersistentVolume) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
allErrs = ValidatePersistentVolume(newPv)
newPv.Status = oldPv.Status
return allErrs
}

// ValidatePersistentVolumeStatusUpdate tests to see if the status update is legal for an end user to make.
// newPv is updated with fields that cannot be changed.
func ValidatePersistentVolumeStatusUpdate(newPv, oldPv *api.PersistentVolume) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
allErrs = append(allErrs, ValidateObjectMetaUpdate(&oldPv.ObjectMeta, &newPv.ObjectMeta).Prefix("metadata")...)
if newPv.ResourceVersion == "" {
allErrs = append(allErrs, fmt.Errorf("ResourceVersion must be specified"))
}
newPv.Spec = oldPv.Spec
return allErrs
}

func ValidatePersistentVolumeClaim(pvc *api.PersistentVolumeClaim) errs.ValidationErrorList {
allErrs := ValidateObjectMeta(&pvc.ObjectMeta, true, ValidatePersistentVolumeName)
if len(pvc.Spec.AccessModes) == 0 {
allErrs = append(allErrs, errs.NewFieldInvalid("persistentVolumeClaim.Spec.AccessModes", pvc.Spec.AccessModes, "at least 1 AccessModeType is required"))
}
if len(pvc.Spec.Resources.Requests) == 0 {
allErrs = append(allErrs, errs.NewFieldInvalid("persistentVolumeClaim.Spec.Resources.Requests", pvc.Spec.AccessModes, "No Resource.Requests specified"))
if _, ok := pvc.Spec.Resources.Requests[api.ResourceStorage]; !ok {
allErrs = append(allErrs, errs.NewFieldInvalid("persistentVolumeClaim.Spec.Resources.Requests", pvc.Spec.Resources.Requests, "No Storage size specified"))
}
return allErrs
}

func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
allErrs = ValidatePersistentVolumeClaim(newPvc)
if oldPvc.Status.VolumeRef != nil {
oldModesAsString := volume.GetAccessModesAsString(oldPvc.Spec.AccessModes)
newModesAsString := volume.GetAccessModesAsString(newPvc.Spec.AccessModes)
if oldModesAsString != newModesAsString {
allErrs = append(allErrs, errs.NewFieldInvalid("spec.AccessModes", oldPvc.Spec.AccessModes, "field is immutable"))
}
if !reflect.DeepEqual(oldPvc.Spec.Resources, newPvc.Spec.Resources) {
allErrs = append(allErrs, errs.NewFieldInvalid("spec.Resources", oldPvc.Spec.Resources, "field is immutable"))
}
}
newPvc.Status = oldPvc.Status
return allErrs
}

func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
allErrs = append(allErrs, ValidateObjectMetaUpdate(&oldPvc.ObjectMeta, &newPvc.ObjectMeta).Prefix("metadata")...)
if newPvc.ResourceVersion == "" {
allErrs = append(allErrs, fmt.Errorf("ResourceVersion must be specified"))
}
newPvc.Spec = oldPvc.Spec
return allErrs
}

Expand Down
Loading

0 comments on commit 9bf35e0

Please sign in to comment.