This commit is contained in:
Sourav Gupta 2024-04-04 15:59:29 +05:30 коммит произвёл GitHub
Родитель 0efccdc3ab
Коммит 8e06e67633
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
53 изменённых файлов: 2319 добавлений и 21428 удалений

Просмотреть файл

@ -1,9 +1,16 @@
## 2.3.0 (Unreleased)
## 2.3.0~preview.1 (Unreleased)
**Bug Fixes**
- [#1057](https://github.com/Azure/azure-storage-fuse/issues/1057) Fixed the issue where user-assigned identity is not used to authenticate when system-assigned identity is enabled.
- Listing blobs is now supported for blob names that contain characters that aren't valid in XML (U+FFFE or U+FFFF).
- [#1359](https://github.com/Azure/azure-storage-fuse/issues/1359), [#1368](https://github.com/Azure/azure-storage-fuse/issues/1368) Fixed RHEL 8.6 mount failure
**Features**
- lazy-write support for async flush and close file call. Actual upload will be scheduled in background when this feature is enable.
- Migrated to the latest [azblob SDK](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob).
- Migrated to the latest [azdatalake SDK](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake).
- Migrated from deprecated ADAL to MSAL through the latest [azidentity SDK](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity).
- Added support for uploading blobs in cold and premium tier.
- Support CPK for adls storage accounts.
- Lazy-write support for async flush and close file call. Actual upload will be scheduled in background when this feature is enabled.
## 2.2.1 (2024-02-28)
**Bug Fixes**
@ -11,7 +18,6 @@
- Fixed block-cache panic on flush of a file which has no active changeset
- Fixed block-cache panic on renaming a file and then flushing older handle
- Fixed block-cache flush resulting in invalid-block-list error
## 2.2.0 (2024-01-24)
**Bug Fixes**

19661
NOTICE

Разница между файлами не показана из-за своего большого размера Загрузить разницу

2
TSG.md
Просмотреть файл

@ -3,8 +3,6 @@
Please ensure logging is turned on DEBUG mode when trying to reproduce an issue.
This can help in many instances to understand what the underlying issue is.
A useful setting in your configuration file to utilize when debugging is `sdk-trace: true` under the azstorage component. This will log all outgoing REST calls.
# BlobFuse2 Health Monitor
One of the biggest BlobFuse2 features is our brand new health monitor. It allows customers gain more insight into how their BlobFuse2 instance is behaving with the rest of their machine. Visit [here](https://github.com/Azure/azure-storage-fuse/blob/main/tools/health-monitor/README.md) to set it up.

Просмотреть файл

@ -73,7 +73,7 @@ func (suite *keysTreeTestSuite) TestParseValue() {
{val: "65535", toType: reflect.Uint16, result: 65535},
{val: "4294967295", toType: reflect.Uint32, result: 4294967295},
{val: "18446744073709551615", toType: reflect.Uint64, result: uint64(18446744073709551615)},
{val: "6.24321908234", toType: reflect.Float32, result: 6.24321908234},
{val: "6.24321908234", toType: reflect.Float32, result: (float32)(6.24321908234)},
{val: "31247921747687123.123871293791263", toType: reflect.Float64, result: 31247921747687123.123871293791263},
{val: "6-8i", toType: reflect.Complex64, result: 6 - 8i},
{val: "2341241-910284i", toType: reflect.Complex128, result: 2341241 - 910284i},

Просмотреть файл

@ -47,7 +47,7 @@ import (
// Standard config default values
const (
blobfuse2Version_ = "2.2.1"
blobfuse2Version_ = "2.3.0~preview.1"
DefaultMaxLogFileSize = 512
DefaultLogFileCount = 10
@ -68,6 +68,8 @@ const (
BfuseStats = "blobfuse_stats"
FuseAllowedFlags = "invalid FUSE options. Allowed FUSE configurations are: `-o attr_timeout=TIMEOUT`, `-o negative_timeout=TIMEOUT`, `-o entry_timeout=TIMEOUT` `-o allow_other`, `-o allow_root`, `-o umask=PERMISSIONS -o default_permissions`, `-o ro`"
UserAgentHeader = "User-Agent"
)
func FuseIgnoredFlags() []string {

Просмотреть файл

@ -49,26 +49,26 @@ type Version struct {
}
// To keep the code simple, we assume we only use a simple subset of semantic versions.
// Namely, the version is either a normal stable version, or a pre-release version with '-preview' attached.
// Examples: 10.1.0, 11.2.0-preview.1
// Namely, the version is either a normal stable version, or a pre-release version with '~preview' or '-preview' attached.
// Examples: 10.1.0, 11.2.0-preview.1, 11.2.0~preview.1
func ParseVersion(raw string) (*Version, error) {
const standardError = "invalid version string"
rawSegments := strings.Split(raw, ".")
if !(len(rawSegments) == 3 || (len(rawSegments) == 4 && strings.Contains(rawSegments[2], "-"))) {
if !(len(rawSegments) == 3 || (len(rawSegments) == 4 && (strings.Contains(rawSegments[2], "-") || strings.Contains(rawSegments[2], "~")))) {
return nil, errors.New(standardError)
}
v := &Version{segments: make([]int64, 4), original: raw}
for i, str := range rawSegments {
//For any case such as SemVer-preview.1, SemVer-beta.1, SemVer-alpha.1 this would be true, and we assume the version to be a preview version.
if strings.Contains(str, "-") {
if strings.Contains(str, "-") || strings.Contains(str, "~") {
if i != 2 {
return nil, errors.New(standardError)
}
v.preview = true
//Splitting the string into two pieces and extracting SemVer which is always at 0th index
str = strings.Split(str, "-")[0]
str = strings.Split(strings.Split(str, "-")[0], "~")[0]
}
val, err := strconv.ParseInt(str, 10, 64)

Просмотреть файл

@ -58,6 +58,14 @@ func (vSuite *versionTestSuite) TestVersionEquality() {
v1, _ = ParseVersion("10.0.0-beta.5")
v2, _ = ParseVersion("10.0.0-beta.5")
assert.Equal(v1.compare(*v2), 0)
v1, _ = ParseVersion("10.0.0~preview.1")
v2, _ = ParseVersion("10.0.0~preview.1")
assert.Equal(v1.compare(*v2), 0)
v1, _ = ParseVersion("10.0.0~beta.5")
v2, _ = ParseVersion("10.0.0~beta.5")
assert.Equal(v1.compare(*v2), 0)
}
func (vSuite *versionTestSuite) TestVersionSuperiority() {
@ -82,6 +90,18 @@ func (vSuite *versionTestSuite) TestVersionSuperiority() {
v1, _ = ParseVersion("15.5.5-preview.6")
v2, _ = ParseVersion("15.5.5-preview.3")
assert.Equal(v1.compare(*v2), 1)
v1, _ = ParseVersion("15.5.6")
v2, _ = ParseVersion("15.5.6~preview.3")
assert.Equal(v1.compare(*v2), 1)
v1, _ = ParseVersion("15.5.6~preview.6")
v2, _ = ParseVersion("15.5.6~preview.3")
assert.Equal(v1.compare(*v2), 1)
v1, _ = ParseVersion("15.5.7~preview.6")
v2, _ = ParseVersion("15.5.7-preview.3")
assert.Equal(v1.compare(*v2), 1)
}
func (vSuite *versionTestSuite) TestVersionInferiority() {
@ -106,6 +126,18 @@ func (vSuite *versionTestSuite) TestVersionInferiority() {
v1, _ = ParseVersion("15.5.5-preview.3")
v2, _ = ParseVersion("15.5.5-preview.6")
assert.Equal(v1.compare(*v2), -1)
v1, _ = ParseVersion("15.5.6~preview.6")
v2, _ = ParseVersion("15.5.6")
assert.Equal(v1.compare(*v2), -1)
v1, _ = ParseVersion("15.5.6~preview.3")
v2, _ = ParseVersion("15.5.6~preview.6")
assert.Equal(v1.compare(*v2), -1)
v1, _ = ParseVersion("15.5.7-preview.3")
v2, _ = ParseVersion("15.5.7~preview.6")
assert.Equal(v1.compare(*v2), -1)
}
func TestVersionTestSuite(t *testing.T) {

Просмотреть файл

@ -34,6 +34,8 @@
package azstorage
import (
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/Azure/azure-storage-fuse/v2/common/log"
)
@ -71,13 +73,13 @@ type azAuthConfig struct {
type azAuth interface {
getEndpoint() string
setOption(key, value string)
getCredential() interface{}
getServiceClient(stConfig *AzStorageConfig) (interface{}, error)
}
// getAzAuth returns a new AzAuth
// config: Defines the AzAuthConfig
func getAzAuth(config azAuthConfig) azAuth {
log.Debug("azAuth::getAzAuth : account %s, account-type %s, protocol %s, endpoint %s",
log.Debug("azAuth::getAzAuth : Account: %s, AccountType: %s, Protocol: %s, Endpoint: %s",
config.AccountName,
config.AccountType,
func(useHttp bool) string {
@ -89,14 +91,14 @@ func getAzAuth(config azAuthConfig) azAuth {
config.Endpoint)
if EAccountType.BLOCK() == config.AccountType {
return getAzAuthBlob(config)
return getAzBlobAuth(config)
} else if EAccountType.ADLS() == config.AccountType {
return getAzAuthBfs(config)
return getAzDatalakeAuth(config)
}
return nil
}
func getAzAuthBlob(config azAuthConfig) azAuth {
func getAzBlobAuth(config azAuthConfig) azAuth {
base := azAuthBase{config: config}
if config.AuthMode == EAuthType.KEY() {
return &azAuthBlobKey{
@ -123,39 +125,39 @@ func getAzAuthBlob(config azAuthConfig) azAuth {
},
}
} else {
log.Crit("azAuth::getAzAuthBlob : Auth type %s not supported. Failed to create Auth object", config.AuthMode)
log.Crit("azAuth::getAzBlobAuth : Auth type %s not supported. Failed to create Auth object", config.AuthMode)
}
return nil
}
func getAzAuthBfs(config azAuthConfig) azAuth {
func getAzDatalakeAuth(config azAuthConfig) azAuth {
base := azAuthBase{config: config}
if config.AuthMode == EAuthType.KEY() {
return &azAuthBfsKey{
return &azAuthDatalakeKey{
azAuthKey{
azAuthBase: base,
},
}
} else if config.AuthMode == EAuthType.SAS() {
return &azAuthBfsSAS{
return &azAuthDatalakeSAS{
azAuthSAS{
azAuthBase: base,
},
}
} else if config.AuthMode == EAuthType.MSI() {
return &azAuthBfsMSI{
return &azAuthDatalakeMSI{
azAuthMSI{
azAuthBase: base,
},
}
} else if config.AuthMode == EAuthType.SPN() {
return &azAuthBfsSPN{
return &azAuthDatalakeSPN{
azAuthSPN{
azAuthBase: base,
},
}
} else {
log.Crit("azAuth::getAzAuthBfs : Auth type %s not supported. Failed to create Auth object", config.AuthMode)
log.Crit("azAuth::getAzDatalakeAuth : Auth type %s not supported. Failed to create Auth object", config.AuthMode)
}
return nil
}
@ -171,3 +173,32 @@ func (base *azAuthBase) setOption(_, _ string) {}
func (base *azAuthBase) getEndpoint() string {
return base.config.Endpoint
}
// this type is included in OAuth modes - spn and msi
type azOAuthBase struct{}
// TODO:: track2 : check ActiveDirectoryEndpoint and AuthResource part
func (base *azOAuthBase) getAzIdentityClientOptions(config *azAuthConfig) azcore.ClientOptions {
if config == nil {
log.Err("azAuth::getAzIdentityClientOptions : azAuthConfig is nil")
return azcore.ClientOptions{}
}
opts := azcore.ClientOptions{
Cloud: getCloudConfiguration(config.Endpoint),
Logging: getSDKLogOptions(),
}
if config.ActiveDirectoryEndpoint != "" {
log.Debug("azAuthBase::getAzIdentityClientOptions : ActiveDirectoryAuthorityHost = %s", config.ActiveDirectoryEndpoint)
opts.Cloud.ActiveDirectoryAuthorityHost = config.ActiveDirectoryEndpoint
}
if config.AuthResource != "" {
if val, ok := opts.Cloud.Services[cloud.ResourceManager]; ok {
log.Debug("azAuthBase::getAzIdentityClientOptions : AuthResource = %s", config.AuthResource)
val.Endpoint = config.AuthResource
opts.Cloud.Services[cloud.ResourceManager] = val
}
}
return opts
}

Просмотреть файл

@ -458,7 +458,7 @@ func (suite *authTestSuite) TestBlockSasKeySetOption() {
assert.Fail("TestBlockSasKeySetOption : Failed to create Storage object")
}
stg.SetupPipeline()
stg.NewCredentialKey("saskey", storageTestConfigurationParameters.BlockSas)
stg.UpdateServiceClient("saskey", storageTestConfigurationParameters.BlockSas)
if err := stg.SetupPipeline(); err != nil {
assert.Fail("TestBlockSasKeySetOption : Failed to setup pipeline")
}
@ -591,7 +591,7 @@ func (suite *authTestSuite) TestAdlsSasKeySetOption() {
assert.Fail("TestBlockSasKeySetOption : Failed to create Storage object")
}
stg.SetupPipeline()
stg.NewCredentialKey("saskey", storageTestConfigurationParameters.AdlsSas)
stg.UpdateServiceClient("saskey", storageTestConfigurationParameters.AdlsSas)
if err := stg.SetupPipeline(); err != nil {
assert.Fail("TestBlockSasKeySetOption : Failed to setup pipeline")
}
@ -634,22 +634,23 @@ func (suite *authTestSuite) TestBlockMsiResId() {
}
}
func (suite *authTestSuite) TestBlockMsiObjId() {
defer suite.cleanupTest()
if !storageTestConfigurationParameters.SkipMsi {
stgConfig := AzStorageConfig{
container: storageTestConfigurationParameters.BlockContainer,
authConfig: azAuthConfig{
AuthMode: EAuthType.MSI(),
AccountType: EAccountType.BLOCK(),
AccountName: storageTestConfigurationParameters.BlockAccount,
ObjectID: storageTestConfigurationParameters.MsiObjId,
Endpoint: generateEndpoint(false, storageTestConfigurationParameters.BlockAccount, EAccountType.BLOCK()),
},
}
suite.validateStorageTest("TestBlockMsiObjId", stgConfig)
}
}
// ObjectID is not supported in msal. So, commenting this.
// func (suite *authTestSuite) TestBlockMsiObjId() {
// defer suite.cleanupTest()
// if !storageTestConfigurationParameters.SkipMsi {
// stgConfig := AzStorageConfig{
// container: storageTestConfigurationParameters.BlockContainer,
// authConfig: azAuthConfig{
// AuthMode: EAuthType.MSI(),
// AccountType: EAccountType.BLOCK(),
// AccountName: storageTestConfigurationParameters.BlockAccount,
// ObjectID: storageTestConfigurationParameters.MsiObjId,
// Endpoint: generateEndpoint(false, storageTestConfigurationParameters.BlockAccount, EAccountType.BLOCK()),
// },
// }
// suite.validateStorageTest("TestBlockMsiObjId", stgConfig)
// }
// }
// Can't use HTTP requests with MSI/SPN credentials
func (suite *authTestSuite) TestAdlsMsiAppId() {

Просмотреть файл

@ -34,15 +34,18 @@
package azstorage
import (
"github.com/Azure/azure-storage-fuse/v2/common/log"
"errors"
"github.com/Azure/azure-storage-azcopy/v10/azbfs"
"github.com/Azure/azure-storage-blob-go/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/service"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake"
serviceBfs "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/service"
"github.com/Azure/azure-storage-fuse/v2/common/log"
)
// Verify that the Auth implement the correct AzAuth interfaces
var _ azAuth = &azAuthBlobKey{}
var _ azAuth = &azAuthBfsKey{}
var _ azAuth = &azAuthDatalakeKey{}
type azAuthKey struct {
azAuthBase
@ -52,38 +55,48 @@ type azAuthBlobKey struct {
azAuthKey
}
// GetCredential : Gets shared key based storage credentials for blob
func (azkey *azAuthBlobKey) getCredential() interface{} {
// getServiceClient : returns shared key based service client for blob
func (azkey *azAuthBlobKey) getServiceClient(stConfig *AzStorageConfig) (interface{}, error) {
if azkey.config.AccountKey == "" {
log.Err("azAuthBlobKey::getCredential : Shared key for account is empty, cannot authenticate user")
return nil
log.Err("azAuthBlobKey::getServiceClient : Shared key for account is empty, cannot authenticate user")
return nil, errors.New("shared key for account is empty, cannot authenticate user")
}
credential, err := azblob.NewSharedKeyCredential(
azkey.config.AccountName,
azkey.config.AccountKey)
cred, err := azblob.NewSharedKeyCredential(azkey.config.AccountName, azkey.config.AccountKey)
if err != nil {
log.Err("azAuthBlobKey::getCredential : Failed to create shared key credentials")
return nil
log.Err("azAuthBlobKey::getServiceClient : Failed to create shared key credential [%s]", err.Error())
return nil, err
}
return credential
svcClient, err := service.NewClientWithSharedKeyCredential(azkey.config.Endpoint, cred, getAzBlobServiceClientOptions(stConfig))
if err != nil {
log.Err("azAuthBlobKey::getServiceClient : Failed to create service client [%s]", err.Error())
}
return svcClient, err
}
type azAuthBfsKey struct {
type azAuthDatalakeKey struct {
azAuthKey
}
// GetCredential : Gets shared key based storage credentials for datalake
func (azkey *azAuthBfsKey) getCredential() interface{} {
// getServiceClient : returns shared key based service client for datalake
func (azkey *azAuthDatalakeKey) getServiceClient(stConfig *AzStorageConfig) (interface{}, error) {
if azkey.config.AccountKey == "" {
log.Err("azAuthBfsKey::getCredential : Shared key for account is empty, cannot authenticate user")
return nil
log.Err("azAuthDatalakeKey::getServiceClient : Shared key for account is empty, cannot authenticate user")
return nil, errors.New("shared key for account is empty, cannot authenticate user")
}
credential := azbfs.NewSharedKeyCredential(
azkey.config.AccountName,
azkey.config.AccountKey)
cred, err := azdatalake.NewSharedKeyCredential(azkey.config.AccountName, azkey.config.AccountKey)
if err != nil {
log.Err("azAuthDatalakeKey::getServiceClient : Failed to create shared key credential [%s]", err.Error())
return nil, err
}
return credential
svcClient, err := serviceBfs.NewClientWithSharedKeyCredential(azkey.config.Endpoint, cred, getAzDatalakeServiceClientOptions(stConfig))
if err != nil {
log.Err("azAuthDatalakeKey::getServiceClient : Failed to create service client [%s]", err.Error())
}
return svcClient, err
}

Просмотреть файл

@ -34,331 +34,76 @@
package azstorage
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"math/rand"
"os"
"os/exec"
"strconv"
"strings"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/service"
serviceBfs "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/service"
"github.com/Azure/azure-storage-fuse/v2/common/log"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/azure-storage-azcopy/v10/azbfs"
"github.com/Azure/azure-storage-azcopy/v10/common"
"github.com/Azure/azure-storage-blob-go/azblob"
)
// Verify that the Auth implement the correct AzAuth interfaces
var _ azAuth = &azAuthBlobMSI{}
var _ azAuth = &azAuthBfsMSI{}
var _ azAuth = &azAuthDatalakeMSI{}
type azAuthMSI struct {
azAuthBase
azOAuthBase
}
func getNextExpiryTimer(token *adal.Token) time.Duration {
delay := time.Duration(5+rand.Intn(120)) * time.Second
return time.Until(token.Expires()) - delay
}
func (azmsi *azAuthMSI) getTokenCredential() (azcore.TokenCredential, error) {
opts := azmsi.getAzIdentityClientOptions(&azmsi.config)
// fetchToken : Generates a token based on the config
func (azmsi *azAuthMSI) fetchToken(endpoint string) (*common.OAuthTokenInfo, error) {
// Resource string is fixed and has no relation with any of the user inputs
// This is not the resource URL, rather a way to identify the resource type and tenant
// There are two options in the structure datalake and storage but datalake is not populated
// and does not work in all types of clouds (US, German, China etc).
// resource := azure.PublicCloud.ResourceIdentifiers.Datalake
// resource := azure.PublicCloud.ResourceIdentifiers.Storage
oAuthTokenInfo := &common.OAuthTokenInfo{
Identity: true,
IdentityInfo: common.IdentityInfo{
ClientID: azmsi.config.ApplicationID,
ObjectID: azmsi.config.ObjectID,
MSIResID: azmsi.config.ResourceID},
ActiveDirectoryEndpoint: endpoint,
msiOpts := &azidentity.ManagedIdentityCredentialOptions{
ClientOptions: opts,
}
token, err := oAuthTokenInfo.GetNewTokenFromMSI(context.Background())
if err != nil {
return nil, err
}
oAuthTokenInfo.Token = *token
return oAuthTokenInfo, nil
}
// fetchTokenFromCLI : Generates a token using the Az Cli
func (azmsi *azAuthMSI) fetchTokenFromCLI() (*common.OAuthTokenInfo, error) {
resource := "https://storage.azure.com"
if azmsi.config.AuthResource != "" {
resource = azmsi.config.AuthResource
// TODO:: track2 : check for ObjectID
if azmsi.config.ApplicationID != "" {
msiOpts.ID = (azidentity.ClientID)(azmsi.config.ApplicationID)
} else if azmsi.config.ResourceID != "" {
msiOpts.ID = (azidentity.ResourceID)(azmsi.config.ResourceID)
}
commandLine := "az account get-access-token -o json --resource " + resource
if azmsi.config.TenantID != "" {
commandLine += " --tenant " + azmsi.config.TenantID
}
cliCmd := exec.CommandContext(context.Background(), "/bin/sh", "-c", commandLine)
cliCmd.Dir = "/bin"
cliCmd.Env = os.Environ()
var stderr bytes.Buffer
cliCmd.Stderr = &stderr
output, err := cliCmd.Output()
if err != nil {
msg := stderr.String()
var exErr *exec.ExitError
if errors.As(err, &exErr) && exErr.ExitCode() == 127 || strings.HasPrefix(msg, "'az' is not recognized") {
msg = "Azure CLI not found on path"
}
if msg == "" {
msg = err.Error()
}
return nil, fmt.Errorf(msg)
}
log.Info("azAuthMSI::fetchTokenFromCLI : Successfully fetched token from Azure CLI")
log.Debug("azAuthMSI::fetchTokenFromCLI : Token: %s", output)
t := struct {
AccessToken string `json:"accessToken"`
Authority string `json:"_authority"`
ClientID string `json:"_clientId"`
ExpiresOn string `json:"expiresOn"`
IdentityProvider string `json:"identityProvider"`
IsMRRT bool `json:"isMRRT"`
RefreshToken string `json:"refreshToken"`
Resource string `json:"resource"`
TokenType string `json:"tokenType"`
UserID string `json:"userId"`
}{}
err = json.Unmarshal(output, &t)
if err != nil {
return nil, err
}
// the Azure CLI's "expiresOn" is local time
expiresOn, err := time.ParseInLocation("2006-01-02 15:04:05.999999", t.ExpiresOn, time.Local)
if err != nil {
return nil, fmt.Errorf("error parsing token expiration time %q: %v", t.ExpiresOn, err)
}
tokenInfo := &common.OAuthTokenInfo{
Token: adal.Token{
AccessToken: t.AccessToken,
RefreshToken: t.RefreshToken,
ExpiresOn: json.Number(strconv.FormatInt(expiresOn.Unix(), 10)),
Resource: t.Resource,
Type: t.TokenType,
},
}
return tokenInfo, nil
cred, err := azidentity.NewManagedIdentityCredential(msiOpts)
return cred, err
}
type azAuthBlobMSI struct {
azAuthMSI
}
// GetCredential : Get MSI based credentials for blob
func (azmsi *azAuthBlobMSI) getCredential() interface{} {
// Generate the token based on configured inputs
var token *common.OAuthTokenInfo = nil
var err error = nil
norefresh := false
msi_endpoint := os.Getenv("MSI_ENDPOINT")
if strings.Contains(msi_endpoint, "127.0.0.1:") || strings.Contains(msi_endpoint, "localhost:") ||
strings.Contains(azmsi.config.ActiveDirectoryEndpoint, "127.0.0.1:") {
// this might be AML workspace so try to get token using CLI
log.Info("azAuthBlobMSI::getCredential : Potential AML workspace detected")
token, err = azmsi.fetchTokenFromCLI()
if err != nil {
log.Err("azAuthBlobMSI::getCredential : %s", err.Error())
} else if token != nil {
norefresh = true
}
}
if token == nil {
log.Debug("azAuthBlobMSI::getCredential : Going for conventional fetchToken. MSI Endpoint : %s", msi_endpoint)
token, err = azmsi.fetchToken(msi_endpoint)
if token == nil {
log.Debug("azAuthBlobMSI::getCredential : Going for conventional fetchToken without endpoint")
token, err = azmsi.fetchToken("")
}
}
// getServiceClient : returns MSI based service client for blob
func (azmsi *azAuthBlobMSI) getServiceClient(stConfig *AzStorageConfig) (interface{}, error) {
cred, err := azmsi.getTokenCredential()
if err != nil {
// fmt.Println(token.AccessToken)
log.Err("azAuthBlobMSI::getCredential : Failed to get credential [%s]", err.Error())
return nil
log.Err("azAuthBlobMSI::getServiceClient : Failed to get token credential from MSI [%s]", err.Error())
return nil, err
}
var tc azblob.TokenCredential
if norefresh {
log.Info("azAuthBlobMSI::getCredential : MSI Token over CLI retrieved")
log.Debug("azAuthBlobMSI::getCredential : Token: %s (%s)", token.AccessToken, token.Expires())
// We are running in cli mode so token can not be refreshed, on expiry just get the new token
tc = azblob.NewTokenCredential(token.AccessToken, func(tc azblob.TokenCredential) time.Duration {
for failCount := 0; failCount < 5; failCount++ {
newToken, err := azmsi.fetchTokenFromCLI()
if err != nil {
log.Err("azAuthBlobMSI::getCredential : Failed to refresh token attempt %d [%s]", failCount, err.Error())
time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
continue
}
// set the new token value
tc.SetToken(newToken.AccessToken)
log.Info("azAuthBlobMSI::getCredential : New MSI Token over CLI retrieved")
log.Debug("azAuthBlobMSI::getCredential : New Token: %s (%s)", newToken.AccessToken, newToken.Expires())
// Get the next token slightly before the current one expires
return getNextExpiryTimer(&newToken.Token)
}
log.Err("azAuthBlobMSI::getCredential : Failed to refresh token bailing out.")
return 0
})
} else {
log.Info("azAuthBlobMSI::getCredential : MSI Token retrieved")
log.Debug("azAuthBlobMSI::getCredential : Token: %s (%s)", token.AccessToken, token.Expires())
// Using token create the credential object, here also register a call back which refreshes the token
tc = azblob.NewTokenCredential(token.AccessToken, func(tc azblob.TokenCredential) time.Duration {
// token, err := azmsi.fetchToken(msi_endpoint)
// if err != nil {
// log.Err("azAuthBlobMSI::getCredential : Failed to fetch token [%s]", err.Error())
// return 0
// }
for failCount := 0; failCount < 5; failCount++ {
newToken, err := token.Refresh(context.Background())
if err != nil {
log.Err("azAuthBlobMSI::getCredential : Failed to refresh token attempt %d [%s]", failCount, err.Error())
time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
continue
}
// set the new token value
tc.SetToken(newToken.AccessToken)
log.Info("azAuthBlobMSI::getCredential : New MSI Token retrieved")
log.Debug("azAuthBlobMSI::getCredential : New Token: %s (%s)", newToken.AccessToken, newToken.Expires())
// Get the next token slightly before the current one expires
return getNextExpiryTimer(newToken)
}
log.Err("azAuthBlobMSI::getCredential : Failed to refresh token bailing out.")
return 0
})
svcClient, err := service.NewClient(azmsi.config.Endpoint, cred, getAzBlobServiceClientOptions(stConfig))
if err != nil {
log.Err("azAuthBlobMSI::getServiceClient : Failed to create service client [%s]", err.Error())
}
return tc
return svcClient, err
}
type azAuthBfsMSI struct {
type azAuthDatalakeMSI struct {
azAuthMSI
}
// GetCredential : Get MSI based credentials for datalake
func (azmsi *azAuthBfsMSI) getCredential() interface{} {
// Generate the token based on configured inputs
var token *common.OAuthTokenInfo = nil
var err error = nil
norefresh := false
msi_endpoint := os.Getenv("MSI_ENDPOINT")
log.Info("azAuthBfsMSI::getCredential : MSI_ENDPOINT = %v", msi_endpoint)
if strings.Contains(msi_endpoint, "127.0.0.1:") || strings.Contains(msi_endpoint, "localhost:") ||
strings.Contains(azmsi.config.ActiveDirectoryEndpoint, "127.0.0.1:") {
// this might be AML workspace so try to get token using CLI
log.Info("azAuthBfsMSI::getCredential : Potential AML workspace detected")
token, err = azmsi.fetchTokenFromCLI()
if err != nil {
log.Err("azAuthBfsMSI::getCredential : %s", err.Error())
} else if token != nil {
norefresh = true
}
}
if token == nil {
log.Debug("azAuthBfsMSI::getCredential : Going for conventional fetchToken. MSI Endpoint : %s", msi_endpoint)
token, err = azmsi.fetchToken(msi_endpoint)
if token == nil {
log.Debug("azAuthBfsMSI::getCredential : Going for conventional fetchToken without endpoint")
token, err = azmsi.fetchToken("")
}
}
// getServiceClient : returns MSI based service client for datalake
func (azmsi *azAuthDatalakeMSI) getServiceClient(stConfig *AzStorageConfig) (interface{}, error) {
cred, err := azmsi.getTokenCredential()
if err != nil {
// fmt.Println(token.AccessToken)
log.Err("azAuthBfsMSI::getCredential : Failed to get credential [%s]", err.Error())
return nil
log.Err("azAuthDatalakeMSI::getServiceClient : Failed to get token credential from MSI [%s]", err.Error())
return nil, err
}
var tc azbfs.TokenCredential
if norefresh {
log.Info("azAuthBfsMSI::getCredential : MSI Token over CLI retrieved")
log.Debug("azAuthBfsMSI::getCredential : Token: %s (%s)", token.AccessToken, token.Expires())
// We are running in cli mode so token can not be refreshed, on expiry just get the new token
tc = azbfs.NewTokenCredential(token.AccessToken, func(tc azbfs.TokenCredential) time.Duration {
for failCount := 0; failCount < 5; failCount++ {
newToken, err := azmsi.fetchTokenFromCLI()
if err != nil {
log.Err("azAuthBfsMSI::getCredential : Failed to refresh token attempt %d [%s]", failCount, err.Error())
time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
continue
}
// set the new token value
tc.SetToken(newToken.AccessToken)
log.Info("azAuthBfsMSI::getCredential : New MSI Token over CLI retrieved")
log.Debug("azAuthBfsMSI::getCredential : New Token: %s (%s)", newToken.AccessToken, newToken.Expires())
// Get the next token slightly before the current one expires
return getNextExpiryTimer(&newToken.Token)
}
log.Err("azAuthBfsMSI::getCredential : Failed to refresh token bailing out.")
return 0
})
} else {
log.Info("azAuthBfsMSI::getCredential : MSI Token retrieved")
log.Debug("azAuthBfsMSI::getCredential : Token: %s (%s)", token.AccessToken, token.Expires())
// Using token create the credential object, here also register a call back which refreshes the token
tc = azbfs.NewTokenCredential(token.AccessToken, func(tc azbfs.TokenCredential) time.Duration {
// token, err := azmsi.fetchToken(msi_endpoint)
// if err != nil {
// log.Err("azAuthBfsMSI::getCredential : Failed to fetch token [%s]", err.Error())
// return 0
// }
for failCount := 0; failCount < 5; failCount++ {
newToken, err := token.Refresh(context.Background())
if err != nil {
log.Err("azAuthBfsMSI::getCredential : Failed to refresh token attempt %d [%s]", failCount, err.Error())
time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
continue
}
// set the new token value
tc.SetToken(newToken.AccessToken)
log.Info("azAuthBfsMSI::getCredential : New MSI Token retrieved")
log.Debug("azAuthBfsMSI::getCredential : New Token: %s (%s)", newToken.AccessToken, newToken.Expires())
// Get the next token slightly before the current one expires
return getNextExpiryTimer(newToken)
}
log.Err("azAuthBfsMSI::getCredential : Failed to refresh token bailing out.")
return 0
})
svcClient, err := serviceBfs.NewClient(azmsi.config.Endpoint, cred, getAzDatalakeServiceClientOptions(stConfig))
if err != nil {
log.Err("azAuthDatalakeMSI::getServiceClient : Failed to create service client [%s]", err.Error())
}
return tc
return svcClient, err
}

Просмотреть файл

@ -34,29 +34,22 @@
package azstorage
import (
"fmt"
"errors"
"strings"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/service"
serviceBfs "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/service"
"github.com/Azure/azure-storage-fuse/v2/common/log"
"github.com/Azure/azure-storage-azcopy/v10/azbfs"
"github.com/Azure/azure-storage-blob-go/azblob"
)
// Verify that the Auth implement the correct AzAuth interfaces
var _ azAuth = &azAuthBlobSAS{}
var _ azAuth = &azAuthBfsSAS{}
var _ azAuth = &azAuthDatalakeSAS{}
type azAuthSAS struct {
azAuthBase
}
// GetEndpoint : Gets the SAS endpoint
func (azsas *azAuthSAS) getEndpoint() string {
return fmt.Sprintf("%s%s",
azsas.config.Endpoint,
azsas.config.SASKey)
}
// SetOption : Sets the sas key information for the SAS auth.
func (azsas *azAuthSAS) setOption(key, value string) {
if key == "saskey" {
@ -64,30 +57,45 @@ func (azsas *azAuthSAS) setOption(key, value string) {
}
}
// GetEndpoint : Gets the SAS endpoint
func (azsas *azAuthSAS) getEndpoint() string {
return azsas.config.Endpoint + "?" + strings.TrimLeft(azsas.config.SASKey, "?")
}
type azAuthBlobSAS struct {
azAuthSAS
}
// GetCredential : Gets SAS based credentials for blob
func (azsas *azAuthBlobSAS) getCredential() interface{} {
// getServiceClient : returns SAS based service client for blob
func (azsas *azAuthBlobSAS) getServiceClient(stConfig *AzStorageConfig) (interface{}, error) {
if azsas.config.SASKey == "" {
log.Err("azAuthBlobSAS::getCredential : SAS key for account is empty, cannot authenticate user")
return nil
log.Err("azAuthBlobSAS::getServiceClient : SAS key for account is empty, cannot authenticate user")
return nil, errors.New("sas key for account is empty, cannot authenticate user")
}
return azblob.NewAnonymousCredential()
svcClient, err := service.NewClientWithNoCredential(azsas.getEndpoint(), getAzBlobServiceClientOptions(stConfig))
if err != nil {
log.Err("azAuthBlobSAS::getServiceClient : Failed to create service client [%s]", err.Error())
}
return svcClient, err
}
type azAuthBfsSAS struct {
type azAuthDatalakeSAS struct {
azAuthSAS
}
// GetCredential : Gets SAS based credentials for datralake
func (azsas *azAuthBfsSAS) getCredential() interface{} {
// getServiceClient : returns SAS based service client for datalake
func (azsas *azAuthDatalakeSAS) getServiceClient(stConfig *AzStorageConfig) (interface{}, error) {
if azsas.config.SASKey == "" {
log.Err("azAuthBfsSAS::getCredential : SAS key for account is empty, cannot authenticate user")
return nil
log.Err("azAuthDatalakeSAS::getServiceClient : SAS key for account is empty, cannot authenticate user")
return nil, errors.New("sas key for account is empty, cannot authenticate user")
}
return azbfs.NewAnonymousCredential()
svcClient, err := serviceBfs.NewClientWithNoCredential(azsas.getEndpoint(), getAzDatalakeServiceClientOptions(stConfig))
if err != nil {
log.Err("azAuthDatalakeSAS::getServiceClient : Failed to create service client [%s]", err.Error())
}
return svcClient, err
}

Просмотреть файл

@ -34,170 +34,92 @@
package azstorage
import (
"fmt"
"math/rand"
"os"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/service"
serviceBfs "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/service"
"github.com/Azure/azure-storage-fuse/v2/common/log"
"github.com/Azure/azure-storage-azcopy/v10/azbfs"
"github.com/Azure/azure-storage-blob-go/azblob"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/go-autorest/autorest/azure"
)
// Verify that the Auth implement the correct AzAuth interfaces
var _ azAuth = &azAuthBlobSPN{}
var _ azAuth = &azAuthBfsSPN{}
var _ azAuth = &azAuthDatalakeSPN{}
type azAuthSPN struct {
azAuthBase
azOAuthBase
}
func getNextExpiryTimerSPN(spt *adal.ServicePrincipalToken) time.Duration {
delay := time.Duration(5+rand.Intn(120)) * time.Second
return time.Until(spt.Token().Expires()) - delay
}
func (azspn *azAuthSPN) getTokenCredential() (azcore.TokenCredential, error) {
var cred azcore.TokenCredential
var err error
func (azspn *azAuthSPN) getAADEndpoint() string {
if azspn.config.ActiveDirectoryEndpoint != "" {
return azspn.config.ActiveDirectoryEndpoint
}
return azure.PublicCloud.ActiveDirectoryEndpoint
}
// fetchToken : Generates a token based on the config
func (azspn *azAuthSPN) fetchToken() (*adal.ServicePrincipalToken, error) {
// Use the configured AAD endpoint for token generation
config, err := adal.NewOAuthConfig(azspn.getAADEndpoint(), azspn.config.TenantID)
if err != nil {
log.Err("AzAuthSPN::fetchToken : Failed to generate OAuth Config for SPN [%s]", err.Error())
return nil, err
}
// Create the resource URL
resourceURL := azspn.config.AuthResource
if resourceURL == "" {
resourceURL = azspn.getEndpoint()
}
// Generate the SPN token
var spt *adal.ServicePrincipalToken
clOpts := azspn.getAzIdentityClientOptions(&azspn.config)
if azspn.config.OAuthTokenFilePath != "" {
log.Trace("AzAuthSPN::fetchToken : Going for fedrated token flow.")
log.Trace("AzAuthSPN::getTokenCredential : Going for fedrated token flow")
tokenReader := func() (string, error) {
token, err := os.ReadFile(azspn.config.OAuthTokenFilePath)
if err != nil {
return "", fmt.Errorf("failed to read OAuth token file %s [%v]", azspn.config.OAuthTokenFilePath, err.Error())
}
return string(token), nil
}
spt, err = adal.NewServicePrincipalTokenFromFederatedTokenCallback(*config, azspn.config.ClientID, tokenReader, resourceURL)
// TODO:: track2 : test this in Azure Kubernetes setup
cred, err = azidentity.NewWorkloadIdentityCredential(&azidentity.WorkloadIdentityCredentialOptions{
ClientOptions: clOpts,
ClientID: azspn.config.ClientID,
TenantID: azspn.config.TenantID,
TokenFilePath: azspn.config.OAuthTokenFilePath,
})
if err != nil {
log.Err("AzAuthSPN::fetchToken : Failed to generate token for SPN [%s]", err.Error())
log.Err("AzAuthSPN::getTokenCredential : Failed to generate token for SPN [%s]", err.Error())
return nil, err
}
} else {
spt, err = adal.NewServicePrincipalToken(*config, azspn.config.ClientID, azspn.config.ClientSecret, resourceURL)
log.Trace("AzAuthSPN::getTokenCredential : Using client secret for fetching token")
cred, err = azidentity.NewClientSecretCredential(azspn.config.TenantID, azspn.config.ClientID, azspn.config.ClientSecret, &azidentity.ClientSecretCredentialOptions{
ClientOptions: clOpts,
})
if err != nil {
log.Err("AzAuthSPN::fetchToken : Failed to generate token for SPN [%s]", err.Error())
log.Err("AzAuthSPN::getTokenCredential : Failed to generate token for SPN [%s]", err.Error())
return nil, err
}
}
return spt, nil
return cred, err
}
type azAuthBlobSPN struct {
azAuthSPN
}
// GetCredential : Get SPN based credentials for blob
func (azspn *azAuthBlobSPN) getCredential() interface{} {
spt, err := azspn.fetchToken()
// getServiceClient : returns SPN based service client for blob
func (azspn *azAuthBlobSPN) getServiceClient(stConfig *AzStorageConfig) (interface{}, error) {
cred, err := azspn.getTokenCredential()
if err != nil {
log.Err("azAuthBlobSPN::getCredential : Failed to fetch token for SPN [%s]", err.Error())
return nil
log.Err("azAuthBlobSPN::getServiceClient : Failed to get token credential from SPN [%s]", err.Error())
return nil, err
}
// Using token create the credential object, here also register a call back which refreshes the token
tc := azblob.NewTokenCredential(spt.Token().AccessToken, func(tc azblob.TokenCredential) time.Duration {
// spt, err = azspn.fetchToken()
// if err != nil {
// log.Err("azAuthBlobSPN::getCredential : Failed to fetch SPN token [%s]", err.Error())
// return 0
// }
for failCount := 0; failCount < 5; failCount++ {
err = spt.Refresh()
if err != nil {
log.Err("azAuthBfsSPN::getCredential : Failed to refresh token attempt %d [%s]", failCount, err.Error())
time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
continue
}
svcClient, err := service.NewClient(azspn.config.Endpoint, cred, getAzBlobServiceClientOptions(stConfig))
if err != nil {
log.Err("azAuthBlobSPN::getServiceClient : Failed to create service client [%s]", err.Error())
}
// set the new token value
tc.SetToken(spt.Token().AccessToken)
log.Info("azAuthBlobSPN::getCredential : SPN Token retrieved")
log.Debug("azAuthBlobSPN::getCredential : Token: %s (%s)", spt.Token().AccessToken, spt.Token().Expires())
// Get the next token slightly before the current one expires
return getNextExpiryTimerSPN(spt)
// Test code to expire token every 30 seconds
// return time.Until(time.Now()) + 30*time.Second
}
log.Err("azAuthBfsSPN::getCredential : Failed to refresh token bailing out.")
return 0
})
return tc
return svcClient, err
}
type azAuthBfsSPN struct {
type azAuthDatalakeSPN struct {
azAuthSPN
}
// GetCredential : Get SPN based credentials for datalake
func (azspn *azAuthBfsSPN) getCredential() interface{} {
spt, err := azspn.fetchToken()
// getServiceClient : returns SPN based service client for datalake
func (azspn *azAuthDatalakeSPN) getServiceClient(stConfig *AzStorageConfig) (interface{}, error) {
cred, err := azspn.getTokenCredential()
if err != nil {
log.Err("azAuthBfsSPN::getCredential : Failed to fetch token for SPN [%s]", err.Error())
return nil
log.Err("azAuthDatalakeSPN::getServiceClient : Failed to get token credential from SPN [%s]", err.Error())
return nil, err
}
// Using token create the credential object, here also register a call back which refreshes the token
tc := azbfs.NewTokenCredential(spt.Token().AccessToken, func(tc azbfs.TokenCredential) time.Duration {
// spt, err = azspn.fetchToken()
// if err != nil {
// log.Err("azAuthBfsSPN::getCredential : Failed to fetch SPN token [%s]", err.Error())
// return 0
// }
for failCount := 0; failCount < 5; failCount++ {
err = spt.Refresh()
if err != nil {
log.Err("azAuthBfsSPN::getCredential : Failed to refresh token attempt %d [%s]", failCount, err.Error())
time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
continue
}
svcClient, err := serviceBfs.NewClient(azspn.config.Endpoint, cred, getAzDatalakeServiceClientOptions(stConfig))
if err != nil {
log.Err("azAuthDatalakeSPN::getServiceClient : Failed to create service client [%s]", err.Error())
}
// set the new token value
tc.SetToken(spt.Token().AccessToken)
log.Info("azAuthBfsSPN::getCredential : SPN Token retrieved")
log.Debug("azAuthBfsSPN::getCredential : Token: %s (%s)", spt.Token().AccessToken, spt.Token().Expires())
// Get the next token slightly before the current one expires
return getNextExpiryTimerSPN(spt)
// Test code to expire token every 30 seconds
// return time.Until(time.Now()) + 30*time.Second
}
log.Err("azAuthBfsSPN::getCredential : Failed to refresh token bailing out.")
return 0
})
return tc
return svcClient, err
}

Просмотреть файл

@ -40,7 +40,7 @@ import (
"syscall"
"time"
azcopyCommon "github.com/Azure/azure-storage-azcopy/v10/common"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-storage-fuse/v2/common"
"github.com/Azure/azure-storage-fuse/v2/common/config"
"github.com/Azure/azure-storage-fuse/v2/common/log"
@ -131,6 +131,9 @@ func (az *AzStorage) OnConfigChange() {
log.Err("AzStorage::OnConfigChange : failed to UpdateConfig", err.Error())
return
}
// dynamic update of the sdk log listener
setSDKLogListener()
}
func (az *AzStorage) configureAndTest(isParent bool) error {
@ -142,6 +145,9 @@ func (az *AzStorage) configureAndTest(isParent bool) error {
return err
}
// set SDK log listener to log the requests and responses
setSDKLogListener()
err = az.storage.SetPrefixPath(az.stConfig.prefixPath)
if err != nil {
log.Err("AzStorage::configureAndTest : Failed to set prefix path [%s]", err.Error())
@ -170,11 +176,6 @@ func (az *AzStorage) Start(ctx context.Context) error {
// create stats collector for azstorage
azStatsCollector = stats_manager.NewStatsCollector(az.Name())
// This is a workaround right now to disable the input watcher thread which continuously monitors below config to change
// Running this thread continuously increases the CPU usage by 5% even when there is no activity on blobfuse2 mount path
// Lifecycle manager init is commented in the "blobfuse2-cpu-usage" branch. Blobfuse2 imports azcopy from this branch.
azcopyCommon.GetLifecycleMgr().EnableInputWatcher()
return nil
}
@ -304,7 +305,9 @@ func (az *AzStorage) StreamDir(options internal.StreamDirOptions) ([]*internal.O
log.Debug("AzStorage::StreamDir : Retrieved %d objects with %s marker for Path %s", len(new_list), options.Token, path)
if new_marker != nil && *new_marker != "" {
if new_marker == nil {
new_marker = to.Ptr("")
} else if *new_marker != "" {
log.Debug("AzStorage::StreamDir : next-marker %s for Path %s", *new_marker, path)
if len(new_list) == 0 {
/* In some customer scenario we have seen that new_list is empty but marker is not empty
@ -570,7 +573,7 @@ func NewazstorageComponent() internal.Component {
stConfig: AzStorageConfig{
blockSize: 0,
maxConcurrency: 32,
defaultTier: getAccessTierType("none"),
defaultTier: getAccessTierType(""),
authConfig: azAuthConfig{
AuthMode: EAuthType.KEY(),
UseHTTP: false,

Просмотреть файл

@ -60,3 +60,18 @@ const (
size = "Size"
target = "Target"
)
// headers which should be logged and not redacted
var allowedHeaders []string = []string{
"x-ms-version", "x-ms-date", "x-ms-range", "x-ms-delete-snapshots", "x-ms-delete-type-permanent", "x-ms-blob-content-type",
"x-ms-blob-type", "x-ms-copy-source", "x-ms-copy-id", "x-ms-copy-status", "x-ms-access-tier", "x-ms-creation-time", "x-ms-copy-progress",
"x-ms-access-tier-inferred", "x-ms-acl", "x-ms-group", "x-ms-lease-state", "x-ms-owner", "x-ms-permissions", "x-ms-resource-type", "x-ms-content-crc64",
"x-ms-rename-source", "accept-ranges", "x-ms-continuation",
}
// query parameters which should be logged and not redacted
var allowedQueryParams []string = []string{
"comp", "delimiter", "include", "marker", "maxresults", "prefix", "restype", "blockid", "blocklisttype",
"directory", "recursive", "resource", "se", "sp", "spr", "srt", "ss", "st", "sv", "action", "continuation", "mode",
"client_id", "authorization_endpoint",
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -39,10 +39,10 @@ import (
"reflect"
"strings"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob"
"github.com/Azure/azure-storage-fuse/v2/common/config"
"github.com/Azure/azure-storage-fuse/v2/common/log"
"github.com/Azure/azure-storage-blob-go/azblob"
"github.com/JeffreyRichter/enum/enum"
)
@ -170,7 +170,6 @@ type AzStorageOptions struct {
MaxRetryDelay int32 `config:"max-retry-delay-sec" yaml:"max-retry-delay-sec,omitempty"`
HttpProxyAddress string `config:"http-proxy" yaml:"http-proxy,omitempty"`
HttpsProxyAddress string `config:"https-proxy" yaml:"https-proxy,omitempty"`
SdkTrace bool `config:"sdk-trace" yaml:"sdk-trace,omitempty"`
FailUnsupportedOp bool `config:"fail-unsupported-op" yaml:"fail-unsupported-op,omitempty"`
AuthResourceString string `config:"auth-resource" yaml:"auth-resource,omitempty"`
UpdateMD5 bool `config:"update-md5" yaml:"update-md5"`
@ -326,8 +325,8 @@ func ParseAndValidateConfig(az *AzStorage, opt AzStorageOptions) error {
}
if opt.BlockSize != 0 {
if opt.BlockSize > azblob.BlockBlobMaxStageBlockBytes {
log.Err("ParseAndValidateConfig : Block size is too large. Block size has to be smaller than %s Bytes", azblob.BlockBlobMaxStageBlockBytes)
if opt.BlockSize > blockblob.MaxStageBlockBytes {
log.Err("ParseAndValidateConfig : Block size is too large. Block size has to be smaller than %s Bytes", blockblob.MaxStageBlockBytes)
return errors.New("block size is too large")
}
az.stConfig.blockSize = opt.BlockSize * 1024 * 1024
@ -406,10 +405,6 @@ func ParseAndValidateConfig(az *AzStorage, opt AzStorageOptions) error {
}
log.Info("ParseAndValidateConfig : using the following proxy address from the config file: %s", az.stConfig.proxyAddress)
az.stConfig.sdkTrace = opt.SdkTrace
log.Info("ParseAndValidateConfig : sdk logging from the config file: %t", az.stConfig.sdkTrace)
err = ParseAndReadDynamicConfig(az, opt, false)
if err != nil {
return err
@ -585,9 +580,9 @@ func ParseAndReadDynamicConfig(az *AzStorage, opt AzStorageOptions, reload bool)
if reload {
log.Info("ParseAndReadDynamicConfig : SAS Key updated")
if err := az.storage.NewCredentialKey("saskey", az.stConfig.authConfig.SASKey); err != nil {
if err := az.storage.UpdateServiceClient("saskey", az.stConfig.authConfig.SASKey); err != nil {
az.stConfig.authConfig.SASKey = oldSas
_ = az.storage.NewCredentialKey("saskey", az.stConfig.authConfig.SASKey)
_ = az.storage.UpdateServiceClient("saskey", az.stConfig.authConfig.SASKey)
return errors.New("SAS key update failure")
}
}

Просмотреть файл

@ -36,7 +36,7 @@ package azstorage
import (
"testing"
"github.com/Azure/azure-storage-blob-go/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob"
"github.com/Azure/azure-storage-fuse/v2/common"
"github.com/Azure/azure-storage-fuse/v2/common/config"
"github.com/Azure/azure-storage-fuse/v2/common/log"
@ -129,7 +129,7 @@ func (s *configTestSuite) TestBlockSize() {
assert.NotNil(err)
assert.Equal(az.stConfig.blockSize, opt.BlockSize*1024*1024)
opt.BlockSize = azblob.BlockBlobMaxStageBlockBytes + 1
opt.BlockSize = blockblob.MaxStageBlockBytes + 1
err = ParseAndValidateConfig(az, opt)
assert.NotNil(err)
assert.Contains(err.Error(), "block size is too large")
@ -385,7 +385,7 @@ func (s *configTestSuite) TestCompressionType() {
}
func (s *configTestSuite) TestInvalidSASRefresh() {
func (s *configTestSuite) TestSASRefresh() {
defer config.ResetConfig()
assert := assert.New(s.T())
az := &AzStorage{}
@ -409,8 +409,7 @@ func (s *configTestSuite) TestInvalidSASRefresh() {
az.storage = &BlockBlob{Auth: &azAuthBlobSAS{azAuthSAS: azAuthSAS{azAuthBase: azAuthBase{config: azAuthConfig{Endpoint: "abcd:://qreq!@#$%^&*()_)(*&^%$#"}}}}}
err := ParseAndReadDynamicConfig(az, opt, true)
assert.NotNil(err)
assert.Equal(err.Error(), "SAS key update failure")
assert.Nil(err)
}
func TestConfigTestSuite(t *testing.T) {

Просмотреть файл

@ -34,19 +34,16 @@
package azstorage
import (
"net/url"
"os"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/Azure/azure-storage-fuse/v2/common"
"github.com/Azure/azure-storage-fuse/v2/common/log"
"github.com/Azure/azure-storage-fuse/v2/internal"
"github.com/Azure/azure-pipeline-go/pipeline"
"github.com/Azure/azure-storage-blob-go/azblob"
)
// Example for azblob usage : https://godoc.org/github.com/Azure/azure-storage-blob-go/azblob#pkg-examples
// For methods help refer : https://godoc.org/github.com/Azure/azure-storage-blob-go/azblob#ContainerURL
// Example for azblob usage : https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob#pkg-examples
// For methods help refer : https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob#Client
type AzStorageConfig struct {
authConfig azAuthConfig
@ -56,7 +53,7 @@ type AzStorageConfig struct {
maxConcurrency uint16
// tier to be set on every upload
defaultTier azblob.AccessTierType
defaultTier *blob.AccessTier
// Return back readDir on mount for given amount of time
cancelListForSeconds uint16
@ -67,7 +64,6 @@ type AzStorageConfig struct {
backoffTime int32
maxRetryDelay int32
proxyAddress string
sdkTrace bool
ignoreAccessModifiers bool
mountAllContainers bool
@ -89,10 +85,6 @@ type AzStorageConfig struct {
type AzStorageConnection struct {
Config AzStorageConfig
Pipeline pipeline.Pipeline
Endpoint *url.URL
}
type AzConnection interface {
@ -126,8 +118,8 @@ type AzConnection interface {
ReadBuffer(name string, offset int64, len int64) ([]byte, error)
ReadInBuffer(name string, offset int64, len int64, data []byte) error
WriteFromFile(name string, metadata map[string]string, fi *os.File) error
WriteFromBuffer(name string, metadata map[string]string, data []byte) error
WriteFromFile(name string, metadata map[string]*string, fi *os.File) error
WriteFromBuffer(name string, metadata map[string]*string, data []byte) error
Write(options internal.WriteFileOptions) error
GetFileBlockOffsets(name string) (*common.BlockOffsetList, error)
@ -140,7 +132,7 @@ type AzConnection interface {
StageBlock(string, []byte, string) error
CommitBlocks(string, []string) error
NewCredentialKey(_, _ string) error
UpdateServiceClient(_, _ string) error
}
// NewAzStorageConnection : Based on account type create respective AzConnection Object

Просмотреть файл

@ -35,7 +35,7 @@ package azstorage
import (
"context"
"errors"
"fmt"
"io/fs"
"net/url"
"os"
@ -44,21 +44,25 @@ import (
"syscall"
"time"
"github.com/Azure/azure-pipeline-go/pipeline"
"github.com/Azure/azure-storage-fuse/v2/common"
"github.com/Azure/azure-storage-fuse/v2/common/log"
"github.com/Azure/azure-storage-fuse/v2/internal"
"github.com/Azure/azure-storage-azcopy/v10/azbfs"
"github.com/Azure/azure-storage-azcopy/v10/ste"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/directory"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/file"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/filesystem"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/service"
)
type Datalake struct {
AzStorageConnection
Auth azAuth
Service azbfs.ServiceURL
Filesystem azbfs.FileSystemURL
BlockBlob BlockBlob
Auth azAuth
Service *service.Client
Filesystem *filesystem.Client
BlockBlob BlockBlob
datalakeCPKOpt *file.CPKInfo
}
// Verify that Datalake implements AzConnection interface
@ -91,6 +95,14 @@ func transformConfig(dlConfig AzStorageConfig) AzStorageConfig {
func (dl *Datalake) Configure(cfg AzStorageConfig) error {
dl.Config = cfg
if dl.Config.cpkEnabled {
dl.datalakeCPKOpt = &file.CPKInfo{
EncryptionKey: &dl.Config.cpkEncryptionKey,
EncryptionKeySHA256: &dl.Config.cpkEncryptionKeySha256,
EncryptionAlgorithm: to.Ptr(directory.EncryptionAlgorithmTypeAES256),
}
}
return dl.BlockBlob.Configure(transformConfig(cfg))
}
@ -103,63 +115,43 @@ func (dl *Datalake) UpdateConfig(cfg AzStorageConfig) error {
return dl.BlockBlob.UpdateConfig(cfg)
}
// NewSASKey : New SAS key provided by user
func (dl *Datalake) NewCredentialKey(key, value string) (err error) {
// UpdateServiceClient : Update the SAS specified by the user and create new service client
func (dl *Datalake) UpdateServiceClient(key, value string) (err error) {
if key == "saskey" {
dl.Auth.setOption(key, value)
// Update the endpoint url from the credential
dl.Endpoint, err = url.Parse(dl.Auth.getEndpoint())
// get the service client with updated SAS
svcClient, err := dl.Auth.getServiceClient(&dl.Config)
if err != nil {
log.Err("Datalake::NewCredentialKey : Failed to form base endpoint url [%s]", err.Error())
return errors.New("failed to form base endpoint url")
log.Err("Datalake::UpdateServiceClient : Failed to get service client [%s]", err.Error())
return err
}
// Update the service url
dl.Service = azbfs.NewServiceURL(*dl.Endpoint, dl.Pipeline)
// update the service client
dl.Service = svcClient.(*service.Client)
// Update the filesystem url
dl.Filesystem = dl.Service.NewFileSystemURL(dl.Config.container)
// Update the filesystem client
dl.Filesystem = dl.Service.NewFileSystemClient(dl.Config.container)
}
return dl.BlockBlob.NewCredentialKey(key, value)
return dl.BlockBlob.UpdateServiceClient(key, value)
}
// getCredential : Create the credential object
func (dl *Datalake) getCredential() azbfs.Credential {
log.Trace("Datalake::getCredential : Getting credential")
// createServiceClient : Create the service client
func (dl *Datalake) createServiceClient() (*service.Client, error) {
log.Trace("Datalake::createServiceClient : Getting service client")
dl.Auth = getAzAuth(dl.Config.authConfig)
if dl.Auth == nil {
log.Err("Datalake::getCredential : Failed to retrieve auth object")
return nil
log.Err("Datalake::createServiceClient : Failed to retrieve auth object")
return nil, fmt.Errorf("failed to retrieve auth object")
}
cred := dl.Auth.getCredential()
if cred == nil {
log.Err("Datalake::getCredential : Failed to get credential")
return nil
svcClient, err := dl.Auth.getServiceClient(&dl.Config)
if err != nil {
log.Err("Datalake::createServiceClient : Failed to get service client [%s]", err.Error())
return nil, err
}
return cred.(azbfs.Credential)
}
// NewPipeline creates a Pipeline using the specified credentials and options.
func NewBfsPipeline(c azbfs.Credential, o azbfs.PipelineOptions, ro ste.XferRetryOptions) pipeline.Pipeline {
// Closest to API goes first; closest to the wire goes last
f := []pipeline.Factory{
azbfs.NewTelemetryPolicyFactory(o.Telemetry),
azbfs.NewUniqueRequestIDPolicyFactory(),
// ste.NewBlobXferRetryPolicyFactory(ro),
ste.NewBFSXferRetryPolicyFactory(ro),
}
f = append(f, c)
f = append(f,
pipeline.MethodFactoryMarker(), // indicates at what stage in the pipeline the method factory is invoked
ste.NewRequestLogPolicyFactory(ste.RequestLogOptions{
LogWarningIfTryOverThreshold: o.RequestLog.LogWarningIfTryOverThreshold,
SyslogDisabled: o.RequestLog.SyslogDisabled,
}))
return pipeline.NewPipeline(f, pipeline.Options{HTTPSender: o.HTTPSender, Log: o.Log})
return svcClient.(*service.Client), nil
}
// SetupPipeline : Based on the config setup the ***URLs
@ -167,33 +159,15 @@ func (dl *Datalake) SetupPipeline() error {
log.Trace("Datalake::SetupPipeline : Setting up")
var err error
// Get the credential
cred := dl.getCredential()
if cred == nil {
log.Err("Datalake::SetupPipeline : Failed to get credential")
return errors.New("failed to get credential")
}
// Create a new pipeline
options, retryOptions := getAzBfsPipelineOptions(dl.Config)
dl.Pipeline = NewBfsPipeline(cred, options, retryOptions)
if dl.Pipeline == nil {
log.Err("Datalake::SetupPipeline : Failed to create pipeline object")
return errors.New("failed to create pipeline object")
}
// Get the endpoint url from the credential
dl.Endpoint, err = url.Parse(dl.Auth.getEndpoint())
// create the service client
dl.Service, err = dl.createServiceClient()
if err != nil {
log.Err("Datalake::SetupPipeline : Failed to form base end point url [%s]", err.Error())
return errors.New("failed to form base end point url")
log.Err("Datalake::SetupPipeline : Failed to get service client [%s]", err.Error())
return err
}
// Create the service url
dl.Service = azbfs.NewServiceURL(*dl.Endpoint, dl.Pipeline)
// Create the filesystem url
dl.Filesystem = dl.Service.NewFileSystemURL(dl.Config.container)
// create the filesystem client
dl.Filesystem = dl.Service.NewFileSystemClient(dl.Config.container)
return dl.BlockBlob.SetupPipeline()
}
@ -206,27 +180,24 @@ func (dl *Datalake) TestPipeline() error {
return nil
}
if dl.Filesystem.String() == "" {
log.Err("Datalake::TestPipeline : Filesystem URL is not built, check your credentials")
if dl.Filesystem == nil || dl.Filesystem.DFSURL() == "" || dl.Filesystem.BlobURL() == "" {
log.Err("Datalake::TestPipeline : Filesystem Client is not built, check your credentials")
return nil
}
maxResults := int32(2)
listPath, err := dl.Filesystem.ListPaths(context.Background(),
azbfs.ListPathsFilesystemOptions{
Path: &dl.Config.prefixPath,
Recursive: false,
MaxResults: &maxResults,
})
listPathPager := dl.Filesystem.NewListPathsPager(false, &filesystem.ListPathsOptions{
MaxResults: &maxResults,
Prefix: &dl.Config.prefixPath,
})
// we are just validating the auth mode used. So, no need to iterate over the pages
_, err := listPathPager.NextPage(context.Background())
if err != nil {
log.Err("Datalake::TestPipeline : Failed to validate account with given auth %s", err.Error)
return err
}
if listPath == nil {
log.Info("Datalake::TestPipeline : Filesystem is empty")
}
return dl.BlockBlob.TestPipeline()
}
@ -262,8 +233,15 @@ func (dl *Datalake) CreateFile(name string, mode os.FileMode) error {
func (dl *Datalake) CreateDirectory(name string) error {
log.Trace("Datalake::CreateDirectory : name %s", name)
directoryURL := dl.Filesystem.NewDirectoryURL(filepath.Join(dl.Config.prefixPath, name))
_, err := directoryURL.Create(context.Background(), false)
directoryURL := dl.Filesystem.NewDirectoryClient(filepath.Join(dl.Config.prefixPath, name))
_, err := directoryURL.Create(context.Background(), &directory.CreateOptions{
CPKInfo: dl.datalakeCPKOpt,
AccessConditions: &directory.AccessConditions{
ModifiedAccessConditions: &directory.ModifiedAccessConditions{
IfNoneMatch: to.Ptr(azcore.ETagAny),
},
},
})
if err != nil {
serr := storeDatalakeErrToErr(err)
@ -291,9 +269,8 @@ func (dl *Datalake) CreateLink(source string, target string) error {
// DeleteFile : Delete a file in the filesystem/directory
func (dl *Datalake) DeleteFile(name string) (err error) {
log.Trace("Datalake::DeleteFile : name %s", name)
fileURL := dl.Filesystem.NewRootDirectoryURL().NewFileURL(filepath.Join(dl.Config.prefixPath, name))
_, err = fileURL.Delete(context.Background())
fileClient := dl.Filesystem.NewFileClient(filepath.Join(dl.Config.prefixPath, name))
_, err = fileClient.Delete(context.Background(), nil)
if err != nil {
serr := storeDatalakeErrToErr(err)
if serr == ErrFileNotFound {
@ -318,8 +295,8 @@ func (dl *Datalake) DeleteFile(name string) (err error) {
func (dl *Datalake) DeleteDirectory(name string) (err error) {
log.Trace("Datalake::DeleteDirectory : name %s", name)
directoryURL := dl.Filesystem.NewDirectoryURL(filepath.Join(dl.Config.prefixPath, name))
_, err = directoryURL.Delete(context.Background(), nil, true)
directoryClient := dl.Filesystem.NewDirectoryClient(filepath.Join(dl.Config.prefixPath, name))
_, err = directoryClient.Delete(context.Background(), nil)
// TODO : There is an ability to pass a continuation token here for recursive delete, should we implement this logic to follow continuation token? The SDK does not currently do this.
if err != nil {
serr := storeDatalakeErrToErr(err)
@ -339,12 +316,11 @@ func (dl *Datalake) DeleteDirectory(name string) (err error) {
func (dl *Datalake) RenameFile(source string, target string) error {
log.Trace("Datalake::RenameFile : %s -> %s", source, target)
fileURL := dl.Filesystem.NewRootDirectoryURL().NewFileURL(url.PathEscape(filepath.Join(dl.Config.prefixPath, source)))
fileClient := dl.Filesystem.NewFileClient(url.PathEscape(filepath.Join(dl.Config.prefixPath, source)))
_, err := fileURL.Rename(context.Background(),
azbfs.RenameFileOptions{
DestinationPath: filepath.Join(dl.Config.prefixPath, target),
})
_, err := fileClient.Rename(context.Background(), filepath.Join(dl.Config.prefixPath, target), &file.RenameOptions{
CPKInfo: dl.datalakeCPKOpt,
})
if err != nil {
serr := storeDatalakeErrToErr(err)
if serr == ErrFileNotFound {
@ -363,12 +339,10 @@ func (dl *Datalake) RenameFile(source string, target string) error {
func (dl *Datalake) RenameDirectory(source string, target string) error {
log.Trace("Datalake::RenameDirectory : %s -> %s", source, target)
directoryURL := dl.Filesystem.NewDirectoryURL(url.PathEscape(filepath.Join(dl.Config.prefixPath, source)))
_, err := directoryURL.Rename(context.Background(),
azbfs.RenameDirectoryOptions{
DestinationPath: filepath.Join(dl.Config.prefixPath, target),
})
directoryClient := dl.Filesystem.NewDirectoryClient(url.PathEscape(filepath.Join(dl.Config.prefixPath, source)))
_, err := directoryClient.Rename(context.Background(), filepath.Join(dl.Config.prefixPath, target), &directory.RenameOptions{
CPKInfo: dl.datalakeCPKOpt,
})
if err != nil {
serr := storeDatalakeErrToErr(err)
if serr == ErrFileNotFound {
@ -387,8 +361,10 @@ func (dl *Datalake) RenameDirectory(source string, target string) error {
func (dl *Datalake) GetAttr(name string) (attr *internal.ObjAttr, err error) {
log.Trace("Datalake::GetAttr : name %s", name)
pathURL := dl.Filesystem.NewRootDirectoryURL().NewFileURL(filepath.Join(dl.Config.prefixPath, name))
prop, err := pathURL.GetProperties(context.Background())
fileClient := dl.Filesystem.NewFileClient(filepath.Join(dl.Config.prefixPath, name))
prop, err := fileClient.GetProperties(context.Background(), &file.GetPropertiesOptions{
CPKInfo: dl.datalakeCPKOpt,
})
if err != nil {
e := storeDatalakeErrToErr(err)
if e == ErrFileNotFound {
@ -402,14 +378,7 @@ func (dl *Datalake) GetAttr(name string) (attr *internal.ObjAttr, err error) {
}
}
lastModified, err := time.Parse(time.RFC1123, prop.LastModified())
if err != nil {
log.Err("Datalake::GetAttr : Failed to convert last modified time for %s [%s]", name, err.Error())
return attr, err
}
mode, err := getFileMode(prop.XMsPermissions())
mode, err := getFileMode(*prop.Permissions)
if err != nil {
log.Err("Datalake::GetAttr : Failed to get file mode for %s [%s]", name, err.Error())
return attr, err
@ -418,28 +387,30 @@ func (dl *Datalake) GetAttr(name string) (attr *internal.ObjAttr, err error) {
attr = &internal.ObjAttr{
Path: name,
Name: filepath.Base(name),
Size: prop.ContentLength(),
Size: *prop.ContentLength,
Mode: mode,
Mtime: lastModified,
Atime: lastModified,
Ctime: lastModified,
Crtime: lastModified,
Mtime: *prop.LastModified,
Atime: *prop.LastModified,
Ctime: *prop.LastModified,
Crtime: *prop.LastModified,
Flags: internal.NewFileBitMap(),
}
parseProperties(attr, prop.XMsProperties())
if azbfs.PathResourceDirectory == azbfs.PathResourceType(prop.XMsResourceType()) {
parseMetadata(attr, prop.Metadata)
if *prop.ResourceType == "directory" {
attr.Flags = internal.NewDirBitMap()
attr.Mode = attr.Mode | os.ModeDir
}
attr.Flags.Set(internal.PropFlagMetadataRetrieved)
if dl.Config.honourACL && dl.Config.authConfig.ObjectID != "" {
acl, err := pathURL.GetAccessControl(context.Background())
acl, err := fileClient.GetAccessControl(context.Background(), nil)
if err != nil {
// Just ignore the error here as rest of the attributes have been retrieved
log.Err("Datalake::GetAttr : Failed to get ACL for %s [%s]", name, err.Error())
} else {
mode, err := getFileModeFromACL(dl.Config.authConfig.ObjectID, acl.ACL, acl.Owner)
mode, err := getFileModeFromACL(dl.Config.authConfig.ObjectID, *acl.ACL, *acl.Owner)
if err != nil {
log.Err("Datalake::GetAttr : Failed to get file mode from ACL for %s [%s]", name, err.Error())
} else {
@ -475,14 +446,14 @@ func (dl *Datalake) List(prefix string, marker *string, count int32) ([]*interna
}
// Get a result segment starting with the path indicated by the current Marker.
listPath, err := dl.Filesystem.ListPaths(context.Background(),
azbfs.ListPathsFilesystemOptions{
Path: &prefixPath,
Recursive: false,
MaxResults: &count,
ContinuationToken: marker,
})
pager := dl.Filesystem.NewListPathsPager(false, &filesystem.ListPathsOptions{
Marker: marker,
MaxResults: &count,
Prefix: &prefixPath,
})
// Process the paths returned in this result segment (if the segment is empty, the loop body won't execute)
listPath, err := pager.NextPage(context.Background())
if err != nil {
log.Err("Datalake::List : Failed to validate account with given auth %s", err.Error())
m := ""
@ -499,7 +470,7 @@ func (dl *Datalake) List(prefix string, marker *string, count int32) ([]*interna
// Process the paths returned in this result segment (if the segment is empty, the loop body won't execute)
for _, pathInfo := range listPath.Paths {
var attr *internal.ObjAttr
var lastModifiedTime time.Time
if dl.Config.disableSymlink {
var mode fs.FileMode
if pathInfo.Permissions != nil {
@ -522,15 +493,21 @@ func (dl *Datalake) List(prefix string, marker *string, count int32) ([]*interna
log.Err("Datalake::List : Failed to get file length for %s", *pathInfo.Name)
}
if pathInfo.LastModified != nil {
lastModifiedTime, err = time.Parse(time.RFC1123, *pathInfo.LastModified)
if err != nil {
log.Err("Datalake::List : Failed to get last modified time for %s [%s]", *pathInfo.Name, err.Error())
}
}
attr = &internal.ObjAttr{
Path: *pathInfo.Name,
Name: filepath.Base(*pathInfo.Name),
Size: contentLength,
Mode: mode,
Mtime: pathInfo.LastModifiedTime(),
Atime: pathInfo.LastModifiedTime(),
Ctime: pathInfo.LastModifiedTime(),
Crtime: pathInfo.LastModifiedTime(),
Mtime: lastModifiedTime,
Atime: lastModifiedTime,
Ctime: lastModifiedTime,
Crtime: lastModifiedTime,
Flags: internal.NewFileBitMap(),
}
if pathInfo.IsDirectory != nil && *pathInfo.IsDirectory {
@ -555,10 +532,10 @@ func (dl *Datalake) List(prefix string, marker *string, count int32) ([]*interna
// Alternatively, if you want Datalake list paths to return metadata/properties as well.
// pass CLI parameter --no-symlinks=false in the mount command.
pathList = append(pathList, attr)
}
m := listPath.XMsContinuation()
return pathList, &m, nil
return pathList, listPath.Continuation, nil
}
// ReadToFile : Download a file to a local file
@ -577,12 +554,12 @@ func (dl *Datalake) ReadInBuffer(name string, offset int64, len int64, data []by
}
// WriteFromFile : Upload local file to file
func (dl *Datalake) WriteFromFile(name string, metadata map[string]string, fi *os.File) (err error) {
func (dl *Datalake) WriteFromFile(name string, metadata map[string]*string, fi *os.File) (err error) {
return dl.BlockBlob.WriteFromFile(name, metadata, fi)
}
// WriteFromBuffer : Upload from a buffer to a file
func (dl *Datalake) WriteFromBuffer(name string, metadata map[string]string, data []byte) error {
func (dl *Datalake) WriteFromBuffer(name string, metadata map[string]*string, data []byte) error {
return dl.BlockBlob.WriteFromBuffer(name, metadata, data)
}
@ -606,7 +583,7 @@ func (dl *Datalake) TruncateFile(name string, size int64) error {
// ChangeMod : Change mode of a path
func (dl *Datalake) ChangeMod(name string, mode os.FileMode) error {
log.Trace("Datalake::ChangeMod : Change mode of file %s to %s", name, mode)
fileURL := dl.Filesystem.NewRootDirectoryURL().NewFileURL(filepath.Join(dl.Config.prefixPath, name))
fileClient := dl.Filesystem.NewFileClient(filepath.Join(dl.Config.prefixPath, name))
/*
// If we need to call the ACL set api then we need to get older acl string here
@ -624,7 +601,9 @@ func (dl *Datalake) ChangeMod(name string, mode os.FileMode) error {
*/
newPerm := getACLPermissions(mode)
_, err := fileURL.SetAccessControl(context.Background(), azbfs.BlobFSAccessControl{Permissions: newPerm})
_, err := fileClient.SetAccessControl(context.Background(), &file.SetAccessControlOptions{
Permissions: &newPerm,
})
if err != nil {
log.Err("Datalake::ChangeMod : Failed to change mode of file %s to %s [%s]", name, mode, err.Error())
e := storeDatalakeErrToErr(err)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -34,9 +34,7 @@
package azstorage
import (
"context"
"crypto/md5"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
@ -49,15 +47,19 @@ import (
"strings"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
azlog "github.com/Azure/azure-sdk-for-go/sdk/azcore/log"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/service"
serviceBfs "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/service"
"github.com/Azure/azure-storage-fuse/v2/common"
"github.com/Azure/azure-storage-fuse/v2/common/log"
"github.com/Azure/azure-storage-fuse/v2/internal"
"github.com/Azure/azure-storage-azcopy/v10/azbfs"
"github.com/Azure/azure-storage-azcopy/v10/ste"
"github.com/Azure/azure-pipeline-go/pipeline"
"github.com/Azure/azure-storage-blob-go/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/datalakeerror"
)
// ----------- Helper to create pipeline options ---------------
@ -72,6 +74,7 @@ const (
DualStack bool = true
MaxIdleConns int = 0 // No limit
MaxIdleConnsPerHost int = 100
MaxConnsPerHost int = 0 // No limit
IdleConnTimeout time.Duration = 90 * time.Second
TLSHandshakeTimeout time.Duration = 10 * time.Second
ExpectContinueTimeout time.Duration = 1 * time.Second
@ -80,11 +83,10 @@ const (
MaxResponseHeaderBytes int64 = 0
)
// getAzBlobPipelineOptions : Create pipeline options based on the config
func getAzBlobPipelineOptions(conf AzStorageConfig) (azblob.PipelineOptions, ste.XferRetryOptions) {
retryOptions := ste.XferRetryOptions{
Policy: ste.RetryPolicyExponential, // Use exponential backoff as opposed to linear
MaxTries: conf.maxRetries, // Try at most 3 times to perform the operation (set to 1 to disable retries)
// getAzStorageClientOptions : Create client options based on the config
func getAzStorageClientOptions(conf *AzStorageConfig) azcore.ClientOptions {
retryOptions := policy.RetryOptions{
MaxRetries: conf.maxRetries, // Try at most 3 times to perform the operation (set to 1 to disable retries)
TryTimeout: time.Second * time.Duration(conf.maxTimeout), // Maximum time allowed for any single try
RetryDelay: time.Second * time.Duration(conf.backoffTime), // Backoff amount for each retry (exponential or linear)
MaxRetryDelay: time.Second * time.Duration(conf.maxRetryDelay), // Max delay between retries
@ -94,72 +96,65 @@ func getAzBlobPipelineOptions(conf AzStorageConfig) (azblob.PipelineOptions, ste
if telemetryValue != "" {
telemetryValue += " "
}
telemetryValue += UserAgent() + " (" + common.GetCurrentDistro() + ")"
telemetryPolicy := newBlobfuseTelemetryPolicy(telemetryValue)
telemetryOptions := azblob.TelemetryOptions{
Value: telemetryValue,
}
logOptions := getSDKLogOptions()
sysLogDisabled := log.GetType() == "silent" // If logging is enabled, allow the SDK to log retries to syslog.
requestLogOptions := azblob.RequestLogOptions{
// TODO: We can potentially consider making LogWarningIfTryOverThreshold a user settable option. For now lets use the default
SyslogDisabled: sysLogDisabled,
transportOptions := newBlobfuse2HttpClient(conf)
return azcore.ClientOptions{
Retry: retryOptions,
Logging: logOptions,
PerCallPolicies: []policy.Policy{telemetryPolicy},
Transport: transportOptions,
}
logOptions := getLogOptions(conf.sdkTrace)
// Create custom HTTPClient to pass to the factory in order to set our proxy
var pipelineHTTPClient = newBlobfuse2HttpClient(conf)
return azblob.PipelineOptions{
Log: logOptions,
RequestLog: requestLogOptions,
Telemetry: telemetryOptions,
HTTPSender: newBlobfuse2HTTPClientFactory(pipelineHTTPClient),
},
// Set RetryOptions to control how HTTP request are retried when retryable failures occur
retryOptions
}
// getAzBfsPipelineOptions : Create pipeline options based on the config
func getAzBfsPipelineOptions(conf AzStorageConfig) (azbfs.PipelineOptions, ste.XferRetryOptions) {
retryOptions := ste.XferRetryOptions{
Policy: ste.RetryPolicyExponential, // Use exponential backoff as opposed to linear
MaxTries: conf.maxRetries, // Try at most 3 times to perform the operation (set to 1 to disable retries)
TryTimeout: time.Second * time.Duration(conf.maxTimeout), // Maximum time allowed for any single try
RetryDelay: time.Second * time.Duration(conf.backoffTime), // Backoff amount for each retry (exponential or linear)
MaxRetryDelay: time.Second * time.Duration(conf.maxRetryDelay), // Max delay between retries
// getAzBlobServiceClientOptions : Create azblob service client options based on the config
func getAzBlobServiceClientOptions(conf *AzStorageConfig) *service.ClientOptions {
return &service.ClientOptions{
ClientOptions: getAzStorageClientOptions(conf),
}
}
telemetryValue := conf.telemetry
if telemetryValue != "" {
telemetryValue += " "
// getAzDatalakeServiceClientOptions : Create azdatalake service client options based on the config
func getAzDatalakeServiceClientOptions(conf *AzStorageConfig) *serviceBfs.ClientOptions {
return &serviceBfs.ClientOptions{
ClientOptions: getAzStorageClientOptions(conf),
}
}
telemetryValue += UserAgent() + " (" + common.GetCurrentDistro() + ")"
telemetryOptions := azbfs.TelemetryOptions{
Value: telemetryValue,
// getLogOptions : to configure the SDK logging policy
func getSDKLogOptions() policy.LogOptions {
if log.GetType() == "silent" || log.GetLogLevel() < common.ELogLevel.LOG_DEBUG() {
return policy.LogOptions{}
} else {
// add headers and query params which should be logged and not redacted
return policy.LogOptions{
AllowedHeaders: allowedHeaders,
AllowedQueryParams: allowedQueryParams,
}
}
}
sysLogDisabled := log.GetType() == "silent" // If logging is enabled, allow the SDK to log retries to syslog.
requestLogOptions := azbfs.RequestLogOptions{
// TODO: We can potentially consider making LogWarningIfTryOverThreshold a user settable option. For now lets use the default
SyslogDisabled: sysLogDisabled,
// setSDKLogListener : log the requests and responses.
// It is disabled if,
// - logging type is silent
// - logging level is less than debug
func setSDKLogListener() {
if log.GetType() == "silent" || log.GetLogLevel() < common.ELogLevel.LOG_DEBUG() {
// reset listener
azlog.SetListener(nil)
} else {
azlog.SetListener(func(cls azlog.Event, msg string) {
log.Debug("SDK(%s) : %s", cls, msg)
})
}
logOptions := getLogOptions(conf.sdkTrace)
// Create custom HTTPClient to pass to the factory in order to set our proxy
var pipelineHTTPClient = newBlobfuse2HttpClient(conf)
return azbfs.PipelineOptions{
Log: logOptions,
RequestLog: requestLogOptions,
Telemetry: telemetryOptions,
HTTPSender: newBlobfuse2HTTPClientFactory(pipelineHTTPClient),
},
// Set RetryOptions to control how HTTP request are retried when retryable failures occur
retryOptions
}
// Create an HTTP Client with configured proxy
// TODO: More configurations for other http client parameters?
func newBlobfuse2HttpClient(conf AzStorageConfig) *http.Client {
func newBlobfuse2HttpClient(conf *AzStorageConfig) *http.Client {
var ProxyURL func(req *http.Request) (*url.URL, error) = func(req *http.Request) (*url.URL, error) {
// If a proxy address is passed return
var proxyURL url.URL = url.URL{
@ -183,6 +178,7 @@ func newBlobfuse2HttpClient(conf AzStorageConfig) *http.Client {
}).Dial, /*Context*/
MaxIdleConns: MaxIdleConns, // No limit
MaxIdleConnsPerHost: MaxIdleConnsPerHost,
MaxConnsPerHost: MaxConnsPerHost, // No limit
IdleConnTimeout: IdleConnTimeout,
TLSHandshakeTimeout: TLSHandshakeTimeout,
ExpectContinueTimeout: ExpectContinueTimeout,
@ -191,85 +187,41 @@ func newBlobfuse2HttpClient(conf AzStorageConfig) *http.Client {
// make things ugly and hence user needs to disable this feature through config
DisableCompression: conf.disableCompression,
MaxResponseHeaderBytes: MaxResponseHeaderBytes,
//ResponseHeaderTimeout: time.Duration{},
//ExpectContinueTimeout: time.Duration{},
},
}
}
// newBlobfuse2HTTPClientFactory creates a custom HTTPClientPolicyFactory object that sends HTTP requests to the http client.
func newBlobfuse2HTTPClientFactory(pipelineHTTPClient *http.Client) pipeline.Factory {
return pipeline.FactoryFunc(func(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.PolicyFunc {
return func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) {
r, err := pipelineHTTPClient.Do(request.WithContext(ctx))
if err != nil {
log.Err("BlockBlob::newBlobfuse2HTTPClientFactory : HTTP request failed [%s]", err.Error())
err = pipeline.NewError(err, "HTTP request failed")
}
return pipeline.NewHTTPResponse(r), err
}
})
// getCloudConfiguration : returns cloud configuration type on the basis of endpoint
func getCloudConfiguration(endpoint string) cloud.Configuration {
if strings.Contains(endpoint, "core.chinacloudapi.cn") {
return cloud.AzureChina
} else if strings.Contains(endpoint, "core.usgovcloudapi.net") {
return cloud.AzureGovernment
} else {
return cloud.AzurePublic
}
}
func getLogOptions(sdkLogging bool) pipeline.LogOptions {
return pipeline.LogOptions{
Log: func(logLevel pipeline.LogLevel, message string) {
if !sdkLogging {
return
}
// blobfuseTelemetryPolicy is a custom pipeline policy to prepend the blobfuse user agent string to the one coming from SDK.
// This is added in the PerCallPolicies which executes after the SDK's default telemetry policy.
type blobfuseTelemetryPolicy struct {
telemetryValue string
}
// message here is a log generated by SDK and it contains URLs as well
// These URLs have '%' as part of their data like / replaced with %2F
// If we pass down message as first argument to our logging api, it assumes it to be
// a format specifier and treat each % in URL to be a type specifier this will
// result into log strings saying we have given %d but no integer as argument.
// Only way to bypass this is to pass message as a second argument to logging method
// so that logging api does not treat it as format string.
switch logLevel {
case pipeline.LogFatal:
log.Crit("SDK : %s", message)
case pipeline.LogPanic:
log.Crit("SDK : %s", message)
case pipeline.LogError:
log.Err("SDK : %s", message)
case pipeline.LogWarning:
log.Warn("SDK : %s", message)
case pipeline.LogInfo:
log.Info("SDK : %s", message)
case pipeline.LogDebug:
log.Debug("SDK : %s", message)
case pipeline.LogNone:
default:
}
},
ShouldLog: func(level pipeline.LogLevel) bool {
if !sdkLogging {
return false
}
currentLogLevel := func(commonLog common.LogLevel) pipeline.LogLevel {
switch commonLog {
case common.ELogLevel.INVALID():
return pipeline.LogNone
case common.ELogLevel.LOG_OFF():
return pipeline.LogNone
case common.ELogLevel.LOG_CRIT():
return pipeline.LogPanic // Panic logs both Panic and Fatal
case common.ELogLevel.LOG_ERR():
return pipeline.LogError
case common.ELogLevel.LOG_WARNING():
return pipeline.LogWarning
case common.ELogLevel.LOG_INFO():
return pipeline.LogInfo
case common.ELogLevel.LOG_TRACE():
return pipeline.LogDebug // No Trace in pipeline.LogLevel
case common.ELogLevel.LOG_DEBUG():
return pipeline.LogDebug
}
return pipeline.LogNone
}(log.GetLogLevel())
return level <= currentLogLevel
},
// newBlobfuseTelemetryPolicy creates an object which prepends the blobfuse user agent string to the User-Agent request header
func newBlobfuseTelemetryPolicy(telemetryValue string) policy.Policy {
return &blobfuseTelemetryPolicy{telemetryValue: telemetryValue}
}
func (p blobfuseTelemetryPolicy) Do(req *policy.Request) (*http.Response, error) {
userAgent := p.telemetryValue
// prepend the blobfuse user agent string
if ua := req.Raw().Header.Get(common.UserAgentHeader); ua != "" {
userAgent = fmt.Sprintf("%s %s", userAgent, ua)
}
req.Raw().Header.Set(common.UserAgentHeader, userAgent)
return req.Next()
}
// ----------- Store error code handling ---------------
@ -283,31 +235,24 @@ const (
InvalidPermission
)
// ErrStr : Store error to string mapping
var ErrStr = map[uint16]string{
ErrNoErr: "No Error found",
ErrUnknown: "Unknown store error",
ErrFileNotFound: "Blob not found",
ErrFileAlreadyExists: "Blob already exists",
}
// For detailed error list refert ServiceCodeType at below link
// https://godoc.org/github.com/Azure/azure-storage-blob-go/azblob#ListBlobsSegmentOptions
// For detailed error list refer below link,
// https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/storage/azblob/bloberror/error_codes.go
// Convert blob storage error to common errors
func storeBlobErrToErr(err error) uint16 {
if serr, ok := err.(azblob.StorageError); ok {
switch serr.ServiceCode() {
case azblob.ServiceCodeBlobAlreadyExists:
var respErr *azcore.ResponseError
errors.As(err, &respErr)
if respErr != nil {
switch (bloberror.Code)(respErr.ErrorCode) {
case bloberror.BlobAlreadyExists:
return ErrFileAlreadyExists
case azblob.ServiceCodeBlobNotFound:
case bloberror.BlobNotFound:
return ErrFileNotFound
case azblob.ServiceCodeInvalidRange:
case bloberror.InvalidRange:
return InvalidRange
case azblob.ServiceCodeLeaseIDMissing:
case bloberror.LeaseIDMissing:
return BlobIsUnderLease
case azblob.ServiceCodeInsufficientAccountPermissions:
return InvalidPermission
case "AuthorizationPermissionMismatch":
case bloberror.InsufficientAccountPermissions, bloberror.AuthorizationPermissionMismatch:
return InvalidPermission
default:
return ErrUnknown
@ -318,17 +263,20 @@ func storeBlobErrToErr(err error) uint16 {
// Convert datalake storage error to common errors
func storeDatalakeErrToErr(err error) uint16 {
if serr, ok := err.(azbfs.StorageError); ok {
switch serr.ServiceCode() {
case azbfs.ServiceCodePathAlreadyExists:
var respErr *azcore.ResponseError
errors.As(err, &respErr)
if respErr != nil {
switch (datalakeerror.StorageErrorCode)(respErr.ErrorCode) {
case datalakeerror.PathAlreadyExists:
return ErrFileAlreadyExists
case azbfs.ServiceCodePathNotFound:
case datalakeerror.PathNotFound:
return ErrFileNotFound
case azbfs.ServiceCodeSourcePathNotFound:
case datalakeerror.SourcePathNotFound:
return ErrFileNotFound
case "LeaseIdMissing":
case datalakeerror.LeaseIDMissing:
return BlobIsUnderLease
case "AuthorizationPermissionMismatch":
case datalakeerror.AuthorizationPermissionMismatch:
return InvalidPermission
default:
return ErrUnknown
@ -339,43 +287,19 @@ func storeDatalakeErrToErr(err error) uint16 {
// ----------- Metadata handling ---------------
//
// Converts datalake properties to a metadata map
func newMetadata(properties string) map[string]string {
metadata := make(map[string]string)
if properties != "" {
// Create a map of the properties (metadata)
pairs := strings.Split(properties, ",")
for _, p := range pairs {
components := strings.SplitN(p, "=", 2)
key := components[0]
value, err := base64.StdEncoding.DecodeString(components[1])
if err == nil {
metadata[key] = string(value)
}
}
}
return metadata
}
// parseProperties : Parse the properties of a given datalake path and populate its attributes
func parseProperties(attr *internal.ObjAttr, properties string) {
metadata := newMetadata(properties)
// Parse the metadata
parseMetadata(attr, metadata)
}
// parseMetadata : Parse the metadata of a given path and populate its attributes
func parseMetadata(attr *internal.ObjAttr, metadata map[string]string) {
func parseMetadata(attr *internal.ObjAttr, metadata map[string]*string) {
// Save the metadata in attributes so that later if someone wants to add anything it can work
attr.Metadata = metadata
for k, v := range metadata {
if strings.ToLower(k) == folderKey && v == "true" {
attr.Flags = internal.NewDirBitMap()
attr.Mode = attr.Mode | os.ModeDir
} else if strings.ToLower(k) == symlinkKey && v == "true" {
attr.Flags = internal.NewSymlinkBitMap()
attr.Mode = attr.Mode | os.ModeSymlink
if v != nil {
if strings.ToLower(k) == folderKey && *v == "true" {
attr.Flags = internal.NewDirBitMap()
attr.Mode = attr.Mode | os.ModeDir
} else if strings.ToLower(k) == symlinkKey && *v == "true" {
attr.Flags = internal.NewSymlinkBitMap()
attr.Mode = attr.Mode | os.ModeSymlink
}
}
}
}
@ -469,34 +393,35 @@ func populateContentType(newSet string) error { //nolint
// ----------- Blob access tier type conversion ---------------
//
// AccessTierMap : Store config to access tier mapping
var AccessTiers = map[string]azblob.AccessTierType{
"none": azblob.AccessTierNone,
"hot": azblob.AccessTierHot,
"cool": azblob.AccessTierCool,
"archive": azblob.AccessTierArchive,
"p4": azblob.AccessTierP4,
"p6": azblob.AccessTierP6,
"p10": azblob.AccessTierP10,
"p15": azblob.AccessTierP15,
"p20": azblob.AccessTierP20,
"p30": azblob.AccessTierP30,
"p40": azblob.AccessTierP40,
"p50": azblob.AccessTierP50,
"p60": azblob.AccessTierP60,
"p70": azblob.AccessTierP70,
"p80": azblob.AccessTierP80,
var AccessTiers = map[string]blob.AccessTier{
"hot": blob.AccessTierHot,
"cool": blob.AccessTierCool,
"cold": blob.AccessTierCold,
"archive": blob.AccessTierArchive,
"p4": blob.AccessTierP4,
"p6": blob.AccessTierP6,
"p10": blob.AccessTierP10,
"p15": blob.AccessTierP15,
"p20": blob.AccessTierP20,
"p30": blob.AccessTierP30,
"p40": blob.AccessTierP40,
"p50": blob.AccessTierP50,
"p60": blob.AccessTierP60,
"p70": blob.AccessTierP70,
"p80": blob.AccessTierP80,
"premium": blob.AccessTierPremium,
}
func getAccessTierType(name string) azblob.AccessTierType {
func getAccessTierType(name string) *blob.AccessTier {
if name == "" {
return azblob.AccessTierNone
return nil
}
value, found := AccessTiers[strings.ToLower(name)]
if found {
return value
return &value
}
return azblob.AccessTierNone
return nil
}
// Called by x method

Просмотреть файл

@ -39,7 +39,8 @@ import (
"strconv"
"testing"
"github.com/Azure/azure-storage-blob-go/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/Azure/azure-storage-fuse/v2/common"
"github.com/Azure/azure-storage-fuse/v2/common/log"
"github.com/stretchr/testify/assert"
@ -180,29 +181,31 @@ func (s *utilsTestSuite) TestGetContentType() {
type accesTierVal struct {
val string
result azblob.AccessTierType
result *blob.AccessTier
}
func (s *utilsTestSuite) TestGetAccessTierType() {
assert := assert.New(s.T())
var inputs = []accesTierVal{
{val: "", result: azblob.AccessTierNone},
{val: "none", result: azblob.AccessTierNone},
{val: "hot", result: azblob.AccessTierHot},
{val: "cool", result: azblob.AccessTierCool},
{val: "archive", result: azblob.AccessTierArchive},
{val: "p4", result: azblob.AccessTierP4},
{val: "p6", result: azblob.AccessTierP6},
{val: "p10", result: azblob.AccessTierP10},
{val: "p15", result: azblob.AccessTierP15},
{val: "p20", result: azblob.AccessTierP20},
{val: "p30", result: azblob.AccessTierP30},
{val: "p40", result: azblob.AccessTierP40},
{val: "p50", result: azblob.AccessTierP50},
{val: "p60", result: azblob.AccessTierP60},
{val: "p70", result: azblob.AccessTierP70},
{val: "p80", result: azblob.AccessTierP80},
{val: "random", result: azblob.AccessTierNone},
{val: "", result: nil},
{val: "none", result: nil},
{val: "hot", result: to.Ptr(blob.AccessTierHot)},
{val: "cool", result: to.Ptr(blob.AccessTierCool)},
{val: "cold", result: to.Ptr(blob.AccessTierCold)},
{val: "archive", result: to.Ptr(blob.AccessTierArchive)},
{val: "p4", result: to.Ptr(blob.AccessTierP4)},
{val: "p6", result: to.Ptr(blob.AccessTierP6)},
{val: "p10", result: to.Ptr(blob.AccessTierP10)},
{val: "p15", result: to.Ptr(blob.AccessTierP15)},
{val: "p20", result: to.Ptr(blob.AccessTierP20)},
{val: "p30", result: to.Ptr(blob.AccessTierP30)},
{val: "p40", result: to.Ptr(blob.AccessTierP40)},
{val: "p50", result: to.Ptr(blob.AccessTierP50)},
{val: "p60", result: to.Ptr(blob.AccessTierP60)},
{val: "p70", result: to.Ptr(blob.AccessTierP70)},
{val: "p80", result: to.Ptr(blob.AccessTierP80)},
{val: "premium", result: to.Ptr(blob.AccessTierPremium)},
{val: "random", result: nil},
}
for _, i := range inputs {
s.Run(i.val, func() {
@ -319,30 +322,30 @@ func (s *utilsTestSuite) TestSanitizeSASKey() {
func (s *utilsTestSuite) TestBlockNonProxyOptions() {
assert := assert.New(s.T())
po, ro := getAzBlobPipelineOptions(AzStorageConfig{})
assert.EqualValues(ro.MaxTries, int(0))
assert.NotEqual(po.RequestLog.SyslogDisabled, true)
opt := getAzBlobServiceClientOptions(&AzStorageConfig{})
assert.EqualValues(opt.Retry.MaxRetries, 0)
assert.GreaterOrEqual(len(opt.Logging.AllowedHeaders), 1)
}
func (s *utilsTestSuite) TestBlockProxyOptions() {
assert := assert.New(s.T())
po, ro := getAzBlobPipelineOptions(AzStorageConfig{proxyAddress: "127.0.0.1", maxRetries: 3})
assert.EqualValues(ro.MaxTries, 3)
assert.NotEqual(po.RequestLog.SyslogDisabled, true)
opt := getAzBlobServiceClientOptions(&AzStorageConfig{proxyAddress: "127.0.0.1", maxRetries: 3})
assert.EqualValues(opt.Retry.MaxRetries, 3)
assert.GreaterOrEqual(len(opt.Logging.AllowedHeaders), 1)
}
func (s *utilsTestSuite) TestBfsNonProxyOptions() {
assert := assert.New(s.T())
po, ro := getAzBfsPipelineOptions(AzStorageConfig{})
assert.EqualValues(ro.MaxTries, int(0))
assert.NotEqual(po.RequestLog.SyslogDisabled, true)
opt := getAzDatalakeServiceClientOptions(&AzStorageConfig{})
assert.EqualValues(opt.Retry.MaxRetries, 0)
assert.GreaterOrEqual(len(opt.Logging.AllowedHeaders), 1)
}
func (s *utilsTestSuite) TestBfsProxyOptions() {
assert := assert.New(s.T())
po, ro := getAzBfsPipelineOptions(AzStorageConfig{proxyAddress: "127.0.0.1", maxRetries: 3})
assert.EqualValues(ro.MaxTries, 3)
assert.NotEqual(po.RequestLog.SyslogDisabled, true)
opt := getAzBlobServiceClientOptions(&AzStorageConfig{proxyAddress: "127.0.0.1", maxRetries: 3})
assert.EqualValues(opt.Retry.MaxRetries, 3)
assert.GreaterOrEqual(len(opt.Logging.AllowedHeaders), 1)
}
type endpointAccountType struct {

81
go.mod
Просмотреть файл

@ -3,11 +3,10 @@ module github.com/Azure/azure-storage-fuse/v2
go 1.20
require (
github.com/Azure/azure-pipeline-go v0.2.4-0.20220425205405-09e6f201e1e4
github.com/Azure/azure-storage-azcopy/v10 v10.19.1-0.20230926150507-787a98b9a2b1
github.com/Azure/azure-storage-blob-go v0.15.0
github.com/Azure/go-autorest/autorest v0.11.29
github.com/Azure/go-autorest/autorest/adal v0.9.23
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1
github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake v1.1.1
github.com/JeffreyRichter/enum v0.0.0-20180725232043-2567042f9cda
github.com/fsnotify/fsnotify v1.7.0
github.com/golang/mock v1.6.0
@ -18,8 +17,8 @@ require (
github.com/sevlyar/go-daemon v0.1.6
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.17.0
github.com/stretchr/testify v1.8.4
github.com/spf13/viper v1.18.2
github.com/stretchr/testify v1.9.0
github.com/vibhansa-msft/tlru v0.0.0-20230621165448-dbd42234ad22
go.uber.org/atomic v1.11.0
gopkg.in/ini.v1 v1.67.0
@ -28,71 +27,37 @@ require (
)
require (
cloud.google.com/go v0.110.10 // indirect
cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.5 // indirect
cloud.google.com/go/storage v1.35.1 // indirect
github.com/Azure/azure-storage-file-go v0.6.1-0.20201111053559-3c1754dc00a5 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/danieljoos/wincred v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hillu/go-ntdll v0.0.0-20230408164318-f8894bfa00af // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-ieproxy v0.0.11 // indirect
github.com/minio/minio-go v6.0.14+incompatible // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/xattr v0.4.9 // indirect
github.com/pelletier/go-toml/v2 v2.2.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.10.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/wastore/keychain v0.0.0-20180920053336-f2c902a3d807 // indirect
github.com/wastore/keyctl v0.3.1 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.15.0 // indirect
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/oauth2 v0.14.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.4.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/api v0.150.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)
replace github.com/spf13/cobra => github.com/gapra-msft/cobra v1.4.1-0.20220411185530-5b83e8ba06dd
//replace github.com/Azure/azure-storage-azcopy/v10 v10.19.1-0.20230717101935-ab8ff0a85e48 => <local path>/azure-storage-azcopy
// Take AzCopy dependencyon this branch only
// go get github.com/Azure/azure-storage-azcopy/v10@blobfuse2-cpu-usage

618
go.sum
Просмотреть файл

@ -1,669 +1,147 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y=
cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w=
cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
github.com/Azure/azure-pipeline-go v0.2.4-0.20220425205405-09e6f201e1e4 h1:hDJImUzpTAeIw/UasFUUDB/+UsZm5Q/6x2/jKKvEUiw=
github.com/Azure/azure-pipeline-go v0.2.4-0.20220425205405-09e6f201e1e4/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
github.com/Azure/azure-storage-azcopy/v10 v10.19.1-0.20230926150507-787a98b9a2b1 h1:VO0RRtIjIMn8/gOJOoNMKMO0r4LRH4YQgLJu1d1d9UE=
github.com/Azure/azure-storage-azcopy/v10 v10.19.1-0.20230926150507-787a98b9a2b1/go.mod h1:TUB6fvsBwrBW1S6mDQU+ecIA3JtUBOVpfGntT5bVqrc=
github.com/Azure/azure-storage-blob-go v0.15.0 h1:rXtgp8tN1p29GvpGgfJetavIG0V7OgcSXPpwp3tx6qk=
github.com/Azure/azure-storage-blob-go v0.15.0/go.mod h1:vbjsVbX0dlxnRc4FFMPsS9BsJWPcne7GB7onqlPvz58=
github.com/Azure/azure-storage-file-go v0.6.1-0.20201111053559-3c1754dc00a5 h1:aHEvBM4oXIWSTOVdL55nCYXO0Cl7ie3Ui5xMQhLVez8=
github.com/Azure/azure-storage-file-go v0.6.1-0.20201111053559-3c1754dc00a5/go.mod h1:++L7GP2pRyUNuastZ7m02vYV69JHmqlWXfCaGoL0v4s=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw=
github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs=
github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk=
github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8=
github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c=
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw=
github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=
github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1 h1:fXPMAmuh0gDuRDey0atC8cXBuKIlqCzCkL8sm1n9Ov0=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1/go.mod h1:SUZc9YRRHfx2+FAQKNDGrssXehqLpxmwRv2mC/5ntj4=
github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake v1.1.1 h1:mkaGMgFkpDJVs7QUQrHvqEEpJFvoDrqGaHqMkywhGN0=
github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake v1.1.1/go.mod h1:3S0vo7Y+O3Fjnnon5JXVrlG2IrfQkXasvKWB4OwX1lk=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/JeffreyRichter/enum v0.0.0-20180725232043-2567042f9cda h1:NOo6+gM9NNPJ3W56nxOKb4164LEw094U0C8zYQM8mQU=
github.com/JeffreyRichter/enum v0.0.0-20180725232043-2567042f9cda/go.mod h1:2CaSFTh2ph9ymS6goiOKIBdfhwWUVsX4nQ5QjIYFHHs=
github.com/PuerkitoBio/goquery v1.7.1/go.mod h1:XY0pP4kfraEmmV1O7Uf6XyjoslwsneBbgeDjLYuN8xY=
github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE=
github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gapra-msft/cobra v1.4.1-0.20220411185530-5b83e8ba06dd h1:U3d5Jlb0ANsyxk2lnlhYh7/Ov4bZpIBUxJTsVuJM9G0=
github.com/gapra-msft/cobra v1.4.1-0.20220411185530-5b83e8ba06dd/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hillu/go-ntdll v0.0.0-20230408164318-f8894bfa00af h1:6qDlty5ZH5RftbuLnx78wNTpPcWy3gUV1NbfBZR7e5g=
github.com/hillu/go-ntdll v0.0.0-20230408164318-f8894bfa00af/go.mod h1:cHjYsnAnSckPDx8/H01Y+owD1hf2adLA6VRiw4guEbA=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
github.com/mattn/go-ieproxy v0.0.11 h1:MQ/5BuGSgDAHZOJe6YY80IF2UVCfGkwfo6AeD7HtHYo=
github.com/mattn/go-ieproxy v0.0.11/go.mod h1:/NsJd+kxZBmjMc5hrJCKMbP57B84rvq9BiDRbtO9AS0=
github.com/minio/minio-go v6.0.14+incompatible h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o=
github.com/minio/minio-go v6.0.14+incompatible/go.mod h1:7guKYtitv8dktvNUGrhzmNlA5wrAABTQXCoesZdFQO8=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/montanaflynn/stats v0.7.0 h1:r3y12KyNxj/Sb/iOE46ws+3mS1+MZca1wlHQFPsY/JU=
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE=
github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE=
github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sevlyar/go-daemon v0.1.6 h1:EUh1MDjEM4BI109Jign0EaknA2izkOyi0LV3ro3QQGs=
github.com/sevlyar/go-daemon v0.1.6/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW3MebLDRKE=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI=
github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI=
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/vibhansa-msft/tlru v0.0.0-20230621165448-dbd42234ad22 h1:PwqTV6gPLW3m7H47Wv0xkj47OLPnoOoFzvPInqv9mAo=
github.com/vibhansa-msft/tlru v0.0.0-20230621165448-dbd42234ad22/go.mod h1:7G2C64UXEWNr8oUzspzcrymxCjD9fKAKTGbL7zO2GW8=
github.com/wastore/keychain v0.0.0-20180920053336-f2c902a3d807 h1:Uzh85j0tl46Sf2OOx1wDePSWkz3Eq8XdCFkLXqaX8Bg=
github.com/wastore/keychain v0.0.0-20180920053336-f2c902a3d807/go.mod h1:zI8umr7xnBSyT9ZJ8wn48RiQ0EWXo4xmYLNw9FQvC9w=
github.com/wastore/keyctl v0.3.1 h1:wMkYW9y9jGbQ1ARBLGLwnDdbgrkbuSeuIQeHy+BZOU0=
github.com/wastore/keyctl v0.3.1/go.mod h1:1359RfMRDlblBSa2vaPC+kkmIxxt+rgl/FxLG38h9xM=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.150.0 h1:Z9k22qD289SZ8gCJrk4DrWXkNjtfvKAUo/l1ma8eBYE=
google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

Просмотреть файл

@ -80,7 +80,7 @@ type ObjAttr struct {
Path string // full path
Name string // base name of the path
MD5 []byte
Metadata map[string]string // extra information to preserve
Metadata map[string]*string // extra information to preserve
}
// IsDir : Test blob is a directory or not

Просмотреть файл

@ -114,7 +114,7 @@ type WriteFileOptions struct {
Handle *handlemap.Handle
Offset int64
Data []byte
Metadata map[string]string
Metadata map[string]*string
}
type GetFileBlockOffsetsOptions struct {
@ -136,7 +136,7 @@ type CopyToFileOptions struct {
type CopyFromFileOptions struct {
Name string
File *os.File
Metadata map[string]string
Metadata map[string]*string
}
type FlushFileOptions struct {

Просмотреть файл

@ -149,7 +149,7 @@ azstorage:
subdirectory: <name of subdirectory to be mounted instead of whole container>
block-size-mb: <size of each block (in MB). Default - 16 MB>
max-concurrency: <number of parallel upload/download threads. Default - 32>
tier: hot|cool|archive|none <blob-tier to be set while uploading a blob. Default - none>
tier: hot|cool|cold|premium|archive|none <blob-tier to be set while uploading a blob. Default - none>
block-list-on-mount-sec: <time list api to be blocked after mount (in sec). Default - 0 sec>
max-retries: <number of retries to attempt for any operation failure. Default - 5>
max-retry-timeout-sec: <maximum timeout allowed for a given retry (in sec). Default - 900 sec>
@ -157,7 +157,6 @@ azstorage:
max-retry-delay-sec: <maximum delay between two tries (in sec). Default - 60 sec>
http-proxy: ip-address:port <http proxy to be used for connection>
https-proxy: ip-address:port <https proxy to be used for connection>
sdk-trace: true|false <enable storage sdk logging>
fail-unsupported-op: true|false <for block blob account return failure for unsupported operations like chmod and chown>
auth-resource: <resource string to be used during OAuth token retrieval>
update-md5: true|false <set md5 sum on upload. Impacts performance. works only when file-cache component is part of the pipeline>

Просмотреть файл

@ -40,15 +40,14 @@ import (
"context"
"errors"
"log"
"net/url"
"os"
"regexp"
"testing"
"github.com/Azure/azure-storage-blob-go/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/service"
)
func getGenericCredential() (*azblob.SharedKeyCredential, error) {
func getGenericCredential() (*service.SharedKeyCredential, error) {
accountNameEnvVar := "STORAGE_ACCOUNT_NAME"
accountKeyEnvVar := "STORAGE_ACCOUNT_Key"
accountName, accountKey := os.Getenv(accountNameEnvVar), os.Getenv(accountKeyEnvVar)
@ -56,48 +55,44 @@ func getGenericCredential() (*azblob.SharedKeyCredential, error) {
if accountName == "" || accountKey == "" {
return nil, errors.New(accountNameEnvVar + " and/or " + accountKeyEnvVar + " environment variables not specified.")
}
return azblob.NewSharedKeyCredential(accountName, accountKey)
return service.NewSharedKeyCredential(accountName, accountKey)
}
func getGenericBSU() (azblob.ServiceURL, error) {
func getGenericServiceClient() (*service.Client, error) {
credential, err := getGenericCredential()
if err != nil {
return azblob.ServiceURL{}, err
return nil, err
}
pipeline := azblob.NewPipeline(credential, azblob.PipelineOptions{})
blobPrimaryURL, _ := url.Parse("https://" + credential.AccountName() + ".blob.core.windows.net/")
return azblob.NewServiceURL(*blobPrimaryURL, pipeline), nil
serviceURL := "https://" + credential.AccountName() + ".blob.core.windows.net/"
return service.NewClientWithSharedKeyCredential(serviceURL, credential, nil)
}
func TestDeleteAllTempContainers(t *testing.T) {
ctx := context.Background()
bsu, err := getGenericBSU()
svcClient, err := getGenericServiceClient()
if err != nil {
log.Fatal(err)
}
marker := azblob.Marker{}
pattern := "fuseut*"
for marker.NotDone() {
resp, err := bsu.ListContainersSegment(ctx, marker, azblob.ListContainersSegmentOptions{})
pager := svcClient.NewListContainersPager(&service.ListContainersOptions{
Prefix: to.Ptr("fuseut"),
})
for pager.More() {
resp, err := pager.NextPage(ctx)
if err != nil {
log.Fatal(err)
}
for _, v := range resp.ContainerItems {
matched, err := regexp.MatchString(pattern, v.Name)
if matched && err == nil {
containerURL := bsu.NewContainerURL(v.Name)
containerURL.Delete(ctx, azblob.ContainerAccessConditions{})
t.Log("Deleting container :", v.Name)
} else {
t.Log("Skipping container :", v.Name)
containerClient := svcClient.NewContainerClient(*v.Name)
t.Log("Deleting container :", v.Name)
_, err = containerClient.Delete(ctx, nil)
if err != nil {
t.Logf("Unable to delete %v : [%v]", v.Name, err.Error())
}
}
marker = resp.NextMarker
}
}

Просмотреть файл

@ -40,7 +40,6 @@ import (
"context"
"fmt"
"io"
"net/url"
"os"
"path"
"time"
@ -49,7 +48,9 @@ import (
"flag"
"testing"
"github.com/Azure/azure-storage-blob-go/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
)
var accountName string
@ -82,17 +83,18 @@ func TestMain(m *testing.M) {
func TestDownloadUpload(t *testing.T) {
c := azblob.NewAnonymousCredential()
p := azblob.NewPipeline(c, azblob.PipelineOptions{})
cURL, _ := url.Parse(fmt.Sprintf("https://%s.blob.core.windows.net/%s%s", accountName, containerName, sas))
containerURL := azblob.NewContainerURL(*cURL, p)
cntURL := fmt.Sprintf("https://%s.blob.core.windows.net/%s%s", accountName, containerName, sas)
containerClient, err := container.NewClientWithNoCredential(cntURL, nil)
if err != nil {
t.Log(err.Error())
}
for i := 1; i < 7; i++ {
// Generate the url
blobname := fmt.Sprintf("%s%d", filepath, i)
//filename := fmt.Sprintf("%s%s", "/mnt/ramdisk/", blobname)
filename := fmt.Sprintf("%s%s", "/mnt/ramdisk/", blobname)
blobURL := containerURL.NewBlockBlobURL(path.Base(blobname))
blobClient := containerClient.NewBlockBlobClient(path.Base(blobname))
t.Log("----------------------------------------------------------------------")
t.Log("Next test file ", filename)
@ -104,15 +106,11 @@ func TestDownloadUpload(t *testing.T) {
t.Log("download : ", filename)
time1 := time.Now()
err = azblob.DownloadBlobToFile(
context.Background(),
blobURL.BlobURL,
0, 0,
file,
azblob.DownloadFromBlobOptions{
BlockSize: 8 * 1024 * 1024,
Parallelism: 64,
})
_, err = blobClient.DownloadFile(context.Background(), file, &blob.DownloadFileOptions{
Range: blob.HTTPRange{Offset: 0, Count: 0},
BlockSize: 8 * 1024 * 1024,
Concurrency: 64,
})
if err != nil {
t.Log(err.Error())
}
@ -134,14 +132,10 @@ func TestDownloadUpload(t *testing.T) {
t.Log("upload : ", filename)
time1 = time.Now()
_, err = azblob.UploadFileToBlockBlob(
context.Background(),
file,
blobURL,
azblob.UploadToBlockBlobOptions{
BlockSize: 8 * 1024 * 1024,
Parallelism: 64,
})
_, err = blobClient.UploadFile(context.Background(), file, &blockblob.UploadFileOptions{
BlockSize: 8 * 1024 * 1024,
Concurrency: 64,
})
if err != nil {
t.Log(err.Error())
}

1
testdata/config/azure_block_perf.yaml поставляемый
Просмотреть файл

@ -35,6 +35,5 @@ azstorage:
account-key: { NIGHTLY_STO_ACC_KEY }
mode: key
container: { 0 }
sdk-trace: false
block-list-on-mount-sec: 10
ignore-access-modify: true

1
testdata/config/azure_key.yaml поставляемый
Просмотреть файл

@ -34,4 +34,3 @@ azstorage:
mode: key
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }

1
testdata/config/azure_key_bc.yaml поставляемый
Просмотреть файл

@ -38,4 +38,3 @@ azstorage:
mode: key
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }

1
testdata/config/azure_key_directio.yaml поставляемый
Просмотреть файл

@ -31,4 +31,3 @@ azstorage:
mode: key
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }

1
testdata/config/azure_key_emptyfile.yaml поставляемый
Просмотреть файл

@ -35,4 +35,3 @@ azstorage:
mode: key
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }

1
testdata/config/azure_key_hmon.yaml поставляемый
Просмотреть файл

@ -34,7 +34,6 @@ azstorage:
mode: key
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }
health_monitor:
enable-monitoring: true

1
testdata/config/azure_key_huge.yaml поставляемый
Просмотреть файл

@ -37,4 +37,3 @@ azstorage:
container: { 0 }
tier: hot
block-list-on-mount-sec: 7
sdk-trace: { VERBOSE_LOG }

1
testdata/config/azure_key_lfu.yaml поставляемый
Просмотреть файл

@ -34,4 +34,3 @@ azstorage:
mode: key
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }

1
testdata/config/azure_key_lru_purge.yaml поставляемый
Просмотреть файл

@ -33,4 +33,3 @@ azstorage:
mode: key
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }

1
testdata/config/azure_key_perf.yaml поставляемый
Просмотреть файл

@ -34,6 +34,5 @@ azstorage:
account-key: { NIGHTLY_STO_ACC_KEY }
mode: key
container: { 0 }
sdk-trace: false
block-list-on-mount-sec: 10
ignore-access-modify: true

3
testdata/config/azure_key_proxy.yaml поставляемый
Просмотреть файл

@ -34,5 +34,4 @@ azstorage:
mode: key
container: { 0 }
tier: hot
https-proxy: 127.0.0.1:8080
sdk-trace: { VERBOSE_LOG }
https-proxy: 127.0.0.1:8080

1
testdata/config/azure_key_symlink.yaml поставляемый
Просмотреть файл

@ -35,4 +35,3 @@ azstorage:
mode: key
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }

3
testdata/config/azure_msi.yaml поставляемый
Просмотреть файл

@ -33,5 +33,4 @@ azstorage:
appid: { NIGHTLY_MSI_APP_ID }
mode: msi
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }
tier: hot

3
testdata/config/azure_msi_sysid.yaml поставляемый
Просмотреть файл

@ -30,5 +30,4 @@ azstorage:
account-name: { NIGHTLY_STO_BLOB_ACC_NAME }
mode: msi
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }
tier: hot

3
testdata/config/azure_sas.yaml поставляемый
Просмотреть файл

@ -33,5 +33,4 @@ azstorage:
sas: { NIGHTLY_STO_ACC_SAS }
mode: sas
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }
tier: hot

1
testdata/config/azure_sas_proxy.yaml поставляемый
Просмотреть файл

@ -35,5 +35,4 @@ azstorage:
container: { 0 }
tier: hot
https-proxy: 127.0.0.1:8080
sdk-trace: { VERBOSE_LOG }

3
testdata/config/azure_spn.yaml поставляемый
Просмотреть файл

@ -35,5 +35,4 @@ azstorage:
tenantid: { NIGHTLY_SPN_TENANT_ID }
clientsecret: { NIGHTLY_SPN_CLIENT_SECRET }
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }
tier: hot

3
testdata/config/azure_spn_proxy.yaml поставляемый
Просмотреть файл

@ -36,5 +36,4 @@ azstorage:
clientsecret: { NIGHTLY_SPN_CLIENT_SECRET }
container: { 0 }
tier: hot
https-proxy: 127.0.0.1:8080
sdk-trace: { VERBOSE_LOG }
https-proxy: 127.0.0.1:8080

3
testdata/config/azure_stream.yaml поставляемый
Просмотреть файл

@ -31,5 +31,4 @@ azstorage:
account-key: { NIGHTLY_STO_ACC_KEY }
mode: key
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }
tier: hot

3
testdata/config/azure_stream_direct.yaml поставляемый
Просмотреть файл

@ -29,5 +29,4 @@ azstorage:
account-key: { NIGHTLY_STO_ACC_KEY }
mode: key
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }
tier: hot

3
testdata/config/azure_stream_filename.yaml поставляемый
Просмотреть файл

@ -32,5 +32,4 @@ azstorage:
account-key: { NIGHTLY_STO_ACC_KEY }
mode: key
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }
tier: hot

Просмотреть файл

@ -30,5 +30,4 @@ azstorage:
account-key: { NIGHTLY_STO_ACC_KEY }
mode: key
container: { 0 }
tier: hot
sdk-trace: { VERBOSE_LOG }
tier: hot