PV Recycling API

This commit is contained in:
markturansky 2015-05-29 16:12:10 -04:00
parent a7ee5559b1
commit 2829fadfad
21 changed files with 155 additions and 11 deletions

View File

@ -10603,6 +10603,10 @@
"claimRef": {
"$ref": "v1.ObjectReference",
"description": "when bound, a reference to the bound claim"
},
"persistentVolumeReclaimPolicy": {
"type": "string",
"description": "persistentVolumeReclaimPolicy is what happens to a volume when released from its claim; Default is Retain."
}
}
},
@ -10807,6 +10811,14 @@
"phase": {
"type": "string",
"description": "the current phase of a persistent volume"
},
"message": {
"type": "string",
"description": "human-readable message indicating details about why the volume is in this state"
},
"reason": {
"type": "string",
"description": "(brief) reason the volume is not is not available, such as failed recycling"
}
}
},
@ -12041,4 +12053,4 @@
}
}
}
}
}

View File

@ -10600,6 +10600,10 @@
"claimRef": {
"$ref": "v1beta3.ObjectReference",
"description": "when bound, a reference to the bound claim"
},
"persistentVolumeReclaimPolicy": {
"type": "string",
"description": "persistentVolumeReclaimPolicy is what happens to a volume when released from its claim; Default is Retain."
}
}
},
@ -10804,6 +10808,14 @@
"phase": {
"type": "string",
"description": "the current phase of a persistent volume"
},
"message": {
"type": "string",
"description": "human-readable message indicating details about why the volume is in this state"
},
"reason": {
"type": "string",
"description": "(brief) reason the volume is not is not available, such as failed recycling"
}
}
},
@ -10862,8 +10874,7 @@
"v1beta3.PodSpec": {
"id": "v1beta3.PodSpec",
"required": [
"containers",
"serviceAccount"
"containers"
],
"properties": {
"volumes": {
@ -12048,4 +12059,4 @@
}
}
}
}
}

View File

@ -6,8 +6,9 @@ metadata:
type: local
spec:
capacity:
storage: 5Gi
storage: 8Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/tmp/data02"
persistentVolumeReclaimPolicy: Recycle

View File

@ -1243,11 +1243,14 @@ func deepCopy_api_PersistentVolumeSpec(in PersistentVolumeSpec, out *PersistentV
} else {
out.ClaimRef = nil
}
out.PersistentVolumeReclaimPolicy = in.PersistentVolumeReclaimPolicy
return nil
}
func deepCopy_api_PersistentVolumeStatus(in PersistentVolumeStatus, out *PersistentVolumeStatus, c *conversion.Cloner) error {
out.Phase = in.Phase
out.Message = in.Message
out.Reason = in.Reason
return nil
}

View File

