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

kubernetes-sigs / blob-csi-driver / 7531622963

15 Jan 2024 04:26PM UTC coverage: 79.562%. Remained the same
7531622963

Pull #1217

github

web-flow
chore(deps): bump github.com/onsi/ginkgo/v2 from 2.13.2 to 2.14.0

Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.13.2 to 2.14.0.
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.13.2...v2.14.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #1217: chore(deps): bump github.com/onsi/ginkgo/v2 from 2.13.2 to 2.14.0

2106 of 2647 relevant lines covered (79.56%)

7.31 hits per line

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

84.74
/pkg/blob/blob.go
1
/*
2
Copyright 2019 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 blob
18

19
import (
20
        "context"
21
        "errors"
22
        "flag"
23
        "fmt"
24
        "os"
25
        "strconv"
26
        "strings"
27
        "sync"
28
        "time"
29

30
        "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage"
31
        azstorage "github.com/Azure/azure-sdk-for-go/storage"
32
        az "github.com/Azure/go-autorest/autorest/azure"
33
        "github.com/container-storage-interface/spec/lib/go/csi"
34
        "github.com/pborman/uuid"
35
        "google.golang.org/grpc"
36
        v1 "k8s.io/api/core/v1"
37
        apierror "k8s.io/apimachinery/pkg/api/errors"
38
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
39
        "k8s.io/client-go/kubernetes"
40
        "k8s.io/klog/v2"
41
        k8sutil "k8s.io/kubernetes/pkg/volume/util"
42
        mount "k8s.io/mount-utils"
43
        utilexec "k8s.io/utils/exec"
44

45
        csicommon "sigs.k8s.io/blob-csi-driver/pkg/csi-common"
46
        "sigs.k8s.io/blob-csi-driver/pkg/util"
47
        azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
48
        "sigs.k8s.io/cloud-provider-azure/pkg/provider"
49
        azure "sigs.k8s.io/cloud-provider-azure/pkg/provider"
50
)
51

52
const (
53
        // DefaultDriverName holds the name of the csi-driver
54
        DefaultDriverName              = "blob.csi.azure.com"
55
        blobCSIDriverName              = "blob_csi_driver"
56
        separator                      = "#"
57
        volumeIDTemplate               = "%s#%s#%s#%s#%s#%s"
58
        secretNameTemplate             = "azure-storage-account-%s-secret"
59
        serverNameField                = "server"
60
        storageEndpointSuffixField     = "storageendpointsuffix"
61
        tagsField                      = "tags"
62
        matchTagsField                 = "matchtags"
63
        protocolField                  = "protocol"
64
        accountNameField               = "accountname"
65
        accountKeyField                = "accountkey"
66
        storageAccountField            = "storageaccount"
67
        storageAccountTypeField        = "storageaccounttype"
68
        skuNameField                   = "skuname"
69
        subscriptionIDField            = "subscriptionid"
70
        resourceGroupField             = "resourcegroup"
71
        locationField                  = "location"
72
        secretNameField                = "secretname"
73
        secretNamespaceField           = "secretnamespace"
74
        containerNameField             = "containername"
75
        containerNamePrefixField       = "containernameprefix"
76
        storeAccountKeyField           = "storeaccountkey"
77
        getLatestAccountKeyField       = "getlatestaccountkey"
78
        isHnsEnabledField              = "ishnsenabled"
79
        softDeleteBlobsField           = "softdeleteblobs"
80
        softDeleteContainersField      = "softdeletecontainers"
81
        enableBlobVersioningField      = "enableblobversioning"
82
        getAccountKeyFromSecretField   = "getaccountkeyfromsecret"
83
        storageSPNClientIDField        = "azurestoragespnclientid"
84
        storageSPNTenantIDField        = "azurestoragespntenantid"
85
        storageAuthTypeField           = "azurestorageauthtype"
86
        storageIdentityClientIDField   = "azurestorageidentityclientid"
87
        storageIdentityObjectIDField   = "azurestorageidentityobjectid"
88
        storageIdentityResourceIDField = "azurestorageidentityresourceid"
89
        msiEndpointField               = "msiendpoint"
90
        storageAADEndpointField        = "azurestorageaadendpoint"
91
        keyVaultURLField               = "keyvaulturl"
92
        keyVaultSecretNameField        = "keyvaultsecretname"
93
        keyVaultSecretVersionField     = "keyvaultsecretversion"
94
        storageAccountNameField        = "storageaccountname"
95
        allowBlobPublicAccessField     = "allowblobpublicaccess"
96
        requireInfraEncryptionField    = "requireinfraencryption"
97
        ephemeralField                 = "csi.storage.k8s.io/ephemeral"
98
        podNamespaceField              = "csi.storage.k8s.io/pod.namespace"
99
        serviceAccountTokenField       = "csi.storage.k8s.io/serviceAccount.tokens"
100
        clientIDField                  = "clientID"
101
        tenantIDField                  = "tenantID"
102
        mountOptionsField              = "mountoptions"
103
        falseValue                     = "false"
104
        trueValue                      = "true"
105
        defaultSecretAccountName       = "azurestorageaccountname"
106
        defaultSecretAccountKey        = "azurestorageaccountkey"
107
        accountSasTokenField           = "azurestorageaccountsastoken"
108
        msiSecretField                 = "msisecret"
109
        storageSPNClientSecretField    = "azurestoragespnclientsecret"
110
        Fuse                           = "fuse"
111
        Fuse2                          = "fuse2"
112
        NFS                            = "nfs"
113
        AZNFS                          = "aznfs"
114
        vnetResourceGroupField         = "vnetresourcegroup"
115
        vnetNameField                  = "vnetname"
116
        subnetNameField                = "subnetname"
117
        accessTierField                = "accesstier"
118
        networkEndpointTypeField       = "networkendpointtype"
119
        mountPermissionsField          = "mountpermissions"
120
        fsGroupChangePolicyField       = "fsgroupchangepolicy"
121
        useDataPlaneAPIField           = "usedataplaneapi"
122

123
        // See https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names
124
        containerNameMinLength = 3
125
        containerNameMaxLength = 63
126

127
        accountNotProvisioned                   = "StorageAccountIsNotProvisioned"
128
        tooManyRequests                         = "TooManyRequests"
129
        clientThrottled                         = "client throttled"
130
        containerBeingDeletedDataplaneAPIError  = "ContainerBeingDeleted"
131
        containerBeingDeletedManagementAPIError = "container is being deleted"
132
        statusCodeNotFound                      = "StatusCode=404"
133
        httpCodeNotFound                        = "HTTPStatusCode: 404"
134

135
        // containerMaxSize is the max size of the blob container. See https://docs.microsoft.com/en-us/azure/storage/blobs/scalability-targets#scale-targets-for-blob-storage
136
        containerMaxSize = 100 * util.TiB
137

138
        subnetTemplate = "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/virtualNetworks/%s/subnets/%s"
139

140
        defaultNamespace = "default"
141

142
        pvcNameKey           = "csi.storage.k8s.io/pvc/name"
143
        pvcNamespaceKey      = "csi.storage.k8s.io/pvc/namespace"
144
        pvNameKey            = "csi.storage.k8s.io/pv/name"
145
        pvcNameMetadata      = "${pvc.metadata.name}"
146
        pvcNamespaceMetadata = "${pvc.metadata.namespace}"
147
        pvNameMetadata       = "${pv.metadata.name}"
148

149
        VolumeID = "volumeid"
150

151
        defaultStorageEndPointSuffix = "core.windows.net"
152

153
        FSGroupChangeNone = "None"
154
)
155

156
var (
157
        supportedProtocolList            = []string{Fuse, Fuse2, NFS}
158
        retriableErrors                  = []string{accountNotProvisioned, tooManyRequests, statusCodeNotFound, containerBeingDeletedDataplaneAPIError, containerBeingDeletedManagementAPIError, clientThrottled}
159
        supportedFSGroupChangePolicyList = []string{FSGroupChangeNone, string(v1.FSGroupChangeAlways), string(v1.FSGroupChangeOnRootMismatch)}
160
)
161

162
// DriverOptions defines driver parameters specified in driver deployment
163
type DriverOptions struct {
164
        NodeID                                 string
165
        DriverName                             string
166
        BlobfuseProxyEndpoint                  string
167
        EnableBlobfuseProxy                    bool
168
        BlobfuseProxyConnTimout                int
169
        EnableBlobMockMount                    bool
170
        AllowInlineVolumeKeyAccessWithIdentity bool
171
        EnableGetVolumeStats                   bool
172
        AppendTimeStampInCacheDir              bool
173
        AppendMountErrorHelpLink               bool
174
        MountPermissions                       uint64
175
        EnableAznfsMount                       bool
176
        VolStatsCacheExpireInMinutes           int
177
        SasTokenExpirationMinutes              int
178
        EnableVolumeMountGroup                 bool
179
        FSGroupChangePolicy                    string
180
}
181

182
func (option *DriverOptions) AddFlags() {
1✔
183
        flag.StringVar(&option.BlobfuseProxyEndpoint, "blobfuse-proxy-endpoint", "unix://tmp/blobfuse-proxy.sock", "blobfuse-proxy endpoint")
1✔
184
        flag.StringVar(&option.NodeID, "nodeid", "", "node id")
1✔
185
        flag.StringVar(&option.DriverName, "drivername", DefaultDriverName, "name of the driver")
1✔
186
        flag.BoolVar(&option.EnableBlobfuseProxy, "enable-blobfuse-proxy", false, "using blobfuse proxy for mounts")
1✔
187
        flag.IntVar(&option.BlobfuseProxyConnTimout, "blobfuse-proxy-connect-timeout", 5, "blobfuse proxy connection timeout(seconds)")
1✔
188
        flag.BoolVar(&option.EnableBlobMockMount, "enable-blob-mock-mount", false, "enable mock mount(only for testing)")
1✔
189
        flag.BoolVar(&option.EnableGetVolumeStats, "enable-get-volume-stats", false, "allow GET_VOLUME_STATS on agent node")
1✔
190
        flag.BoolVar(&option.AppendTimeStampInCacheDir, "append-timestamp-cache-dir", false, "append timestamp into cache directory on agent node")
1✔
191
        flag.Uint64Var(&option.MountPermissions, "mount-permissions", 0777, "mounted folder permissions")
1✔
192
        flag.BoolVar(&option.AllowInlineVolumeKeyAccessWithIdentity, "allow-inline-volume-key-access-with-idenitity", false, "allow accessing storage account key using cluster identity for inline volume")
1✔
193
        flag.BoolVar(&option.AppendMountErrorHelpLink, "append-mount-error-help-link", true, "Whether to include a link for help with mount errors when a mount error occurs.")
1✔
194
        flag.BoolVar(&option.EnableAznfsMount, "enable-aznfs-mount", false, "replace nfs mount with aznfs mount")
1✔
195
        flag.IntVar(&option.VolStatsCacheExpireInMinutes, "vol-stats-cache-expire-in-minutes", 10, "The cache expire time in minutes for volume stats cache")
1✔
196
        flag.IntVar(&option.SasTokenExpirationMinutes, "sas-token-expiration-minutes", 1440, "sas token expiration minutes during volume cloning")
1✔
197
        flag.BoolVar(&option.EnableVolumeMountGroup, "enable-volume-mount-group", true, "indicates whether enabling VOLUME_MOUNT_GROUP")
1✔
198
        flag.StringVar(&option.FSGroupChangePolicy, "fsgroup-change-policy", "", "indicates how the volume's ownership will be changed by the driver, OnRootMismatch is the default value")
1✔
199
}
1✔
200

201
// Driver implements all interfaces of CSI drivers
202
type Driver struct {
203
        csicommon.CSIDriver
204

205
        cloud                 *azure.Cloud
206
        KubeClient            kubernetes.Interface
207
        blobfuseProxyEndpoint string
208
        // enableBlobMockMount is only for testing, DO NOT set as true in non-testing scenario
209
        enableBlobMockMount                    bool
210
        enableBlobfuseProxy                    bool
211
        enableGetVolumeStats                   bool
212
        allowInlineVolumeKeyAccessWithIdentity bool
213
        appendTimeStampInCacheDir              bool
214
        appendMountErrorHelpLink               bool
215
        blobfuseProxyConnTimout                int
216
        mountPermissions                       uint64
217
        enableAznfsMount                       bool
218
        enableVolumeMountGroup                 bool
219
        fsGroupChangePolicy                    string
220
        mounter                                *mount.SafeFormatAndMount
221
        volLockMap                             *util.LockMap
222
        // A map storing all volumes with ongoing operations so that additional operations
223
        // for that same volume (as defined by VolumeID) return an Aborted error
224
        volumeLocks *volumeLocks
225
        // only for nfs feature
226
        subnetLockMap *util.LockMap
227
        // a map storing all volumes created by this driver <volumeName, accountName>
228
        volMap sync.Map
229
        // a timed cache storing all volumeIDs and storage accounts that are using data plane API
230
        dataPlaneAPIVolCache azcache.Resource
231
        // a timed cache storing account search history (solve account list throttling issue)
232
        accountSearchCache azcache.Resource
233
        // a timed cache storing volume stats <volumeID, volumeStats>
234
        volStatsCache azcache.Resource
235
        // a timed cache storing account which should use sastoken for azcopy based volume cloning
236
        azcopySasTokenCache azcache.Resource
237
        // sas expiry time for azcopy in volume clone
238
        sasTokenExpirationMinutes int
239
        // azcopy for provide exec mock for ut
240
        azcopy *util.Azcopy
241
}
242

243
// NewDriver Creates a NewCSIDriver object. Assumes vendor version is equal to driver version &
244
// does not support optional driver plugin info manifest field. Refer to CSI spec for more details.
245
func NewDriver(options *DriverOptions, kubeClient kubernetes.Interface, cloud *provider.Cloud) *Driver {
124✔
246
        d := Driver{
124✔
247
                volLockMap:                             util.NewLockMap(),
124✔
248
                subnetLockMap:                          util.NewLockMap(),
124✔
249
                volumeLocks:                            newVolumeLocks(),
124✔
250
                blobfuseProxyEndpoint:                  options.BlobfuseProxyEndpoint,
124✔
251
                enableBlobfuseProxy:                    options.EnableBlobfuseProxy,
124✔
252
                allowInlineVolumeKeyAccessWithIdentity: options.AllowInlineVolumeKeyAccessWithIdentity,
124✔
253
                blobfuseProxyConnTimout:                options.BlobfuseProxyConnTimout,
124✔
254
                enableBlobMockMount:                    options.EnableBlobMockMount,
124✔
255
                enableGetVolumeStats:                   options.EnableGetVolumeStats,
124✔
256
                enableVolumeMountGroup:                 options.EnableVolumeMountGroup,
124✔
257
                appendMountErrorHelpLink:               options.AppendMountErrorHelpLink,
124✔
258
                mountPermissions:                       options.MountPermissions,
124✔
259
                enableAznfsMount:                       options.EnableAznfsMount,
124✔
260
                sasTokenExpirationMinutes:              options.SasTokenExpirationMinutes,
124✔
261
                fsGroupChangePolicy:                    options.FSGroupChangePolicy,
124✔
262
                azcopy:                                 &util.Azcopy{},
124✔
263
                KubeClient:                             kubeClient,
124✔
264
                cloud:                                  cloud,
124✔
265
        }
124✔
266
        d.Name = options.DriverName
124✔
267
        d.Version = driverVersion
124✔
268
        d.NodeID = options.NodeID
124✔
269

124✔
270
        var err error
124✔
271
        getter := func(key string) (interface{}, error) { return nil, nil }
131✔
272
        if d.accountSearchCache, err = azcache.NewTimedCache(time.Minute, getter, false); err != nil {
124✔
273
                klog.Fatalf("%v", err)
×
274
        }
×
275
        if d.dataPlaneAPIVolCache, err = azcache.NewTimedCache(10*time.Minute, getter, false); err != nil {
124✔
276
                klog.Fatalf("%v", err)
×
277
        }
×
278
        if d.azcopySasTokenCache, err = azcache.NewTimedCache(15*time.Minute, getter, false); err != nil {
124✔
279
                klog.Fatalf("%v", err)
×
280
        }
×
281

282
        if options.VolStatsCacheExpireInMinutes <= 0 {
248✔
283
                options.VolStatsCacheExpireInMinutes = 10 // default expire in 10 minutes
124✔
284
        }
124✔
285
        if d.volStatsCache, err = azcache.NewTimedCache(time.Duration(options.VolStatsCacheExpireInMinutes)*time.Minute, getter, false); err != nil {
124✔
286
                klog.Fatalf("%v", err)
×
287
        }
×
288
        d.mounter = &mount.SafeFormatAndMount{
124✔
289
                Interface: mount.New(""),
124✔
290
                Exec:      utilexec.New(),
124✔
291
        }
124✔
292

124✔
293
        // Initialize default library driver
124✔
294
        d.AddControllerServiceCapabilities(
124✔
295
                []csi.ControllerServiceCapability_RPC_Type{
124✔
296
                        csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME,
124✔
297
                        //csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT,
124✔
298
                        //csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS,
124✔
299
                        csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
124✔
300
                        csi.ControllerServiceCapability_RPC_SINGLE_NODE_MULTI_WRITER,
124✔
301
                        csi.ControllerServiceCapability_RPC_CLONE_VOLUME,
124✔
302
                })
124✔
303
        d.AddVolumeCapabilityAccessModes([]csi.VolumeCapability_AccessMode_Mode{
124✔
304
                csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
124✔
305
                csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY,
124✔
306
                csi.VolumeCapability_AccessMode_SINGLE_NODE_SINGLE_WRITER,
124✔
307
                csi.VolumeCapability_AccessMode_SINGLE_NODE_MULTI_WRITER,
124✔
308
                csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY,
124✔
309
                csi.VolumeCapability_AccessMode_MULTI_NODE_SINGLE_WRITER,
124✔
310
                csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
124✔
311
        })
124✔
312

124✔
313
        nodeCap := []csi.NodeServiceCapability_RPC_Type{
124✔
314
                csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME,
124✔
315
                csi.NodeServiceCapability_RPC_SINGLE_NODE_MULTI_WRITER,
124✔
316
        }
124✔
317
        if d.enableGetVolumeStats {
124✔
318
                nodeCap = append(nodeCap, csi.NodeServiceCapability_RPC_GET_VOLUME_STATS)
×
319
        }
×
320
        if d.enableVolumeMountGroup {
124✔
321
                nodeCap = append(nodeCap, csi.NodeServiceCapability_RPC_VOLUME_MOUNT_GROUP)
×
322
        }
×
323
        d.AddNodeServiceCapabilities(nodeCap)
124✔
324

124✔
325
        return &d
124✔
326
}
327

328
// Run driver initialization
329
func (d *Driver) Run(ctx context.Context, endpoint string) error {
2✔
330
        versionMeta, err := GetVersionYAML(d.Name)
2✔
331
        if err != nil {
2✔
332
                klog.Fatalf("%v", err)
×
333
        }
×
334
        klog.Infof("\nDRIVER INFORMATION:\n-------------------\n%s\n\nStreaming logs below:", versionMeta)
2✔
335
        grpcInterceptor := grpc.UnaryInterceptor(csicommon.LogGRPC)
2✔
336
        opts := []grpc.ServerOption{
2✔
337
                grpcInterceptor,
2✔
338
        }
2✔
339
        s := grpc.NewServer(opts...)
2✔
340
        csi.RegisterIdentityServer(s, d)
2✔
341
        csi.RegisterControllerServer(s, d)
2✔
342
        csi.RegisterNodeServer(s, d)
2✔
343

2✔
344
        go func() {
4✔
345
                //graceful shutdown
2✔
346
                <-ctx.Done()
2✔
347
                s.GracefulStop()
2✔
348
        }()
2✔
349
        // Driver d act as IdentityServer, ControllerServer and NodeServer
350
        listener, err := csicommon.Listen(ctx, endpoint)
2✔
351
        if err != nil {
2✔
352
                klog.Fatalf("failed to listen to endpoint, error: %v", err)
×
353
        }
×
354
        err = s.Serve(listener)
2✔
355
        if errors.Is(err, grpc.ErrServerStopped) {
2✔
356
                klog.Infof("gRPC server stopped serving")
×
357
                return nil
×
358
        }
×
359
        return err
2✔
360
}
361

362
// GetContainerInfo get container info according to volume id
363
// the format of VolumeId is: rg#accountName#containerName#uuid#secretNamespace#subsID
364
//
365
// e.g.
366
// input: "rg#f5713de20cde511e8ba4900#containerName#uuid#"
367
// output: rg, f5713de20cde511e8ba4900, containerName, "" , ""
368
// input: "rg#f5713de20cde511e8ba4900#containerName#uuid#namespace#"
369
// output: rg, f5713de20cde511e8ba4900, containerName, namespace, ""
370
// input: "rg#f5713de20cde511e8ba4900#containerName#uuid#namespace#subsID"
371
// output: rg, f5713de20cde511e8ba4900, containerName, namespace, subsID
372
func GetContainerInfo(id string) (string, string, string, string, string, error) {
39✔
373
        segments := strings.Split(id, separator)
39✔
374
        if len(segments) < 3 {
48✔
375
                return "", "", "", "", "", fmt.Errorf("error parsing volume id: %q, should at least contain two #", id)
9✔
376
        }
9✔
377
        var secretNamespace, subsID string
30✔
378
        if len(segments) > 4 {
36✔
379
                secretNamespace = segments[4]
6✔
380
        }
6✔
381
        if len(segments) > 5 {
33✔
382
                subsID = segments[5]
3✔
383
        }
3✔
384
        return segments[0], segments[1], segments[2], secretNamespace, subsID, nil
30✔
385
}
386

387
// A container name must be a valid DNS name, conforming to the following naming rules:
388
//  1. Container names must start with a letter or number, and can contain only letters, numbers, and the dash (-) character.
389
//  2. Every dash (-) character must be immediately preceded and followed by a letter or number; consecutive dashes are not permitted in container names.
390
//  3. All letters in a container name must be lowercase.
391
//  4. Container names must be from 3 through 63 characters long.
392
//
393
// See https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names
394
func getValidContainerName(volumeName, protocol string) string {
5✔
395
        containerName := strings.ToLower(volumeName)
5✔
396
        if len(containerName) > containerNameMaxLength {
6✔
397
                containerName = containerName[0:containerNameMaxLength]
1✔
398
        }
1✔
399
        if !checkContainerNameBeginAndEnd(containerName) || len(containerName) < containerNameMinLength {
5✔
400
                // now we set as 63 for maximum container name length
×
401
                // todo: get cluster name
×
402
                containerName = k8sutil.GenerateVolumeName(fmt.Sprintf("pvc-%s", protocol), uuid.NewUUID().String(), 63)
×
403
                klog.Warningf("requested volume name (%s) is invalid, regenerated as (%q)", volumeName, containerName)
×
404
        }
×
405
        return strings.Replace(containerName, "--", "-", -1)
5✔
406
}
407

408
func checkContainerNameBeginAndEnd(containerName string) bool {
11✔
409
        length := len(containerName)
11✔
410
        if (('a' <= containerName[0] && containerName[0] <= 'z') ||
11✔
411
                ('0' <= containerName[0] && containerName[0] <= '9')) &&
11✔
412
                (('a' <= containerName[length-1] && containerName[length-1] <= 'z') ||
11✔
413
                        ('0' <= containerName[length-1] && containerName[length-1] <= '9')) {
20✔
414
                return true
9✔
415
        }
9✔
416

417
        return false
2✔
418
}
419

420
// isSASToken checks if the key contains the patterns.
421
// SAS token format could refer to https://docs.microsoft.com/en-us/rest/api/eventhub/generate-sas-token
422
func isSASToken(key string) bool {
3✔
423
        return strings.HasPrefix(key, "?")
3✔
424
}
3✔
425

426
// GetAuthEnv return <accountName, containerName, authEnv, error>
427
func (d *Driver) GetAuthEnv(ctx context.Context, volumeID, protocol string, attrib, secrets map[string]string) (string, string, string, string, []string, error) {
10✔
428
        rgName, accountName, containerName, secretNamespace, _, err := GetContainerInfo(volumeID)
10✔
429
        if err != nil {
12✔
430
                // ignore volumeID parsing error
2✔
431
                klog.V(2).Infof("parsing volumeID(%s) return with error: %v", volumeID, err)
2✔
432
                err = nil
2✔
433
        }
2✔
434

435
        var (
10✔
436
                subsID                  string
10✔
437
                accountKey              string
10✔
438
                accountSasToken         string
10✔
439
                msiSecret               string
10✔
440
                storageSPNClientSecret  string
10✔
441
                storageSPNClientID      string
10✔
442
                storageSPNTenantID      string
10✔
443
                secretName              string
10✔
444
                pvcNamespace            string
10✔
445
                keyVaultURL             string
10✔
446
                keyVaultSecretName      string
10✔
447
                keyVaultSecretVersion   string
10✔
448
                azureStorageAuthType    string
10✔
449
                authEnv                 []string
10✔
450
                getAccountKeyFromSecret bool
10✔
451
                getLatestAccountKey     bool
10✔
452
                clientID                string
10✔
453
                tenantID                string
10✔
454
                serviceAccountToken     string
10✔
455
        )
10✔
456

10✔
457
        for k, v := range attrib {
36✔
458
                switch strings.ToLower(k) {
26✔
459
                case subscriptionIDField:
1✔
460
                        subsID = v
1✔
461
                case resourceGroupField:
×
462
                        rgName = v
×
463
                case containerNameField:
3✔
464
                        containerName = v
3✔
465
                case keyVaultURLField:
1✔
466
                        keyVaultURL = v
1✔
467
                case keyVaultSecretNameField:
1✔
468
                        keyVaultSecretName = v
1✔
469
                case keyVaultSecretVersionField:
1✔
470
                        keyVaultSecretVersion = v
1✔
471
                case storageAccountField:
2✔
472
                        accountName = v
2✔
473
                case storageAccountNameField: // for compatibility
1✔
474
                        accountName = v
1✔
475
                case secretNameField:
1✔
476
                        secretName = v
1✔
477
                case secretNamespaceField:
1✔
478
                        secretNamespace = v
1✔
479
                case pvcNamespaceKey:
1✔
480
                        pvcNamespace = v
1✔
481
                case getAccountKeyFromSecretField:
1✔
482
                        getAccountKeyFromSecret = strings.EqualFold(v, trueValue)
1✔
483
                case storageAuthTypeField:
×
484
                        azureStorageAuthType = v
×
485
                        authEnv = append(authEnv, "AZURE_STORAGE_AUTH_TYPE="+v)
×
486
                case storageIdentityClientIDField:
1✔
487
                        authEnv = append(authEnv, "AZURE_STORAGE_IDENTITY_CLIENT_ID="+v)
1✔
488
                case storageIdentityObjectIDField:
1✔
489
                        authEnv = append(authEnv, "AZURE_STORAGE_IDENTITY_OBJECT_ID="+v)
1✔
490
                case storageIdentityResourceIDField:
1✔
491
                        authEnv = append(authEnv, "AZURE_STORAGE_IDENTITY_RESOURCE_ID="+v)
1✔
492
                case msiEndpointField:
1✔
493
                        authEnv = append(authEnv, "MSI_ENDPOINT="+v)
1✔
494
                case storageSPNClientIDField:
1✔
495
                        storageSPNClientID = v
1✔
496
                case storageSPNTenantIDField:
1✔
497
                        storageSPNTenantID = v
1✔
498
                case storageAADEndpointField:
1✔
499
                        authEnv = append(authEnv, "AZURE_STORAGE_AAD_ENDPOINT="+v)
1✔
500
                case getLatestAccountKeyField:
1✔
501
                        if getLatestAccountKey, err = strconv.ParseBool(v); err != nil {
2✔
502
                                return rgName, accountName, accountKey, containerName, authEnv, fmt.Errorf("invalid %s: %s in volume context", getLatestAccountKeyField, v)
1✔
503
                        }
1✔
504
                case strings.ToLower(clientIDField):
×
505
                        clientID = v
×
506
                case strings.ToLower(tenantIDField):
×
507
                        tenantID = v
×
508
                case strings.ToLower(serviceAccountTokenField):
×
509
                        serviceAccountToken = v
×
510
                }
511
        }
512
        klog.V(2).Infof("volumeID(%s) authEnv: %s", volumeID, authEnv)
9✔
513

9✔
514
        if protocol == NFS {
11✔
515
                // nfs protocol does not need account key, return directly
2✔
516
                return rgName, accountName, accountKey, containerName, authEnv, err
2✔
517
        }
2✔
518

519
        if secretNamespace == "" {
13✔
520
                if pvcNamespace == "" {
12✔
521
                        secretNamespace = defaultNamespace
6✔
522
                } else {
6✔
523
                        secretNamespace = pvcNamespace
×
524
                }
×
525
        }
526

527
        if rgName == "" {
8✔
528
                rgName = d.cloud.ResourceGroup
1✔
529
        }
1✔
530

531
        if tenantID == "" {
14✔
532
                tenantID = d.cloud.TenantID
7✔
533
        }
7✔
534

535
        // if client id is specified, we only use service account token to get account key
536
        if clientID != "" {
7✔
537
                klog.V(2).Infof("clientID(%s) is specified, use service account token to get account key", clientID)
×
538
                if subsID == "" {
×
539
                        subsID = d.cloud.SubscriptionID
×
540
                }
×
541
                accountKey, err := d.cloud.GetStorageAccesskeyFromServiceAccountToken(ctx, subsID, accountName, rgName, clientID, tenantID, serviceAccountToken)
×
542
                authEnv = append(authEnv, "AZURE_STORAGE_ACCESS_KEY="+accountKey)
×
543
                return rgName, accountName, accountKey, containerName, authEnv, err
×
544
        }
545

546
        // 1. If keyVaultURL is not nil, preferentially use the key stored in key vault.
547
        // 2. Then if secrets map is not nil, use the key stored in the secrets map.
548
        // 3. Finally if both keyVaultURL and secrets map are nil, get the key from Azure.
549
        if keyVaultURL != "" {
8✔
550
                key, err := d.getKeyVaultSecretContent(ctx, keyVaultURL, keyVaultSecretName, keyVaultSecretVersion)
1✔
551
                if err != nil {
2✔
552
                        return rgName, accountName, accountKey, containerName, authEnv, err
1✔
553
                }
1✔
554
                if isSASToken(key) {
×
555
                        accountSasToken = key
×
556
                } else {
×
557
                        accountKey = key
×
558
                }
×
559
        } else {
6✔
560
                if len(secrets) == 0 {
11✔
561
                        if secretName == "" && accountName != "" {
9✔
562
                                secretName = fmt.Sprintf(secretNameTemplate, accountName)
4✔
563
                        }
4✔
564
                        if secretName != "" {
10✔
565
                                // read from k8s secret first
5✔
566
                                var name, spnClientID, spnTenantID string
5✔
567
                                name, accountKey, accountSasToken, msiSecret, storageSPNClientSecret, spnClientID, spnTenantID, err = d.GetInfoFromSecret(ctx, secretName, secretNamespace)
5✔
568
                                if name != "" {
5✔
569
                                        accountName = name
×
570
                                }
×
571
                                if spnClientID != "" {
5✔
572
                                        storageSPNClientID = spnClientID
×
573
                                }
×
574
                                if spnTenantID != "" {
5✔
575
                                        storageSPNTenantID = spnTenantID
×
576
                                }
×
577
                                if err != nil && strings.EqualFold(azureStorageAuthType, "msi") {
5✔
578
                                        klog.V(2).Infof("ignore error(%v) since secret is optional for auth type(%s)", err, azureStorageAuthType)
×
579
                                        err = nil
×
580
                                }
×
581
                                if err != nil && !getAccountKeyFromSecret && (azureStorageAuthType == "" || strings.EqualFold(azureStorageAuthType, "key")) {
10✔
582
                                        klog.V(2).Infof("get account(%s) key from secret(%s, %s) failed with error: %v, use cluster identity to get account key instead",
5✔
583
                                                accountName, secretNamespace, secretName, err)
5✔
584
                                        accountKey, err = d.cloud.GetStorageAccesskey(ctx, subsID, accountName, rgName, getLatestAccountKey)
5✔
585
                                        if err != nil {
7✔
586
                                                return rgName, accountName, accountKey, containerName, authEnv, fmt.Errorf("no key for storage account(%s) under resource group(%s), err %w", accountName, rgName, err)
2✔
587
                                        }
2✔
588
                                }
589
                        }
590
                } else {
1✔
591
                        for k, v := range secrets {
8✔
592
                                v = strings.TrimSpace(v)
7✔
593
                                switch strings.ToLower(k) {
7✔
594
                                case accountNameField:
1✔
595
                                        accountName = v
1✔
596
                                case defaultSecretAccountName: // for compatibility with built-in blobfuse plugin
1✔
597
                                        accountName = v
1✔
598
                                case accountKeyField:
1✔
599
                                        accountKey = v
1✔
600
                                case defaultSecretAccountKey: // for compatibility with built-in blobfuse plugin
1✔
601
                                        accountKey = v
1✔
602
                                case accountSasTokenField:
1✔
603
                                        accountSasToken = v
1✔
604
                                case msiSecretField:
1✔
605
                                        msiSecret = v
1✔
606
                                case storageSPNClientSecretField:
1✔
607
                                        storageSPNClientSecret = v
1✔
608
                                case storageSPNClientIDField:
×
609
                                        storageSPNClientID = v
×
610
                                case storageSPNTenantIDField:
×
611
                                        storageSPNTenantID = v
×
612
                                }
613
                        }
614
                }
615
        }
616

617
        if containerName == "" {
4✔
618
                err = fmt.Errorf("could not find containerName from attributes(%v) or volumeID(%v)", attrib, volumeID)
×
619
        }
×
620

621
        if accountKey != "" {
8✔
622
                authEnv = append(authEnv, "AZURE_STORAGE_ACCESS_KEY="+accountKey)
4✔
623
        }
4✔
624

625
        if accountSasToken != "" {
5✔
626
                klog.V(2).Infof("accountSasToken is not empty, use it to access storage account(%s), container(%s)", accountName, containerName)
1✔
627
                authEnv = append(authEnv, "AZURE_STORAGE_SAS_TOKEN="+accountSasToken)
1✔
628
        }
1✔
629

630
        if msiSecret != "" {
5✔
631
                klog.V(2).Infof("msiSecret is not empty, use it to access storage account(%s), container(%s)", accountName, containerName)
1✔
632
                authEnv = append(authEnv, "MSI_SECRET="+msiSecret)
1✔
633
        }
1✔
634

635
        if storageSPNClientSecret != "" {
5✔
636
                klog.V(2).Infof("storageSPNClientSecret is not empty, use it to access storage account(%s), container(%s)", accountName, containerName)
1✔
637
                authEnv = append(authEnv, "AZURE_STORAGE_SPN_CLIENT_SECRET="+storageSPNClientSecret)
1✔
638
        }
1✔
639

640
        if storageSPNClientID != "" {
4✔
641
                klog.V(2).Infof("storageSPNClientID(%s) is not empty, use it to access storage account(%s), container(%s)", storageSPNClientID, accountName, containerName)
×
642
                authEnv = append(authEnv, "AZURE_STORAGE_SPN_CLIENT_ID="+storageSPNClientID)
×
643
        }
×
644

645
        if storageSPNTenantID != "" {
4✔
646
                klog.V(2).Infof("storageSPNTenantID(%s) is not empty, use it to access storage account(%s), container(%s)", storageSPNTenantID, accountName, containerName)
×
647
                authEnv = append(authEnv, "AZURE_STORAGE_SPN_TENANT_ID="+storageSPNTenantID)
×
648
        }
×
649

650
        return rgName, accountName, accountKey, containerName, authEnv, err
4✔
651
}
652

653
// GetStorageAccountAndContainer get storage account and container info
654
// returns <accountName, accountKey, accountSasToken, containerName>
655
// only for e2e testing
656
func (d *Driver) GetStorageAccountAndContainer(ctx context.Context, volumeID string, attrib, secrets map[string]string) (string, string, string, string, error) {
3✔
657
        var (
3✔
658
                subsID                string
3✔
659
                accountName           string
3✔
660
                accountKey            string
3✔
661
                accountSasToken       string
3✔
662
                containerName         string
3✔
663
                keyVaultURL           string
3✔
664
                keyVaultSecretName    string
3✔
665
                keyVaultSecretVersion string
3✔
666
                getLatestAccountKey   bool
3✔
667
                err                   error
3✔
668
        )
3✔
669

3✔
670
        for k, v := range attrib {
8✔
671
                switch strings.ToLower(k) {
5✔
672
                case subscriptionIDField:
×
673
                        subsID = v
×
674
                case containerNameField:
1✔
675
                        containerName = v
1✔
676
                case keyVaultURLField:
×
677
                        keyVaultURL = v
×
678
                case keyVaultSecretNameField:
1✔
679
                        keyVaultSecretName = v
1✔
680
                case keyVaultSecretVersionField:
1✔
681
                        keyVaultSecretVersion = v
1✔
682
                case storageAccountField:
×
683
                        accountName = v
×
684
                case storageAccountNameField: // for compatibility
1✔
685
                        accountName = v
1✔
686
                case getLatestAccountKeyField:
1✔
687
                        if getLatestAccountKey, err = strconv.ParseBool(v); err != nil {
2✔
688
                                return "", "", "", "", fmt.Errorf("invalid %s: %s in volume context", getLatestAccountKeyField, v)
1✔
689
                        }
1✔
690
                }
691
        }
692

693
        // 1. If keyVaultURL is not nil, preferentially use the key stored in key vault.
694
        // 2. Then if secrets map is not nil, use the key stored in the secrets map.
695
        // 3. Finally if both keyVaultURL and secrets map are nil, get the key from Azure.
696
        if keyVaultURL != "" {
2✔
697
                key, err := d.getKeyVaultSecretContent(ctx, keyVaultURL, keyVaultSecretName, keyVaultSecretVersion)
×
698
                if err != nil {
×
699
                        return "", "", "", "", err
×
700
                }
×
701
                if isSASToken(key) {
×
702
                        accountSasToken = key
×
703
                } else {
×
704
                        accountKey = key
×
705
                }
×
706
        } else {
2✔
707
                if len(secrets) == 0 {
4✔
708
                        var rgName string
2✔
709
                        rgName, accountName, containerName, _, _, err = GetContainerInfo(volumeID)
2✔
710
                        if err != nil {
2✔
711
                                return "", "", "", "", err
×
712
                        }
×
713

714
                        if rgName == "" {
2✔
715
                                rgName = d.cloud.ResourceGroup
×
716
                        }
×
717

718
                        accountKey, err = d.cloud.GetStorageAccesskey(ctx, subsID, accountName, rgName, getLatestAccountKey)
2✔
719
                        if err != nil {
3✔
720
                                return "", "", "", "", fmt.Errorf("no key for storage account(%s) under resource group(%s), err %w", accountName, rgName, err)
1✔
721
                        }
1✔
722
                }
723
        }
724

725
        if containerName == "" {
1✔
726
                return "", "", "", "", fmt.Errorf("could not find containerName from attributes(%v) or volumeID(%v)", attrib, volumeID)
×
727
        }
×
728

729
        return accountName, accountKey, accountSasToken, containerName, nil
1✔
730
}
731

732
func IsCorruptedDir(dir string) bool {
4✔
733
        _, pathErr := mount.PathExists(dir)
4✔
734
        return pathErr != nil && mount.IsCorruptedMnt(pathErr)
4✔
735
}
4✔
736

737
func isRetriableError(err error) bool {
5✔
738
        if err != nil {
9✔
739
                for _, v := range retriableErrors {
19✔
740
                        if strings.Contains(strings.ToLower(err.Error()), strings.ToLower(v)) {
18✔
741
                                return true
3✔
742
                        }
3✔
743
                }
744
        }
745
        return false
2✔
746
}
747

748
func isSupportedProtocol(protocol string) bool {
17✔
749
        if protocol == "" {
18✔
750
                return true
1✔
751
        }
1✔
752
        for _, v := range supportedProtocolList {
40✔
753
                if protocol == v {
38✔
754
                        return true
14✔
755
                }
14✔
756
        }
757
        return false
2✔
758
}
759

760
func isSupportedAccessTier(accessTier string) bool {
20✔
761
        if accessTier == "" {
33✔
762
                return true
13✔
763
        }
13✔
764
        for _, tier := range storage.PossibleAccessTierValues() {
25✔
765
                if accessTier == string(tier) {
21✔
766
                        return true
3✔
767
                }
3✔
768
        }
769
        return false
4✔
770
}
771

772
// container names can contain only lowercase letters, numbers, and hyphens,
773
// and must begin and end with a letter or a number
774
func isSupportedContainerNamePrefix(prefix string) bool {
19✔
775
        if prefix == "" {
30✔
776
                return true
11✔
777
        }
11✔
778
        if len(prefix) > 20 {
9✔
779
                return false
1✔
780
        }
1✔
781
        if prefix[0] == '-' {
8✔
782
                return false
1✔
783
        }
1✔
784
        for _, v := range prefix {
19✔
785
                if v != '-' && (v < '0' || v > '9') && (v < 'a' || v > 'z') {
17✔
786
                        return false
4✔
787
                }
4✔
788
        }
789
        return true
2✔
790
}
791

792
// isNFSProtocol checks if the protocol is NFS or AZNFS
793
func isNFSProtocol(protocol string) bool {
21✔
794
        protocol = strings.ToLower(protocol)
21✔
795
        return protocol == NFS || protocol == AZNFS
21✔
796
}
21✔
797

798
// get storage account from secrets map
799
func getStorageAccount(secrets map[string]string) (string, string, error) {
22✔
800
        if secrets == nil {
23✔
801
                return "", "", fmt.Errorf("unexpected: getStorageAccount secrets is nil")
1✔
802
        }
1✔
803

804
        var accountName, accountKey string
21✔
805
        for k, v := range secrets {
64✔
806
                v = strings.TrimSpace(v)
43✔
807
                switch strings.ToLower(k) {
43✔
808
                case accountNameField:
7✔
809
                        accountName = v
7✔
810
                case defaultSecretAccountName: // for compatibility with built-in azurefile plugin
13✔
811
                        accountName = v
13✔
812
                case accountKeyField:
7✔
813
                        accountKey = v
7✔
814
                case defaultSecretAccountKey: // for compatibility with built-in azurefile plugin
12✔
815
                        accountKey = v
12✔
816
                }
817
        }
818

819
        if accountName == "" {
25✔
820
                return accountName, accountKey, fmt.Errorf("could not find %s or %s field in secrets", accountNameField, defaultSecretAccountName)
4✔
821
        }
4✔
822
        if accountKey == "" {
21✔
823
                return accountName, accountKey, fmt.Errorf("could not find %s or %s field in secrets", accountKeyField, defaultSecretAccountKey)
4✔
824
        }
4✔
825

826
        accountName = strings.TrimSpace(accountName)
13✔
827
        klog.V(4).Infof("got storage account(%s) from secret", accountName)
13✔
828
        return accountName, accountKey, nil
13✔
829
}
830

831
func getContainerReference(containerName string, secrets map[string]string, env az.Environment) (*azstorage.Container, error) {
9✔
832
        accountName, accountKey, rerr := getStorageAccount(secrets)
9✔
833
        if rerr != nil {
11✔
834
                return nil, rerr
2✔
835
        }
2✔
836
        client, err := azstorage.NewBasicClientOnSovereignCloud(accountName, accountKey, env)
7✔
837
        if err != nil {
13✔
838
                return nil, err
6✔
839
        }
6✔
840
        blobClient := client.GetBlobService()
1✔
841
        container := blobClient.GetContainerReference(containerName)
1✔
842
        if container == nil {
1✔
843
                return nil, fmt.Errorf("ContainerReference of %s is nil", containerName)
×
844
        }
×
845
        return container, nil
1✔
846
}
847

848
func setAzureCredentials(ctx context.Context, kubeClient kubernetes.Interface, accountName, accountKey, secretNamespace string) (string, error) {
6✔
849
        if kubeClient == nil {
8✔
850
                klog.Warningf("could not create secret: kubeClient is nil")
2✔
851
                return "", nil
2✔
852
        }
2✔
853
        if accountName == "" || accountKey == "" {
6✔
854
                return "", fmt.Errorf("the account info is not enough, accountName(%v), accountKey(%v)", accountName, accountKey)
2✔
855
        }
2✔
856
        secretName := fmt.Sprintf(secretNameTemplate, accountName)
2✔
857
        secret := &v1.Secret{
2✔
858
                ObjectMeta: metav1.ObjectMeta{
2✔
859
                        Namespace: secretNamespace,
2✔
860
                        Name:      secretName,
2✔
861
                },
2✔
862
                Data: map[string][]byte{
2✔
863
                        defaultSecretAccountName: []byte(accountName),
2✔
864
                        defaultSecretAccountKey:  []byte(accountKey),
2✔
865
                },
2✔
866
                Type: "Opaque",
2✔
867
        }
2✔
868
        _, err := kubeClient.CoreV1().Secrets(secretNamespace).Create(ctx, secret, metav1.CreateOptions{})
2✔
869
        if apierror.IsAlreadyExists(err) {
3✔
870
                err = nil
1✔
871
        }
1✔
872
        if err != nil {
2✔
873
                return "", fmt.Errorf("couldn't create secret %w", err)
×
874
        }
×
875
        return secretName, err
2✔
876
}
877

878
// GetStorageAccesskey get Azure storage account key from
879
//  1. secrets (if not empty)
880
//  2. use k8s client identity to read from k8s secret
881
//  3. use cluster identity to get from storage account directly
882
func (d *Driver) GetStorageAccesskey(ctx context.Context, accountOptions *azure.AccountOptions, secrets map[string]string, secretName, secretNamespace string) (string, string, error) {
11✔
883
        if len(secrets) > 0 {
16✔
884
                return getStorageAccount(secrets)
5✔
885
        }
5✔
886

887
        // read from k8s secret first
888
        if secretName == "" {
10✔
889
                secretName = fmt.Sprintf(secretNameTemplate, accountOptions.Name)
4✔
890
        }
4✔
891
        _, accountKey, _, _, _, _, _, err := d.GetInfoFromSecret(ctx, secretName, secretNamespace) //nolint
6✔
892
        if err != nil {
10✔
893
                klog.V(2).Infof("could not get account(%s) key from secret(%s) namespace(%s), error: %v, use cluster identity to get account key instead", accountOptions.Name, secretName, secretNamespace, err)
4✔
894
                accountKey, err = d.cloud.GetStorageAccesskey(ctx, accountOptions.SubscriptionID, accountOptions.Name, accountOptions.ResourceGroup, accountOptions.GetLatestAccountKey)
4✔
895
        }
4✔
896
        return accountOptions.Name, accountKey, err
6✔
897
}
898

899
// GetInfoFromSecret get info from k8s secret
900
// return <accountName, accountKey, accountSasToken, msiSecret, spnClientSecret, spnClientID, spnTenantID, error>
901
func (d *Driver) GetInfoFromSecret(ctx context.Context, secretName, secretNamespace string) (string, string, string, string, string, string, string, error) {
15✔
902
        if d.cloud.KubeClient == nil {
24✔
903
                return "", "", "", "", "", "", "", fmt.Errorf("could not get account key from secret(%s): KubeClient is nil", secretName)
9✔
904
        }
9✔
905

906
        secret, err := d.cloud.KubeClient.CoreV1().Secrets(secretNamespace).Get(ctx, secretName, metav1.GetOptions{})
6✔
907
        if err != nil {
8✔
908
                return "", "", "", "", "", "", "", fmt.Errorf("could not get secret(%v): %w", secretName, err)
2✔
909
        }
2✔
910

911
        accountName := strings.TrimSpace(string(secret.Data[defaultSecretAccountName][:]))
4✔
912
        accountKey := strings.TrimSpace(string(secret.Data[defaultSecretAccountKey][:]))
4✔
913
        accountSasToken := strings.TrimSpace(string(secret.Data[accountSasTokenField][:]))
4✔
914
        msiSecret := strings.TrimSpace(string(secret.Data[msiSecretField][:]))
4✔
915
        spnClientSecret := strings.TrimSpace(string(secret.Data[storageSPNClientSecretField][:]))
4✔
916
        spnClientID := strings.TrimSpace(string(secret.Data[storageSPNClientIDField][:]))
4✔
917
        spnTenantID := strings.TrimSpace(string(secret.Data[storageSPNTenantIDField][:]))
4✔
918

4✔
919
        klog.V(4).Infof("got storage account(%s) from secret(%s) namespace(%s)", accountName, secretName, secretNamespace)
4✔
920
        return accountName, accountKey, accountSasToken, msiSecret, spnClientSecret, spnClientID, spnTenantID, nil
4✔
921
}
922

923
// getSubnetResourceID get default subnet resource ID from cloud provider config
924
func (d *Driver) getSubnetResourceID(vnetResourceGroup, vnetName, subnetName string) string {
6✔
925
        subsID := d.cloud.SubscriptionID
6✔
926
        if len(d.cloud.NetworkResourceSubscriptionID) > 0 {
10✔
927
                subsID = d.cloud.NetworkResourceSubscriptionID
4✔
928
        }
4✔
929

930
        if len(vnetResourceGroup) == 0 {
11✔
931
                vnetResourceGroup = d.cloud.ResourceGroup
5✔
932
                if len(d.cloud.VnetResourceGroup) > 0 {
8✔
933
                        vnetResourceGroup = d.cloud.VnetResourceGroup
3✔
934
                }
3✔
935
        }
936

937
        if len(vnetName) == 0 {
11✔
938
                vnetName = d.cloud.VnetName
5✔
939
        }
5✔
940

941
        if len(subnetName) == 0 {
11✔
942
                subnetName = d.cloud.SubnetName
5✔
943
        }
5✔
944
        return fmt.Sprintf(subnetTemplate, subsID, vnetResourceGroup, vnetName, subnetName)
6✔
945
}
946

947
func (d *Driver) useDataPlaneAPI(volumeID, accountName string) bool {
4✔
948
        cache, err := d.dataPlaneAPIVolCache.Get(volumeID, azcache.CacheReadTypeDefault)
4✔
949
        if err != nil {
4✔
950
                klog.Errorf("get(%s) from dataPlaneAPIVolCache failed with error: %v", volumeID, err)
×
951
        }
×
952
        if cache != nil {
7✔
953
                return true
3✔
954
        }
3✔
955
        cache, err = d.dataPlaneAPIVolCache.Get(accountName, azcache.CacheReadTypeDefault)
1✔
956
        if err != nil {
1✔
957
                klog.Errorf("get(%s) from dataPlaneAPIVolCache failed with error: %v", accountName, err)
×
958
        }
×
959
        if cache != nil {
1✔
960
                return true
×
961
        }
×
962
        return false
1✔
963
}
964

965
// appendDefaultMountOptions return mount options combined with mountOptions and defaultMountOptions
966
func appendDefaultMountOptions(mountOptions []string, tmpPath, containerName string) []string {
4✔
967
        var defaultMountOptions = map[string]string{
4✔
968
                "--pre-mount-validate": "true",
4✔
969
                "--use-https":          "true",
4✔
970
                "--tmp-path":           tmpPath,
4✔
971
                "--container-name":     containerName,
4✔
972
                // prevent billing charges on mounting
4✔
973
                "--cancel-list-on-mount-seconds": "10",
4✔
974
                // allow remounting using a non-empty tmp-path
4✔
975
                "--empty-dir-check": "false",
4✔
976
        }
4✔
977

4✔
978
        // stores the mount options already included in mountOptions
4✔
979
        included := make(map[string]bool)
4✔
980

4✔
981
        for _, mountOption := range mountOptions {
11✔
982
                for k := range defaultMountOptions {
49✔
983
                        if strings.HasPrefix(mountOption, k) {
46✔
984
                                included[k] = true
4✔
985
                        }
4✔
986
                }
987
        }
988

989
        allMountOptions := mountOptions
4✔
990

4✔
991
        for k, v := range defaultMountOptions {
28✔
992
                if _, isIncluded := included[k]; !isIncluded {
44✔
993
                        if v != "" {
40✔
994
                                allMountOptions = append(allMountOptions, fmt.Sprintf("%s=%s", k, v))
20✔
995
                        } else {
20✔
996
                                allMountOptions = append(allMountOptions, k)
×
997
                        }
×
998
                }
999
        }
1000

1001
        return allMountOptions
4✔
1002
}
1003

1004
// chmodIfPermissionMismatch only perform chmod when permission mismatches
1005
func chmodIfPermissionMismatch(targetPath string, mode os.FileMode) error {
3✔
1006
        info, err := os.Lstat(targetPath)
3✔
1007
        if err != nil {
4✔
1008
                return err
1✔
1009
        }
1✔
1010
        perm := info.Mode() & os.ModePerm
2✔
1011
        if perm != mode {
3✔
1012
                klog.V(2).Infof("chmod targetPath(%s, mode:0%o) with permissions(0%o)", targetPath, info.Mode(), mode)
1✔
1013
                if err := os.Chmod(targetPath, mode); err != nil {
1✔
1014
                        return err
×
1015
                }
×
1016
        } else {
1✔
1017
                klog.V(2).Infof("skip chmod on targetPath(%s) since mode is already 0%o)", targetPath, info.Mode())
1✔
1018
        }
1✔
1019
        return nil
2✔
1020
}
1021

1022
func createStorageAccountSecret(account, key string) map[string]string {
1✔
1023
        secret := make(map[string]string)
1✔
1024
        secret[defaultSecretAccountName] = account
1✔
1025
        secret[defaultSecretAccountKey] = key
1✔
1026
        return secret
1✔
1027
}
1✔
1028

1029
// setKeyValueInMap set key/value pair in map
1030
// key in the map is case insensitive, if key already exists, overwrite existing value
1031
func setKeyValueInMap(m map[string]string, key, value string) {
6✔
1032
        if m == nil {
7✔
1033
                return
1✔
1034
        }
1✔
1035
        for k := range m {
16✔
1036
                if strings.EqualFold(k, key) {
13✔
1037
                        m[k] = value
2✔
1038
                        return
2✔
1039
                }
2✔
1040
        }
1041
        m[key] = value
3✔
1042
}
1043

1044
// getValueInMap get value from map by key
1045
// key in the map is case insensitive
1046
func getValueInMap(m map[string]string, key string) string {
12✔
1047
        if m == nil {
13✔
1048
                return ""
1✔
1049
        }
1✔
1050
        for k, v := range m {
23✔
1051
                if strings.EqualFold(k, key) {
16✔
1052
                        return v
4✔
1053
                }
4✔
1054
        }
1055
        return ""
7✔
1056
}
1057

1058
// replaceWithMap replace key with value for str
1059
func replaceWithMap(str string, m map[string]string) string {
13✔
1060
        for k, v := range m {
18✔
1061
                if k != "" {
9✔
1062
                        str = strings.ReplaceAll(str, k, v)
4✔
1063
                }
4✔
1064
        }
1065
        return str
13✔
1066
}
1067

1068
func isSupportedFSGroupChangePolicy(policy string) bool {
27✔
1069
        if policy == "" {
47✔
1070
                return true
20✔
1071
        }
20✔
1072
        for _, v := range supportedFSGroupChangePolicyList {
25✔
1073
                if policy == v {
21✔
1074
                        return true
3✔
1075
                }
3✔
1076
        }
1077
        return false
4✔
1078
}
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