2018年11月22日木曜日

Microsoft Flow のコネクタで接続エラーとなっているものをチェックする

Microsoft Flow を利用していて多くの人が感じるものに、作成したコネクタの接続情報が定期的に接続エラーになってしまう、というものがあります。接続時に利用しているアクセストークンの期限切れなどが理由で、気が付くとエラーになっていたりするのですが、毎回ポータルから確認するというのも手間でした。

今回、このチェックを Flow にて自動化してみました。

エントリとして結構長いので、先に確認したい方は github にエクスポートしたパッケージを用意してありますので、こちらもご利用ください。

まず前段階として、Flow でどのように接続情報が管理されているかについてです。

1.Flow 上での接続情報と取得

Logic Apps では API 接続として管理されている内容ですが、Flow では接続メニューか確認が行えます。その際、接続エラーとなっているものがあった場合、一覧上でエラーと表示され始めて問題が起きていることに気づける仕組みです。そのため、ある日突然 Flow が動かなくなってしまった、という状況に陥りやすい形となっています。

image

Flow では環境ごとに接続情報が管理されていて、その情報は Flow Management コネクタにて取得が可能です。

image

List My Connections(ListConnections) アクションはこのような形で、取得対象となる環境を指定して利用します。

image

実行すると環境に保持されている接続情報が取得でき、その中の情報として

{
   "name": "shared-approvals-zzzzzzz-xxxx-4883-bef8-1167d33409c9",
   "id": "/providers/Microsoft.PowerApps/apis/shared_approvals/connections/shared-approvals-zzzzzzz-xxxx-4883-bef8-1167d33409c9",
   "type": "Microsoft.PowerApps/apis/connections",
   "properties": {
     "apiId": "/providers/Microsoft.PowerApps/apis/shared_approvals",
     "displayName": "Approvals",
     "iconUri": "https://psux.azureedge.net/Content/Images/Connectors/Approvals3.svg",
     "statuses": [
       {
         "status": "Connected"
       }
     ],
     "connectionParameters": {
       "sku": "Enterprise"
     },
     "keywordsRemaining": 38,
     "createdBy": {
       "id": "zzzzzzz-xxxx-4447-b638-0b3aabfcae18",
       "displayName": "クマー",
       "email": "ahf@hogehoge.onmicrosoft.com",
       "type": "User",
       "tenantId": "zzzzzzz-6ace-4629-b910-6dc08bc4b453",
       "userPrincipalName": "ahf@hogehoge.onmicrosoft.com"
     },
     "createdTime": "2018-04-10T03:59:34.5393925Z",
     "lastModifiedTime": "2018-04-10T03:59:34.5393925Z",
     "environment": {
       "id": "/providers/Microsoft.PowerApps/environments/zzzzzzz-xxxx-4ef6-a237-0a357b9910de",
       "name": "zzzzzzz-xxxx-4ef6-a237-0a357b9910de"
     }
   }
}

このような形で、接続情報を取得できます。その際、statuses の配列の中に、status というキー名で接続状況が記載されており、ここが Connected でないものは接続エラーとなっているものとなります。ここをチェックすることで、対応が必要な接続をピックアップする、というのが今回のメインです。

2.作成した LogicFlow

image

今回作成した LogicFlow は上記のようになりました。単純なチェックだけであれば、この半分以下で済むのですが、それを通知しようとした際に色々問題がみつかったため、このような大き目の LogicFlow となっています。全体の流れとしては以下の通りです。

  1. 環境にある接続情報を取得
  2. 環境にある Flow の一覧を取得
  3. 接続情報から Connected でないものにフィルタリング
  4. Connected でない接続が現在でも利用されているかを Flow 一覧から確認
  5. 現在も利用されている接続だった場合、コネクタ名を記録
  6. 記録された結果から重複を取り除き、メールで通知

3.接続情報を利用しやすい形に調整する

Flow Management コネクタで取得した接続情報は、値として大きく複雑な構造であるので、後続で利用しやすい形に調整します。選択アクションを利用して、必要項目に絞った配列へと再作成しています。

image

今回の処理で必要なのは「名称」と「接続状態」です。名称については、取得できた値をそのまま利用していますが、この値は Flow 内部で命名された名称で、利用者側にはオープンにされていないものです。

もう一つの接続状態は、以下の関数を指定して利用しやすくしています。

first(item()['properties']['statuses'])['status']

一番最初にサンプルの接続情報を記載しているので、そこと合わせてみてください。ポイントは、接続状態が記録される status という値は、properties.statuses に配列で設定されている点です。そのため first 関数を利用して、statuses 配列の最初の値を利用しています。定義として配列なので、他の値が来るのかと思っていたのですが、今時点では複数の接続状態が設定されているケースは確認できていません。

4.利用している接続情報のみチェックを行う

image

全体図を見てもらうと、接続情報を取得するのと同時に、作成した Flow の一覧を取得しているのに気づかれると思います。これは理由があって、Flow の接続情報には現在利用していないものも残っており、チェックが不要なものも含まれているためです。また、Flow のポータル上に表示されていないゴミ情報も残っていることがあり、余分な処理を省く必要があります。

そのため、現在存在している Flow の一覧を取得し、そのどれかで利用されているかどうかという判断を行っています。

