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."))
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'])))
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."))
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