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

kubernetes-sigs / blob-csi-driver / 7614615314

22 Jan 2024 04:56PM UTC coverage: 79.444%. Remained the same
7614615314

Pull #1227

github

web-flow
chore(deps): bump github.com/onsi/gomega from 1.30.0 to 1.31.1

Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.30.0 to 1.31.1.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.30.0...v1.31.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #1227: chore(deps): bump github.com/onsi/gomega from 1.30.0 to 1.31.1

2114 of 2661 relevant lines covered (79.44%)

7.66 hits per line

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

84.8
/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/sdk/resourcemanager/storage/armstorage"
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
        "sigs.k8s.io/cloud-provider-azure/pkg/azclient"
48
        azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
49
        "sigs.k8s.io/cloud-provider-azure/pkg/provider"
50
        azure "sigs.k8s.io/cloud-provider-azure/pkg/provider"
51
)
52

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

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

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

136
        // 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
137
        containerMaxSize = 100 * util.TiB
138

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

141
        defaultNamespace = "default"
142

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

150
        VolumeID = "volumeid"
151

152
        defaultStorageEndPointSuffix = "core.windows.net"
153

154
        FSGroupChangeNone = "None"
155
)
156

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

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

183
func (option *DriverOptions) AddFlags() {
1✔
184
        flag.StringVar(&option.BlobfuseProxyEndpoint, "blobfuse-proxy-endpoint", "unix://tmp/blobfuse-proxy.sock", "blobfuse-proxy endpoint")
1✔
185
        flag.StringVar(&option.NodeID, "nodeid", "", "node id")
1✔
186
        flag.StringVar(&option.DriverName, "drivername", DefaultDriverName, "name of the driver")
1✔
187
        flag.BoolVar(&option.EnableBlobfuseProxy, "enable-blobfuse-proxy", false, "using blobfuse proxy for mounts")
1✔
188
        flag.IntVar(&option.BlobfuseProxyConnTimout, "blobfuse-proxy-connect-timeout", 5, "blobfuse proxy connection timeout(seconds)")
1✔
189
        flag.BoolVar(&option.EnableBlobMockMount, "enable-blob-mock-mount", false, "enable mock mount(only for testing)")
1✔
190
        flag.BoolVar(&option.EnableGetVolumeStats, "enable-get-volume-stats", false, "allow GET_VOLUME_STATS on agent node")
1✔
191
        flag.BoolVar(&option.AppendTimeStampInCacheDir, "append-timestamp-cache-dir", false, "append timestamp into cache directory on agent node")
1✔
192
        flag.Uint64Var(&option.MountPermissions, "mount-permissions", 0777, "mounted folder permissions")
1✔
193
        flag.BoolVar(&option.AllowInlineVolumeKeyAccessWithIdentity, "allow-inline-volume-key-access-with-idenitity", false, "allow accessing storage account key using cluster identity for inline volume")
1✔
194
        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✔
195
        flag.BoolVar(&option.EnableAznfsMount, "enable-aznfs-mount", false, "replace nfs mount with aznfs mount")
1✔
196
        flag.IntVar(&option.VolStatsCacheExpireInMinutes, "vol-stats-cache-expire-in-minutes", 10, "The cache expire time in minutes for volume stats cache")
1✔
197
        flag.IntVar(&option.SasTokenExpirationMinutes, "sas-token-expiration-minutes", 1440, "sas token expiration minutes during volume cloning")
1✔
198
        flag.BoolVar(&option.EnableVolumeMountGroup, "enable-volume-mount-group", true, "indicates whether enabling VOLUME_MOUNT_GROUP")
1✔
199
        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✔
200
}
1✔
201

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

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

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

277
        var err error
131✔
278
        getter := func(key string) (interface{}, error) { return nil, nil }
138✔
279
        if d.accountSearchCache, err = azcache.NewTimedCache(time.Minute, getter, false); err != nil {
131✔
280
                klog.Fatalf("%v", err)
×
281
        }
×
282
        if d.dataPlaneAPIVolCache, err = azcache.NewTimedCache(10*time.Minute, getter, false); err != nil {
131✔
283
                klog.Fatalf("%v", err)
×
284
        }
×
285
        if d.azcopySasTokenCache, err = azcache.NewTimedCache(15*time.Minute, getter, false); err != nil {
131✔
286
                klog.Fatalf("%v", err)
×
287
        }
×
288

