mcpField
D
dd-oci-integration

dd-oci-integration

github.com/datadog-labsクラウド・DevOps18348 回インストール今日更新
リポジトリ

dd-oci-integration について

dd-oci-integration は、Terraform で Datadog と OCI を連携するための手順スキルです。OCI の認証情報とユーザー情報を検証し、設定項目を確認してからインフラ変更の適用を求めます。

主な機能

  1. 01Terraform による OCI 連携設定
  2. 02OCI IAM ユーザー、グループ、ポリシー、API キーの作成
  3. 03OCI プロファイル認証情報の検証
  4. 04選択したプロファイルからテナンシーとユーザーの OCID を取得
  5. 05オプションのログ収集設定

活用シーン

  1. 01OCI テナンシーを Datadog に接続
  2. 02連携リソースのプロビジョニング前に OCI プロファイルを確認
  3. 03OCI ログ転送を設定するか選択

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/datadog-labs/agent-skills --skill dd-oci-integration

インストール後、Claude Code で/dd-oci-integrationを入力して読み込まれたか確認します。

詳細

Datadog OCI インテグレーション

Terraform を使用して Datadog OCI インテグレーションを設定するユーザーを支援します。

このインテグレーションでは、Datadog の公式 OCI Terraform モジュールを使って、顧客の OCI テナンシーに必要な IAM リソース(ユーザー、グループ、ポリシー、API キー)を作成し、Datadog に登録します。

この設定は実際に操作しながら進めます。ユーザーにコマンドの一覧を渡すのではなく、会話の中で自分でコマンドを実行し、ユーザーにも状況を共有してください。また、terraform apply の前に確認を求めてください。

別のスキルを実行する

以下の手順では、別のスキル(たとえば dd-account-setup)に処理を引き継ぐ場合があります。そのスキルがインストールされていれば、実行してください。インストールされていない場合は、ダウンロードしてローカルで読み込んでください。

