Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
This code snippet will help break Blob Leases in Windows Azure Storage.
/*
* This code snippet will help break Blob Leases in Windows Azure Storage.
*
* I did not write this code, it was found at the website below.
*
* @see http://blogs.msdn.com/b/interoperability/archive/2012/08/01/node-js-script-for-releasing-a-windows-azure-blob-lease.aspx
*/
// updated 3/3/2014 for latest version of Azure CLI
// Import required modules from Windows Azure Cross Platform Tool's library
var azure = require('./node_modules/azure/lib/azure');
var blobUtils = require('./lib/util/blobUtils');
var BlobService = require('./node_modules/azure/lib/services/blob/blobservice');
var Cli = require('./lib/cli');
var util = require('util');
var utils = require('./lib/util/utils');
var svcMgmtChannel = null;
var blobChannel = null;
var blobUrlInfo = null;
var hostName = null;
var progress = null;
var cli = new Cli();
var logger = cli.output;
// Validate the command-line argument
if (process.argv.length !== 3) {
showUsage(logger, 'help');
process.exit(1);
}
// Validate blob url
blobUrlInfo = blobUtils.splitDestinationUri(process.argv[2]);
if (!blobUrlInfo.accountName || !blobUrlInfo.container || !blobUrlInfo.blobName) {
logger.error("Invalid <absolute-url-to-blob>");
showUsage(logger, 'error');
}
// Strip the protocol part and post slash
blobUrlInfo.normalizedUri = stripUrl(blobUrlInfo.normalizedUri);
// Create channel for Windows Azure Service Management
svcMgmtChannel = utils.createServiceManagementService(
cli.category('account').getCurrentSubscription(),
logger);
// Retrieve list of storage accounts, validate <account-name>.<host-name>
// part of <absolute-url-to-blob> and fetch the storage account key
// Step1
progress = cli.interaction.progress('Retrieving storage accounts');
utils.doServiceManagementOperation(svcMgmtChannel, 'listStorageAccounts', function (error, response) {
if (error) {
showMessage(progress, logger.error, error);
} else {
var storageAccounts = response.body;
if (storageAccounts.length > 0) {
for (var i = 0; (i < storageAccounts.length) && !hostName; i++) {
var endPoints = storageAccounts[i].StorageServiceProperties.Endpoints;
if (endPoints && endPoints.Endpoint) {
for (var j = 0; (j < endPoints.Endpoint.length) && !hostName; j++) {
var endPoint = endPoints.Endpoint[j];
// Validate <storage-account>.<host-name> part of <absolute-url-to-blob>
if (endPoint.indexOf('.blob.') > -1) {
endPoint = stripUrl(endPoints.Endpoint[j]);
if (blobUrlInfo.normalizedUri.indexOf(endPoint) === 0) {
hostName = endPoint.substr(blobUrlInfo.accountName.length + 1);
}
}
}
}
}
if (!hostName) {
showMessage(
progress,
logger.error,
"Looks like either you do not have a storage account with name "
+ blobUrlInfo.accountName
+ " or the <host-name> part of the <absolute-url-to-blob> is invalid");
return;
}
cli.interaction.progress('Retrieving storage account key for ' + blobUrlInfo.accountName);
utils.doServiceManagementOperation(svcMgmtChannel, 'getStorageAccountKeys', blobUrlInfo.accountName, function (error, response) {
if (error) {
showMessage(progress, logger.error, error);
} else {
var stgAccountAccessKeys = response.body.StorageServiceKeys;
stgAccountAccessKey = stgAccountAccessKeys.Primary;
blobChannel = new BlobService(blobUrlInfo.accountName,
stgAccountAccessKey,
hostName
);
step2('listDisks');
}
});
} else {
showMessage(progress, logger.info, "There is no storage account in your subscription");
}
}
});
/**
* Step2: Check the given url is attached to disk or os image.
*
* @param {string} The list command, listDisks or listOSImage.
* @return {string}
*/
function step2(listCmd) {
type = null;
if (listCmd === 'listDisks') {
type = 'Disk Image';
} else {
type = 'OS Image';
}
progress = cli.interaction.progress('Retrieving ' + type + 's to check the given blob url is attached to any ' + type);
utils.doServiceManagementOperation(svcMgmtChannel, listCmd, function (error, response) {
if (error) {
showMessage(progress, logger.error, error);
} else {
var image = null;
for (var k = 0; k < response.body.length; k++) {
var image = response.body[k];
if (image.MediaLink && (stripUrl(image.MediaLink) === blobUrlInfo.normalizedUri)) {
showMessage(progress, logger.error, 'Lease will not be released since the given blob-url is attached to the ' + type + ' ' + image.Name);
return;
}
}
showMessage(progress, logger.info, 'The url is not attached to any ' + type);
if (listCmd === 'listDisks') {
step2('listOSImage');
} else {
step3();
}
}
});
}
/**
* Step3: Remove the lease
*
* @return {undefined}
*/
function step3() {
progress = cli.interaction.progress('Deleting the lease on ' + blobUrlInfo.blobName);
blobChannel.breakLease(blobUrlInfo.container, blobUrlInfo.blobName, null, { timeoutIntervalInMs: 60000 }, function (error, lease, response) {
if (error) {
showMessage(progress, logger.error, error);
} else {
showMessage(progress, logger.info, "The lease has been broken");
}
});
}
/**
* remove protocol and trailing slash from the url.
*
* @param {strin} url The url to strip
* @return {string}
*/
function stripUrl(url) {
if (url.indexOf('http://') === 0) {
url = url.substr(7);
}
if (url.indexOf('https://') === 0) {
url = url.substr(8);
}
if (url.slice(-1) === '/') {
url = url.slice(0, -1);
}
return url;
}
/**
* Show usage
*
* @param {object} logger The logger object.
* @param {string} level The log level.
* @return {undefined}
*/
function showUsage(logger, level) {
logger[level]("Usage: node breakLease.js <absolute-url-to-blob>");
logger[level]("<absolute-url-to-blob> = http://<storage-account-name>.<host-name>/<container-name>/<blob-name>");
logger[level]("<host-name> = [blob.core.windows.net | blob.core.azure-preview.com]");
}
/**
* Stop progress control and output error
*
* @param {object} progress The progress control.
* @param {function} outFun The log function.
* @param {object | string} message The message details to output.
* @return {undefined}
*/
function showMessage(progress, outFun, message) {
if (progress) {
progress.end();
}
outFun(util.inspect(message));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.