289
        if options.VolStatsCacheExpireInMinutes <= 0 {
262✔
290
                options.VolStatsCacheExpireInMinutes = 10 // default expire in 10 minutes
131✔
291
        }
131✔
292
        if d.volStatsCache, err = azcache.NewTimedCache(time.Duration(options.VolStatsCacheExpireInMinutes)*time.Minute, getter, false); err != nil {
131✔
293
                klog.Fatalf("%v", err)
×
294
        }
×
295
        d.mounter = &mount.SafeFormatAndMount{
131✔
296
                Interface: mount.New(""),
131✔
297
                Exec:      utilexec.New(),
131✔
298
        }
131✔
299

131✔
300
        // Initialize default library driver
131✔
301
        d.AddControllerServiceCapabilities(
131✔
302
                []csi.ControllerServiceCapability_RPC_Type{
131✔
303
                        csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME,
131✔
304
                        //csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT,
131✔
305
                        //csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS,
131✔
306
                        csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
131✔
307
                        csi.ControllerServiceCapability_RPC_SINGLE_NODE_MULTI_WRITER,
131✔
308
                        csi.ControllerServiceCapability_RPC_CLONE_VOLUME,
131✔
309
                })
131✔
310
        d.AddVolumeCapabilityAccessModes([]csi.VolumeCapability_AccessMode_Mode{
131✔
311
                csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
131✔
312
                csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY,
131✔
313
                csi.VolumeCapability_AccessMode_SINGLE_NODE_SINGLE_WRITER,
131✔
314
                csi.VolumeCapability_AccessMode_SINGLE_NODE_MULTI_WRITER,
131✔
315
                csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY,
131✔
316
                csi.VolumeCapability_AccessMode_MULTI_NODE_SINGLE_WRITER,
131✔
317
                csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
131✔
318
        })
131✔
319

131✔
320
        nodeCap := []csi.NodeServiceCapability_RPC_Type{
131✔
321
                csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME,
131✔
322
                csi.NodeServiceCapability_RPC_SINGLE_NODE_MULTI_WRITER,
131✔
323
        }
131✔
324
        if d.enableGetVolumeStats {
131✔
325
                nodeCap = append(nodeCap, csi.NodeServiceCapability_RPC_GET_VOLUME_STATS)
×
326
        }
×
327
        if d.enableVolumeMountGroup {
131✔
328
                nodeCap = append(nodeCap, csi.NodeServiceCapability_RPC_VOLUME_MOUNT_GROUP)
×
329
        }
×
330
        d.AddNodeServiceCapabilities(nodeCap)
131✔
331

131✔
332
        return &d
131✔
333
}
334

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

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

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

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

415
func checkContainerNameBeginAndEnd(containerName string) bool {
11✔
416
        length := len(containerName)
11✔
417
        if (('a' <= containerName[0] && containerName[0] <= 'z') ||
11✔
418
                ('0' <= containerName[0] && containerName[0] <= '9')) &&
11✔
419
                (('a' <= containerName[length-1] && containerName[length-1] <= 'z') ||
11✔
420
                        ('0' <= containerName[length-1] && containerName[length-1] <= '9')) {
20✔
421
                return true
9✔
422
        }
9✔
423

424
        return false
2✔
425
}
426

427
// isSASToken checks if the key contains the patterns.
428
// SAS token format could refer to https://docs.microsoft.com/en-us/rest/api/eventhub/generate-sas-token
429
func isSASToken(key string) bool {
3✔
430
        return strings.HasPrefix(key, "?")
3✔
431
}
3✔
432

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

442
        var (
10✔
443
                subsID                  string
10✔
444
                accountKey              string
10✔
445
                accountSasToken         string
10✔
446
                msiSecret               string
10✔
447
                storageSPNClientSecret  string
10✔
448
                storageSPNClientID      string
10✔
449
                storageSPNTenantID      string
10✔
450
                secretName              string
10✔
451
                pvcNamespace            string
10✔
452
                keyVaultURL             string
10✔
453
                keyVaultSecretName      string
10✔
454
                keyVaultSecretVersion   string
10✔
455
                azureStorageAuthType    string
10✔
456
                authEnv                 []string
10✔
457
                getAccountKeyFromSecret bool
10✔
458
                getLatestAccountKey     bool
10✔
459
                clientID                string
10✔
460
                tenantID                string
10✔
461
                serviceAccountToken     string
10✔
462
        )
