def ui_command_create(self, name, size, cfgstring, wwn=None,
                          hw_max_sectors=None):
        '''
        Creates a User-backed storage object.

        SIZE SYNTAX
        ===========
        - If size is an int, it represents a number of bytes.
        - If size is a string, the following units can be used:
            - B{B} or no unit present for bytes
            - B{k}, B{K}, B{kB}, B{KB} for kB (kilobytes)
            - B{m}, B{M}, B{mB}, B{MB} for MB (megabytes)
            - B{g}, B{G}, B{gB}, B{GB} for GB (gigabytes)
            - B{t}, B{T}, B{tB}, B{TB} for TB (terabytes)
        '''

        size = human_to_bytes(size)
        wwn = self.ui_eval_param(wwn, 'string', None)

        config = self.handler + "/" + cfgstring

        ok, errmsg = self.iface.CheckConfig('(s)', config)
        if not ok:
            raise ExecutionError("cfgstring invalid: %s" % errmsg)

        try:
            so = UserBackedStorageObject(name, size=size, config=config,
                                         wwn=wwn, hw_max_sectors=hw_max_sectors)
        except:
            raise ExecutionError("UserBackedStorageObject creation failed.")

        ui_so = UIUserBackedStorageObject(so, self)
        self.shell.log.info("Created user-backed storage object %s size %d."
                            % (name, size))
        return self.new_node(ui_so)
示例#2
0
 def _create_file(self, filename, size, sparse=True):
     try:
         f = open(filename, "w+")
     except (OSError, IOError):
         raise ExecutionError("Could not open %s" % filename)
     try:
         if sparse:
             try:
                 os.posix_fallocate(f.fileno(), 0, size)
             except AttributeError:
                 # Prior to version 3.3, Python does not provide fallocate
                 os.ftruncate(f.fileno(), size)
         else:
             self.shell.log.info("Writing %d bytes" % size)
             while size > 0:
                 write_size = min(size, 1024)
                 f.write("\0" * write_size)
                 size -= write_size
     except (OSError, IOError):
         os.remove(filename)
         raise ExecutionError("Could not expand file to %d bytes" % size)
     except OverflowError:
         raise ExecutionError("The file size is too large (%d bytes)" %
                              size)
     finally:
         f.close()
示例#3
0
    def ui_command_changemedium(self, name, size, cfgstring):
        size = human_to_bytes(size)
        config = self.handler + "/" + cfgstring

        try:
            rc, errmsg = self.iface.ChangeMedium('(sts)', name, size, config)
        except Exception as e:
            raise ExecutionError("ChangeMedium failed: %s" % e)
        else:
            if rc == 0:
                self.shell.log.info("Medium Changed.")
            else:
                raise ExecutionError("ChangeMedium failed: %s" % errmsg)
示例#4
0
    def ui_command_restoreconfig(self,
                                 savefile=default_save_file,
                                 clear_existing=False,
                                 target=None,
                                 storage_object=None):
        '''
        Restores configuration from a file.
        '''
        self.assert_root()

        savefile = os.path.expanduser(savefile)

        if not os.path.isfile(savefile):
            self.shell.log.info("Restore file %s not found" % savefile)
            return

        target = self.ui_eval_param(target, 'string', None)
        storage_object = self.ui_eval_param(storage_object, 'string', None)
        errors = self.rtsroot.restore_from_file(savefile, clear_existing,
                                                target, storage_object)

        self.refresh()

        if errors:
            raise ExecutionError("Configuration restored, %d recoverable errors:\n%s" % \
                                     (len(errors), "\n".join(errors)))

        self.shell.log.info("Configuration restored from %s" % savefile)
