Chef: Creating an already existing node should fail?

Created on 18 May 2015  Â·  5Comments  Â·  Source: chef/chef

Hi!

At least on Chef 11.x, when I tried to create a new node with knife and it already existed, knife would return an error like this:

$ knife node create testing.localdomain --disable-editing
ERROR: Conflict
Response: Node already exists

This also can happen if I try to create the node at the same time. I think it's the expected behavior.

But since Chef 12 (tested up to 12.0.8), no matter how many times or if a node already exists, knife will return OK:

$ knife node create testing.localdomain --disable-editing
Created node[testing.localdomain]

Turning on the DEBUG, I can see that:

# creating a node at the same time, with conflict
DEBUG: HTTP 1.1 409 Conflict
INFO: HTTP Request Returned 409 Conflict: Node already exists
/usr/share/ruby/net/http/response.rb:119:in `error!': 409 "Conflict" (Net::HTTPServerException)
...

# creating a node at the same time, wiithout conflict
DEBUG: HTTP 1.1 201 Created

# creating a node that already exists, several seconds later+
DEBUG: HTTP 1.1 200 OK 

Isn't the correct behavior to return 409 Conflict instead of HTTP 200?

My use explanation:

I'm using this to automatically name servers based on the last known server number, so I can create on-demand servers for autoscaling purposes. I'm using "knife node create" to reserve the name before renaming hostname, executing chef, and so on.

When server returns HTTP 200 to knife, the node thinks he reserved its name and creates a race condition when multiple servers are ran at the same time: two nodes reserve the same name, but only one will use it.

Medium Sustaining Backlog Bug

All 5 comments

This is also the case when using chef-zero, e.g.

knife node create existing.node -z

and also the same with data bags…

I've tracked this down for someone to come along and fix if there is a solution that will work for everyone. I believe this has been the behavior for a long time, but I cannot confirm.

knife node create executes the following code:

node = Chef::Node.new
node.name(@node_name)
create_object(node)

#create_object comes from chef/knife.rb and executes the following:

output = edit_data(object)

if Kernel.block_given?
  output = block.call(output)
else
  output.save
end

#edit_data comes from chef/knife/core/ui.rb and returns the Chef object in question, in this case, a Chef::Node object. Chef::Node#save first attempts to update a node via PUT. If that fails, then a POST call is issued. Here's the code:

def save
  # Try PUT. If the node doesn't yet exist, PUT will return 404,
  # so then POST to create.
  begin
    if Chef::Config[:why_run]
      Chef::Log.warn("In whyrun mode, so NOT performing node save.")
    else
      chef_server_rest.put_rest("nodes/#{name}", data_for_save)
    end
  rescue Net::HTTPServerException => e
    raise e unless e.response.code == "404"
    chef_server_rest.post_rest("nodes", data_for_save)
  end
  self
end

I don't know if there are historical reasons why we don't just call Chef::Node#create here instead.

So Chef::Node#save is correct we always want node.save to have create_or_update semantics.

Either #edit_data needs to be changed or something else higher up this call stack should get changed.

So also I think this is a legit bug:

  1. People would rationally expect that 'create' followed CRUD semantics and would not nuke an existing node
  2. People could get into trouble by typo'ing a node name and then this would wipe out an existing node and its data, when they meant to create a different one.
  3. We don't do anything to prompt "hey, it looks like you're trying to overwrite an existing node, are you sure?" which would make this UX better if we wanted to go that way.

I am with the same issue!
Anyone have some idea about when this will be on focus?

For me, this is more then a "Low Priority" bug because Chef + Autoscaling doesn't works how it is expected.

Was this page helpful?
0 / 5 - 0 ratings