• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubernetes-sigs / azuredisk-csi-driver / 12595822764

03 Jan 2025 09:47AM UTC coverage: 66.391% (+1.8%) from 64.6%
12595822764

Pull #2787

github

ScottZhuMS
test: refine UT for gen-disk-skus-map_test
Pull Request #2787: test: refine UT for gen-disk-skus-map_test

7 of 10 new or added lines in 1 file covered. (70.0%)

20 existing lines in 1 file now uncovered.

4018 of 6052 relevant lines covered (66.39%)

5.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.71
/pkg/tool/gen-disk-skus-map.go
1
/*
2
Copyright 2021 The Kubernetes Authors.
3

4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    http://www.apache.org/licenses/LICENSE-2.0
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
package main
18

19
import (
20
        "bytes"
21
        "encoding/json"
22
        "fmt"
23
        "io"
24
        "os"
25
        "os/exec"
26
        "strconv"
27
        "strings"
28

29
        "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6"
30
        "k8s.io/klog/v2"
31

32
        "sigs.k8s.io/azuredisk-csi-driver/pkg/optimization"
33
)
34

35
var (
36
        MaxValueOfMaxSharesCapability        = "maxvalueofmaxshares"
37
        MaxBurstIopsCapability               = "maxburstiops"
38
        MaxIOpsCapability                    = "maxiops"
39
        MaxBandwidthMBpsCapability           = "maxbandwidthmbps"
40
        MaxBurstBandwidthMBpsCapability      = "maxburstbandwidthmbps"
41
        MaxSizeGiBCapability                 = "maxsizegib"
42
        UncachedDiskIOPSCapability           = "uncacheddiskiops"
43
        UncachedDiskBytesPerSecondCapability = "uncacheddiskbytespersecond"
44
        MaxDataDiskCountCapability           = "maxdatadiskcount"
45
        VCPUsCapability                      = "vcpus"
46
)
47

48
func init() {
1✔
49
        klog.InitFlags(nil)
1✔
50
}
1✔
51

52
// exit is a separate function to handle program termination
53
var exit = func(code int) {
×
54
        os.Exit(code)
×
55
}
×
56

57
func main() {
1✔
58

1✔
59
        boilerPlate := `/*
1✔
60
Copyright 2021 The Kubernetes Authors.
1✔
61
        
1✔
62
Licensed under the Apache License, Version 2.0 (the "License");
1✔
63
you may not use this file except in compliance with the License.
1✔
64
You may obtain a copy of the License at
1✔
65

1✔
66
    http://www.apache.org/licenses/LICENSE-2.0
1✔
67
        
1✔
68
Unless required by applicable law or agreed to in writing, software
1✔
69
distributed under the License is distributed on an "AS IS" BASIS,
1✔
70
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1✔
71
See the License for the specific language governing permissions and
1✔
72
limitations under the License.
1✔
73
*/
1✔
74
        
1✔
75
package optimization
1✔
76
        