10✔
463

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

9✔
521
        if protocol == NFS {
11✔
522
                // nfs protocol does not need account key, return directly
2✔
523
                return rgName, accountName, accountKey, containerName, authEnv, err
2✔
524
        }
2✔
525

526
        if secretNamespace == "" {
13✔
527
                if pvcNamespace == "" {
12✔
528
                        secretNamespace = defaultNamespace
6✔
529
                } else {
6✔
530
                        secretNamespace = pvcNamespace
×
531
                }
×
532
        }
533

534
        if rgName == "" {
8✔
535
                rgName = d.cloud.ResourceGroup
1✔
536
        }
1✔
537

538
        if tenantID == "" {
14✔
539
                tenantID = d.cloud.TenantID
7✔
540
        }
7✔
541

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

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

624
        if containerName == "" {
4✔
625
                err = fmt.Errorf("could not find containerName from attributes(%v) or volumeID(%v)", attrib, volumeID)
×
626
        }
×
627

628
        if accountKey != "" {
8✔
629
                authEnv = append(authEnv, "AZURE_STORAGE_ACCESS_KEY="+accountKey)
4✔
630
        }
4✔
631

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

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

642
        if storageSPNClientSecret != "" {
5✔
643
                klog.V(2).Infof("storageSPNClientSecret is not empty, use it to access storage account(%s), container(%s)", accountName, containerName)
1✔
644
                authEnv = append(authEnv, "AZURE_STORAGE_SPN_CLIENT_SECRET="+storageSPNClientSecret)
1✔
645
        }
1✔
646

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

652
        if storageSPNTenantID != "" {
4✔
653
                klog.V(2).Infof("storageSPNTenantID(%s) is not empty, use it to access storage account(%s), container(%s)", storageSPNTenantID, accountName, containerName)
×
654
                authEnv = append(authEnv, "AZURE_STORAGE_SPN_TENANT_ID="+storageSPNTenantID)
×
655
        }
×
656

657
        return rgName, accountName, accountKey, containerName, authEnv, err
4✔
658
}
659

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

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

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

721
                        if rgName == "" {
2✔
722
                                rgName = d.cloud.ResourceGroup
×
723
                        }
×
724

725
                        accountKey, err = d.cloud.GetStorageAccesskey(ctx, subsID, accountName, rgName, getLatestAccountKey)
2✔
726
                        if err != nil {
3✔
727
                                return "", "", "", "", fmt.Errorf("no key for storage account(%s) under resource group(%s), err %w", accountName, rgName, err)
1✔
728
                        }
1✔
729
                }
730
        }
731

732
        if containerName == "" {
1✔
733
                return "", "", "", "", fmt.Errorf("could not find containerName from attributes(%v) or volumeID(%v)", attrib, volumeID)
×
734
        }
×
735

736
        return accountName, accountKey, accountSasToken, containerName, nil
1✔
737
}
738

739
func IsCorruptedDir(dir string) bool {
4✔
740
        _, pathErr := mount.PathExists(dir)
4✔
741
        return pathErr != nil && mount.IsCorruptedMnt(pathErr)
4✔
742
}
4✔
743

744
func isRetriableError(err error) bool {
5✔
745
        if err != nil {
9✔
746
                for _, v := range retriableErrors {
19✔
747
                        if strings.Contains(strings.ToLower(err.Error()), strings.ToLower(v)) {
18✔
748
                                return true
3✔
749
                        }
3✔
750
                }
751
        }
752
        return false
2✔
753
}
754

755
func isSupportedProtocol(protocol string) bool {
17✔
756
        if protocol == "" {
18✔
757
                return true
1✔
758
        }
1✔
759
        for _, v := range supportedProtocolList {
40✔
760
                if protocol == v {
38✔
761
                        return true
14✔
762
                }
14✔
763
        }
764
        return false
2✔
765
}
766

767
func isSupportedAccessTier(accessTier string) bool {
20✔
768
        if accessTier == "" {
33✔
769
                return true
13✔
770
        }
13✔
771
        for _, tier := range armstorage.PossibleAccessTierValues() {
25✔
772
                if accessTier == string(tier) {
21✔
773
                        return true
3✔
774
                }
3✔
775
        }
776
        return false
4✔
777
}
778

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

799
// isNFSProtocol checks if the protocol is NFS or AZNFS
800
func isNFSProtocol(protocol string) bool {
21✔
801
        protocol = strings.ToLower(protocol)
21✔
802
        return protocol == NFS || protocol == AZNFS
21✔
803
}
21✔
804

