Description: Check for commented out drives in fstab
 This patch checks for commented out drives in /etc/fstab, in case Swift
 drive-audit process removed it.
Author: Thomas Goirand <zigo@debian.org>
Forwarded: https://review.opendev.org/c/openstack/puppet-swift/+/775631
Last-Update: 2021-02-15

Index: puppet-module-swift/lib/facter/swift-commented-fstab-entries.rb
===================================================================
--- /dev/null
+++ puppet-module-swift/lib/facter/swift-commented-fstab-entries.rb
@@ -0,0 +1,21 @@
+# module_name/lib/facter/swift-commented-fstab-entries
+Facter.add(:swift_commented_fstab_entries) do
+  setcode do
+    myhash = {}
+    File.open('/etc/fstab').readlines.each{ |line|
+      if line.match('^[#]*UUID=')
+        mountpoint = line.split[1]
+        if mountpoint.match('^/srv/node/')
+          drivename = mountpoint.gsub('/srv/node/', '')
+          if line.match('^#')
+            c = { drivename => 'commented' }
+          else
+            c = { drivename => 'active' }
+          end
+          myhash = myhash.merge(c)
+        end
+      end
+    }
+    myhash
+  end
+end
Index: puppet-module-swift/manifests/storage/mount.pp
===================================================================
--- puppet-module-swift.orig/manifests/storage/mount.pp
+++ puppet-module-swift/manifests/storage/mount.pp
@@ -40,71 +40,86 @@
     $fsoptions = 'user_xattr'
   }
 
-  # The directory that represents the mount point needs to exist.
-  file { "${mnt_base_dir}/${name}":
-    ensure  => directory,
-    require => Anchor['swift::config::begin'],
-    before  => Anchor['swift::config::end'],
-  }
-
-  # Make root own the mount point to prevent swift processes from writing files
-  # when the disk device is not mounted
-  exec { "fix_mountpoint_permissions_${name}":
-    command => ['chown', '-R', 'root:root', "${mnt_base_dir}/${name}"],
-    path    => ['/usr/bin', '/bin'],
-    before  => Anchor['swift::config::end'],
-    unless  => "grep ${mnt_base_dir}/${name} /etc/mtab",
-  }
-
-  mount { "${mnt_base_dir}/${name}":
-    ensure  => present,
-    device  => $device,
-    fstype  => $fstype,
-    options => "${options},${fsoptions}",
-  }
-
-  # double checks to make sure that things are mounted
-  exec { "mount_${name}":
-    command => "mount ${mnt_base_dir}/${name}",
-    path    => ['/bin'],
-    unless  => "grep ${mnt_base_dir}/${name} /etc/mtab",
-    before  => Anchor['swift::config::end'],
-  }
-
   $user = $::swift::params::user
   $group = $::swift::params::group
 
