kontena / k8s-client

Ruby Kubernetes API client
Apache License 2.0
76 stars 26 forks source link

client.update_resource(some_service_resource) fails with missing resourceVersion and empty clusterIP #37

Closed d11wtq closed 6 years ago

d11wtq commented 6 years ago

I'm trying to do the following (should essentially be a no-op, equivalent to kubectl apply with unchanged resources):

resources = K8s::Resource.from_files('/path/to/manifests')
resources.each do |resource|
  begin
    client.update_resource(resource)
  rescue K8s::Error::NotFound
    client.create_resource(resource)
  end
end

Which produces an error because resourceVersion and clusterIP seem to be sent as empty strings to the server.

/Users/d11wtq/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/k8s-client-0.3.4/lib/k8s/transport.rb:192:in `parse_response': PUT /api/v1/namespaces/projectname/services/api => HTTP 422 Unprocessable Entity: Service "api" is invalid: [metadata.resourceVersion: Invalid value: "": must be specified for an update, spec.clusterIP: Invalid value: "": field is immutable] (K8s::Error::Invalid)
        from /Users/d11wtq/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/k8s-client-0.3.4/lib/k8s/transport.rb:210:in `request'
        from /Users/d11wtq/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/k8s-client-0.3.4/lib/k8s/resource_client.rb:218:in `update_resource'
        from /Users/d11wtq/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/k8s-client-0.3.4/lib/k8s/client.rb:164:in `update_resource'
        from test.rb:41:in `block in <main>'
        from test.rb:32:in `each'
        from test.rb:32:in `<main>'

There are two resources in the list: Deployment and Service (NodePort). Both were originally created with kubectl apply. The deployment seems to be update fine, but the service always blows up on the error above. I'm not sure if this is expected, or if I'm supposed to change the spec in some way once I've read the manifests off disk.

Is this the correct way to do something along the lines of kubectl apply? Happy with anything that more or less performs an upsert style operation for the resource.

Here is the entire manifest, if it helps:

---
apiVersion: v1
kind: Service
metadata:
  namespace: projectname
  name: api
  labels:
    app: projectname
    service: api
spec:
  type: NodePort
  selector:
    app: projectname
    service: api
  ports:
    - name: http
      port: 8082
      protocol: TCP
d11wtq commented 6 years ago

Apologies. Figured out that the way to do this is:

resources = K8s::Resource.from_files('/path/to/manifests')
resources.each do |resource|
  server_resource = begin
    client.get_resource(resource)
  rescue K8s::Error::NotFound
    client.create_resource(resource)
  end

  client.update_resource(server_resource)
end