puppetpuppet-enterprise

Triggering dependent resources in a interation loop


I'm using Puppet to set up workstations and I want to modify the default (NTUSER.DAT) HKLM registry before the user logs on, which involves loading and unloading the hive. I have written some PowerShell scripts to facilitate the load/unload. Although I have three distinct actions, it appears that Puppet is trying to unload the hive before the registry module can make all the changes. I believe I need to add some dependencies using subscribe and refreshonly.

This question is very similar to this one, with the exception that my data is in Hiera, therefore I want to iterate over the data.

$temp_hive_name = $base_windows::temp_hive_name

# LOAD REGISTRY HIVE
exec { 'load_registry_hive' :
  command   => template('base_windows/Load-RegHive.ps1.erb'),
  unless    => template('base_windows/Test-HiveLoadState.ps1.erb'),
  provider  => powershell,
  logoutput => true,
}

# MODIFY REGISTRY, ITERATING OVER HIERA DATA
$base_windows::registry.each | $key, $value | {
  registry::value { "registry_${key}" :
    key   => "${value['key']}\\${temp_hive_name}\\${value['subkey']}",
    type  => $value['type'],
    data  => $value['data'],
    value => $value['value'],
  }
}

# UNLOAD REGISTRY HIVE
exec { 'unload_registry_hive' :
  command   => template('base_windows/Unload-RegHive.ps1.erb'),
  onlyif    => template('base_windows/Test-HiveLoadState.ps1.erb'),
  provider  => powershell,
  logoutput => true,
}

This works fine when there are one or two Hiera entries.

I guess I could put the load / unload exec resources into an .each loop and add subscribe and refreshonly, however, it seems rather inefficient to do that for each item.

If anyone has any ideas, I'd be grateful if you could share?

T.I.A.


Solution

  • I believe I need to add some dependencies using subscribe and refreshonly.

    I'm not so sure that you need to add dependencies, because without explicit dependencies, resources should be applied in the relative order in which they appear in the manifest. Additionally, refreshonly does not declare a dependency, and subscribe is probably not appropriate for this particular task. Furthermore, although refreshonly works in conjunction with dependencies, it's probably not appropriate for this task, either, because notify / subscribe is not right for it.

    In a general sense, the key issues are these:

    You cannot make Exec['load_registry_hive'] refreshonly because there is no resource that would signal it. You can, however, check whether $base_windows::registry has any elements as a precondition for doing any of the work. If it does, then you definitely need to load the hive.

    You can set up explicit dependencies, and I'm generally inclined to do that, as it protects against surprises when a resource is affected by dependency edges that are not apparent at the point of its declaration. So I would suggest this:

    $temp_hive_name = $base_windows::temp_hive_name
    
    if ! $base_windows::registry.empty() {
      # LOAD REGISTRY HIVE
      exec { 'load_registry_hive' :
        command   => template('base_windows/Load-RegHive.ps1.erb'),
        unless    => template('base_windows/Test-HiveLoadState.ps1.erb'),
        provider  => powershell,
        logoutput => true,
      }
    
      # MODIFY REGISTRY, ITERATING OVER HIERA DATA
      $base_windows::registry.each | $key, $value | {
        registry::value { "registry_${key}" :
          key     => "${value['key']}\\${temp_hive_name}\\${value['subkey']}",
          type    => $value['type'],
          data    => $value['data'],
          value   => $value['value'],
          require => Exec['load_registry_hive'],
          before  => Exec['unload_registry_hive'],
        }
      }
    
      # UNLOAD REGISTRY HIVE
      exec { 'unload_registry_hive' :
        command   => template('base_windows/Unload-RegHive.ps1.erb'),
        onlyif    => template('base_windows/Test-HiveLoadState.ps1.erb'),
        provider  => powershell,
        logoutput => true,
      }
    }
    

    Note that you will necessarily both load and unload the hive on each Puppet run, because you cannot determine whether any entries need to be updated without doing so.