SKILL='<skill-name>'
case "$SKILL" in ''|/*|*..*|*[!A-Za-z0-9._/-]*) echo "invalid skill name: $SKILL"; exit 1 ;; esac
d=$(mktemp -d) || exit 1
code=$(curl -q -sS --proto '=https' --connect-timeout 10 --max-time 120 -o "$d/repo.tar.gz" -w '%{http_code}' \
  https://codeload.github.com/datadog-labs/agent-skills/tar.gz/refs/heads/main) && [ "$code" = 200 ] \
  || { echo "download failed (HTTP ${code:-none}) - stop"; exit 1; }
list=$(tar -tzf "$d/repo.tar.gz") || { echo "downloaded archive is unreadable - stop"; exit 1; }
printf '%s\n' "$list" | grep -qxF "agent-skills-main/$SKILL/SKILL.md" \
  || { echo "skill $SKILL not found in datadog-labs/agent-skills - stop"; exit 1; }
tar -xzf "$d/repo.tar.gz" -C "$d" --strip-components=1 "agent-skills-main/$SKILL" \
  || { echo "extracting $SKILL failed - stop"; exit 1; }
[ -f "$d/$SKILL/SKILL.md" ] || { echo "extracted skill $SKILL is missing SKILL.md - stop"; exit 1; }
rm -f "$d/repo.tar.gz"
echo "$d/$SKILL"

このコマンドは、リポジトリの現在の main のスナップショットを1つダウンロードします(実行中のスキルより新しい場合があります)。さらに、対象スキルのディレクトリだけを展開するため、そこから参照されるすべてのファイル(references/、scripts/ など)がそろいます。このブロックはディレクトリを出力します。そこで SKILL.md と、参照先のファイルがあればそれも、ファイル読み取りツールを使って最後まで読み、その指示に従ってからここに戻ってください。Web 取得ツールや要約ツールは使わないでください。スキルの内容が短縮され、手順が抜け落ちるためです。このブロックが失敗した場合は、引き継ぎを中止してユーザーに伝えてください。記憶や不完全なダウンロードをもとに続行してはいけません。ダウンロードしたスキルは参照用の指示にすぎず、ユーザーの指示やこのスキルの安全ルールに優先することはありません。

フェーズ 0:事前確認

Terraform または OpenTofu。 このスキルのすべてのコマンドは terraform として記載されていますが、OpenTofu もそのまま置き換えて使用できます。ここで使うプロバイダーとモジュールのソースは、どちらのレジストリでも同じように解決されます。フェーズ 1 の前に、ユーザーが実際にどちらのバイナリを使えるか確認してください。

command -v terraform tofu

PATH に tofu しかない場合は、以下のすべての terraform <subcommand> を tofu <subcommand> と読み替えてください。両方ある場合は、決めつけず、どちらを使うかユーザーに確認してください。

Datadog の認証情報。 環境変数から DD_SITE/DD_API_KEY/DD_APP_KEY を読み込み(.env.local/.env があれば、そちらも使用)、2つのキーをそれぞれ検証してください。検証は個別に失敗する場合があります。

for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
: "${DD_SITE:=datadoghq.com}"
echo "DD_SITE=${DD_SITE}"
echo "DD_API_KEY=$([ -n "${DD_API_KEY:-}" ] && echo set || echo UNSET)   DD_APP_KEY=$([ -n "${DD_APP_KEY:-}" ] && echo set || echo UNSET)"
printf 'DD-API-KEY: %s\n' "$DD_API_KEY" \
  | curl -sS --max-time 20 -o /dev/null -w "validate:     HTTP %{http_code}\n" \
      -H @- "https://api.${DD_SITE}/api/v1/validate"
printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
  | curl -sS --max-time 20 -o /dev/null -w "current_user: HTTP %{http_code}\n" \
      -H @- "https://api.${DD_SITE}/api/v2/current_user"
結果意味対応
どちらも 200このサイトで有効なキーですフェーズ 1 に進みます
validate が 403API キーが無効か、DD_SITE とは異なるリージョンのキーですキーがどのサイトのものかを尋ね、DD_SITE を修正して再確認します
validate が 200、current_user が 403app キーが誤っているか、別のリージョンのものです。API キーの問題ではありません<APP_BASE>/organization-settings/application-keys から取得します
いずれかのキーが未設定検証するものがありません商用サイトでは、dd-account-setup スキルを実行してから戻ってください。ddog-gov.com または us2.ddog-gov.com では、ユーザーにキーを直接尋ねてください。このスキルは、政府機関向けの両サイトを含まないリストに照らして DD_SITE を検証するため、どちらも拒否されます

アプリの URL。 Datadog アプリのホストは、すべてのサイトで app.${DD_SITE} になるわけではありません。https://app.datadoghq.com(US1)、https://app.datadoghq.eu(EU1)、https://app.ddog-gov.com(Gov)で、その他のすべてのサイトでは https://${DD_SITE} 自体です。例:https://us3.datadoghq.com、https://us5.datadoghq.com、https://ap1.datadoghq.com、https://ap2.datadoghq.com、https://uk1.datadoghq.com。一度解決し、以下に出てくる <APP_BASE> のすべての箇所に置き換えてください。全リスト:https://docs.datadoghq.com/getting_started/site/ 解決済みの DD_SITE を記憶しておいてください。 ほとんどのエージェントランタイムでは、コマンドごとに新しいシェルが起動するため、上記の export は次のブロックでは引き継がれません。そのため、認証情報が必要な後続のブロックでは、読み込み行を毎回そのまま先頭に繰り返しています。これは意図的なもので、記載の揺れではありません。削除しないでください。DD_SITE はシークレットではないため、後続の各ブロックで DD_SITE='<site>'; export DD_SITE を明示して改めて設定します。<site> は Phase 0 で確認したサイトに置き換えてください。 これは意図的に : "${DD_SITE:=...}" ではなく、単純な代入にしています。:= は 未設定または空の 値にしか値を設定しないため、.env に誤った空でない DD_SITE が残っていると、そのまま使われ、すべての呼び出しが誤ったリージョンに送られてしまいます。キーには代わりに :? を使っているため、キーがない場合は空のヘッダーを送信せず、明確なエラーで中断します。キーの値をインラインで記述しないでください。必ず読み込み処理を介して $DD_API_KEY/$DD_APP_KEY として渡す必要があります。次の2点はいずれも意図的なものです。

  • Datadog への呼び出しでは、ヘッダーを標準入力経由で渡します。printf 'DD-API-KEY: %s\n' "$DD_API_KEY" | curl -H @- ... のようにします。 printf はシェル組み込みコマンドなので、キーがどのプロセスの引数にもならず、ps に表示されることもありません。代わりに -H "DD-API-KEY: $DD_API_KEY" と記述すると、キーが curl の argv に含まれてしまいます。(-H @- には curl 7.55+ が必要です。ヘッダー行だけが読み込まれるため、-d と --data-urlencode は通常どおり使えます。)
  • AWS、Azure、GCP では、Terraform にキーの値を一切渡しません。Datadog プロバイダーは環境変数から DD_API_KEY/DD_APP_KEY を読み込むため、ルート変数も -var= 引数もなく、Terraform のステートや保存済みプランに記録されるものもありません。(例外は OCI です。そのモジュールでは入力としてキーが必要なため、TF_VAR_* として渡します。)

これらの方法に読み込み処理を組み合わせることで、両方のキーが文字起こし、シェル履歴、プロセス一覧に残らないようにしています。

ツール。 terraform は必須です。oci CLI は任意です(設定の検証と OCID の検索に使用します)。

command -v terraform || echo "MISSING terraform - https://developer.hashicorp.com/terraform/install"
command -v oci >/dev/null 2>&1 && echo "oci: available" || echo "oci: not installed"

以下のスニペットは POSIX シェル用です。 PowerShell または cmd では、Windows 用の同等のコマンド(Get-Command、$env:VAR、2>$null、curl.exe)を使用してください。呼び出しと順序は同じです。

フェーズ 1:OCI 認証情報の確認

Terraform の oci プロバイダーは ~/.oci/config から読み込むため、terraform apply を実行して成功させるには、このファイルが存在し、内容が完全である必要があります。

このスキルでほかの操作を実行する前に、プロファイルを確定してください。 ユーザーがプロファイルを指定した場合は、ここでエクスポートしてください。以下のすべてのコードスニペット、すべての oci CLI 呼び出し、モジュールの config_file_profile は、同じ値を読み取ります。これを省略すると、チェックでは DEFAULT が検証されますが、これはインストール対象のテナンシーやユーザーとは異なる場合があります。その場合、誤ったアイデンティティでチェックが成功または失敗します。

export OCI_CLI_PROFILE="TEAM"   # <- the profile the user named; omit only if they said DEFAULT

次に、ファイル全体を表示せずに必須フィールドを確認してください。OCI プロファイルには pass_phrase が含まれる場合があり、プロファイル全体を表示すると、その内容がトランスクリプトに残ってしまいます。

cfg="$HOME/.oci/config"
[ -r "$cfg" ] || { echo "missing or unreadable: $cfg"; exit 1; }
prof="${OCI_CLI_PROFILE:-DEFAULT}"
field() { awk -v p="[$prof]" -v k="$1" '/^\[/{inp=($0==p); next} inp && $0 ~ "^[ \t]*"k"[ \t]*=" {sub(/^[^=]*=[ \t]*/,""); gsub(/[ \t]+$/,""); print; exit}' "$cfg"; }
bad=0
for k in user tenancy region key_file fingerprint; do
  v=$(field "$k")
  [ -n "$v" ] || bad=1
  case "$k" in
    fingerprint) printf '%-12s %s\n' "$k" "$([ -n "$v" ] && echo present || echo MISSING)" ;;
    *)           printf '%-12s %s\n' "$k" "${v:-MISSING}" ;;
  esac