"value": [
   {
     "name": "zzzzzzzz-xxxx-478b-b279-f16ef9ab1e80",
     "id": "/providers/Microsoft.Flow/environments/zzzzzzzz-df04-4ef6-a237-0a357b9910de/flows/zzzzzzzz-xxxx-478b-b279-f16ef9ab1e80",
     "type": "Microsoft.Flow/environments/flows",
     "properties": {
       "apiId": "/providers/Microsoft.PowerApps/apis/shared_logicflows",
       "displayName": "Get an email report of approvals waiting for my response",
       "userType": "Owner",
       "state": "Stopped",
       "connectionReferences": {
         "shared_commondataservice": {
           "connectionName": "shared-commondataser-zzzzzzzz-d7b6-4703-ae28-91074b9e1f96",
           "source": "Embedded",
           "id": "/providers/Microsoft.PowerApps/apis/shared_commondataservice",
           "displayName": "Common Data Service",
           "iconUri": "https://connectoricons-prod.azureedge.net/commondataservice/icon_1.0.1002.1175.png",
           "brandColor": "#742775",
           "tier": "NotSpecified"
         },
         "shared_flowpush": {
           "connectionName": "shared-flowpush-zzzzzzzz-cacb-432b-b285-6157e8d10791",
           "source": "Embedded",
           "id": "/providers/Microsoft.PowerApps/apis/shared_flowpush",
           "displayName": "Notifications",
           "iconUri": "https://psux.azureedge.net/Content/Images/Connectors/FlowNotification.svg",
           "brandColor": "#FF3B30",
           "tier": "NotSpecified"
         }
       },
       "createdTime": "2018-04-10T04:25:58.2803477Z",
       "lastModifiedTime": "2018-04-11T02:05:13.2155405Z",
       "templateName": "33d7ad77f610418d8cf3d61fe39fd507",
       "environment": {
         "name": "zzzzzzzz-df04-4ef6-a237-0a357b9910de",
         "type": "Microsoft.Flow/environments",
         "id": "/providers/Microsoft.Flow/environments/zzzzzzzz-df04-4ef6-a237-0a357b9910de"
       },
       "definitionSummary": {
         "triggers": [   ...以下省略

Flow の情報は上記のように取得できます。Logic Apps では CodeView からも参照できる、LogicFlow の定義そのものです。この中に、利用している接続の情報も含まれています。

properties.connectionReferences の中にその接続情報が記載されているのですが、ここが今回の作業における一番のネックでした。connectionReference の中は、接続名をキーとして、その詳細情報が記録されています。つまり、この中にどのような名称(shared_commondataservice や shared_flowpush )で値が記録されているか、というのが不定だということです。LogicFlow の現在の機能では、キー名を取得することができませんので、この部分をどうするかというのが一番の問題でした。

この点に対しては、次のようなやり方にて対応しています。

image

Flow に記録されている接続情報は、 キー名:[決まったレイアウト]、というフォーマットです。connectionReferences 配下だけに限定できればその後の処理も行いやすくなります。

split(replace(string(items('Flowごとの接続情報をチェックする')['properties']['connectionReferences']),'},','}},'),'},')

見ての通り、非常に力業となります。connectReference の値が、”connectReference “: { ~ } という形式で保持されているので、、”connectReference “:  な部分を除去し、{ ~ }  と値だけの状況にします。例えば、複数の値が設定されていた場合は、{ ~ }, { ~ }・・・、という形式に調整を行い、値だけの配列を作成します(なお、上記の関数にあるように、ここでは除去を行ってはいませんが、後続の処理にて行っています)

そうすることで、後続の処理では ForEach ループを用いてこの作成した配列をもとに、判定を行うことが可能になります。

image

ループの中では、利用しやすいように、先ほど {~} な形に変換した値を json 関数にて JSON値 にしています。その際に先ほどあった connectReference の部分を除去しています。

json(substring(item(), add(indexOf(item(), ':'), 1), sub(length(item()), add(indexOf(item(), ':'), 1))))

キー名と値を区切る : の位置を indexOf 関数で取得し、その次の文字から末尾までを抽出させ、結果を JSON 関数で JSON 値に変換しています。

「検索条件の設定」は特に行う必要はありません。テストしている際に確認をしやすくするためのものです。

image

Flow の情報にある接続情報の中に、エラーとなった接続譲歩と同一の名称が存在しているか、値をフィルタリングさせています。

image

このあたりになると、ダイアログ側で利用したい値が出てこないことが多いので、詳細設定モードを利用しての直接記載が便利になってきます。

image

フィルタした結果からの判断部分は、このように記載しています。

@greater(length(body('接続一覧から対象の接続情報に絞り込む')), 0)

フィルタした結果が 1 件以上あるのであれば、この Flow でエラーとなっている接続を利用していることになります。ここで 0 件であれば、この Flow では利用されていないことになります。

image

1 件以上あった場合ですが、今回はこのタイミングでその接続がエラーかどうかを判定させています。このあたりは処理の組み立て方な部分でして、あらかじめエラーのものだけに絞ってから処理を行えば、ここでの判定は不要になります。

@not(equals(first(first(actionBody('接続一覧から対象の接続情報に絞り込む'))['properties']?['statuses'])?['status'], 'Connected'))

image

判定結果でエラーだった場合には、後で結果を送信するためにも配列で作成した変数に追加しています。ここで配列を利用している理由ですが、同じコネクタの接続でも複数作成することができますので、単純に文字を追加していった場合は結果が重複してしまいます。そのため一度配列に追加し、あとで重複分を除去しています。

image

重複の除去は、union 関数を利用します。union 関数は二つ配列を指定する必要があるのですが、ここでは同じ変数を指定します。そうすることで重複が除去できます。

image

重複を除去したら、最後に通知用のメールを作成します。エラーな接続が記録されている配列を、join 関数にて一つの文字列へと変換します。その際、<br> で区切らせ、メールの文面上で改行させます。

実際に送付された結果はこのようになりました。こうすることで、このメールが届いた時だけ Flow ポータルへ行って接続情報を修正すればよいと、確認行為自体を自動化することができます。

0 件のコメント:

コメントを投稿