Home Download Docs Code Community
     1	/*
     2	Copyright 2014 The Perkeep Authors
     3	
     4	Licensed under the Apache License, Version 2.0 (the "License");
     5	you may not use this file except in compliance with the License.
     6	You may obtain a copy of the License at
     7	
     8	     http://www.apache.org/licenses/LICENSE-2.0
     9	
    10	Unless required by applicable law or agreed to in writing, software
    11	distributed under the License is distributed on an "AS IS" BASIS,
    12	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13	See the License for the specific language governing permissions and
    14	limitations under the License.
    15	*/
    16	
    17	/*
    18	Package azure registers the "azure" blobserver storage type, storing
    19	blobs in a Microsoft Azure Blob Storage container.
    20	
    21	Example low-level config:
    22	
    23		"/r1/": {
    24		    "handler": "storage-azure",
    25		    "handlerArgs": {
    26		       "container": "foo",
    27		       "azure_account": "...",
    28		       "azure_access_key": "...",
    29		       "skipStartupCheck": false
    30		     }
    31		},
    32	*/
    33	package azure
    34	
    35	import (
    36		"context"
    37		"encoding/base64"
    38		"fmt"
    39	
    40		"go4.org/jsonconfig"
    41		"perkeep.org/internal/azure/storage"
    42		"perkeep.org/pkg/blob"
    43		"perkeep.org/pkg/blobserver"
    44		"perkeep.org/pkg/blobserver/memory"
    45		"perkeep.org/pkg/constants"
    46	)
    47	
    48	var (
    49		_ blob.SubFetcher               = (*azureStorage)(nil)
    50		_ blobserver.MaxEnumerateConfig = (*azureStorage)(nil)
    51	)
    52	
    53	type azureStorage struct {
    54		azureClient *storage.Client
    55		container   string
    56		hostname    string
    57		cache       *memory.Storage // or nil for no cache
    58	}
    59	
    60	func (s *azureStorage) String() string {
    61		return fmt.Sprintf("\"azure\" blob storage at host %q, container %q", s.hostname, s.container)
    62	}
    63	
    64	func newFromConfig(_ blobserver.Loader, config jsonconfig.Obj) (blobserver.Storage, error) {
    65		hostname := config.OptionalString("hostname", "")
    66		cacheSize := config.OptionalInt64("cacheSize", 32<<20)
    67	
    68		AccessKey := make([]byte, 66)
    69		i, err := base64.StdEncoding.Decode(AccessKey, []byte(config.RequiredString("azure_access_key")))
    70		if err != nil {
    71			panic(err)
    72		}
    73		AccessKey = AccessKey[:i]
    74		client := &storage.Client{
    75			Auth: &storage.Auth{
    76				Account:   config.RequiredString("azure_account"),
    77				AccessKey: AccessKey,
    78			},
    79			Hostname: hostname,
    80		}
    81		sto := &azureStorage{
    82			azureClient: client,
    83			container:   config.RequiredString("container"),
    84			hostname:    hostname,
    85		}
    86		skipStartupCheck := config.OptionalBool("skipStartupCheck", false)
    87		if err := config.Validate(); err != nil {
    88			return nil, err
    89		}
    90		if cacheSize != 0 {
    91			sto.cache = memory.NewCache(cacheSize)
    92		}
    93		if !skipStartupCheck {
    94			_, err := client.ListBlobs(context.TODO(), sto.container, 1)
    95			if serr, ok := err.(*storage.Error); ok {
    96				if serr.AzureError.Code == "ContainerNotFound" {
    97					return nil, fmt.Errorf("container %q doesn't exist", sto.container)
    98				}
    99				return nil, fmt.Errorf("error listing container %s: %v", sto.container, serr)
   100			} else if err != nil {
   101				return nil, fmt.Errorf("error listing container %s: %v", sto.container, err)
   102			}
   103		}
   104		return sto, nil
   105	}
   106	
   107	func init() {
   108		// It's assumed the MaxBlobSize won't change in the foreseeable future.
   109		// However, just in case it does, let's be aware that the current implementation doesn't support it.
   110		// Azure itself can support it by splitting up requests in multiple parts but that's more work which is not yet needed.
   111		if constants.MaxBlobSize > 64000000 {
   112			panic("Blob sizes over 64mb aren't supported by Azure")
   113		}
   114		blobserver.RegisterStorageConstructor("azure", blobserver.StorageConstructor(newFromConfig))
   115	}
Website layout inspired by memcached.
Content by the authors.