1✔
77
import (
1✔
78
)`
1✔
79
        var sb strings.Builder
1✔
80
        diskMapStart := "        DiskSkuMap = map[string]map[string]DiskSkuInfo{"
1✔
81
        diskMapEnd := "        }"
1✔
82
        accStart := `        "%s": map[string]DiskSkuInfo {`
1✔
83
        accEnd := "                },"
1✔
84
        diskSku := `                "%s": DiskSkuInfo{StorageAccountType: "%s", StorageTier: "%s", DiskSize: "%s", MaxAllowedShares: %s, MaxBurstIops: %s, MaxIops: %s, MaxBwMbps: %s, MaxBurstBwMbps: %s, MaxSizeGiB: %s},`
1✔
85

1✔
86
        nodeMapStart := "        NodeInfoMap = map[string]NodeInfo{"
1✔
87
        nodeInfo := `        "%s": NodeInfo{SkuName: "%s", MaxDataDiskCount: %s, VCpus: %s, MaxBurstIops: %s, MaxIops: %s, MaxBwMbps: %s, MaxBurstBwMbps: %s},`
1✔
88
        nodeMapEnd := "        }"
1✔
89

1✔
90
        skusFullfilePath := "skus-full.json"
1✔
91
        defer os.Remove(skusFullfilePath)
1✔
92
        skusFilePath := "pkg/azuredisk/azure_skus_map.go"
1✔
93

1✔
94
        skuMap := map[string]bool{}
1✔
95

1✔
96
        var resources []*armcompute.ResourceSKU
1✔
97

1✔
98
        if err := getAllSkus(&skusFullfilePath); err != nil {
1✔
UNCOV
99
                klog.Errorf("Could not get skus. Error: %v", err)
×
UNCOV
100
        }
×
101

102
        diskSkusFullJSON, err := os.Open(skusFullfilePath)
1✔
103
        if err != nil {
1✔
104
                klog.Errorf("Could not read file. Error: %v, FilePath: %s", err, skusFullfilePath)
×
105
                return
×
106
        }
×
107
        defer diskSkusFullJSON.Close()
1✔
108

1✔
109
        byteValue, _ := io.ReadAll(diskSkusFullJSON)
1✔
110

1✔
111
        err = json.Unmarshal([]byte(byteValue), &resources)
1✔
112
        if err != nil {
1✔
UNCOV
113
                klog.Errorf("Could not parse json file file. Error: %v, FilePath: %s", err, skusFullfilePath)
×
UNCOV
114
                return
×
UNCOV
115
        }
×
116

117
        diskSkuInfoMap := map[string]map[string]optimization.DiskSkuInfo{}
1✔
118
        vmSkuInfoMap := map[string]optimization.NodeInfo{}
1✔
119

1✔
120
        for _, sku := range resources {
5✔
121
                resType := strings.ToLower(*sku.ResourceType)
4✔
122
                skuKey := ""
4✔
123
                if resType == "disks" {
6✔
124
                        skuKey = fmt.Sprintf("%s-%s-%s", *sku.Name, *sku.Tier, *sku.Size)
2✔
125
                } else if resType == "virtualmachines" {
5✔
126
                        skuKey = *sku.Name
1✔
127
                } else {
2✔
128
                        continue
1✔
129
                }
130
                // If we already added the sku, skip
131
                skuKeyLower := strings.ToLower(skuKey)
3✔
132
                if _, ok := skuMap[skuKeyLower]; ok {
4✔
133
                        continue
1✔
134
                }
135
                skuMap[skuKeyLower] = true
2✔
136
                if resType == "disks" {
3✔
137
                        account := strings.ToLower(*sku.Name)
1✔
138
                        diskSize := strings.ToLower(*sku.Size)
1✔
139
                        if _, ok := diskSkuInfoMap[account]; !ok {
2✔
140
                                diskSkuInfoMap[account] = map[string]optimization.DiskSkuInfo{}
1✔
141
                        }
1✔
142
                        diskSkuInfoMap[account][diskSize], err = getDiskCapabilities(sku)
1✔
143
                        if err != nil {
1✔
144
                                klog.Errorf("populateSkuMap: Failed to get disk capabilities for disk %s %s %s. Error: %v", *sku.Name, *sku.Size, *sku.Tier, err)
×
145
                                exit(1)
×
146
                        }
×
147
                } else if resType == "virtualmachines" {
2✔
148
                        nodeInfo := optimization.NodeInfo{}
1✔
149
                        nodeInfo.SkuName = *sku.Name
1✔
150
                        err = populateNodeCapabilities(sku, &nodeInfo)
1✔
151
                        if err != nil {
1✔
152
                                klog.Errorf("populateSkuMap: Failed to populate node capabilities. Error: %v", err)
×
153
                                exit(1)
×
154
                        }
×
155
                        vmSkuInfoMap[strings.ToLower(*sku.Name)] = nodeInfo
1✔
156
                }
157
        }
158

159
        // Write the boiler plate stuff
160
        appendWithErrCheck(&sb, boilerPlate)
1✔
161
        appendWithErrCheck(&sb, "\n")
1✔
162
        appendWithErrCheck(&sb, "\n")
1✔
163
        appendWithErrCheck(&sb, "var (")
1✔
164
        appendWithErrCheck(&sb, "\n")
1✔
165

1✔
166
        // Write the disk map
1✔
167
        appendWithErrCheck(&sb, diskMapStart)
1✔
168
        for account, sizes := range diskSkuInfoMap {
2✔
169
                appendWithErrCheck(&sb, "\n")
1✔
170
                appendWithErrCheck(&sb, fmt.Sprintf(accStart, account))
1✔
171

1✔
172
                for size, sku := range sizes {
2✔
173
                        //diskSku := `"%s": DiskSkuInfo{storageAccountType: "%s", storageTier: "%s", diskSize: "%s",
1✔
174
                        //maxAllowedShares: %s, maxBurstIops: %s, maxIops: %s, maxBwMbps: %s, maxBurstBwMbps: %s, maxSizeGiB: %s},`
1✔
175
                        appendWithErrCheck(&sb, "\n")
1✔
176
                        appendWithErrCheck(&sb, fmt.Sprintf(diskSku, size, sku.StorageAccountType, sku.StorageTier, sku.DiskSize, strconv.Itoa(sku.MaxAllowedShares),
1✔
177
                                strconv.Itoa(sku.MaxBurstIops), strconv.Itoa(sku.MaxIops), strconv.Itoa(sku.MaxBwMbps), strconv.Itoa(sku.MaxBurstBwMbps), strconv.Itoa(sku.MaxSizeGiB)))
1✔
178
                }
1✔
179
                appendWithErrCheck(&sb, "\n")
1✔
180
                appendWithErrCheck(&sb, accEnd)
1✔
181
        }