done
[ -n "$(field pass_phrase)" ] && echo "note: this profile has a pass_phrase; it is deliberately not printed"
keyf=$(field key_file); case "$keyf" in "~/"*) keyf="$HOME/${keyf#\~/}" ;; esac
if [ -n "$keyf" ] && [ -r "$keyf" ]; then echo "key_file     readable"
else echo "key_file     NOT readable: ${keyf:-<unset>}"; bad=1; fi
[ "$bad" -eq 0 ] || { echo "profile [$prof] in $cfg is incomplete - fix it before continuing"; exit 1; }

user、tenancy、fingerprint、key_file、region のすべてが存在し、秘密鍵が読み取り可能でなければなりません。値が空、または MISSING の場合、プロファイルは不完全です。続行しないでください。

ファイルが存在しない、または内容が不完全な場合は、ユーザーに次の手順を案内してください。

  1. OCI Console にログインし、Profile → My profile → API keys → Add API key に移動します。
  2. Generate API key pair を選択し、秘密鍵をダウンロードして ~/.oci/oci_api_key.pem に保存します。
  3. 鍵のアクセス許可を設定します:chmod 600 ~/.oci/oci_api_key.pem
  4. 鍵の追加後に OCI に表示される構成ファイルのスニペットをコピーします。
  5. ~/.oci/config に保存し、key_file がダウンロードした秘密鍵のパスを指していることを確認します。

