From 0451894b48340ed8b916b0e51bdd9246416c1eb2 Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Tue, 7 Apr 2026 19:02:17 +1000 Subject: [PATCH] feat: add ceph service management profiles and facts (#459) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Adds `Unkin::Ceph::Utils` facter module detecting ceph service instances via `systemctl list-units`, exposing `is_ceph_mon`, `is_ceph_mgr`, `is_ceph_mds`, `is_ceph_osd` booleans and a `ceph_services` hash of unit names - Adds `profiles::ceph::mon`, `mgr`, `mds`, `osd` — each with `Boolean $ensure_running` that iterates discovered service instances and manages them as running and enabled - Works across incus nodes (mon/mgr/mds/osd) and k8s compute/control nodes (osd only); verified on prodnxsr0001 which correctly reports `is_ceph_osd: true` and `ceph_services: {osd: [ceph-osd@5]}` ## Test plan - [x] Noop deploy against prodnxsr0001.main.unkin.net passed cleanly - [x] `ceph_services` fact returns correct service map - [x] `is_ceph_osd` returns `True`, `is_ceph_mon` returns `False` as expected - [x] Test on an incus/ceph node with mon/mgr/mds services Reviewed-on: https://git.unkin.net/unkin/puppet-prod/pulls/459 --- hieradata/roles/infra/incus/node.yaml | 4 ++ hieradata/roles/infra/k8s.yaml | 1 + modules/libs/lib/facter/ceph_services.rb | 56 ++++++++++++++++++++++++ site/profiles/manifests/ceph/mds.pp | 13 ++++++ site/profiles/manifests/ceph/mgr.pp | 13 ++++++ site/profiles/manifests/ceph/mon.pp | 13 ++++++ site/profiles/manifests/ceph/osd.pp | 13 ++++++ 7 files changed, 113 insertions(+) create mode 100644 modules/libs/lib/facter/ceph_services.rb create mode 100644 site/profiles/manifests/ceph/mds.pp create mode 100644 site/profiles/manifests/ceph/mgr.pp create mode 100644 site/profiles/manifests/ceph/mon.pp create mode 100644 site/profiles/manifests/ceph/osd.pp diff --git a/hieradata/roles/infra/incus/node.yaml b/hieradata/roles/infra/incus/node.yaml index 1951163..cc68287 100644 --- a/hieradata/roles/infra/incus/node.yaml +++ b/hieradata/roles/infra/incus/node.yaml @@ -5,6 +5,10 @@ hiera_include: - incus - zfs - profiles::ceph::node + - profiles::ceph::mon + - profiles::ceph::mgr + - profiles::ceph::mds + - profiles::ceph::osd - profiles::ceph::client - profiles::ceph::dashboard - profiles::storage::cephfsvols diff --git a/hieradata/roles/infra/k8s.yaml b/hieradata/roles/infra/k8s.yaml index 3b55032..caa9c73 100644 --- a/hieradata/roles/infra/k8s.yaml +++ b/hieradata/roles/infra/k8s.yaml @@ -2,6 +2,7 @@ hiera_include: - profiles::selinux::setenforce - profiles::ceph::node + - profiles::ceph::osd - profiles::ceph::client - exporters::frr_exporter - frrouting diff --git a/modules/libs/lib/facter/ceph_services.rb b/modules/libs/lib/facter/ceph_services.rb new file mode 100644 index 0000000..b10607c --- /dev/null +++ b/modules/libs/lib/facter/ceph_services.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require 'facter' + +# Detects active ceph service instances via systemctl and exposes facts +# for use in ceph service management profiles. +# rubocop:disable Style/ClassAndModuleChildren +module Unkin + module Ceph + # Detects active ceph service instances via systemctl and exposes Facter facts. + module Utils + TYPES = %w[mon mgr mds osd].freeze + + def self.services + output = Facter::Core::Execution.execute( + 'systemctl list-units "ceph*" --no-legend --plain --all 2>/dev/null', + on_fail: '' + ) + parse_units(output) + end + + def self.parse_units(output) + result = TYPES.each_with_object({}) { |type, hash| hash[type] = [] } + output.each_line do |line| + unit = line.split.first + next unless unit + + match_unit(result, unit) + end + result + end + + def self.match_unit(result, unit) + TYPES.each do |type| + match = unit.match(/\Aceph-#{type}@(.+)\.service\z/) + result[type] << "ceph-#{type}@#{match[1]}" if match + end + end + + TYPES.each do |type| + define_singleton_method(:"#{type}?") { !services[type].empty? } + end + end + end +end +# rubocop:enable Style/ClassAndModuleChildren + +Facter.add('ceph_services') do + setcode { Unkin::Ceph::Utils.services } +end + +Unkin::Ceph::Utils::TYPES.each do |type| + Facter.add("is_ceph_#{type}") do + setcode { Unkin::Ceph::Utils.public_send(:"#{type}?") } + end +end diff --git a/site/profiles/manifests/ceph/mds.pp b/site/profiles/manifests/ceph/mds.pp new file mode 100644 index 0000000..1745c75 --- /dev/null +++ b/site/profiles/manifests/ceph/mds.pp @@ -0,0 +1,13 @@ +class profiles::ceph::mds ( + Boolean $ensure_running = true, +) { + + if $ensure_running and $facts['is_ceph_mds'] { + $facts['ceph_services']['mds'].each |String $svc| { + service { $svc: + ensure => running, + enable => true, + } + } + } +} diff --git a/site/profiles/manifests/ceph/mgr.pp b/site/profiles/manifests/ceph/mgr.pp new file mode 100644 index 0000000..34b3b4b --- /dev/null +++ b/site/profiles/manifests/ceph/mgr.pp @@ -0,0 +1,13 @@ +class profiles::ceph::mgr ( + Boolean $ensure_running = true, +) { + + if $ensure_running and $facts['is_ceph_mgr'] { + $facts['ceph_services']['mgr'].each |String $svc| { + service { $svc: + ensure => running, + enable => true, + } + } + } +} diff --git a/site/profiles/manifests/ceph/mon.pp b/site/profiles/manifests/ceph/mon.pp new file mode 100644 index 0000000..9be1864 --- /dev/null +++ b/site/profiles/manifests/ceph/mon.pp @@ -0,0 +1,13 @@ +class profiles::ceph::mon ( + Boolean $ensure_running = true, +) { + + if $ensure_running and $facts['is_ceph_mon'] { + $facts['ceph_services']['mon'].each |String $svc| { + service { $svc: + ensure => running, + enable => true, + } + } + } +} diff --git a/site/profiles/manifests/ceph/osd.pp b/site/profiles/manifests/ceph/osd.pp new file mode 100644 index 0000000..d56ff1d --- /dev/null +++ b/site/profiles/manifests/ceph/osd.pp @@ -0,0 +1,13 @@ +class profiles::ceph::osd ( + Boolean $ensure_running = true, +) { + + if $ensure_running and $facts['is_ceph_osd'] { + $facts['ceph_services']['osd'].each |String $svc| { + service { $svc: + ensure => running, + enable => true, + } + } + } +}