Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

k8s.ReplaceNamespacedCustomObject() extension isn't working #1879

Closed
jefflill opened this issue Jan 31, 2024 · 3 comments
Closed

k8s.ReplaceNamespacedCustomObject() extension isn't working #1879

jefflill opened this issue Jan 31, 2024 · 3 comments

Comments

@jefflill
Copy link
Collaborator

jefflill commented Jan 31, 2024

The k8s.ReplaceNamespacedCustomObject() extension method is failing with UnprocessableEntity errors. This is probably happening with the cluster custom objects as well. This is impacting our Upsert related methods when the resource already exists. The base k8s.ReplaceNamespacedCustomObject() isn't documented anymore for .NET and is barely documented for other languages.

Perhaps we can use one of the patch related methods instead.

@marcusbooyah
Copy link
Member

Where is it not working?

@jefflill
Copy link
Collaborator Author

jefflill commented Jan 31, 2024

Here's a simple repro (an existing cluster is required):

using k8s;
using k8s.Models;

using Neon.Kube;
using Neon.Kube.K8s;
using Neon.Kube.Resources.Istio;

namespace test
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            var k8s       = new Kubernetes(KubernetesClientConfiguration.BuildDefaultConfig());
            var telemetry = new V1Telemetry()
            {
                Metadata = new V1ObjectMeta()
                {
                    Name              = "upsert-test",
                    NamespaceProperty = "default"
                },
                Spec = new V1TelemetrySpec()
                {
                    Tracing = new List<Tracing>()
                    {
                        new Tracing()
                        {
                            Providers = new List<TracingProvider>()
                            {
                                new TracingProvider()
                                {
                                    Name = "opencensus"
                                }
                            },
                            RandomSamplingPercentage = 1.0
                        }
                    }
                }
            };

            // This creates the resource.

            await k8s.CustomObjects.UpsertNamespacedCustomObjectAsync<V1Telemetry>(telemetry, name: telemetry.Name(), namespaceParameter: telemetry.Namespace());

            // This should update the resource, but fails.

            telemetry.Spec.Tracing[0].RandomSamplingPercentage = 100.0;

            await k8s.CustomObjects.UpsertNamespacedCustomObjectAsync<V1Telemetry>(telemetry, name: telemetry.Name(), namespaceParameter: telemetry.Namespace());
        }
    }
}

...and here's the error:

Operation returned an invalid status code 'UnprocessableEntity', response body {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"telemetries.telemetry.istio.io \"upsert-test\" is invalid: metadata.resourceVersion: Invalid value: 0x0: must be specified for an update","reason":"Invalid","details":{"name":"upsert-test","group":"telemetry.istio.io","kind":"telemetries","causes":[{"reason":"FieldValueInvalid","message":"Invalid value: 0x0: must be specified for an update","field":"metadata.resourceVersion"}]},

Looks like we need to pass the original resource's resourceVersion. I spent a couple minutes playing around with that but then set it aside to look at later.

I noticed this when single-stepping through the V1Telemetry creation in namespaces code during cluster setup, when I quit debugging after one resource was created and then restarted setup and I expected that it would just update the first existing resource and then finish creating the other resources. But the upsert call failed on that existing resource.

I've worked around this by using CreateNamespacedCustomObjectAsync() and protecting each with an InvokeIdempotentAsync().

@marcusbooyah
Copy link
Member

Fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants