やりたいこと
トライアル環境のSAP HANA Cloudのインスタンスは毎日自動的に停止するので、使いたいときにすぐに使えるよう、停止状態を確認したら再起動したいです。
これまでにやったことと、課題
以前の記事で、毎日決まった時刻にインスタンスの起動をスケジュールすることはできました。
HANA Cloudの稼働状況を確認すると、日本時間の15時頃に停止していることがわかりますが、停止時刻には若干の変動があるようです。
停止から起動までの時間を最小にできないだろうか、と思ったことが今回の検証のきっかけです。
※単純に起動を5分おきにスケジュールするでもいいのですが、Automation Pilotで色々やってみたいために検証しました
参考にしたもの
Automation PilotのサンプルリポジトリにあるCheck HANA Cloud Availabilityというコマンドを参考に作成しました。
以下で参考にしたコマンドについて解説します。
インプット、アウトプット
インプットはHANA Cloudに関する情報、BTPのログイン情報など多数、アウトプットは3つです。
コマンド
このコマンドは4つのステップから構成されています。
- HANA CloudのAPIアクセス用のトークンを取得
- APIを使ってHANA Cloudの状態を確認
- (HANA Cloudが停止している場合)Alert Notificationに通知
- (HANA Cloudが停止している場合)HANA Cloudを起動
次に、今回作成しようとしているコマンドに関連するポイントについて説明します。
APIを使ってHANA Cloudの状態を確認
SAP HANA CloudのMetrics ServiceのAPIを使ってHANA Cloudの状態を取得しています。
https://api.sap.com/api/MetricsAPI/path/get_metrics_v1_serviceInstances__serviceInstanceID__values
names=HDBAccessible
というパラメータをつけて呼び出すと、直近1時間の30秒ごとの状態を返してくれます。valueに"1"が設定されている場合はアクセス可能な状態です。
HANA Cloudを起動
dblm-sapcp:StartHanaCloudInstance:1
というコマンドを使っています。これはCloud Foundryに作成されたインスタンスを起動するコマンドです。
今回は"Other Environments"で作成したHANA Cloudインスタンスを起動するので、sm-sapcp:UpdateServiceInstance:1
というコマンドを使用します。
作成したもの
インプット、アウトプット
コマンドで必要なパラメータはHANA Cloudのサービスキーと、Service Managerのサービスキーにすべて入っているので、この2つをインプットとします。アウトプットは参考にしたコマンドと同様です。
HANA Cloudのサービスキーは、Service Bindingで作成します。
コマンド
ステップは以下の2つです。pingHanaCloudのステップで使っているhttp-sapcp:HttpRequest:1
というコマンドがOAuth 2.0 Client Credentials Flowに対応しているので、事前にトークンを取得するステップは不要になりました。
HANA Cloudの状態を確認
http-sapcp:HttpRequest:1
コマンドのパラメータを以下のように設定しています。
URLはサービスキーのhostの値をもとに、式を使って設定しています。
https://api.gateway.orchestration.$(.execution.input.hanaCloudServiceKey.host | split(".") | .[2:] | join("."))/metrics/v1/serviceInstances/$(.execution.input.hanaCloudServiceKey.host | split(".")[0])/values?names=HDBAccessible
式の作成では全体的にChatGPTを活用しました。利用可能なjqの式には制限があるので、以下のヘルプを参照します。
https://help.sap.com/docs/automation-pilot/automation-pilot/dynamic-expression
サンプルのコマンドではインプットパラメータが多数ありましたが、jqを駆使することでサービスキーのみにできたのがよかったです。
hostの値
37b4cc7b-2eb5-4e06-912d-511d1a50135e
.hana.trial-us10.hanacloud.ondemand.com
設定されたURL(網掛けがhostから設定された部分)
https
://api.gateway.orchestration.trial-us10.hanacloud.ondemand.com
/metrics/v1/serviceInstances/37b4cc7b-2eb5-4e06-912d-511d1a50135e
/values?names=HDBAccessible
レスポンスボディにはHANA Cloudの状態が時系列(古いものが上)で並んでいるので、直前の状態を確認するためにAdvancedタブのResponse Body Transformerで逆順に並べ替えています。これは、参考にしたコマンドの設定と同じです。
HANA Cloudを起動
HANA Cloudが停止している場合、sm-sapcp:UpdateServiceInstance:1
というコマンドを使い、HANA Cloudを起動します。
「停止している場合」という条件は、コマンドのConditionで以下のように設定します。直近の3つ(90秒間)のHANA Cloudの状態で1つも稼働状態がない場合、ということです。
コマンドのインプットにはHANA CloudのサービスインスタンスIDとService Managerのキーを渡します。
また、parametersに以下を設定することで、インスタンスが起動されます。
{
"data": {
"serviceStopped": false
}
}
実行結果
HANA Cloudが稼働している場合、アウトプットは以下のようになります。HANA Cloudの起動がスキップされています。実行時間は約2秒です。
HANA Cloudが停止している場合、アウトプットは以下のようになります。実行時間は3分半でした。
スケジュール
14:50~15:15の間、5分おきに起動するようにしたいので、以下のようにスケジュールします。(実際には14:00, 14:05, 14:10, 14:15, 15:50, 15:55にも動きます)
最終的には、15:10, 15:15, 15:20の3回で十分でした
初日の実行結果は以下のようになっていました(初日は20~40分台にもスケジュール)。6:10 UTCに開始したものが時間がかかっており、ここでHANA Cloudが起動したのがわかります。
Appendix: 使い方
1. カタログのインポート
{
"id": "HANACloud-<<<TENANT_ID>>>",
"technicalName": "HANACloud",
"name": "Manage HANA Cloud",
"description": "",
"owner": "<<<TENANT_ID>>>",
"inputs": [
{
"id": "HANACloud-<<<TENANT_ID>>>:HanaCloudCredentials:1",
"name": "HanaCloudCredentials",
"description": null,
"catalog": "HANACloud-<<<TENANT_ID>>>",
"owner": null,
"version": 1,
"keys": {
"serviceManagerKey": {
"type": "object",
"sensitive": true,
"description": "Service Manager key"
},
"hanaCloudServiceKey": {
"type": "object",
"sensitive": true,
"description": "HANA Cloud service key"
}
},
"values": {
"serviceManagerKey": "",
"hanaCloudServiceKey": ""
},
"tags": {}
}
],
"commands": [
{
"configuration": {
"values": [],
"output": {
"isHanaCloudAvailable": "$(.pingHanaCloud.output.body | toArray | [.[0] ,.[1] ,.[2]] | any(.value == 1) )",
"resultHanaStart": "$(.startHanaCloud.executed)",
"checkPing": "$(.pingHanaCloud.output.body)"
},
"executors": [
{
"execute": "http-sapcp:HttpRequest:1",
"input": {
"responseBodyTransformer": "toObject.data[0].values | reverse",
"clientId": "$(.execution.input.hanaCloudServiceKey.uaa.clientid)",
"tokenUrl": "$(.execution.input.hanaCloudServiceKey.uaa.url)/oauth/token?grant_type=client_credentials",
"method": "GET",
"clientSecret": "$(.execution.input.hanaCloudServiceKey.uaa.clientsecret)",
"url": "https://api.gateway.orchestration.$(.execution.input.hanaCloudServiceKey.host | split(\".\") | .[2:] | join(\".\"))/metrics/v1/serviceInstances/$(.execution.input.hanaCloudServiceKey.host | split(\".\")[0])/values?names=HDBAccessible"
},
"alias": "pingHanaCloud",
"description": null,
"progressMessage": null,
"initialDelay": null,
"pause": null,
"when": null,
"validate": null,
"autoRetry": null,
"repeat": null,
"errorMessages": [],
"dryRun": null
},
{
"execute": "sm-sapcp:UpdateServiceInstance:1",
"input": {
"instanceId": "$(.execution.input.hanaCloudServiceKey.host | split(\".\")[0])",
"serviceKey": "$(.execution.input.serviceManagerKey)",
"parameters": "{ \"data\": { \"serviceStopped\": false } }"
},
"alias": "startHanaCloud",
"description": null,
"progressMessage": null,
"initialDelay": null,
"pause": null,
"when": {
"semantic": "OR",
"conditions": [
{
"semantic": "OR",
"cases": [
{
"expression": "$(.pingHanaCloud.output.body | toArray | [.[0] ,.[1] ,.[2]] | any(.value == 1) )",
"operator": "EQUALS",
"semantic": "OR",
"values": [
"false"
]
}
]
}
]
},
"validate": null,
"autoRetry": null,
"repeat": null,
"errorMessages": [],
"dryRun": null
}
],
"listeners": []
},
"id": "HANACloud-<<<TENANT_ID>>>:CheckHanaCloudAvailability:1",
"name": "CheckHanaCloudAvailability",
"description": "Check availability for HANA Cloud",
"catalog": "HANACloud-<<<TENANT_ID>>>",
"version": 1,
"inputKeys": {
"serviceManagerKey": {
"type": "object",
"sensitive": true,
"required": false,
"minSize": null,
"maxSize": null,
"minValue": null,
"maxValue": null,
"allowedValues": null,
"allowedValuesFromInputKeys": null,
"suggestedValues": null,
"suggestedValuesFromInputKeys": null,
"defaultValue": null,
"defaultValueFromInput": {
"inputReference": "HANACloud-<<<TENANT_ID>>>:HanaCloudCredentials:1",
"inputKey": "serviceManagerKey"
},
"description": null
},
"hanaCloudServiceKey": {
"type": "object",
"sensitive": true,
"required": false,
"minSize": null,
"maxSize": null,
"minValue": null,
"maxValue": null,
"allowedValues": null,
"allowedValuesFromInputKeys": null,
"suggestedValues": null,
"suggestedValuesFromInputKeys": null,
"defaultValue": null,
"defaultValueFromInput": {
"inputReference": "HANACloud-<<<TENANT_ID>>>:HanaCloudCredentials:1",
"inputKey": "hanaCloudServiceKey"
},
"description": null
}
},
"outputKeys": {
"isHanaCloudAvailable": {
"type": "string",
"sensitive": false,
"description": "Check on whether or not the HANA Cloud instance is available, where: \"true\" = HANA Cloud is available; \"false\" = HANA Cloud is not available."
},
"resultHanaStart": {
"type": "string",
"sensitive": false,
"description": null
},
"checkPing": {
"type": "string",
"sensitive": false,
"description": "The entire response for the metric \"HDBAccessible\" returned by HANA Cloud Metrics Service REST API."
}
},
"tags": {}
}
]
}
2. インプットの設定
HanaCloudCredentials
というインプットにHANA CloudとService Managerのサービスキーを設定してください。
3. 実行
CheckHanaCloudAvailability
というコマンドを実行します。