@ -234,8 +234,11 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
},
func(pv *api.PersistentVolume, c fuzz.Continue) {
c.FuzzNoCustom(pv) // fuzz self without calling this function again
types := []api.PersistentVolumePhase{api.VolumePending, api.VolumeBound, api.VolumeReleased, api.VolumeAvailable}
types := []api.PersistentVolumePhase{api.VolumeAvailable, api.VolumePending, api.VolumeBound, api.VolumeReleased, api.VolumeFailed}
pv.Status.Phase = types[c.Rand.Intn(len(types))]
pv.Status.Message = c.RandString()
reclamationPolicies := []api.PersistentVolumeReclaimPolicy{api.PersistentVolumeReclaimRecycle, api.PersistentVolumeReclaimRetain}
pv.Spec.PersistentVolumeReclaimPolicy = reclamationPolicies[c.Rand.Intn(len(reclamationPolicies))]
},
func(pvc *api.PersistentVolumeClaim, c fuzz.Continue) {
c.FuzzNoCustom(pvc) // fuzz self without calling this function again

View File

@ -263,11 +263,33 @@ type PersistentVolumeSpec struct {
// ClaimRef is expected to be non-nil when bound.
// claim.VolumeName is the authoritative bind between PV and PVC.
ClaimRef *ObjectReference `json:"claimRef,omitempty"`
// Optional: what happens to a persistent volume when released from its claim.
PersistentVolumeReclaimPolicy PersistentVolumeReclaimPolicy `json:"persistentVolumeReclaimPolicy,omitempty" description:"what happens to a volume when released from its claim; Valid options are Retain (default) and Recycle. Recyling must be supported by the volume plugin underlying this persistent volume."`
}
// PersistentVolumeReclaimPolicy describes a policy for end-of-life maintenance of persistent volumes
type PersistentVolumeReclaimPolicy string
const (
// PersistentVolumeReclaimRecycle means the volume will be recycled back into the pool of unbound persistent volumes on release from its claim.
// The volume plugin must support Recycling.
PersistentVolumeReclaimRecycle PersistentVolumeReclaimPolicy = "Recycle"
// PersistentVolumeReclaimDelete means the volume will be deleted from Kubernetes on release from its claim.
// The volume plugin must support Deletion.
// TODO: implement w/ DeletableVolumePlugin
// PersistentVolumeReclaimDelete PersistentVolumeReclaimPolicy = "Delete"
// PersistentVolumeReclaimRetain means the volume will left in its current phase (Released) for manual reclamation by the administrator.
// The default policy is Retain.
PersistentVolumeReclaimRetain PersistentVolumeReclaimPolicy = "Retain"
)
type PersistentVolumeStatus struct {
// Phase indicates if a volume is available, bound to a claim, or released by a claim
Phase PersistentVolumePhase `json:"phase,omitempty"`
// A human-readable message indicating details about why the volume is in this state.
Message string `json:"message,omitempty"`
// Reason is a brief CamelCase string that describes any failure and is meant for machine parsing and tidy display in the CLI
Reason string `json:"reason,omitempty"`
}
type PersistentVolumeList struct {
@ -331,12 +353,16 @@ const (
// used for PersistentVolumes that are not available
VolumePending PersistentVolumePhase = "Pending"
// used for PersistentVolumes that are not yet bound
// Available volumes are held by the binder and matched to PersistentVolumeClaims
VolumeAvailable PersistentVolumePhase = "Available"
// used for PersistentVolumes that are bound
VolumeBound PersistentVolumePhase = "Bound"
// used for PersistentVolumes where the bound PersistentVolumeClaim was deleted
// released volumes must be recycled before becoming available again
// this phase is used by the persistent volume claim binder to signal to another process to reclaim the resource
VolumeReleased PersistentVolumePhase = "Released"
// used for PersistentVolumes that failed to be correctly recycled or deleted after being released from a claim
VolumeFailed PersistentVolumePhase = "Failed"
)
type PersistentVolumeClaimPhase string

View File

@ -1358,6 +1358,7 @@ func convert_api_PersistentVolumeSpec_To_v1_PersistentVolumeSpec(in *api.Persist
} else {
out.ClaimRef = nil
}
out.PersistentVolumeReclaimPolicy = PersistentVolumeReclaimPolicy(in.PersistentVolumeReclaimPolicy)
return nil
}
@ -1366,6 +1367,8 @@ func convert_api_PersistentVolumeStatus_To_v1_PersistentVolumeStatus(in *api.Per
defaulting.(func(*api.PersistentVolumeStatus))(in)
}
out.Phase = PersistentVolumePhase(in.Phase)
out.Message = in.Message
out.Reason = in.Reason
return nil
}
@ -3633,6 +3636,7 @@ func convert_v1_PersistentVolumeSpec_To_api_PersistentVolumeSpec(in *PersistentV
} else {
out.ClaimRef = nil
}
out.PersistentVolumeReclaimPolicy = api.PersistentVolumeReclaimPolicy(in.PersistentVolumeReclaimPolicy)
return nil
}
@ -3641,6 +3645,8 @@ func convert_v1_PersistentVolumeStatus_To_api_PersistentVolumeStatus(in *Persist
defaulting.(func(*PersistentVolumeStatus))(in)
}
out.Phase = api.PersistentVolumePhase(in.Phase)
out.Message = in.Message
out.Reason = in.Reason
return nil
}

View File

@ -1174,11 +1174,14 @@ func deepCopy_v1_PersistentVolumeSpec(in PersistentVolumeSpec, out *PersistentVo
} else {
out.ClaimRef = nil
}
out.PersistentVolumeReclaimPolicy = in.PersistentVolumeReclaimPolicy
return nil
}
func deepCopy_v1_PersistentVolumeStatus(in PersistentVolumeStatus, out *PersistentVolumeStatus, c *conversion.Cloner) error {
out.Phase = in.Phase
out.Message = in.Message
out.Reason = in.Reason
return nil
}

View File

