k6-manage について
k6-manageは、gcxコマンドラインまたはcurlでGrafana Cloud k6を操作するためのスキルリファレンスです。認証、APIの探索、テスト実行データの取得、エンドポイントごとの注意点を扱います。
主な機能
- 01gcxコマンドラインとcurlの利用案内
- 02Grafana Cloudの認証設定
- 03OpenAPIを使ったエンドポイント探索
- 04一覧の並べ替えとページネーション
- 05REST、ログ、トレースのリクエスト案内
活用シーン
- 01k6 Cloudアカウントへの認証
- 02gcx k6にないAPI操作の探索
- 03最新または全テスト実行の一覧取得
- 04ログ、トレース、テストファイルの取得
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ grafana/ skills --skill k6-manageインストール後、Claude Code で/k6-manageを入力して読み込まれたか確認します。
同梱ファイルreferences/metrics.md
詳細
Grafana Cloud k6 — インタラクションリファレンス
デフォルトの方法は gcx CLI です。gcx がインストールされていない場合でも、ここに記載されているすべてのエンドポイントには、k6 の公開ホストに対する直接の curl でアクセスできます。認証ヘッダーとホストの変換ルールについては §1.2 を参照してください。以降の内容を形作る原則は 2 つあります。
- Grafana 側の認証は(利用可能な場合)gcx が管理します。 すべての呼び出しに適切なヘッダーを挿入するため、認証ヘッダーを自分で設定する必要はありません。自分で設定する唯一のヘッダーは
X-K6TestRun-Idです。Loki のログクエリ(§4)、ブラウザーのスクリーンショット/ファイルの取得(§6)、Tempo のトレースクエリ(§7)で使用します。それ以外のヘッダーは上書きされるか、競合の原因になります。curl モードでは認証ヘッダーを手動で設定します。§1.2 を参照してください。 - まず
gcx k6 ...サブコマンドを使ってください。 よく使われる操作を扱いやすい形でラップし、ページネーションにも対応します。利用可能なコマンドはgcx help-tree k6で確認できます(さらに詳しく調べるにはgcx help-tree k6 <subcommand>を実行します)。必要な操作に対応するサブコマンドがない場合に限り、gcx apiに切り替えてください。
1. 認証
1.1 gcx を使う場合(デフォルト)
gcx login --context <ctx> # one-time OAuth, browser flow
gcx --context <ctx> config check # expect "✔ Connectivity: online"
コンテキストでログインすると、すべての gcx api ... および gcx k6 ... 呼び出しが、その認証状態を引き継ぎます。呼び出しで "Invalid or expired token —
run gcx login to refresh" が返された場合、OAuth セッションの有効期限が切れています。gcx login --context <ctx> を再実行してください。
1.2 gcx を使わない場合 — 直接の curl
まず command -v gcx を確認してください。見つからない場合でも、このスキルに記載されているすべてのエンドポイントには、k6 の公開ホストに直接アクセスできます。ほかの箇所にある gcx の例と比べて、次の 3 点が異なります。
- 認証ヘッダーは手動で設定します。 すべての呼び出しで、次の両方を設定してください。
Authorization: Bearer <k6_token>X-Stack-ID: <int>
- ホストはプラグインプロキシのものに置き換えます。
- REST(
/cloud/v6/...、/cloud/v5/...、/cloud-resources/v1/...、/insights/...)→https://api.k6.io - ログ(Loki)とトレース(Tempo)→
https://cloudlogs.k6.io
- REST(
/api/plugins/k6-app/resources/{cloud,logs,insights}プレフィックスはありません。 削除してください。gcx の例でこのプレフィックスより後にある部分が、実際の k6 パスです。§2 にあるcloud/cloud/の二重表記は、単一の/cloud/にまとめられます。最初のcloud/はプロキシのルートにすぎません。
認証情報の取得
推測せず、セッションごとに一度、ユーザーに次の情報を尋ねてください。
-
k6 API トークン — 有効期間の長いベアラートークンです。gcx が設定されている場合に
gcx k6 auth tokenが出力する値と同じです。 -
スタック — 整数の stack ID(
X-Stack-IDで直接使用)または Grafana の スタック URL(例:https://myorg.grafana.net)。ユーザーが URL を指定した場合は、X-Stack-Urlヘッダーに URL を指定してGET /cloud/v6/authを一度呼び出し、ID に解決してください。戻り値は{stack_id, default_project_id}です。STACK_ID=$(curl -sS https://api.k6.io/cloud/v6/auth \ -H "Authorization: Bearer $K6_TOKEN" \ -H "X-Stack-Url: $STACK_URL" \ | jq -r '.stack_id')解決した ID はセッション中キャッシュしてください。以降の呼び出しではすべて
X-Stack-IDにこの ID が必要です。(注:/cloud/v6/authはX-Stack-IDの代わりにX-Stack-Urlを受け取る唯一のエンドポイントです。これは「ユーザーが知っている URL」から「API が必要とする ID」へ変換する方法です。)
翻訳用チートシート
| gcx 形式(プラグインプロキシ) | curl 形式(直接アクセス) |
|---|---|
gcx api /api/plugins/k6-app/resources/cloud/cloud/v6/test_runs/123 | curl https://api.k6.io/cloud/v6/test_runs/123 -H ... |
gcx api /api/plugins/k6-app/resources/cloud/cloud/v5/test_runs/<id>/metrics | curl https://api.k6.io/cloud/v5/test_runs/<id>/metrics -H ... |
gcx api /api/plugins/k6-app/resources/cloud/cloud-resources/v1/files/index | curl https://api.k6.io/cloud-resources/v1/files/index -H ... |
gcx api /api/plugins/k6-app/resources/insights/insights/api/v1/testrun/<id>/executions | curl https://api.k6.io/insights/api/v1/testrun/<id>/executions -H ... |
gcx api /api/plugins/k6-app/resources/logs/api/v1/query_range?... | curl https://cloudlogs.k6.io/api/v1/query_range?... -H ... |
gcx api /api/plugins/k6-app/resources/logs/api/v1/tempo/api/search?... | curl https://cloudlogs.k6.io/api/v1/tempo/api/search?... -H ... |
上記の各 -H ... の箇所では、次の両方の認証ヘッダーを送信します。
-H "Authorization: Bearer $K6_TOKEN" -H "X-Stack-ID: $STACK_ID"。
注:
- gcx が指定を任せるエンドポイント固有のヘッダー(ログ、トレース、ファイルのエンドポイント(§4、§6、§7)における
X-K6TestRun-Id)は、認証ヘッダーの組み合わせに加えて引き続き必要です。 - §2 の
gcx apiフラグの注意点(エンベロープの出力、--json fieldによるフィルタリング、出力形式の指定に使う-o)は curl には適用されません。curl の通常のフラグを使用してください。本文を保存するには-o file、PUT のペイロードには--data-binary @file、ステータスコードには-w '%{http_code}'などを使います。 - ページネーションの動作(§3 の
$orderby、$top、$skip、@nextLink)は v6 エンドポイント自体の仕様であり、curl でも同じように機能します。サーバーが返す@nextLinkの URL はすでに絶対 URL(https://api.k6.io/...)です。そのまま curl に渡してください。§3 のプラグインプロキシ向けの変換は不要です。
2. gcx api のパスの構成
サブコマンドがない場合は、Grafana プラグインプロキシのルートに対して gcx api を使用します。
- REST API(
/cloud/v6/、/cloud/v5/)—/api/plugins/k6-app/resources/cloud/<k6-path>を先頭に付けます。 - ログ(Loki) —
/api/plugins/k6-app/resources/logs/<loki-path>を先頭に付けます。
| k6 パス | gcx の呼び出し |
|---|---|
/cloud/v6/test_runs/{id} | gcx api /api/plugins/k6-app/resources/cloud/cloud/v6/test_runs/{id} |
/cloud/v5/test_runs/{id}/metrics | gcx api /api/plugins/k6-app/resources/cloud/cloud/v5/test_runs/{id}/metrics |
Loki /api/v1/query_range?... | gcx api /api/plugins/k6-app/resources/logs/api/v1/query_range?... |
すべての REST パスで cloud/cloud/ が重複していることに注意してください。最初の cloud はプロキシルート、2つ目は k6 の /cloud/v{N}/ 名前空間です。
gcx api のフラグに関する注意点
gcx api は curl のクローンではありません。いくつかのフラグは、curl の操作に慣れている場合に想定するものと異なります。
-
レスポンス本文は標準出力に書き込まれます。本文を保存するための
-o <file>フラグはありません。-oは出力形式(json、yaml、agents)を選択します。代わりに、シェルのリダイレクト(> file)または$(...)によるキャプチャを使用してください。 -
リクエスト本文には、
-d <string>、-d @file、または-d @-(標準入力)を使用します。--data-binaryはありません。-d @fileですでにバイト列が保持されます。 -
jq を使わないフィールド選択:
--json field1,field2,...は指定したフィールドのみを返し、--json list(または--json '?')で利用可能なフィールドを確認できます。浅い階層の抽出には、jq にパイプするよりすっきりする場合がよくあります。 -
標準エラー出力のノイズ:gcx はほとんどの呼び出しで、標準エラー出力に1行の
hint:を出力します。jq へのパイプで予期しない動作が起きないよう、2>/dev/nullでリダイレクトしてください。 -
レスポンスヘッダーは
gcx apiから直接取得できません。ワークフローの分岐がContent-Typeに依存する場合(例:§5 のスクリプト GET)は、ダウンロードした本文をfile <path>で調べてください。 -
大きなレスポンスは一時ファイルに退避され、標準出力にはラッパーのエンベロープのみが出力されます。しきい値は数十 KB 程度のため、中程度のサイズのリストエンドポイントでも発生します。エンベロープは次のようになります。
{"spilled_to":"/var/folders/.../gcx-results-<n>.json", "bytes":2365037, "preview_sample":["@nextLink","value"], "message":"Response too large for stdout..."}json.loads(stdout).get('value', [])のような単純なパターンでは、この場合に何もエラーを出さず空の値が返されます。エンベロープにはvalueキーがありません。確実な対処法は2つあります。-o jsonを指定すると、サイズにかかわらずインライン出力が強制されます(本文を解析するスクリプトに推奨)。退避が発生するのはエージェントモードのデフォルトの形式設定が原因です。-o jsonを指定すると回避できます。- または、エンベロープを検出して退避先のファイルを再読み込みする:
d = json.loads(stdout) if 'spilled_to' in d: d = json.load(open(d['spilled_to']))
どちらでも動作しますが、
-o jsonのほうが記述する行数が少なくて済みます。 -
Grafana プラグインプロキシは
Content-Type: multipart/...をapplication/jsonに書き換えます。gcx api自体は-H "Content-Type: ..."ヘッダーを正しく転送します(--log-http-payloadのトレースで確認できます)が、上流のプラグインプロキシは、k6 の API に到達する前に multipart の Content-Type を JSON に書き換えます。その結果、テスト作成に使用するPOST /cloud/v6/projects/{id}/load_tests(フォームパートとしてnameとscriptを受け取ります)など、multipart の本文を必要とするエンドポイントは、gcx 側でどのヘッダーを設定してもHTTP 415 "Unsupported media type \"application/json\""を返します。これらのエンドポイントでは、api.k6.ioに対する直接の curl(§1.2)に切り替えてください。curl -F name=... -F script=@...は multipart の本文を構築し、プラグインプロキシを回避します。その他の Content-Type 値(例:§5 のスクリプト更新 PUT で使用するapplication/octet-stream)は、プロキシを通じて変更されずに転送されます。
3. エンドポイントの探索と呼び出し
gcx k6 のサブコマンド(gcx help-tree k6 を参照)では、一般的な読み取り操作に対応できます。それ以外の操作(変更、ニッチな読み取り、サブコマンドとして提供されていないエンドポイント)では、k6 Cloud API の範囲は広く、時間の経過とともに変化します。古くなるチートシートに頼るのではなく、リクエスト時に OpenAPI 仕様から必要な操作を見つけてください。
ワークフロー
-
セッションごとに一度、仕様を取得します(サイズが大きいため、
/tmpにキャッシュします)。gcx api /api/plugins/k6-app/resources/cloud/cloud/v6/openapi > /tmp/k6-openapi.json -
まず
operationIdとdescriptionでインデックスを作成します。検索中に扱うデータを小さく保てます。jq '[.paths | to_entries[] | .key as $p | .value | to_entries[] | {path: $p, method: .key, operationId: .value.operationId, description: .value.description}]' /tmp/k6-openapi.json必要な操作(「abort」、「limits」、「schedule」など)をこの結果から grep します。
-
選んだ操作の完全なスキーマを取得します。パラメーター、リクエスト本文、レスポンスを確認し、
$refによる参照を解決します。jq '.paths["<path>"]["<method>"]' /tmp/k6-openapi.json # Then for each "$ref": "#/components/schemas/Foo": jq '.components.schemas.Foo' /tmp/k6-openapi.json -
§2 に従ってパスの前にプレフィックスを付け、同じパスに対する
gcx api呼び出しを組み立てます。 認証は gcx によってすでに挿入されているため、自分で追加しないでください。
一覧リクエスト
呼び出す操作が一覧エンドポイントの場合は、デフォルトで**createdの降順(新しい順)で並べ替え**、20件ずつページネーションしてください。どちらも、その操作のOpenAPIスキーマで公開されているクエリパラメーター名を使用します。名前はさまざまです(ordering=-created、order_by=created.desc、sort=-created、limit=20、page_size=20)。そのため、手順3でスキーマからパラメーターを確認することが重要です。新しい順にすることで、ユーザーが通常知りたいエントリーが最初のページに表示されます。ページサイズを20件にすると、コンテキストを使いすぎずに要約できる程度にレスポンスを小さく保てます。
全件取得:@nextLinkを使ったページネーション
新しいページだけでなく、すべての行を取得する必要がある場合、v6の一覧エンドポイントは各レスポンスを1000行(デフォルトの$top)に制限し、次のページを示す@nextLinkフィールドを返します。gcx k6 runs list --limit 0は@nextLinkを自動的にたどらず、デフォルトでは昇順になります。過去の実行が1000件を超えるテストでは、最新ではなく最も古い1000件が黙って返されます。実際には、この出力から要約した(first/last_run)が大幅に古くなる可能性があります(たとえば、毎日スケジュールされ、何年も実行されているテストのlast_runが約3年前として表示されることがあります)。最新順のデータを取得するには、v6エンドポイントに対して$orderby=created descを指定したgcx apiを使います。全件取得するには、@nextLinkがなくなるまで繰り返します。
v6の一覧エンドポイントでは、OData形式のクエリパラメーターを使用できます。
| パラメーター | 用途 |
|---|---|
$orderby | 並べ替え。値は<field> <direction>形式(例:created desc)にする必要があります。指定できるフィールドは操作ごとに異なりますが、一般的なのはcreatedです。デフォルトは昇順です。 |
$top | ページサイズ。デフォルトは1000(上限も1000) |
$skip | オフセット(@nextLinkにすでに含まれています) |
$count | レスポンスに総件数を含めます |
ループで使う実用的なデフォルトは2つあります。最初のページに最新の実行(ほとんどの場合、エージェントが必要とするのはこれだけです)が含まれるようにする$orderby=created descと、ページ間で解析方法を統一できるよう、スピルエンベロープ(§2を参照)を使わない-o jsonです。
import json, subprocess, urllib.parse
CTX = "<stack>"
TEST_ID = "<test_id>"
PROXY = "/api/plugins/k6-app/resources/cloud"
all_runs = []
# Start with newest first; -o json keeps the body inline for clean json.loads().
path = (
f"{PROXY}/cloud/v6/load_tests/{TEST_ID}/test_runs"
"?%24orderby=created%20desc&%24top=1000"
)
while path:
r = subprocess.run(["gcx", "--context", CTX, "api", path, "-o", "json"],
capture_output=True, text=True, timeout=60)
d = json.loads(r.stdout)
all_runs.extend(d.get("value", []))
nxt = d.get("@nextLink")
if not nxt:
path = None
continue
# @nextLink comes back as an absolute http://api.k6.io/... URL with
# OData params already encoded ($skip, $top, $orderby). Reshape its
# path+query into the plugin-proxy prefix:
p = urllib.parse.urlparse(nxt)
path = f"{PROXY}{p.path}" + (f"?{p.query}" if p.query else "")
同じ方法は、@nextLinkを返すv6の一覧エンドポイントであれば、/test_runs以外にも使えます。直近の数件だけが必要な場合は、最初のページを取得したところでループを終了します。$orderby=created descを指定していれば、そのページにはすでに最新の1000件が含まれています。
メトリクス
時系列メトリクスと集計メトリクスはv5 API(/cloud/v5/...)にあります。OData形式のURL関数呼び出し(query_range_k6(query='...',metric='...'))内でPrometheus風のクエリセマンティクスを使用し、v6のOpenAPIには含まれていません。エンドポイントの完全なリファレンス、セレクター構文、メトリクスタイプ別のクエリメソッド、および具体例はreferences/metrics.mdに記載されています。メトリクスクエリを作成する前に、こちらを読んでください。
ログ
§4を参照してください。
4. ログ(gcx api 経由の Loki)
プラグインは Loki を /api/plugins/k6-app/resources/logs/ の下でプロキシします。手動で指定するヘッダーは X-K6TestRun-Id だけです。認証は gcx が処理します。
RUN_ID="<run_id>"
# Scope the log window to the run itself: `created` for start, `ended`
# for end. If `ended` is null the run is still in progress — fall back
# to "now". Use a wider hard-coded window only when the run object's
# timestamps don't fit what you're investigating.
RUN=$(gcx api /api/plugins/k6-app/resources/cloud/cloud/v6/test_runs/$RUN_ID 2>/dev/null)
# k6 emits sub-second precision (e.g. "...:58.984041Z"); jq's
# fromdateiso8601 only accepts whole seconds, so strip the fraction.
START=$(echo "$RUN" | jq -r '.created | sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601')
END=$(echo "$RUN" | jq -r 'if .ended then (.ended | sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601) else (now | floor) end')
QUERY=$(printf '{test_run_id="%s"}' "$RUN_ID" | jq -sRr @uri)
# Save the raw response to /tmp/ — log payloads can be large; streaming
# them inline burns context. Summarise from the file, then jq into
# specific entries only when needed.
gcx api "/api/plugins/k6-app/resources/logs/api/v1/query_range?query=${QUERY}&direction=backward&start=${START}&end=${END}&limit=1000" \
-H "X-K6TestRun-Id: $RUN_ID" 2>/dev/null > /tmp/run_${RUN_ID}_logs.json
# Tight summary — counts and stream labels only:
jq '{status, streams: (.data.result | length),
total_entries: ([.data.result[].values | length] | add),
stream_labels: [.data.result[].stream]}' /tmp/run_${RUN_ID}_logs.json
クエリを再実行するのではなく、必要に応じて /tmp/run_${RUN_ID}_logs.json から個々のエントリを取得してください(例:jq '.data.result[].values[]' …)。
すべての LogQL クエリには、必ず {test_run_id="<run_id>"} ストリームセレクターを含めてください。プラグインプロキシは実行ごとにログを分割しており、これを含まないクエリは拒否されるか、結果が返されません。このセレクターに追加のフィルターを重ねてください。
{test_run_id="<run_id>"}— すべて{test_run_id="<run_id>"} | level=~"(error|warn)"— エラーと警告のみ{test_run_id="<run_id>"} |= "specific text"— 部分文字列フィルター
方向と時間範囲のヒント:
start/endの範囲には、壁時計の「過去 1 時間」ではなく、実行のcreated/endedフィールドを指定してください。そうしないと、時間範囲より古いログがクエリから黙って漏れます。これと異なる範囲を指定するのは、別の時間帯(例:前後の状況)を明確に調べたい場合に限ります。- 最初のエラーを見つけるには、
start = run.createdとdirection=forwardを指定します。 - 最新の出力を見つけるには、
end = run.ended(実行中の場合は現在時刻)とdirection=backwardを指定します。 - Loki の保持期間は通常 k6 のカスケード削除より長いため、削除された子実行のログも、しばらくはクエリ可能な場合があります。
5. テストスクリプトを安全に編集する
2 つの異なるスクリプトエンドポイント
k6 スクリプト本文を返す GET エンドポイントは 2 つありますが、相互に置き換えて使うことはできません。
| エンドポイント | 返される内容 | 使用する場面 |
|---|---|---|
/cloud/v6/load_tests/<test_id>/script | 現在の負荷テストスクリプト(変更可能、PUT をサポート) | スクリプトの編集、現在の状態の読み取り |
/cloud/v6/test_runs/<run_id>/script | 特定の実行に含まれるスクリプトのスナップショット(読み取り専用) | 過去の実行で実際に何が実行されたかの調査、バージョン間の差分確認 |
2 つの内容は異なる場合があります。実行完了後に負荷テストのスクリプトが編集されると、その実行に含まれるスナップショットは実行時の内容のまま固定される一方、負荷テストのエンドポイントは新しい現行バージョンを返します。スナップショットのエンドポイントは GET 専用です。過去のバイト列を変更することはできません。
以下の安全な編集手順では、編集可能な負荷テストのエンドポイントを使用します。実行間のスクリプト差分(例:「最後に成功した実行から最初に失敗した実行までの間にスクリプトが変更されたか」)を確認するには、両方の実行に対して /test_runs/<id>/script を GET し、ローカルで差分を取ってください。
スクリプト本文の形式
スクリプト GET エンドポイントが返す形式は 2 種類あります。形式を決めつける前に、必ずどちらかを判別してください。
-
単一の js/ts ファイル。以下の手順でそのまま処理できます。
-
k6 tar アーカイブ(通常の tar または gzip 圧縮)。複数ファイルのプロジェクトバンドル(エントリースクリプト、インポートされたモジュール、アセット)です。編集するには、JS ファイルを展開して変更した後、変更済みの JS から
k6 archiveを使ってアーカイブを再構築します。tarで手動で再パッケージしないでください。アーカイブには、解析済みオプション(projectID、thresholds、scenarios)を含むmetadata.jsonがあり、k6 archiveはこれをスクリプトソースから正しく再生成します。手動で再パッケージすると古いメタデータが残り、実行時エラー(例:projectID の不一致)が発生します。# Edit a k6 tar archive tar -xf /tmp/script_body -C /tmp/extracted/ # extract # ... edit the JS file ... k6 archive /tmp/edited_script.js -O /tmp/new_archive.tar # rebuild
gcx api はレスポンスヘッダーを公開しないため(§2 を参照)、ダウンロードした本文を file(1) で調べて形式を判別してください。
gcx api /api/plugins/k6-app/resources/cloud/cloud/v6/load_tests/$ID/script \
> /tmp/script_body
file /tmp/script_body
# Expected output (examples):
# ASCII text → js/ts source
# POSIX tar archive → k6 tar bundle
# gzip compressed data → gzipped tar bundle
PUT の本文には、スクリプト(またはアーカイブ)の生バイト列を指定する必要があります(application/octet-stream)。gcx はリクエストを変更せずに k6 へ転送します。
ID="<load_test_id>"
# 1. Pull current script (single-file js/ts case)
gcx api /api/plugins/k6-app/resources/cloud/cloud/v6/load_tests/$ID/script \
> /tmp/script_current.js
# 2. Backup
cp /tmp/script_current.js /tmp/script_backup_$(date +%s).js
# 3. Edit → /tmp/script_new.js
# 4. Local parse-only sanity check
k6 inspect /tmp/script_new.js | head -20
# 5. 1-iteration smoke (edit IN-FILE; --iterations CLI flag breaks browser scenarios)
sed 's/iterations: [0-9]\+/iterations: 1/' /tmp/script_new.js > /tmp/script_1iter.js
k6 run --quiet /tmp/script_1iter.js # exit 0 = pass, 99 = threshold fail
# 6. PUT — Content-Type must be application/octet-stream
gcx api /api/plugins/k6-app/resources/cloud/cloud/v6/load_tests/$ID/script \
-X PUT \
-H "Content-Type: application/octet-stream" \
-d "@/tmp/script_new.js"
# 7. Verify by re-fetching and comparing sha256 — the two hashes MUST match.
# Do not rely on the `updated` timestamp; it does not bump on script PUT.
gcx api /api/plugins/k6-app/resources/cloud/cloud/v6/load_tests/$ID/script \
> /tmp/script_verify.js
shasum -a 256 /tmp/script_new.js /tmp/script_verify.js
PUT が 415 を返す場合は、-H "Content-Type: application/octet-stream" が正しく渡されたことを確認してください(シェルの引用符の誤りによってヘッダーが欠落することがあります)。デバッグ時は gcx api に -vvv を渡すと、リクエスト/レスポンスのトレースを確認できます。
6. ブラウザーのスクリーンショット
ブラウザーモジュールの実行では、実行ごとの S3 ストレージにスクリーンショットの PNG が書き込まれます。現在、files API で取得できるアーティファクトはこれだけです。/cloud/v6/ 経由では公開されておらず、別の cloud-resources/v1/files/ プラグインルートを使った 2 段階のフローで取得します。どちらの呼び出しにも、ログクエリで使うものと同じ X-K6TestRun-Id ヘッダー(§4)が必要です。認証は引き続き gcx が処理しますが、実行 ID は手動で指定する必要があり、指定しないとエンドポイントは HTTP 422 を返します。
RUN_ID="<run_id>"
# 1. Index — JSON array of screenshot paths owned by this run. Empty
# array if the run took none (e.g. non-browser tests, or browser
# runs that didn't call page.screenshot()).
gcx api /api/plugins/k6-app/resources/cloud/cloud-resources/v1/files/index \
-H "X-K6TestRun-Id: $RUN_ID" -o json 2>/dev/null > /tmp/files_${RUN_ID}.json
# Each entry looks like:
# "7542817/files/screenshots/screenshots/login-success.png"
# The doubled "screenshots/screenshots/" segment is real, not a typo —
# pass the path back unchanged to step 2.
# 2. Request pre-signed download URLs for the files you want. The
# request body must be JSON; Content-Type matters.
FILES=$(jq -c '[.[] | {name: .}]' /tmp/files_${RUN_ID}.json)
PAYLOAD=$(jq -nc --argjson files "$FILES" \
'{service:"aws_s3", operation:"download", files:$files}')
gcx api /api/plugins/k6-app/resources/cloud/cloud-resources/v1/files/generate-pre-signed-url \
-X POST \
-H "X-K6TestRun-Id: $RUN_ID" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" -o json 2>/dev/null > /tmp/presigned_${RUN_ID}.json
# 3. Download each pre-signed URL directly — they're plain S3 GETs, no
# gcx and no auth header (the signature is in the URL). The URLs
# are valid for 24h (X-Amz-Expires=86400); re-run step 2 if they
# expire.
mkdir -p /tmp/run_${RUN_ID}_files
jq -r '.urls[] | [.name, .pre_signed_url] | @tsv' /tmp/presigned_${RUN_ID}.json |
while IFS=$'\t' read -r NAME URL; do
curl -sS -o "/tmp/run_${RUN_ID}_files/$(basename "$NAME")" "$URL"
done
知っておくべき注意点
- 署名の前にインデックスを確認します。
generate-pre-signed-urlはファイルの存在を検証しません。どのキーに対しても URL を生成し、ダウンロードしようとしたときに初めて 404 が発生します(S3 は<Error><Code>NoSuchKey</Code>...を返します)。ファイル一覧はパスの形式から推測せず、必ずfiles/indexから取得してください。 - 署名リクエストをまとめます。
filesは配列なので、ファイルごとに 1 回ずつ呼び出すのではなく、必要な URL をすべて 1 回の POST でリクエストしてください。同じ有効期限 24 時間がバッチ全体に適用されます。 - ブラウザーテストとプロトコルテストの違い。 インデックスにエントリがあるのは、
page.screenshot()を呼び出した実行だけです。プロトコル/HTTP のみの実行では[]が返されます。インデックスに必ず項目があるとは限りません。
7. ブラウザートレース(gcx api 経由の Tempo)
ブラウザーモジュールの実行では、イテレーション、ナビゲーション、ロケーターのクリック、スクリーンショット、Web Vitals の観測など、それぞれに OTel スパンが出力されます。プラグインは /api/plugins/k6-app/resources/logs/ 配下の Tempo バックエンドにプロキシします(§4 を参照。同じプレフィックスを Loki も使用します)。すべての呼び出しに同じ X-K6TestRun-Id ヘッダーが必要です。これがない場合、検索と取得のどちらも HTTP 401 "Test run ID missing" を返します。
取得は TraceQL で検索した後、ID を使ってトレース全体を取得する 2 段階のフローです。トレース全体はサイズが大きく(120 スパンのイテレーションでは、-o json による整形出力でディスク上約 100 KB、コンパクト形式で約 50 KB)、結合して要約することで、エージェントのコンテキストを簡潔に保てます。
RUN_ID="<run_id>"
# 1. Find the run's start/end window and pick the scenario name.
# Same caveat as §4: strip the sub-second fraction before
# fromdateiso8601, and fall back to "now" if the run is still
# running. Add a small buffer because spans can land slightly
# after the run object reports `ended`.
RUN=$(gcx api /api/plugins/k6-app/resources/cloud/cloud/v6/test_runs/$RUN_ID 2>/dev/null)
START=$(echo "$RUN" | jq -r '.created | sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601')
END=$( echo "$RUN" | jq -r 'if .ended then (.ended | sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601) else (now|floor) end')
START=$((START - 60))
END=$((END + 60))
SCENARIO="ui" # whatever your scenario is named; check run.ui.exec / k6 script
# 2. Search for iteration root spans. TraceQL goes in `q`; URL-encode
# it. `start`/`end` must be unix seconds — RFC3339 returns
# HTTP 400 `invalid start: strconv.ParseUint`. limit=500 caps the
# result, enough to cover several thousand iterations.
Q=$(printf '{ name = "iteration" && span.test.iteration.number >= 0 && span.test.vu >= 0 && span.test.scenario = "%s" }' "$SCENARIO")
QE=$(printf '%s' "$Q" | jq -sRr @uri)
gcx api "/api/plugins/k6-app/resources/logs/api/v1/tempo/api/search?start=${START}&end=${END}&q=${QE}&limit=500" \
-H "X-K6TestRun-Id: $RUN_ID" -o json 2>/dev/null > /tmp/traces_${RUN_ID}.json
# Each entry has: traceID (32-char hex), rootServiceName ("k6"),
# rootTraceName ("iteration"), durationMs, startTimeUnixNano, and a
# spanSet preview of the iteration root span's attributes
# (test.iteration.number, test.vu, test.scenario).
# 3. Fetch a full trace. The response is OTLP-shaped:
# { "batches": [ { "resource": {...}, "scopeSpans": [ { "spans": [...] } ] } ] }
TRACE_ID=$(jq -r '.traces[0].traceID' /tmp/traces_${RUN_ID}.json)
gcx api "/api/plugins/k6-app/resources/logs/api/v1/tempo/api/traces/$TRACE_ID" \
-H "X-K6TestRun-Id: $RUN_ID" -o json 2>/dev/null > /tmp/trace_${TRACE_ID}.json
エージェント向けの簡潔な要約
1 回のイテレーションの OTLP ボディは、整形出力で約 100 KB になることがあります。これをそのままコンテキストに出力するのは非効率です。役立つ情報の大半は、スパン名の分布、個別スパンの所要時間上位、Web Vitals の評価に含まれています。以下のパイプラインは、トレースを約 1~2 KB のプレーンテキストにまとめます。
jq -r '
# OTel value envelope: pick by key presence, not //-chaining — jq's //
# treats `false` as missing and would drop legitimate boolValue:false.
def attrval:
if has("stringValue") then .stringValue
elif has("intValue") then .intValue
elif has("boolValue") then .boolValue
elif has("doubleValue") then .doubleValue
else null end;
def attrs: [.attributes[] | {(.key): (.value | attrval)}] | add // {};
def dur: (((.endTimeUnixNano|tonumber) - (.startTimeUnixNano|tonumber)) / 1000000 | floor);
[.batches[].scopeSpans[].spans[] | {name, dur: dur, a: attrs, status: (.status.code // "OK")}] as $spans
| "── span-name rollup (count · total ms · max ms) ──",
([$spans[] | {name, dur}]
| group_by(.name) | map({name: .[0].name, n: length,
t: (map(.dur)|add), m: (map(.dur)|max)})
| sort_by(-.t)[]
| " \(.n|tostring|.+" "|.[0:4]) \(.t|tostring|.+" "|.[0:7]) \(.m|tostring|.+" "|.[0:6]) \(.name)"),
"\n── slowest spans (ms · name · navigation.url / page.goto.url) ──",
([$spans[] | select(.name != "iteration")] | sort_by(-.dur) | .[0:8][]
| " \(.dur|tostring|.+" "|.[0:7]) \(.name)\(if .a["navigation.url"] // .a["page.goto.url"] then " " + (.a["navigation.url"] // .a["page.goto.url"]) else "" end)"),
"\n── web-vital ratings ──",
([$spans[] | select(.name == "web_vital")
| {n: .a["web_vital.name"], v: .a["web_vital.value"], r: .a["web_vital.rating"]}]
| group_by(.n) | map({name: .[0].n,
ratings: ([.[].r] | group_by(.) | map({(.[0]): length}) | add)})[]
| " \(.name) \(.ratings)"),
"\n── span errors ──",
([$spans[] | select(.status != "OK" and .status != null)] | length | " count: \(.)")
' /tmp/trace_${TRACE_ID}.json
7542817 のような実行では、次のような出力になります。
── span-name rollup (count · total ms · max ms) ──
1 154552 154552 iteration
37 153391 17746 navigation
11 21778 5168 page.waitForNavigation
...
── slowest spans (ms · name · navigation.url / page.goto.url) ──
17746 navigation https://k6e2etests.grafana-dev.net/a/k6-app/projects
14992 navigation https://k6e2etests.grafana-dev.net/a/k6-app/projects/58195
...
── web-vital ratings ──
LCP {"poor":5,"needs-improvement":1}
CLS {"good":2}
...
2 段落のテキストで、どのナビゲーションに時間がかかっているか、どの Web Vitals が悪化しているか、スパン名の全体的な分布を把握できます。OTLP ツリーをくまなく調べずに、ブラウザーのパフォーマンスを分析するには十分です。
知っておくとよい注意点
- ヘッダーは必須です。
/searchと/traces/<id>はどちらも、X-K6TestRun-Idがないと HTTP 401 を返します。このヘッダーによって、クエリの対象が実行のテナントに限定されます。 start/endは UNIX 秒です。 RFC3339 形式の ISO 文字列を指定すると、HTTP 400 invalid start: strconv.ParseUintが返されます。技術的には省略可能で、指定しなくても検索できますが、実行のcreated/endedに合った期間(さらに約60秒のバッファー)を指定すると、クエリが高速になり、シナリオ名が同じ無関係な実行と一致するのを防げます。- LogQL ではなく TraceQL です。
qパラメーターでは TraceQL を使用します。スパンの述語はspan.<attribute>と記述し、&&で結合します。推奨クエリは特定のシナリオのイテレーションルートスパンを絞り込みます。test.scenarioを削除すると対象を広げられ、たとえばspan.test.vu = 3 && span.test.iteration.number = 5を追加すると、特定の VU における単一のイテレーションに絞り込めます。 - シナリオ名は実行から取得します。 実行オブジェクトの
.options.scenariosの キー がシナリオ名です。次のコマンドで一覧表示できます。gcx api /api/plugins/k6-app/resources/cloud/cloud/v6/test_runs/$RUN_ID --json options 2>/dev/null | jq -r '.options.scenarios | keys[]'デフォルトのシナリオ名はdefaultです。ブラウザーテストではui、browserなどの名前がよく使われます。 - OTLP ボディー内のスパン ID は base64 形式です。 検索レスポンスの
traceIDは16進数形式(/traces/<id>が受け付ける形式)ですが、OTLP バッチ内のtraceId/spanId/parentSpanIdフィールドは base64 エンコードされたバイト列です。親子関係は、どちらも base64 のままparentSpanId == spanIdで照合できます。デコードは不要です。 - ブラウザーテストのスパンで役立つ属性キーは、
navigation.url、page.goto.url、screenshot.path、web_vital.name、web_vital.value、web_vital.rating、test.scenario、test.vu、test.iteration.number、k6.test_run_idです。サマリーに含める価値がある属性です。OTel の値エンベロープは{stringValue|intValue|boolValue|doubleValue}です(上記の jqattrvalヘルパーは4種類すべてに対応しています)。
8. Cloud Insights(実行の監査結果)
Cloud Insights は完了したテストにヒューリスティックを適用し、高カーディナリティ、Web Vitals の回帰、しきい値の未設定、負荷生成器の過剰利用などをチェックして、別の /resources/insights/ プラグインルート(/cloud/v{N}/ ではありません)を通じて結果を公開します。認証には引き続き gcx を使用するため、追加のヘッダーは不要です。
データを取得するには3つの呼び出しが必要です。エージェントに役立つ出力は、そのうち2つの結果を結合したものです。
RUN_ID="<run_id>"
BASE="/api/plugins/k6-app/resources/insights/insights/api/v1/testrun/$RUN_ID"
# 1. List executions for the run, take the most recent. The response
# is { "executions": [ {id, version}, ... ] } — NOT a bare array.
# Pick the last entry; insights re-runs append, and the newest one
# reflects the current set of audits/scores.
EXEC_ID=$(gcx api "$BASE/executions" -o json 2>/dev/null \
| jq -r '.executions[-1].id')
# 2. Audit definitions (id, title, description, weight). ~15 items.
gcx api "$BASE/executions/$EXEC_ID/audits" -o json 2>/dev/null \
> /tmp/insights_audits_${RUN_ID}.json
# 3. Audit results (audit_id, status, score, explanation, actions).
gcx api "$BASE/executions/$EXEC_ID/audits/results" -o json 2>/dev/null \
> /tmp/insights_results_${RUN_ID}.json
どちらのレスポンスも同じトップレベルキー audits を使いますが、内容は異なります。ステップ2は各監査のチェック内容のカタログで、ステップ3はその監査で今回の実行について検出された結果です。result.audit_id == audit.id で相互結合します(実際には1対1です)。
コンパクトでエージェントが読みやすいサマリーへの結合
監査と結果の生 JSON を合わせると約10 KBです。監査ごとに3行を読み取るだけなのに、両方をコンテキストに出力するのは非効率です。jq で結合し、簡潔なブロックを1つ出力しましょう。以下のパイプラインが推奨される形式です。
jq -nr \
--slurpfile a /tmp/insights_audits_${RUN_ID}.json \
--slurpfile r /tmp/insights_results_${RUN_ID}.json '
($a[0].audits | INDEX(.id)) as $defs
| $r[0].audits
| map({
title: ($defs[.audit_id].title // "?"),
description: ($defs[.audit_id].description // ""),
status: .status,
status_reason: .status_reason,
score: (
if .score == null then "n/a"
elif .score.type == "binary" then (if .score.value then "pass" else "fail" end)
else (.score.value | tostring)
end),
explanation: (.explanation // "" | gsub("\n+"; " ") | .[0:300]),
actions: (.actions // [])
})
| .[]
| "── \(.title) — score: \(.score)\(if .status == "failed" then " [audit did not run: \(.status_reason // "unknown")]" else "" end)\n \(.description)\n → \(.explanation)\(if (.actions|length) > 0 then "\n actions:\n - " + (.actions|join("\n - ")) else "" end)\n"
'
監査が15件の実行では、タイトル、スコア、1行の説明、1行の解説、アクション項目を含む約5 KBのプレーンテキストが出力されます。テストの健全性をエージェントが判断するにはこれで十分で、どちらの JSON も読み直す必要はありません。
知っておくべき注意点
status≠ 判定です。status: "succeeded"は、監査が実行されたことを意味します。判定はscoreに示されます(binaryの true/false、または最良値が 1 のnumericの 0…1)。status: "failed"は、監査自体を実行できなかったことを意味します(通常はstatus_reason: "missing data"。たとえば、トレースを行わないテストでの HTTP Spans 監査など)。scoreフィールドはありません。これらは失敗ではなく、「シグナルなし」として扱ってください。- スコアのしきい値は監査ごとに異なります。 ある監査では
numericの 0.94 が問題なくても、別の監査では懸念事項となる場合があります。全体に適用できるしきい値はありません。スコアの意味を判断する際はexplanationを基準とし、合否ルールを独自に作るのではなく、そのまま提示してください。 - 具体的な対応につながるのは
actionsです。 監査に具体的な推奨事項(「urlラベルのカーディナリティを下げる……」など)がある場合にのみ表示されます。改善を目指しているユーザー向けに実行結果を要約する場合は、actions配列が空でない監査を最初に取り上げてください。 - 最初ではなく、最後の実行結果を選んでください。
.executions[]は時系列順で、再実行すると末尾に追加されます。古い実行結果は以前の監査ロジックに基づいており、現在の状況を反映していない場合があります。 - Insights は実行後の分析です。 実行が完了していない場合(または Insights の計算に必要なデータが得られていない場合)、実行リストが空になることがあります。
length == 0の場合は適切に処理を中断してください。
9. ローカルの k6 CLI(スモークテストと k6 cloud run)
ローカルの k6 CLI は、クラウドに送信する前の構文チェックや、1 イテレーションのスモークテストに適しています。
k6 inspect script.js | head -20 # parse-only sanity
k6 run --quiet script.js # run locally
k6 cloud run(ノート PC からクラウドにアップロードして実行する場合)では、gcx から取得したトークンとスタック URL を使って k6 cloud login で認証してください。トークンは gcx k6 auth token から取得し、スタック URL はアクティブな gcx コンテキストの grafana.server フィールドから取得します。
TOKEN=$(gcx --context <ctx> k6 auth token)
STACK=$(gcx --context <ctx> config view --minify -o json | jq -r '.contexts[].grafana.server')
k6 cloud login --token "$TOKEN" --stack "$STACK"
k6 cloud run script.js
k6 のクラウド設定(~/.config/k6/cloud.json)は単一コンテキストのみを対象とするため、gcx コンテキストを切り替えるたびに k6 cloud login を再実行してください。そうしないと、k6 cloud run は以前のスタックを対象にし続けます。
終了コード:0 は合格、99 はしきい値未達、それ以外はスクリプトまたは実行時のエラーです。
10. 注意事項
| 症状 | 原因 | 対処方法 |
|---|---|---|
401 "Invalid or expired token — run gcx login to refresh" | gcx の OAuth セッションの有効期限が切れています | gcx login --context <ctx> |
正しいように見えるパスで 403 / 404 が発生する | REST エンドポイントで cloud/cloud/ を二重に指定し忘れています | …/resources/cloud/cloud/v{N}/… を使用します |
スクリプトの PUT で 415 unsupported media type が発生する | -H "Content-Type: application/octet-stream" がありません | 追加し、gcx api に -vvv(または --log-http-payload)を渡してリクエストを確認します |
| スクリプトの PUT は 200 を返すものの、変更が反映されない | スクリプトの変更では updated タイムスタンプが更新されません | GET の sha256 で確認します(§5 手順 7) |
実行ステータスは passed ですが、チェックは失敗しています | 観測数がゼロのしきい値は成功として報告され、check() だけでは実行は失敗しません | 'checks{check:<name>}': ['rate==1.0'] を追加します。catch ブロックでは check(null, {"script completed":()=>false}) を使って観測を強制します |
| 最近の実行について Loki クエリが何も返しません | X-K6TestRun-Id ヘッダーがありません | ログクエリでは常に -H "X-K6TestRun-Id: <run_id>" を渡します |
gcx k6 runs list --limit 0 は最新 1000 件ではなく、最古の 1000 件を返します | サブコマンドは @nextLink をたどらず、昇順がデフォルトです。実行が 1000 件を超えると、表示される first/last は最近のアクティビティではなく、履歴の開始部分になります | 最新順の一部を取得するには $orderby=created desc を指定して gcx api を使うか、§3 の @nextLink をすべてたどるループを使います |
gcx k6 load-tests update -f は ✔ Updated を返しますが、変更が反映されません | v6 PATCH スキーマの範囲外のフィールドは(PatchLoadTestApiModel では name、baseline_test_run_id のみが許可され、additionalProperties: false)、通知なく無視されます。特に project_id はこの方法では更新できません | プロジェクトを移動するには専用の /move エンドポイント(§11)を使用します。他の変更については OpenAPI 仕様の PATCH スキーマを確認してください。必ず再度 GET して確認します |
gcx k6 load-tests list --project-id <id> がすべてのプロジェクトのテストを返します | フラグは受け付けられますが、フィルタリングされません。/cloud/v6/load_tests にはプロジェクトのクエリパラメーターがありません | gcx api 経由で GET /cloud/v6/projects/{id}/load_tests を使うか、jq で select(.project_id == X) を使ってクライアント側でフィルタリングします |
gcx api 経由のマルチパート POST で HTTP 415 "Unsupported media type \"application/json\"" が発生します | Grafana プラグインプロキシが転送前にマルチパートの Content-Type を application/json に書き換えます(gcx 自体は指定したヘッダーを送信しますが、プロキシが取り除きます) | api.k6.io に対する直接の curl(§1.2)に切り替えます。テストの作成(POST /cloud/v6/projects/{id}/load_tests)や、その他のマルチパートエンドポイントに影響します |
api.k6.io / cloudlogs.k6.io を直接呼び出すと(curl モード)401 Unauthorized が発生します | Authorization: Bearer … または X-Stack-ID ヘッダーがないか、誤っています | 両方のヘッダーを再確認します。/cloud/v6/auth(§1.2)を使ってスタック URL から X-Stack-ID を取得します |
api.k6.io/api/plugins/... を呼び出すと(curl モード)404 が発生します | 誤ってプラグインプロキシのプレフィックスを残しています | /api/plugins/k6-app/resources/{cloud,logs,insights} を取り除きます。§1.2 を参照してください |
11. update -f で対応していない変更
gcx k6 <resource> update -f は、そのリソースの v6 PATCH スキーマに従います。スキーマに含まれないフィールドは、gcx が引き続き ✔ Updated <resource> <id> と表示していても、黙って破棄されます(§10 の行を参照)。よくある変更の中には、専用のエンドポイントが用意されているものがあり、PATCH ルートでは何も行われません。
| 変更 | エンドポイント | 本文 |
|---|---|---|
| テストを別のプロジェクトに移動する | PUT /cloud/v6/load_tests/{id}/move | {"project_id": <int>} |
| テスト実行を開始する | POST /cloud/v6/load_tests/{id}/start | {}(または実行オプション) |
開始した実行のポーリング: 実行を開始した後、status が completed または aborted になるまで GET /cloud/v6/test_runs/{id} をポーリングします。status とともに、必ず result フィールドも確認してください。status: completed で result: error の場合、しきい値超過ではなく、設定またはインフラストラクチャの障害を意味します。passed 以外の結果になった場合は、ユーザーからの報告を待たずに、直ちにログ(§4)を取得してエラーを明らかにしてください。
| 実行中のテストを中止する | POST /cloud/v6/test_runs/{id}/abort | 空 |
| スケジュールを設定/上書きする | POST /cloud/v6/load_tests/{id}/schedule | スケジュール本文(recurrence_rule または cron) |
| スケジュールを無効化/再有効化する | POST /cloud/v6/schedules/{id}/{deactivate,activate} | 空 |
| 負荷テストを作成する(マルチパート!)| POST /cloud/v6/projects/{id}/load_tests | マルチパート:name + script |
| 保持期間を過ぎても実行を保存する | POST /cloud/v6/test_runs/{id}/save | 空(/unsave と対になります) |
update -f で実行できる PATCH スタイルの更新:
| リソース | 更新可能なフィールド |
|---|---|
| 負荷テスト | name、baseline_test_run_id(PatchLoadTestApiModel による) |
| プロジェクト | name のみ(PatchProjectApiModel による) |
どちらのスキーマでも additionalProperties: false が宣言されています。マニフェストに指定したその他のフィールドは、PATCH の送信前に黙って除外されますが、gcx は引き続き ✔ Updated と報告します。update -f で is_default を切り替えたり、grafana_folder_uid を移動したりしないでください。これらは v6 PATCH で変更できるフィールドとして公開されていません。
フィールドが変更可能だと判断する前に、OpenAPI 仕様で操作のリクエストスキーマを確認してください(§3 のワークフローを参照)。
実例 — テストを別のプロジェクトに移動する
gcx api /api/plugins/k6-app/resources/cloud/cloud/v6/load_tests/<test_id>/move \
-X PUT \
-H "Content-Type: application/json" \
-d '{"project_id": <new_project_id>}'
# Verify — re-GET and check project_id reflects the new value.
# Do not trust the absence of an error from the PUT; HTTP 204 with
# empty body is the success shape but gcx api prints nothing.
gcx --context <ctx> k6 load-tests get <test_id> -o json | jq '{id, name, project_id}'
このエンドポイントの OpenAPI の説明は明確です。「負荷テストを同じ組織内の別のプロジェクトに移動します。関連するすべてのテスト実行も新しいプロジェクトに移動されます。」 実行を個別に移行する必要はありません。
知っておくべきカスケード動作
- 負荷テストを削除すると、そのスケジュールも連鎖的に削除されます。 スケジュールは
/cloud/v6/schedulesと/cloud/v6/load_tests/{id}/scheduleから直ちに削除されます。予防策として先にgcx k6 schedules delete <load-test-id>を実行する必要はありません。 - 実行中のテストがあるプロジェクトを削除しようとすると、HTTP 409 エラーで失敗します(OpenAPI 仕様では「Cannot delete project with a running test.」)。実行中でないテストはプロジェクトとともに削除されるようですが、削除前にプロジェクトの内容を一覧で確認する場合は、
GET /cloud/v6/projects/{id}/load_testsを使用してください(gcx k6 load-tests list --project-id <id>はフィルタリングされません。§10 を参照)。 - テストを移動すると、その実行と実行履歴も一緒に移動します。 スケジュールの関連付けもテストに追従します(プロジェクトではなく、
load_test_idにひも付けられているため)。
検証の目安
このスキルで繰り返し見られるパターンは、*「基盤となる呼び出しが何もしなくても、gcx は成功を確認したと報告する」*というものです。状態を変更するたびに、次のことを行ってください。
- 変更されると予想した内容(フィールド、件数、ステータス)を記録します。
- リソースを再度 GET し、変更が反映されていることを確認します。
- 反映されていない場合は、
update -fではなく、専用のエンドポイント(このセクション)を使用する必要があったかどうかを確認します。