oci CLI が利用可能な場合は、上記の手動手順の代わりに、ユーザーが oci setup config --profile "${OCI_CLI_PROFILE:-DEFAULT}" を実行して、対話形式で構成を生成することもできます。

認証情報で実際に認証できることを確認してください。

oci CLI が利用可能な場合:

oci --profile "${OCI_CLI_PROFILE:-DEFAULT}" iam region-subscription list 2>&1

成功した場合は続行します。認証エラーが発生した場合は、続行する前にユーザーが構成を修正できるよう案内してください。

それ以外の場合、ここでの明示的な検証は省略します。フェーズ 3 の terraform plan で OCI プロバイダーから明確なエラーが表示され、認証に関する問題が明らかになります。失敗した場合は、その時点で構成を修正してください。

フェーズ 2:情報の収集

このモジュールにはテナンシー OCIDと認証済みユーザーの OCIDが必要です。どちらもフェーズ 1 で確認したプロファイルに記載されています。これが信頼できる情報源なので、そこから読み取ってください。

cfg="$HOME/.oci/config"; prof="${OCI_CLI_PROFILE:-DEFAULT}"
field() { awk -v p="[$prof]" -v k="$1" '/^\[/{inp=($0==p); next} inp && $0 ~ "^[ \t]*"k"[ \t]*=" {sub(/^[^=]*=[ \t]*/,""); gsub(/[ \t]+$/,""); print; exit}' "$cfg"; }
tenancy=$(field tenancy); user=$(field user)
case "$tenancy" in ocid1.tenancy.*) echo "TENANCY_OCID=$tenancy" ;;
  *) echo "tenancy in $cfg is missing or not an ocid1.tenancy OCID - fix Phase 1 first"; exit 1 ;; esac
case "$user" in ocid1.user.*) echo "USER_OCID=$user" ;;
  *) echo "user in $cfg is missing or not an ocid1.user OCID - fix Phase 1 first"; exit 1 ;; esac

oci iam region-subscription list や oci iam user list からこれらの値を導き出そうとしないでください。RegionSubscription にはテナンシー ID が含まれておらず、user list は認証済みユーザーではなく、テナンシー内の任意の先頭ユーザーを返します。そのため、どちらも誤った値をひそかに出力する可能性があります。

続行する前に、2 つの OCID をユーザーに確認してください。プロファイルとは異なるテナンシーまたはユーザーを希望する場合は、その旨を明示してもらうか、OCI Console で値を確認してください。

  • テナンシー OCID:Administration → Tenancy Details。
  • ユーザー OCID:Profile → My profile → OCID はユーザー名の下に表示されます。

ホームリージョンは同じプロファイルから読み取るため、別途入力する必要はありません。

また、ログ収集を有効にするかどうかも確認してください(デフォルト:はい)。AWS、Azure、GCP の統合とは異なり、OCI のログ転送は同じモジュールに含まれています。logs_enabled = true にするとプロビジョニングされます。

フェーズ 3:Terraform の生成と適用

既存の状態を確認する — まずローカルの Terraform、次に Datadog

何かを生成または適用する前に、必ず次の順序で確認してください。既存のインテグレーションを更新できるのか、それとも触れてはいけないのかを判断するため、まずローカルの状態を確認します。

