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と入力すると取り込めましたが1、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がリソースのプロパティに対しても使えれば解決するので近々できるようになったりするといいですね。

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


  1. 最新Terraformではimportブロックを使ってコードで取り込みが可能です。