10877: Configurable base URL for Azure storage, e.g., StorageBaseURL: core.usgovcloud...
[arvados.git] / services / keepstore / azure_blob_volume.go
index 383759803ccdbe55169f63737651aadfcb11f7c7..a28f8b7f732ba1c2df8e862b6fceb9d9b7aaf604 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{
@@ -156,7 +137,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)
        }
@@ -652,6 +636,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 +676,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