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

Improve documentation of use of resourceVersion for update preconditions #2115

Closed
erictune opened this issue Nov 1, 2014 · 12 comments
Closed
Assignees
Labels
area/api Indicates an issue on api area. kind/documentation Categorizes issue or PR as related to documentation.

Comments

@erictune
Copy link
Member

erictune commented Nov 1, 2014

POST /api/v1beta1/replicationControllers
        {
          "kind": "ReplicationController",
          "apiVersion": "v1beta1",
          "id": "a",
          "desiredState": {
            "replicas": 2,
            "replicaSelector": {"name": "a"},
            "podTemplate": {
              "desiredState": {
                 "manifest": {
                   "version": "v1beta1",
                   "id": "a",
                   "containers": [{
                     "name": "foo",
                     "image": "bar/foo",
                   }]
                 }
               },
               "labels": {"name": "a"}
              }},
          "labels": {"name": "a"}
        }

That works (200)

Then, PUT the exact same body to the created URL, and get a 409 Conflict.

PUT /api/v1beta1/replicationControllers/a
        {
          "kind": "ReplicationController",
          "apiVersion": "v1beta1",
          "id": "a",
          "desiredState": {
            "replicas": 2,
            "replicaSelector": {"name": "a"},
            "podTemplate": {
              "desiredState": {
                 "manifest": {
                   "version": "v1beta1",
                   "id": "a",
                   "containers": [{
                     "name": "foo",
                     "image": "bar/foo",
                   }]
                 }
               },
               "labels": {"name": "a"}
              }},
          "labels": {"name": "a"}
        }

Shouldn't you be able to update the same object with the same body as you created it with?

Maybe the problem is that there are some server-added fields that I should GET before PUTting back, but then why does this return 409 while you get a 422 for doing the same thing with /services?

@brendandburns
Copy link
Contributor

You're not setting the resource version during the PUT, that's why there's
an error.

Brendan
On Nov 1, 2014 4:47 PM, "Eric Tune" notifications@github.com wrote:

POST /api/v1beta1/replicationControllers
{
"kind": "ReplicationController",
"apiVersion": "v1beta1",
"id": "a",
"desiredState": {
"replicas": 2,
"replicaSelector": {"name": "a"},
"podTemplate": {
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "a",
"containers": [{
"name": "foo",
"image": "bar/foo",
}]
}
},
"labels": {"name": "a"}
}},
"labels": {"name": "a"}
}

That works (200)

Then, PUT the exact same body to the created URL, and get a 409 Conflict.

PUT /api/v1beta1/replicationControllers/a
{
"kind": "ReplicationController",
"apiVersion": "v1beta1",
"id": "a",
"desiredState": {
"replicas": 2,
"replicaSelector": {"name": "a"},
"podTemplate": {
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "a",
"containers": [{
"name": "foo",
"image": "bar/foo",
}]
}
},
"labels": {"name": "a"}
}},
"labels": {"name": "a"}
}

Shouldn't you be able to update the same object with the same body as you
created it with?

Maybe the problem is that there are some server-added fields that I should
GET before PUTting back, but then why does this return 409 while you get a
422 for doing the same thing with /services?


Reply to this email directly or view it on GitHub
#2115.

@brendandburns
Copy link
Contributor

I'm closing this as it is WAI.

@abonas
Copy link
Contributor

abonas commented Nov 3, 2014

@brendanburns can you elaborate/point to documentation how to use the 'resourceVersion' property? Should the user increment +1 it everytime the PUT is sent? why isn't it incremented automatically by the server? or there are other rules to changing this property?
thank you.

@bgrant0607
Copy link
Member

@abonas Search for resourceVersion in https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/api-conventions.md and let us know whether this answers your question.

@abonas
Copy link
Contributor

abonas commented Nov 3, 2014

@bgrant0607 Thank you, read it. what's still not clear to me is "This value MUST be treated as opaque by clients and passed unmodified back to the server" - so when a user is passing a PUT request that updates the entity, the resourceVersion should not be changed? the next GET request after this PUT request will send to client an "increased by 1" resourceVersion value?

@brendandburns
Copy link
Contributor

You can't guarantee that it's increased by one, just that it will be
different.

The resourceVersion is used to enable optimistic concurrency for atomic
read/update/write operations.

The way that it works is like this:

Client reads value, get's resource version N
Client updates the value client side to represent desired change.
Client writes back the value with resource version N.

