e2etest/config.go (166 lines of code) (raw):

// Copyright © Microsoft <wastore@microsoft.com> // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. package e2etest import ( "encoding/json" "fmt" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "os" "reflect" "strconv" "github.com/JeffreyRichter/enum/enum" ) // clearly define all the inputs to the end-to-end tests // it's ok to panic if the inputs are absolutely required // the general guidance is to take in as few parameters as possible type GlobalInputManager struct{} func (GlobalInputManager) GetWorkloadIdentity() (tenantID string, clientID string, token string) { tenantID = os.Getenv("tenantId") if tenantID == "" { panic("tenantId must be specified to authenticate with workload identity") } clientID = os.Getenv("servicePrincipalId") if clientID == "" { panic("servicePrincipalId must be specified to authenticate with workload identity") } token = os.Getenv("idToken") if token == "" { panic("idToken must be specified to authenticate with workload identity") } return } func (GlobalInputManager) GetServicePrincipalAuth() (tenantID string, applicationID string, clientSecret string) { tenantID = os.Getenv("AZCOPY_E2E_TENANT_ID") applicationID = os.Getenv("AZCOPY_E2E_APPLICATION_ID") clientSecret = os.Getenv("AZCOPY_E2E_CLIENT_SECRET") if applicationID == "" || clientSecret == "" { panic("Insufficient information was supplied for service principal authentication") } return } func (GlobalInputManager) GetAccountAndKey(accountType AccountType) (string, string) { var name, key string switch accountType { case EAccountType.Standard(): name = os.Getenv("AZCOPY_E2E_ACCOUNT_NAME") key = os.Getenv("AZCOPY_E2E_ACCOUNT_KEY") case EAccountType.HierarchicalNamespaceEnabled(): name = os.Getenv("AZCOPY_E2E_ACCOUNT_NAME_HNS") key = os.Getenv("AZCOPY_E2E_ACCOUNT_KEY_HNS") case EAccountType.Classic(): name = os.Getenv("AZCOPY_E2E_CLASSIC_ACCOUNT_NAME") key = os.Getenv("AZCOPY_E2E_CLASSIC_ACCOUNT_KEY") case EAccountType.Azurite(): // Note: the key below is not a secret, this is the publicly documented Azurite key name = "devstoreaccount1" key = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" default: panic("Only the standard account type is supported for the moment.") } if name == "" || key == "" { panic(fmt.Sprintf("Name and key for %s account must be set before running tests", accountType)) } return name, key } func (GlobalInputManager) GetExecutablePath() string { path := os.Getenv("AZCOPY_E2E_EXECUTABLE_PATH") if path == "" { panic("Cannot test AzCopy if AZCOPY_E2E_EXECUTABLE_PATH is not provided") } return path } func (GlobalInputManager) KeepFailedData() bool { raw := os.Getenv("AZCOPY_E2E_KEEP_FAILED_DATA") if raw == "" { return false } result, err := strconv.ParseBool(raw) if err != nil { panic("If AZCOPY_E2E_KEEP_FAILED_DATA is set, it must be a boolean") } return result } func (GlobalInputManager) TestSummaryLogPath() string { return os.Getenv("AZCOPY_E2E_TEST_SUMMARY_LOG") } var EAccountType = AccountType(0) type AccountType uint8 func (AccountType) Standard() AccountType { return AccountType(0) } func (AccountType) PremiumBlockBlobs() AccountType { return AccountType(1) } func (AccountType) PremiumPageBlobs() AccountType { return AccountType(8) } func (AccountType) PremiumFileShares() AccountType { return AccountType(9) } func (AccountType) PremiumHNSEnabled() AccountType { return AccountType(10) } func (AccountType) HierarchicalNamespaceEnabled() AccountType { return AccountType(2) } func (AccountType) Classic() AccountType { return AccountType(3) } func (AccountType) StdManagedDisk() AccountType { return AccountType(4) } func (AccountType) OAuthManagedDisk() AccountType { return AccountType(5) } func (AccountType) S3() AccountType { return AccountType(6) } // Stub, for future testing use func (AccountType) GCP() AccountType { return AccountType(7) } // Stub, for future testing use func (AccountType) Azurite() AccountType { return AccountType(8) } func (AccountType) ManagedDiskSnapshot() AccountType { return AccountType(9) } func (AccountType) ManagedDiskSnapshotOAuth() AccountType { return AccountType(10) } func (AccountType) LargeManagedDiskSnapshot() AccountType { return AccountType(11) } func (AccountType) LargeManagedDisk() AccountType { return AccountType(12) } func (o AccountType) String() string { return enum.StringInt(o, reflect.TypeOf(o)) } func (o AccountType) IsManagedDisk() bool { return o == o.StdManagedDisk() || o == o.OAuthManagedDisk() || o == o.ManagedDiskSnapshot() || o == o.ManagedDiskSnapshotOAuth() || o == o.LargeManagedDiskSnapshot() || o == o.LargeManagedDisk() } func (o AccountType) IsBlobOnly() bool { return o.IsManagedDisk() || o == o.HierarchicalNamespaceEnabled() } /* {"SubscriptionID":"","ResourceGroupName":"","DiskName":""} */ type ManagedDiskConfig struct { SubscriptionID string ResourceGroupName string DiskName string oauth AccessToken isSnapshot bool } var ClassicE2EOAuthCache *OAuthCache func (gim GlobalInputManager) GetMDConfig(accountType AccountType) (*ManagedDiskConfig, error) { var mdConfigVar string var isSnapshot bool switch accountType { case EAccountType.StdManagedDisk(): mdConfigVar = "AZCOPY_E2E_STD_MANAGED_DISK_CONFIG" case EAccountType.OAuthManagedDisk(): mdConfigVar = "AZCOPY_E2E_OAUTH_MANAGED_DISK_CONFIG" case EAccountType.LargeManagedDisk(): mdConfigVar = "AZCOPY_E2E_LARGE_MANAGED_DISK_CONFIG" case EAccountType.ManagedDiskSnapshot(): mdConfigVar = "AZCOPY_E2E_STD_MANAGED_DISK_SNAPSHOT_CONFIG" isSnapshot = true case EAccountType.ManagedDiskSnapshotOAuth(): mdConfigVar = "AZCOPY_E2E_OAUTH_MANAGED_DISK_SNAPSHOT_CONFIG" isSnapshot = true case EAccountType.LargeManagedDiskSnapshot(): mdConfigVar = "AZCOPY_E2E_LARGE_MANAGED_DISK_SNAPSHOT_CONFIG" isSnapshot = true default: return nil, fmt.Errorf("account type %s is invalid for GetMDConfig", accountType.String()) } conf := os.Getenv(mdConfigVar) if conf == "" { return nil, fmt.Errorf("config for env var %s was empty; empty config: {\"SubscriptionID\":\"\",\"ResourceGroupName\":\"\",\"DiskName\":\"\"}", mdConfigVar) } var out ManagedDiskConfig err := json.Unmarshal([]byte(conf), &out) if err != nil { return nil, fmt.Errorf("failed to parse config") // Outputting the error may reveal semi-sensitive info like subscription ID } // Attach additional details to the config out.isSnapshot = isSnapshot err = gim.SetupClassicOAuthCache() if err != nil { return nil, fmt.Errorf("failed to setup OAuth cache: %w", err) } out.oauth, err = ClassicE2EOAuthCache.GetAccessToken(AzureManagementResource) if err != nil { return nil, fmt.Errorf("failed to get access token: %w", err) } return &out, nil } func (gim GlobalInputManager) SetupClassicOAuthCache() error { tenantId := os.Getenv("tenantId") cred, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{TenantID: tenantId}) if err != nil { return fmt.Errorf("failed to create credential: %w", err) } ClassicE2EOAuthCache = NewOAuthCache(cred, tenantId) return nil }