しばたテックブログ

PowerShellを中心に気分で書いている技術ブログです。

AzurePSDriveの実装を調べてみた

azure-mokumoku.connpass.com

先週ちょっと東京へ行く用事があり、それに合わせてAzureもくもく会@新宿に参加した際に調べた内容をまとめたエントリです。

AzurePSDriveとは

AzurePSDriveはAzure CloudShell(PowerShell)を起動した際のカレントロケーションがPS Azure:\>となるアレを提供する仕組みです。

f:id:stknohg:20180829203208p:plain

PowerShellのドライブはファイルシステム以外にも階層構造をもつデータであれば拡張して扱うことが可能であり、AzurePSDriveではAzureのサブスクリプションとそれに紐づく各リソースをドライブとして扱うことができる様になります。

類似のものとしてはIISの設定を行うWebAdminstrationモジュールのIISドライブや、SqlServerモジュールSQL Serverドライブなどがあり、こちらの方がイメージがつかみやすいかもしれません。

ソースコード

AzurePSDriveはGitHubでそのソースが公開されています。

github.com

英語ですが基本的な概念や使い方もこちらに記載されています。

AzurePSDriveの実装について

ここから本題に入ります。
Azure Cloud Shellの環境で実際にAzurePSDriveを使いながらその実装を追っていきます。

Simple Hierarchy in PowerShell(SHiPS)

AzurePSDriveでは独自のドライブを実装するのにSimple Hierarchy in PowerShell(SHiPS)と呼ばれるPowerShellモジュールを利用しています。

github.com

このモジュールは従来独自の実装が必要であったPSドライブを簡易に作成するためのモジュールであり、SHiPSDirectorySHiPSLeafといったクラスを継承したクラスを作ることで簡単に階層構造を表現することができる様になります。

詳しい話と実装例がぎたぱそ先生の本(4.9.14 SHiPSとクラスを使ったPSドライブの自作)に書いてますので気になる人はぜひご覧ください。(宣伝)

PowerShell実践ガイドブック ~クロスプラットフォーム対応の次世代シェルを徹底解説~

PowerShell実践ガイドブック ~クロスプラットフォーム対応の次世代シェルを徹底解説~

以下同書のサンプルコードを例として紹介します。

# SHiPSの実装例
#   https://github.com/guitarrapc/Book-PowerShell-Samples/blob/master/Book-PowerShell-Samples/Chapter4/4.9_Class/PSDrive/SolarSystem.psm1 より抜粋
using namespace Microsoft.PowerShell.SHiPS

# SHiPSDirectory を継承したクラスでコンテナとなる要素を定義
class SolarSystem : SHiPSDirectory {

    # ・・・中略・・・

}

# SHiPSLeaf を継承したクラスで枝要素を定義
class Moon : SHiPSLeaf {
    
    # ・・・中略・・・
}

Azure PowerShellモジュールと独自の型定義

AzurePSDriveは内部でAzureのリソースにアクセスする際にAzure PowerShell moduleの機能を利用しています。
Windows PowerShell、PowerShell Core両方に対応しており、現時点のバージョン(Ver.0.8.7)では、

  • AzureRM.Profile (AzureRM.Profile.NetCore)
  • AzureRM.Resources (AzureRM.Resources.NetCore)
  • AzureRM.Compute (AzureRM.Compute.NetCore)
  • AzureRM.Websites (AzureRM.Websites.NetCore)
  • Azure.Storage (Azure.Storage.NetCore)

が依存モジュールとなっています。

また、内部的にはAzure PowerShell moduleのオブジェクトをそのまま使っている部分があるのですが、一部オブジェクトについてはドライブ独自の型に差し替えられています。

例として、改めて後述しますが、AllResources要素ではGet-AzureRmResourceの結果である Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.PSResource型のオブジェクトをそのまま使っているのですが、この型がAzurePSDriveではAzurePSDriveResourceTypeになります。

細かい説明は省きますが、実装としては以下の様にして取得したオブジェクトの型を差し替えています。

# AzurePSDriveResource.psm1 より一部抜粋
& "$script:AzureRM_Resources\Get-AzureRmResource" | %{ $_.psobject.typenames.Insert(0, "AzurePSDriveResourceType"); $_ }

CloudShellログイン時点

ここからはAzure Cloud Shell(PowerShell)の実際の画面を基に各階層の内容について説明していきます。

最初にAzure Cloud Shellにログインした時点では最上位の階層であるAzureドライブがカレントロケーションとなります。

f:id:stknohg:20180829203208p:plain

Get-PSDriveを使うとこのAzureドライブの情報を見ることができます。

PS Azure:\> Get-PSDrive | Format-Table -AutoSize

