Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import store = require('artifact-engine/Store');
import tl = require('azure-pipelines-task-lib/task');
import { BlobItem, BlobServiceClient, ContainerClient, StorageSharedKeyCredential } from '@azure/storage-blob';
import abortController = require("@azure/abort-controller");
import { ClientSecretCredential } from '@azure/identity';

const resourcePath: string = path.join(__dirname, 'module.json');
tl.setResourcePath(resourcePath);
Expand All @@ -24,26 +25,44 @@ export class AzureBlobProvider implements models.IArtifactProvider {
private _containerClient: ContainerClient;
private _blobServiceClient: BlobServiceClient;
private _addPrefixToDownloadedItems: boolean = false;
private _clientSecretCredential: ClientSecretCredential;

constructor(storageAccount: string, containerName: string, accessKey: string, prefixFolderPath?: string, host?: string, addPrefixToDownloadedItems?: boolean) {
constructor(storageAccount: string, containerName: string, accessKey: string, prefixFolderPath?: string, host?: string, addPrefixToDownloadedItems?: boolean);
constructor(storageAccount: string, containerName: string, clientSecretCredential: ClientSecretCredential, prefixFolderPath?: string, host?: string, addPrefixToDownloadedItems?: boolean);

// Generic Constructor
constructor(storageAccount: string, containerName: string, credential: string | ClientSecretCredential, prefixFolderPath?: string, host?: string, addPrefixToDownloadedItems?: boolean) {
this._storageAccount = storageAccount;
this._accessKey = accessKey;
this._containerName = containerName;

if (typeof credential === 'string') {
this._accessKey = credential;
const sharedKeyCredential = new StorageSharedKeyCredential(this._storageAccount, this._accessKey);
this._blobServiceClient = new BlobServiceClient(this.getStorageUrl(storageAccount, host), sharedKeyCredential);
} else {
this._clientSecretCredential = credential;
this._blobServiceClient = new BlobServiceClient(this.getStorageUrl(storageAccount, host), this._clientSecretCredential);
}

if (!!prefixFolderPath) {
this._prefixFolderPath = prefixFolderPath.endsWith("/") ? prefixFolderPath : prefixFolderPath + "/";
} else {
this._prefixFolderPath = "";
}

const sharedKeyCredential = new StorageSharedKeyCredential(this._storageAccount, this._accessKey);

this._blobServiceClient = new BlobServiceClient(this.getStorageUrl(this._storageAccount), sharedKeyCredential);

this._containerClient = this._blobServiceClient.getContainerClient(this._containerName);

this._addPrefixToDownloadedItems = !!addPrefixToDownloadedItems;
}

// Factory method for Storage Access Key
public static createWithStorageAccountAccessKey(storageAccount: string, containerName: string, accessKey: string, prefixFolderPath?: string, host?: string, addPrefixToDownloadedItems?: boolean): AzureBlobProvider {
return new AzureBlobProvider(storageAccount, containerName, accessKey, prefixFolderPath, host, addPrefixToDownloadedItems);
}

// Factory method for ClientSecretCredential
public static createWithClientSecretCredential(storageAccount: string, containerName: string, clientSecretCredential: ClientSecretCredential, prefixFolderPath?: string, host?: string, addPrefixToDownloadedItems?: boolean): AzureBlobProvider {
return new AzureBlobProvider(storageAccount, containerName, clientSecretCredential, prefixFolderPath, host, addPrefixToDownloadedItems);
}

public async putArtifactItem(item: models.ArtifactItem, readStream: Readable): Promise<models.ArtifactItem> {
await this._containerClient.createIfNotExists();
Expand Down Expand Up @@ -164,7 +183,7 @@ export class AzureBlobProvider implements models.IArtifactProvider {
return artifactItems;
}

private getStorageUrl(storageAccount: string): string {
return `https://${storageAccount}.blob.core.windows.net`;
private getStorageUrl(storageAccount: string, host?: string): string {
return host ? `https://${storageAccount}.${host}` : `https://${storageAccount}.blob.core.windows.net`;
}
}
33 changes: 30 additions & 3 deletions common-npm-packages/az-blobstorage-provider/blobservice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,51 @@ import artifactProviders = require('artifact-engine/Providers');
import azureBlobProvider = require('./azureBlobStorageProvider');
import artifactProcessor = require('artifact-engine/Engine');
import models = require('artifact-engine/Models');
import { ClientSecretCredential } from '@azure/identity';

export class BlobService {
private _storageAccountName: string;
private _storageAccessKey: string;
private _credential?: ClientSecretCredential;
private _host: string;

/**
* @deprecated
* Use `createWithStorageAccountAccessKey` or `createWithClientSecretCredential` instead.
*/
public constructor(storageAccountName: string, storageAccessKey: string, host?: string) {
this._storageAccountName = storageAccountName;
this._storageAccessKey = storageAccessKey;
this._host = host;
}

// Static factory method for using Storage Account Access Key
public static createWithStorageAccountAccessKey(storageAccountName: string, storageAccountAccessKey: string, host?: string): BlobService {
return new BlobService(storageAccountName, storageAccountAccessKey, host);
}

// Static factory method for using ClientSecretCredential
public static createWithClientSecretCredential(storageAccountName: string, credential: ClientSecretCredential, host?: string): BlobService {
// Create an instance using a dummy access key and then set the credential
const instance = new BlobService(storageAccountName, undefined, host);
instance._credential = credential;
return instance;
}

public async uploadBlobs(source: string, container: string, prefixFolderPath?: string, itemPattern?: string): Promise<string[]> {
var fileProvider = new artifactProviders.FilesystemProvider(source);
var azureProvider = new azureBlobProvider.AzureBlobProvider(this._storageAccountName, container, this._storageAccessKey, prefixFolderPath, this._host);

var processor = new artifactProcessor.ArtifactEngine();
var processorOptions = new artifactProcessor.ArtifactEngineOptions();
if (itemPattern) {
processorOptions.itemPattern = itemPattern;

//TODO: Check if _credential is populated. If yes, create AzureBlobProvider with it.
let azureProvider: azureBlobProvider.AzureBlobProvider;
if (this._credential) {
// Create AzureBlobProvider using ClientSecretCredential
//azureProvider = new azureBlobProvider.AzureBlobProvider(this._storageAccountName, container, this._credential, prefixFolderPath, this._host);
} else {
// Use the storage access key if no credential is provided
azureProvider = new azureBlobProvider.AzureBlobProvider(this._storageAccountName, container, this._storageAccessKey, prefixFolderPath, this._host);
}

var uploadedItemTickets = await processor.processItems(fileProvider, azureProvider);
Expand All @@ -37,6 +63,7 @@ export class BlobService {

public async downloadBlobs(destination: string, container: string, prefixFolderPath?: string, itemPattern?: string, addPrefixToDownloadedItems?: boolean): Promise<void> {
var fileProvider = new artifactProviders.FilesystemProvider(destination);
//TODO: Revise this init too
var azureProvider = new azureBlobProvider.AzureBlobProvider(this._storageAccountName, container, this._storageAccessKey, prefixFolderPath, this._host, !!addPrefixToDownloadedItems);
var processor = new artifactProcessor.ArtifactEngine();
var processorOptions = new artifactProcessor.ArtifactEngineOptions();
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion common-npm-packages/az-blobstorage-provider/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@
"scripts": {
"build": "cd ../build-scripts && npm install && cd ../az-blobstorage-provider && node make.js"
}
}
}