mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-28 01:31:17 +00:00
Add control on PVC to take volume snapshot
Signed-off-by: Akash Srivastava <akash.srivastava@openebs.io>
This commit is contained in:
@@ -3,6 +3,7 @@ package kubernetes
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
|
||||
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"
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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))
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -36,6 +36,7 @@ const (
|
||||
StorageDriver = report.KubernetesStorageDriver
|
||||
VolumeSnapshotName = report.KubernetesVolumeSnapshotName
|
||||
SnapshotData = report.KubernetesSnapshotData
|
||||
VolumeCapacity = report.KubernetesVolumeCapacity
|
||||
)
|
||||
|
||||
// Exposed for testing
|
||||
@@ -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{
|
||||
@@ -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
|
||||
})
|
||||
|
||||
@@ -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, capacity string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type mockPipeClient map[string]xfer.Pipe
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user