Ejemplo n.º 1
0
    def validate_networks(self, context, requested_networks):
        """Validate that the tenant can use the requested networks."""
        LOG.debug(_('validate_networks() for %s'), requested_networks)
        if not requested_networks:
            return
        net_ids = []

        for (net_id, _i, port_id) in requested_networks:
            if not port_id:
                net_ids.append(net_id)
                continue
            port = quantumv2.get_client(context).show_port(port_id).get('port')
            if not port:
                raise exception.PortNotFound(port_id=port_id)
            if port.get('device_id', None):
                raise exception.PortInUse(port_id=port_id)
            net_id = port['network_id']
            if net_id in net_ids:
                raise exception.NetworkDuplicated(network_id=net_id)
            net_ids.append(net_id)

        nets = self._get_available_networks(context, context.project_id,
                                            net_ids)
        if len(nets) != len(net_ids):
            requsted_netid_set = set(net_ids)
            returned_netid_set = set([net['id'] for net in nets])
            lostid_set = requsted_netid_set - returned_netid_set
            id_str = ''
            for _id in lostid_set:
                id_str = id_str and id_str + ', ' + _id or _id
            raise exception.NetworkNotFound(network_id=id_str)
Ejemplo n.º 2
0
    def validate_networks(self, context, requested_networks):
        """Validate that the tenant can use the requested networks."""
        LOG.debug(_('validate_networks() for %s'),
                  requested_networks)

        if not requested_networks:
            nets = self._get_available_networks(context, context.project_id)
            if len(nets) > 1:
                # Attaching to more than one network by default doesn't
                # make sense, as the order will be arbitrary and the guest OS
                # won't know which to configure
                msg = _("Multiple possible networks found, use a Network "
                         "ID to be more specific.")
                raise exception.NetworkAmbiguous(msg)
            return

        net_ids = []

        for (net_id, _i, port_id) in requested_networks:
            if port_id:
                try:
                    port = (neutronv2.get_client(context)
                                     .show_port(port_id)
                                     .get('port'))
                except neutronv2.exceptions.NeutronClientException as e:
                    if e.status_code == 404:
                        port = None
                if not port:
                    raise exception.PortNotFound(port_id=port_id)
                if port.get('device_id', None):
                    raise exception.PortInUse(port_id=port_id)
                net_id = port['network_id']
            if net_id in net_ids:
                raise exception.NetworkDuplicated(network_id=net_id)
            net_ids.append(net_id)

        # Now check to see if all requested networks exist
        nets = self._get_available_networks(context,
                                context.project_id, net_ids)

        if len(nets) != len(net_ids):
            requsted_netid_set = set(net_ids)
            returned_netid_set = set([net['id'] for net in nets])
            lostid_set = requsted_netid_set - returned_netid_set
            id_str = ''
            for _id in lostid_set:
                id_str = id_str and id_str + ', ' + _id or _id
            raise exception.NetworkNotFound(network_id=id_str)
