예제 #1
0
 def _check_host_states(self):
     current_ihosts = pecan.request.dbapi.ihost_get_list()
     for h in current_ihosts:
         if (h['administrative'] != constants.ADMIN_LOCKED
                 and not utils.is_host_active_controller(h)):
             raise wsme.exc.ClientSideError(
                 _("Infrastructure subnet configuration cannot be "
                   "updated with hosts other than the active controller "
                   "in an unlocked state. Please lock all hosts except "
                   "the active controller."))
예제 #2
0
 def _check_hosts(self):
     hosts = pecan.request.dbapi.ihost_get_list()
     for h in hosts:
         if api_utils.is_aio_simplex_host_unlocked(h):
             raise wsme.exc.ClientSideError(
                 _("Host {} must be locked.".format(h['hostname'])))
         elif (h['administrative'] != constants.ADMIN_LOCKED
               and constants.WORKER in h['subfunctions']
               and not api_utils.is_host_active_controller(h)
               and not api_utils.is_host_simplex_controller(h)):
             raise wsme.exc.ClientSideError(
                 _("Host {} must be locked.".format(h['hostname'])))
예제 #3
0
 def _check_host_interfaces(self):
     controller_ihosts = pecan.request.dbapi.ihost_get_by_personality(
         personality=constants.CONTROLLER)
     for host in controller_ihosts:
         if utils.is_host_active_controller(host):
             interface_list = pecan.request.dbapi.iinterface_get_by_ihost(
                 host.uuid)
             network = pecan.request.dbapi.network_get_by_type(
                 constants.NETWORK_TYPE_INFRA)
             for interface in interface_list:
                 if interface[
                         'ifclass'] == constants.INTERFACE_CLASS_PLATFORM:
                     if str(network['id']) in interface['networks']:
                         return True
     raise wsme.exc.ClientSideError(
         _("Infrastructure interface must be configured on the active "
           "controller prior to applying infrastructure network "
           "configuration."))
