tech.guitarrapc.cóm

Technical updates

Pulumi リソースのプロパティが変わってしまい create-replacement が発生する場合の対処方法

Pulumi のパッケージ更新をしたら、プロパティ名が変わっており craete-replacement が生じてしまう。

Pulumi SDK 側でプロパティ名が変更されると発生するのですが、普段出会うことはまずありません。 しかし稀に、プレビューパッケージを使ったり、プレビューから GA した直後のサービスで起こることがあります。

Azure の Container Apps で最近起こったので備忘録に挙げておきます。

Warning: この対処は、リソースの再作成がかかる 必須プロパティでのみ必要になります。オプショナルなプロパティでは、単純にプロパティ名変更に追随するだけでokです。

tl;dr;

リソースのプロパティ名変更に対応するには、2つの方法が考えられます。

  1. 該当 URN をステートから削除してリソースをインポートしなおす
  2. スタックをエキスポートしてステートJSON を直接編集してスタックにインポートしなおす

残念ながら、リソースの必須プロパティ名の変更で生じる reate-replacement に対処できる Custom Resource Options は存在しません。 類似ケースのIssue があるのですが、プロパティに Alias がつけられるようになれば Terraform の moved ブロックのように何とかなりそうですね。

github.com

問題の概要

Pulumi はリソース URN 自体の移動に対しては CustomResourceoption で Alias を指定することで移動が可能です。 リソースプロパティの無視は Ignore で可能です。

しかし、リソースのプロパティ名の変更が起こった時に、旧プロパティ名から新プロパティ名に変更を追随するためのマーカーを渡す方法がありません。 オプショナルなプロパティであればプロパティ名を変えればいいのですが、必須プロパティの場合 create-replacement が生じてしまいます。

対処方法

要はステートのプロパティ名が違っているので、一度 URN を削除してから同じ URN にインポートしなおすことでプロパティ名の変更に追随できます。 ステートを直接JSONで触るか/触らないかで、2つのワークアラウンドが考えられます。

  1. 該当 URN をステートから削除してリソースをインポートしなおす
  2. スタックをエキスポートしてステートJSON を直接編集してスタックにインポートしなおす

JSONを直接いじりたくないので、1について説明します。

該当 URN をステートから削除してリソースをインポートしなおす。

この方法は JSON を直接触るより手間がかかります。 代わりに、JSON で万が一にも変なところを触ってインポート時におかしくなるという状況は避けられます。

該当ステートの状態をブラウザで確認しておく (オプショナル)

このステップは必須ではありませんが、やることをお勧めします。

この後、Pulumi から URN を削除すると今の Pulumi での状態が見れなくなります。

できれば ブラウザで Pulumi Console の街頭 URN を開いて、プロパティの状態をタブで開いておきましょう。 タブで開いていおくことで、「構築時のコード」と「インポート時に必要なプロパティ」の暗黙の指定が明確に把握できます。 インポート時にコードとリソースの差分が出ても、このタブを見ればどんな違いがあるか推測するのに役立ちます。

該当コードの URN を見つける

Pulumi Console のリソース一覧 (グラフからでも一覧でもよし) を開き、該当の URN を見つけてください。 あるいは pulumi cli であれば pulumi stack --show-urns から探してもいいでしょう。

pulumi stack --show-urns | grep "リソース名"

URN: urn:pulumi:xxx:Stack名::Provider名:なんとかかんとか といったフォーマットの URN が見つかったらメモします。

ステートから URN を削除する

URN を ステートから削除することによって、クラウドプロバイダー上にリソースを残したまま Pulumi の対応を消すことができます。 pulumi cli をつかって、該当の URN 消します。

pulumi state delete <先ほど見つけたURN>

確認されるので y で削除を実行します。

クラウド環境からリソースをインポートする

Terraform同様に、Pulumi もクラウド環境の状態をコードに取り込むことができます。 Terraform は cli で terraform import クラウドリソースID で取り込みましたが、Pulumi はコード上の CustomResourceOptions.ImportId で指定します。

www.pulumi.com

例えば、Azure の Managed Environment であれば次のようになります。

Note: Pulumi.AzureNative を .NET で使っている場合、NuGet パッケージ 1.64.1 から 1.65.0 に更新すると発生します。

_ = new ManagedEnvironment("FooBar", new ManagedEnvironmentArgs
{
    EnvironmentName = "foo", // ここが AzureNative nuget パッケージの更新で Name から EnvironmentName に変わった
    AppLogsConfiguration = new AppLogsConfigurationArgs
    {
        Destination = "log-analytics",
        LogAnalyticsConfiguration = new LogAnalyticsConfigurationArgs
        {
            CustomerId = "ログアナリティクスID"
            // SharedKey = "シェアドキー" <- インポート時に SharedKey は入らないのでコメントアウト必須
        },
        ZoneRedundant = false, // 暗黙のプロパティ で false だが、インポート時は 明示的に指定しないと Diff が出てインポートが失敗する
        ResourceGroupName = "Foo-Group",
        Location = "japan-east",
        Tags = .... // あればちゃんと指定する
    }
}, new CustomResourceoptions
{
    Parent = this, // インポート時のリソースの Parent 指定になるので、コンポーネントと親子関係持たせるなら必須
    ImportId = "/subscriptions/xxxxxxx/resourceGorups/Foo-Group/providers/Microsoft.App/managedEnvironment/foo" // Azure Resource Id
});

インポート時の注意は、現在のリソースとの Diff が生じてはいけないということです。 このため、暗黙のプロパティで与えられる値も明示的に指定が必要です。(例では ZoneRedundant = false は暗黙で与えられるが明示的に指定が必要) インポート時のリソースは、 CustomResourceoptions.ImportId で指定しましょう。Azure の場合はリソースID です。

あとは差分がないか pulumi cli で確認します。

差分があるとインポートは 100% 失敗します、差分がないように気を付けてください。 ただし差分は Diff ではプロパティ名までしか確認できず値がわかりません。 「該当ステートの状態をブラウザで確認しておく」のステップで開いておいたタブでプロパティ値とコードを見比べるといいでしょう。

pulumi preview

差分がなければインポートを実行します。

pulumi up

インポートが成功すればokです。

コードから ImportId を削除する

コードから CustomResourceoptions.ImportId セクションを消して、 pulumi を実行してみて差分が出ず実行完了すれば終わりです。

まとめ

Pulumi の人からリプライがついていますが、Alias がリソースのプロパティに対しても使えれば解決するので近々できるようになったりするといいですね。

相談を受けて、そういえば記事にしていなかったので起こしました。