805
// get storage account from secrets map
806
func getStorageAccount(secrets map[string]string) (string, string, error) {
22✔
807
        if secrets == nil {
23✔
808
                return "", "", fmt.Errorf("unexpected: getStorageAccount secrets is nil")
1✔
809
        }
1✔
810

811
        var accountName, accountKey string
21✔
812
        for k, v := range secrets {
64✔
813
                v = strings.TrimSpace(v)
43✔
814
                switch strings.ToLower(k) {
43✔
815
                case accountNameField:
7✔
816
                        accountName = v
7✔
817
                case defaultSecretAccountName: // for compatibility with built-in azurefile plugin
13✔
818
                        accountName = v
13✔
819
                case accountKeyField:
7✔
820
                        accountKey = v
7✔
821
                case defaultSecretAccountKey: // for compatibility with built-in azurefile plugin
12✔
822
                        accountKey = v
12✔
823
                }
824
        }
825

826
        if accountName == "" {
25✔
827
                return accountName, accountKey, fmt.Errorf("could not find %s or %s field in secrets", accountNameField, defaultSecretAccountName)
4✔
828
        }
4✔
829
        if accountKey == "" {
21✔
830
                return accountName, accountKey, fmt.Errorf("could not find %s or %s field in secrets", accountKeyField, defaultSecretAccountKey)
4✔
831
        }
4✔
832

833
        accountName = strings.TrimSpace(accountName)
13✔
834
        klog.V(4).Infof("got storage account(%s) from secret", accountName)
13✔
835
        return accountName, accountKey, nil
13✔
836
}
837

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

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

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

894
        // read from k8s secret first
895
        if secretName == "" {
10✔
896
                secretName = fmt.Sprintf(secretNameTemplate, accountOptions.Name)
4✔
897
        }
4✔
898
        _, accountKey, _, _, _, _, _, err := d.GetInfoFromSecret(ctx, secretName, secretNamespace) //nolint
6✔
899
        if err != nil {
10✔
900
                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✔
901
                accountKey, err = d.cloud.GetStorageAccesskey(ctx, accountOptions.SubscriptionID, accountOptions.Name, accountOptions.ResourceGroup, accountOptions.GetLatestAccountKey)
4✔
902
        }
4✔
903
        return accountOptions.Name, accountKey, err
6✔
904
}
905

906
// GetInfoFromSecret get info from k8s secret
907
// return <accountName, accountKey, accountSasToken, msiSecret, spnClientSecret, spnClientID, spnTenantID, error>
908
func (d *Driver) GetInfoFromSecret(ctx context.Context, secretName, secretNamespace string) (string, string, string, string, string, string, string, error) {
15✔
909
        if d.KubeClient == nil {
24✔
910
                return "", "", "", "", "", "", "", fmt.Errorf("could not get account key from secret(%s): KubeClient is nil", secretName)
9✔
911
        }
9✔
912

913
        secret, err := d.KubeClient.CoreV1().Secrets(secretNamespace).Get(ctx, secretName, metav1.GetOptions{})
6✔
914
        if err != nil {
8✔
915
                return "", "", "", "", "", "", "", fmt.Errorf("could not get secret(%v): %w", secretName, err)
2✔
916
        }
2✔
917

918
        accountName := strings.TrimSpace(string(secret.Data[defaultSecretAccountName][:]))
4✔
919
        accountKey := strings.TrimSpace(string(secret.Data[defaultSecretAccountKey][:]))
4✔
920
        accountSasToken := strings.TrimSpace(string(secret.Data[accountSasTokenField][:]))
4✔
921
        msiSecret := strings.TrimSpace(string(secret.Data[msiSecretField][:]))
4✔
922
        spnClientSecret := strings.TrimSpace(string(secret.Data[storageSPNClientSecretField][:]))
4✔
923
        spnClientID := strings.TrimSpace(string(secret.Data[storageSPNClientIDField][:]))
4✔
924
        spnTenantID := strings.TrimSpace(string(secret.Data[storageSPNTenantIDField][:]))
4✔
925

4✔
926
        klog.V(4).Infof("got storage account(%s) from secret(%s) namespace(%s)", accountName, secretName, secretNamespace)
4✔
927
        return accountName, accountKey, accountSasToken, msiSecret, spnClientSecret, spnClientID, spnTenantID, nil
4✔
928
}
929

