Merge pull request #2788 from Lucretius/azure-blob-logs

Add support for primary store of Azure blob
This commit is contained in:
Brad Rydzewski 2019-08-20 11:55:01 -07:00 committed by GitHub
commit d581dab302
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 159 additions and 10 deletions

View file

@ -49,6 +49,7 @@ type (
Authn Authentication Authn Authentication
Agent Agent Agent Agent
AzureBlob AzureBlob
Cron Cron Cron Cron
Cloning Cloning Cloning Cloning
Database Database Database Database
@ -362,6 +363,13 @@ type (
PathStyle bool `envconfig:"DRONE_S3_PATH_STYLE"` PathStyle bool `envconfig:"DRONE_S3_PATH_STYLE"`
} }
//AzureBlob providers the storage configuration.
AzureBlob struct {
ContainerName string `envconfig:"DRONE_AZURE_BLOB_CONTAINER_NAME"`
StorageAccountName string `envconfig:"DRONE_AZURE_STORAGE_ACCOUNT_NAME"`
StorageAccessKey string `envconfig:"DRONE_AZURE_STORAGE_ACCESS_KEY"`
}
// HTTP provides http configuration. // HTTP provides http configuration.
HTTP struct { HTTP struct {
AllowedHosts []string `envconfig:"DRONE_HTTP_ALLOWED_HOSTS"` AllowedHosts []string `envconfig:"DRONE_HTTP_ALLOWED_HOSTS"`

View file

@ -81,17 +81,25 @@ func provideBuildStore(db *db.DB) core.BuildStore {
// provideLogStore is a Wire provider function that provides a // provideLogStore is a Wire provider function that provides a
// log datastore, configured from the environment. // log datastore, configured from the environment.
func provideLogStore(db *db.DB, config config.Config) core.LogStore { func provideLogStore(db *db.DB, config config.Config) core.LogStore {
if config.S3.Bucket == "" {
return logs.New(db)
}
s := logs.New(db) s := logs.New(db)
p := logs.NewS3Env( if config.S3.Bucket != "" {
config.S3.Bucket, p := logs.NewS3Env(
config.S3.Prefix, config.S3.Bucket,
config.S3.Endpoint, config.S3.Prefix,
config.S3.PathStyle, config.S3.Endpoint,
) config.S3.PathStyle,
return logs.NewCombined(p, s) )
return logs.NewCombined(p, s)
}
if config.AzureBlob.ContainerName != "" {
p := logs.NewAzureBlobEnv(
config.AzureBlob.ContainerName,
config.AzureBlob.StorageAccountName,
config.AzureBlob.StorageAccessKey,
)
return logs.NewCombined(p, s)
}
return s
} }
// provideStageStore is a Wire provider function that provides a // provideStageStore is a Wire provider function that provides a

1
go.mod
View file

@ -3,6 +3,7 @@ module github.com/drone/drone
require ( require (
docker.io/go-docker v1.0.0 docker.io/go-docker v1.0.0
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e
github.com/Azure/azure-storage-blob-go v0.7.0
github.com/Microsoft/go-winio v0.4.11 github.com/Microsoft/go-winio v0.4.11
github.com/asaskevich/govalidator v0.0.0-20180315120708-ccb8e960c48f github.com/asaskevich/govalidator v0.0.0-20180315120708-ccb8e960c48f
github.com/aws/aws-sdk-go v1.15.57 github.com/aws/aws-sdk-go v1.15.57

8
go.sum
View file

@ -2,6 +2,10 @@ docker.io/go-docker v1.0.0 h1:VdXS/aNYQxyA9wdLD5z8Q8Ro688/hG8HzKxYVEVbE6s=
docker.io/go-docker v1.0.0/go.mod h1:7tiAn5a0LFmjbPDbyTPOaTTOuG1ZRNXdPA6RvKY+fpY= docker.io/go-docker v1.0.0/go.mod h1:7tiAn5a0LFmjbPDbyTPOaTTOuG1ZRNXdPA6RvKY+fpY=
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e h1:rl2Aq4ZODqTDkeSqQBy+fzpZPamacO1Srp8zq7jf2Sc= github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e h1:rl2Aq4ZODqTDkeSqQBy+fzpZPamacO1Srp8zq7jf2Sc=
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e/go.mod h1:Xa6lInWHNQnuWoF0YPSsx+INFA9qk7/7pTjwb3PInkY= github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e/go.mod h1:Xa6lInWHNQnuWoF0YPSsx+INFA9qk7/7pTjwb3PInkY=
github.com/Azure/azure-pipeline-go v0.2.1 h1:OLBdZJ3yvOn2MezlWvbrBMTEUQC72zAftRZOMdj5HYo=
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
github.com/Azure/azure-storage-blob-go v0.7.0 h1:MuueVOYkufCxJw5YZzF842DY2MBsp+hLuh2apKY0mck=
github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -178,6 +182,8 @@ github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uP
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6 h1:qCv4319q2q7XKn0MQbi8p37hsJ+9Xo8e6yojA73JVxk= github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6 h1:qCv4319q2q7XKn0MQbi8p37hsJ+9Xo8e6yojA73JVxk=
github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6/go.mod h1:fXcdFsQoipQa7mwORhKad5jmDCeSy/RCGzWA08PO0lM= github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6/go.mod h1:fXcdFsQoipQa7mwORhKad5jmDCeSy/RCGzWA08PO0lM=
github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/nomad v0.0.0-20190125003214-134391155854 h1:L7WhLZt2ory/kQWxqkMwOiBpIoa4BWoadN7yx8LHEtk= github.com/hashicorp/nomad v0.0.0-20190125003214-134391155854 h1:L7WhLZt2ory/kQWxqkMwOiBpIoa4BWoadN7yx8LHEtk=
@ -200,6 +206,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149 h1:HfxbT6/JcvIljmERptWhwa8XzP7H3T+Z2N26gTsaDaA=
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=

100
store/logs/azureblob.go Normal file
View file

@ -0,0 +1,100 @@
// 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
}

View file

@ -0,0 +1,24 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build oss
package logs
import "github.com/drone/drone/core"
// New returns a zero value LogStore.
func NewAzureBlobEnv(containerName, storageAccountName, storageAccessKey string) core.LogStore {
return nil
}