Name     Used (GB) Free (GB) Provider    Root               CurrentLocation
----     --------- --------- --------    ----               ---------------
/            15.01     33.40 FileSystem  /                      home/stknohg
Alias                        Alias
Azure                        SHiPS       AzurePSDrive#Azure
Env                          Environment
Function                     Function
Variable                     Variable

ファイルシステムなどのドライブの中にAzureドライブが存在し、SHiPSプロバイダーとして定義されていることが分かります。

第1階層 : サブスクリプション

AzureドライブでGet-ChildItem(dir)を実行すると子要素を一覧することができ、たとえば私のアカウントだと以下の様に表示されます。

PS Azure:\> dir


    Directory: Azure:


Mode SubscriptionName SubscriptionId                       TenantId                             State
---- ---------------- --------------                       --------                             -----
+    stknohg          ********-****-****-****-************ ********-****-****-****-************ Enabled

最初の階層はログインしたアカウントに紐づくサブスクリプションが列挙されます。

各サブスクリプションはSubscription型として定義されており、内部的にはACC_TID環境変数が定義されていればそのテナントID、ACC_TID環境変数が定義されていない場合は(Get-AzureRmTenant)[0].IdとなるテナントIDに紐づくサブスクリプションをGet-AzureRmSubscriptionで取得しています。

ちなみに現在Azure Cloud Shellは全てLinux(Ubuntu)のコンテナになってしまったため、lsコマンドは/bin/lsなのでAzureドライブの子要素を取得するのには使えませんので注意してください。

第2階層 : リソース分類

つづけてSet-Location(cd)でサブスクリプション(ここではstknohg)に移動し、子要素を一覧すると以下の様になります。

PS Azure:\> cd ./stknohg/
PS Azure:\> dir


    Directory: Azure:/stknohg


Mode Name
---- ----
+    AllResources
+    ResourceGroups
+    StorageAccounts
+    VirtualMachines
+    WebApps

SubScriptionの子要素は以下で固定されています。

  • AllResources
  • ResourceGroups
  • StorageAccounts
  • VirtualMachines
  • WebApps

それぞれ名前から予測はつくと思いますが詳細は後述します。

第3階層(AllResouces)

ここからはSubScriptionの各子要素について説明します。
最初にAllResources要素についてです。

この要素はAllResources型で表現され、内容としては単純にGet-AzureRmResourceの結果を返しているだけになります。
さらなる子要素はありません。

通常Get-AzureRmResourceの結果は Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.PSResource型ですが、表向きの型をAzurePSDriveResourceTypeに更新しており、Get-Memberで取得できる型名は後者となっています。

第3階層(ResourceGroups)

ResourceGroups要素がおそらくAzurePSDriveで扱うメインの要素になるかと思います。

この要素はResourceGroups型で表現され、子要素にResourceGroup型のオブジェクトを持ちます。

実装としては、Get-AzureRmResourceGroupGet-AzureRmResourceを内部で使い、各リソースを呼出してリソースの階層構造を表現しています。
ここから第4階層(ResourceProvider)、第5階層(ResourceType)と続くのですが説明が冗長になる*1ので本エントリではこのくらいにしておきます。

第3階層(StorageAccounts)

ここからのStorageAccounts、VirtualMachines、WebAppsについてはリソースの中でもよく使うであろうものを特別視したものと思われます。
(もしかしたら子要素の表現が難しいものを特別視している可能性もありますが、ちょっと断言できません...)

この要素はStorageAccounts型で表現され、Get-AzureRmStorageAccountの結果を子要素にStorageAccount型として持ちます。

StorageAccountの子要素として各ストレージの種類に応じた、

  • Blobs
  • Files
  • Tables
  • Queues

がありそれぞれの情報にアクセスすることができます。
内部的にはAzure.Storage (Azure.Storage.NetCore)モジュールの各コマンドレットが使われ、その結果を利用しています。

第3階層(VirtualMachines)

この要素はVirtualMachines型で表現され、 Get-AzureRmVMの結果をAzurePSDriveVM型として子要素に持ちます。

これ以上の階層は無く、単純にVMの一覧が取得できて終わりの様です。

第3階層(WebApps)

この要素はWebApps型として表現され、Get-AzureRmWebAppの結果をAzurePSDriveWebApp型として子要素に持ちます。

この要素もこれ以上の階層は無く、単純にWebAppの一覧が取得できて終わりです。

最後に

とりあえずこんな感じです。

私自身Azureをさほど使いこなしていないため、ソースを読み間違えている部分があるかもしれません。
もし本エントリの内容におかしな点がありましたらフィードバックしていただけると嬉しいです。

*1:調べきれなかったとも言います...