示例#5
0
    def ui_command_saveconfig(self, savefile=default_save_file):
        '''
        Saves the current configuration to a file so that it can be restored
        on next boot.
        '''
        self.assert_root()

        savefile = os.path.expanduser(savefile)

        # Only save backups if saving to default location
        if savefile == default_save_file:
            backup_dir = os.path.dirname(savefile) + "/backup"
            backup_name = "saveconfig-" + \
                datetime.now().strftime("%Y%m%d-%H:%M:%S") + ".json"
            backupfile = backup_dir + "/" + backup_name
            backup_error = None

            if not os.path.exists(backup_dir):
                try:
                    os.makedirs(backup_dir);
                except OSError as exe:
                    raise ExecutionError("Cannot create backup directory [%s] %s." % (backup_dir, exc.strerror))

            # Only save backups if savefile exits
            if os.path.exists(savefile):
                backed_files_list = sorted(glob(os.path.dirname(savefile) + "/backup/*.json"))
                # Save backup if 1. backup dir is empty, or 2. savefile is differnt from recent backup copy
                if not backed_files_list or not filecmp.cmp(backed_files_list[-1], savefile):
                    try:
                        shutil.copy(savefile, backupfile)

                    except IOError as ioe:
                        backup_error = ioe.strerror or "Unknown error"

                    if backup_error == None:
                        # Kill excess backups
                        max_backup_files = int(self.shell.default_prefs['max_backup_files'])

                        try:
                            with open(universal_prefs_file) as prefs:
                                backups = [line for line in prefs.read().splitlines() if re.match('^max_backup_files\s*=', line)]
                                if max_backup_files < int(backups[0].split('=')[1].strip()):
                                    max_backup_files = int(backups[0].split('=')[1].strip())
                        except:
                            self.shell.log.debug("No universal prefs file '%s'." % universal_prefs_file)

                        files_to_unlink = list(reversed(backed_files_list))[max_backup_files:]
                        for f in files_to_unlink:
                            with ignored(IOError):
                                os.unlink(f)

                        self.shell.log.info("Last %d configs saved in %s." % \
                                            (max_backup_files, backup_dir))
                    else:
                        self.shell.log.warning("Could not create backup file %s: %s." % \
                                               (backupfile, backup_error))

        self.rtsroot.save_to_file(savefile)

        self.shell.log.info("Configuration saved to %s" % savefile)
示例#6
0
    def ui_command_create(self, tag, portal_list):
        """Add a portal group.

        Args:
           portals: List of portals e.g. ip:port ip2:port2
           tag: Portal group tag (unique, integer > 0)
        """
        portals = []
        for portal in portal_list.strip().split(" "):
            host = portal
            cpumask = None
            if "@" in portal:
                host, cpumask = portal.split("@")
            if ":" not in host:
                raise ExecutionError(
                    "Incorrect format of portal group. Port is missing."
                    "Use 'help create' to see the command syntax.")
            host, port = host.rsplit(":", -1)
            portals.append({'host': host, 'port': port})
            if cpumask:
                print(
                    "WARNING: Specifying a CPU mask for portal groups is no longer supported. Ignoring."
                )
        tag = self.ui_eval_param(tag, "number", None)
        self.get_root().construct_portal_group(tag=tag,
                                               portals=portals,
                                               private=None)
示例#7
0
 def setup_model_alias(self, storageobject):
     if self.shell.prefs['export_backstore_name_as_model']:
         try:
             storageobject.set_attribute("emulate_model_alias", 1)
         except RTSLibError:
             raise ExecutionError("'export_backstore_name_as_model' is set but"
                                  " emulate_model_alias\n  not supported by kernel.")
示例#8
0
    def ui_command_delete(self, name, save=None):
        '''
        Recursively deletes the storage object having the specified I{name}. If
        there are LUNs using this storage object, they will be deleted too.

        EXAMPLE
        =======
        B{delete mystorage}
        -------------------
        Deletes the storage object named mystorage, and all associated LUNs.
        '''
        self.assert_root()
        try:
            child = self.get_child(name)
        except ValueError:
            raise ExecutionError("No storage object named %s." % name)

        save = self.ui_eval_param(save, 'bool', False)
        if save:
            rn = self.get_root()
            rn._save_backups(default_save_file)

        child.rtsnode.delete(save=save)
        self.remove_child(child)
        self.shell.log.info("Deleted storage object %s." % name)
示例#9
0
 def assert_root(self):
     '''
     For commands requiring root privileges, disable command if not the root
     node's as_root attribute is False.
     '''
     root_node = self.get_root()
     if hasattr(root_node, 'as_root') and not self.get_root().as_root:
         raise ExecutionError("This privileged command is disabled: " +
                              "you are not root.")
示例#10
0
    def _ui_block_ro_check(self, dev):
        BLKROGET = 0x0000125E
        try:
            f = os.open(dev, os.O_RDONLY)
        except (OSError, IOError):
            raise ExecutionError("Could not open %s" % dev)
        # ioctl returns an int. Provision a buffer for it
        buf = array.array('b', [0] * 4)
        try:
            fcntl.ioctl(f, BLKROGET, buf)
        except (OSError, IOError):
            os.close(f)
            return False

        os.close(f)
        if struct.unpack('I', buf)[0] == 0:
            return False
        return True
示例#11
0
 def _create_dir(self, dirname):
     '''
     create directory with permissions 0o600 set
     if directory already exists, set right perms
     '''
     mode = stat.S_IRUSR | stat.S_IWUSR  # 0o600
     if not os.path.exists(dirname):
         umask = 0o777 ^ mode  # Prevents always downgrading umask to 0
         umask_original = os.umask(umask)
         try:
             os.makedirs(dirname, mode)
         except OSError as exe:
             raise ExecutionError("Cannot create directory [%s] %s." %
                                  (dirname, exe.strerror))
         finally:
             os.umask(umask_original)
     else:
         if (os.stat(dirname).st_mode & 0o777) != mode:
             os.chmod(dirname, mode)
