Одним из значительных нововведений после 7 июня 2012 года стало усовершенствование функции Copy Blob. При написании этой статьи я использовал материалы команды разработки, которые можно найти здесь. Что привлекло моё внимание – функциональность copy blob позволяет копировать блобы извне Windows Azure, если они публично доступны. То есть им нет необходимости находиться в Windows Azure.
Это заставило меня сесть и подумать.. То есть сейчас у меня есть вариант простого переноса моих файлов в хранилище блобов Windows Azure, при этом большинство работы будет выполнено самой платформой. Поэтому я и подумал, а не написать ли простое приложение, которое попробует скопировать файл (объект) из Amazon S3 в хранилище блобов Windows Azure. Получилось это сделать за несколько часов (часов потому что не было аккаунта в S3 до определенного момента, соответственно знания о клиентской библиотеке для хранилища были несколько ограничены). Но что я хочу сказать: это реально работает и это реально просто сделать.
Зачем это делать?
Я подумал о нескольких сценариях, в которых могло бы понадобиться копирование контента из одного облачного провайдера в хранилище блобов Windows Azure.
Хранилище блобов Windows Azure действительно конкурентноспособно
Со всеми новыми фичами и снижением цен хранилище Windows Azure – реальная альтернатива другим облачным провайдерам, предоставляющим услуги облачного хранилища. Это может стать одной из причин, по которой вы перейдете с используемого провайдера на Windows Azure Storage. Либо вы всегда хотели перейти, но не могли придумать, как перенести данные с хранилища. Новая функция Copy Blob делает решение этой проблемы суперпростым.
Хранилище блобов Windows Azure как бэкап для существующих данных
Теперь можно легко использовать хранилище блобов как место для резервирования данных из используемого облачного хранилища. Это было возможно и раньше, но было довольно болезненным процессом, так как требовало кучу кода.
С последними нововведениями это стало реально просто. Теперь не надо писать код для копирования байт из источника в блоб в Windows Azure. Все это делает платформа. Вы просто говорите, где находится источник и куда его надо перенести, вызываете функцию копирования и всё.
Покажите мне код!!!
OK, хватит разговоров! Давайте посмотрим на код. Я создал простое консольное приложение (код ниже), но прежде чем я перейду к нему, хотелось бы обсудить ещё пару моментов. .
Prerequisites
Перед запуском кода нужно совершить несколько действий:
1. Создать аккаунт хранилища: обратите внимание, что новая функциональность будет работать только в том случае, если аккаунт хранилища создан после 7-го июня 2012 года (почему – см. примечание, прим. переводчика).
2. Скачайте последнюю версию клиентской библиотеки хранилища: на момент написания статьи официально зарелизенной версией библиотеки является 1.7. К сожалению, новая функциональность в ней не работает, поэтому нужно скачать 1.7.1 с GitHub. Скачайте исходники и скомпилируйте.
3. Проверьте публичную доступность объекта/блоба: функция Copy Blobs может копировать только публично доступные блобы извне Windows Azure. Поэтому, в случае Amazon S3, нужно удостовериться, что объект имеет разрешения как минимум уровня READ для анонимных пользователей.
Код
Как я уже сказал выше, код очень прост:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
namespace CopyAmazonObjectToBlobStorage
{
class Program
{
private static string azureStorageAccountName = “";
private static string azureStorageAccountKey = "";
private static string azureBlobContainerName = "";
private static string amazonObjectUrl = "";
private static string azureBlobName = "";
static void Main(string[] args)
{
CloudStorageAccount csa = new CloudStorageAccount(new StorageCredentialsAccountAndKey(azureStorageAccountName, azureStorageAccountKey), true);
CloudBlobClient blobClient = csa.CreateCloudBlobClient();
var blobContainer = blobClient.GetContainerReference(azureBlobContainerName);
Console.WriteLine("Trying to create the blob container....");
blobContainer.CreateIfNotExist();
Console.WriteLine("Blob container created....");
var blockBlob = blobContainer.GetBlockBlobReference(azureBlobName);
Console.WriteLine("Created a reference for block blob in Windows Azure....");
Console.WriteLine("Blob Uri: " + blockBlob.Uri.AbsoluteUri);
Console.WriteLine("Now trying to initiate copy....");
blockBlob.StartCopyFromBlob(new Uri(amazonObjectUrl), null, null, null);
Console.WriteLine("Copy started....");
Console.WriteLine("Now tracking blob's copy progress....");
bool continueLoop = true;
while (continueLoop)
{
Console.WriteLine("");
Console.WriteLine("Fetching lists of blobs in Azure blob container....");
var blobsList = blobContainer.ListBlobs(true, BlobListingDetails.Copy);
foreach (var blob in blobsList)
{
var tempBlockBlob = (CloudBlob) blob;
var destBlob = blob as CloudBlob;
if (tempBlockBlob.Name == azureBlobName)
{
var copyStatus = tempBlockBlob.CopyState;
if (copyStatus != null)
{
Console.WriteLine("Status of blob copy...." + copyStatus.Status);
var percentComplete = copyStatus.BytesCopied / copyStatus.TotalBytes;
Console.WriteLine("Total bytes to copy...." + copyStatus.TotalBytes);
Console.WriteLine("Total bytes copied...." + copyStatus.BytesCopied);
if (copyStatus.Status != CopyStatus.Pending)
{
continueLoop = false;
}
}
}
}
Console.WriteLine("");
Console.WriteLine("==============================================");
System.Threading.Thread.Sleep(1000);
}
Console.WriteLine("Process completed....");
Console.WriteLine("Press any key to terminate the program....");
Console.ReadLine();
}
}
}
Код достаточно прост. Что я делаю: я указываю учетные данные для доступа к хранилищу Windows Azure и URL блоба-источника (в Amazon S3); создаю контейнер блобов в Windows Azure и начинаю копирование блоба с URL источника. После отправки запроса на копирование всё, что делает приложение, это мониторит процесс копирования. Как вы видите, ни одной строки кода для копирования байт из источника в приемник. Всё это делает Windows Azure.
Вот как выглядит объект в Amazon S3:
Увеличить
После того, как объект скопирован, я могу увидеть его в хранилище блобов Windows Azure, используяCloud Storage Studio.
Увеличить
Как вы увидели, Windows Azure предоставляет возможность простого переноса данных. Если вы рассматриваете возможность перехода с другой облачной платформы на Windows Azure, но беспокоились о всяких связанных с этим проблемах, одной проблемой стало меньше.
Я создал простой пример, который копирует один файл из Amazon S3 в хранилище блобов Windows Azure. Эту функциональность можно расширить до копирования всех объектов из корзины Amazon S3 в контейнер блобов Windows Azure. Давайте перейдем к следующей статье – как скопировать корзину из Amazon S3 в хранилище блобов Windows Azure, используя Copy Blob.
Prerequisites
Перед запуском кода нужно совершить несколько действий:
- Проверьте публичную доступность объекта/блоба: функция Copy Blobs может копировать только публично доступные блобы извне Windows Azure. Поэтому, в случае Amazon S3, нужно удостовериться, что объект имеет разрешения как минимум уровня READ для анонимных пользователей.
- Создать аккаунт хранилища: обратите внимание, что новая функциональность будет работать только в том случае, если аккаунт хранилища создан после 7-го июня 2012 года (почему – см.примечание, прим. переводчика).
- Скачайте последнюю версию клиентской библиотеки хранилища: на момент написания статьи официально зарелизенной версией библиотеки является 1.7. К сожалению, новая функциональность в ней не работает, поэтому нужно скачать 1.7.1 с GitHub. Скачайте исходники и скомпилируйте.
- Amazon SDK for .Net: Нужно скачать Amazon SDK for .Net с сайта Amazon AWS.
- Держите рядом учетные данные для Amazon: Нужно будет использовать Amazon AccessKey и SecretKey для получения списка объектов, хранящихся в корзине Amazon S3.
Код
Код очень простой. Учтите, что он только для демонстрации. Можете модифицировать его как вам необходимо.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.S3.Transfer;
using Amazon.S3.Util;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using System.Globalization;
namespace CopyAmazonBucketToBlobStorage
{
class Program
{
private static string azureStorageAccountName = “”;
private static string azureStorageAccountKey = “”;
private static string azureBlobContainerName = “”;
private static string amazonAccessKey = “”;
private static string amazonSecretKey = “”;
private static string amazonBucketName = “”;
private static string objectUrlFormat = “https://{0}.s3.amazonaws.com/{1}”;
private static Dictionary<string, CopyBlobProgress> CopyBlobProgress;
static void Main(string[] args)
{
//Создание ссылки на аккаунт хранилища Windows Azure
CloudStorageAccount azureCloudStorageAccount = new CloudStorageAccount(new StorageCredentialsAccountAndKey(azureStorageAccountName, azureStorageAccountKey), true);
//Получение ссылки на контейнер блоба, куда будут скопированы объекты.
var blobContainer = azureCloudStorageAccount.CreateCloudBlobClient().GetContainerReference(azureBlobContainerName);
//Создание контейнера блобов, если это необходимо.
Console.WriteLine(«Trying to create the blob container....»);
blobContainer.CreateIfNotExist();
Console.WriteLine(«Blob container created....»);
//Создание ссылки на клиент Amazon
AmazonS3Client amazonClient = new AmazonS3Client(amazonAccessKey, amazonSecretKey);
//Инициализация словаря
CopyBlobProgress = new Dictionary<string, CopyBlobProgress>();
string continuationToken = null;
bool continueListObjects = true;
//Так как ListObjects может возвратить за один раз не более 1000 объектов, //вызываем функцию до тех пор, пока не будут возвращены все объекты.
while (continueListObjects)
{
ListObjectsRequest requestToListObjects = new ListObjectsRequest()
{
BucketName = amazonBucketName,
Marker = continuationToken,
MaxKeys = 100,
};
Console.WriteLine(«Trying to list objects from S3 Bucket....»);
//Получение списка объектов в Amazon S3
var listObjectsResponse = amazonClient.ListObjects(requestToListObjects);
//Список объектов
var objectsFetchedSoFar = listObjectsResponse.S3Objects;
Console.WriteLine(«Object listing complete. Now starting the copy process....»);
//Просматриваем, не доступны ли еще объекты. Сначала обрабатываем полученные объекты, потом переходим на следующее множество с использованием continuation token.
continuationToken = listObjectsResponse.NextMarker;
foreach (var s3Object in objectsFetchedSoFar)
{
string objectKey = s3Object.Key;
//ListObjects возвращает файлы и папки, пропускаем папки, проверяя для этого значение S3 Object Key. Если оно кончается на /, предполагаем что это папка.
if (!objectKey.EndsWith(«/»))
{
//формируем URL для копирования
string urlToCopy = string.Format(CultureInfo.InvariantCulture, objectUrlFormat, amazonBucketName, objectKey);
//Создаем экземпляр CloudBlockBlob
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(objectKey);
var blockBlobUrl = blockBlob.Uri.AbsoluteUri;
if (!CopyBlobProgress.ContainsKey(blockBlobUrl))
{
CopyBlobProgress.Add(blockBlobUrl, new CopyBlobProgress()
{
Status = CopyStatus.NotStarted,
});
//Запускаем копирование. Оборачиваем его в блок try/catch
//так как копирование из Amazon S3 будет произведено только для публично доступных объектов.
try
{
Console.WriteLine(string.Format(«Trying to copy \»{0}\» to \»{1}\»«, urlToCopy, blockBlobUrl));
blockBlob.StartCopyFromBlob(new Uri(urlToCopy));
CopyBlobProgress[blockBlobUrl].Status = CopyStatus.Started;
}
catch (Exception exception)
{
CopyBlobProgress[blockBlobUrl].Status = CopyStatus.Failed;
CopyBlobProgress[blockBlobUrl].Error = exception;
}
}
}
}
Console.WriteLine(««);
Console.WriteLine(«==========================================================«);
Console.WriteLine(««);
Console.WriteLine(«Checking the status of copy process....»);
//Мониторим процесс
bool checkForBlobCopyStatus = true;
while (checkForBlobCopyStatus)
{
//Получаем список блобов в контейнере блобов
var blobsList = blobContainer.ListBlobs(true, BlobListingDetails.Copy);
foreach (var blob in blobsList)
{
var tempBlockBlob = blob as CloudBlob;
var copyStatus = tempBlockBlob.CopyState;
if (CopyBlobProgress.ContainsKey(tempBlockBlob.Uri.AbsoluteUri))
{
var copyBlobProgress = CopyBlobProgress[tempBlockBlob.Uri.AbsoluteUri];
if (copyStatus != null)
{
Console.WriteLine(string.Format(«Status of \»{0}\» blob copy....», tempBlockBlob.Uri.AbsoluteUri, copyStatus.Status));
switch (copyStatus.Status)
{
case Microsoft.WindowsAzure.StorageClient.CopyStatus.Aborted:
if (copyBlobProgress != null)
{
copyBlobProgress.Status = CopyStatus.Aborted;
}
break;
case Microsoft.WindowsAzure.StorageClient.CopyStatus.Failed:
if (copyBlobProgress != null)
{
copyBlobProgress.Status = CopyStatus.Failed;
}
break;
case Microsoft.WindowsAzure.StorageClient.CopyStatus.Invalid:
if (copyBlobProgress != null)
{
copyBlobProgress.Status = CopyStatus.Invalid;
}
break;
case Microsoft.WindowsAzure.StorageClient.CopyStatus.Pending:
if (copyBlobProgress != null)
{
copyBlobProgress.Status = CopyStatus.Pending;
}
break;
case Microsoft.WindowsAzure.StorageClient.CopyStatus.Success:
if (copyBlobProgress != null)
{
copyBlobProgress.Status = CopyStatus.Success;
}
break;
}
}
}
}
var pendingBlob = CopyBlobProgress.FirstOrDefault(c => c.Value.Status == CopyStatus.Pending);
if (string.IsNullOrWhiteSpace(pendingBlob.Key))
{
checkForBlobCopyStatus = false;
}
else
{
System.Threading.Thread.Sleep(1000);
}
}
if (string.IsNullOrWhiteSpace(continuationToken))
{
continueListObjects = false;
}
Console.WriteLine(««);
Console.WriteLine(«==========================================================«);
Console.WriteLine(««);
}
Console.WriteLine(«Process completed....»);
Console.WriteLine(«Press any key to terminate the program....»);
Console.ReadLine();
}
}
public class CopyBlobProgress
{
public CopyStatus Status
{
get;
set;
}
public Exception Error
{
get;
set;
}
}
public enum CopyStatus
{
NotStarted,
Started,
Aborted,
Failed,
Invalid,
Pending,
Success
}
}
Код достаточно прост. Приложение:
- Создает контейнер блобов в хранилище Windows Azure, если есть такая необходимость.
- Получает список объектов из корзины Amazon S3. Обратите внимание, что Amazon S3 может возвратить в один вызов функции до 1000 объектов, иначе возвращается continuation token, который используется для получения маркера, обозначающего следующее подмножество сущностей.
- Для каждого возвращенного объекта формируется URL, который используется для функции Copy Blob.
- Приложение проверяет состояние процесса копирования. После окончания всех процессов копирования, повторяются шаги 2-4 до тех пор, пока все объекты не будут скопированы.
Для управления контентом в Amazon S3 я использовал Bucket Explorer, который показал следующее состояние:
Увеличить
После окончания копирования следующее состояние хранилища блобов Windows Azure показал Cloud Storage Studio.
Увеличить
Резюме
Я создал простой пример, который копирует все содержимое из корзины Amazon S3 в хранилище блобов Windows Azure.
Резюме от переводчика
Эмоции Гаурава о новых возможностях API понятны — честно говоря, до 7 июня 2012 года API для использования сервисов хранилищ местами хромало на функциональность, о чем говорит переводная серия статей того же Гаурава о сравнении хранилищ Windows Azure и Amazon. Теперь же возможность использовать хранилище Windows Azure в качестве того же места для резервирования, да ещё и с возможностью регулировать степень избыточности (теперь доступно два типа), позволяет избежать, наверное, последствий любого катаклизма и создать действительно отказотерпимый (:) сервис.
Примечание от переводчика
Сервисы хранилища Windows Azure могут принимать запросы, которые указывают конкретную версию каждой операции (сервиса), при этом разработчик может указать версию, используя заголовок x-ms-version. Естественно, что функциональность различных версий и механизмы работы (не концептуальные) могут различаться.
Надо учитывать правила системы, по которой сервис блобов определяет, какую версию использовать для интерпретации параметров SAS:
1. Если в запросе есть заголовок x-ms-version, но нет signedversion, используется версия 2009-07-17 для интерпретации параметров SAS, для операции же используется версия, указанная в x-ms-version.
2. Если в запросе нет заголовка x-ms-version и нет signedversion, но владелец аккаунта установил версию сервиса, используя операцию Set Blob Service Properties, будет использована версия 2009-07-07 для интерпретации параметров SAS, для операции же используется версия, указанная владельцем аккаунта для сервиса.
3. Если в запросе нет заголовка x-ms-version, нет signedversion и владелец аккаунта не устанавливал версию сервиса, будет использована версия 2009-07-17 для интерпретации параметров SAS. Если контейнер имеет права public и ограничения доступа были установлены с использованием операции Set Container ACL, использующей версию 2009-09-19 (или новее).будет использована версия 2009-09-19 для операции.
Подробнее про версии и поддерживаемую ими функциональность.