@ -113,6 +113,9 @@ func addDefaultingFuncs() {
if obj.Status.Phase == "" {
obj.Status.Phase = VolumePending
}
if obj.Spec.PersistentVolumeReclaimPolicy == "" {
obj.Spec.PersistentVolumeReclaimPolicy = PersistentVolumeReclaimRetain
}
},
func(obj *PersistentVolumeClaim) {
if obj.Status.Phase == "" {

View File

@ -258,6 +258,9 @@ func TestSetDefaultPersistentVolume(t *testing.T) {
if pv2.Status.Phase != versioned.VolumePending {
t.Errorf("Expected volume phase %v, got %v", versioned.VolumePending, pv2.Status.Phase)
}
if pv2.Spec.PersistentVolumeReclaimPolicy != versioned.PersistentVolumeReclaimRetain {
t.Errorf("Expected pv reclaim policy %v, got %v", versioned.PersistentVolumeReclaimRetain, pv2.Spec.PersistentVolumeReclaimPolicy)
}
}
func TestSetDefaultPersistentVolumeClaim(t *testing.T) {

View File

@ -280,11 +280,33 @@ type PersistentVolumeSpec struct {
// ClaimRef is expected to be non-nil when bound.
// claim.VolumeName is the authoritative bind between PV and PVC.
ClaimRef *ObjectReference `json:"claimRef,omitempty" description:"when bound, a reference to the bound claim"`
// Optional: what happens to a persistent volume when released from its claim.
PersistentVolumeReclaimPolicy PersistentVolumeReclaimPolicy `json:"persistentVolumeReclaimPolicy,omitempty" description:"what happens to a volume when released from its claim; Valid options are Retain (default) and Recycle. Recyling must be supported by the volume plugin underlying this persistent volume."`
}
// PersistentVolumeReclaimPolicy describes a policy for end-of-life maintenance of persistent volumes
type PersistentVolumeReclaimPolicy string
const (
// PersistentVolumeReclaimRecycle means the volume will be recycled back into the pool of unbound persistent volumes on release from its claim.
// The volume plugin must support Recycling.
PersistentVolumeReclaimRecycle PersistentVolumeReclaimPolicy = "Recycle"
// PersistentVolumeReclaimDelete means the volume will be deleted from Kubernetes on release from its claim.
// The volume plugin must support Deletion.
// TODO: implement w/ DeletableVolumePlugin
// PersistentVolumeReclaimDelete PersistentVolumeReclaimPolicy = "Delete"
// PersistentVolumeReclaimRetain means the volume will left in its current phase (Released) for manual reclamation by the administrator.
// The default policy is Retain.
PersistentVolumeReclaimRetain PersistentVolumeReclaimPolicy = "Retain"
)
type PersistentVolumeStatus struct {
// Phase indicates if a volume is available, bound to a claim, or released by a claim
Phase PersistentVolumePhase `json:"phase,omitempty" description:"the current phase of a persistent volume"`
// A human-readable message indicating details about why the volume is in this state.
Message string `json:"message,omitempty" description:"human-readable message indicating details about why the volume is in this state"`
// Reason is a brief CamelCase string that describes any failure and is meant for machine parsing and tidy display in the CLI
Reason string `json:"reason,omitempty" description:"(brief) reason the volume is not is not available"`
}
type PersistentVolumeList struct {
@ -348,12 +370,16 @@ const (
// used for PersistentVolumes that are not available
VolumePending PersistentVolumePhase = "Pending"
// used for PersistentVolumes that are not yet bound
// Available volumes are held by the binder and matched to PersistentVolumeClaims
VolumeAvailable PersistentVolumePhase = "Available"
// used for PersistentVolumes that are bound
VolumeBound PersistentVolumePhase = "Bound"
// used for PersistentVolumes where the bound PersistentVolumeClaim was deleted
// released volumes must be recycled before becoming available again
// this phase is used by the persistent volume claim binder to signal to another process to reclaim the resource
VolumeReleased PersistentVolumePhase = "Released"
// used for PersistentVolumes that failed to be correctly recycled or deleted after being released from a claim
VolumeFailed PersistentVolumePhase = "Failed"
)
type PersistentVolumeClaimPhase string

View File

@ -1216,6 +1216,7 @@ func convert_api_PersistentVolumeSpec_To_v1beta3_PersistentVolumeSpec(in *api.Pe
} else {
out.ClaimRef = nil
}
out.PersistentVolumeReclaimPolicy = PersistentVolumeReclaimPolicy(in.PersistentVolumeReclaimPolicy)
return nil
}
@ -1224,6 +1225,8 @@ func convert_api_PersistentVolumeStatus_To_v1beta3_PersistentVolumeStatus(in *ap
defaulting.(func(*api.PersistentVolumeStatus))(in)
}
out.Phase = PersistentVolumePhase(in.Phase)
out.Message = in.Message
out.Reason = in.Reason
return nil
}
@ -3305,6 +3308,7 @@ func convert_v1beta3_PersistentVolumeSpec_To_api_PersistentVolumeSpec(in *Persis
} else {
out.ClaimRef = nil
}
out.PersistentVolumeReclaimPolicy = api.PersistentVolumeReclaimPolicy(in.PersistentVolumeReclaimPolicy)
return nil
}
@ -3313,6 +3317,8 @@ func convert_v1beta3_PersistentVolumeStatus_To_api_PersistentVolumeStatus(in *Pe
defaulting.(func(*PersistentVolumeStatus))(in)
}
out.Phase = api.PersistentVolumePhase(in.Phase)
out.Message = in.Message
out.Reason = in.Reason
return nil
}