示例#12
0
    def ui_command_delete(self, name):
        '''
        Recursively deletes the storage object having the specified I{name}. If
        there are LUNs using this storage object, they will be deleted too.

        EXAMPLE
        =======
        B{delete mystorage}
        -------------------
        Deletes the storage object named mystorage, and all associated LUNs.
        '''
        self.assert_root()
        try:
            child = self.get_child(name)
        except ValueError:
            raise ExecutionError("No storage object named %s." % name)

        child.rtsnode.delete()
        self.remove_child(child)
        self.shell.log.info("Deleted storage object %s." % name)
示例#13
0
    def ui_command_restoreconfig(self, savefile=default_save_file, clear_existing=False):
        '''
        Restores configuration from a file.
        '''
        self.assert_root()

        savefile = os.path.expanduser(savefile)

        if not os.path.isfile(savefile):
            self.shell.log.info("Restore file %s not found" % savefile)
            return

        errors = self.rtsroot.restore_from_file(savefile, clear_existing)

        self.refresh()

        if errors:
            raise ExecutionError("Configuration restored, %d recoverable errors:\n%s" % \
                                     (len(errors), "\n".join(errors)))

        self.shell.log.info("Configuration restored from %s" % savefile)
示例#14
0
    def _save_backups(self, savefile):
        '''
        Take backup of config-file if needed.
        '''
        # Only save backups if saving to default location
        if savefile != default_save_file:
            return

        backup_dir = os.path.dirname(savefile) + "/backup/"
        backup_name = "saveconfig-" + \
                      datetime.now().strftime("%Y%m%d-%H:%M:%S") + "-json.gz"
        backupfile = backup_dir + backup_name
        backup_error = None

        if not os.path.exists(backup_dir):
            try:
                os.makedirs(backup_dir)
            except OSError as exe:
                raise ExecutionError(
                    "Cannot create backup directory [%s] %s." %
                    (backup_dir, exe.strerror))

        # Only save backups if savefile exits
        if not os.path.exists(savefile):
            return

        backed_files_list = sorted(glob(os.path.dirname(savefile) + \
                                   "/backup/saveconfig-*json*"))

        # Save backup if backup dir is empty, or savefile is differnt from recent backup copy
        if not backed_files_list or not self._compare_files(
                backed_files_list[-1], savefile):
            try:
                with open(savefile, 'rb') as f_in, gzip.open(backupfile,
                                                             'wb') as f_out:
                    shutil.copyfileobj(f_in, f_out)
                    f_out.flush()
            except IOError as ioe:
                backup_error = ioe.strerror or "Unknown error"

            if backup_error == None:
                # remove excess backups
                max_backup_files = int(self.shell.prefs['max_backup_files'])

                try:
                    with open(universal_prefs_file) as prefs:
                        backups = [
                            line for line in prefs.read().splitlines()
                            if re.match('^max_backup_files\s*=', line)
                        ]
                        if max_backup_files < int(
                                backups[0].split('=')[1].strip()):
                            max_backup_files = int(
                                backups[0].split('=')[1].strip())
                except:
                    self.shell.log.debug("No universal prefs file '%s'." %
                                         universal_prefs_file)

                files_to_unlink = list(
                    reversed(backed_files_list))[max_backup_files - 1:]
                for f in files_to_unlink:
                    with ignored(IOError):
                        os.unlink(f)

                self.shell.log.info("Last %d configs saved in %s." %
                                    (max_backup_files, backup_dir))
            else:
                self.shell.log.warning("Could not create backup file %s: %s." %
                                       (backupfile, backup_error))
