13 "github.com/Azure/azure-sdk-for-go/storage"
17 azureStorageAccountName string
18 azureStorageAccountKeyFile string
21 type azureVolumeAdder struct {
25 func (s *azureVolumeAdder) Set(containerName string) error {
26 if containerName == "" {
27 return errors.New("no container name given")
29 buf, err := ioutil.ReadFile(azureStorageAccountKeyFile)
31 return errors.New("reading key from " + azureStorageAccountKeyFile + ": " + err.Error())
33 accountKey := strings.TrimSpace(string(buf))
35 return errors.New("empty account key in " + azureStorageAccountKeyFile)
37 azClient, err := storage.NewBasicClient(azureStorageAccountName, accountKey)
39 return errors.New("creating Azure storage client: " + err.Error())
42 log.Print("Notice: -serialize is not supported by azure-blob-container volumes.")
44 v := NewAzureBlobVolume(azClient, containerName, flagReadonly)
45 if err := v.Check(); err != nil {
48 *s.volumeSet = append(*s.volumeSet, v)
53 flag.Var(&azureVolumeAdder{&volumes},
54 "azure-storage-container-volume",
55 "Use the given container as a storage volume. Can be given multiple times.")
57 &azureStorageAccountName,
58 "azure-storage-account-name",
60 "Azure storage account name used for subsequent --azure-storage-container-volume arguments.")
62 &azureStorageAccountKeyFile,
63 "azure-storage-account-key-file",
65 "File containing the account key used for subsequent --azure-storage-container-volume arguments.")
68 // An AzureBlobVolume stores and retrieves blocks in an Azure Blob
70 type AzureBlobVolume struct {
71 azClient storage.Client
72 bsClient storage.BlobStorageClient
77 func NewAzureBlobVolume(client storage.Client, containerName string, readonly bool) *AzureBlobVolume {
78 return &AzureBlobVolume{
80 bsClient: client.GetBlobService(),
81 containerName: containerName,
86 // Check returns nil if the volume is usable.
87 func (v *AzureBlobVolume) Check() error {
88 ok, err := v.bsClient.ContainerExists(v.containerName)
93 return errors.New("container does not exist")
98 func (v *AzureBlobVolume) Get(loc string) ([]byte, error) {
99 rdr, err := v.bsClient.GetBlob(v.containerName, loc)
104 buf := bufs.Get(BlockSize)
105 n, err := io.ReadFull(rdr, buf)
107 case io.EOF, io.ErrUnexpectedEOF:
115 func (v *AzureBlobVolume) Compare(loc string, data []byte) error {
119 func (v *AzureBlobVolume) Put(loc string, block []byte) error {
120 if err := v.bsClient.CreateBlockBlob(v.containerName, loc); err != nil {
123 // We use the same block ID, base64("0")=="MA==", for everything.
124 if err := v.bsClient.PutBlock(v.containerName, loc, "MA==", block); err != nil {
127 return v.bsClient.PutBlockList(v.containerName, loc, []storage.Block{{"MA==", storage.BlockStatusUncommitted}})
130 func (v *AzureBlobVolume) Touch(loc string) error {
134 func (v *AzureBlobVolume) Mtime(loc string) (time.Time, error) {
135 return time.Time{}, NotFoundError
138 func (v *AzureBlobVolume) IndexTo(prefix string, writer io.Writer) error {
142 func (v *AzureBlobVolume) Delete(loc string) error {
146 func (v *AzureBlobVolume) Status() *VolumeStatus {
147 return &VolumeStatus{
149 BytesFree: BlockSize * 1000,
154 func (v *AzureBlobVolume) String() string {
155 return fmt.Sprintf("azure-storage-container:%+q", v.containerName)
158 func (v *AzureBlobVolume) Writable() bool {