-  exec { "fix_mount_permissions_${name}":
-    command     => ['chown', '-R', "${user}:${group}", "${mnt_base_dir}/${name}"],
-    path        => ['/usr/bin', '/bin'],
-    refreshonly => true,
-    before      => Anchor['swift::config::end'],
-  }
-
-  File["${mnt_base_dir}/${name}"]
-  -> Exec["fix_mountpoint_permissions_${name}"]
-  -> Mount["${mnt_base_dir}/${name}"]
-  -> Exec["mount_${name}"]
-
-  Mount["${mnt_base_dir}/${name}"] ~> Exec["fix_mount_permissions_${name}"]
-  Exec["mount_${name}"] ~> Exec["fix_mount_permissions_${name}"]
-
-  # mounting in linux and puppet is broken and non-atomic
-  # we have to mount, check mount with executing command,
-  # fix ownership and on selinux systems fix context.
-  # It would be definitely nice if passing options uid=,gid=
-  # would be possible as context is. But, as there already is
-  # chown command we'll just restorecon on selinux enabled
-  # systems :(
-  if (str2bool($facts['os']['selinux']['enabled']) == true) {
-    exec { "restorecon_mount_${name}":
-      command     => ['restorecon', "${mnt_base_dir}/${name}"],
-      path        => ['/usr/sbin', '/sbin'],
+  if $facts['swift_commented_fstab_entries'][$name] {
+    if $facts['swift_commented_fstab_entries'][$name] == 'active'{
+      # double checks to make sure that things are mounted
+      exec { "mount_${name}":
+        command => "mount ${mnt_base_dir}/${name}",
+        path    => ['/usr/bin', '/usr/sbin', '/bin', '/sbin',],
+        unless  => "cat /proc/mounts | grep -E '^/dev/.* ${mnt_base_dir}/${name}'",
+        require => Anchor['swift::config::begin'],
+      }->
+      exec { "fix_mount_permissions_${name}":
+        command => "chown swift:swift ${mnt_base_dir}/${name}",
+        path    => ['/usr/bin', '/usr/sbin', '/bin', '/sbin',],
+        onlyif  => "[ `stat -c '%U' ${mnt_base_dir}/${name}` != 'swift' ] || [ `stat -c '%G' ${mnt_base_dir}/${name}` != 'swift' ]",
+        before  => Anchor['swift::config::end'],
+      }
+    }else{
+      # double checks to make sure that the folder is unmounted
+      exec { "unmount_fstab_commented_${name}":
+        command => "umount ${mnt_base_dir}/${name}",
+        path    => ['/usr/bin', '/usr/sbin', '/bin', '/sbin',],
+        onlyif  => "cat /proc/mounts | grep -q -E '^/dev/.* ${mnt_base_dir}/${name}'",
+      }
+      # If the drive was unmounted by swift disk auditor
+      # make sure that /srv/node/NAME is owned by root,
+      # so swift cannot fill-up the system partition.
+      -> exec { "fix_unmounted_drive_permissions_${name}":
+        command => "chown root:root ${mnt_base_dir}/${name}",
+        path    => ['/usr/bin', '/usr/sbin', '/bin', '/sbin',],
+        unless  => "cat /proc/mounts | grep -q -E '^/dev/.* ${mnt_base_dir}/${name}'",
+        onlyif  => "[ `stat -c '%U' ${mnt_base_dir}/${name}` != 'root' ] || [ `stat -c '%G' ${mnt_base_dir}/${name}` != 'root' ]",
+      }
+      # If it's really unmounted, but not empty, then it
+      # means the folder contains files on the root filesystem:
+      # Chown its top folders.
+      -> exec { "chown_folder_${mnt_base_dir}/${name}/objects":
+        command => "chown root:root ${mnt_base_dir}/${name}/objects",
+        path    => ['/usr/bin', '/usr/sbin', '/bin', '/sbin',],
+        onlyif  => "ls -A1q ${mnt_base_dir}/${name}/ | grep -q . && test -d ${mnt_base_dir}/${name}/objects"
+      }
+      -> exec { "chown_folder_${mnt_base_dir}/${name}/accounts":
+        command => "chown root:root ${mnt_base_dir}/${name}/accounts",
+        path    => ['/usr/bin', '/usr/sbin', '/bin', '/sbin',],
+        onlyif  => "ls -A1q ${mnt_base_dir}/${name}/ | grep -q . && test -d ${mnt_base_dir}/${name}/accounts"
+      }
+      -> exec { "chown_folder_${mnt_base_dir}/${name}/containers":
+        command => "chown root:root ${mnt_base_dir}/${name}/containers",
+        path    => ['/usr/bin', '/usr/sbin', '/bin', '/sbin',],
+        onlyif  => "ls -A1q ${mnt_base_dir}/${name}/ | grep -q . && test -d ${mnt_base_dir}/${name}/containers"
+      }
+      -> notify{"${name}: The device already exist in fsttab, but is commented out": }
+      -> notify{"${name}: This may happen if swift has detected a problem on the device":}
+      -> notify{"${name}: and the swift drive-audit umounted the drive.":}
+      -> notify{"${name}: THIS NEEDS MANUAL UNCOMMENT AND MOUNT IF THE DRIVE IS FIXED/REPLACED.":
+        before  => Anchor['swift::config::end'],}
+    }
+  }else{
+    # The directory must be owned by root before the mount,
+    # otherwise, when the drive breaks, swift fills-up the
+    # system partition.
+    file { "${mnt_base_dir}/${name}":
+      ensure  => directory,
+      owner   => 'root',
+      group   => 'root',
+      require => Anchor['swift::config::begin'],
+    }->
+    mount { "${mnt_base_dir}/${name}":
+      ensure  => mounted,
+      device  => $device,
+      fstype  => $fstype,
+      options => "${options},${fsoptions}",
+    }->
+    # Fixup rights *only* once mounted
+    exec { "fix_mount_permissions_${name}":
+      command     => "chown swift:swift ${mnt_base_dir}/${name}",
+      path        => ['/usr/bin', '/usr/sbin', '/bin', '/sbin',],
       before      => Anchor['swift::config::end'],
       refreshonly => true,
     }
-
-    Mount["${mnt_base_dir}/${name}"] ~> Exec["restorecon_mount_${name}"]
-    Exec["mount_${name}"] ~> Exec["restorecon_mount_${name}"]
   }
 }
