Azure CLI で仮想マシンを全停止する

# はじめに
Azure Portal にアクセスして仮想マシンを管理していたのですが、台数が多いと起動停止だけでも手順が少し煩雑に感じられてきました。このストックでは Azure CLI 2.0 を使用してどうやったら簡単にパブリッククラウドの必要なときに必要なだけという柔軟なリソースを享受できるのかというのを目的にあれこれ試した備忘録を残しておこうと思います。
コマンド実行結果は適当にマスクしてます。
__本情報の内容（添付文書、リンク先などを含む）は、作成日時点でのものであり、予告なく変更される場合があります。__

# 手順
## 事前準備
以前書いたストックで、バッチで操作可能にするためにサービスプリンシパルを作成しておきます。
[Azure CLI をバッチで使用する方法](https://qiita.com/mihochannel/items/b297b07c826b631ba0ea)

## 仮想マシンのリストアップ
仮想マシンのリストアップをするためには、__az vm list__ や __az vm show__コマンドレットを使用します。そのまま実行すればわかるのですが、__az vm list__にオプションをつけないと詳細まで含む json が結果として返されて何が何だかわかりません。実行例を貼っておきますね。


```bash
$az vm list
[
  {
    "additionalProperties": {},
    "availabilitySet": null,
    "diagnosticsProfile": {
      "additionalProperties": {},
      "bootDiagnostics": {
        "additionalProperties": {},
        "enabled": true,
        "storageUri": "https://...snip....blob.core.windows.net/"
      }
    },
    "hardwareProfile": {
      "additionalProperties": {},
      "vmSize": "Standard_D2s_v3"
    },
    "id": "/subscriptions/...snip.../resourceGroups/ALOHA/providers/Microsoft.Compute/virtualMachines/commersonii",
    "identity": null,
    "instanceView": null,
    "licenseType": null,
    "location": "japanwest",
    "name": "commersonii",
    "networkProfile": {
      "additionalProperties": {},
      "networkInterfaces": [
        {
          "additionalProperties": {},
          "id": "/subscriptions/...snip.../resourceGroups/Aloha/providers/Microsoft.Network/networkInterfaces/commersonii273",
          "primary": null,
          "resourceGroup": "Aloha"
        }
      ]
    },
    "osProfile": {
      "additionalProperties": {},
      "adminPassword": null,
      "adminUsername": "miyamam",
      "computerName": "commersonii",
      "customData": null,
      "linuxConfiguration": {
        "additionalProperties": {},
        "disablePasswordAuthentication": true,
        "ssh": {
          "additionalProperties": {},
          "publicKeys": [
            {
              "additionalProperties": {},
              "keyData": "ssh-rsa ...snip...",
              "path": "/home/miyamam/.ssh/authorized_keys"
            }
          ]
        }
      },
      "secrets": [],
      "windowsConfiguration": null
    },
    "plan": null,
    "provisioningState": "Succeeded",
    "resourceGroup": "ALOHA",
    "resources": [
      {
        "additionalProperties": {},
        "autoUpgradeMinorVersion": null,
        "forceUpdateTag": null,
        "id": "/subscriptions/...snip.../resourceGroups/ALOHA/providers/Microsoft.Compute/virtualMachines/commersonii/extensions/Microsoft.Insights.VMDiagnosticsSettings",
        "instanceView": null,
        "location": null,
        "name": null,
        "protectedSettings": null,
        "provisioningState": null,
        "publisher": null,
        "resourceGroup": "ALOHA",
        "settings": null,
        "tags": null,
        "type": null,
        "typeHandlerVersion": null,
        "virtualMachineExtensionType": null
      },
      {
        "additionalProperties": {},
        "autoUpgradeMinorVersion": null,
        "forceUpdateTag": null,
        "id": "/subscriptions/...snip.../resourceGroups/ALOHA/providers/Microsoft.Compute/virtualMachines/commersonii/extensions/OmsAgentForLinux",
        "instanceView": null,
        "location": null,
        "name": null,
        "protectedSettings": null,
        "provisioningState": null,
        "publisher": null,
        "resourceGroup": "ALOHA",
        "settings": null,
        "tags": null,
        "type": null,
        "typeHandlerVersion": null,
        "virtualMachineExtensionType": null
      }
    ],
    "storageProfile": {
      "additionalProper
#...snip...
```

結局ほしいのは、__リソースグループ__と__仮想マシン名__だけなので、タブ区切りでもらうと下記のように指定します。

```bash
$az vm list --query "[].[name, resourceGroup]" --output tsv 
commersonii	ALOHA
dolphin	ALOHA
Hawaii	ALOHA
Manta	ALOHA
Naia	ALOHA
Oahu	ALOHA
```

## ステータスチェック
ステータスチェックするコマンドは__az vm get-instance-view__ コマンドを使用します。こちらもそのままだと使い勝手が悪いので、ステータスだけを取得するように書くと下記のようになります。

```bash
$az vm get-instance-view -g $rgname -n $vmname --query instanceView.statuses[1].displayStatus --output tsv
```

## 起動、停止処理の条件
__az vm stop__ と __az vm start__コマンドレットを使いますが、引数は先ほど取得した仮想マシン名とリソースグループ名です。
起動用シェル等にする場合は、オプションで__--no-wait__をつけてもよいと思います。
これを配列分まわすと下記のような感じになります。
__気づいたのですが課金対策に使用する場合は、割り当て解除する必要があります。__
__az vm stop__ のかわりに __az vm deallocate__を使用しましょう。

```bash
az login --service-principal --username ...snip... --password ...snip... --tenant ...snip...

az vm list --query "[].[name, resourceGroup]" --output tsv | while read line
    do
        set -- $line
        vmname=$1
        rgname=$2

        vmstatus=`az vm get-instance-view -g $rgname -n $vmname --query instanceView.statuses[1].displayStatus --output tsv`

        if [ "$vmstatus" = "VM stopped" ]
        then
            echo $vmname "is starting"
            az vm start -n $vmname -g $rgname
        else
            echo $vmname $vmstatus
        fi
    done
```

開発環境等の使ってるときだけ起動したいケースでは、スクリプトに起動停止を書いておくことで柔軟な利用ができると思います。私の場合、ずっと稼働させておく必要がないVMばかりだったので全停止にしてますが、除外を加えるとか特定のリソースグループのみを対象にしてもよいと思います。
GUIが好き？ということであれば[Azure DevTest Labs](https://azure.microsoft.com/ja-jp/services/devtest-lab/)のご利用もご検討されてみてはいかがでしょうか。

# 参考資料
[Azure CLI をバッチで使用する方法](https://qiita.com/mihochannel/items/b297b07c826b631ba0ea)
[Azure CLI 2.0](https://docs.microsoft.com/en-us/cli/azure/overview?view=azure-cli-latest)
[Use JMESPath queries with Azure CLI 2.0](https://docs.microsoft.com/en-us/cli/azure/query-azure-cli?view=azure-cli-latest)