sigs.k8s.io/blob-csi-driver@v1.24.1/test/e2e/testsuites/pre_provisioned_provided_credentials_tester.go (about)

     1  /*
     2  Copyright 2020 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 testsuites
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  
    24  	"github.com/onsi/ginkgo/v2"
    25  
    26  	"sigs.k8s.io/blob-csi-driver/pkg/blob"
    27  	"sigs.k8s.io/blob-csi-driver/test/e2e/driver"
    28  	"sigs.k8s.io/blob-csi-driver/test/utils/azure"
    29  
    30  	v1 "k8s.io/api/core/v1"
    31  	clientset "k8s.io/client-go/kubernetes"
    32  	"k8s.io/kubernetes/test/e2e/framework"
    33  )
    34  
    35  // PreProvisionedProvidedCredentiasTest will provision required PV(s), PVC(s) and Pod(s)
    36  // Testing that the Pod(s) can be created successfully with provided storage account name and key(or sastoken)
    37  type PreProvisionedProvidedCredentiasTest struct {
    38  	CSIDriver driver.PreProvisionedVolumeTestDriver
    39  	Pods      []PodDetails
    40  	Driver    *blob.Driver
    41  }
    42  
    43  func (t *PreProvisionedProvidedCredentiasTest) Run(ctx context.Context, client clientset.Interface, namespace *v1.Namespace) {
    44  	kvClient, err := azure.NewKeyVaultClient()
    45  	framework.ExpectNoError(err)
    46  
    47  	authClient, err := azure.NewAuthorizationClient()
    48  	framework.ExpectNoError(err)
    49  
    50  	for _, pod := range t.Pods {
    51  		for n, volume := range pod.Volumes {
    52  			accountName, accountKey, _, _, err := t.Driver.GetStorageAccountAndContainer(ctx, volume.VolumeID, nil, nil)
    53  			framework.ExpectNoError(err, fmt.Sprintf("Error GetStorageAccountAndContainer from volumeID(%s): %v", volume.VolumeID, err))
    54  			var secretData map[string]string
    55  			var i int
    56  			var run = func() {
    57  				// add suffix to volumeID to force kubelet to NodeStageVolume every time,
    58  				// otherwise it will skip NodeStageVolume for the same VolumeID(VolumeHanlde)
    59  				pod.Volumes[n].VolumeID = fmt.Sprintf("%s-%d", volume.VolumeID, i)
    60  				i++
    61  
    62  				tsecret := NewTestSecret(client, namespace, volume.NodeStageSecretRef, secretData)
    63  				tsecret.Create(ctx)
    64  				defer tsecret.Cleanup(ctx)
    65  
    66  				tpod, cleanup := pod.SetupWithPreProvisionedVolumes(ctx, client, namespace, t.CSIDriver)
    67  				// defer must be called here for resources not get removed before using them
    68  				for i := range cleanup {
    69  					defer cleanup[i](ctx)
    70  				}
    71  
    72  				ginkgo.By("deploying the pod")
    73  				tpod.Create(ctx)
    74  				defer func() {
    75  					tpod.Cleanup(ctx)
    76  				}()
    77  
    78  				ginkgo.By("checking that the pods command exits with no error")
    79  				tpod.WaitForSuccess(ctx)
    80  			}
    81  
    82  			// test for storage account key
    83  			ginkgo.By("Run for storage account key")
    84  			secretData = map[string]string{
    85  				"azurestorageaccountname": accountName,
    86  				"azurestorageaccountkey":  accountKey,
    87  			}
    88  			run()
    89  
    90  			// test for storage account SAS token
    91  			ginkgo.By("Run for storage account SAS token")
    92  			pod.Volumes[n].Attrib = map[string]string{
    93  				"azurestorageauthtype": "SAS",
    94  			}
    95  			sasToken := GenerateSASToken(accountName, accountKey)
    96  			secretData = map[string]string{
    97  				"azurestorageaccountname":     accountName,
    98  				"azurestorageaccountsastoken": sasToken,
    99  			}
   100  			run()
   101  
   102  			// test for service principal
   103  			ginkgo.By("Run for service principal")
   104  			pod.Volumes[n].Attrib = map[string]string{
   105  				"azurestorageauthtype":    "SPN",
   106  				"azurestoragespnclientid": kvClient.Cred.AADClientID,
   107  				"azurestoragespntenantid": kvClient.Cred.TenantID,
   108  			}
   109  			secretData = map[string]string{
   110  				"azurestorageaccountname":     accountName,
   111  				"azurestoragespnclientsecret": kvClient.Cred.AADClientSecret,
   112  			}
   113  
   114  			// assign role to service principal
   115  			objectID, err := kvClient.GetServicePrincipalObjectID(ctx, kvClient.Cred.AADClientID)
   116  			framework.ExpectNoError(err, fmt.Sprintf("Error GetServicePrincipalObjectID from clientID(%s): %v", kvClient.Cred.AADClientID, err))
   117  
   118  			resourceID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/%s", kvClient.Cred.SubscriptionID, kvClient.Cred.ResourceGroup, accountName)
   119  
   120  			ginkgo.By(fmt.Sprintf("assign Storage Blob Data Contributor role to the service principal, objectID:%s", objectID))
   121  			roleDef, err := authClient.GetRoleDefinition(ctx, resourceID, "Storage Blob Data Contributor")
   122  			framework.ExpectNoError(err, fmt.Sprintf("Error GetRoleDefinition from resourceID(%s): %v", resourceID, err))
   123  
   124  			roleDefID := *roleDef.ID
   125  			_, err = authClient.AssignRole(ctx, resourceID, objectID, roleDefID)
   126  			if err != nil && strings.Contains(err.Error(), "The role assignment already exists") {
   127  				err = nil
   128  			}
   129  			framework.ExpectNoError(err, fmt.Sprintf("Error AssignRole (roleDefID(%s)) to objectID(%s) to access resource (resourceID(%s)), error: %v", roleDefID, objectID, resourceID, err))
   130  
   131  			run()
   132  
   133  			// test for managed identity(objectID)
   134  			objectID, err = kvClient.GetMSIObjectID(ctx, "blobfuse-csi-driver-e2e-test-id")
   135  			if err != nil {
   136  				// only e2e-vmss test job will use msi blobfuse-csi-driver-e2e-test-id, other jobs use service principal, so skip here
   137  				return
   138  			}
   139  
   140  			ginkgo.By(fmt.Sprintf("Run for managed identity (objectID %s)", objectID))
   141  			pod.Volumes[n].Attrib = map[string]string{
   142  				"azurestorageauthtype":         "MSI",
   143  				"azurestorageidentityobjectid": objectID,
   144  			}
   145  
   146  			secretData = map[string]string{
   147  				"azurestorageaccountname": accountName,
   148  			}
   149  			ginkgo.By(fmt.Sprintf("assign Storage Blob Data Contributor role to the managed identity, objectID:%s", objectID))
   150  			_, err = authClient.AssignRole(ctx, resourceID, objectID, roleDefID)
   151  			if err != nil && strings.Contains(err.Error(), "The role assignment already exists") {
   152  				err = nil
   153  			}
   154  			framework.ExpectNoError(err, fmt.Sprintf("Error AssignRole (roleDefID(%s)) to objectID(%s) to access resource (resourceID(%s)), error: %v", roleDefID, objectID, resourceID, err))
   155  
   156  			run()
   157  
   158  			// test for managed identity(resourceID)
   159  			resourceID, err = kvClient.GetMSIResourceID(ctx, "blobfuse-csi-driver-e2e-test-id")
   160  			if err != nil {
   161  				// only e2e-vmss test job will use msi blobfuse-csi-driver-e2e-test-id, other jobs use service principal, so skip here
   162  				return
   163  			}
   164  			ginkgo.By(fmt.Sprintf("Run for managed identity (resourceID %s)", resourceID))
   165  			pod.Volumes[n].Attrib = map[string]string{
   166  				"azurestorageauthtype":           "MSI",
   167  				"azurestorageidentityresourceid": resourceID,
   168  			}
   169  			secretData = map[string]string{
   170  				"azurestorageaccountname": accountName,
   171  			}
   172  
   173  			run()
   174  		}
   175  	}
   176  }