// Copyright 2019 Drone.IO Inc. All rights reserved. // Use of this source code is governed by the Drone Non-Commercial License // that can be found in the LICENSE file. // +build !oss package logs import ( "context" "fmt" "io" "net/url" "github.com/Azure/azure-storage-blob-go/azblob" "github.com/drone/drone/core" ) // NewAzureBlobEnv returns a new Azure blob log store. func NewAzureBlobEnv(containerName, storageAccountName, storageAccessKey string) core.LogStore { return &azureBlobStore{ containerName: containerName, storageAccountName: storageAccountName, storageAccessKey: storageAccessKey, containerURL: nil, } } type azureBlobStore struct { containerName string storageAccountName string storageAccessKey string containerURL *azblob.ContainerURL } func (az *azureBlobStore) Find(ctx context.Context, step int64) (io.ReadCloser, error) { err := az.getContainerURL() if err != nil { return nil, err } blobURL := az.containerURL.NewBlockBlobURL(fmt.Sprintf("%d", step)) out, err := blobURL.Download(ctx, 0, azblob.CountToEnd, azblob.BlobAccessConditions{}, false) if err != nil { return nil, err } return out.Body(azblob.RetryReaderOptions{}), nil } func (az *azureBlobStore) Create(ctx context.Context, step int64, r io.Reader) error { err := az.getContainerURL() if err != nil { return err } opts := &azblob.UploadStreamToBlockBlobOptions{ BufferSize: 4 * 1024 * 1024, MaxBuffers: 5, } blobURL := az.containerURL.NewBlockBlobURL(fmt.Sprintf("%d", step)) _, err = azblob.UploadStreamToBlockBlob(ctx, r, blobURL, *opts) return err } func (az *azureBlobStore) Update(ctx context.Context, step int64, r io.Reader) error { return az.Create(ctx, step, r) } func (az *azureBlobStore) Delete(ctx context.Context, step int64) error { err := az.getContainerURL() if err != nil { return err } blobURL := az.containerURL.NewBlockBlobURL(fmt.Sprintf("%d", step)) _, err = blobURL.Delete(ctx, azblob.DeleteSnapshotsOptionInclude, azblob.BlobAccessConditions{}) return err } func (az *azureBlobStore) getContainerURL() error { if az.containerURL != nil { return nil } if len(az.storageAccountName) == 0 || len(az.storageAccessKey) == 0 { return fmt.Errorf("Either the storage account or storage access key environment variable is not set") } credential, err := azblob.NewSharedKeyCredential(az.storageAccountName, az.storageAccessKey) if err != nil { return err } p := azblob.NewPipeline(credential, azblob.PipelineOptions{}) URL, err := url.Parse(fmt.Sprintf("https://%s.blob.core.windows.net/%s", az.storageAccountName, az.containerName)) if err != nil { return err } containerURL := azblob.NewContainerURL(*URL, p) az.containerURL = &containerURL return nil }