C#でTGZやTARを作成

.NET(C#)でフォルダごとTGZやTARにまとめる方法を紹介します。
同様のサンプルは様々なところで取り上げられていますが、ファイルを絶対パスのまま登録しているため、任意の場所に解凍できなくなってしまうという状態でしたので、少し修正しました。

このコードはSharpZipLibというライブラリを使用します。

http://www.icsharpcode.net/opensource/sharpziplib/

TGZのサンプル。TarArchiveに登録するエントリの名前を相対パスに変換しています。

        /// <summary>
        /// Creates a GZipped Tar file from a source directory
        /// </summary>
        /// <param name="outputTarFilename">Output .tar.gz file</param>
        /// <param name="sourceDirectory">Input directory containing files to be added to GZipped tar archive</param>
        public void CreateTar(string outputTarFilePath, string sourceDirectory)
        {
            using (FileStream fs = new FileStream(outputTarFilePath, FileMode.Create, FileAccess.Write, FileShare.None))
            using (Stream gzipStream = new GZipOutputStream(fs))
            using (TarArchive tarArchive = TarArchive.CreateOutputTarArchive(gzipStream))
            {
                tarArchive.SetKeepOldFiles(true);
                //tarArchive.AsciiTranslate = false;
                AddDirectoryFilesToTar(tarArchive, sourceDirectory, sourceDirectory, true);
            }
        }

        /// <summary>
        /// Recursively adds folders and files to archive
        /// </summary>
        /// <param name="tarArchive"></param>
        /// <param name="sourceDirectory"></param>
        /// <param name="recurse"></param>
        private void AddDirectoryFilesToTar(TarArchive tarArchive, string rootDirectory, string sourceDirectory, bool recurse)
        {
            // Recursively add sub-folders
            if (recurse)
            {
                string[] directories = Directory.GetDirectories(sourceDirectory);
                foreach (string directory in directories)
                    AddDirectoryFilesToTar(tarArchive, rootDirectory, directory, recurse);
            }

            // Add files
            string[] filenames = Directory.GetFiles(sourceDirectory);
            foreach (string filename in filenames)
            {
                TarEntry tarEntry = TarEntry.CreateEntryFromFile(filename);
                tarEntry.Name = filename.Remove(0, rootDirectory.Length);
                tarArchive.WriteEntry(tarEntry, true);
            }
        }

TARのサンプル。上記との違いは、GZIPを使わずにTarArchiveに渡すところだけです。

        /// <summary>
        /// Creates a GZipped Tar file from a source directory
        /// </summary>
        /// <param name="outputTarFilename">Output .tar.gz file</param>
        /// <param name="sourceDirectory">Input directory containing files to be added to GZipped tar archive</param>
        public void CreateTar(string outputTarFilePath, string sourceDirectory)
        {
            using (FileStream fs = new FileStream(outputTarFilePath, FileMode.Create, FileAccess.Write, FileShare.None))
            using (TarArchive tarArchive = TarArchive.CreateOutputTarArchive(fs))
            {
                tarArchive.SetKeepOldFiles(true);
                //tarArchive.AsciiTranslate = false;
                AddDirectoryFilesToTar(tarArchive, sourceDirectory, sourceDirectory, true);
            }
        }

Posted in 未分類 | Tagged | Leave a comment

ストレージアカウントを越えたAzure Blobのコピー

ストレージアカウントを跨いだAzure Blobのコピーは可能です。
順を追って見ていきたいと思います。

まずは、転送元ブロブへの参照と共有アクセス署名を取得する必要があります。
共有アクセス署名を取得する際には、アクセス権限と有効期間を指定します。
10分でも大抵は問題ありませんが、大量のファイルを同時にコピーしたり、大容量のファイルをコピーする場合には、十分なテストを行った上で決定しましょう。

// 転送元ストレージクライアント取得
CloudStorageAccount storageAccountSrc = 
    new CloudStorageAccount(new StorageCredentials(storageAccountNameSrc, storageAccountKeySrc), true);
CloudBlobClient clientSrc = storageAccountSrc.CreateCloudBlobClient();

// 転送元ブロブ取得
ICloudBlob blobSrc = clientSrc.GetBlobReferenceFromServer(new Uri(urlSrc));
// 転送元ブロブの共有アクセス署名の取得
string sasSrc = blobSrc.GetSharedAccessSignature(
    new SharedAccessBlobPolicy() { 
        Permissions = SharedAccessBlobPermissions.Read, 
        SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(10) });

次に転送先のブロブへの参照を取得します。

// 転送先ストレージクライアント取得
CloudStorageAccount storageAccountDst = 
    new CloudStorageAccount(new StorageCredentials(storageAccountNameDst, storageAccountKeyDst), true);
CloudBlobClient clientDst = storageAccountDst.CreateCloudBlobClient();

// 転送先ブロブ取得
CloudBlockBlob blobDst = clientDst.GetBlobReferenceFromServer(new Uri(urlDst));

コピー命令の起点は転送先になります。転送元のアカウント情報がなくなるため、ここで共有アクセス署名が必要になります。
転送元ブロブのURLに共有アクセス署名を付加します。

また、コピーは非同期で行われるため、コピーが終わったことを確認するためにポーリングを行っています。
FetchAttributes()を実行した後で、CopyState.Statusを確認するとPendingやSuccessなどのコピー状況が取得できます。

// コピー実行
blobDst.StartCopyFromBlob(new Uri(blobSrc.Uri + sasSrc), null, null);
while (true)
{
    blobDst.FetchAttributes();
    if (blobDst.CopyState.Status == CopyStatus.Success)
    {
        break;
    }
    System.Threading.Thread.Sleep(500);
}

最後にコピー先のブロブにContentTypeを設定しています。
コピーによってコピー元の内容が反映されるので、通常は不要ですが、このようにプロパティを変更したい場合は、本サンプルのように完了を待ち合わせる必要があります。
もし、Pending状態のブロブに変更を加えようとすると、「競合(409)」エラーになってしまいます。

// Content-Type設定
blobDst.Properties.ContentType = "images/jpeg";
blobDst.SetProperties();

コピー処理の命令は内部的には一旦キューに格納されてから実行されていきます。
そのため、Pendingが長時間続く場合があります。
ほとんどの場合は数秒で実行されますが、時々200秒程度待たされることもありました。

非常に便利な機能ですが、いくつかの特性を理解した上で利用する必要があります。


Posted in 未分類 | Tagged , | Leave a comment

Azure Storage Client 1.xから2.0への移行サンプル

Azure Storage Client 2.0では、基本的なAPIの使い方が少し変更されています。
1.x系からの移行で戸惑うことは少ないかと思いますが、ファイルアップロードの場合を例に変更箇所をまとめてみました。

まずは名前空間の指定から。
役割ごとに細分化されました。

1.x系
using Microsoft.WindowsAzure.StorageClient;

2.0
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.RetryPolicies;

次にストレージアカウントの生成。
認証情報を表すクラス名が変わっています。

1.x系
StorageCredentialsAccountAndKey storageCredentials = new StorageCredentialsAccountAndKey(storageAccount, storageKey);
CloudStorageAccount account = new CloudStorageAccount(storageCredentials, true);

2.0
StorageCredentials storageCredentials = new StorageCredentials(storageAccount, storageKey);
CloudStorageAccount account = new CloudStorageAccount(storageCredentials, true);

コンテナの作成。
ExistがExistsになっただけです。

1.x系
CloudBlobContainer container = client.GetContainerReference(containerName);
container.CreateIfNotExist();

2.0
CloudBlobContainer container = client.GetContainerReference(containerName);
container.CreateIfNotExists();

転送ブロックサイズの指定。
通常はデフォルトで問題ありませんが、指定している場合は書き換えてください。

1.x系
container.ServiceClient.WriteBlockSizeInBytes = maxBlockSize;

2.0
container.ServiceClient.SingleBlobUploadThresholdInBytes = maxBlockSize;

次にリクエストオプションの指定ですが、リトライポリシーやタイムアウトの指定が若干変わりました。
その他にも変更箇所がありますが、通常意識するのはこのくらいでしょうか。

1.x系
BlobRequestOptions options = new BlobRequestOptions()
{
RetryPolicy = RetryPolicies.RetryExponential(RetryPolicies.DefaultClientRetryCount, RetryPolicies.DefaultMaxBackoff),
Timeout = TimeSpan.FromSeconds(90)
};

2.0
BlobRequestOptions options = new BlobRequestOptions()
{
RetryPolicy = new ExponentialRetry(),
ServerTimeout = TimeSpan.FromSeconds(90)
};

最後にアップロードです。
リクエストオプションを指定する場合には、AccessConditionの後に指定します。
AccessConditionは1.x系ではBlobRequestOptionsのメンバーでしたが変更になっています。
指定が不要であればnullで構いません。

1.x系
blob.UploadFromStream(fs, options);

2.0
blob.UploadFromStream(fs, null, options);


Posted in 未分類 | Tagged , | Leave a comment

Webロールにカスタムのパフォーマンスカウンタを追加

パフォーマンスカウンタを初期登録する際、WebロールのGlobal.asax等で登録すると以下の例外が発生します。

System.Security.SecurityException: Requested registry access is not allowed.

Webロールはワーカープロセスで実行されるため、管理者権限がないためです。このような処理は、WebRole.csのOnStartで実装すると上手くいきます。

csdefに以下の定義を追加してあれば、RoleEntryPointは管理者権限で実行されます。

<Runtime executionContext="elevated">

詳細は下記が非常に参考になります。
http://codezine.jp/article/detail/5880

注意しなければならないのは、OnStartでパフォーマンスカウンタを追加する際には、そのカウンタの診断ログ転送はwadcfgでは定義してはいけないということです。
wadcfgによる診断ログの構成は、スタートアップタスクやOnStartよりも前に実行されるため、その時点ではカウンタが定義されていないためです。
カスタムのパフォーマンスカウンタについては、コードでログ転送の構成を行ってください。

このことは以下にも書かれています。
http://msdn.microsoft.com/en-us/library/gg604918.aspx

カスタムのパフォーマンスカウンタについては、下記のサンプルコードが参考になりました。
http://msdn.microsoft.com/ja-jp/library/system.diagnostics.performancecounter.aspx
http://msdn.microsoft.com/en-us/library/system.diagnostics.performancecountertype.aspx


Posted in 未分類 | Tagged , | Leave a comment

Azure仮想マシンのサイズを変更する

Windows Server 2012を実行するAzure仮想マシンのサイズを変更しようとしたところ、以下のエラーが発生しました。

The operation cannot be performed because the virtual machine is faulted. The long running operation tracking ID was: ##########.

コミュニティでも同様の事象は報告されている模様です。

条件は掴めませんが、パターンとしては2つあります。
・サイズ変更自体に失敗する。
・サイズ変更には成功するが起動に失敗する。

日を改めて再試行したり、同じディスクで仮想マシンを再作成してもエラーになりました。

目的は、小(small)から中(middle)への変更です。
現在は以下を試したところ、サイズ変更と起動に成功しました。
1.small ⇒ middle ×
2.small ⇒ large ○
3.large ⇒ small ○
4.small ⇒ middle ×
5.small ⇒ middle ○

要するに何度かやっているうちに上手くいったという状況です。
この辺りがプレビューということなんでしょうね。


Posted in 未分類 | Tagged , | Leave a comment

Azure仮想マシンとVMロールの違い

Azure Virtual Machines(仮想マシン)とVMロールがよく混同されているようです。
使ったことがある人にとっては、すぐにわかりますが、公な記事などでも混同されている場合があるので注意してください。

今回は、少し前の記事ですが、Azure仮想マシンとVMロールの違いについて書かれたものがあったので、ざっくり訳してみました。(少しかいつまんでいます。)

VMロール
付属するソフトウェアやサービスパック、パッチ、更新、インストールされたアプリケーションと共にOSイメージをWindows Azureへ送信します。
アプリケーションだけでなくOSの健全性にも責任を持つ必要があります。パッチを適用し、メンテナンスしなければなりません。
差分ディスクにより更新を適用することができます。そのため、20-30GBのシステムイメージを再送信する必要はありません。

異なるホストでVMロールが実行されるには、多くの理由(ブルースクリーンのような)があります。
その際、イメージを取得し、新しいホストを検出し、イメージを実行します。
古いVMは破棄され、異なる顧客のための利用可能なホストになります。
そのため、ローカルファイルシステムに加えた変更は失われます。

IaaS仮想マシン
6月6日、7日に告知された仮想マシンは、Windows Azureデータセンターで実行さる文字通り仮想マシンです。
それもまた、OSとパッチ適用とメンテナンスに責任を持つ必要があります。
しかし、計画的および非計画的なリブートに対して、完全に永続化されます。
レジストリやファイルシステムを変更したり、COMコンポーネントを登録したりしても、システム障害などで異なるホストへの移動があると、その変更は移動後にも維持されます。
オンプレミス環境の仮想マシンと同様に、すべての変更は移動後でも維持されます。
続きを読む >>


Posted in 未分類 | Tagged , , | Leave a comment

Azure Webサイトで、East AsiaとWest USの速度を比較してみた

Azure Webサイトの作成時に選択できるデータセンターの地域に「東アジア」が追加されていました。
そこで、思いつきですが、以前作成した「アメリカ合衆国西部」と同じサイトを乗せてみて、速度を比較してみました。

<アメリカ合衆国西部(West US)>

<東アジア(East Asia)>

「アメリカ合衆国西部」がAverage 423msに対して、「東アジア」が299msとなりました。
この差はかなり大きいですね。

ちなみに、初回アクセスやしばらく放置した際のアクセス時には、2秒前後掛かる場合もあります。
また、共有インスタンスであるためか、バラつきは結構あるようです。


Posted in 未分類 | Tagged , | Leave a comment

Azure Service Busのオンプレミス側サービスの実行準備

Service Busを使ってAzureとオンプレミス側のサービスを接続する際、Azure側では、ロールインスタンス起動時のStartupコマンドで、RelayConfigurationInstaller.exeを実行するのが定石かと思います。

オンプレミス側でもServiceBus向けのエンドポイントを定義するため、サービスの起動前に、RelayConfigurationInstaller.exeを実行してMachine.configを書き換えておく必要があります。

この手順が抜けていると、実行時に以下のエラーが発生します。

——————–
構成内の要素が無効です。拡張名 ‘transportClientEndpointBehavior’ は、system.serviceModel/extensions/behaviorExtensions のコレクションに登録されていません。
——————–

開発環境では動作していたのに、別のマシンに持っていったら起動しなくなったという場合は確認が必要です。


Posted in 未分類 | Tagged , | Leave a comment

Startupコマンドの問題でWebロールが起動しない

あるサービスの検証で、Startupコマンドを追加してAzureに配置したら動かなくなりました。

    <Startup>
      <Task commandLine="Setup.cmd"
            executionContext="elevated"
            taskType="simple" /> 
    </Startup>
  </WebRole>

ローカルでデバッグ実行したところ、ロール実行の段階で応答しなくなり、以下のエラーが出力されました。

——————–
14:27:45 – Role instances recycled for a certain amount of times during an update or upgrade operation. This indicates that the new version of your service or the configuration settings you provided when configuring the service prevent role instances from running. The most likely reason for this is that your code throws an unhandled exception. Please consider fixing your service or changing your configuration settings so that role instances do not throw unhandled exceptions. Then start another update or upgrade operation. Until you start another update or upgrade operation, Windows Azure will continue trying to update your service to the new version or configuration you provided
14:27:45 – 致命的なエラーで配置に失敗しました
——————–

具体的なことが書かれてないため、少しハマりましたが、普通にローカルで、
Setup.cmdを実行したら文字化けで実行できないことが原因でした。
メモ帳で作成し直したら、無事デプロイに成功しました。

VisualStudioでテキストファイルとして追加したのが良くなかったようです。


Posted in 未分類 | Tagged | Leave a comment

Azureサービスバス開発で必要な RelayConfigurationInstaller が失敗

Windows Azure サービスバスの開発で必要となる以下のコマンドですが、実行するとエラーが発生しました。
SDKを一度アンインストールしたりしたからかも。

RelayConfigurationInstaller.exe /i

————————————
ハンドルされていない例外: System.IO.FileNotFoundException: ファイルまたはアセンブリ ‘Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。
場所 Microsoft.ServiceBus.Configuration.Program.Main(String[] args)
————————————

原因は、C:\Program Files\Windows Azure SDK\v1.6\ServiceBus\ref にあるdllが見つけられないためでした。

dllをRelayConfigurationInstaller.exeと同じbinフォルダにコピーしてやると無事成功しました。


Posted in 未分類 | Tagged , | Leave a comment
This site has been fine-tuned by 3 WordPress Tweaks