概要
Oracle Cloud Infrastructure(OCI)のResource Schedulerで登録したリソース起動スケジュールが失敗した時にアラート通知します。
背景
Resource Schedulerはスケジュール定期実行できるサービスですが、2024年10月時点では実行がエラーになった場合の検出サービスが見当たらなかったため検出できる仕組みを作成しました。
構成
- VMからResource schedulerの最終実行結果を定期取得
- Resource schedulerの最終実行結果を取得
- 最終実行=SUCCEEDED以外があればメトリックを1にしてOCI Monitoringに送信
- 上記を定期実行
- OCI Monitoringで監視
- メトリック1の場合Notificationsで設定した送付先に通知
- VM自体の障害を考慮して、メトリックが存在しない場合Notificationsで設定した送付先に通知
- (オプション)失敗したSchedule名を抽出するFunctionを実行
- Resource schedulerの最終実行結果を取得
- 最終実行=SUCCEEDED以外のSchedule名を抽出
- Notificationsで設定した送付先に通知
VMからResource schedulerの最終実行結果を定期取得
準備
Oracle Cloud Infrastructure (OCI)内に以下を準備します
- Linux VMおよびPython実行環境
-
OCIの監視設定例-Webサーバ Disk使用率を参考にポリシー設定
今回はociユーザー資格情報を使用
Pythonコード
import json
import oci
import datetime
from pytz import timezone
# User Principal
config = oci.config.from_file()
# Check resource schedule
resource_scheduler_client = oci.resource_scheduler.ScheduleClient(config,service_endpoint="https://resource-scheduler.ap-tokyo-1.oci.oraclecloud.com")
list_schedules_response = resource_scheduler_client.list_schedules(
compartment_id="【COMPARTMENT OCID】",
lifecycle_state="ACTIVE"
)
with open('/tmp/jsonout.json', 'w') as f:
print(list_schedules_response.data, file=f)
with open('/tmp/jsonout.json', 'r') as f:
di = json.load(f)
di2=(di["items"])
runstatus=0
for item in di2:
if item["last_run_status"] != "SUCCEEDED":
runstatus=1
# Post value to OCI Monitor
monitoring_client = oci.monitoring.MonitoringClient(config,service_endpoint="https://telemetry-ingestion.ap-tokyo-1.oraclecloud.com")
times_stamp = datetime.datetime.now(timezone('UTC'))
post_metric_data_response = monitoring_client.post_metric_data(
post_metric_data_details=oci.monitoring.models.PostMetricDataDetails(
metric_data=[
oci.monitoring.models.MetricDataDetails(
namespace="custom_metrics",
compartment_id="【COMPARTMENT OCID】",
name="resource_scheduler",
dimensions={'result': "scheduler2"},
datapoints=[
oci.monitoring.models.Datapoint(
timestamp=datetime.datetime.strftime(
times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"),
value=runstatus)]
)]
)
)
5分おきに実行するようcron設定します
$ crontab -l
*/5 * * * * python /path/to/rscschcheck.py
OCI Monitoringで監視
準備
- Notificationsを利用して通知先設定
監視設定
- OCIコンソール ナビゲーションメニュー>>監視および管理>>モニタリング>>メトリック・エクスプローラにてメトリックが受信できていることを確認
- このメトリックを利用して2つのアラート設定
(オプション)失敗したSchedule名を抽出するFunctionを実行
準備
Resource schedulerはテナンシー単位の操作となります
私の環境はコンパートメント単位で操作許可が付与されており、テナンシーレベルでリソースプリンシパルができないため、FunctionsにResource schedulerの操作権限を付与することができません。
そのため、Policyは以下の方針としました。
- Policy
- Functionsにリソースプリンシパルを使用してOCI Vault情報を読み取る
- FunctionsにOCI Vaultから取得したociユーザー資格情報を使用してResource schedulerの操作を行う
- Functionsにリソースプリンシパルを使用してNotificationsで設定した送付先に通知
(FunctionsにResource schedulerの操作を行う権限が付与できればOCI Vaultは不要です)
- OCI Valut
- ociユーザー資格情報を登録
- OCI Functions アプリケーション作成
Functionsコード
import io
import json
import logging
import oci
import base64
import datetime
from pytz import timezone
def handler(ctx, data: io.BytesIO = None):
try:
signer = oci.auth.signers.get_resource_principals_signer()
# User principal from OCI Vault
secrets_client = oci.secrets.SecretsClient(config={},signer=signer,service_endpoint="https://secrets.vaults.ap-tokyo-1.oci.oraclecloud.com")
get_secret_bundle_response = secrets_client.get_secret_bundle(secret_id="【config_userのVAULTSECRET OCID】")
config_user=base64.b64decode(get_secret_bundle_response.data.secret_bundle_content.content).decode()
get_secret_bundle_response = secrets_client.get_secret_bundle(secret_id="【config_tenancyのVAULTSECRET OCID】")
config_tenancy=base64.b64decode(get_secret_bundle_response.data.secret_bundle_content.content).decode()
get_secret_bundle_response = secrets_client.get_secret_bundle(secret_id="【config_fingerprintのVAULTSECRET OCID】")
config_fingerprint=base64.b64decode(get_secret_bundle_response.data.secret_bundle_content.content).decode()
get_secret_bundle_response = secrets_client.get_secret_bundle(secret_id="【config_key_contentのVAULTSECRET OCID】")
config_key_content=base64.b64decode(get_secret_bundle_response.data.secret_bundle_content.content).decode()
config = {
"user": config_user,
"key_content": config_key_content,
"fingerprint": config_fingerprint,
"tenancy": config_tenancy,
"region": "ap-tokyo-1"
}
oci.config.validate_config(config)
resource_scheduler_client = oci.resource_scheduler.ScheduleClient(config,service_endpoint="https://resource-scheduler.ap-tokyo-1.oci.oraclecloud.com")
# Extract error
list_schedules_response = resource_scheduler_client.list_schedules(
compartment_id="【TENANCY OCID】",
lifecycle_state="ACTIVE"
)
with open('/tmp/jsonout.json', 'w') as f:
print(list_schedules_response.data, file=f)
with open('/tmp/jsonout.json', 'r') as f:
di = json.load(f)
di2=(di["items"])
with open('/tmp/displayname.json', 'w') as f2:
print("display name", file=f2)
for item in di2:
if item["last_run_status"] != "SUCCEEDED":
with open('/tmp/displayname.json', 'a') as f2:
print(item["display_name"], file=f2)
with open('/tmp/displayname.json', 'r') as f2:
displayname = f2.read()
# Publish Message
ons_client = oci.ons.NotificationDataPlaneClient(config={},signer=signer,service_endpoint="https://notification.ap-tokyo-1.oci.oraclecloud.com")
publish_message_response = ons_client.publish_message(
topic_id="【TOPIC OCID】",
message_details=oci.ons.models.MessageDetails(
body=displayname,
title="Resource Schedule Error")
)
except Exception as e:
print('ERROR: bad Event!', flush=True)
raise
schema_version: 20180708
name: rscscherror
version: 0.0.1
runtime: python
build_image: fnproject/python:3.11-dev
run_image: fnproject/python:3.11
entrypoint: /python/bin/fdk /function/func.py handler
memory: 256
fdk>=0.1.83
oci
デプロイして実行します
$ fn -v deploy --app fnapp
$ fn invoke fnapp rscscherror
成功すると以下のように失敗したスケジュールが通知されます
題名:Resource Schedule Error
本文:display name
SCH-EXAMPLE ←失敗したSchedule名
この作成したFunctionsを"OCI Monitoringで監視"で指定するNotifucationsに追加することによりアラート送付時にFunctionsを実行可能です。