| Puppet Version: 6.15.0 Puppet Server Version: – OS Name/Version: macOS 10.15 Describe your issue in as much detail as possible… When applying manifest blocks, Bolt uses ToDataConverter to serialize plan variables, which can include Target objects. Bolt sets local_reference:true for ToDataConverter, as Target objects have references to objects that in turn have references to the Target object, causing endless recursion. https://github.com/puppetlabs/bolt/blob/master/lib/bolt/applicator.rb#L182-L186 Later in execution, the serialized data is passed to FromDataConverter, which begins to deserialize the plan variables, including the Target objects. https://github.com/puppetlabs/bolt/blob/master/lib/bolt/catalog.rb#L75 During deserialization, any targets that share identical config and are set as plan variables will cause Puppet to raise an error due to an attempt to access a deserialized Target object's config via the bracket [] operator. For example, given the following inventory where targets share identical configuration:
targets: |
- name: targetA |
config: |
ssh: |
run-as: root |
host-key-check: false |
tty: true |
- name: targetB |
config: |
ssh: |
run-as: root |
host-key-check: false |
tty: true |
ToDataConverter will serialize these targets such that target B will have a local reference to target A's configuration:
... |
"targetA"=> |
[{"__ptype"=>"Target", |
"name"=>"targetA", |
"config"=> { |
"transport"=>"ssh", |
"ssh"=> { |
"run-as" => "root", |
"host-key-check" => false, |
"tty" => true |
} |
} |
}], |
"targetB"=> |
[{"__ptype"=>"Target", |
"name"=>"targetB", |
"config"=>{ |
"transport"=>"ssh", |
"ssh"=>{ |
"__ptype"=>"LocalRef", |
"__pvalue"=>"$['targetA'][0]['config']['ssh']" |
} |
} |
}], |
...
|
However, during deserialization, the data hash for targetA will be replaced with the deserialized Bolt::ApplyTarget object. When targetB is deserialized, the local reference for the configuration will then be resolved such that $['targetA'][0] returns the Bolt::ApplyTarget object, and then attempts to access the configuration with ['config']['ssh']. This raises an exception, as the Bolt::ApplyTarget object does not define the [] method. Describe steps to reproduce… **Create an inventory with multiple targets that share identical configuration:
# Boltdir/inventory.yaml |
targets: |
- uri: <URI> |
name: targetA |
config: |
transport: ssh |
ssh: |
host-key-check: false |
connect-timeout: 100 |
- uri: <URI> |
name: targetB |
config: |
transport: ssh |
ssh: |
host-key-check: false |
connect-timeout: 100
|
Create a plan that sets these targets as plan variables and then has an apply block:
plan bolt ( |
TargetSpec $targets |
) { |
$targetA = get_targets('targetA') |
$targetB = get_targets('targetB') |
|
$targetA.apply_prep |
|
apply($targetA) { |
notice('') |
} |
} |
Run the plan
$ bolt plan run bolt -t all
|
**The plan will fail with the following error:
Failed on targetA: |
Apply failed to compile for targetA: undefined method `[]' for #<Bolt::ApplyTarget:0x00007fc769ae5258> on node targetA |
Failed on 1 target: targetA
|
Additional Context: ToDataConverter will only create local references for identical configuration when a plan variable has an array of targets. If all plan variables are singular targets, ToDataConverter will not create local references for identical configuration. I've attached the catalog input that contains the serialized plan variables for reference. Target B has a local reference to Target A's configuration: repo.json **The related Bolt issue can be found here: https://github.com/puppetlabs/bolt/issues/1836 Desired Behavior: **FromDataConverter should not attempt to access referenced values from a deserialized object. Actual Behavior: FromDataConverter attempts to access referenced values from a deserialized object. See above. |