182

183
        appendWithErrCheck(&sb, "\n")
1✔
184
        appendWithErrCheck(&sb, diskMapEnd)
1✔
185
        appendWithErrCheck(&sb, "\n")
1✔
186
        appendWithErrCheck(&sb, "\n")
1✔
187

1✔
188
        // Write the VM Sku map
1✔
189
        appendWithErrCheck(&sb, nodeMapStart)
1✔
190

1✔
191
        //nodeInfo := `        "%s": NodeInfo{skuName: "%s", maxDataDiskCount: %s, vcpus: %s, maxBurstIops: %s, maxIops: %s, maxBwMbps: %s, maxBurstBwMbps: %s},`
1✔
192
        for vm, sku := range vmSkuInfoMap {
2✔
193
                appendWithErrCheck(&sb, "\n")
1✔
194
                appendWithErrCheck(&sb, fmt.Sprintf(nodeInfo, vm, sku.SkuName, strconv.Itoa(sku.MaxDataDiskCount), strconv.Itoa(sku.VCpus),
1✔
195
                        strconv.Itoa(sku.MaxBurstIops), strconv.Itoa(sku.MaxIops), formatInt(sku.MaxBwMbps), formatInt(sku.MaxBurstBwMbps)))
1✔
196
        }
1✔
197
        appendWithErrCheck(&sb, "\n")
1✔
198
        appendWithErrCheck(&sb, nodeMapEnd)
1✔
199
        appendWithErrCheck(&sb, "\n")
1✔
200
        appendWithErrCheck(&sb, ")")
1✔
201
        appendWithErrCheck(&sb, "\n")
1✔
202

1✔
203
        err = os.WriteFile(skusFilePath, []byte(sb.String()), 0644)
1✔
204
        if err != nil {
2✔
205
                klog.Errorf("Could write file. Error: %v, FilePath: %s", err, skusFilePath)
1✔
206
        }
1✔
207
        klog.Info("Wrote to file ", skusFilePath)
1✔
208
}
209

210
func formatInt(value int) string {
2✔
211
        if value <= 0 {
2✔
212
                return "0"
×
213
        }
×
214

215
        return strconv.Itoa(value)
2✔
216
}
217
func getAllSkus(filePath *string) (err error) {
1✔
218
        if os.Getenv("TEST_SCENARIO") == "true" {
2✔
219
                if _, err := os.Stat("skus-sample.json"); err == nil {
2✔
220
                        *filePath = "skus-sample.json"
1✔
221
                        return nil
1✔
222
                }
1✔
223
        }
NEW
224
        klog.V(2).Infof("Getting skus and writing to %s", *filePath)
×
UNCOV
225
        cmd := exec.Command("az", "vm", "list-skus")
×
NEW
226
        outfile, err := os.Create(*filePath)
×
UNCOV
227
        var errorBuf bytes.Buffer
×
UNCOV
228
        if err != nil {
×
NEW
229
                klog.Errorf("Could not create file. Error: %v File: %s", err, *filePath)
×
230
                return err
×
231
        }
×
UNCOV
232
        defer outfile.Close()
×
UNCOV
233

×
UNCOV
234
        cmd.Stdout = outfile
×
UNCOV
235
        cmd.Stderr = &errorBuf
×
UNCOV
236

×
UNCOV
237
        err = cmd.Start()
×
UNCOV
238
        if err != nil {
×
239
                return err
×
240
        }
×
UNCOV
241
        err = cmd.Wait()
×
UNCOV
242
        if err != nil {
×
UNCOV
243
                klog.Errorf("Could not get skus. ExitCode: %v Error: %s", err, errorBuf.String())
×
UNCOV
244
        }
×
UNCOV
245
        return err
×
246
}
247

