示例#1
0
def detach(device=" ", logger=False):
    """
    Eject the ramdisk
    Detach (on the mac) is a better solution than unmount and eject
    separately.. Besides unmounting the disk, it also stops any processes
    related to the mntPoint

    @author: Roy Nielsen
    """
    success = False
    if not logger:
        logger = CyLogger()
    else:
        logger = logger
    myRunWith = RunWith(logger)
    if not re.match("^\s*$", device):
        cmd = ["/usr/bin/hdiutil", "detach", device]
        myRunWith.setCommand(cmd)
        myRunWith.communicate()
        retval, reterr, retcode = myRunWith.getNlogReturns()
        if not reterr:
            success = True

        myRunWith.getNlogReturns()
    else:
        raise Exception("Cannot eject a device with an empty name..")
    return success
示例#2
0
def detach(device=" ", logger=False):
    """
    Eject the ramdisk
    Detach (on the mac) is a better solution than unmount and eject
    separately.. Besides unmounting the disk, it also stops any processes
    related to the mntPoint

    @author: Roy Nielsen
    """
    success = False
    if not logger:
        logger = CyLogger()
    else:
        logger = logger
    myRunWith = RunWith(logger)
    if not re.match("^\s*$", device):
        cmd = ["/usr/bin/hdiutil", "detach", device]
        myRunWith.setCommand(cmd)
        myRunWith.communicate()
        retval, reterr, retcode = myRunWith.getNlogReturns()
        if not reterr:
            success = True

        myRunWith.getNlogReturns()
    else:
        raise Exception("Cannot eject a device with an empty name..")
    return success
示例#3
0
def unmount(mnt_point="", logger=False):
    """
    Unmount the ramdisk

    @author: Roy Nielsen
    """
    success = False
    if mnt_point:
        runWith = RunWith(logger)
        command = ["/bin/umount", mnt_point]
        runWith.setCommand(command)
        runWith.communicate()
        retval, reterr, retcode = runWith.getNlogReturns()
        if not reterr:
            success = True

    return success
示例#4
0
def umount(mnt_point="", logger=False):
    """
    Unmount the ramdisk

    @author: Roy Nielsen
    """
    success = False
    if mnt_point:

        paths = [
            "/bin", "/usr/bin", "/sbin", "/usr/sbin", "/usr/local/bin",
            "/user/local/sbin"
        ]

        #####
        # Look for the umount command
        umountFound = False
        umountPath = ""
        for path in paths:
            possibleFullPath = os.path.join(path, "umount")
            if os.path.exists(possibleFullPath):
                umountPath = possibleFullPath
                umountFound = True

        if not umountFound:
            raise SystemToolNotAvailable("Cannot find umount command...")

        #####
        # Run the umount command...
        runWith = RunWith(logger)
        command = [umountPath, mnt_point]
        runWith.setCommand(command)
        runWith.communicate()
        retval, reterr, retcode = runWith.getNlogReturns()
        if not reterr:
            success = True

    return success
示例#5
0
class RamDisk(RamDiskTemplate):
    """
    http://www.cyberciti.biz/tips/what-is-devshm-and-its-practical-usage.html

    In this example, remount /dev/shm with 8G size as follows:

    # mount -o remount,size=8G /dev/shm

    To be frank, if you have more than 2GB RAM + multiple Virtual machines,
    this hack always improves performance. In this example, you will give you
    tmpfs instance on /disk2/tmpfs which can allocate 5GB RAM/SWAP in 5K inodes
    and it is only accessible by root:

    # mount -t tmpfs -o size=5G,nr_inodes=5k,mode=700 tmpfs /disk2/tmpfs

    Where,

    -o opt1,opt2 : Pass various options with a -o flag followed by a comma
                   separated string of options. In this examples, I used the
                   following options:
       remount : Attempt to remount an already-mounted filesystem. In this
                 example, remount the system and increase its size.
       size=8G or size=5G : Override default maximum size of the
                           /dev/shm filesystem. he size is given in bytes,
                           and rounded up to entire pages. The default is half
                           of the memory. The size parameter also accepts a
                           suffix % to limit this tmpfs instance to that
                           percentage of your pysical RAM: the default, when
                           neither size nor nr_blocks is specified, is
                           size=50%. In this example it is set to 8GiB or 5GiB.
                           The tmpfs mount options for sizing ( size,
                           nr_blocks, and nr_inodes) accept a suffix k, m or
                           g for Ki, Mi, Gi (binary kilo, mega and giga) and
                           can be changed on remount.
       nr_inodes=5k : The maximum number of inodes for this instance. The
                      default is half of the number of your physical RAM pages,
                      or (on a machine with highmem) the number of lowmem RAM
                      pages, whichever is the lower.
       mode=700 : Set initial permissions of the root directory.
       tmpfs : Tmpfs is a file system which keeps all files in virtual memory.

    ---------------------------------------------------------------------------

    Another link:
    http://www.jamescoyle.net/how-to/943-create-a-ram-disk-in-linux

    Exerpt:
    mount -t [TYPE] -o size=[SIZE],opt2=[opt2],opt3=[opt3] [FSTYPE] [MOUNTPOINT]
    Substitute the following attirbutes for your own values:

    [TYPE] is the type of RAM disk to use; either tmpfs or ramfs.
    [SIZE] is the size to use for the file system. Remember that ramfs does not
           have a physical limit and is specified as a starting size.
    [FSTYPE] is the type of RAM disk to use; either tmpfs, ramfs, ext4, etc.
    Example:

    mount -t tmpfs -o size=512m tmpfs /mnt/ramdisk

    """
    def __init__(self, size=0, mountpoint="",  logger=False,
                 mode=700, uid=None, gid=None,
                 fstype="tmpfs", nr_inodes=None, nr_blocks=None):
        """
        """
        super(RamDisk, self).__init__(size, mountpoint, logger)
        #####
        # The passed in size of ramdisk should be in 1Mb chunks
        self.module_version = '20160224.032043.009191'
        self.logger = logger
        if not sys.platform.startswith("linux"):
            raise self.NotValidForThisOS("This ramdisk is only viable for a Linux.")

        if fstype in ["tmpfs", "ramfs"]:
            self.fstype = fstype
            if fstype == "tmpfs":
                self.myRamdiskDev = "/dev/tmpfs"
        else:
            raise self.BadRamdiskArguments("Not a valid argument for " + \
                                           "'fstype'...")

        if isinstance(mode, int):
            self.mode = mode
        else:
            self.mode = 700

        if not isinstance(uid, int):
            self.uid = os.getuid()
        else:
            self.uid = uid

        if not isinstance(gid, int):
            self.gid = os.getgid()
        else:
            self.gid = gid

        if isinstance(nr_inodes, basestring):
            self.nr_inodes = nr_inodes
        else:
            self.nr_inodes = None

        if isinstance(nr_blocks, basestring):
            self.nr_blocks = nr_blocks
        else:
            self.nr_blocks = None

        self.printData()

        #####
        # Initialize the RunWith helper for executing shelled out commands.
        self.runWith = RunWith(self.logger)
        self.runWith.getNlogReturns()
        self.success = self._mount()


    ###########################################################################

    def buildCommand(self):
        """
        Build a command based on the "fstype" passed in.

        For more options on the tmpfs filesystem, check the mount manpage.

        @author: Roy Nielsen
        """
        command=None
        if self.fstype == "ramfs":
            command = ["/bin/mount", "-t", "ramfs"]
        elif self.fstype == "tmpfs":
            options = ["size=" + str(self.diskSize) + "m"]
            options.append("uid=" + str(self.uid))
            options.append("gid=" + str(self.gid))
            options.append("mode=" + str(self.mode))
            """
            try:
                options.append(self.nr_inodes)
            except AttributeError:
                pass
            try:
                options.append("nr_blocks=" + str(self.nr_blocks))
            except AttributeError:
                pass
            """

            command = ["/bin/mount", "-t", "tmpfs", "-o",
                       ",".join(options), "tmpfs", self.mntPoint]
            #/bin/mount -t tmpfs  -o size=500m,uid=0,gid=0,mode=700 /tmp/tmp0gnLNt
        return command

    ###########################################################################

    def _mount(self) :
        """
        Mount the disk

        @author: Roy Nielsen
        """
        success = False
        command = self.buildCommand()
        self.runWith.setCommand(command)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        self.printData()
        self.runWith.getNlogReturns()
        return success

    def remount(self, size=0, mountpoint="", mode=700, uid=None, gid=None,
                nr_inodes=None, nr_blocks=None):
        """
        Use the tmpfs ability to be remounted with different options

        If bad input is given, the previous values will be used.

        @author: Roy Nielsen
        """
        #####
        # Input Validation:
        #####
        # tmpfs is the only viable ramdisk that handles remounting ok.
        # this includes mouting tmpfs with msdos, ext2,3,4, etc.
        if not self.fstype == "tmpfs":
            raise self.BadRamdiskArguments("Can only use 'remount' with " + \
                                           "tmpfs...")
        if size and isinstance(size, int):
            self.diskSize = size

        if mountpoint and isinstance(mountpoint, type.string):
            self.mntPoint = mountpoint

        if mode and isinstance(mode, int):
            self.mode = mode

        if uid and isinstance(uid, int):
            self.uid = uid

        if gid and isinstance(gid, int):
            self.gid = gid

        if nr_inodes and isinstance(nr_inodes, (int, long)):
            self.nr_inodes = nr_inodes

        if nr_blocks and isinstance(nr_blocks, (int, long)):
            self.nr_blocks = nr_blocks

        #####
        # Initialize the RunWith helper for executing shelled out commands.
        self.runWith = RunWith(self.logger)

        self.buildCommand()
        self._mount()

    ###########################################################################

    def unmount(self) :
        """
        Unmount the disk

        @author: Roy Nielsen
        """
        success = False

        command = ["/bin/umount", self.mntPoint]
        self.runWith.setCommand(command)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True

        return success

    ###########################################################################

    def detach(self) :
        """
        Unmount the disk

        @author: Roy Nielsen
        """
        success = False

        success = self.unmount()

        return success

    ###########################################################################

    def __isMemoryAvailable(self):
        """
        Check to make sure there is plenty of memory of the size passed in
        before creating the ramdisk

        Must be over-ridden to provide OS/Method specific functionality

        @author: Roy Nielsen
        """
        #mem_free = psutil.phymem_usage()[2]

        #print "Memory free = " + str(mem_free)
        success = False
        return success

    ###########################################################################

    def getVersion(self):
        """
        Getter for the version of the ramdisk

        @author: Roy Nielsen
        """
        return self.module_version