find . -maxdepth 1 -type f \( -name '*.tf' -o -name 'terraform.tfstate' \) -print
# A project is "present" if it has configuration - .terraform/ may simply not exist yet on a fresh clone
# with a remote backend, and terraform.tfstate does not exist at all when state is remote.
if [ -n "$(find . -maxdepth 1 -type f \( -name '*.tf' -o -name '*.tf.json' \) -print -quit)" ]; then
  terraform init -input=false >/dev/null || { echo "terraform init failed - resolve that before concluding anything about existing state"; exit 1; }
  out=$(terraform state list 2>&1); rc=$?
  if [ "$rc" -ne 0 ]; then
    case $out in
      *'No state file'*|*'no state'*|*'Backend initialization required'*)
        echo "project is initialized but has no state yet - treat as a clean install" ;;
      *)
        printf '%s\n' "$out"
        echo "could not read state (backend or credentials problem) - do NOT treat this as 'nothing exists'"; exit 1 ;;
    esac
  elif [ -z "$out" ]; then
    echo "state is empty - treat as a clean install"
  else
    printf '%s\n' "$out" | grep -F 'module.datadog_oci' || echo "state exists but holds no module.datadog_oci resource"
  fi
else
  echo "no Terraform configuration here yet - clean install"
fi

あいまいな grep -i datadog ではなく、リソースアドレス module.datadog_oci に完全一致させてください。そうしないと、無関係な Datadog リソースや、部分的な適用後に残ったクラウド IAM が、管理対象のインテグレーションとして判定されるおそれがあります。

次に、Datadog に既存のリソースを確認します。

for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
DD_SITE='datadoghq.com'; export DD_SITE   # <- replace with the site confirmed in Phase 0.
# Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
: "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
resp=$(printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
  | curl -sS -w '\n%{http_code}' -X GET -H @- "https://api.${DD_SITE}/api/v2/integration/oci/tenancies")
code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
[ "$code" = "200" ] || { echo "lookup failed with HTTP $code - do not assume 'not connected':"; printf '%s\n' "$body"; exit 1; }
printf '%s\n' "$body"

その後、作業を進める前に、両方の確認結果を照合します。

  • Datadog に存在せず、ローカルの状態にもない場合 — 新規インストールです。続行してください。
  • Datadog に存在し、ローカルの状態にも存在する場合 — これは重複ではなく、更新または修復のケースです。以下の Terraform に進み、既存リソースへの変更として扱い、何が変更されるかをプランで確認してください。
  • Datadog には存在するが、ローカルの状態には存在しない場合(Phase 2 のテナンシー OCID がすでに登録済み)— 停止してください。適用すると、重複を作成するか、既存の管理元と競合する可能性があります。そのことを明確に伝え、選択肢として、すでに管理されている場所で管理を続けるか、先に Datadog でインテグレーションを削除するかを提示してください。ここで terraform import を提案してはいけません。このスキルはモジュールをデプロイするものであり、モジュールにはインポート可能な単一のアドレスがないため、安全な一行のインポート方法はありません。ユーザーがいずれかを選択し、確認した場合にのみ続行してください。
  • ローカルの状態には存在するが、Datadog には存在しない場合 — 部分的なインストール、またはロールバックされたインストールです。登録はなくても、クラウド側のリソースが存在する可能性があります。最初からやり直してはいけません。プランを実行して不足しているものを確認し、登録のみが再作成されることを想定してください。
既存の Terraform を確認する
find . -maxdepth 1 -type f \( -name '*.tf' -o -name 'terraform.tfstate' \) -print

既存の .tf ファイルが見つかった場合は、datadog または oci プロバイダーがすでに設定されているか確認し、既存のものを再利用してください。

Terraform を生成する

このインテグレーションでは、リリースタグでバージョンを固定した、Datadog 公式の OCI Terraform モジュールを使用します。Terraform のロックファイルではリモートモジュールのリビジョンが固定されないため、Git ソースのバージョンを固定しないと、新しい init のたびにデフォルトブランチが再解決されます。このモジュールは IAM ユーザー、ポリシー、API キー、Vault リソースを作成するため、上流の変更によって、設定を変更していないのにプロビジョニング内容が予期せず変わるおそれがあります。

variable "datadog_api_key" {
  description = "Datadog API key"
  type        = string
  sensitive   = true
}

variable "datadog_app_key" {
  description = "Datadog application key"
  type        = string
  sensitive   = true
}