示例#15
0
    def ui_command_sessions(self, action="list", sid=None):
        '''
        Displays a detailed list of all open sessions.

        PARAMETERS
        ==========

        action
        ------
        The action is one of:
            - `list`` gives a short session list
            - `detail` gives a detailed list

        sid
        ---
        You can specify an "sid" to only list this one,
        with or without details.

        SEE ALSO
        ========
        status
        '''

        indent_step = 4
        base_steps = 0
        action_list = ("list", "detail")

        if action not in action_list:
            raise ExecutionError("action must be one of: %s" %
                                 ", ".join(action_list))
        if sid is not None:
            try:
                int(sid)
            except ValueError:
                raise ExecutionError("sid must be a number, '%s' given" % sid)

        def indent_print(text, steps):
            console = self.shell.con
            console.display(console.indent(text, indent_step * steps),
                            no_lf=True)

        def print_session(session):
            acl = session['parent_nodeacl']
            indent_print("alias: %(alias)s\tsid: %(id)i type: " \
                             "%(type)s session-state: %(state)s" % session,
                         base_steps)

            if action == 'detail':
                if self.as_root:
                    if acl.authenticate_target:
                        auth = " (authenticated)"
                    else:
                        auth = " (NOT AUTHENTICATED)"
                else:
                    auth = ""

                indent_print("name: %s%s" % (acl.node_wwn, auth),
                             base_steps + 1)

                for mlun in acl.mapped_luns:
                    plugin = mlun.tpg_lun.storage_object.plugin
                    name = mlun.tpg_lun.storage_object.name
                    if mlun.write_protect:
                        mode = "r"
                    else:
                        mode = "rw"
                    indent_print(
                        "mapped-lun: %d backstore: %s/%s mode: %s" %
                        (mlun.mapped_lun, plugin, name, mode), base_steps + 1)

                for connection in session['connections']:
                    indent_print("address: %(address)s (%(transport)s)  cid: " \
                                     "%(cid)i connection-state: %(cstate)s" % \
                                     connection, base_steps + 1)

        if sid:
            printed_sessions = [
                x for x in self.rtsroot.sessions if x['id'] == int(sid)
            ]
        else:
            printed_sessions = list(self.rtsroot.sessions)

        if len(printed_sessions):
            for session in printed_sessions:
                print_session(session)
        else:
            if sid is None:
                indent_print("(no open sessions)", base_steps)
            else:
                raise ExecutionError("no session found with sid %i" % int(sid))
示例#16
0
    def ui_command_create(self,
                          name,
                          file_or_dev,
                          size=None,
                          write_back=None,
                          sparse=None,
                          wwn=None):
        '''
        Creates a FileIO storage object. If I{file_or_dev} is a path
        to a regular file to be used as backend, then the I{size}
        parameter is mandatory. Else, if I{file_or_dev} is a path to a
        block device, the size parameter B{must} be ommited. If
        present, I{size} is the size of the file to be used, I{file}
        the path to the file or I{dev} the path to a block device. The
        I{write_back} parameter is a boolean controlling write
        caching. It is enabled by default. The I{sparse} parameter is
        only applicable when creating a new backing file. It is a
        boolean stating if the created file should be created as a
        sparse file (the default), or fully initialized.

        SIZE SYNTAX
        ===========
        - If size is an int, it represents a number of bytes.
        - If size is a string, the following units can be used:
            - B{B} or no unit present for bytes
            - B{k}, B{K}, B{kB}, B{KB} for kB (kilobytes)
            - B{m}, B{M}, B{mB}, B{MB} for MB (megabytes)
            - B{g}, B{G}, B{gB}, B{GB} for GB (gigabytes)
            - B{t}, B{T}, B{tB}, B{TB} for TB (terabytes)
        '''
        self.assert_root()

        sparse = self.ui_eval_param(sparse, 'bool', True)
        write_back = self.ui_eval_param(write_back, 'bool', True)
        wwn = self.ui_eval_param(wwn, 'string', None)

        self.shell.log.debug("Using params size=%s write_back=%s sparse=%s" %
                             (size, write_back, sparse))

        file_or_dev = os.path.expanduser(file_or_dev)
        # can't use is_dev_in_use() on files so just check against other
        # storage object paths
        if os.path.exists(file_or_dev):
            for so in RTSRoot().storage_objects:
                if so.udev_path and os.path.samefile(file_or_dev,
                                                     so.udev_path):
                    raise ExecutionError("storage object for %s already exists: %s" % \
                                             (file_or_dev, so.name))

        if get_block_type(file_or_dev) is not None:
            if size:
                self.shell.log.info("Block device, size parameter ignored")
                size = None
            self.shell.log.info(
                "Note: block backstore preferred for best results")
        else:
            # use given file size only if backing file does not exist
            if os.path.isfile(file_or_dev):
                new_size = os.path.getsize(file_or_dev)
                if size:
                    self.shell.log.info(
                        "%s exists, using its size (%s bytes) instead" %
                        (file_or_dev, new_size))
                size = new_size
            elif os.path.exists(file_or_dev):
                raise ExecutionError("Path %s exists but is not a file" %
                                     file_or_dev)
            else:
                # create file and extend to given file size
                if not size:
                    raise ExecutionError("Attempting to create file for new" +
                                         " fileio backstore, need a size")
                size = human_to_bytes(size)
                self._create_file(file_or_dev, size, sparse)

        so = FileIOStorageObject(name,
                                 file_or_dev,
                                 size,
                                 write_back=write_back,
                                 wwn=wwn)
        ui_so = UIFileioStorageObject(so, self)
        self.setup_model_alias(so)
        self.shell.log.info("Created fileio %s with size %s" % (name, so.size))
        return self.new_node(ui_so)