示例#6
0
class MacOSUser(ManageUserTemplate):
    """
    Class to manage users on Mac OS.

    #----- Getters
    @method findUniqueUid
    @method uidTaken
    @method getUser
    @method getUserShell
    @method getUserComment
    @method getUserUid
    @method getUserPriGid
    @method getUserHomeDir
    @method isUserInstalled
    @method isUserInGroup
    @method authenticate
    #----- Setters
    @method createStandardUser
    @method createBasicUser
    @method setUserShell
    @method setUserComment
    @method setUserUid
    @method setUserPriGid
    @method setUserHomeDir
    @method createHomeDirectory
    @method addUserToGroup
    @method setUserPassword
    @method fixUserHome
    #----- User removal
    @method rmUser
    @method rmUserHome
    @method rmUserFromGroup

    @author: Roy Nielsen
    """
    def __init__(self, logger, userName="", userShell="/bin/bash",
                 userComment="", userUid=1000, userPriGid=20,
                 userHomeDir="/tmp"):
        super(MacOSUser, self).__init__(logger, userName, userShell,
                                         userComment, userUid, userPriGid,
                                         userHomeDir)
        self.module_version = '20160225.125554.540679'
        if isinstance(logger, CyLogger):
            self.logger = logger
        else:
            raise NotACyLoggerError("Passed in value for logger is invalid, try again.")
        self.dscl = "/usr/bin/dscl"
        self.userData = []
        self.runWith = RunWith(self.logger)

    #----------------------------------------------------------------------
    # Getters
    #----------------------------------------------------------------------

    def findUniqueUid(self):
        """
        """
        pass

    #----------------------------------------------------------------------

    def uidTaken(self, uid):
        """
        """
        pass

    #----------------------------------------------------------------------

    def getUser(self, userName=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def getUserShell(self, userName=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def getUserComment(self, userName=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def getUserUid(self, userName=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def getUserPriGid(self, userName=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def getUserHomeDir(self, userName=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def isUserInstalled(self, user=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def isUserInGroup(self, userName="", groupName=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def authenticate(self, user="", password=""):
        """
        """
        pass

    #----------------------------------------------------------------------
    # Setters
    #----------------------------------------------------------------------

    def createStandardUser(self, userName, password):
        """
        Creates a user that has the "next" uid in line to be used, then puts
        in in a group of the same id.  Uses /bin/bash as the standard shell.
        The userComment is left empty.  Primary use is managing a user
        during test automation, when requiring a "user" context.

        @author: Roy Nielsen
        """
        pass

    #----------------------------------------------------------------------

    def createBasicUser(self, userName=""):
        """
        Create a username with just a moniker.  Allow the system to take care of
        the rest.

        Only allow usernames with letters and numbers.

        @author: Roy Nielsen
        """
        pass

    #----------------------------------------------------------------------

    def setUserShell(self, user="", shell=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def setUserComment(self, user="", comment=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def setUserUid(self, user="", uid=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def setUserPriGid(self, user="", priGid=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def setUserHomeDir(self, user="", userHome=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def addUserToGroup(self, user="", group=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def rmUserFromGroup(self, user="", group=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def setUserPassword(self, user="", password=""):
        """
        """
        pass

    #----------------------------------------------------------------------
    # User Property Removal
    #----------------------------------------------------------------------

    def rmUser(self, user=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def rmUserHome(self, user=""):
        """
        """
        pass

    #----------------------------------------------------------------------

    def fixUserHome(self, userName=""):
        """
        Get the user information from the local directory and fix the user
        ownership and group of the user's home directory to reflect
        what is in the local directory service.

        @author: Roy Nielsen
        """
        pass

    #----------------------------------------------------------------------
    # Unix related OS Specific Methods, uses /etc/password user management
    #----------------------------------------------------------------------

    def acquireUserData(self):
        """
        Acquire local user data that can be found in /etc/password and 
        /etc/shadow.
        
        @author: Roy Nielsen
        """
        success = False
        
        #####
        # Check the UID of the user, only try processing what is available
        # to the uid running this code.
        if not os.getuid() == 0:
            success = self.processEtcPassword()
            if success:
                self.processEtcGroup()
        else:
            success = self.processEtcPassword()
            if success:
                success = self.processEtcGroup()
            if success:
                self.processEtcShadow()

        return success
        
    def processEtcPassword(self):
        """
        Acquire user data from /etc/passwd
        """
        success = False
        userinfo = {}
        #####
        # Process /etc/passwd
        try:
            pass_file = open("/etc/password", 'r')
        except OSError as err:
            self.logger.log(lp.INFO, "Error trying to acquire /etc/password data: " + str(err))
        else:
            for line in pass_file.readlines():
                #####
                # Pull apart the line from the password file to acquire the data
                col = line.split(':')
                userinfo = {}
                user = col[0]
                userinfo['uid'] = col[2]
                userinfo['pgid'] = col[3]
                userinfo['ucomment'] = col[4]
                userinfo['uhome'] = col[5]
                userinfo['ushell'] = col[6]
                #####
                # Put the acquired user data into the class variable
                self.userData[user] = userinfo
            pass_file.close()
            success = True
        return success

    def processEtcShadow(self):
        """
        Acquire user data from /etc/shadow

        @author: Roy Nielsen
        """
        success = False
        #####
        # Process /etc/passwd
        try:
            pass_file = open("/etc/password", 'r')
        except OSError as err:
            self.logger.log(lp.INFO, "Error trying to acquire /etc/shadow data: " + str(err))
        else:
            for line in pass_file.readlines():
                #####
                # Pull apart the line from the password file to acquire the data
                col = line.split(':')
                userinfo = {}
                user = ""
                user = col[0]
                userinfo['lastchanged']    = col[2]
                userinfo['min']   = col[3]
                userinfo['max'] = col[4]
                userinfo['warn']  = col[5]
                userinfo['inactive'] = col[6]
                userinfo['expore']  = col[5]
                #####
                # Put the acquired user data into the class variable
                self.userData[user] = userinfo
            pass_file.close()
            success = True
        return success

    def processEtcGroup(self):
        """
        Acqure a list of groups each user is in
        
        @author: Roy Nielsen
        """
        success = False
        grps = "/usr/bin/groups"

        for user in self.userData:
            #####
            # Run the 'groups <user>' command to acquire the user's groups
            cmd = [grps, user]
            self.runWith.setCommand(cmd)
            self.runWith.communicate()
            retval, reterr, retcode = self.runWith.getNlogReturns()
            #####
            # If there is no error, process the data.
            if not reterr:
                #####
                # Acquire the user's groups from the output
                userGrps = retval.split()
                #####
                # create a dictionary, which will later be added to userData
                # class variable.
                groups = {'groups' : userGrps}
                #####
                # Add the groups the user is a member of.
                self.userData[user] += groups
        return success
示例#7
0
class RamDisk(RamDiskTemplate):
    """
    http://www.cyberciti.biz/tips/what-is-devshm-and-its-practical-usage.html

    In this example, remount /dev/shm with 8G size as follows:

    # mount -o remount,size=8G /dev/shm

    To be frank, if you have more than 2GB RAM + multiple Virtual machines,
    this hack always improves performance. In this example, you will give you
    tmpfs instance on /disk2/tmpfs which can allocate 5GB RAM/SWAP in 5K inodes
    and it is only accessible by root:

    # mount -t tmpfs -o size=5G,nr_inodes=5k,mode=700 tmpfs /disk2/tmpfs

    Where,

    -o opt1,opt2 : Pass various options with a -o flag followed by a comma
                   separated string of options. In this examples, I used the
                   following options:
       remount : Attempt to remount an already-mounted filesystem. In this
                 example, remount the system and increase its size.
       size=8G or size=5G : Override default maximum size of the
                           /dev/shm filesystem. he size is given in bytes,
                           and rounded up to entire pages. The default is half
                           of the memory. The size parameter also accepts a
                           suffix % to limit this tmpfs instance to that
                           percentage of your pysical RAM: the default, when
                           neither size nor nr_blocks is specified, is
                           size=50%. In this example it is set to 8GiB or 5GiB.
                           The tmpfs mount options for sizing ( size,
                           nr_blocks, and nr_inodes) accept a suffix k, m or
                           g for Ki, Mi, Gi (binary kilo, mega and giga) and
                           can be changed on remount.
       nr_inodes=5k : The maximum number of inodes for this instance. The
                      default is half of the number of your physical RAM pages,
                      or (on a machine with highmem) the number of lowmem RAM
                      pages, whichever is the lower.
       mode=700 : Set initial permissions of the root directory.
       tmpfs : Tmpfs is a file system which keeps all files in virtual memory.

    ---------------------------------------------------------------------------

    Another link:
    http://www.jamescoyle.net/how-to/943-create-a-ram-disk-in-linux

    Exerpt:
    mount -t [TYPE] -o size=[SIZE],opt2=[opt2],opt3=[opt3] [FSTYPE] [MOUNTPOINT]
    Substitute the following attirbutes for your own values:

    [TYPE] is the type of RAM disk to use; either tmpfs or ramfs.
    [SIZE] is the size to use for the file system. Remember that ramfs does not
           have a physical limit and is specified as a starting size.
    [FSTYPE] is the type of RAM disk to use; either tmpfs, ramfs, ext4, etc.
    Example:

    mount -t tmpfs -o size=512m tmpfs /mnt/ramdisk

    """
    def __init__(self,
                 size,
                 mountpoint,
                 logger,
                 mode=700,
                 uid=None,
                 gid=None,
                 fstype="tmpfs",
                 nr_inodes=None,
                 nr_blocks=None):
        """
        """
        super(RamDisk, self).__init__(size, mountpoint, logger)
        #####
        # The passed in size of ramdisk should be in 1Mb chunks
        self.module_version = '20160224.032043.009191'
        self.logger = logger
        if not sys.platform.startswith("linux"):
            raise NotValidForThisOS("This ramdisk is only viable for a Linux.")

        if fstype in ["tmpfs", "ramfs"]:
            self.fstype = fstype
            if fstype == "tmpfs":
                self.myRamdiskDev = "/dev/tmpfs"
        else:
            raise BadRamdiskArguments("Not a valid argument for " + \
                                           "'fstype'...")

        if isinstance(mode, int):
            self.mode = mode
        else:
            self.mode = 700

        if not isinstance(uid, int):
            self.uid = os.getuid()
        else:
            self.uid = uid

        if not isinstance(gid, int):
            self.gid = os.getgid()
        else:
            self.gid = gid

        if isinstance(nr_inodes, basestring):
            self.nr_inodes = nr_inodes
        else:
            self.nr_inodes = None

        if isinstance(nr_blocks, basestring):
            self.nr_blocks = nr_blocks
        else:
            self.nr_blocks = None

        #####
        # Initialize the mount and umount command paths...
        self.mountPath = ""
        self.umountPath = ""
        self.getCmds()

        #####
        # Initialize the RunWith helper for executing shelled out commands.
        self.runWith = RunWith(self.logger)
        #self.runWith.getNlogReturns()
        self.success = self._mount()
        self.logger.log(lp.DEBUG, "Finishing linux ramdisk init...")

    ###########################################################################

    def getCmds(self):
        """
        Acquire the paths for mount and umount on the system...

        @author: Roy Nielsen
        """
        success = False
        paths = [
            "/bin", "/usr/bin", "/sbin", "/usr/sbin", "/usr/local/bin",
            "/user/local/sbin"
        ]

        #####
        # Look for the mount command
        mountFound = False
        for path in paths:
            possibleFullPath = os.path.join(path, "mount")
            if os.path.exists(possibleFullPath):
                self.mountPath = possibleFullPath
                mountFound = True

        if not mountFound:
            raise SystemToolNotAvailable("Cannot find mount command...")

        #####
        # Look for the umount command
        umountFound = False
        for path in paths:
            possibleFullPath = os.path.join(path, "umount")
            if os.path.exists(possibleFullPath):
                self.umountPath = possibleFullPath
                umountFound = True

        if not umountFound:
            raise SystemToolNotAvailable("Cannot find umount command...")

        #####
        # Figure out if this method was successfull or not.
        if mountFound and umountFound:
            success = True

        return success

    ###########################################################################

    def buildCommand(self):
        """
        Build a command based on the "fstype" passed in.

        For more options on the tmpfs filesystem, check the mount manpage.

        @author: Roy Nielsen
        """
        command = None
        if self.fstype == "ramfs":
            command = [self.mountPath, "-t", "ramfs"]
        elif self.fstype == "tmpfs":
            options = ["size=" + str(self.diskSize) + "m"]
            options.append("uid=" + str(self.uid))
            options.append("gid=" + str(self.gid))
            options.append("mode=" + str(self.mode))
            """
            try:
                options.append(self.nr_inodes)
            except AttributeError:
                pass
            try:
                options.append("nr_blocks=" + str(self.nr_blocks))
            except AttributeError:
                pass
            """

            command = [
                self.mountPath, "-t", "tmpfs", "-o", ",".join(options),
                "tmpfs", self.mntPoint
            ]
            self.logger.log(lp.DEBUG, "command: " + str(command))
            #/bin/mount -t tmpfs  -o size=500m,uid=0,gid=0,mode=700 /tmp/tmp0gnLNt
        return command

    ###########################################################################

    def _format(self):
        """
        One can't really format a tmpfs disk, so this will mimic a format 
        by unmounting an recreating the disk.

        @author: Roy Nielsen
        """
        success = False
        successOne = self.umount()
        successTwo = self._mount()
        if successOne and successTwo:
            success = True
        return success

    ###########################################################################

    def _mount(self):
        """
        Mount the disk

        @author: Roy Nielsen
        """
        success = False
        command = self.buildCommand()
        self.logger.log(lp.WARNING, "Command: " + str(command))
        if self.runWith.setCommand(command):
            self.logger.log(lp.DEBUG, "All is Stars, Rainbows and Unicorns...")
            output, error, returncode = self.runWith.communicate()
            self.logger.log(lp.DEBUG, "All is Stars, Rainbows and Unicorns...")
        else:
            raise Exception(
                "Cannot Grok Command.................................")
        self.logger.log(lp.DEBUG, "output    : " + str(output))
        self.logger.log(lp.DEBUG, "error     : " + str(error))
        self.logger.log(lp.DEBUG, "returncode: " + str(returncode))

        if not error:
            success = True
            self.logger.log(lp.DEBUG, "Damn it Jim! The Damn Thing worked!!!")
        self.getNlogData()
        return success

    ###########################################################################

    def remount(self,
                size=0,
                mountpoint="",
                mode=700,
                uid=None,
                gid=None,
                nr_inodes=None,
                nr_blocks=None):
        """
        Use the tmpfs ability to be remounted with different options

        If bad input is given, the previous values will be used.

        @author: Roy Nielsen
        """
        #####
        # Input Validation:
        #####
        # tmpfs is the only viable ramdisk that handles remounting ok.
        # this includes mouting tmpfs with msdos, ext2,3,4, etc.
        if not self.fstype == "tmpfs":
            raise BadRamdiskArguments("Can only use 'remount' with " + \
                                           "tmpfs...")
        if size and isinstance(size, int):
            self.diskSize = size

        if mountpoint and isinstance(mountpoint, type.string):
            self.mntPoint = mountpoint

        if mode and isinstance(mode, int):
            self.mode = mode

        if uid and isinstance(uid, int):
            self.uid = uid

        if gid and isinstance(gid, int):
            self.gid = gid

        if nr_inodes and isinstance(nr_inodes, (int, long)):
            self.nr_inodes = nr_inodes

        if nr_blocks and isinstance(nr_blocks, (int, long)):
            self.nr_blocks = nr_blocks

        self.buildCommand()
        self._mount()

    ###########################################################################

    def unmount(self):
        """
        Unmount the disk

        @author: Roy Nielsen
        """
        success = False

        command = [self.umountPath, self.mntPoint]
        self.runWith.setCommand(command)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True

        return success

    ###########################################################################

    def umount(self):
        """
        Unmount the disk

        @author: Roy Nielsen
        """
        success = False

        success = self.unmount()
        return success

    ###########################################################################

    def detach(self):
        """
        Unmount the disk

        @author: Roy Nielsen
        """
        success = False

        success = self.umount()

        return success

    ###########################################################################

    def __isMemoryAvailable(self):
        """
        Check to make sure there is plenty of memory of the size passed in
        before creating the ramdisk

        Must be over-ridden to provide OS/Method specific functionality

        @author: Roy Nielsen
        """
        #mem_free = psutil.phymem_usage()[2]

        #print "Memory free = " + str(mem_free)
        success = False
        return success

    ###########################################################################

    def getVersion(self):
        """
        Getter for the version of the ramdisk

        @author: Roy Nielsen
        """
        return self.module_version
示例#8
0
class RamDisk(RamDiskTemplate) :
    """
    Class to manage a ramdisk

    utilizes commands I've used to manage ramdisks

    Size passed in must be passed in as 1Mb chunks

    @param: size - size of the ramdisk to create - must have a value on the Mac
                   or the creation will fail.
    @param: mountpoint - where to mount the disk, if left empty, will mount
                         on locaiton created by tempfile.mkdtemp.
    @param: message_level - level at which to log.

    @author: Roy Nielsen
    """
    def __init__(self, size=0, mountpoint="", logger=False) :
        """
        Constructor
        """
        super(RamDisk, self).__init__(size, mountpoint, logger)

        if not getOsFamily() == "darwin":
            raise NotValidForThisOS("This ramdisk is only viable for a MacOS.")

        self.module_version = '20160225.125554.540679'

        #####
        # Initialize the RunWith helper for executing shelled out commands.
        self.runWith = RunWith(self.logger)

        #####
        # Calculating the size of ramdisk in 1Mb chunks
        self.diskSize = str(int(size) * 1024 * 1024 / 512)

        self.hdiutil = "/usr/bin/hdiutil"
        self.diskutil = "/usr/sbin/diskutil"

        #####
        # Just /dev/disk<#>
        self.myRamdiskDev = ""

        #####
        # should take the form of /dev/disk2s1, where disk 2 is the assigned
        # disk and s1 is the slice, or partition number.  While just /dev/disk2
        # is good for some things, others will need the full path to the
        # device, such as formatting the disk.
        self.devPartition = ""

        #####
        # Indicate if the ramdisk is "mounted" in the Mac sense - attached,
        # but not mounted.
        self.mounted = False

        success = False

        #####
        # Passed in disk size must have a non-default value
        if not self.diskSize == 0 :
            success  = True
        #####
        # Checking to see if memory is availalbe...
        if not self.__isMemoryAvailable() :
            self.logger.log(lp.DEBUG, "Physical memory not available to create ramdisk.")
            success = False
        else:
            success = True

        if success :

            #####
            # If a mountpoint is passed in, use that, otherwise, set up for a
            # random mountpoint.
            if mountpoint:
                self.logger.log(lp.INFO, "\n\n\n\tMOUNTPOINT: " + str(mountpoint) + "\n\n\n")
                self.mntPoint = mountpoint
                #####
                # eventually have checking to make sure that directory
                # doesn't already exist, and have data in it.
            else :
                #####
                # If a mountpoint is not passed in, create a randomized
                # mount point.
                self.logger.log(lp.DEBUG, "Attempting to acquire a radomized mount " + \
                           "point. . .")
                if not self.getRandomizedMountpoint() :
                    success = False

            #####
            # The Mac has a more complicated method of managing ramdisks...
            if success:
                #####
                # Attempt to create the ramdisk
                if not self.__create():
                    success = False
                    self.logger.log(lp.WARNING, "Create appears to have failed..")
                else:
                    #####
                    # Ramdisk created, try mounting it.
                    if not self.__mount():
                        success = False
                        self.logger.log(lp.WARNING, "Mount appears to have failed..")
                    else:
                        #####
                        # Filessystem journal will only slow the ramdisk down...
                        # No need to keep it as when the journal is unmounted
                        # all memory is de-allocated making it impossible to do
                        # forensics on the volume.
                        if not self.__remove_journal():
                            success = False
                            self.logger.log(lp.WARNING, "Remove journal " + \
                                            "appears to have failed..")

        self.success = success
        if success:
            self.logger.log(lp.INFO, "Mount point: " + str(self.mntPoint))
            self.logger.log(lp.INFO, "Device: " + str(self.myRamdiskDev))
        self.logger.log(lp.INFO, "Success: " + str(self.success))
            

    ###########################################################################

    def __create(self) :
        """
        Create a ramdisk device

        @author: Roy Nielsen
        """
        retval = None
        reterr = None
        success = False
        #####
        # Create the ramdisk and attach it to a device.
        cmd = [self.hdiutil, "attach", "-nomount", "ram://" + self.diskSize]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()

        if reterr:
            success = False
            raise Exception("Error trying to create ramdisk(" + \
                            str(reterr).strip() + ")")
        else:
            self.myRamdiskDev = retval.strip()
            self.logger.log(lp.DEBUG, "Device: \"" + str(self.myRamdiskDev) + "\"")
            success = True
        self.logger.log(lp.DEBUG, "Success: " + str(success) + " in __create")
        return success

    ###########################################################################

    def getData(self):
        """
        Getter for mount data, and if the mounting of a ramdisk was successful

        Does not print or log the data.

        @author: Roy Nielsen
        """
        return (self.success, str(self.mntPoint), str(self.myRamdiskDev))

    ###########################################################################

    def getNlogData(self):
        """
        Getter for mount data, and if the mounting of a ramdisk was successful

        Also logs the data.

        @author: Roy Nielsen
        """
        self.logger.log(lp.INFO, "Success: " + str(self.success))
        self.logger.log(lp.INFO, "Mount point: " + str(self.mntPoint))
        self.logger.log(lp.INFO, "Device: " + str(self.myRamdiskDev))
        return (self.success, str(self.mntPoint), str(self.myRamdiskDev))

    ###########################################################################

    def getNprintData(self):
        """
        Getter for mount data, and if the mounting of a ramdisk was successful
        """
        print "Success: " + str(self.success)
        print "Mount point: " + str(self.mntPoint)
        print "Device: " + str(self.myRamdiskDev)
        return (self.success, str(self.mntPoint), str(self.myRamdiskDev))

    ###########################################################################

    def __mount(self) :
        """
        Mount the disk - for the Mac, just run self.__attach

        @author: Roy Nielsen
        """
        success = False
        success = self.__attach()
        if success:
            self.mounted = True
        return success

    ###########################################################################

    def __attach(self):
        """
        Attach the device so it can be formatted

        @author: Roy Nielsen
        """
        success = False
        #####
        # Attempt to partition the disk.
        if self.__partition():
            success = True
            #####
            # eraseVolume format name device
            if self.mntPoint:
                #####
                # "Mac" unmount (not eject)
                cmd = [self.diskutil, "unmount", self.myRamdiskDev + "s1"]
                self.runWith.setCommand(cmd)
                self.runWith.communicate()
                retval, reterr, retcode = self.runWith.getNlogReturns()

                if not reterr:
                    success = True

                if success:
                    #####
                    # remount to self.mntPoint
                    cmd = [self.diskutil, "mount", "-mountPoint",
                           self.mntPoint, self.devPartition]
                    self.runWith.setCommand(cmd)
                    self.runWith.communicate()
                    retval, reterr, retcode = self.runWith.getNlogReturns()

                    if not reterr:
                        success = True
            self.runWith.getNlogReturns()
            self.getData()
            self.logger.log(lp.DEBUG, "Success: " + str(success) + " in __mount")
        return success

    ###########################################################################

    def __remove_journal(self) :
        """
        Having a journal in ramdisk makes very little sense.  Remove the journal
        after creating the ramdisk device

        cmd = ["/usr/sbin/diskutil", "disableJournal", "force", myRamdiskDev]

        using "force" doesn't work on a mounted filesystem, without it, the
        command will work on a mounted file system

        @author: Roy Nielsen
        """
        success = False
        cmd = [self.diskutil, "disableJournal", self.myRamdiskDev + "s1"]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        self.logger.log(lp.DEBUG, "Success: " + str(success) + " in __remove_journal")
        return success

    ###########################################################################

    def unionOver(self, target="", fstype="hfs", nosuid=None, noowners=True,
                        noatime=None, nobrowse=None):
        """
        Use unionfs to mount a ramdisk on top of a location already on the
        filesystem.

        @parameter: target - where to lay the ramdisk on top of, ie the lower
                             filesystem layer.

        @parameter: nosuid - from the mount manpage: "Do not allow
                             set-user-identifier bits to take effect.

        @parameter: fstype - What supported filesystem to use.

        @parameter: noowners - From the mount manpage: "Ignore the ownership
                               field for the entire volume.  This causes all
                               objects to appear as owned by user ID 99 and
                               group ID 99.  User ID 99 is interpreted as
                               the current effective user ID, while group
                               99 is used directly and translates to "unknown".

        @parameter: noatime - from the mount manpage: "Do not update the file
                              access time when reading from a file.  This
                              option is useful on file systems where there are
                              large numbers of files and performance is more
                              critical than updating the file access time
                              (which is rarely ever important).

        @parameter: nobrowse - from the mount manpage: "This option indicates
                               that the mount point should not be visible via
                               the GUI (i.e., appear on the Desktop as a
                               separate volume).

        @author: Roy Nielsen
        """
        success = False

        #####
        # If the ramdisk is mounted, unmount it (not eject...)
        if self.mounted:
            self._unmount()

        #####
        # Create the target directory if it doesn't exist yet...
        if not os.path.isdir(target):
            if os.path.isfile(target):
                shutil.move(target, target + ".bak")
            os.makedirs(target)

        #####
        # Put together the command if the base options are given
        if fstype and self.devPartition:
            #####
            # Compile the options
            options = "union"
            if nosuid:
                options = options + ",nosuid"
            if noowners:
                options = options + ",noowners"
            if noatime:
                options = options + ",noatime"
            if nobrowse:
                options = options + ",nobrowse"
            #####
            # Put the command together.
            cmd = ["/sbin/mount", "-t", str(fstype), "-o", options,
                   self.devPartition, target]

            #####
            # Run the command
            self.runWith.setCommand(cmd)
            self.runWith.communicate()
            retval, reterr, retcode = self.runWith.getNlogReturns()
            if not reterr:
                success = True

        return success

    ###########################################################################

    def unmount(self) :
        """
        Unmount the disk - same functionality as __eject on the mac

        @author: Roy Nielsen
        """
        success = False
        if self.eject() :
            success = True
        self.logger.log(lp.DEBUG, "Success: " + str(success) + " in unmount")
        return success

    ###########################################################################

    def detach(self) :
        """
        Unmount the disk - same functionality as __eject on the mac

        @author: Roy Nielsen
        """
        success = False
        if self.eject() :
            success = True
        self.logger.log(lp.DEBUG, "Success: " + str(success) + " in detach")
        return success

    ###########################################################################

    def _unmount(self) :
        """
        Unmount in the Mac sense - ie, the device is still accessible.

        @author: Roy Nielsen
        """
        success = False
        cmd = [self.diskutil, "unmount", self.devPartition]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        return success

    ###########################################################################

    def _mount(self) :
        """
        Mount in the Mac sense - ie, mount an already accessible device to
        a mount point.

        @author: Roy Nielsen
        """
        success = False
        cmd = [self.diskutil, "mount", "-mountPoint", self.mntPoint, self.devPartition]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        return success

    ###########################################################################

    def eject(self) :
        """
        Eject the ramdisk

        Detach (on the mac) is a better solution than unmount and eject
        separately.. Besides unmounting the disk, it also stops any processes
        related to the mntPoint

        @author: Roy Nielsen
        """
        success = False
        cmd = [self.hdiutil, "detach", self.myRamdiskDev]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        self.runWith.getNlogReturns()

        return success

    ###########################################################################

    def _format(self) :
        """
        Format the ramdisk

        @author: Roy Nielsen
        """
        success = False
        #####
        # Unmount (in the mac sense - the device should still be accessible)
        # Cannot format the drive unless only the device is accessible.
        success = self._unmount()
        #####
        # Format the disk (partition)
        cmd = ["/sbin/newfs_hfs", "-v", "ramdisk", self.devPartition]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        #####
        # Re-mount the disk
        self._mount()
        return success

    ###########################################################################

    def __partition(self) :
        """
        Partition the ramdisk (mac specific)

        @author: Roy Nielsen
        """
        success=False
        size = str(int(self.diskSize)/(2*1024))
        cmd = [self.diskutil, "partitionDisk", self.myRamdiskDev, str(1),
               "MBR", "HFS+", "ramdisk", str(size) + "M"]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        if success:
            #####
            # Need to get the partition device out of the output to assign to
            # self.devPartition
            for line in retval.split("\n"):
                if re.match("^Initialized (\S+)\s+", line):
                    linematch = re.match("Initialized\s+(\S+)", line)
                    rdevPartition = linematch.group(1)
                    self.devPartition = re.sub("rdisk", "disk", rdevPartition)
                    break

        self.runWith.getNlogReturns()

        return success

    ###########################################################################

    def __isMemoryAvailable(self) :
        """
        Check to make sure there is plenty of memory of the size passed in
        before creating the ramdisk

        Best method to do this on the Mac is to get the output of "top -l 1"
        and re.search("unused\.$", line)

        @author: Roy Nielsen
        """
        #mem_free = psutil.phymem_usage()[2]

        #print "Memory free = " + str(mem_free)
        success = False
        found = False
        almost_size = 0
        size = 0
        self.free = 0
        line = ""
        freeMagnitude = None

        #####
        # Set up and run the command
        cmd = ["/usr/bin/top", "-l", "1"]

        proc = Popen(cmd, stdout=PIPE, stderr=PIPE)

        while True:
            line = proc.stdout.readline().strip()
            #####
            # Split on spaces
            line = line.split()
            #####
            # Get the last item in the list
            found = line[-1]
            almost_size = line[:-1]
            size = almost_size[-1]

            found = found.strip()
            #almost_size = almost_size.strip()
            size = size.strip()

            self.logger.log(lp.INFO, "size: " + str(size))
            self.logger.log(lp.INFO, "found: " + str(found))

            if re.search("unused", found) or re.search("free", found):
                #####
                # Found the data we wanted, stop the search.
                break
        proc.kill()

        #####
        # Find the numerical value and magnitute of the ramdisk
        if size:
            sizeCompile = re.compile("(\d+)(\w+)")

            split_size = sizeCompile.search(size)
            freeNumber = split_size.group(1)
            freeMagnitude = split_size.group(2)

            if re.match("^\d+$", freeNumber.strip()):
                if re.match("^\w$", freeMagnitude.strip()):
                    if freeMagnitude:
                        #####
                        # Calculate the size of the free memory in Megabytes
                        if re.search("G", freeMagnitude.strip()):
                            self.free = 1024 * int(freeNumber)
                            self.free = str(self.free)
                        elif re.search("M", freeMagnitude.strip()):
                            self.free = freeNumber
        self.logger.log(lp.DEBUG, "free: " + str(self.free))
        self.logger.log(lp.DEBUG, "Size requested: " + str(self.diskSize))
        if int(self.free) > int(self.diskSize)/(2*1024):
            success = True
        print str(self.free)
        print str(success)
        return success

    ###########################################################################

    def getDevice(self):
        """
        Getter for the device name the ramdisk is using

        @author: Roy Nielsen
        """
        return self.myRamdiskDev

    ###########################################################################

    def setDevice(self, device=None):
        """
        Setter for the device so it can be ejected.

        @author: Roy Nielsen
        """
        if device:
            self.myRamdiskDev = device
        else:
            raise Exception("Problem trying to set the device..")

    ###########################################################################

    def getVersion(self):
        """
        Getter for the version of the ramdisk

        @author: Roy Nielsen
        """
        return self.module_version
示例#9
0
class RamDisk(RamDiskTemplate) :
    """
    Class to manage a ramdisk

    utilizes commands I've used to manage ramdisks

    Size passed in must be passed in as 1Mb chunks

    @param: size - size of the ramdisk to create - must have a value on the Mac
                   or the creation will fail.
    @param: mountpoint - where to mount the disk, if left empty, will mount
                         on locaiton created by tempfile.mkdtemp.
    @param: message_level - level at which to log.

    @author: Roy Nielsen
    """
    def __init__(self, size=0, mountpoint="", logger=False) :
        """
        Constructor
        """
        super(RamDisk, self).__init__(size, mountpoint, logger)

        if not getOsFamily() == "darwin":
            raise NotValidForThisOS("This ramdisk is only viable for a MacOS.")

        self.module_version = '20160225.125554.540679'

        #####
        # Initialize the RunWith helper for executing shelled out commands.
        self.runWith = RunWith(self.logger)

        #####
        # Calculating the size of ramdisk in 1Mb chunks
        self.diskSize = str(int(size) * 1024 * 1024 / 512)

        self.hdiutil = "/usr/bin/hdiutil"
        self.diskutil = "/usr/sbin/diskutil"

        #####
        # Just /dev/disk<#>
        self.myRamdiskDev = ""

        #####
        # should take the form of /dev/disk2s1, where disk 2 is the assigned
        # disk and s1 is the slice, or partition number.  While just /dev/disk2
        # is good for some things, others will need the full path to the
        # device, such as formatting the disk.
        self.devPartition = ""

        #####
        # Indicate if the ramdisk is "mounted" in the Mac sense - attached,
        # but not mounted.
        self.mounted = False

        success = False

        #####
        # Passed in disk size must have a non-default value
        if not self.diskSize == 0 :
            success  = True
        #####
        # Checking to see if memory is availalbe...
        if not self.__isMemoryAvailable() :
            self.logger.log(lp.DEBUG, "Physical memory not available to create ramdisk.")
            success = False
        else:
            success = True

        if success :

            #####
            # If a mountpoint is passed in, use that, otherwise, set up for a
            # random mountpoint.
            if mountpoint:
                self.logger.log(lp.INFO, "\n\n\n\tMOUNTPOINT: " + str(mountpoint) + "\n\n\n")
                self.mntPoint = mountpoint
                #####
                # eventually have checking to make sure that directory
                # doesn't already exist, and have data in it.
            else :
                #####
                # If a mountpoint is not passed in, create a randomized
                # mount point.
                self.logger.log(lp.DEBUG, "Attempting to acquire a radomized mount " + \
                           "point. . .")
                if not self.getRandomizedMountpoint() :
                    success = False

            #####
            # The Mac has a more complicated method of managing ramdisks...
            if success:
                #####
                # Attempt to create the ramdisk
                if not self.__create():
                    success = False
                    self.logger.log(lp.WARNING, "Create appears to have failed..")
                else:
                    #####
                    # Ramdisk created, try mounting it.
                    if not self.__mount():
                        success = False
                        self.logger.log(lp.WARNING, "Mount appears to have failed..")
                    else:
                        #####
                        # Filessystem journal will only slow the ramdisk down...
                        # No need to keep it as when the journal is unmounted
                        # all memory is de-allocated making it impossible to do
                        # forensics on the volume.
                        if not self.__remove_journal():
                            success = False
                            self.logger.log(lp.WARNING, "Remove journal " + \
                                            "appears to have failed..")

        self.success = success
        if success:
            self.logger.log(lp.INFO, "Mount point: " + str(self.mntPoint))
            self.logger.log(lp.INFO, "Device: " + str(self.myRamdiskDev))
        self.logger.log(lp.INFO, "Success: " + str(self.success))
            

    ###########################################################################

    def __create(self) :
        """
        Create a ramdisk device

        @author: Roy Nielsen
        """
        retval = None
        reterr = None
        success = False
        #####
        # Create the ramdisk and attach it to a device.
        cmd = [self.hdiutil, "attach", "-nomount", "ram://" + self.diskSize]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()

        if reterr:
            success = False
            raise Exception("Error trying to create ramdisk(" + \
                            str(reterr).strip() + ")")
        else:
            self.myRamdiskDev = retval.strip()
            self.logger.log(lp.DEBUG, "Device: \"" + str(self.myRamdiskDev) + "\"")
            success = True
        self.logger.log(lp.DEBUG, "Success: " + str(success) + " in __create")
        return success

    ###########################################################################

    def getData(self):
        """
        Getter for mount data, and if the mounting of a ramdisk was successful

        Does not print or log the data.

        @author: Roy Nielsen
        """
        return (self.success, str(self.mntPoint), str(self.myRamdiskDev))

    ###########################################################################

    def getNlogData(self):
        """
        Getter for mount data, and if the mounting of a ramdisk was successful

        Also logs the data.

        @author: Roy Nielsen
        """
        self.logger.log(lp.INFO, "Success: " + str(self.success))
        self.logger.log(lp.INFO, "Mount point: " + str(self.mntPoint))
        self.logger.log(lp.INFO, "Device: " + str(self.myRamdiskDev))
        return (self.success, str(self.mntPoint), str(self.myRamdiskDev))

    ###########################################################################

    def getNprintData(self):
        """
        Getter for mount data, and if the mounting of a ramdisk was successful
        """
        print "Success: " + str(self.success)
        print "Mount point: " + str(self.mntPoint)
        print "Device: " + str(self.myRamdiskDev)
        return (self.success, str(self.mntPoint), str(self.myRamdiskDev))

    ###########################################################################

    def __mount(self) :
        """
        Mount the disk - for the Mac, just run self.__attach

        @author: Roy Nielsen
        """
        success = False
        success = self.__attach()
        if success:
            self.mounted = True
        return success

    ###########################################################################

    def __attach(self):
        """
        Attach the device so it can be formatted

        @author: Roy Nielsen
        """
        success = False
        #####
        # Attempt to partition the disk.
        if self.__partition():
            success = True
            #####
            # eraseVolume format name device
            if self.mntPoint:
                #####
                # "Mac" unmount (not eject)
                cmd = [self.diskutil, "unmount", self.myRamdiskDev + "s1"]
                self.runWith.setCommand(cmd)
                self.runWith.communicate()
                retval, reterr, retcode = self.runWith.getNlogReturns()

                if not reterr:
                    success = True

                if success:
                    #####
                    # remount to self.mntPoint
                    cmd = [self.diskutil, "mount", "-mountPoint",
                           self.mntPoint, self.devPartition]
                    self.runWith.setCommand(cmd)
                    self.runWith.communicate()
                    retval, reterr, retcode = self.runWith.getNlogReturns()

                    if not reterr:
                        success = True
            self.runWith.getNlogReturns()
            self.getData()
            self.logger.log(lp.DEBUG, "Success: " + str(success) + " in __mount")
        return success

    ###########################################################################

    def __remove_journal(self) :
        """
        Having a journal in ramdisk makes very little sense.  Remove the journal
        after creating the ramdisk device

        cmd = ["/usr/sbin/diskutil", "disableJournal", "force", myRamdiskDev]

        using "force" doesn't work on a mounted filesystem, without it, the
        command will work on a mounted file system

        @author: Roy Nielsen
        """
        success = False
        cmd = [self.diskutil, "disableJournal", self.myRamdiskDev + "s1"]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        self.logger.log(lp.DEBUG, "Success: " + str(success) + " in __remove_journal")
        return success

    ###########################################################################

    def unionOver(self, target="", fstype="hfs", nosuid=None, noowners=True,
                        noatime=None, nobrowse=None):
        """
        Use unionfs to mount a ramdisk on top of a location already on the
        filesystem.

        @parameter: target - where to lay the ramdisk on top of, ie the lower
                             filesystem layer.

        @parameter: nosuid - from the mount manpage: "Do not allow
                             set-user-identifier bits to take effect.

        @parameter: fstype - What supported filesystem to use.

        @parameter: noowners - From the mount manpage: "Ignore the ownership
                               field for the entire volume.  This causes all
                               objects to appear as owned by user ID 99 and
                               group ID 99.  User ID 99 is interpreted as
                               the current effective user ID, while group
                               99 is used directly and translates to "unknown".

        @parameter: noatime - from the mount manpage: "Do not update the file
                              access time when reading from a file.  This
                              option is useful on file systems where there are
                              large numbers of files and performance is more
                              critical than updating the file access time
                              (which is rarely ever important).

        @parameter: nobrowse - from the mount manpage: "This option indicates
                               that the mount point should not be visible via
                               the GUI (i.e., appear on the Desktop as a
                               separate volume).

        @author: Roy Nielsen
        """
        success = False

        #####
        # If the ramdisk is mounted, unmount it (not eject...)
        if self.mounted:
            self._unmount()

        #####
        # Create the target directory if it doesn't exist yet...
        if not os.path.isdir(target):
            if os.path.isfile(target):
                shutil.move(target, target + ".bak")
            os.makedirs(target)

        #####
        # Put together the command if the base options are given
        if fstype and self.devPartition:
            #####
            # Compile the options
            options = "union"
            if nosuid:
                options = options + ",nosuid"
            if noowners:
                options = options + ",noowners"
            if noatime:
                options = options + ",noatime"
            if nobrowse:
                options = options + ",nobrowse"
            #####
            # Put the command together.
            cmd = ["/sbin/mount", "-t", str(fstype), "-o", options,
                   self.devPartition, target]

            #####
            # Run the command
            self.runWith.setCommand(cmd)
            self.runWith.communicate()
            retval, reterr, retcode = self.runWith.getNlogReturns()
            if not reterr:
                success = True

        return success

    ###########################################################################

    def unmount(self) :
        """
        Unmount the disk - same functionality as __eject on the mac

        @author: Roy Nielsen
        """
        success = False
        if self.eject() :
            success = True
        self.logger.log(lp.DEBUG, "Success: " + str(success) + " in unmount")
        return success

    ###########################################################################

    def detach(self) :
        """
        Unmount the disk - same functionality as __eject on the mac

        @author: Roy Nielsen
        """
        success = False
        if self.eject() :
            success = True
        self.logger.log(lp.DEBUG, "Success: " + str(success) + " in detach")
        return success

    ###########################################################################

    def _unmount(self) :
        """
        Unmount in the Mac sense - ie, the device is still accessible.

        @author: Roy Nielsen
        """
        success = False
        cmd = [self.diskutil, "unmount", self.devPartition]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        return success

    ###########################################################################

    def _mount(self) :
        """
        Mount in the Mac sense - ie, mount an already accessible device to
        a mount point.

        @author: Roy Nielsen
        """
        success = False
        cmd = [self.diskutil, "mount", "-mountPoint", self.mntPoint, self.devPartition]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        return success

    ###########################################################################

    def eject(self) :
        """
        Eject the ramdisk

        Detach (on the mac) is a better solution than unmount and eject
        separately.. Besides unmounting the disk, it also stops any processes
        related to the mntPoint

        @author: Roy Nielsen
        """
        success = False
        cmd = [self.hdiutil, "detach", self.myRamdiskDev]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        self.runWith.getNlogReturns()

        return success

    ###########################################################################

    def _format(self) :
        """
        Format the ramdisk

        @author: Roy Nielsen
        """
        success = False
        #####
        # Unmount (in the mac sense - the device should still be accessible)
        # Cannot format the drive unless only the device is accessible.
        success = self._unmount()
        #####
        # Format the disk (partition)
        cmd = ["/sbin/newfs_hfs", "-v", "ramdisk", self.devPartition]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        #####
        # Re-mount the disk
        self._mount()
        return success

    ###########################################################################

    def __partition(self) :
        """
        Partition the ramdisk (mac specific)

        @author: Roy Nielsen
        """
        success=False
        size = str(int(self.diskSize)/(2*1024))
        cmd = [self.diskutil, "partitionDisk", self.myRamdiskDev, str(1),
               "MBR", "HFS+", "ramdisk", str(size) + "M"]
        self.runWith.setCommand(cmd)
        self.runWith.communicate()
        retval, reterr, retcode = self.runWith.getNlogReturns()
        if not reterr:
            success = True
        if success:
            #####
            # Need to get the partition device out of the output to assign to
            # self.devPartition
            for line in retval.split("\n"):
                if re.match("^Initialized (\S+)\s+", line):
                    linematch = re.match("Initialized\s+(\S+)", line)
                    rdevPartition = linematch.group(1)
                    self.devPartition = re.sub("rdisk", "disk", rdevPartition)
                    break

        self.runWith.getNlogReturns()

        return success

    ###########################################################################

    def __isMemoryAvailable(self) :
        """
        Check to make sure there is plenty of memory of the size passed in
        before creating the ramdisk

        Best method to do this on the Mac is to get the output of "top -l 1"
        and re.search("unused\.$", line)

        @author: Roy Nielsen
        """
        #mem_free = psutil.phymem_usage()[2]

        #print "Memory free = " + str(mem_free)
        success = False
        found = False
        almost_size = 0
        size = 0
        self.free = 0
        line = ""
        freeMagnitude = None

        #####
        # Set up and run the command
        cmd = ["/usr/bin/top", "-l", "1"]

        proc = Popen(cmd, stdout=PIPE, stderr=PIPE)

        while True:
            line = proc.stdout.readline().strip()
            #####
            # Split on spaces
            line = line.split()
            #####
            # Get the last item in the list
            found = line[-1]
            almost_size = line[:-1]
            size = almost_size[-1]

            found = found.strip()
            #almost_size = almost_size.strip()
            size = size.strip()

            self.logger.log(lp.INFO, "size: " + str(size))
            self.logger.log(lp.INFO, "found: " + str(found))

            if re.search("unused", found) or re.search("free", found):
                #####
                # Found the data we wanted, stop the search.
                break
        proc.kill()

        #####
        # Find the numerical value and magnitute of the ramdisk
        if size:
            sizeCompile = re.compile("(\d+)(\w+)")

            split_size = sizeCompile.search(size)
            freeNumber = split_size.group(1)
            freeMagnitude = split_size.group(2)

            if re.match("^\d+$", freeNumber.strip()):
                if re.match("^\w$", freeMagnitude.strip()):
                    if freeMagnitude:
                        #####
                        # Calculate the size of the free memory in Megabytes
                        if re.search("G", freeMagnitude.strip()):
                            self.free = 1024 * int(freeNumber)
                            self.free = str(self.free)
                        elif re.search("M", freeMagnitude.strip()):
                            self.free = freeNumber
        self.logger.log(lp.DEBUG, "free: " + str(self.free))
        self.logger.log(lp.DEBUG, "Size requested: " + str(self.diskSize))
        if int(self.free) > int(self.diskSize)/(2*1024):
            success = True
        print str(self.free)
        print str(success)
        return success

    ###########################################################################

    def getDevice(self):
        """
        Getter for the device name the ramdisk is using

        @author: Roy Nielsen
        """
        return self.myRamdiskDev

    ###########################################################################

    def setDevice(self, device=None):
        """
        Setter for the device so it can be ejected.

        @author: Roy Nielsen
        """
        if device:
            self.myRamdiskDev = device
        else:
            raise Exception("Problem trying to set the device..")

    ###########################################################################

    def getVersion(self):
        """
        Getter for the version of the ramdisk

        @author: Roy Nielsen
        """
        return self.module_version
示例#10
0
class MacOSUser(ParentManageUser):
    '''Class to manage users on Mac OS.
    
    #----- Getters
    @method findUniqueUid
    @method uidTaken
    @method getUser
    @method getUserShell
    @method getUserComment
    @method getUserUid
    @method getUserPriGid
    @method getUserHomeDir
    @method isUserInstalled
    @method isUserInGroup
    @method authenticate
    #----- Setters
    @method createStandardUser
    @method createBasicUser
    @method setUserShell
    @method setUserComment
    @method setUserUid
    @method setUserPriGid
    @method setUserHomeDir
    @method createHomeDirectory
    @method addUserToGroup
    @method setUserPassword
    @method fixUserHome
    #----- User removal
    @method rmUser
    @method rmUserFromGroup
    @method rmUserHome
    
    @author: Roy Nielsen


    '''
    def __init__(self, **kwargs):
        """
        Variables that can be passed in:
        logger
        userName
        userShell
        userComment
        userUid
        userPriGid
        userHomeDir
        """
        if 'logDispatcher' not in kwargs:
            raise ValueError("Variable 'logDispatcher' a required parameter for " + str(self.__class__.__name__))
        super(MacOSUser, self).__init__(**kwargs)

        self.module_version = '20160225.125554.540679'

        self.dscl = "/usr/bin/dscl"
        self.runWith = RunWith(self.logger)

    #----------------------------------------------------------------------
    # Getters
    #----------------------------------------------------------------------

    def findUniqueUid(self):
        '''We need to make sure to find an unused uid (unique ID) for the user,
           $ dscl . -list /Users UniqueID
        will list all the existing users, an unused number above 500 is good.
        
        @author: Roy Nielsen


        '''
        success = False
        maxUserID = 0
        newUserID = 0
        userList = self.getDscl(".", "-list", "/Users", "UniqueID")

        #####
        # Sort the list, add one to the highest value and return that
        # value
        for user in str(userList).split("\n"):
            if int(user.split()[1]) > maxUserID:
                maxUserID = int(user.split()[1])

        newUserID = str(int(maxUserID + 1))

        return newUserID

    #----------------------------------------------------------------------

    def uidTaken(self, uid):
        '''See if the UID requested has been taken.  Only approve uid's over 1k
           $ dscl . -list /Users UniqueID
        
        @author: Roy Nielsen

        :param uid: 

        '''
        uidList = []
        success = False
        userList = self.getDscl(".", "-list", "/Users", "UniqueID")

        #####
        # Sort the list, add one to the highest value and return that
        # value
        for user in str(userList).split("\n"):
            uidList.append(str(user.split()[1]))

        if str(uid) in uidList:
            success = True

        return success

    #----------------------------------------------------------------------

    def getUser(self, userName=""):
        '''

        :param userName:  (Default value = "")

        '''
        userInfo = False
        if self.isSaneUserName(userName):
            output = self.getDscl(".", "read", "/Users/" + str(userName), "RecordName")
            try:
                userInfo = output.split()[1]
            except (KeyError, IndexError) as err:
                self.logger.log(lp.INFO, "Error attempting to find user" + \
                                         str(userName) + " in the " + \
                                         "directory service.")
        else:
            raise BadUserInfoError("Need a valid user name...")

        return userInfo

    #----------------------------------------------------------------------

    def getUserShell(self, userName=""):
        '''

        :param userName:  (Default value = "")

        '''
        userShell = False
        if self.isSaneUserName(userName):
            output = self.getDscl(".", "read", "/Users/" + str(userName), "UserShell")
            try:
                userShell = output.split()[1]
            except (KeyError, IndexError) as err:
                self.logger.log(lp.INFO, "Error attempting to find user" + \
                                         str(userName) + " in the " + \
                                         "directory service.")
        else:
            raise BadUserInfoError("Need a valid user name...")

        return userShell

    #----------------------------------------------------------------------

    def getUserComment(self, userName=""):
        '''

        :param userName:  (Default value = "")

        '''
        userComment = False
        if self.isSaneUserName(userName):
            #####
            # Need to process the output to get the right information due to a
            # spurrious "\n" in the output
            output = self.getDscl(".", "read", "/Users/" + str(userName), "RealName")
            try:
                userComment = output[1]
            except (KeyError, IndexError) as err:
                self.logger.log(lp.INFO, "Error attempting to find user" + \
                                         str(userName) + " in the " + \
                                         "directory service.")
        else:
            raise BadUserInfoError("Need a valid user name...")

        return userComment

    #----------------------------------------------------------------------

    def getUserUid(self, userName=""):
        '''

        :param userName:  (Default value = "")

        '''
        userUid = False
        if self.isSaneUserName(userName):
            output = self.getDscl(".", "read", "/Users/" + str(userName), "UniqueID")
            #####
            # Process to get out the right information....
            try:
                userUid = output.split()[1]
            except (KeyError, IndexError) as err:
                self.logger.log(lp.INFO, "Error attempting to find user" + \
                                         str(userName) + " in the " + \
                                         "directory service.")
        else:
            raise BadUserInfoError("Need a valid user name...")

        return userUid

    #----------------------------------------------------------------------

    def getUserPriGid(self, userName=""):
        '''

        :param userName:  (Default value = "")

        '''
        userPriGid = False
        if self.isSaneUserName(userName):
            output = self.getDscl(".", "read", "/Users/" + str(userName), "PrimaryGroupID")
            #####
            # Process to get out the right information....
            try:
                userPriGid = output.split()[1]
            except (KeyError, IndexError) as err:
                self.logger.log(lp.INFO, "Error attempting to find user" + \
                                         str(userName) + " in the " + \
                                         "directory service.")
        else:
            raise BadUserInfoError("Need a valid user name...")

        return userPriGid

    #----------------------------------------------------------------------

    def getUserHomeDir(self, userName=""):
        '''

        :param userName:  (Default value = "")

        '''
        userHomeDir = False
        if self.isSaneUserName(userName):
            output = self.getDscl(".", "read", "/Users/" + str(userName), "NFSHomeDirectory")
            #####
            # Process to get out the right information....
            try:
                userHomeDir = output.split()[1]
            except (KeyError, IndexError) as err:
                self.logger.log(lp.INFO, "Error attempting to find user" + \
                                         str(userName) + " in the " + \
                                         "directory service.")
        else:
            raise BadUserInfoError("Need a valid user name...")

        return userHomeDir

    #----------------------------------------------------------------------

    def isUserInstalled(self, user=""):
        '''Check if the user "user" is installed
        
        @author Roy Nielsen

        :param user:  (Default value = "")

        '''
        success = False
        if self.isSaneUserName(user):
            cmd = [self.dscl, ".", "-read", "/Users/" + str(user)]
            self.runWith.setCommand(cmd)
            self.runWith.communicate()
            retval, reterr, retcode = self.runWith.getNlogReturns()

            if not reterr:
                success = True

        return success

    #----------------------------------------------------------------------

    def isUserInGroup(self, userName="", groupName=""):
        '''Check if this user is in this group
        
        @author: Roy Nielsen

        :param userName:  (Default value = "")
        :param groupName:  (Default value = "")

        '''
        self.logger.log(lp.DEBUG, "U: " + str(userName))
        self.logger.log(lp.DEBUG, "G: " + str(groupName))
        
        
        success = False
        if self.isSaneUserName(userName) and self.isSaneGroupName(groupName):
            output = self.getDscl(".", "-read", "/Groups/" + groupName, "users")
            self.logger.log(lp.CRITICAL, "Output: " + str(output))
            users = output[1:]
            self.logger.log(lp.CRITICAL, "Users: " + str(users))
            if userName in users:
                success = True
        return success

    #----------------------------------------------------------------------

    def validateUser(self, userName=False, userShell=False, userComment=False,
                     userUid=False, userPriGid=False, userHomeDir=False):
        '''Future functionality... validate that the passed in parameters to the
        class instanciation match.
        
        @author:

        :param userName:  (Default value = False)
        :param userShell:  (Default value = False)
        :param userComment:  (Default value = False)
        :param userUid:  (Default value = False)
        :param userPriGid:  (Default value = False)
        :param userHomeDir:  (Default value = False)

        '''
        sane = False
        #####
        # Look up all user attributes and check that they are accurate.
        # Only check the "SANE" parameters passed in.
        if self.isSaneUserName(userName):
            self.userName = userName
            sane = True
        else:
            raise BadUserInfoError("Need a valid user name...")

        if self.isSaneUserShell(userShell) and sane:
            self.userShell = userShell
        elif not userShell:
            pass
        else:
            sane = False

        if self.isSaneUserComment(userComment) and sane:
            self.userComment = userComment
        elif not userComment:
            pass
        else:
            sane = False

        if self.isSaneUserUid(str(userUid)) and sane:
            self.userUid = self.userUid
        elif not userUid:
            pass
        else:
            sane = False

        if self.isSaneUserPriGid(str(userPriGid)) and sane:
            self.userUid = userUid
        elif not userPriGid:
            pass
        else:
            sane = False

        if self.isSaneUserHomeDir(userHomeDir) and sane:
            self.userHomeDir = userHomeDir
        elif not userHomeDir:
            pass
        else:
            sane = False

        return sane

    def authenticate(self, user="", password=""):
        '''Open a pty to run "su" to see if the password is correct...

        :param user:  (Default value = "")
        :param password:  (Default value = "")

        '''
        authenticated = False

        if not self.isSaneUserName(user) or \
           re.match("^\s+$", password) or not password:
            self.logger.log(lp.INFO, "Cannot pass in empty or bad parameters...")
            self.logger.log(lp.INFO, "user = \"" + str(user) + "\"")
            self.logger.log(lp.INFO, "check password...")
        else:
            output = ""
            internal_command = ["/usr/bin/su", "-", str(user), "-c", "/bin/echo hello world"]
            command = " ".join(internal_command)

            self.logger.log(lp.INFO, "command: " + str(command))

            (master, slave) = pty.openpty()            
            process = Popen(internal_command, stdin=slave, stdout=slave, stderr=slave, shell=False)

            #####
            # Read password prompt
            prompt = os.read(master, 512)

            #####
            # send the password
            os.write(master, password + "\n")

            #####
            # catch the password
            prompt = os.read(master, 512)

            #####
            # catch the output
            output = os.read(master, 512)

            os.close(master)
            os.close(slave)
            process.wait()

            output = output.strip()

            #####
            # Check if valid or not...
            if re.match("^su: Sorry", str(output)):
                authenticated = False
            elif re.match("^hello world", str(output)):
                authenticated = True
            else:
                authenticated = False
            self.logger.log(lp.INFO, "Leaving authenticate method with " + \
                                     "output of: \"" + str(output) + "\"")
        return authenticated

    #----------------------------------------------------------------------
    # Setters
    #----------------------------------------------------------------------

    def createStandardUser(self, userName, password):
        '''Creates a user that has the "next" uid in line to be used, then puts
        in in a group of the same id.  Uses /bin/bash as the standard shell.
        The userComment is left empty.  Primary use is managing a user
        during test automation, when requiring a "user" context.
        
        It does not set a login keychain password as that is created on first
        login to the GUI.
        
        @author: Roy Nielsen

        :param userName: 
        :param password: 

        '''
        self.createBasicUser(userName)
        newUserID = self.findUniqueUid()
        newUserGID = newUserID
        self.setUserUid(userName, newUserID)
        self.setUserPriGid(userName, newUserID)
        self.setUserHomeDir(userName)
        self.setUserShell(userName, "/bin/bash")
        self.setUserPassword(userName, password)
        #####
        # Don't need to set the user login keychain password as it should be
        # created on first login.

    #----------------------------------------------------------------------

    def createBasicUser(self, userName=""):
        '''Create a username with just a moniker.  Allow the system to take care of
        the rest.
        
        Only allow usernames with letters and numbers.
        
        On the MacOS platform, all other steps must also be done.
        
        @author: Roy Nielsen

        :param userName:  (Default value = "")

        '''
        success = False
        reterr = ""
        if isinstance(userName, str)\
           and re.match("^[A-Za-z][A-Za-z0-9]*$", userName):
            cmd = [self.dscl, ".", "-create", "/Users/" + str(userName)]
            self.runWith.setCommand(cmd)
            self.runWith.communicate()
            retval, reterr, retcode = self.runWith.getNlogReturns()

            if not reterr:
                success = True
            else:
                raise DsclError("Error trying to set a value with dscl (" + \
                                str(reterr).strip() + ")")
        return success
            
    #----------------------------------------------------------------------

    def setUserShell(self, user="", shell=""):
        '''dscl . -create /Users/luser UserShell /bin/bash
        
        @author: Roy Nielsen

        :param user:  (Default value = "")
        :param shell:  (Default value = "")

        '''
        success = False
        if self.isSaneUserName(user) and self.isSaneUserShell(shell):
            isSetDSL = self.setDscl(".", "-create", "/Users/" + str(user),
                                    "UserShell", str(shell))
            if isSetDSL:
                success = True

        return success

    #----------------------------------------------------------------------

    def setUserComment(self, user="", comment=""):
        '''dscl . -create /Users/luser RealName "Real A. Name"
        
        @author: Roy Nielsen

        :param user:  (Default value = "")
        :param comment:  (Default value = "")

        '''
        success = False

        if self.isSaneUserName(user) and comment:
            isSetDSL = self.setDscl(".", "-create", "/Users/" + str(user),
                                    "RealName", str(comment))
            if isSetDSL:
                success = True

        return success

    #----------------------------------------------------------------------

    def setUserUid(self, user="", uid=""):
        '''dscl . -create /Users/luser UniqueID "503"
        
        @author: Roy Nielsen

        :param user:  (Default value = "")
        :param uid:  (Default value = "")

        '''
        success = False

        if self.isSaneUserName(user) and uid:
            isSetDSL = self.setDscl(".", "-create", "/Users/" + str(user),
                                    "UniqueID", str(uid))

            if isSetDSL:
                success = True

        return success

    #----------------------------------------------------------------------

    def setUserPriGid(self, user="", priGid=""):
        '''dscl . -create /Users/luser PrimaryGroupID 20
        
        @author: Roy Nielsen

        :param user:  (Default value = "")
        :param priGid:  (Default value = "")

        '''
        success = False

        if self.isSaneUserName(user) and priGid:
            isSetDSL = self.setDscl(".", "-create", "/Users/" + str(user),
                                    "PrimaryGroupID", str(priGid))

            if isSetDSL:
                success = True

        return success

    #----------------------------------------------------------------------

    def setUserHomeDir(self, user="", userHome=""):
        '''Create a "local" home directory
        
        dscl . -create /Users/luser NFSHomeDirectory /Users/luser
        
        better yet:
        
        createhomedir -l -u <username>
        
        @author: Roy Nielsen

        :param user:  (Default value = "")
        :param userHome:  (Default value = "")

        '''
        success = False
        #####
        # Creating a non-standard userHome is not currently permitted
        #if self.saneUserName(user) and self.saneUserHomeDir(userHome):
        if self.isSaneUserName(user):
            isSetDSCL = self.setDscl(".", "-create", "/Users/" + str(user),
                                     "NFSHomeDirectory", str("/Users/" + str(user)))
            if isSetDSCL:
                success = True

        return success

    #----------------------------------------------------------------------

    def createHomeDirectory(self, user=""):
        '''createhomedir -c -u luser
        
        This should use the system "User Template" for standard system user
        settings.
        
        @author: Roy Nielsen

        :param user:  (Default value = "")

        '''
        success = False
        reterr = ""
        if user:
            cmd = ["/usr/sbin/createhomedir", "-c", " -u", + str(user)]
            self.runWith.setCommand(cmd)
            self.runWith.communicate()
            retval, reterr, retcode = self.runWith.getNlogReturns()

            if not reterr:
                success = True
            else:
                raise CreateHomeDirError("Error trying to create user home (" + \
                                         str(reterr).strip() + ")")
        return success

    #----------------------------------------------------------------------

    def addUserToGroup(self, user="", group=""):
        '''dscl . -append /Groups/admin GroupMembership luser
        
        @author: Roy Nielsen

        :param user:  (Default value = "")
        :param group:  (Default value = "")

        '''
        success = False

        if self.isSaneUserName(user) and self.isSaneGroupName(group):
            isSetDSCL = self.setDscl(".", "-append", "/Groups/" + str(group),
                                     "GroupMembership", str(user))
        if isSetDSCL:
            success = True

        return success

    #----------------------------------------------------------------------

    def setUserPassword(self, user="", password="", oldPassword=""):
        '''dscl . -passwd /Users/luser password
        -- or --
        dscl . -passwd /Users/luser oldPassword password
        
        @author: Roy Nielsen

        :param user:  (Default value = "")
        :param password:  (Default value = "")
        :param oldPassword:  (Default value = "")

        '''
        success = False

        if self.isSaneUserName(user):
            if oldPassword:
                isSetDSCL = self.setDscl(".", "-passwd", "/Users/" + str(user),
                                         '%s'%oldPassword, '%s'%password)
            else:
                isSetDSCL = self.setDscl(".", "-passwd", "/Users/" + str(user),
                                         '%s'%password)
            self.logger.log(lp.DEBUG, "isSetDSCL: " + str(isSetDSCL))
        else:
            self.logger.log(lp.DEBUG, "Tribbles in the bulkhead Jim!")

        if not isSetDSCL:
            success = False
        else:
            success = True

        return success

    #----------------------------------------------------------------------

    def fixUserHome(self, userName=""):
        '''Get the user information from the local directory and fix the user
        ownership and group of the user's home directory to reflect
        what is in the local directory service.
        
        @author: Roy Nielsen

        :param userName:  (Default value = "")

        '''
        success = False
        if self.isSaneUserName(userName):
            #####
            # Acquire the user data based on the username first.
            try:
                userUid = self.getUserUid(userName)
                userPriGid = self.getUserPriGid(userName)
                userHomeDir = self.getUserHomeDir(userName)
            except BadUserInfoError as err:
                self.logger.log(lp.INFO, "Exception trying to find: \"" + \
                                         str(userName) + "\" user information")
                self.logger.log(lp.INFO, "err: " + str(err))
            else:
                success = True

        if success:
            try:
                for root, dirs, files in os.walk(userHomeDir):
                    for d in dirs:
                        os.chown(os.path.join(root, d), userUid, userPriGid)
                    for f in files:
                        os.chown(os.path.join(root, d, f), userUid, userPriGid)
            except:
                success = False
                self.logger.log(lp.INFO, "Exception attempting to chown...")
                raise err
            else:
                success = True
        return success

    #----------------------------------------------------------------------
    # User Property Removal
    #----------------------------------------------------------------------

    def rmUser(self, user=""):
        '''dscl . delete /Users/<user>
        
        @author: Roy Nielsen

        :param user:  (Default value = "")

        '''
        success = False

        if self.isSaneUserName(user):
            cmd = [self.dscl, ".", "-delete", "/Users/" + str(user)]
            self.runWith.setCommand(cmd)
            self.runWith.communicate()
            retval, reterr, retcode = self.runWith.getNlogReturns()

            if not reterr:
                success = True
            else:
                raise Exception("Error trying to remove a user (" + \
                                str(reterr).strip() + ")")

            return success

    #----------------------------------------------------------------------

    def rmUserHome(self, user=""):
        '''Remove the user home... right now only default location, but should
        look up the user home in the directory service and remove that
        specifically.
        
        @author: Roy Nielsen

        :param user:  (Default value = "")

        '''
        success = False
        if self.isSaneUserName(user):

            #####
            #
            # ***** WARNING WILL ROBINSON *****
            #
            # Please refactor to do a lookup of the user in the directory
            # service, and use the home directory specified there..
            #
            try:
                shutil.rmtree("/Users/" + str(user))
            except IOError or OSError as err:
                self.logger.log(lp.INFO, "Exception trying to remove user home...")
                self.logger.log(lp.INFO, "Exception: " + str(err))
                raise err
            else:
                success = True

        return success

    #----------------------------------------------------------------------

    def rmUserFromGroup(self, user="", group=""):
        '''

        :param user:  (Default value = "")
        :param group:  (Default value = "")

        '''
        success = False

        if self.isSaneUserName(user) and self.isSaneGroupName(group):
            isSetDSCL = self.setDscl(".", "-delete", "/Groups/" + str(group),
                                     "GroupMembership", str(user))
        if isSetDSCL:
            success = True

        return success

    #----------------------------------------------------------------------
    # Mac OS Specific Methods
    #----------------------------------------------------------------------

    def setDscl(self, directory=".", action="", object="", property="", value=""):
        '''Using dscl to set a value in a directory...
        
        @author: Roy Nielsen

        :param directory:  (Default value = ".")
        :param action:  (Default value = "")
        :param object:  (Default value = "")
        :param property:  (Default value = "")
        :param value:  (Default value = "")

        '''
        success = False
        reterr = ""
        retval = ""
        #####
        # If elevated, use the liftDown runWith method to run the command as
        # a regular user.
        if directory and action and object and property:
            if directory and action and object and property and value:
                cmd = [self.dscl, directory, action, object, property, value]
            else:
                cmd = [self.dscl, directory, action, object, property]

            self.runWith.setCommand(cmd)
            if re.match("^%0$", str(os.getuid()).strip()):
                #####
                # Run the command, lift down...
                self.logger.log(lp.DEBUG, "dscl-cmd: " + str(cmd))
                self.runWith.liftDown(self.userName)
                self.logger.log(lp.INFO, "Took the lift down...")
                retval, reterr, retcode = self.runWith.getNlogReturns()
                if not reterr:
                    success = True
            else:
                #####
                # Run the command
                retval, reterr, retcode = self.runWith.communicate()

                if not reterr:
                    success = True

            retval, reterr, retcode = self.runWith.getNlogReturns()

        return success

    #----------------------------------------------------------------------

    def getDscl(self, directory="", action="", dirobj="", dirprop=""):
        '''Using dscl to retrieve a value from the directory
        
        @author: Roy Nielsen

        :param directory:  (Default value = "")
        :param action:  (Default value = "")
        :param dirobj:  (Default value = "")
        :param dirprop:  (Default value = "")

        '''
        success = False
        reterr = ""
        retval = ""

        #####
        # FIRST VALIDATE INPUT!!
        if isinstance(directory, str) and re.match("^[/\.][A-Za-z0-9/]*", directory):
            success = True
        else:
            success = False
        if isinstance(action, str) and re.match("^[-]*[a-z]+", action) and success:
            success = True
        else:
            success = False
        if isinstance(dirobj, str) and re.match("^[A-Za-z0=9/]+", dirobj) and success:
            success = True
        else:
            success = False
        if isinstance(dirprop, str) and re.match("^[A-Za-z0-9]+", dirprop) and success:
            success = True
        else:
            success = False
        self.logger.log(lp.CRITICAL, "SUCCESS: " + str(success))
        #####
        # Now do the directory lookup.
        if success:
            cmd = [self.dscl, directory, action, dirobj, dirprop]

            self.runWith.setCommand(cmd)
            self.runWith.communicate()
            retval, reterr, retcode = self.runWith.getNlogReturns()

            if not reterr:
                success = True
            else:
                raise DsclError("Error trying to get a value with dscl (" + \
                                str(reterr).strip() + ")")
        return retval

    #----------------------------------------------------------------------

    def isUserAnAdmin(self, userName=""):
        '''Check if this user is in this group
        
        @author: Roy Nielsen

        :param userName:  (Default value = "")

        '''
        success = False
        if self.isSaneUserName(userName):
            success = self.isUserInGroup(userName, "admin")
        return success

    #----------------------------------------------------------------------

    def acquireUserData(self):
        '''Acquire user data for local user lookup information.
        
        @author: Roy Nielsen


        '''
        pass