chef-boneyard / chef-provisioning-vsphere

DEPRECATED: A chef-provisioning provisioner for VMware vSphere
MIT License
17 stars 15 forks source link

machine_execute and machine_file fails with undefined method `[]' for nil:NilClass #94

Open Ryuzavi opened 5 years ago

Ryuzavi commented 5 years ago

Versions:

Platform Details

Scenario:

When trying to run either the machine_execute or machine_file resources on vsphere they both fail with the generic error undefined method[]' for nil:NilClass`

Steps to Reproduce:

Set up Chef Provisioning vSphere as normal and try to execute the machine_execute or machine_file resource, e.g.

machine_execute 'hostname' do
  machine 'test'
  live_stream true
end

Expected Result:

For the command to be run successfully on the box or the action performed on the file.

Actual Result:

Generic undefined method[]' for nil:NilClass` error suggesting an attribute somewhere isn't being set correctly

    ================================================================================
    Error executing action `run` on resource 'machine_execute[hostname]'
    ================================================================================

    NoMethodError
    -------------
    undefined method `[]' for nil:NilClass

    Resource Declaration:
    ---------------------
    # In /root/.chef/local-mode-cache/cache/cookbooks/test/recipes/build.rb

     33:   machine_execute 'hostname' do
     34:     machine 'test'
     35:     live_stream true
     36:   end
     37: 

    Compiled Resource:
    ------------------
    # Declared in /root/.chef/local-mode-cache/cache/cookbooks/test/recipes/build.rb:33:in `from_file'

    machine_execute("hostname") do
      action [:run]
      default_guard_interpreter :default
      chef_server {:chef_server_url=>"chefzero://localhost:8889", :options=>{:client_name=>"****", :signing_key_filename=>nil, :api_version=>"0"}}
      declared_type :machine_execute
      cookbook_name "test"
      recipe_name "build"
      machine "test"
      live_stream true
      command "hostname"
    end

    System Info:
    ------------
    chef_version=14.7.17
    platform=ubuntu
    platform_version=18.04
    ruby=ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux]
    program_name=/opt/chefdk/bin/chef-client
jjlimepoint commented 5 years ago

Can reproduce - issue seems to be machine_for is referencing machine_options[:bootstrap_options][:ssh] but bootstrap optionsa re not coming through :(

EDIT: whereas other drivers put the entire bootstrap options in machine_spec.reference, and use that, c-p-vsphere does not, and relies on "what is passed in" - so this can never have worked :).

jjlimepoint commented 5 years ago

Hilariously, you can work around this by putting a machine_options in your client.rb file that you use - it will merge this with the exsting config. This is obviously not ideal, but will get you running - so mine looks like this:

machine_options Hash({ :bootstrap_options => { :ssh => { :user => root, :password => 'redacted' }}})

The correct fix would be to hook up the correct hookups between these to pass in the machine_options from the resource, of course - chef-provisioning assumes that's all been persisted to machine_spec.reference, which goes into node attributes. but we probably don't want to store them in the node attributes, since they can contain passwords - which means hooking up something else to keep track of it during the run.... I played the whole "lookup the resource" game, which did kind of work for getting the machine options out, but again this is not the worlds simplest patch(tm) (for one, you can't just grab resource(machine[name]), due to machine_batch).

Indeed, the code is literally:

      machine_options = { :convergence_options => { :chef_server => chef_server } }
      machine_options = Cheffish::MergedConfig.new(config[:machine_options], machine_options) if config[:machine_options]
      driver.connect_to_machine(machine_spec, machine_options)

you'll note the lack of any refernce to our actual machine, or the contents of machien spec - which means it is always going to break unless the driver is keeping track internally of the credentials. whee! The right thing to do, would be for chef-provisioning to take that machine object as an input, and merge in the machine_options from the machine object, of course.

Ryuzavi commented 5 years ago

Interesting stuff indeed. I thought it might be something fundamental like that. Shame it doesn't appear to be straightforward to fix. I'll certainly give that client.rb workaround a try for now. I wonder how other drivers are handling this, like AWS?

jjlimepoint commented 5 years ago

AWS handles this by fundamentally being a much more complicated driver, and hence keeping track internally of what it did - my first impulse was/is to modify the vsphere drive to do the same, but I'm not inclined to add that level of complexity - I did get a quick fix working for machine rather than machine_batch by modifying chef-provisioning itself to go and fetch the machine_options from machine when looking them up, which appears to be how it was always "intended" to work for simpler drivers - but there is a bit of complexity around machine_batch that i haven't had a chance to look at yet (right now, i'm just using net::ssh in my own code here, but honsetly, i'm keen to cut that out!)