930
// getSubnetResourceID get default subnet resource ID from cloud provider config
931
func (d *Driver) getSubnetResourceID(vnetResourceGroup, vnetName, subnetName string) string {
6✔
932
        subsID := d.cloud.SubscriptionID
6✔
933
        if len(d.cloud.NetworkResourceSubscriptionID) > 0 {
10✔
934
                subsID = d.cloud.NetworkResourceSubscriptionID
4✔
935
        }
4✔
936

937
        if len(vnetResourceGroup) == 0 {
11✔
938
                vnetResourceGroup = d.cloud.ResourceGroup
5✔
939
                if len(d.cloud.VnetResourceGroup) > 0 {
8✔
940
                        vnetResourceGroup = d.cloud.VnetResourceGroup
3✔
941
                }
3✔
942
        }
943

944
        if len(vnetName) == 0 {
11✔
945
                vnetName = d.cloud.VnetName
5✔
946
        }
5✔
947

948
        if len(subnetName) == 0 {
11✔
949
                subnetName = d.cloud.SubnetName
5✔
950
        }
5✔
951
        return fmt.Sprintf(subnetTemplate, subsID, vnetResourceGroup, vnetName, subnetName)
6✔
952
}
953

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

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

4✔
985
        // stores the mount options already included in mountOptions
4✔
986
        included := make(map[string]bool)
4✔
987

4✔
988
        for _, mountOption := range mountOptions {
11✔
989
                for k := range defaultMountOptions {
49✔
990
                        if strings.HasPrefix(mountOption, k) {
46✔
991
                                included[k] = true
4✔
992
                        }
4✔
993
                }
994
        }
995

996
        allMountOptions := mountOptions
4✔
997

4✔
998
        for k, v := range defaultMountOptions {
28✔
999
                if _, isIncluded := included[k]; !isIncluded {
44✔
1000
                        if v != "" {
40✔
1001
                                allMountOptions = append(allMountOptions, fmt.Sprintf("%s=%s", k, v))
20✔
1002
                        } else {
20✔
1003
                                allMountOptions = append(allMountOptions, k)
×
1004
                        }
×
1005
                }
1006
        }
1007

1008
        return allMountOptions
4✔
1009
}
1010

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

1029
func createStorageAccountSecret(account, key string) map[string]string {
1✔
1030
        secret := make(map[string]string)
1✔
1031
        secret[defaultSecretAccountName] = account
1✔
1032
        secret[defaultSecretAccountKey] = key
1✔
1033
        return secret
1✔
1034
}
1✔
1035

1036
// setKeyValueInMap set key/value pair in map
1037
// key in the map is case insensitive, if key already exists, overwrite existing value
1038
func setKeyValueInMap(m map[string]string, key, value string) {
6✔
1039
        if m == nil {
7✔
1040
                return
1✔
1041
        }
1✔
1042
        for k := range m {
16✔
1043
                if strings.EqualFold(k, key) {
13✔
1044
                        m[k] = value
2✔
1045
                        return
2✔
1046
                }
2✔
1047
        }
1048
        m[key] = value
3✔
1049
}
1050

1051
// getValueInMap get value from map by key
1052
// key in the map is case insensitive
1053
func getValueInMap(m map[string]string, key string) string {
12✔
1054
        if m == nil {
13✔
1055
                return ""
1✔
1056
        }
1✔
1057
        for k, v := range m {
23✔
1058
                if strings.EqualFold(k, key) {
16✔
1059
                        return v
4✔
1060
                }
4✔
1061
        }
1062
        return ""
7✔
1063
}
1064

1065
// replaceWithMap replace key with value for str
1066
func replaceWithMap(str string, m map[string]string) string {
13✔
1067
        for k, v := range m {
18✔
1068
                if k != "" {
9✔
1069
                        str = strings.ReplaceAll(str, k, v)
4✔
1070
                }
4✔
1071
        }
1072
        return str
13✔
1073
}
1074

1075
func isSupportedFSGroupChangePolicy(policy string) bool {
27✔
1076
        if policy == "" {
47✔
1077
                return true
20✔
1078
        }
20✔
1079
        for _, v := range supportedFSGroupChangePolicyList {
25✔
1080
                if policy == v {
21✔
1081
                        return true
3✔
1082
                }
3✔
1083
        }
1084
        return false
4✔
1085
}
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