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

kubernetes-sigs / azuredisk-csi-driver / 12595635323

03 Jan 2025 09:30AM UTC coverage: 64.216% (-0.4%) from 64.6%
12595635323

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

10 of 13 new or added lines in 1 file covered. (76.92%)

28 existing lines in 1 file now uncovered.

3887 of 6053 relevant lines covered (64.22%)

5.57 hits per line

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

22.58
/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 {
2✔
104
                klog.Errorf("Could not read file. Error: %v, FilePath: %s", err, skusFullfilePath)
1✔
105
                return
1✔
106
        }
1✔
UNCOV
107
        defer diskSkusFullJSON.Close()
×
UNCOV
108

×
UNCOV
109
        byteValue, _ := io.ReadAll(diskSkusFullJSON)
×
UNCOV
110

×
UNCOV
111
        err = json.Unmarshal([]byte(byteValue), &resources)
×
UNCOV
112
        if err != nil {
×
NEW
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{}
×
118
        vmSkuInfoMap := map[string]optimization.NodeInfo{}
×
119

×
120
        for _, sku := range resources {
×
121
                resType := strings.ToLower(*sku.ResourceType)
×
122
                skuKey := ""
×
123
                if resType == "disks" {
×
124
                        skuKey = fmt.Sprintf("%s-%s-%s", *sku.Name, *sku.Tier, *sku.Size)
×
125
                } else if resType == "virtualmachines" {
×
126
                        skuKey = *sku.Name
×
127
                } else {
×
128
                        continue
×
129
                }
130
                // If we already added the sku, skip
131
                skuKeyLower := strings.ToLower(skuKey)
×
132
                if _, ok := skuMap[skuKeyLower]; ok {
×
133
                        continue
×
134
                }
135
                skuMap[skuKeyLower] = true
×
136
                if resType == "disks" {
×
137
                        account := strings.ToLower(*sku.Name)
×
138
                        diskSize := strings.ToLower(*sku.Size)
×
139
                        if _, ok := diskSkuInfoMap[account]; !ok {
×
140
                                diskSkuInfoMap[account] = map[string]optimization.DiskSkuInfo{}
×
141
                        }
×
142
                        diskSkuInfoMap[account][diskSize], err = getDiskCapabilities(sku)
×
143
                        if err != nil {
×
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" {
×
148

×
149
                        nodeInfo := optimization.NodeInfo{}
×
150
                        nodeInfo.SkuName = *sku.Name
×
151
                        err = populateNodeCapabilities(sku, &nodeInfo)
×
152
                        if err != nil {
×
153
                                klog.Errorf("populateSkuMap: Failed to populate node capabilities. Error: %v", err)
×
154
                                exit(1)
×
155
                        }
×
156
                        vmSkuInfoMap[strings.ToLower(*sku.Name)] = nodeInfo
×
157
                }
158
        }
159

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

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

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

184
        appendWithErrCheck(&sb, "\n")
×
185
        appendWithErrCheck(&sb, diskMapEnd)
×
186
        appendWithErrCheck(&sb, "\n")
×
187
        appendWithErrCheck(&sb, "\n")
×
188

×
189
        // Write the VM Sku map
×
190
        appendWithErrCheck(&sb, nodeMapStart)
×
191

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

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

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

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

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

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

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

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

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

285
        if nodeInfo.MaxBurstBwMbps < nodeInfo.MaxBwMbps {
×
286
                nodeInfo.MaxBurstBwMbps = nodeInfo.MaxBwMbps
×
287
        }
×
288

289
        return nil
×
290
}
291

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

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

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

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

333
        if diskSku.MaxBurstBwMbps < diskSku.MaxBwMbps {
×
334
                diskSku.MaxBurstBwMbps = diskSku.MaxBwMbps
×
335
        }
×
336

337
        return diskSku, nil
×
338
}
339

340
func appendWithErrCheck(sb *strings.Builder, strToAppend string) {
×
341
        if _, err := sb.WriteString(strToAppend); err != nil {
×
342
                panic(err)
×
343
        }
344
}
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