[PUP-3732] type validation should not run for `puppet resource` Created: 2014/12/03  Updated: 2018/11/30

Status: Accepted
Project: Puppet
Component/s: Types and Providers
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Normal
Reporter: Hunter (Hunner) Haugen Assignee: Unassigned
Resolution: Unresolved Votes: 4
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Template:
Team: Coremunity

 Description   

tl;dr: puppet resource creates resource types without attributes, which causes the type's global validate block to fail. It should initialize the type with values from the provider so that it can be validated.

Puppet types can have per-parameter or per-property validate blocks, but can also have a global validate block.

Oddly, when running puppet resource <whatever> the per-attribute validates are not called (as no attributes are passed), but the global validate is. Validation is usually done on the resource coming from the catalog, which is self in the context of the global validate. When using puppet resource there is no true catalog per-say, but if no arguments are passed then the resource types @parameter hash is not initialized and thus validation will fail.

If the @parameter hash was merged with the values from self.provider's @property_hash then the global validation block would still be validating any values that were passed on the command-line, or just the values returned by self.instances if there are no arguments.

This *should* still work for normal catalog application, as a resource returned by self.instances and thus passing global validation is already configured correctly.



 Comments   
Comment by Ben Roberts [ 2016/10/13 ]

Having just lost about 6 hours to debugging this exact same issue, issue still present in 4.7.0.

Comment by Josh Cooper [ 2017/05/15 ]

Hunter (Hunner) Haugen, Ben Roberts Agree this is a problem, can you provide examples of where you've run into this?

Comment by Bernhard Frauendienst [ 2017/06/19 ]

This should still work for normal catalog application, as a resource returned by self.instances and thus passing global validation is already configured correctly.

Are you sure about this? I've encountered the same issue with resources created by self.instances when trying to purge them with resources.

I tried to follow the code, the resources are created in self.instances @ type.rb#L1174 with just a name and a provider, and are then validated in initialize @ type.rb#L2398. I can't see where the values from the provider would be set inbetween, and given that the validation fails, this does not seem to be the case.
Then again, I'm very new to the Ruby language. Am I missing something here?

I've checked most built-in types, and none of them have a global validate block that would not work if the values are not set. That would explain why this never was reported with a built-in type.

Comment by Taylan Develioglu [ 2017/06/19 ]

Just wanted to chime in that you can guard against this behavior by checking if the resource is managed. e.g.:

  validate do
    if managed?
      unless self[:value]
        raise ArgumentError, 'Value must be set'
      end
    end
  end

Comment by Bernhard Frauendienst [ 2017/06/19 ]

Taylan Develioglu thanks, that's good to know! However, in my case, even for unmanaged resources that validated invariant always holds true, so guarding for managed resources would just be working around implementation details.

Comment by Bernhard Frauendienst [ 2017/06/19 ]

Taylan Develioglu, it turns out that checking for managed? does not help (at least not in all cases), because even for managed resources the above situation occurs, where the resource is created but validation is called before properties are set. However, the resources is already marked as managed.

Comment by Hunter (Hunner) Haugen [ 2017/06/19 ]

Josh Cooper I see occurrences of this at least in the F5, netapp, and Azure modules, if you want code examples. Otherwise specific scenarios may not help as it's a "gotcha" any time I'm coding any global validate block (and especially having to make "required" parameters since there is no way to make required parameters for puppet types otherwise). Eg:

validate do
  raise ArgumentError, "Passing value or othervalue is required" if ! self[:value] and ! self[:othervalue]
end

Comment by William Yardley [ 2017/10/14 ]

I believe these describe a similar issue as well:
https://github.com/voxpupuli/puppet-rabbitmq/issues/147
https://github.com/voxpupuli/puppet-rabbitmq/pull/651
Having a validate block in the type causes puppet resource foo to fail

In those cases, moving validation to #create in the provider seems to work as a workaround, but is not ideal.

Generated at Sat May 25 22:32:54 PDT 2019 using JIRA 7.7.1#77002-sha1:e75ca93d5574d9409c0630b81c894d9065296414.