Skip to content

Commit

Permalink
Add control on PVC to take volume snapshot
Browse files Browse the repository at this point in the history
Signed-off-by: Akash Srivastava <akash.srivastava@openebs.io>
  • Loading branch information
Akash Srivastava committed Oct 8, 2018
1 parent e36a065 commit 6b08ce9
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 17 deletions.
24 changes: 24 additions & 0 deletions probe/kubernetes/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package kubernetes
import (
"fmt"
"io"
"strings"
"sync"
"time"

"github.com/weaveworks/common/backoff"

snapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1"
snapshot "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned"
"github.com/pborman/uuid"
log "github.com/sirupsen/logrus"
apiappsv1beta1 "k8s.io/api/apps/v1beta1"
apibatchv1 "k8s.io/api/batch/v1"
Expand Down Expand Up @@ -48,6 +50,7 @@ type Client interface {

WatchPods(f func(Event, Pod))

CreateVolumeSnapshot(namespaceID, persistentVolumeClaimID, capacity string) error
GetLogs(namespaceID, podID string, containerNames []string) (io.ReadCloser, error)
DeletePod(namespaceID, podID string) error
ScaleUp(resource, namespaceID, id string) error
Expand Down Expand Up @@ -427,6 +430,27 @@ func (c *client) WalkVolumeSnapshotData(f func(VolumeSnapshotData) error) error
return nil
}

func (c *client) CreateVolumeSnapshot(namespaceID, persistentVolumeClaimID, capacity string) error {
UID := strings.Split(uuid.New(), "-")
volumeSnapshot := &snapshotv1.VolumeSnapshot{
ObjectMeta: metav1.ObjectMeta{
Name: "snapshot-" + time.Now().Format("20060102150405") + "-" + UID[1],
Namespace: namespaceID,
Annotations: map[string]string{
"capacity": capacity,
},
},
Spec: snapshotv1.VolumeSnapshotSpec{
PersistentVolumeClaimName: persistentVolumeClaimID,
},
}
_, err := c.snapshotClient.VolumesnapshotV1().VolumeSnapshots(namespaceID).Create(volumeSnapshot)
if err != nil {
return err
}
return nil
}

func (c *client) GetLogs(namespaceID, podID string, containerNames []string) (io.ReadCloser, error) {
readClosersWithLabel := map[io.ReadCloser]string{}
for _, container := range containerNames {
Expand Down
49 changes: 41 additions & 8 deletions probe/kubernetes/controls.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import (

// Control IDs used by the kubernetes integration.
const (
GetLogs = report.KubernetesGetLogs
DeletePod = report.KubernetesDeletePod
ScaleUp = report.KubernetesScaleUp
ScaleDown = report.KubernetesScaleDown
CreateVolumeSnapshot = report.KubernetesCreateVolumeSnapshot
GetLogs = report.KubernetesGetLogs
DeletePod = report.KubernetesDeletePod
ScaleUp = report.KubernetesScaleUp
ScaleDown = report.KubernetesScaleDown
)

// GetLogs is the control to get the logs for a kubernetes pod
Expand Down Expand Up @@ -43,6 +44,14 @@ func (r *Reporter) GetLogs(req xfer.Request, namespaceID, podID string, containe
}
}

func (r *Reporter) createVolumeSnapshot(req xfer.Request, namespaceID, persistentVolumeClaimID, capacity string) xfer.Response {
err := r.client.CreateVolumeSnapshot(namespaceID, persistentVolumeClaimID, capacity)
if err != nil {
return xfer.ResponseError(err)
}
return xfer.Response{}
}

func (r *Reporter) deletePod(req xfer.Request, namespaceID, podID string, _ []string) xfer.Response {
if err := r.client.DeletePod(namespaceID, podID); err != nil {
return xfer.ResponseError(err)
Expand Down Expand Up @@ -95,6 +104,28 @@ func (r *Reporter) CaptureDeployment(f func(xfer.Request, string, string) xfer.R
}
}

// CapturePersistentVolumeClaim will return name, namespace and capacity of PVC
func (r *Reporter) CapturePersistentVolumeClaim(f func(xfer.Request, string, string, string) xfer.Response) func(xfer.Request) xfer.Response {
return func(req xfer.Request) xfer.Response {
uid, ok := report.ParsePersistentVolumeClaimNodeID(req.NodeID)
if !ok {
return xfer.ResponseErrorf("Invalid ID: %s", req.NodeID)
}
// find persistentVolumeClaim by UID
var persistentVolumeClaim PersistentVolumeClaim
r.client.WalkPersistentVolumeClaims(func(p PersistentVolumeClaim) error {
if p.UID() == uid {
persistentVolumeClaim = p
}
return nil
})
if persistentVolumeClaim == nil {
return xfer.ResponseErrorf("Persistent volume claim not found: %s", uid)
}
return f(req, persistentVolumeClaim.Namespace(), persistentVolumeClaim.Name(), persistentVolumeClaim.GetCapacity())
}
}

// ScaleUp is the control to scale up a deployment
func (r *Reporter) ScaleUp(req xfer.Request, namespace, id string) xfer.Response {
return xfer.ResponseError(r.client.ScaleUp(report.Deployment, namespace, id))
Expand All @@ -107,16 +138,18 @@ func (r *Reporter) ScaleDown(req xfer.Request, namespace, id string) xfer.Respon

func (r *Reporter) registerControls() {
controls := map[string]xfer.ControlHandlerFunc{
GetLogs: r.CapturePod(r.GetLogs),
DeletePod: r.CapturePod(r.deletePod),
ScaleUp: r.CaptureDeployment(r.ScaleUp),
ScaleDown: r.CaptureDeployment(r.ScaleDown),
CreateVolumeSnapshot: r.CapturePersistentVolumeClaim(r.createVolumeSnapshot),
GetLogs: r.CapturePod(r.GetLogs),
DeletePod: r.CapturePod(r.deletePod),
ScaleUp: r.CaptureDeployment(r.ScaleUp),
ScaleDown: r.CaptureDeployment(r.ScaleDown),
}
r.handlerRegistry.Batch(nil, controls)
}

func (r *Reporter) deregisterControls() {
controls := []string{
CreateVolumeSnapshot,
GetLogs,
DeletePod,
ScaleUp,
Expand Down
35 changes: 27 additions & 8 deletions probe/kubernetes/persistentvolumeclaim.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ const (
type PersistentVolumeClaim interface {
Meta
Selector() (labels.Selector, error)
GetNode() report.Node
GetNode(string) report.Node
GetStorageClass() string
GetCapacity() string
}

// persistentVolumeClaim represents kubernetes Persistent Volume Claims
Expand Down Expand Up @@ -47,14 +48,32 @@ func (p *persistentVolumeClaim) GetStorageClass() string {
return storageClassName
}

// GetCapacity returns the storage size of PVC
func (p *persistentVolumeClaim) GetCapacity() string {
capacity := p.Spec.Resources.Requests[apiv1.ResourceStorage]
if capacity.String() != "" {
return capacity.String()
}
return ""
}

// GetNode returns Persistent Volume Claim as Node
func (p *persistentVolumeClaim) GetNode() report.Node {
return p.MetaNode(report.MakePersistentVolumeClaimNodeID(p.UID())).WithLatests(map[string]string{
NodeType: "Persistent Volume Claim",
Status: string(p.Status.Phase),
VolumeName: p.Spec.VolumeName,
StorageClassName: p.GetStorageClass(),
})
func (p *persistentVolumeClaim) GetNode(probeID string) report.Node {
latests := map[string]string{
NodeType: "Persistent Volume Claim",
Status: string(p.Status.Phase),
VolumeName: p.Spec.VolumeName,
StorageClassName: p.GetStorageClass(),
report.ControlProbeID: probeID,
}

if p.GetCapacity() != "" {
latests[VolumeCapacity] = p.GetCapacity()
}

return p.MetaNode(report.MakePersistentVolumeClaimNodeID(p.UID())).
WithLatests(latests).
WithLatestActiveControls(CreateVolumeSnapshot)
}

// Selector returns all Persistent Volume Claim selector
Expand Down
10 changes: 9 additions & 1 deletion probe/kubernetes/reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
StorageDriver = report.KubernetesStorageDriver
VolumeSnapshotName = report.KubernetesVolumeSnapshotName
SnapshotData = report.KubernetesSnapshotData
VolumeCapacity = report.KubernetesVolumeCapacity
)

// Exposed for testing
Expand Down Expand Up @@ -124,6 +125,7 @@ var (
Status: {ID: Status, Label: "Status", From: report.FromLatest, Priority: 3},
VolumeName: {ID: VolumeName, Label: "Volume", From: report.FromLatest, Priority: 4},
StorageClassName: {ID: StorageClassName, Label: "Storage class", From: report.FromLatest, Priority: 5},
VolumeCapacity: {ID: VolumeCapacity, Label: "Capacity", From: report.FromLatest, Priority: 6},
}

StorageClassMetadataTemplates = report.MetadataTemplates{
Expand Down Expand Up @@ -463,8 +465,14 @@ func (r *Reporter) persistentVolumeClaimTopology() (report.Topology, []Persisten
result := report.MakeTopology().
WithMetadataTemplates(PersistentVolumeClaimMetadataTemplates).
WithTableTemplates(TableTemplates)
result.Controls.AddControl(report.Control{
ID: CreateVolumeSnapshot,
Human: "Create snapshot",
Icon: "fa-camera",
Rank: 0,
})
err := r.client.WalkPersistentVolumeClaims(func(p PersistentVolumeClaim) error {
result.AddNode(p.GetNode())
result.AddNode(p.GetNode(r.probeID))
persistentVolumeClaims = append(persistentVolumeClaims, p)
return nil
})
Expand Down
3 changes: 3 additions & 0 deletions probe/kubernetes/reporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ func (c *mockClient) ScaleUp(resource, namespaceID, id string) error {
func (c *mockClient) ScaleDown(resource, namespaceID, id string) error {
return nil
}
func (c *mockClient) CreateVolumeSnapshot(namespaceID, persistentVolumeClaimID string) error {
return nil
}

type mockPipeClient map[string]xfer.Pipe

Expand Down
2 changes: 2 additions & 0 deletions report/map_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ const (
KubernetesStorageDriver = "kubernetes_storage_driver"
KubernetesVolumeSnapshotName = "kubernetes_volume_snapshot_name"
KubernetesSnapshotData = "kuberneets_snapshot_data"
KubernetesCreateVolumeSnapshot = "kubernetes_create_volume_snapshot"
KubernetesVolumeCapacity = "kubernetes_volume_capacity"
// probe/awsecs
ECSCluster = "ecs_cluster"
ECSCreatedAt = "ecs_created_at"
Expand Down

0 comments on commit 6b08ce9

Please sign in to comment.