From 90d2d0a5437b2c5d2eabcd02e90d241a069753ca Mon Sep 17 00:00:00 2001
From: Britney Fransen <brfransen@gmail.com>
Date: Thu, 9 Mar 2017 19:52:37 +0000
Subject: LinHES-system: remove_storage.py: initial inclusion

add_storage.py: in reconstruct and reconstruct_sg add some checks for removed in .conf files
---
 abs/core/LinHES-system/PKGBUILD          |   7 +-
 abs/core/LinHES-system/add_storage.py    |  45 +++++---
 abs/core/LinHES-system/remove_storage.py | 184 +++++++++++++++++++++++++++++++
 3 files changed, 219 insertions(+), 17 deletions(-)
 create mode 100755 abs/core/LinHES-system/remove_storage.py

diff --git a/abs/core/LinHES-system/PKGBUILD b/abs/core/LinHES-system/PKGBUILD
index c6280b4..aed479d 100755
--- a/abs/core/LinHES-system/PKGBUILD
+++ b/abs/core/LinHES-system/PKGBUILD
@@ -1,6 +1,6 @@
 pkgname=LinHES-system
 pkgver=8.4
-pkgrel=21
+pkgrel=22
 arch=('i686' 'x86_64')
 install=system.install
 pkgdesc="Everything that makes LinHES an automated system"
@@ -18,7 +18,7 @@ binfiles="LinHES-start optimize_mythdb.py myth_mtc.py
  lh_system_backup lh_system_backup_job lh_system_restore lh_system_restore_job
  lh_system_host_update lh_system_all_host_update
  add_storage.py balance_storage_groups.py empty_storage_groups.py
- diskspace.sh cacheclean lh_backend_control.sh
+ remove_storage.py diskspace.sh cacheclean lh_backend_control.sh
  create_media_dirs.sh msg_client.py msg_daemon.py mythvidexport.py
  gen_is_xml.py gen_lib_xml.py gen_light_include.py gen_game_xml.py
  misc_recent_recordings.pl misc_status_config.py misc_status_info.sh