Ejemplo n.º 3
0
    def validate_networks(self, context, requested_networks, num_instances):
        """Validate that the tenant can use the requested networks.

        Return the number of instances than can be successfully allocated
        with the requested network configuration.
        """
        LOG.debug(_('validate_networks() for %s'), requested_networks)

        neutron = neutronv2.get_client(context)
        ports_needed_per_instance = 0

        if not requested_networks:
            nets = self._get_available_networks(context,
                                                context.project_id,
                                                neutron=neutron)
            if len(nets) > 1:
                # Attaching to more than one network by default doesn't
                # make sense, as the order will be arbitrary and the guest OS
                # won't know which to configure
                msg = _("Multiple possible networks found, use a Network "
                        "ID to be more specific.")
                raise exception.NetworkAmbiguous(msg)
            else:
                ports_needed_per_instance = 1

        else:
            net_ids = []

            for (net_id, _i, port_id) in requested_networks:
                if port_id:
                    try:
                        port = neutron.show_port(port_id).get('port')
                    except neutronv2.exceptions.NeutronClientException as e:
                        if e.status_code == 404:
                            port = None
                        else:
                            with excutils.save_and_reraise_exception():
                                LOG.exception(_("Failed to access port %s"),
                                              port_id)
                    if not port:
                        raise exception.PortNotFound(port_id=port_id)
                    if port.get('device_id', None):
                        raise exception.PortInUse(port_id=port_id)
                    if not port.get('fixed_ips'):
                        raise exception.PortRequiresFixedIP(port_id=port_id)
                    net_id = port['network_id']
                else:
                    ports_needed_per_instance += 1

                if net_id in net_ids:
                    raise exception.NetworkDuplicated(network_id=net_id)
                net_ids.append(net_id)

            # Now check to see if all requested networks exist
            nets = self._get_available_networks(context,
                                                context.project_id,
                                                net_ids,
                                                neutron=neutron)
            for net in nets:
                if not net.get('subnets'):
                    raise exception.NetworkRequiresSubnet(
                        network_uuid=net['id'])

            if len(nets) != len(net_ids):
                requsted_netid_set = set(net_ids)
                returned_netid_set = set([net['id'] for net in nets])
                lostid_set = requsted_netid_set - returned_netid_set
                id_str = ''
                for _id in lostid_set:
                    id_str = id_str and id_str + ', ' + _id or _id
                raise exception.NetworkNotFound(network_id=id_str)

        # Note(PhilD): Ideally Nova would create all required ports as part of
        # network validation, but port creation requires some details
        # from the hypervisor.  So we just check the quota and return
        # how many of the requested number of instances can be created

        ports = []
        quotas = neutron.show_quota(tenant_id=context.project_id)['quota']
        if quotas.get('port', -1) == -1:
            # Unlimited Port Quota
            return num_instances
        else:
            free_ports = quotas.get('port') - len(ports)
            ports_needed = ports_needed_per_instance * num_instances
            if free_ports >= ports_needed:
                return num_instances
            else:
                return free_ports // ports_needed_per_instance
Ejemplo n.º 4
0
    def create(self, req, server_id, body):
        """Attach an interface to an instance."""
        context = req.environ['nova.context']
        authorize(context)

        network_id = None
        port_id = None
        req_ip = None
        if body:
            attachment = body['interfaceAttachment']
            network_id = attachment.get('net_id', None)
            port_id = attachment.get('port_id', None)
            try:
                req_ip = attachment['fixed_ips'][0]['ip_address']
            except Exception:
                pass

        if network_id and port_id:
            msg = _("Must not input both network_id and port_id")
            raise exc.HTTPBadRequest(explanation=msg)
        if req_ip and not network_id:
            msg = _("Must input network_id when request IP address")
            raise exc.HTTPBadRequest(explanation=msg)

        #if the port has attached in this instance, raise
        port_info = {}
        if utils.is_neutron():
            if port_id:
                try:
                    port_info = self.network_api.show_port(context, port_id)
                except exception.NotFound as e:
                    raise exc.HTTPNotFound(explanation=e.format_message())
                if port_info['port']['device_id']:
                    raise exception.PortInUse(port_id=port_id)

        #check network is duplicated or not when allow_duplicate_networks is false
        if utils.is_neutron():
            if not cfg.CONF.neutron.allow_duplicate_networks:
                search_opts = {'device_id': server_id}
                try:
                    data = self.network_api.list_ports(context, **search_opts)
                except exception.NotFound as e:
                    raise exc.HTTPNotFound(explanation=e.format_message())
                except NotImplementedError:
                    msg = _("Network driver does not support this function.")
                    raise webob.exc.HTTPNotImplemented(explanation=msg)
                ports = data.get('ports', [])
                instance_networks = []
                for port in ports:
                    instance_networks.append(port.get('network_id'))
                if port_id:
                    network_id = port_info['port'].get('network_id')
                if network_id in instance_networks:
                    raise exception.NetworkDuplicated(network_id=network_id)

        try:
            instance = common.get_instance(self.compute_api,
                                           context, server_id,
                                           want_objects=True)
            LOG.audit(_("Attach interface"), instance=instance)
            vif = self.compute_api.attach_interface(context,
                instance, network_id, port_id, req_ip)
        except (exception.PortNotFound,
                exception.FixedIpAlreadyInUse,
                exception.PortInUse,
                exception.NetworkDuplicated,
                exception.NetworkAmbiguous,
                exception.NetworkNotFound,
                exception.PortNotUsable) as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except NotImplementedError:
            msg = _("Network driver does not support this function.")
            raise webob.exc.HTTPNotImplemented(explanation=msg)
        except exception.InterfaceAttachFailed as e:
            LOG.exception(e)
            msg = _("Failed to attach interface")
            raise webob.exc.HTTPInternalServerError(explanation=msg)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'attach_interface')

        return self.show(req, server_id, vif['id'])