upload/azure: move UploadImage under a new StorageClient struct

We will soon introduce new methods to the storage client.

Signed-off-by: Ondřej Budai <ondrej@budai.cz>
This commit is contained in:
Ondřej Budai 2021-03-02 09:57:11 +01:00 committed by Tom Gundersen
parent f67ca8b616
commit 478f69e092
4 changed files with 71 additions and 51 deletions

View file

@ -37,13 +37,20 @@ func main() {
fmt.Println("Image to upload is:", fileName)
err := azure.UploadImage(azure.Credentials{
StorageAccount: storageAccount,
StorageAccessKey: storageAccessKey,
}, azure.ImageMetadata{
ImageName: path.Base(fileName),
ContainerName: containerName,
}, fileName, threads)
c, err := azure.NewStorageClient(storageAccount, storageAccessKey)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = c.UploadImage(
azure.ImageMetadata{
ImageName: path.Base(fileName),
ContainerName: containerName,
},
fileName,
threads,
)
if err != nil {
fmt.Println("Error: ", err)

View file

@ -227,18 +227,20 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
if !osbuildOutput.Success {
continue
}
credentials := azure.Credentials{
StorageAccount: options.StorageAccount,
StorageAccessKey: options.StorageAccessKey,
azureStorageClient, err := azure.NewStorageClient(options.StorageAccount, options.StorageAccessKey)
if err != nil {
r = append(r, err)
continue
}
metadata := azure.ImageMetadata{
ContainerName: options.Container,
ImageName: t.ImageName,
}
const azureMaxUploadGoroutines = 4
err := azure.UploadImage(
credentials,
err = azureStorageClient.UploadImage(
metadata,
path.Join(outputDirectory, options.Filename),
azureMaxUploadGoroutines,

View file

@ -33,14 +33,15 @@ func wrapErrorf(innerError error, format string, a ...interface{}) error {
}
type azureCredentials struct {
azure.Credentials
ContainerName string
SubscriptionID string
ClientID string
ClientSecret string
TenantID string
Location string
ResourceGroup string
StorageAccount string
StorageAccessKey string
ContainerName string
SubscriptionID string
ClientID string
ClientSecret string
TenantID string
Location string
ResourceGroup string
}
// getAzureCredentialsFromEnv gets the credentials from environment variables
@ -67,17 +68,15 @@ func GetAzureCredentialsFromEnv() (*azureCredentials, error) {
}
return &azureCredentials{
Credentials: azure.Credentials{
StorageAccount: storageAccount,
StorageAccessKey: storageAccessKey,
},
ContainerName: containerName,
SubscriptionID: subscriptionId,
ClientID: clientId,
ClientSecret: clientSecret,
TenantID: tenantId,
Location: location,
ResourceGroup: resourceGroup,
StorageAccount: storageAccount,
StorageAccessKey: storageAccessKey,
ContainerName: containerName,
SubscriptionID: subscriptionId,
ClientID: clientId,
ClientSecret: clientSecret,
TenantID: tenantId,
Location: location,
ResourceGroup: resourceGroup,
}, nil
}
@ -87,7 +86,11 @@ func UploadImageToAzure(c *azureCredentials, imagePath string, imageName string)
ContainerName: c.ContainerName,
ImageName: imageName,
}
err := azure.UploadImage(c.Credentials, metadata, imagePath, 16)
client, err := azure.NewStorageClient(c.StorageAccount, c.StorageAccessKey)
if err != nil {
return err
}
err = client.UploadPageBlob(metadata, imagePath, 16)
if err != nil {
return fmt.Errorf("upload to azure failed: %v", err)
}

View file

@ -13,47 +13,55 @@ import (
"strings"
"sync"
"github.com/Azure/azure-pipeline-go/pipeline"
"github.com/Azure/azure-storage-blob-go/azblob"
)
// Credentials contains credentials to connect to your account
// It uses so called "Client credentials", see the official documentation for more information:
// https://docs.microsoft.com/en-us/azure/go/azure-sdk-go-authorization#available-authentication-types-and-methods
type Credentials struct {
StorageAccount string
StorageAccessKey string
// StorageClient is a client for the Azure Storage API,
// see the docs: https://docs.microsoft.com/en-us/rest/api/storageservices/
type StorageClient struct {
pipeline pipeline.Pipeline
}
// NewStorageClient creates a new client for Azure Storage API.
// See the following keys how to retrieve the storageAccessKey using the
// Azure's API:
// https://docs.microsoft.com/en-us/rest/api/storagerp/storageaccounts/listkeys
func NewStorageClient(storageAccount, storageAccessKey string) (*StorageClient, error) {
credential, err := azblob.NewSharedKeyCredential(storageAccount, storageAccessKey)
if err != nil {
return nil, fmt.Errorf("cannot create shared key credential: %v", err)
}
p := azblob.NewPipeline(credential, azblob.PipelineOptions{})
return &StorageClient{
pipeline: p,
}, nil
}
// ImageMetadata contains information needed to store the image in a proper place.
// In case of Azure cloud storage this includes container name and blob name.
type ImageMetadata struct {
ContainerName string
ImageName string
StorageAccount string
ContainerName string
ImageName string
}
// UploadImage takes the metadata and credentials required to upload the image specified by `fileName`
// It can speed up the upload by using goroutines. The number of parallel goroutines is bounded by
// the `threads` argument.
func UploadImage(credentials Credentials, metadata ImageMetadata, fileName string, threads int) error {
func (c StorageClient) UploadImage(metadata ImageMetadata, fileName string, threads int) error {
// Azure cannot create an image from a storage blob without .vhd extension
if !strings.HasSuffix(metadata.ImageName, ".vhd") {
metadata.ImageName = metadata.ImageName + ".vhd"
}
// Create a default request pipeline using your storage account name and account key.
credential, err := azblob.NewSharedKeyCredential(credentials.StorageAccount, credentials.StorageAccessKey)
if err != nil {
return fmt.Errorf("cannot create azure credentials: %v", err)
}
p := azblob.NewPipeline(credential, azblob.PipelineOptions{})
// get storage account blob service URL endpoint.
URL, _ := url.Parse(fmt.Sprintf("https://%s.blob.core.windows.net/%s", credentials.StorageAccount, metadata.ContainerName))
URL, _ := url.Parse(fmt.Sprintf("https://%s.blob.core.windows.net/%s", metadata.StorageAccount, metadata.ContainerName))
// Create a ContainerURL object that wraps the container URL and a request
// pipeline to make requests.
containerURL := azblob.NewContainerURL(*URL, p)
containerURL := azblob.NewContainerURL(*URL, c.pipeline)
// Create the container, use a never-expiring context
ctx := context.Background()