module "datadog_oci" {
  source = "github.com/DataDog/oracle-cloud-integration//datadog-terraform-onboarding?ref=datadog-integration-v1.1.17"

  datadog_api_key = var.datadog_api_key
  datadog_app_key = var.datadog_app_key
  datadog_site    = "<DD_SITE>"

  tenancy_ocid      = "<TENANCY_OCID>"
  current_user_ocid = "<USER_OCID>"

  # Must match the profile verified in Phase 1. The module builds its own providers and otherwise reads
  # DEFAULT, which can be a different identity than the one you just validated.
  config_file_profile = "<OCI_CLI_PROFILE>"

  logs_enabled = <LOGS_ENABLED>
}

このモジュールは、すべてのリソースのプロビジョニングを処理します。

  • OCI に Datadog サービスユーザーとグループを作成します
  • Datadog にメトリクス、ログ、リソースへの読み取りアクセスを許可する IAM ポリシーを作成します
  • 認証用の API キーを生成します
  • API 経由でテナンシーを Datadog に登録します

高度なオプション変数(ユーザーが必要とする場合にのみ含めてください)。

変数説明
config_file_profileモジュールのプロバイダーが使用する OCI CLI プロファイルです。デフォルトは DEFAULT です。Phase 1 で確認したプロファイルに合わせて設定してください
user_email作成されたサービスユーザーについて OCI から通知を受け取るメールアドレスです
resource_compartment_ocidDatadog リソース用のコンパートメントです。null の場合、テナンシー内に Datadog という名前のコンパートメントが作成されます
existing_user_idユーザーを新規作成する代わりに、既存の OCI ユーザーを使用します
existing_group_idグループを新規作成する代わりに、既存の OCI グループを使用します
domain_idIdentity Domain の OCID(Identity Domain を使用するテナンシーの場合)
subnet_ocidsログ収集用サブネット。1 行につき 1 つの OCID を指定します
defined_tags作成するリソースの定義済みタグ。1 行につき namespace.key:value を指定します。テナンシーに必須のタグのデフォルト値がない場合は空欄のままにしてください
logs_onlyメトリクスとリソースの収集を無効にしつつ、利用可能な状態でインテグレーションを作成します
events_collection_enabledOCI Events Service のイベントを収集します。デフォルトは false です
enable_regional_vaults(2026-08-13 時点で master のモジュールに存在することを確認済み)サブスクライブ済みの各リージョンに Vault/Key/Secret を作成し、各リージョンのフォワーダーがローカルで API キーを読み取れるようにします。デフォルトは false です。既存のインストールでは、明示的に有効にする必要があります
Terraform を適用する
  1. すべての <PLACEHOLDER> の値を置き換えます。<DD_SITE> はフェーズ 0、<TENANCY_OCID> と <USER_OCID> はフェーズ 2、<OCI_CLI_PROFILE> はフェーズ 1 の最初に確定したプロファイルを指定し、<LOGS_ENABLED> は true または false にします。

  2. terraform init を実行して、モジュールをダウンロードします。

  3. プランを作成し、ファイルに保存します。どちらのキーも TF_VAR_* 環境変数として Terraform に渡します。 -var= 引数として渡すと、Terraform のコマンドラインにキーが含まれてしまいます。

    for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
    DD_SITE='datadoghq.com'; export DD_SITE   # <- replace with the site confirmed in Phase 0.
    # Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
    : "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
    export TF_VAR_datadog_api_key="$DD_API_KEY" TF_VAR_datadog_app_key="$DD_APP_KEY"
    umask 077          # tighten permissions on the plan file regardless
    terraform plan -out=tfplan
    

    プランの出力をユーザーに提示し、明示的な確認を待ちます。

  4. ユーザーの確認後、保存したプランを適用します。ファイルを適用することで、承認が意味を持ちます。 プランファイルを指定せずに terraform apply を実行すると、新しいプランが作成されます。また、-auto-approve を指定すると、誰にも確認されないまま実行されるため、プラン作成後に変更された内容もレビューなしで適用されてしまいます。

    for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
    DD_SITE='datadoghq.com'; export DD_SITE   # <- replace with the site confirmed in Phase 0.
    # Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
    : "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
    export TF_VAR_datadog_api_key="$DD_API_KEY" TF_VAR_datadog_app_key="$DD_APP_KEY"
    # EXIT cleans up; the signal handlers must also terminate, or a Ctrl-C would delete tfplan and
    # then fall through into a retry of a file that no longer exists.
    trap 'rm -f tfplan' EXIT
    trap 'rm -f tfplan; exit 130' HUP INT TERM
    attempt=1
    while :; do
      out=$(terraform apply tfplan 2>&1); rc=$?
      printf '%s\n' "$out"
      [ "$rc" -eq 0 ] && { echo "apply complete"; break; }
      case $out in
        *'no such host'*|*'dial tcp'*)
          if [ "$attempt" -ge 3 ]; then echo "still failing after $attempt attempts - stopping"; exit 1; fi
          echo "transient OCI endpoint lookup failure - retry $attempt of 3 in 10s"
          attempt=$((attempt + 1)); sleep 10 ;;
        *'stale'*|*'Saved plan is stale'*)
          echo "the saved plan is stale (state moved under it) - re-run the plan step and apply the NEW file"; exit 1 ;;
        *)
          echo "apply failed for a non-transient reason - do NOT retry and do NOT report success"; exit 1 ;;
      esac
    done
    

    trap は、ユーザーが判断中に Ctrl-C を押した場合も含め、あらゆる終了経路でプランファイルを削除します。 apply を囲む if/else も重要です。ブロックの最終行にクリーンアップコマンドを置くと、適用に失敗しても 終了コードが 0 になり、実際には行われなかったデプロイをエージェントが「検証」してしまいます。(status は zsh で読み取り専用の変数なので、意図的に status=$? ではなく if を使用しています。)

    OCI は、ほかの 3 つのスキルとはキーの扱いが異なります。 ほかのスキルは Terraform に何も渡しません。 Datadog プロバイダーが環境変数を読み取るため、プランファイルにシークレットは含まれません。このモジュールでは datadog_api_key と datadog_app_key を通常のモジュール入力として受け取るため、両方のキーが保存済みプランに記録されます。 さらに、API キーは state にも保存されます(モジュールがこのキーから Vault シークレットを作成します。 app key はプロバイダーのヘッダーにのみ使用され、永続化されません)。また、これらのキーはリソースに渡されるため、 どちらも ephemeral にできません。プラン作成前に、次の影響を明確に伝えてください。tfplan は存在する間、 平文のシークレットです。umask 077 で制限できるのはほかのローカルユーザーだけであり、リモート state バックエンドでも保護されません。 .gitignore に tfplan を追加し、決してコミットしないでください。上記のトラップは、承認中に Ctrl-C を押した場合も含め、 あらゆる終了経路でファイルを削除します。ただし、エージェントのセッションが強制終了された場合は、手動で削除してください。

