Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cyclic dependency error when using systemd::unit_file in multiple classes #178

Closed
tuxmea opened this issue Feb 18, 2021 · 3 comments
Closed

Comments

@tuxmea
Copy link
Member

tuxmea commented Feb 18, 2021

Using systemd::unit_file in multiple, strictly ordered classes, causes a cyclic dependency error.

Consider the following code:

  1. Role:
class role::base {
  contain profile::systemd
  contain profile::base_os
  contain profile::monitoring

  Class['profile::systemd']
  -> Class['profile::base_os']
  -> Class['profile::monitoring']
}
  1. Profiles
    2.1. profile::systemd
class profile::systemd {
  class { 'systemd':
    manage_resolved => false,
    manage_networkd => false,
  }
}

2.2. profie::base_os

class profile::base_os {
  systemd::unit_file { 'remove_check_mk_cache.service':
    content => file('profile/remove_checkmk_cache.service'),
    active  => true,
    notify  => Service['remove_check_mk_cache'],
  }
  service { 'remove_check_mk_cache':
    ensure => running,
    enable => true,
    require => Class['systemd::systemctl::daemon_reload'],
  }
}

2.3. profile::monitoring

class profile::monitoring {
  systemd::unit_file { 'send_downtime.service':
    content => file('profile/send_downtime.service'),
    active  => true,
    notify  => Service['send_downtime'],
  }
  service { 'send_downtime':
    ensure => running,
    enable => true,
    require => Class['systemd::systemctl::daemon_reload'],
  }
}

Unit tests or using this code on a system produce cyclic dependency error:

role::base on centos-7-x86_64 is expected to compile into a catalogue without dependency cycles
     Failure/Error: it { is_expected.to compile }
       dependency cycles found: (Exec[systemctl-daemon-reload] => Class[Systemd::Systemctl::Daemon_reload] => Service[remove_check_mk_cache] => Class[Profile::Base_os] => Class[Profile::Monitoring] => Systemd::Unit_file[send_downtime.service] => File[/etc/systemd/system/send_downtime.service] => Class[Systemd::Systemctl::Daemon_reload] => Exec[systemctl-daemon-reload])
     # ./spec/classes/base_spec.rb:10:in `block (4 levels) in <top (required)>'
@bastelfreak
Copy link
Member

Hi!
I thought a bit about this. If you set active to true on the systemd::unit_file defined resources, it creates the service resource for you:
https://github.com/camptocamp/puppet-systemd/blob/8f68b0dcf3bbbafc60c025879a28004fc9815aab/manifests/unit_file.pp#L91-L98

You basically define the service twice, once in your profile and once via the defined resource. This works by accident because the defined resource references the service with send_downtime.service and the profile with send_downtime. This means that you could shorten the profiles:

class profile::monitoring {
  systemd::unit_file { 'send_downtime.service':
    content => file('profile/send_downtime.service'),
    active  => true,
    enable => true,
  }
}

class profile::base_os {
  systemd::unit_file { 'remove_check_mk_cache.service':
    content => file('profile/remove_checkmk_cache.service'),
    active  => true,
    enable => true,
  }
}

While this is shorter, it indeed creates the dependency loop you mentioned. On a few of my profiles I workaround this by not ordering the profiles like you did in your role. I set explicit dependencies in my profile to resources to the other profiles. In your case that would mean:

class profile::monitoring {
  systemd::unit_file { 'send_downtime.service':
    content => file('profile/send_downtime.service'),
    active  => true,
    enable => true,
  }
  Service['remove_check_mk_cache.service'] -> Service['send_downtime.service']
}

class profile::base_os {
  systemd::unit_file { 'remove_check_mk_cache.service':
    content => file('profile/remove_checkmk_cache.service'),
    active  => true,
    enable => true,
  }
}

But I understand that ordering profiles in a role is a common pattern and I do that myself alot as well. In that case just remove the active => true, line from your two systemd::unit_file and all works as well.

@tuxmea
Copy link
Member Author

tuxmea commented Feb 19, 2021

Fix is available in #171

@ekohl
Copy link
Member

ekohl commented Mar 2, 2021

#171 has been merged so I think this can be closed now.

@tuxmea tuxmea closed this as completed Mar 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants