From 518fa4c1c80b8a030bd1e62b86933b6159efee63 Mon Sep 17 00:00:00 2001
From: "A. Karl Kornel" <akkornel@stanford.edu>
Date: Wed, 17 Aug 2016 14:48:33 -0700
Subject: [PATCH] =?UTF-8?q?ipmi:=20Pull=20in=20Karl=E2=80=99s=20changes=20?=
 =?UTF-8?q?from=20base=20dev?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 manifests/ipmi.pp                      | 354 ++++++++++++++++++-------
 templates/ipmi/etc/default/ipmievd.erb |   2 +-
 2 files changed, 254 insertions(+), 102 deletions(-)

diff --git a/manifests/ipmi.pp b/manifests/ipmi.pp
index 498425d..ef89459 100644
--- a/manifests/ipmi.pp
+++ b/manifests/ipmi.pp
@@ -1,119 +1,271 @@
-# base::ipmi and base::noipmi
+# base::ipmi: ipmi classes to load, and suppress loading, IPMI client & server.
 #
-# ipmi classes to load, and suppress loading, ipmi client modules.
-# Loading of ipmi is automatically suppressed on VMware platforms.
+# Most of the time, you should use it like this:
+#
+# include base::ipmi
+#
+# That will enable IPMI for physical systems, and will disable IPMI for virtual
+# systems (including EC2 systems).  This cannot be overridden.
+#
+# If you want to disable IPMI (for example, on workstations), use it like this:
+#
+# class { 'base::ipmi':
+#   ensure => absent,
+# }
+#
+# WARNING: On a running system, changing base::ipmi::ensure from present to 
+# absent may not work properly, depending on what user-space stuff is using 
+# IPMI functionality.  If you get errors, restart.
 
-class base::ipmi {
+class base::ipmi (
+  $ensure = present,
+) {
 
-  # disable ipmi and ipmievd on vmware (or others). facter string comparison
+  # If we are virtual or on EC2, then explicitly disable IPMI
   if $::is_virtual == 'true' or $::ec2_profile == 'default-paravirtual' {
-    case $::operatingsystem {
-      'debian', 'ubuntu': {
-        package { 'ipmitool': ensure => purged }
-      }
-      'redhat': {
-        service { 'ipmi':
-          ensure  => stopped,
-          enable  => false,
-        }
-      }
-      default: {}
-    }
-  } else {
-    case $::osfamily {
-      'Debian': {
-        package { 'ipmitool':
-          ensure => present;
-        }
-        if ($::kernelmajversion >= '3.13') {
-          # no msghandler module on kernels > 3.13
-          base::os::kernel_module { 'ipmi_si':
-            ensure  => present,
-          }
-        }
-        else {
-          base::os::kernel_module { 'ipmi_msghandler':
+    $real_ensure = absent
+  }
+  else {
+    $real_ensure = $ensure
+  }
+
+  # Check to see what we should do
+  case $real_ensure {
+    'present': {
+      case $::osfamily {
+        'Debian': {
+
+          # First, install the ipmitool package
+          package { 'ipmitool':
             ensure => present;
           }
-          base::os::kernel_module { 'ipmi_si':
-            ensure  => present,
-            require => Base::Os::Kernel_module['ipmi_msghandler'];
+
+          # Next, install the config file
+          file { '/etc/default/ipmievd':
+            content => template('base/ipmi/etc/default/ipmievd.erb'),
+            require => Package['ipmitool'],
           }
-        }
-        base::os::kernel_module { 'ipmi_devintf':
-          ensure  => present,
-          require => Base::Os::Kernel_module['ipmi_si'];
-        }
-        service { 'ipmievd':
-          ensure      => running,
-          name        => 'ipmievd',
-          enable      => true,
-          hasstatus   => false,
-          status      => 'pidof ipmievd',
-          require     => [Base::Os::Kernel_module['ipmi_devintf'],
-                          File['/etc/default/ipmievd']
-                          ],
-        }
-        file { '/etc/default/ipmievd':
-          content => template('base/ipmi/etc/default/ipmievd.erb'),
-          notify  => Service['ipmievd'],
-        }
-      }
-      'RedHat': {
-        case $::lsbmajdistrelease {
-          '6', '7': {
-            package { 'OpenIPMI':   ensure => present; }
-          }
-          default: {
-            package {
-              'OpenIPMI-tools':   ensure => present;
-              'OpenIPMI':         ensure => present;
+
+          # Next, install kernel modules
+          # For Debian 8+, the package brings in everything it needs by
+          # default.  But, if we are re-enabling we need to recover a file that
+          # we deleted.  We then have to trigger systemd to load modules.
+          if $::operatingsystem == 'Debian' and $::lsbmajdistrelease >= 8 {
+            exec { 'Re-create /usr/lib/modules-load.d/ipmievd.conf':
+              command => '/usr/bin/apt-get install --reinstall ipmitool',
+              creates => '/usr/lib/modules-load.d/ipmievd.conf',
+              require => Package['ipmitool'],
+              notify  => Exec['Load modules from /usr/lib/modules-load.d/ipmievd.conf'],
             }
+            exec { 'Load modules from /usr/lib/modules-load.d/ipmievd.conf':
+              command     => 'systemctl restart systemd-modules-load.service',
+              notify      => Service['ipmievd'],
+              refreshonly => true,
+            }
+
+            # Our ipmievd requirements are just the package & the config file.
+            $ipmievd_requirements = [Package['ipmitool'],
+                                     File['/etc/default/ipmievd'],
+                                    ]
           }
-        }
-        service { 'ipmi':
-          ensure    => running,
-          name      => 'ipmi',
-          enable    => true,
-          hasstatus => true,
-          require   => Package['OpenIPMI'],
-        }
-        case $::lsbmajdistrelease {
-          '5', '6': {
-            service { 'ipmievd':
-              ensure      => running,
-              name        => 'ipmievd',
-              enable      => true,
-              hasstatus   => true,
-              require     => $::lsbmajdistrelease ? {
-                '5' => Package['OpenIPMI-tools'],
-                default    => Package['OpenIPMI'],
-              },
+          # For older Debian, and all Ubuntu, we must load the modules.
+          else {
+            # Start with ipmi_msghandler
+            base::os::kernel_module { 'ipmi_msghandler':
+              ensure => present,
             }
+
+            # Load lots of additional modules
+            # In Unbuntu, Kernel 3.13 apparently had one IPMI function compiled
+            # into the kernel, meaning there was no driver to load.
+            # See Ubuntu bug #1284334
+            # Also, there's a kernel module called 'ipmi_watchdog', but it has
+            # alot of options to set on load, so we don't try to load it.
+            if     $::operatingsystem  == 'Ubuntu'
+               and $::kernelmajversion == '3.13'
+            {
+              $additional_ipmi_modules = [
+                'acpi_ipmi',
+                'ipmi_devintf',
+                'ipmi_poweroff',
+              ]
+            } else {
+              $additional_ipmi_modules = [
+                'acpi_ipmi',
+                'ipmi_devintf',
+                'ipmi_poweroff',
+                'ipmi_si',
+              ]
+            }
+            base::os::kernel_module { $additional_ipmi_modules:
+              ensure  => present,
+              require => Base::Os::Kernel_module['ipmi_msghandler'],
+            }
+
+            # Set our requirements for starting ipevd
+            $ipmievd_requirements = [Base::Os::Kernel_module['ipmi_devintf'],
+                                     File['/etc/default/ipmievd']
+                                    ]
+          }
+
+          # Finally, start the ipmievd service
+          service { 'ipmievd':
+            ensure    => running,
+            name      => 'ipmievd',
+            enable    => true,
+            hasstatus => false,
+            status    => 'pidof ipmievd',
+            require   => $ipmievd_requirements,
+          }
+        } # Done handling ensure => present for osfamily Debian
+
+        # Catch RHEL and related systems
+        'RedHat': {
+
+          # We need to have the OpenIPMI package
+          package { 'OpenIPMI':
+            ensure => present,
           }
+
+          # For RHEL 5 and earlier, the client is a separate package
+          if $::lsbmajdistrelease <= 5 {
+            package { 'OpenIPMI-tools':
+              ensure => present,
+            }
+            $ipmi_package = [Package['OpenIPMI'],
+                             Package['OpenIPMI-tools'],
+                            ]
+          } else {
+            $ipmi_package = Package['OpenIPMI']
+          }
+
+          # Define and start the services
+          # (For RHEL <= 5, we don't need the client to start the service)
+          service { 'ipmi':
+            ensure    => running,
+            name      => 'ipmi',
+            enable    => true,
+            hasstatus => true,
+            require   => $ipmi_package,
+          }
+
+          # ipmievd is a separate service, starting with RHEL 5
+          service { 'ipmievd':
+            ensure    => running,
+            name      => 'ipmievd',
+            enable    => true,
+            hasstatus => true,
+            require   => $ipmi_package,
+          }
+        } # Done handling ensure => present for osfamily RedHat
+
+        default: {
+          fail('base::ipmi does not recognize this osfamily')
         }
-      }
-    }
+      } # Done checking $osfamily
+    } # Done handling ensure => 'present'
 
-    # Disable cipher zero.  Some IPMI report the ciphers backwards so we work
-    # around it. Puppet 2.6.3 doesn't support provider param for exec.
-    # Working around it.  The signal file /etc/noipmi allows this execution to
-    # be suppressed on systems that don't have ipmi.
-    exec { 'ipmitool lan set 1 cipher_privs XaaaaaaaaaaaaaX':
-      unless => 'bash -c \'if [ ! -e /etc/noipmi ] && ! `ipmitool lan print | grep -q "Cipher Suite Priv Max   : Not Available"`; then ipmitool lan print | grep "Cipher Suite Priv Max" | cut -d: -f2 | egrep -q "^ XaaaaaaaaaaaaaX"; fi\'',
-    }
-  }
-}
+    'absent': {
+      case $::osfamily {
+        'Debian': {
+          # Stop the IPMI service
+          service { 'ipmievd':
+            ensure    => stopped,
+            name      => 'ipmievd',
+            enable    => false,
+            hasstatus => false,
+            status    => 'pidof ipmievd',
+            require   => $ipmievd_requirements,
+          }
+
+          # Remove any remaining ipmievd configuration
+          file { '/etc/default/ipmievd':
+            ensure  => absent,
+            require => Service['ipmievd'],
+          }
+
+          # Unload lots of additional modules
+          # In Unbuntu, Kernel 3.13 apparently had one IPMI function compiled
+          # into the kernel, meaning there was no driver to unload.
+          # See Ubuntu bug #1284334
+          if     $::operatingsystem  == 'Ubuntu'
+             and $::kernelmajversion == '3.13'
+          {
+            $dependent_ipmi_modules = [
+              'acpi_ipmi',
+              'ipmi_devintf',
+              'ipmi_poweroff',
+              'ipmi_watchdog'
+            ]
+            base::os::kernel_module { $dependent_ipmi_modules:
+              ensure  => absent,
+              require => Service['ipmievd'],
+            }
+          } else {
+            # This is a little more annoying, as we have two dependency levels
+            # to deal with.
+            $additional_ipmi_modules = [
+              'acpi_ipmi',
+              'ipmi_devintf',
+              'ipmi_poweroff',
+              'ipmi_watchdog',
+            ]
+            base::os::kernel_module { $additional_ipmi_modules:
+              ensure  => absent,
+              require => Service['ipmievd'],
+            }
+
+            $dependent_ipmi_modules = 'ipmi_si'
+            base::os::kernel_module { $dependent_ipmi_modules:
+              ensure  => absent,
+              require => Base::Os::Kernel_module[$additional_ipmi_modules],
+            }
+          }
+
+          # Unload the ipmi_msghandler, the root for most IPMI stuff
+          base::os::kernel_module { 'ipmi_msghandler':
+            ensure  => absent,
+            require => Base::Os::Kernel_module[$dependent_ipmi_modules],
+          }
+
+          # For Debian 8+, make sure modules are not re-loaded on startup
+          if $::operatingsystem == 'Debian' and $::lsbmajdistrelease >= 8 {
+            file { '/usr/lib/modules-load.d/ipmievd.conf':
+              ensure => absent,
+            }
+          }
 
-class base::noipmi inherits base::ipmi {
-  Base::Os::Kernel_module['ipmi_si']      { ensure => absent }
-  Base::Os::Kernel_module['ipmi_devintf'] { ensure => absent }
-  File['/etc/default/ipmievd']            { ensure => absent }
+          # Packages: The IPMI daemon and the client come in one package.
+          # Some people might want to keep the client, so we don't delete it.
+        } # Done handling ensure => absent for osfamily Debian
 
-  Service['ipmievd'] { ensure => stopped }
+        'RedHat': {
+          # Make sure the IPMI service isn't running
+          service { 'ipmi':
+            ensure => stopped,
+            enable => false,
+          }
 
-  file { '/etc/noipmi':
-    mode    => '0644',
-    content => "ipmi is not supported on this system\n",
+          # Make sure the IPMI packages are uninstalled
+          # (We keep tools, but remove the server/driver)
+          package { 'OpenIPMI':
+            ensure => purged;
+          }
+        }
+        default: {
+          fail('base::noipmi does not recognize this OS family')
+        }
+      } # Dont handling ensure => absent for osfamily RedHat
+
+      # Leave a file marker on the system saying that IPMI is disabled
+      file { '/etc/noipmi':
+        mode    => '0644',
+        content => "ipmi is not supported, or has been disabled in Puppet.\n",
+      }
+    } # Done handling ensure => absent
+
+    default: {
+      fail("Valid values for base::ipmi::ensure are 'present' or 'absent'")
+    }
   }
 }
diff --git a/templates/ipmi/etc/default/ipmievd.erb b/templates/ipmi/etc/default/ipmievd.erb
index 448a624..acfff56 100644
--- a/templates/ipmi/etc/default/ipmievd.erb
+++ b/templates/ipmi/etc/default/ipmievd.erb
@@ -1,7 +1,7 @@
 ENABLED=true
 
 <% if ((@operatingsystem == 'Debian' and @lsbmajdistrelease >= 8) \
-       or (@operatingsystem == 'Ubuntu' and @lsbmajdistrelease.split('.')[0].to_i >= 14))
+       or (@operatingsystem == 'Ubuntu' and !@lsbmajdistrelease.split('.')[0].nil? and @lsbmajdistrelease.split('.')[0].to_i >= 14))
 %>
 IPMIEVD_OPTIONS="open daemon"
 <% end -%>
-- 
GitLab