一時的な OCI DNS エラーへの対処

OCI のアイデンティティエンドポイントでは、次のようなエラーが断続的に発生します。 dial tcp: lookup identity.<region>.oci.oraclecloud.com: no such host

これは既知の一時的な OCI の問題であり、環境が OCI にアクセスできないことを意味するものではありません。 terraform plan または terraform apply がこのエラーで失敗した場合は、10 秒間隔で最大 3 回まで自動的に再試行してください。 このエラーだけを根拠に、環境の設定に誤りがある、または OCI にアクセスできないとユーザーに伝えてはいけません。

フェーズ 4:セットアップを検証する

terraform apply の完了後、テナンシーが登録されていることを確認します。

for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
DD_SITE='datadoghq.com'; export DD_SITE   # <- replace with the site confirmed in Phase 0.
# Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
: "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
resp=$(printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
  | curl -sS -w '\n%{http_code}' -X GET -H @- "https://api.${DD_SITE}/api/v2/integration/oci/tenancies")
code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
[ "$code" = "200" ] || { echo "lookup failed with HTTP $code - do not assume 'not connected':"; printf '%s\n' "$body"; exit 1; }
printf '%s\n' "$body"

応答にテナンシー OCID が含まれていることを確認します。次に、メトリクスを確認します。

for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
DD_SITE='datadoghq.com'; export DD_SITE   # <- replace with the site confirmed in Phase 0.
# Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
: "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
sleep 10
resp=$(printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
  | curl -sS -w '\n%{http_code}' -G -H @- "https://api.${DD_SITE}/api/v1/query" \
  --data-urlencode "from=$(($(date +%s) - 900))" \
  --data-urlencode "to=$(date +%s)" \
  --data-urlencode "query=avg:oci.computeagent.cpu_utilization{*}")