This write only succeeds if the current resource version matches N. This
ensures that no one else has snuck in and written a different update while
the client was in the process of performing it's update. This prevents
bugs like the following:

Client #1 Client #2
Read Foo Read Foo
Set Foo.Bar = "one" Set Foo.Baz =
"two"
Write Foo Write Foo

When these things happen in parallel, either the change to Foo.Bar or the
change to Foo.Baz can be lost. If you instead use resource versions:

Client #1 Client #2
Read Foo @ Revision N Read Foo @ Revision N
Set Foo.Bar = "one" Set Foo.Baz =
"two"
Write Foo @ Revision N Write Foo @ Revision N

One of the writes will now fail, since which ever write succeeds changes
the revision for Foo.

--brendan

On Mon, Nov 3, 2014 at 7:21 AM, abonas notifications@github.com wrote:

@bgrant0607 https://github.com/bgrant0607 Thank you, read it. what's
still not clear to me is "This value MUST be treated as opaque by clients
and passed unmodified back to the server" - so when a user is passing a PUT
request that updates the entity, the resourceVersion should not be changed?
the next GET request after this PUT request will send to client an
"increased by 1" resourceVersion value?


Reply to this email directly or view it on GitHub
#2115 (comment)
.

@abonas
Copy link
Contributor

abonas commented Nov 3, 2014

@brendandburns thanks a lot. is there a predefined error code for cases when the write fails specifically due to a mismatch in resourceVersion as you describe above? so clients can distinguish this case from other types of failure during an update operation?

@brendandburns
Copy link
Contributor

Yeah, we send back HTTP 409 (conflict) in this case.

See:
https://github.com/GoogleCloudPlatform/kubernetes/blob/master/pkg/api/errors/errors.go

On Mon, Nov 3, 2014 at 8:01 AM, abonas notifications@github.com wrote:

@brendandburns https://github.com/brendandburns thanks a lot. is there
a predefined error code for cases when the write fails specifically due to
a mismatch in resourceVersion as you describe above? so clients can
distinguish this case from other types of failure during an update
operation?


Reply to this email directly or view it on GitHub
#2115 (comment)
.

@abonas
Copy link
Contributor

abonas commented Nov 3, 2014

@brendandburns thanks!

@bgrant0607 bgrant0607 changed the title PUT to existing /replicationControllers was conflict. Improve documentation of use of resourceVersion for update preconditions Nov 3, 2014
@bgrant0607 bgrant0607 added kind/documentation Categorizes issue or PR as related to documentation. area/api Indicates an issue on api area. labels Nov 3, 2014
@bgrant0607 bgrant0607 reopened this Nov 3, 2014
@bgrant0607 bgrant0607 added this to the v1.0 milestone Nov 3, 2014
@dchen1107
Copy link
Member

Are we sure about this is a WAI? I saw Travis failure with:

auth_test.go:377: case {PUT /api/v1beta1/replicationControllers/a 
    {
      "kind": "ReplicationController",
      "apiVersion": "v1beta1",
      "id": "a",
      "desiredState": {
        "replicas": 2,
        "replicaSelector": {"name": "a"},
        "podTemplate": {
          "desiredState": {
             "manifest": {
               "version": "v1beta1",
               "id": "a",
               "containers": [{
                 "name": "foo",
                 "image": "bar/foo",
               }]
             }
           },
           "labels": {"name": "a"}
          }},
      "labels": {"name": "a"}
    }
     map[409:true]}
auth_test.go:390: Expected status one of map[409:true], but got 202
auth_test.go:392: Body: {"kind":"Status","creationTimestamp":null,"apiVersion":"v1beta1","status":"Working","reason":"Working","details":{"id":"8","kind":"operation"}}

@bgrant0607 bgrant0607 self-assigned this Nov 6, 2014
@smarterclayton
Copy link
Contributor

That's a bad test case - the server returned while the operation was continuing (because we exceeded the default async threshold).

@Kaijun
Copy link

Kaijun commented Nov 23, 2017

Hi, all, I'm not sure if it's the right place to ask question.

While updating Deployment, the ResourceVersion is allowed to be empty, but while updating Service, ResourceVersion must be given. Is there any difference between the updating behaviors of these two resources?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/api Indicates an issue on api area. kind/documentation Categorizes issue or PR as related to documentation.
Projects
None yet
Development

No branches or pull requests

7 participants