예제 #4
0
def _semantic_checks(operation, partition):
    # Semantic checks
    LOG.debug("PART Partition semantic checks for %s operation" % operation)
    ihost = pecan.request.dbapi.ihost_get(partition['forihostid'])

    # Get disk.
    idiskid = partition.get('idisk_id') or partition.get('idisk_uuid')
    idisk = pecan.request.dbapi.idisk_get(idiskid)

    # Check host and host state.
    _check_host(partition, ihost, idisk)

    # Make sure this partition's type is valid.
    _check_partition_type(partition)

    # Check existing partitions and make sure we don't have any partitions
    # being changed for an existing host/disk pairing. If so => reject request.
    _check_for_outstanding_requests(partition, idisk)

    # Make sure the disk on which we create the partition is valid.
    _check_disk(idisk)

    # Semantic checks based on operation.
    if operation == constants.PARTITION_CMD_CREATE:
        ############
        # CREATING #
        ############
        if int(partition['size_mib']) <= 0:
            raise wsme.exc.ClientSideError(
                _("Partition size must be greater than 0."))

        # Check if there is enough space on the disk to accommodate the
        # partition.
        if not _enough_avail_space_on_disk(partition.get('size_mib'), idisk):
            raise wsme.exc.ClientSideError(
                _("Requested size %s GiB is larger than the %s GiB "
                  "available.") % (partition['size_mib'] / 1024,
                                   math.floor(float(idisk.available_mib) / 1024 * 1000) / 1000.0))

        _are_partition_operations_simultaneous(ihost, partition,
                                               constants.PARTITION_CMD_CREATE)

        # Enough space is availabe, save the disk ID.
        if uuidutils.is_uuid_like(idiskid):
            idisk_id = idisk['id']
        else:
            idisk_id = idiskid
        partition.update({'idisk_id': idisk_id})

    elif operation == constants.PARTITION_CMD_MODIFY:
        #############
        # MODIFYING #
        #############
        # Only allow in-service modify of partitions. If the host isn't
        # provisioned just limit operations to create/delete.
        if ihost.invprovision != constants.PROVISIONED:
            raise wsme.exc.ClientSideError(
                _("Only partition Add/Delete operations are allowed on an "
                  "unprovisioned host."))

        # Allow modification of in-use PVs only for cinder-volumes
        ipv_uuid = partition.get('ipv_uuid')
        ipv_lvg_name = None
        if ipv_uuid:
            ipv_lvg_name = pecan.request.dbapi.ipv_get(ipv_uuid)['lvm_vg_name']
        if (ipv_lvg_name != constants.LVG_CINDER_VOLUMES and
                (ipv_uuid or
                 partition.get('status') == constants.PARTITION_IN_USE_STATUS)):
            raise wsme.exc.ClientSideError(
                _("Can not modify partition. A physical volume (%s) is "
                  "currently associated with this partition.") %
                partition.get('device_node'))

        if (ipv_lvg_name == constants.LVG_CINDER_VOLUMES):
            if (utils.get_system_mode() == constants.SYSTEM_MODE_SIMPLEX):
                if ihost['administrative'] != constants.ADMIN_LOCKED:
                    raise wsme.exc.ClientSideError(
                        _("Cannot modify the partition (%(dev_node)s) associated with "
                          "the physical volume (%(PV)s) while the host is unlocked.") %
                        {'dev_node': partition.get('device_node'), 'PV': ipv_uuid})
                # TODO(oponcea) Deny modifications if instances are still running.
            elif utils.is_host_active_controller(ihost):
                raise wsme.exc.ClientSideError(
                    _("Can only modify the partition (%(dev_node)s) associated with the physical "
                      "volume (%(PV)s) if the personality is 'Controller-Standby'") %
                    {'dev_node': partition.get('device_node'), 'PV': ipv_uuid})

        # Prevent modifying a partition that is in creating state.
        allowed_states = [constants.PARTITION_READY_STATUS]
        if ipv_lvg_name == constants.LVG_CINDER_VOLUMES:
            allowed_states.append(constants.PARTITION_IN_USE_STATUS)
        status = partition.get('status')
        if status not in allowed_states:
            raise wsme.exc.ClientSideError(
                _("Can not modify partition. Only partitions in the %s state "
                  "can be modified.") %
                constants.PARTITION_STATUS_MSG[
                    constants.PARTITION_READY_STATUS])

        # Check that the partition to modify is the last partition.
        if not cutils.is_partition_the_last(pecan.request.dbapi,
                                            partition):
            raise wsme.exc.ClientSideError(
                _("Can not modify partition. Only the last partition on disk "
                  "can be modified."))

        # Obtain the current partition info.
        crt_part = pecan.request.dbapi.partition_get(partition.get('uuid'))
        crt_part_size = crt_part.size_mib
        new_part_size = partition.get('size_mib')
        extra_size = new_part_size - crt_part_size

        # Check if there is enough space to enlarge the partition.
        if not _enough_avail_space_on_disk(extra_size, idisk):
            raise wsme.exc.ClientSideError(
                _("Requested extra size %s GiB is larger than the %s GiB "
                  "available.") % (extra_size / 1024,
                                   math.floor(float(idisk.available_mib) / 1024 * 1000) / 1000.0))

    elif operation == constants.PARTITION_CMD_DELETE:
        ############
        # DELETING #
        ############
        # Make sure that there is no PV associated with this partition
        if (partition.get('ipv_uuid') or
                partition.get('status') == constants.PARTITION_IN_USE_STATUS):
            raise wsme.exc.ClientSideError(
                _("Can not delete partition. A physical volume (%s) is "
                  "currently associated with this partition") %
                partition.get('device_node'))

        _are_partition_operations_simultaneous(ihost, partition,
                                               constants.PARTITION_CMD_DELETE)

        status = partition.get('status')
        if status == constants.PARTITION_READY_STATUS:
            # Check that the partition to delete is the last partition.
            if not cutils.is_partition_the_last(pecan.request.dbapi,
                                                partition):
                raise wsme.exc.ClientSideError(
                    _("Can not delete partition. Only the last partition on "
                      "disk can be deleted."))
        elif status not in constants.PARTITION_STATUS_OK_TO_DELETE:
            raise wsme.exc.ClientSideError(
                _("Can not delete partition. Only partitions in one of these "
                  "states can be deleted: %s") % ", ".join(
                      map(constants.PARTITION_STATUS_MSG.get,
                          constants.PARTITION_STATUS_OK_TO_DELETE)))
    else:
        raise wsme.exc.ClientSideError(
            _("Internal Error: Invalid Partition operation: %s" % operation))

    return partition