Open tusharshahrs opened 1 year ago
The issue looks like it's due to our pulumi-kubernetes thinking that a new cluster is being targeted. Hence, it will attempt to create the resources again. When it does so, it uses a imperative create method, that will fail since the cluster already has the resources applied earlier. We should be doing something like "create or update" in events like these, since the failure on creation shouldn't be important if it's due to the resource already existing.
Note that issue not only affects CRDs, but any Kubernetes resources.
We can workaround this issue by using server side apply instead, and it will not error out since a PATCH request is sent instead in SSA mode.
Relevant code chunks:
In client side mode, we do a client.Create
: https://github.com/pulumi/pulumi-kubernetes/blob/dae363925ac5d7b613afeb2fca1ffb1999c7ee83/provider/pkg/await/await.go#L221
Whereas SSA does a PATCH request: https://github.com/pulumi/pulumi-kubernetes/blob/dae363925ac5d7b613afeb2fca1ffb1999c7ee83/provider/pkg/await/await.go#L206
For a fix to happen/next steps, we would need to implement logic to determine when a provider is being switched and use a patch request instead of a create request.
I updated the issue description with new information about the problem.
After further investigation, there does not appear to be an easy solution to this bug. The same issue affecting SSA-managed resources also impacts a few other resources.
There are a few possible solutions that require further investigation:
In the meantime, our recommendation is the following:
I've also run into this issue following a provider update, due to certificates in the kubeconfig
being renewed. I was able to work around it with some stack surgery (manually editing the stack to contain the new kubeconfig, so the change isn't detected).
Unfortunately, I don't think either of recommendations is feasible for us:
A resource's provider should not be changed as part of an update
We need to change the kubeconfig
, because the old one is no longer valid (expired certificate).
If the provider needs to be changed, the resource should be dropped from Pulumi state, and then reimported under the new provider.
We have several copies of this stack, each with several hundred resources. Most of the resources have names auto-generated by Pulumi, so we'd also have to find the correct name to import for each stack (possible, but not trivial).
I think implementing https://github.com/pulumi/pulumi-kubernetes/issues/2745 could help since it would provide a way to stop provider from being replaced
I'm reassigning to Bryce since he's working on #2745 and that should resolve this one.
we're hitting this as well, thanks for the helpful explanations above
I've got a simpler reproduction and explanation, but I'll leave the original issue text below for historical context.
What happened?
Resource replacement erroneously deletes the resource when the following conditions are true:
This does not happen in Client-side apply mode because the resource creation fails during replacement due to the resource already existing.
In Server-side apply mode, the create succeeds even if the resource existed previously. This behavior was intended to support "upsert" behavior. Unfortunately, the "delete" portion of the resource replacement now removes the resource, causing it to be deleted from the cluster. (
deleteBeforeReplace
still works as expected, but is not an option forCustomResourceDefinition
resources, since this will also delete relatedCustomResource
resources on the cluster.)Further complicating this problem, the engine, rather than the provider, plans the resource replacement based on the provider changing. Resource aliases do not currently support aliasing providers. It is possible to manually drop the resource from state and then import it with the new provider, but this requires changes outside of the program code, so it may not be an option for some users.
Expected Behavior
The provider should not delete the resource that it is expected to replace.
Steps to reproduce
pulumi config set kubernetes:enableServerSideApply true
pulumi up
the following programconst provider = new k8s.Provider("k8s", { enableServerSideApply: true, }); new k8s.core.v1.ConfigMap("test", { metadata: {name: "test"}, data: {foo: "bar"} }, { provider, });
Dependencies: NAME VERSION @pulumi/pulumi 3.61.0 @pulumi/kubernetes 3.23.0
View in Browser (Ctrl+O): https://app.pulumi.com/tushar-pulumi-corp/aws-classic-ts-eks-spot-mg/dev/previews/259d842b-1a54-410c-83f8-7a0420e07b58
+- └─ kubernetes:apiextensions.k8s.io/v1:CustomResourceDefinition shaht-foobarcrd replace [diff: ~provider]
Resources: +-1 to replace 60 unchanged
++kubernetes:apiextensions.k8s.io/v1:CustomResourceDefinition: (create-replacement) [id=foobars.stable.example.com] [urn=urn:pulumi:dev::aws-classic-ts-eks-spot-mg::kubernetes:apiextensions.k8s.io/v1:CustomResourceDefinition::shaht-foobarcrd] [provider: urn:pulumi:dev::aws-classic-ts-eks-spot-mg::pulumi:providers:kubernetes::shaht-k8sprovider::acfa6c62-f920-40a3-9587-61e4ab3b1c33 => urn:pulumi:dev::aws-classic-ts-eks-spot-mg::pulumi:providers:kubernetes::default_3_25_0::output]
+-kubernetes:apiextensions.k8s.io/v1:CustomResourceDefinition: (replace) [id=foobars.stable.example.com] [urn=urn:pulumi:dev::aws-classic-ts-eks-spot-mg::kubernetes:apiextensions.k8s.io/v1:CustomResourceDefinition::shaht-foobarcrd]
View in Browser (Ctrl+O): https://app.pulumi.com/tushar-pulumi-corp/aws-classic-ts-eks-spot-mg/dev/updates/84
+- └─ kubernetes:apiextensions.k8s.io/v1:CustomResourceDefinition shaht-foobarcrd replacing failed [diff: ~provider]; 1 error
Diagnostics: pulumi:pulumi:Stack (aws-classic-ts-eks-spot-mg-dev): error: update failed
kubernetes:apiextensions.k8s.io/v1:CustomResourceDefinition (shaht-foobarcrd): error: resource foobars.stable.example.com was not successfully created by the Kubernetes API server : customresourcedefinitions.apiextensions.k8s.io "foobars.stable.example.com" already exists
Outputs:
Expected Behavior
The crd should be replaced even if it is across different providers.
Steps to reproduce
cd aws-classic-ts-eks-spot-mg
pulumi stack init dev
npm install
pulumi config set aws:region us-east-2
# any valid aws regionpulumi up -y
pulumi stack output my_crd
expected output:foobars.stable.example.com
// { provider: k8sProvider, dependsOn: [namespace, mycluster]});
{dependsOn: [namespace, mycluster]});
pulumi up
and see that the preview will show that the crd is beingreplaced
Resources: +-1 to replace 60 unchanged
Do you want to perform this update? details pulumi:pulumi:Stack: (same) [urn=urn:pulumi:dev::aws-classic-ts-eks-spot-mg::pulumi:pulumi:Stack::aws-classic-ts-eks-spot-mg-dev] ++kubernetes:apiextensions.k8s.io/v1:CustomResourceDefinition: (create-replacement) [id=foobars.stable.example.com] [urn=urn:pulumi:dev::aws-classic-ts-eks-spot-mg::kubernetes:apiextensions.k8s.io/v1:CustomResourceDefinition::shaht-foobarcrd] [provider: urn:pulumi:dev::aws-classic-ts-eks-spot-mg::pulumi:providers:kubernetes::shaht-k8sprovider::acfa6c62-f920-40a3-9587-61e4ab3b1c33 => urn:pulumi:dev::aws-classic-ts-eks-spot-mg::pulumi:providers:kubernetes::default_3_25_0::output]
apiVersion: "apiextensions.k8s.io/v1"
kind : "CustomResourceDefinition"
metadata : {
labels: {
app.kubernetes.io/managed-by: "pulumi"
}
name : "foobars.stable.example.com"
}
spec : {
group : "stable.example.com"
names : {
kind : "FooBar"
plural : "foobars"
shortNames: [
+- └─ kubernetes:apiextensions.k8s.io/v1:CustomResourceDefinition shaht-foobarcrd replacing failed [diff: ~provider]; 1 error
Diagnostics: pulumi:pulumi:Stack (aws-classic-ts-eks-spot-mg-dev): error: update failed
kubernetes:apiextensions.k8s.io/v1:CustomResourceDefinition (shaht-foobarcrd): error: resource foobars.stable.example.com was not successfully created by the Kubernetes API server : customresourcedefinitions.apiextensions.k8s.io "foobars.stable.example.com" already exists
Outputs:
Resources: 60 unchanged
Duration: 9s