View File

@ -1178,11 +1178,14 @@ func deepCopy_v1beta3_PersistentVolumeSpec(in PersistentVolumeSpec, out *Persist
} else {
out.ClaimRef = nil
}
out.PersistentVolumeReclaimPolicy = in.PersistentVolumeReclaimPolicy
return nil
}
func deepCopy_v1beta3_PersistentVolumeStatus(in PersistentVolumeStatus, out *PersistentVolumeStatus, c *conversion.Cloner) error {
out.Phase = in.Phase
out.Message = in.Message
out.Reason = in.Reason
return nil
}

View File

@ -117,6 +117,9 @@ func addDefaultingFuncs() {
if obj.Status.Phase == "" {
obj.Status.Phase = VolumePending
}
if obj.Spec.PersistentVolumeReclaimPolicy == "" {
obj.Spec.PersistentVolumeReclaimPolicy = PersistentVolumeReclaimRetain
}
},
func(obj *PersistentVolumeClaim) {
if obj.Status.Phase == "" {

View File

@ -195,6 +195,9 @@ func TestSetDefaultPersistentVolume(t *testing.T) {
if pv2.Status.Phase != versioned.VolumePending {
t.Errorf("Expected volume phase %v, got %v", versioned.VolumePending, pv2.Status.Phase)
}
if pv2.Spec.PersistentVolumeReclaimPolicy != versioned.PersistentVolumeReclaimRetain {
t.Errorf("Expected pv reclaim policy %v, got %v", versioned.PersistentVolumeReclaimRetain, pv2.Spec.PersistentVolumeReclaimPolicy)
}
}
func TestSetDefaultPersistentVolumeClaim(t *testing.T) {

View File

@ -280,11 +280,33 @@ type PersistentVolumeSpec struct {
// ClaimRef is expected to be non-nil when bound.
// claim.VolumeName is the authoritative bind between PV and PVC.
ClaimRef *ObjectReference `json:"claimRef,omitempty" description:"when bound, a reference to the bound claim"`
// Optional: what happens to a persistent volume when released from its claim.
PersistentVolumeReclaimPolicy PersistentVolumeReclaimPolicy `json:"persistentVolumeReclaimPolicy,omitempty" description:"what happens to a volume when released from its claim; Valid options are Retain (default) and Recycle. Recyling must be supported by the volume plugin underlying this persistent volume."`
}
// PersistentVolumeReclaimPolicy describes a policy for end-of-life maintenance of persistent volumes
type PersistentVolumeReclaimPolicy string
const (
// PersistentVolumeReclaimRecycle means the volume will be recycled back into the pool of unbound persistent volumes on release from its claim.
// The volume plugin must support Recycling.
PersistentVolumeReclaimRecycle PersistentVolumeReclaimPolicy = "Recycle"
// PersistentVolumeReclaimDelete means the volume will be deleted from Kubernetes on release from its claim.
// The volume plugin must support Deletion.
// TODO: implement w/ DeletableVolumePlugin
// PersistentVolumeReclaimDelete PersistentVolumeReclaimPolicy = "Delete"
// PersistentVolumeReclaimRetain means the volume will left in its current phase (Released) for manual reclamation by the administrator.
// The default policy is Retain.
PersistentVolumeReclaimRetain PersistentVolumeReclaimPolicy = "Retain"
)
type PersistentVolumeStatus struct {
// Phase indicates if a volume is available, bound to a claim, or released by a claim
Phase PersistentVolumePhase `json:"phase,omitempty" description:"the current phase of a persistent volume"`
// A human-readable message indicating details about why the volume is in this state.
Message string `json:"message,omitempty" description:"human-readable message indicating details about why the volume is in this state"`
// Reason is a brief CamelCase string that describes any failure and is meant for machine parsing and tidy display in the CLI
Reason string `json:"reason,omitempty" description:"(brief) reason the volume is not is not available"`
}
type PersistentVolumeList struct {
@ -348,12 +370,16 @@ const (
// used for PersistentVolumes that are not available
VolumePending PersistentVolumePhase = "Pending"
// used for PersistentVolumes that are not yet bound
// Available volumes are held by the binder and matched to PersistentVolumeClaims
VolumeAvailable PersistentVolumePhase = "Available"
// used for PersistentVolumes that are bound
VolumeBound PersistentVolumePhase = "Bound"
// used for PersistentVolumes where the bound PersistentVolumeClaim was deleted
// released volumes must be recycled before becoming available again
// this phase is used by the persistent volume claim binder to signal to another process to reclaim the resource
VolumeReleased PersistentVolumePhase = "Released"
// used for PersistentVolumes that failed to be correctly recycled or deleted after being released from a claim
VolumeFailed PersistentVolumePhase = "Failed"
)
type PersistentVolumeClaimPhase string

View File

@ -151,7 +151,8 @@ func TestPersistentVolumeStatusUpdate(t *testing.T) {
},
},
Status: api.PersistentVolumeStatus{
Phase: api.VolumeBound,
Phase: api.VolumeBound,
Message: "foo",
},
}
c := &testClient{

View File

@ -311,6 +311,8 @@ func (d *PersistentVolumeDescriber) Describe(namespace, name string) (string, er
} else {
fmt.Fprintf(out, "Claim:\t%s\n", "")
}
fmt.Fprintf(out, "Reclaim Policy:\t%d\n", pv.Spec.PersistentVolumeReclaimPolicy)
fmt.Fprintf(out, "Message:\t%d\n", pv.Status.Message)
return nil
})
}