@@ -101,9 +101,10 @@ md5sums=('c6e6b83a1f4c35ef4501e277657ab2ac'
          'bc69a520add58ede9b060c73e67ace13'
          '74e17d6f7453c52d56fecaed5c3f6ad5'
          '47e093e8cfe4b5b96602358e1f540832'
-         'dbd51b9146f843acb582bb5722adbe37'
+         '727a886a1ba237906f48cda2e4e7844b'
          '0c81e5cad656f6260e39cd7585b1421a'
          'e5bb027c54a2727d0bcf8d6fb357ba32'
+         '17c75e02632ed83c2f73ca94ef701210'
          '2c005d95312018bef80092136f80f254'
          'c8db6a83ecc089ea37ab7fcb0f7a01cf'
          'ca63946920ba33de1f15abda83e74e40'
diff --git a/abs/core/LinHES-system/add_storage.py b/abs/core/LinHES-system/add_storage.py
index c172f6f..29eecde 100755
--- a/abs/core/LinHES-system/add_storage.py
+++ b/abs/core/LinHES-system/add_storage.py
@@ -518,16 +518,16 @@ def prompt_sg(dir_sg):
     if dir_sg != True:
         loop = True
         prompt_string='''
-    MythTV Storage Groups are used for artwork, database backups,
+    MythTV storage groups are used for artwork, database backups,
     photos, music, streaming, TV recordings, and videos.
 
     The content on these storage groups will
     only be available while the system is online.
 
-    Enabling MythTV Storage Groups will create the directories
+    Enabling MythTV storage groups will create the directories
     on the disk(s) and add the paths to the MythTV database.
 
-    Enable MythTV Storage Groups (Y/N)?:'''
+    Enable MythTV storage groups (Y/N)?:'''
 
         while loop:
             str1 = raw_input(prompt_string)
@@ -538,14 +538,14 @@ def prompt_sg(dir_sg):
 
         if str1 == 'Y' or str1 == 'y':
             dir_sg = True
-            print "    ** Will add MythTV Storage Groups!"
+            print "    ** Will add MythTV storage groups!"
         else:
-            print "    ** Will NOT add MythTV Storage Groups!"
+            print "    ** Will NOT add MythTV storage groups!"
             dir_sg = False
     else:
         dir_sg = True
         print "\n    --add_sg option used"
-        print "    ** Will add MythTV Storage Groups!"
+        print "    ** Will add MythTV storage groups!"
 
     return dir_sg
 
@@ -774,7 +774,7 @@ def myth_main(no_mount,install_call,dir_sg):
     runcmd(cmd)
 
 def reconstruct_storagegroups():
-    print "\nRecreating Storage Groups from contents of /etc/storage.d/\n"
+    print "\nRecreating storage groups from contents of /etc/storage.d/\n"
 
     DB = MythDB()
     host=gethostname()
@@ -784,15 +784,22 @@ def reconstruct_storagegroups():
         parser.read(conf_file)
         mount_point = parser.get('storage', 'mountpoint')
         mmount = parser.getboolean('storage', 'mmount')
+        try:
+            removed = parser.getboolean('storage', 'removed')
+        except:
+            removed = False
+        if removed:
+            print "Skipping: " + mount_point + " - removed"
+            continue
         if not os.path.ismount(mount_point):
-            print "Skipping: " + mount_point + " not mounted"
+            print "Skipping: " + mount_point + " - not mounted"
             continue
         try:
             dir_sg = parser.getboolean('storage', 'storage_groups')
         except ConfigParser.NoOptionError, err:
             print "SG not found in conf, get setting from DB"
             dir_sg = False
-            # Get Storage Group directories from DB
+            # Get storage sroup directories from DB
             recs = DB.getStorageGroup(groupname="Default")
             for record in recs:
                 if record.dirname.startswith(mount_point):
@@ -875,6 +882,10 @@ class reconstruct_path:
             self.fstype = parser.get('storage', 'fstype')
         except:
             self.fstype = self.get_fstype()
+        try:
+            self.removed = parser.get('storage', 'removed')
+        except:
+            self.removed = False
 
     def get_fstype(self):
         cmd = "fsck -N UUID=%s" %self.uuid
@@ -903,6 +914,9 @@ class reconstruct_path:
     def get_disk_num(self):
         return self.disk_num
 
+    def get_removed(self):
+        return self.removed
+
     def create_mount_point(self):
         try:
             os.stat(self.mount_point)
@@ -1035,6 +1049,9 @@ def reconstruct_mounts(no_mount):
         print "\n"
         cf = reconstruct_path(conf_file)
 
+        # skip if the disk was removed
+        if cf.get_removed():
+            continue
         #print cf.get_conf()
         #print cf.get_uuid()
         print "    Recreating %s" %cf.get_mount_point()
@@ -1070,15 +1087,15 @@ def usage():
         Add disk to /etc/fstab
         Mount the disk
         Create the directories
-            (if user enables MythTV Storage Groups)
+            (if user enables MythTV storage groups)
         Write out the disk config file to /etc/storage.d/
         Create disk# symlink at /data/storage/
         Create /myth symlink (if applicable)
-        Create MythTV Storage Group paths in MythTV database
-            (if user enables MythTV Storage Groups)
+        Create MythTV storage group paths in MythTV database
+            (if user enables MythTV storage groups)
 
     Options:
-    --add_sg:           Create the MythTV Storage Group directories and
+    --add_sg:           Create the MythTV storage group directories and
                            database entries for database backups, TV
                            recordings, photos, music, streaming, videos
                            and artwork.
@@ -1095,7 +1112,7 @@ def usage():
                            /data/storage/disk# symlink, and mount the disk.
                            --no_mount is the only option that works with
                            --reconstruct.
-    --reconstruct_sg:   Recreate the MythTV Storage Group directories and
+    --reconstruct_sg:   Recreate the MythTV storage group directories and
                            database entries if they don't exist.
                            No other options work with --reconstruct_sg.
     --report:           Scan disks and print new found disks.
diff --git a/abs/core/LinHES-system/remove_storage.py b/abs/core/LinHES-system/remove_storage.py
new file mode 100755
index 0000000..fd4c0b4
--- /dev/null
+++ b/abs/core/LinHES-system/remove_storage.py
@@ -0,0 +1,184 @@
+#!/usr/bin/python2
+#remove_storage.py removes disks that were added using add_storage.py
+#
+#Only disks that have a conf file in /etc/storage.d/ are presented
+#as choices to remove.
+
+
+import os,sys,commands
+import ConfigParser
+from ConfigParser import SafeConfigParser
+import glob
+from socket import gethostname
+from MythTV import MythDB
+
+storage_dir = "/etc/storage.d"
+
+def runcmd(cmd):
+    if True :
+        pass
+    else:
+        cmd = "echo "+cmd
+    #print cmd
+    cmdout = commands.getstatusoutput(cmd)
+    #logging.debug("    %s", cmdout)
+    return cmdout
+
+def read_fstab():
+    f = open('/etc/fstab', 'r')
+    fstab=f.readlines()
+    f.close()
+    return fstab
+
+def unmount_disk(conf):
+    if os.path.ismount(conf[1]):
+        print "Unmounting " + conf[1] + "."
+        cmd = "umount %s" %conf[1]
+        runcmd(cmd)
+
+def remove_fstab_entry(conf):
+    fstab=read_fstab()
+    f = open('/etc/fstab', 'w')
+    for line in fstab:
+        if not line.startswith("#"):
+            if line.find(conf[1]) > -1 and line.find(conf[2]) > -1 :
+                print "Removing " + conf[1] + " from fstab."
+            else:
+                f.write(line)
+        else:
+            f.write(line)
+    f.close()
+
+def remove_SG_entries(conf):
+    DB = MythDB()
+    host=gethostname()
+    with DB as c:
+        print "Removing " + conf[1] + " storage group\n    paths from MythTV database."
+        c.execute("""delete from storagegroup where hostname = %s and dirname like %s""", (host,conf[1] + '%'))
+        c.execute("""delete from settings where hostname = %s and value like %s""", (host,'SGweightPerDir:' + host + ':' + conf[1] + '%'))
+
+def remove_disk_link(conf):
+    if os.path.islink("/data/storage/disk" + str(conf[0])):
+        print "Removing link /data/storage/disk%s." %(conf[0])
+        cmd = "rm -f /data/storage/disk%s" %(conf[0])
+        runcmd(cmd)
+
+def remove_disk_mount(conf):
+    print "Removing mountpoint %s." %(conf[1])
+    cmd = "rm -rf %s" %(conf[1])
+    runcmd(cmd)
+
+def update_conf_file(conf):
+    print "Updating %s file\n    and running systemconfig." %(conf[4])
+    parser = SafeConfigParser()
+    parser.read(conf[4])
+    parser.set('storage','shareable',"False")
+    parser.set('storage','removed',"True")
+    with open(conf[4], 'wb') as conf[4]:
+        parser.write(conf[4])
+    cmd = "systemconfig.py -m fileshare"
+    runcmd(cmd)
+
+def usage():
+    help='''
+    remove_storage.py removes disks that were added using add_storage.py.
+    Only disks that have a conf file in /etc/storage.d/ are presented
+    as choices to remove.
+
+    Disks removed from the system are not erased or formatted.
+
+    Normal operations include (in this order):
+        Ask which disk to remove
+        Unmount the disk if mounted
+        Remove disk from /etc/fstab
+        Remove MythTV storage group paths in MythTV database
+        Remove disk# symlink at /data/storage/
+        Remove disk name mountpoint at /data/storage/
+        Make shareable = False in /etc/storage.d/DISKNAME.conf
+        Add removed = True in /etc/stoarge.d/DISKNAME.conf
+        Run systemconfig.py -m fileshare to update File Shares
+
+    Options:
+    -h, --help:         Show this help message.
+    '''
+    print help
+    sys.exit(0)
+
+#--------------------------------------------
+
+def main():
+    all_confs = []
+
+    # get conf files that are not disk0 or not removed
+    for conf_file in glob.glob('%s/*.conf' %storage_dir):
+        this_conf = []
+        parser = SafeConfigParser()
+        parser.read(conf_file)
+        mounted = ""
+        disk_num = parser.get('storage', 'disk_num')
+        try:
+            removed = parser.get('storage', 'removed')
+        except:
+            removed = False
+        if disk_num == "0" or removed:
+            continue
+        this_conf.append(int(disk_num)) #0
+        this_conf.append(parser.get('storage', 'mountpoint')) #1
+        this_conf.append(parser.get('storage', 'uuid')) #2
+        if os.path.ismount(this_conf[1]):
+            this_conf.append("(mounted)") #3
+        else:
+            this_conf.append("") #3
+        this_conf.append(conf_file) #4
+        all_confs.append(this_conf)
+
+    # sort confs on disk num
+    all_confs.sort(key=lambda x: x[0])
+
+    # exit if no disks found
+    if len(all_confs) == 0:
+        print "\nThere are no disks to remove. Exiting."
+        sys.exit(0)
+
+    print "\nDisks found in /etc/storage.d/:\n"
+
+    # print list of disks to remove
+    for i,conf in enumerate(all_confs):
+        print str(i+1) + ": " + conf[1] + " (disk" + str(conf[0]) + ") " + conf[3]
+
+    # get user input of disk to remove
+    try:
+        conf_select=raw_input("\nEnter the number of the disk to remove: ")
+        conf_select=int(conf_select)
+        if conf_select > len(all_confs) or conf_select < 1:
+            conf_select=int("e")
+    except ValueError:
+        print "You must enter a number between 1 and " + str(len(all_confs)) + ". Exiting."
+        sys.exit(0)
+
+    selected_conf = all_confs[conf_select-1]
+
+    # confirm selection
+    confirm_select=raw_input("\nDisk " + selected_conf[1] + " (disk" + str(selected_conf[0]) + ") will be removed.\nAre you sure you want to remove it (yes/no)? ")
+    if confirm_select != "yes":
+        print "Exiting."
+        sys.exit(0)
+
+    print ""
+    unmount_disk(selected_conf)
+    remove_fstab_entry(selected_conf)
+    remove_SG_entries(selected_conf)
+    remove_disk_link(selected_conf)
+    remove_disk_mount(selected_conf)
+    update_conf_file(selected_conf)
+
+    print "\nDisk " + selected_conf[1] + " has been removed."
+
+if __name__ == "__main__":
+    if not os.geteuid()==0:
+        sys.exit("\nRoot access is required to run this program.\n")
+
+    if "--help" in sys.argv or "-h" in sys.argv:
+        usage()
+    else:
+        main()
-- 
cgit v0.12

