X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/3121f0dfb9262ccd50d0637c9f7cedf9191f69bf..75e00445b6de230493e9ee37483dd4c469db29b1:/services/keepstore/azure_blob_volume.go diff --git a/services/keepstore/azure_blob_volume.go b/services/keepstore/azure_blob_volume.go index 383759803c..3090b95cb2 100644 --- a/services/keepstore/azure_blob_volume.go +++ b/services/keepstore/azure_blob_volume.go @@ -97,6 +97,7 @@ func init() { type AzureBlobVolume struct { StorageAccountName string StorageAccountKeyFile string + StorageBaseURL string // "" means default, "core.windows.net" ContainerName string AzureReplication int ReadOnly bool @@ -106,26 +107,6 @@ type AzureBlobVolume struct { bsClient *azureBlobClient } -// azureBlobClient wraps storage.BlobStorageClient in order to count -// I/O and API usage stats. -type azureBlobClient struct { - client *storage.BlobStorageClient - stats azureBlobStats -} - -type azureBlobStats struct { - statsTicker - Ops uint64 - GetOps uint64 - GetRangeOps uint64 - CreateOps uint64 - SetMetadataOps uint64 - DelOps uint64 - ListOps uint64 - - lock sync.Mutex -} - // Examples implements VolumeWithExamples. func (*AzureBlobVolume) Examples() []Volume { return []Volume{ @@ -136,6 +117,14 @@ func (*AzureBlobVolume) Examples() []Volume { AzureReplication: 3, RequestTimeout: azureDefaultRequestTimeout, }, + &AzureBlobVolume{ + StorageAccountName: "cn-account-name", + StorageAccountKeyFile: "/etc/azure_cn_storage_account_key.txt", + StorageBaseURL: "core.chinacloudapi.cn", + ContainerName: "cn-container-name", + AzureReplication: 3, + RequestTimeout: azureDefaultRequestTimeout, + }, } } @@ -156,7 +145,10 @@ func (v *AzureBlobVolume) Start() error { if err != nil { return err } - v.azClient, err = storage.NewBasicClient(v.StorageAccountName, accountKey) + if v.StorageBaseURL == "" { + v.StorageBaseURL = storage.DefaultBaseURL + } + v.azClient, err = storage.NewClient(v.StorageAccountName, accountKey, v.StorageBaseURL, storage.DefaultAPIVersion, true) if err != nil { return fmt.Errorf("creating Azure storage client: %s", err) } @@ -182,6 +174,11 @@ func (v *AzureBlobVolume) Start() error { return nil } +// DeviceID returns a globally unique ID for the storage container. +func (v *AzureBlobVolume) DeviceID() string { + return "azure://" + v.StorageBaseURL + "/" + v.StorageAccountName + "/" + v.ContainerName +} + // Return true if expires_at metadata attribute is found on the block func (v *AzureBlobVolume) checkTrashed(loc string) (bool, map[string]string, error) { metadata, err := v.bsClient.GetBlobMetadata(v.ContainerName, loc) @@ -652,6 +649,38 @@ func (v *AzureBlobVolume) InternalStats() interface{} { return &v.bsClient.stats } +type azureBlobStats struct { + statsTicker + Ops uint64 + GetOps uint64 + GetRangeOps uint64 + GetMetadataOps uint64 + GetPropertiesOps uint64 + CreateOps uint64 + SetMetadataOps uint64 + DelOps uint64 + ListOps uint64 +} + +func (s *azureBlobStats) TickErr(err error) { + if err == nil { + return + } + errType := fmt.Sprintf("%T", err) + if err, ok := err.(storage.AzureStorageServiceError); ok { + errType = errType + fmt.Sprintf(" %d (%s)", err.StatusCode, err.Code) + } + log.Printf("errType %T, err %s", err, err) + s.statsTicker.TickErr(err, errType) +} + +// azureBlobClient wraps storage.BlobStorageClient in order to count +// I/O and API usage stats. +type azureBlobClient struct { + client *storage.BlobStorageClient + stats azureBlobStats +} + func (c *azureBlobClient) ContainerExists(cname string) (bool, error) { c.stats.Tick(&c.stats.Ops) ok, err := c.client.ContainerExists(cname) @@ -660,14 +689,14 @@ func (c *azureBlobClient) ContainerExists(cname string) (bool, error) { } func (c *azureBlobClient) GetBlobMetadata(cname, bname string) (map[string]string, error) { - c.stats.Tick(&c.stats.Ops) + c.stats.Tick(&c.stats.Ops, &c.stats.GetMetadataOps) m, err := c.client.GetBlobMetadata(cname, bname) c.stats.TickErr(err) return m, err } func (c *azureBlobClient) GetBlobProperties(cname, bname string) (*storage.BlobProperties, error) { - c.stats.Tick(&c.stats.Ops) + c.stats.Tick(&c.stats.Ops, &c.stats.GetPropertiesOps) p, err := c.client.GetBlobProperties(cname, bname) c.stats.TickErr(err) return p, err