after the introduction of Debian to our infrastructure as an OS for hardware as well as for VM's in our Ganeti environment, I am trying now to deploy apt sources lists for Debian hosts by using a local hiera.yaml file within the module it self.

We are deploying the apt sources lists for Ubuntu as well as our local repo with a dedicated module as a wrapper for puppetlabs/apt module. The global hiera.yaml on puppet server looks as follows:

---
version: 5
defaults:
  datadir: data
  data_hash: yaml_data
hierarchy:
  - name: "module scope"
    paths:
      - "%{facts.fqdn}.yaml"
      - "%{facts.context}-%{facts.location}-%{facts.hostgroup}.yaml"
      - "%{facts.context}-%{facts.datacenter}-%{facts.hostgroup}.yaml"
      - "%{facts.context}-%{facts.hostgroup}.yaml"
      - "%{facts.context}-%{facts.location}.yaml"
      - "%{facts.context}-%{facts.datacenter}.yaml"
      - "%{facts.context}.yaml"
      - common.yaml
    datadir: "/etc/puppetlabs/code/environments/%{environment}/modules/%{module_name}/data"

In the apt_sources module the common.yaml contains the apt key of our repo. The %{facts.context}.yaml contains all Ubuntu and our repo sources lists, which is sufficient in moste cases, thus for some host groups we need some external repos, such as mysql, percona, ceph etc.. and these sources are included in the respective yaml file, either in a %{facts.context}-%{facts.hostgroup}.yaml or on of the other yaml files and at the end we just merge the hashes in %{facts.context}.yaml and in the other relevant yaml files. Now with Debian things are getting a bit more complex, I had to restructure the data directory in our apt_sources module so Debian sources lists are separated from Ubuntu sources lists as follows:

apt_sources$ tree -L 1 data/
data/
├── common.yaml
├── Debian
└── Ubuntu

2 directories, 1 file
apt_sources$ 

and I created a local hiera.yaml file with the following content:

---
version: 5
defaults:
  datadir: data
  data_hash: yaml_data
hierarchy:
  - name: "module scope"
    paths:
      - "%{facts.operatingsystem}/%{facts.fqdn}.yaml"
      - "%{facts.operatingsystem}/%{facts.context}-%{facts.location}-%{facts.hostgroup}.yaml"
      - "%{facts.operatingsystem}/%{facts.context}-%{facts.datacenter}-%{facts.hostgroup}.yaml"
      - "%{facts.operatingsystem}/%{facts.context}-%{facts.hostgroup}.yaml"
      - "%{facts.operatingsystem}/%{facts.context}-%{facts.location}.yaml"
      - "%{facts.operatingsystem}/%{facts.context}-%{facts.datacenter}.yaml"
      - "%{facts.operatingsystem}/%{facts.context}.yaml"
      - common.yaml
    datadir: "/etc/puppetlabs/code/environments/%{environment}/modules/%{module_name}/data"

The relevant part of our init.pp wich has to stay puppet 3 compatible due compatibility to some QA infrastructure:

#
class apt_sources (
  Hash $gnupg_key     = {},
  Hash $pin           = {},
  $proxy              = {},
  $purge_sources      = false,
  Hash $settings      = {},
  Hash $sources       = {},
  ) {

  class { 'apt':
    update => {
      frequency => 'daily',
    },
    purge  => {
      'sources.list'   => $purge_sources,
      'sources.list.d' => $purge_sources,
    },
  }

  create_resources('apt::source', hiera_hash('apt_sources::sources', $sources))
  create_resources('apt::setting', hiera_hash('apt_sources::settings', $settings))
  create_resources('apt::key', hiera_hash('apt_sources::gnupg_key', $gnupg_key))
  create_resources('apt::pin', hiera_hash('apt_sources::pin', $pin))

  Apt::Pin <| |> -> Apt::Source <| |> -> Apt::Ppa <| |> -> Exec['apt_update'] -> Package <| |>
}

Now when deploying the apt_sources for a host with an additional %{facts.context}-%{facts.hostgroup}.yaml file, the sources lists are not getting merged, rather only the more specific yaml file wins, in this case the %{facts.context}-%{facts.hostgroup}.yaml file, so the main repos in %{facts.context}.yaml are not deployed. In puppetserver I can see in the logfile how Puppet looks up for the keys using the global hiera.yaml and then the local hiera.yaml but only for the first hash, then there is this line:

Hiera configuration recreated due to change of scope variables used in interpolation expressions

and Puppet keeps looking for the other keys, but this time using only the global hiera.yaml configuration and skips the local one so Puppet cannot find any hash and using the default {} value.

Unfortunately I cannot replace hiear_hash with lookup function for the moment due Puppet 3 compatibility.

EDIT

Originally with only Ubuntu as OS I had all hiera data in the directory data/ and the init.pp looked like this:

#
class apt_sources (
  $proxy         = {},
  $purge_sources = false,
  $merge_sources = true,
  ) {

  class { 'apt':
    update => {
      frequency => 'daily',
    },
    purge  => {
      'sources.list'   => $purge_sources,
      'sources.list.d' => $purge_sources,
    },
  }

  if $merge_sources {
    $sources = hiera_hash('apt_sources::sources', {})
    create_resources('apt::source', $sources)
  }
  else {
    $sources = hiera('apt_sources::sources')
    create_resources('apt::source', $sources)
  }

  $settings = hiera_hash('apt_sources::settings', {})
  create_resources('apt::setting', $settings)

  $gnupg_key = hiera_hash('apt_sources::gnupg_key', {})
  create_resources('apt::key', $gnupg_key)

  $pin = hiera_hash('apt_sources::pin', {})
  create_resources('apt::pin', $pin)

  Apt::Pin <| |> -> Apt::Source <| |> -> Apt::Ppa <| |> -> Exec['apt_update'] -> Package <| |>
}

Maybe someone can explain this behavior.

Thank you for your help.

1 Answers

2
Max On

I fixed it by adding the following to the common.yaml:

lookup_options:
  apt_sources::sources:
    merge:
      strategy: deep

further more I changed the create_resources statements as follows:

create_resources('apt::source', $sources)
create_resources('apt::setting', $settings)
create_resources('apt::key', $gnupg_key)
create_resources('apt::pin', $pin)