-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathvolume_finder.go
172 lines (146 loc) · 6.08 KB
/
volume_finder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
Copyright (c) 2020-2022 Dell Inc. or its subsidiaries. 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 k8s
import (
"context"
"fmt"
"strings"
"time"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
tracer "github.com/dell/karavi-topology/internal/tracers"
"github.com/sirupsen/logrus"
)
const (
// ProtocolNfs Protocol NFS in lower case
ProtocolNfs = "nfs"
// CsiDriverNamePowerScale CSI PowerScale Name
CsiDriverNamePowerScale = "isilon"
// CsiDriverNamePowerMax CSI PowerMax Name
CsiDriverNamePowerMax = "powermax"
)
// VolumeGetter is an interface for getting a list of persistent volume information
//
//go:generate mockgen -destination=mocks/volume_getter_mocks.go -package=mocks github.com/dell/karavi-topology/internal/k8s VolumeGetter
type VolumeGetter interface {
GetPersistentVolumes() (*corev1.PersistentVolumeList, error)
}
// VolumeFinder is a volume finder that will query the Kubernetes API for Persistent Volumes created by a matching DriverName
type VolumeFinder struct {
API VolumeGetter
DriverNames []string
Logger *logrus.Logger
}
// VolumeInfo contains information about mapping a Persistent Volume to the volume created on a storage system
type VolumeInfo struct {
Namespace string `json:"namespace"`
PersistentVolumeClaim string `json:"persistent_volume_claim"`
PersistentVolumeStatus string `json:"volume_status"`
VolumeClaimName string `json:"volume_claim_name"`
PersistentVolume string `json:"persistent_volume"`
StorageClass string `json:"storage_class"`
Driver string `json:"driver"`
ProvisionedSize string `json:"provisioned_size"`
StorageSystemVolumeName string `json:"storage_system_volume_name"`
StoragePoolName string `json:"storage_pool_name"`
StorageSystem string `json:"storage_system"`
Protocol string `json:"protocol"`
CreatedTime string `json:"created_time"`
}
// GetPersistentVolumes will return a list of persistent volume information
func (f VolumeFinder) GetPersistentVolumes(ctx context.Context) ([]VolumeInfo, error) {
ctx, span := tracer.GetTracer(ctx, "GetPersistentVolumes")
defer span.End()
start := time.Now()
defer f.timeSince(start, "GetPersistentVolumes")
volumeInfo := make([]VolumeInfo, 0)
volumes, err := f.API.GetPersistentVolumes()
if err != nil {
return nil, err
}
for _, volume := range volumes.Items {
if volume.Spec.CSI != nil && Contains(f.DriverNames, volume.Spec.CSI.Driver) {
capacity := volume.Spec.Capacity[v1.ResourceStorage]
claim := volume.Spec.ClaimRef
status := volume.Status
volumeHandle := volume.Spec.CSI.VolumeHandle
f.Logger.WithField("volume_attributes", volume.Spec.CSI.VolumeAttributes).Debug("volumefinder volumes attributes map")
info := VolumeInfo{
Namespace: claim.Namespace,
PersistentVolumeClaim: string(claim.UID),
VolumeClaimName: claim.Name,
PersistentVolumeStatus: string(status.Phase),
PersistentVolume: volume.Name,
StorageClass: volume.Spec.StorageClassName,
Driver: volume.Spec.CSI.Driver,
ProvisionedSize: capacity.String(),
StorageSystemVolumeName: volume.Spec.CSI.VolumeAttributes["Name"],
StoragePoolName: volume.Spec.CSI.VolumeAttributes["StoragePoolName"],
StorageSystem: volume.Spec.CSI.VolumeAttributes["StorageSystem"],
Protocol: volume.Spec.CSI.VolumeAttributes["Protocol"],
CreatedTime: volume.CreationTimestamp.String(),
}
// powerstore do not return this value, csi created volume has storage volume name and pv name same
if info.StorageSystemVolumeName == "" || len(info.StorageSystemVolumeName) == 0 {
info.StorageSystemVolumeName = volume.Name
}
// powerflex will provide storagesystem id and powerstore will provide array IP
if info.StorageSystem == "" || len(info.StorageSystem) == 0 {
info.StorageSystem = volume.Spec.CSI.VolumeAttributes["arrayID"]
}
// set StoregeSystem and Protocol for PowerScale
if strings.Contains(info.Driver, CsiDriverNamePowerScale) {
info.StorageSystem = volume.Spec.CSI.VolumeAttributes["ClusterName"] + ":" + volume.Spec.CSI.VolumeAttributes["AccessZone"]
info.Protocol = ProtocolNfs
}
// set attributes for PowerMax
if strings.Contains(info.Driver, CsiDriverNamePowerMax) {
info.StorageSystemVolumeName = parsePowerMaxVolumeName(volumeHandle)
info.StorageSystem = volume.Spec.CSI.VolumeAttributes["powermax/SYMID"]
info.StoragePoolName = volume.Spec.CSI.VolumeAttributes["SRP"]
if info.Protocol == "" {
info.Protocol = "N/A"
}
}
// powerstore volume do not have storage pool unlike powerflex
if info.StoragePoolName == "" || len(info.StoragePoolName) == 0 {
info.StoragePoolName = "N/A"
}
volumeInfo = append(volumeInfo, info)
}
}
return volumeInfo, nil
}
// parsePowerMaxVolumeName parse PowerMax PV volumeHandle and return storage volume name
func parsePowerMaxVolumeName(volumeHandle string) string {
ele := strings.Split(volumeHandle, "-")
if len(ele) == 7 {
return fmt.Sprintf("%s:%s", ele[6], strings.Join(ele[0:5], "-"))
}
return volumeHandle
}
// Contains will return true if the slice contains the given value
func Contains(slice []string, value string) bool {
for _, element := range slice {
if element == value {
return true
}
}
return false
}
func (f VolumeFinder) timeSince(start time.Time, fName string) {
f.Logger.WithFields(logrus.Fields{
"duration": fmt.Sprintf("%v", time.Since(start)),
"function": fName,
}).Debug("function duration")
}