9005: Rename ClearCache to RefreshServiceDiscovery
[arvados.git] / services / keepstore / azure_blob_volume.go
index 383759803ccdbe55169f63737651aadfcb11f7c7..3090b95cb22909614c909d1e8b4b56cffe4e0c40 100644 (file)
@@ -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