Копирование объектов и корзин Amazon S3 в Windows Azure Storage
В этой статье – как скопировать объект и корзину (bucket) из Amazon S3 в хранилище блобов Windows Azure.
Одним из значительных нововведений после 7 июня 2012 года стало усовершенствование функции Copy Blob. При написании этой статьи я использовал материалы команды разработки, которые можно найти здесь: https://blogs.msdn.com/b/windowsazurestorage/archive/2012/06/12/introducing-asynchronous-cross-account-copy-blob.aspx. Что привлекло моё внимание – функциональность copy blob позволяет копировать блобы извне Windows Azure, если они публично доступны. То есть им нет необходимости находиться в Windows Azure.
ЭТО ОЧЕНЬ КРУТО!!!
Это заставило меня сесть и подумать.. То есть сейчас у меня есть вариант простого переноса моих файлов в хранилище блобов Windows Azure, при этом большинство работы будет выполнено самой платформой. Поэтому я и подумал, а не написать ли простое приложение, которое попробует скопировать файл (объект) из Amazon S3 в хранилище блобов Windows Azure. Получилось это сделать за несколько часов (часов потому что не было аккаунта в S3 до определенного момента, соответственно знания о клиентской библиотеке для хранилища были несколько ограничены). Но что я хочу сказать: это реально работает и это реально просто сделать.
Зачем это делать?
Я подумал о нескольких сценариях, в которых могло бы понадобиться копирование контента из одного облачного провайдера в хранилище блобов Windows Azure.
Со всеми новыми фичами и снижением цен хранилище Windows Azure – реальная альтернатива другим облачным провайдерам, предоставляющим услуги облачного хранилища. Это может стать одной из причин, по которой вы перейдете с используемого провайдера на Windows Azure Storage. Либо вы всегда хотели перейти, но не могли придумать, как перенести данные с хранилища. Новая функция Copy Blob делает решение этой проблемы суперпростым.
Теперь можно легко использовать хранилище блобов как место для резервирования данных из используемого облачного хранилища. Это было возможно и раньше, но было довольно болезненным процессом, так как требовало кучу кода.
С последними нововведениями это стало реально просто. Теперь не надо писать код для копирования байт из источника в блоб в 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 для операции.
Подробнее про версии и поддерживаемую ими функциональность.
Перевод выполнен: Александр Белоцерковский.