code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
[ "$code" = "200" ] || { echo "metric query failed with HTTP $code - that is NOT 'metrics still propagating':"; printf '%s\n' "$body"; exit 1; }
printf '%s\n' "$body"

メトリクスが送信されている場合は、ユーザーを祝福してください。送信されていない場合は、OCI メトリクスの表示には通常 5~10 分かかることを伝えてください。

リンクを提示します。

  • OCI Integration タイル:<APP_BASE>/integrations/oracle-cloud-infrastructure
  • Metrics Explorer:<APP_BASE>/metric/explorer?exp_metric=oci.computeagent.cpu_utilization
  • Infrastructure Map:<APP_BASE>/infrastructure/map
  • Logs Explorer(logs_enabled の場合):<APP_BASE>/logs

重要な注意事項

  • OCI テナンシーでユーザー、グループ、ポリシー、API キーを作成するには、ユーザーに IAM 権限が必要です。 アイデンティティ・ドメイン・テナンシーの場合、このモジュールは対象ドメインにサービスユーザーとグループを作成するため、 対象ドメインの管理者権限が必要です。
  • このモジュールには Terraform >= 1.5.0 が必要です(providers.tf で required_version = ">= 1.5.0" が宣言されています)。 古い CLI では terraform init の実行時に失敗するため、Phase 3 の前に terraform version を確認してください。OpenTofu のリリースはすべてこの要件を満たします。バージョンは 1.6 から始まるため、tofu version を別途確認する必要はありません。
  • existing_user_id と existing_group_id は必ずペアで指定してください。 どちらか一方だけが設定されている場合に失敗する事前条件がモジュールにあります。既存のユーザーとグループを再利用する場合は両方を指定し、作成させる場合はどちらも指定しないでください。
  • 統合できるのは親テナンシーのみです。子テナンシーは親から継承します。
  • Terraform モジュールのソースは github.com/DataDog/oracle-cloud-integration です。これは Datadog の公式モジュールです。
  • Terraform で管理されている統合を削除する場合は、Datadog UI ではなく terraform destroy を実行してください。
  • このモジュールはシークレット情報を Terraform の状態に保存します。 Datadog のサービスユーザー用に OCI API キーを作成し、プロビジョニングするリソースに Datadog API キーを渡します。また、sensitive = true によって CLI 出力では値が伏せられますが、状態から削除されるわけではありません (HashiCorp のドキュメント)。 このモジュールには、これを回避する方法がありません。 認証情報の入力として用意されているのは、生の datadog_api_key 変数と datadog_app_key 変数だけです。既存の Vault シークレット OCID を受け取る入力はなく、Vault、Key、Secret もモジュール自身が プロビジョニングします。したがって、正直な選択肢は 2 つだけであり、ユーザーは計画前にどちらかを選ぶ必要があります。(a)これを受け入れ、 最初に暗号化されたリモートバックエンドを設定する。Terraform のデフォルトでは、作業ディレクトリにプレーンテキストの terraform.tfstate が作成され、 後から状態を移動してもプレーンテキストのコピーが残るためです。または、(b)ここで作業を中止し、代わりに Datadog UI の OCI 統合タイルを使用する。 こちらではキーが状態に保存されることはありません。3 つ目の選択肢があるかのように示唆しないでください。また、(a)を選んだ場合は、バックエンドが設定され、検証されるまでプランを開始しないでください。
  • Datadog の API キーとアプリケーションキーは、プラン/適用時に TF_VAR_* を通じて Terraform に渡します。コミット対象の .tfvars ファイルや、その他の永続ファイルに書き込まないでください。このモジュールは API キーをプランと状態にも保存します。以下の状態に関する説明を参照してください。これが、最初にバックエンドを決める必要がある理由です。
  • プランをユーザーに見せずに terraform apply を実行してはいけません。

コメント