View File

@ -259,7 +259,7 @@ var resourceQuotaColumns = []string{"NAME"}
var namespaceColumns = []string{"NAME", "LABELS", "STATUS"}
var secretColumns = []string{"NAME", "TYPE", "DATA"}
var serviceAccountColumns = []string{"NAME", "SECRETS"}
var persistentVolumeColumns = []string{"NAME", "LABELS", "CAPACITY", "ACCESSMODES", "STATUS", "CLAIM"}
var persistentVolumeColumns = []string{"NAME", "LABELS", "CAPACITY", "ACCESSMODES", "STATUS", "CLAIM", "REASON"}
var persistentVolumeClaimColumns = []string{"NAME", "LABELS", "STATUS", "VOLUME"}
var componentStatusColumns = []string{"NAME", "STATUS", "MESSAGE", "ERROR"}
@ -732,7 +732,7 @@ func printPersistentVolume(pv *api.PersistentVolume, w io.Writer, withNamespace
aQty := pv.Spec.Capacity[api.ResourceStorage]
aSize := aQty.Value()
_, err := fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\t%s\n", name, formatLabels(pv.Labels), aSize, modesStr, pv.Status.Phase, claimRefUID)
_, err := fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\t%s\t%s\n", name, formatLabels(pv.Labels), aSize, modesStr, pv.Status.Phase, claimRefUID, pv.Status.Reason)
return err
}

View File

@ -59,9 +59,12 @@ func validNewPersistentVolume(name string) *api.PersistentVolume {
PersistentVolumeSource: api.PersistentVolumeSource{
HostPath: &api.HostPathVolumeSource{Path: "/foo"},
},
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimRetain,
},
Status: api.PersistentVolumeStatus{
Phase: api.VolumePending,
Phase: api.VolumePending,
Message: "bar",
Reason: "foo",
},
}
return pv

View File

@ -98,7 +98,7 @@ func TestExampleObjects(t *testing.T) {
Spec: api.PersistentVolumeSpec{
AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse("5Gi"),
api.ResourceName(api.ResourceStorage): resource.MustParse("8Gi"),
},
PersistentVolumeSource: api.PersistentVolumeSource{
HostPath: &api.HostPathVolumeSource{