1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
17 18 19 20 21 22 23 24 25 26 27 28 29 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
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
109
110
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 }