Cloud Run Admin APIでサービスを取得する時の注意点


特定のCloud Runサービスの情報を取得しようとした時に思いっきり嵌ったので備忘録を残しておきます。

まず始めにCloud Runを操作するAPIは以下に用意されています。

上記ライブラリを読むと以下メソッドでCloud Runのサービス情報を取得できることが分かります。

// Get: Get information about a service.
//
// - name: The name of the service to retrieve. For Cloud Run (fully
//   managed), replace {namespace_id} with the project ID or number.
func (r *NamespacesServicesService) Get(name string) *NamespacesServicesGetCall {
    c := &NamespacesServicesGetCall{s: r.s, urlParams_: make(gensupport.URLParams)}
    c.name = name
    return c
}

nameをどういった形式で入れれば良いのかが判然としないので、Google Cloud公式のドキュメントを確認します。

以下にAPIに関する情報が記載されており、この内容を読むとnamespaces/{namespace_id}/services/{service_id}の形式で渡してやれば良いと分かります。namespace_idservice_idの変数部分はそれぞれGoogle CloudのプロジェクトIDとCloud Runのサービス名を渡してやります。

ここまで調べた内容をもとに以下のようなコードを書きました。

import (
    "context"
    "fmt"

    "google.golang.org/api/run/v1"
)

func FetchURLByServiceName(ctx context.Context, projectID, name string) (string, error) {
    c, err := run.NewService(ctx)
    if err != nil {
        return "", err
    }

    service, err := c.Namespaces.Services.Get(fmt.Sprintf("namespaces/%s/services/%s", projectID, name)).Do()
    if err != nil {
        return "", err
    }

    return service.Status.Url, nil
}

しかし以下のようにエラーになってしまいます...。

googleapi: Error 404: Requested entity was not found.

どこもおかしいような箇所は無いように思うのですが、存在しないエンティティにリクエストを投げていると言われているので、取り敢えずデバッガーで実際に投げているURLを確認します。

一通り見ても期待通りの値が入っているので途方に暮れてしまいました。
ここで数時間悶々としていたのですが、以下のドキュメントに手がかりが書いてありました。

https://run.googleapis.com (Global API endpoint, supports list methods only)

デフォルトで付与されるエンドポイントhttps://run.googleapis.comはListメソッドでしか利用できず、その他のメソッドを使用する場合はリージョン毎のエンドポイントにリクエストを投げる必要がありました。

この点を踏まえ以下のように実装したところ、ようやく期待動作するようになりました。

import (
    "context"
    "fmt"

    "google.golang.org/api/run/v1"
)

func FetchURLByServiceName(ctx context.Context, name, projectID, region string) (string, error) {
    c, err := run.NewService(ctx)
    if err != nil {
        return "", err
    }
    c.BasePath = fmt.Sprintf("https://%s-run.googleapis.com/", region)

    service, err := c.Namespaces.Services.Get(fmt.Sprintf("namespaces/%s/services/%s", projectID, name)).Do()
    if err != nil {
        return "", err
    }

    return service.Status.Url, nil
}

ドキュメントはちゃんと読め、ということですね...。