GO SDK track2 migration (#1380)
This commit is contained in:
Родитель
0efccdc3ab
Коммит
8e06e67633
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -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**
|
||||
|
@ -12,7 +19,6 @@
|
|||
- 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**
|
||||
- Invalidate attribute cache entry on `PathAlreadyExists` error in create directory operation.
|
||||
|
|
19621
NOTICE
19621
NOTICE
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
2
TSG.md
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
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
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())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -34,4 +34,3 @@ azstorage:
|
|||
mode: key
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
||||
|
|
|
@ -38,4 +38,3 @@ azstorage:
|
|||
mode: key
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
||||
|
|
|
@ -31,4 +31,3 @@ azstorage:
|
|||
mode: key
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
||||
|
|
|
@ -35,4 +35,3 @@ azstorage:
|
|||
mode: key
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
||||
|
|
|
@ -34,7 +34,6 @@ azstorage:
|
|||
mode: key
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
||||
|
||||
health_monitor:
|
||||
enable-monitoring: true
|
||||
|
|
|
@ -37,4 +37,3 @@ azstorage:
|
|||
container: { 0 }
|
||||
tier: hot
|
||||
block-list-on-mount-sec: 7
|
||||
sdk-trace: { VERBOSE_LOG }
|
||||
|
|
|
@ -34,4 +34,3 @@ azstorage:
|
|||
mode: key
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
||||
|
|
|
@ -33,4 +33,3 @@ azstorage:
|
|||
mode: key
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -35,4 +35,3 @@ azstorage:
|
|||
container: { 0 }
|
||||
tier: hot
|
||||
https-proxy: 127.0.0.1:8080
|
||||
sdk-trace: { VERBOSE_LOG }
|
|
@ -35,4 +35,3 @@ azstorage:
|
|||
mode: key
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
||||
|
|
|
@ -34,4 +34,3 @@ azstorage:
|
|||
mode: msi
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
|
@ -31,4 +31,3 @@ azstorage:
|
|||
mode: msi
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
|
@ -34,4 +34,3 @@ azstorage:
|
|||
mode: sas
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
|
@ -35,5 +35,4 @@ azstorage:
|
|||
container: { 0 }
|
||||
tier: hot
|
||||
https-proxy: 127.0.0.1:8080
|
||||
sdk-trace: { VERBOSE_LOG }
|
||||
|
|
@ -36,4 +36,3 @@ azstorage:
|
|||
clientsecret: { NIGHTLY_SPN_CLIENT_SECRET }
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
|
@ -37,4 +37,3 @@ azstorage:
|
|||
container: { 0 }
|
||||
tier: hot
|
||||
https-proxy: 127.0.0.1:8080
|
||||
sdk-trace: { VERBOSE_LOG }
|
|
@ -32,4 +32,3 @@ azstorage:
|
|||
mode: key
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
|
@ -30,4 +30,3 @@ azstorage:
|
|||
mode: key
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
|
@ -33,4 +33,3 @@ azstorage:
|
|||
mode: key
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
|
@ -31,4 +31,3 @@ azstorage:
|
|||
mode: key
|
||||
container: { 0 }
|
||||
tier: hot
|
||||
sdk-trace: { VERBOSE_LOG }
|
Загрузка…
Ссылка в новой задаче