248
// populateNodeCapabilities populates node capabilities from SkuInfo
249
func populateNodeCapabilities(sku *armcompute.ResourceSKU, nodeInfo *optimization.NodeInfo) (err error) {
1✔
250
        if sku.Capabilities != nil {
2✔
251
                for _, capability := range sku.Capabilities {
26✔
252
                        err = nil
25✔
253
                        if capability.Name != nil {
50✔
254
                                switch strings.ToLower(*capability.Name) {
25✔
255
                                case UncachedDiskIOPSCapability:
1✔
256
                                        nodeInfo.MaxIops, err = strconv.Atoi(*capability.Value)
1✔
257
                                case UncachedDiskBytesPerSecondCapability:
1✔
258
                                        bw, err := strconv.Atoi(*capability.Value)
1✔
259
                                        nodeInfo.MaxBwMbps = bw / (1024 * 1024)
1✔
260
                                        if err != nil {
1✔
261
                                                return fmt.Errorf("PopulateNodeCapabilities: Failed to parse node capability %s. Error: %v", *capability.Name, err)
×
262
                                        }
×
263
                                case MaxDataDiskCountCapability:
1✔
264
                                        nodeInfo.MaxDataDiskCount, err = strconv.Atoi(*capability.Value)
1✔
265
                                case VCPUsCapability:
1✔
266
                                        nodeInfo.VCpus, err = strconv.Atoi(*capability.Value)
1✔
267
                                default:
21✔
268
                                        continue
21✔
269
                                }
270
                        }
271

272
                        if err != nil {
4✔
273
                                return fmt.Errorf("PopulateNodeCapabilities: Failed to parse node capability %s. Error: %v", *capability.Name, err)
×
274
                        }
×
275
                }
276
        }
277

278
        // If node doesn't support burst capabilities.
279
        // Set the burst limits as regular limits
280
        if nodeInfo.MaxBurstIops < nodeInfo.MaxIops {
2✔
281
                nodeInfo.MaxBurstIops = nodeInfo.MaxIops
1✔
282
        }
1✔
283

284
        if nodeInfo.MaxBurstBwMbps < nodeInfo.MaxBwMbps {
2✔
285
                nodeInfo.MaxBurstBwMbps = nodeInfo.MaxBwMbps
1✔
286
        }
1✔
287

288
        return nil
1✔
289
}
290

291
// getDiskCapabilities gets disk capabilities from SkuInfo
292
func getDiskCapabilities(sku *armcompute.ResourceSKU) (diskSku optimization.DiskSkuInfo, err error) {
1✔
293
        diskSku = optimization.DiskSkuInfo{}
1✔
294
        diskSku.StorageAccountType = *sku.Name
1✔
295
        diskSku.StorageTier = *sku.Tier
1✔
296
        diskSku.DiskSize = *sku.Size
1✔
297

1✔
298
        if sku.Capabilities != nil {
2✔
299
                for _, capability := range sku.Capabilities {
20✔
300
                        err = nil
19✔
301
                        if capability.Name != nil {
38✔
302
                                switch strings.ToLower(*capability.Name) {
19✔
303
                                case MaxValueOfMaxSharesCapability:
1✔
304
                                        diskSku.MaxAllowedShares, err = strconv.Atoi(*capability.Value)
1✔
305
                                case MaxBurstIopsCapability:
×
306
                                        diskSku.MaxBurstIops, err = strconv.Atoi(*capability.Value)
×
307
                                case MaxIOpsCapability:
×
308
                                        diskSku.MaxIops, err = strconv.Atoi(*capability.Value)
×
309
                                case MaxBandwidthMBpsCapability:
×
310
                                        diskSku.MaxBwMbps, err = strconv.Atoi(*capability.Value)
×
311
                                case MaxBurstBandwidthMBpsCapability:
×
312
                                        diskSku.MaxBurstBwMbps, err = strconv.Atoi(*capability.Value)
×
313
                                case MaxSizeGiBCapability:
1✔
314
                                        diskSku.MaxSizeGiB, err = strconv.Atoi(*capability.Value)
1✔
315
                                default:
17✔
316
                                        continue
17✔
317
                                }
318
                        }
319

320
                        if err != nil {
2✔
321
                                return diskSku, fmt.Errorf("GetDiskCapabilities: Failed to parse disk capability %s. Error: %v", *capability.Name, err)
×
322
                        }
×
323
                }
324
        }
325

326
        // If disk doesn't support burst capabilities.
327
        // Set the burst limits as regular limits
328
        if diskSku.MaxBurstIops < diskSku.MaxIops {
1✔
329
                diskSku.MaxBurstIops = diskSku.MaxIops
×
330
        }
×
331

332
        if diskSku.MaxBurstBwMbps < diskSku.MaxBwMbps {
1✔
333
                diskSku.MaxBurstBwMbps = diskSku.MaxBwMbps
×
334
        }
×
335

336
        return diskSku, nil
1✔
337
}
338

339
func appendWithErrCheck(sb *strings.Builder, strToAppend string) {
24✔
340
        if _, err := sb.WriteString(strToAppend); err != nil {
24✔
341
                panic(err)
×
342
        }
343
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc