/
volumes.go
185 lines (160 loc) · 6.65 KB
/
volumes.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
173
174
175
176
177
178
179
180
181
182
183
184
185
// Copyright 2018 NetApp, Inc. All Rights Reserved.
package common
import (
"fmt"
hash "github.com/mitchellh/hashstructure"
log "github.com/sirupsen/logrus"
"github.com/netapp/trident/config"
"github.com/netapp/trident/core"
"github.com/netapp/trident/storage"
sa "github.com/netapp/trident/storage_attribute"
"github.com/netapp/trident/storage_class"
"github.com/netapp/trident/utils"
)
const (
autoStorageClassPrefix = "auto_sc_%d"
)
// getStorageClass accepts a list of volume creation options and returns a
// matching storage class. If the orchestrator already has a matching
// storage class, that is returned; otherwise a new one is created and
// registered with the orchestrator.
func GetStorageClass(options map[string]string, o core.Orchestrator) (*storageclass.Config, error) {
// Create a storage class based on available options
newScConfig, err := makeStorageClass(options)
if err != nil {
return nil, err
}
// Check existing storage classes for a match based on the name
sc, err := o.GetStorageClass(newScConfig.Name)
if err != nil && !core.IsNotFoundError(err) {
return nil, err
}
if sc != nil {
log.WithField("storageClass", sc.Config.Name).Debug("Matched existing storage class.")
return sc.Config, nil
}
// No match found, so register the new storage class
addedSc, err := o.AddStorageClass(newScConfig)
if err != nil {
log.WithFields(log.Fields{
"storageClass": newScConfig.Name,
}).Error("couldn't add the storage class: ", err)
return nil, err
}
return addedSc.Config, nil
}
// MakeStorageClass accepts a list of volume creation options and creates a
// matching storage class. The name of the new storage class contains a hash
// of the attributes it contains, thereby enabling comparison of storage
// classes generated by this method by simply comparing their names.
func makeStorageClass(options map[string]string) (*storageclass.Config, error) {
scConfig := new(storageclass.Config)
if p, ok := options[sa.StoragePools]; ok {
if pools, err := sa.CreateBackendStoragePoolsMapFromEncodedString(p); err != nil {
return nil, err
} else {
scConfig.Pools = pools
delete(options, sa.StoragePools)
}
}
if p, ok := options[sa.AdditionalStoragePools]; ok {
if additionalPools, err := sa.CreateBackendStoragePoolsMapFromEncodedString(p); err != nil {
return nil, err
} else {
scConfig.AdditionalPools = additionalPools
delete(options, sa.AdditionalStoragePools)
}
}
// Map options to storage class attributes
scConfig.Attributes = make(map[string]sa.Request)
for k, v := range options {
// format: attribute: "type:value"
req, err := sa.CreateAttributeRequestFromAttributeValue(k, v)
if err != nil {
log.WithFields(log.Fields{
"storageClass": scConfig.Name,
"storageClass_parameters": options,
}).Debugf("Frontend ignoring storage class attribute: %v", err)
continue
}
scConfig.Attributes[k] = req
}
// Set name based on hash value
scHash, err := hash.Hash(scConfig, nil)
if err != nil {
log.WithFields(log.Fields{
"storageClass": scConfig.Name,
"storageClass_parameters": options,
}).Errorf("Frontend couldn't hash the storage class attributes: %v", err)
return nil, err
}
scConfig.Name = fmt.Sprintf(autoStorageClassPrefix, scHash)
return scConfig, nil
}
// GetVolumeConfig accepts a set of parameters describing a volume creation request
// and returns a volume config structure suitable for passing to the orchestrator core.
func GetVolumeConfig(
name, storageClass string, sizeBytes int64, opts map[string]string,
protocol config.Protocol, accessMode config.AccessMode, volumeMode config.VolumeMode,
) (*storage.VolumeConfig, error) {
return &storage.VolumeConfig{
Name: name,
Size: fmt.Sprintf("%d", sizeBytes),
StorageClass: storageClass,
Protocol: protocol,
AccessMode: accessMode,
VolumeMode: volumeMode,
SpaceReserve: utils.GetV(opts, "spaceReserve", ""),
SecurityStyle: utils.GetV(opts, "securityStyle", ""),
SplitOnClone: utils.GetV(opts, "splitOnClone", ""),
SnapshotPolicy: utils.GetV(opts, "snapshotPolicy", ""),
SnapshotReserve: utils.GetV(opts, "snapshotReserve", ""),
SnapshotDir: utils.GetV(opts, "snapshotDir", ""),
ExportPolicy: utils.GetV(opts, "exportPolicy", ""),
UnixPermissions: utils.GetV(opts, "unixPermissions", ""),
BlockSize: utils.GetV(opts, "blocksize", ""),
QoS: utils.GetV(opts, "qos", ""),
QoSType: utils.GetV(opts, "type", ""),
FileSystem: utils.GetV(opts, "fstype|fileSystemType", ""),
Encryption: utils.GetV(opts, "encryption", ""),
CloneSourceVolume: utils.GetV(opts, "from", ""),
CloneSourceSnapshot: utils.GetV(opts, "fromSnapshot", ""),
ServiceLevel: utils.GetV(opts, "serviceLevel", ""),
Network: utils.GetV(opts, "network", ""),
}, nil
}
func CombineAccessModes(accessModes []config.AccessMode) config.AccessMode {
volConfigAccessMode := config.ModeAny
for _, accessMode := range accessModes {
// Rules for combining multiple access modes into a single access mode:
// Current AccessMode Next AccessMode Result
// Any Any Any
// Any ReadWriteOnce ReadWriteOnce
// Any ReadOnlyMany ReadOnlyMany
// Any ReadWriteMany ReadWriteMany
// ReadWriteOnce Any ReadWriteOnce
// ReadWriteOnce ReadWriteOnce ReadWriteOnce
// ReadWriteOnce ReadOnlyMany ReadWriteMany
// ReadWriteOnce ReadWriteMany ReadWriteMany
// ReadOnlyMany Any ReadOnlyMany
// ReadOnlyMany ReadWriteOnce ReadWriteMany
// ReadOnlyMany ReadOnlyMany ReadOnlyMany
// ReadOnlyMany ReadWriteMany ReadWriteMany
// ReadWriteMany Any ReadWriteMany
// ReadWriteMany ReadWriteOnce ReadWriteMany
// ReadWriteMany ReadOnlyMany ReadWriteMany
// ReadWriteMany ReadWriteMany ReadWriteMany
if volConfigAccessMode == config.ModeAny {
volConfigAccessMode = accessMode
} else if volConfigAccessMode == config.ReadWriteOnce {
if accessMode == config.ReadOnlyMany || accessMode == config.ReadWriteMany {
volConfigAccessMode = config.ReadWriteMany
}
} else if volConfigAccessMode == config.ReadOnlyMany {
if accessMode == config.ReadWriteOnce || accessMode == config.ReadWriteMany {
volConfigAccessMode = config.ReadWriteMany
}
}
}
return volConfigAccessMode
}