示例#1
0
def diagnose_network(context, id, fields):
    if id == "*":
        return {'networks': [_diag_network(context, net, fields) for
                net in db_api.network_find(context, scope=db_api.ALL)]}
    db_net = db_api.network_find(context, id=id, scope=db_api.ONE)
    if not db_net:
        raise exceptions.NetworkNotFound(net_id=id)
    net = _diag_network(context, db_net, fields)
    return {'networks': net}
示例#2
0
def diagnose_network(context, id, fields):
    if not context.is_admin:
        raise n_exc.NotAuthorized()

    if id == "*":
        return {'networks': [_diag_network(context, net, fields) for
                net in db_api.network_find(context, scope=db_api.ALL)]}
    db_net = db_api.network_find(context, id=id, scope=db_api.ONE)
    if not db_net:
        raise n_exc.NetworkNotFound(net_id=id)
    net = _diag_network(context, db_net, fields)
    return {'networks': net}
示例#3
0
def get_networks(context, filters=None, fields=None):
    """Retrieve a list of networks.

    The contents of the list depends on the identity of the user
    making the request (as indicated by the context) as well as any
    filters.
    : param context: neutron api request context
    : param filters: a dictionary with keys that are valid keys for
        a network as listed in the RESOURCE_ATTRIBUTE_MAP object
        in neutron/api/v2/attributes.py.  Values in this dictiontary
        are an iterable containing values that will be used for an exact
        match comparison for that value.  Each result returned by this
        function will have matched one of the values for each key in
        filters.
    : param fields: a list of strings that are valid keys in a
        network dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_networks for tenant %s with filters %s, fields %s" %
             (context.tenant_id, filters, fields))
    filters = filters or {}
    nets = db_api.network_find(context, join_subnets=True, **filters) or []
    nets = [v._make_network_dict(net, fields=fields) for net in nets]
    return nets
示例#4
0
def create_ip_policy(context, ip_policy):
    LOG.info("create_ip_policy for tenant %s" % context.tenant_id)

    ipp = ip_policy["ip_policy"]

    if not ipp.get("exclude"):
        raise exceptions.BadRequest(resource="ip_policy",
                                    msg="Empty ip_policy.exclude regions")

    ipp["exclude"] = netaddr.IPSet(ipp["exclude"])
    network_id = ipp.get("network_id")
    subnet_id = ipp.get("subnet_id")

    model = None
    if subnet_id:
        model = db_api.subnet_find(context, id=subnet_id, scope=db_api.ONE)
        if not model:
            raise exceptions.SubnetNotFound(id=subnet_id)
    elif network_id:
        model = db_api.network_find(context, id=network_id,
                                    scope=db_api.ONE)
        if not model:
            raise exceptions.NetworkNotFound(id=network_id)
    else:
        raise exceptions.BadRequest(
            resource="ip_policy",
            msg="network_id or subnet_id unspecified")

    if model["ip_policy"]:
        raise quark_exceptions.IPPolicyAlreadyExists(
            id=model["ip_policy"]["id"], n_id=model["id"])
    model["ip_policy"] = db_api.ip_policy_create(context, **ipp)
    return v._make_ip_policy_dict(model["ip_policy"])
示例#5
0
def diagnose_network(context, id, fields):
    if not context.is_admin:
        raise n_exc.NotAuthorized()

    if id == "*":
        return {
            'networks': [
                _diag_network(context, net, fields)
                for net in db_api.network_find(context, scope=db_api.ALL)
            ]
        }
    db_net = db_api.network_find(context, id=id, scope=db_api.ONE)
    if not db_net:
        raise n_exc.NetworkNotFound(net_id=id)
    net = _diag_network(context, db_net, fields)
    return {'networks': net}
示例#6
0
def delete_network(context, id):
    """Delete a network.

    : param context: neutron api request context
    : param id: UUID representing the network to delete.
    """
    LOG.info("delete_network %s for tenant %s" % (id, context.tenant_id))
    with context.session.begin():
        net = db_api.network_find(context=context,
                                  limit=None,
                                  sorts=['id'],
                                  marker=None,
                                  page_reverse=False,
                                  id=id,
                                  scope=db_api.ONE)
        if not net:
            raise n_exc.NetworkNotFound(net_id=id)
        if not context.is_admin:
            if STRATEGY.is_provider_network(net.id):
                raise n_exc.NotAuthorized(net_id=id)
        if net.ports:
            raise n_exc.NetworkInUse(net_id=id)
        net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])
        net_driver.delete_network(context, id)
        for subnet in net["subnets"]:
            subnets._delete_subnet(context, subnet)
        db_api.network_delete(context, net)
示例#7
0
def create_ip_policy(context, ip_policy):
    LOG.info("create_ip_policy for tenant %s" % context.tenant_id)

    ipp = ip_policy["ip_policy"]

    if not ipp.get("exclude"):
        raise exceptions.BadRequest(resource="ip_policy",
                                    msg="Empty ip_policy.exclude regions")

    ipp["exclude"] = netaddr.IPSet(ipp["exclude"])
    network_id = ipp.get("network_id")
    subnet_id = ipp.get("subnet_id")

    model = None
    if subnet_id:
        model = db_api.subnet_find(context, id=subnet_id, scope=db_api.ONE)
        if not model:
            raise exceptions.SubnetNotFound(id=subnet_id)
    elif network_id:
        model = db_api.network_find(context, id=network_id, scope=db_api.ONE)
        if not model:
            raise exceptions.NetworkNotFound(id=network_id)
    else:
        raise exceptions.BadRequest(resource="ip_policy",
                                    msg="network_id or subnet_id unspecified")

    if model["ip_policy"]:
        raise quark_exceptions.IPPolicyAlreadyExists(
            id=model["ip_policy"]["id"], n_id=model["id"])
    model["ip_policy"] = db_api.ip_policy_create(context, **ipp)
    return v._make_ip_policy_dict(model["ip_policy"])
示例#8
0
def update_ip_policy(context, id, ip_policy):
    LOG.info("update_ip_policy for tenant %s" % context.tenant_id)

    ipp = ip_policy["ip_policy"]

    with context.session.begin():
        ipp_db = db_api.ip_policy_find(context, id=id, scope=db_api.ONE)
        if not ipp_db:
            raise quark_exceptions.IPPolicyNotFound(id=id)

        ip_policy_cidrs = ipp.get("exclude")
        network_ids = ipp.get("network_ids")
        subnet_ids = ipp.get("subnet_ids")

        if subnet_ids and network_ids:
            raise exceptions.BadRequest(
                resource="ip_policy", msg="network_ids and subnet_ids specified. only one allowed"
            )

        models = []
        all_subnets = []
        if subnet_ids:
            for subnet in ipp_db["subnets"]:
                subnet["ip_policy"] = None
            subnets = db_api.subnet_find(context, id=subnet_ids, scope=db_api.ALL)
            if len(subnets) != len(subnet_ids):
                raise exceptions.SubnetNotFound(id=subnet_ids)
            if ip_policy_cidrs is not None:
                ensure_default_policy(ip_policy_cidrs, subnets)
                _validate_cidrs_fit_into_subnets(ip_policy_cidrs, subnets)
            all_subnets.extend(subnets)
            models.extend(subnets)

        if network_ids:
            for network in ipp_db["networks"]:
                network["ip_policy"] = None
            nets = db_api.network_find(context, id=network_ids, scope=db_api.ALL)
            if len(nets) != len(network_ids):
                raise exceptions.NetworkNotFound(net_id=network_ids)
            subnets = [subnet for net in nets for subnet in net.get("subnets", [])]
            if ip_policy_cidrs is not None:
                ensure_default_policy(ip_policy_cidrs, subnets)
                _validate_cidrs_fit_into_subnets(ip_policy_cidrs, subnets)
            all_subnets.extend(subnets)
            models.extend(nets)

        if not subnet_ids and not network_ids and ip_policy_cidrs is not None:
            ensure_default_policy(ip_policy_cidrs, ipp_db["subnets"])
            _validate_cidrs_fit_into_subnets(ip_policy_cidrs, ipp_db["subnets"])

        for model in models:
            if model["ip_policy"]:
                raise quark_exceptions.IPPolicyAlreadyExists(id=model["ip_policy"]["id"], n_id=model["id"])
            model["ip_policy"] = ipp_db

        if ip_policy_cidrs:
            _validate_policy_with_routes(context, ip_policy_cidrs, all_subnets)
        ipp_db = db_api.ip_policy_update(context, ipp_db, **ipp)
    return v._make_ip_policy_dict(ipp_db)
示例#9
0
文件: subnets.py 项目: kilogram/quark
def create_subnet(context, subnet):
    """Create a subnet.

    Create a subnet which represents a range of IP addresses
    that can be allocated to devices

    : param context: neutron api request context
    : param subnet: dictionary describing the subnet, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_subnet for tenant %s" % context.tenant_id)
    net_id = subnet["subnet"]["network_id"]

    net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
    if not net:
        raise exceptions.NetworkNotFound(net_id=net_id)

    sub_attrs = subnet["subnet"]

    _validate_subnet_cidr(context, net_id, sub_attrs["cidr"])

    cidr = netaddr.IPNetwork(sub_attrs["cidr"])
    gateway_ip = utils.pop_param(sub_attrs, "gateway_ip", str(cidr[1]))
    dns_ips = utils.pop_param(sub_attrs, "dns_nameservers", [])
    host_routes = utils.pop_param(sub_attrs, "host_routes", [])
    allocation_pools = utils.pop_param(sub_attrs, "allocation_pools", [])
    sub_attrs["network"] = net

    new_subnet = db_api.subnet_create(context, **sub_attrs)

    default_route = None
    for route in host_routes:
        netaddr_route = netaddr.IPNetwork(route["destination"])
        if netaddr_route.value == routes.DEFAULT_ROUTE.value:
            default_route = route
            gateway_ip = default_route["nexthop"]
        new_subnet["routes"].append(db_api.route_create(
            context, cidr=route["destination"], gateway=route["nexthop"]))

    if default_route is None:
        new_subnet["routes"].append(db_api.route_create(
            context, cidr=str(routes.DEFAULT_ROUTE), gateway=gateway_ip))

    for dns_ip in dns_ips:
        new_subnet["dns_nameservers"].append(db_api.dns_create(
            context, ip=netaddr.IPAddress(dns_ip)))

    if allocation_pools:
        exclude = netaddr.IPSet([cidr])
        for p in allocation_pools:
            x = netaddr.IPSet(netaddr.IPRange(p["start"], p["end"]))
            exclude = exclude - x
        new_subnet["ip_policy"] = db_api.ip_policy_create(context,
                                                          exclude=exclude)
    subnet_dict = v._make_subnet_dict(new_subnet,
                                      default_route=routes.DEFAULT_ROUTE)
    subnet_dict["gateway_ip"] = gateway_ip
    return subnet_dict
示例#10
0
def create_ip_policy(context, ip_policy):
    LOG.info("create_ip_policy for tenant %s" % context.tenant_id)

    ipp = ip_policy['ip_policy']

    if not ipp.get("exclude"):
        raise exceptions.BadRequest(resource="ip_policy",
                                    msg="Empty ip_policy.exclude")

    network_ids = ipp.get("network_ids")
    subnet_ids = ipp.get("subnet_ids")

    if subnet_ids and network_ids:
        raise exceptions.BadRequest(
            resource="ip_policy",
            msg="network_ids and subnet_ids specified. only one allowed")

    if not subnet_ids and not network_ids:
        raise exceptions.BadRequest(
            resource="ip_policy",
            msg="network_ids or subnet_ids not specified")

    with context.session.begin():
        if subnet_ids:
            subnets = db_api.subnet_find(context,
                                         id=subnet_ids,
                                         scope=db_api.ALL)
            if not subnets:
                raise exceptions.SubnetNotFound(id=subnet_ids)
            _check_for_pre_existing_policies_in(subnets)
            ensure_default_policy(ipp["exclude"], subnets)
            _validate_cidrs_fit_into_subnets(ipp["exclude"], subnets)
            ipp.pop("subnet_ids")
            ipp["subnets"] = subnets

        if network_ids:
            nets = db_api.network_find(context,
                                       id=network_ids,
                                       scope=db_api.ALL)
            if not nets:
                raise exceptions.NetworkNotFound(net_id=network_ids)
            _check_for_pre_existing_policies_in(nets)
            subnets = [
                subnet for net in nets for subnet in net.get("subnets", [])
            ]
            ensure_default_policy(ipp["exclude"], subnets)
            _validate_cidrs_fit_into_subnets(ipp["exclude"], subnets)
            ipp.pop("network_ids")
            ipp["networks"] = nets

        ip_policy = db_api.ip_policy_create(context, **ipp)
    return v._make_ip_policy_dict(ip_policy)
示例#11
0
def create_ip_policy(context, ip_policy):
    LOG.info("create_ip_policy for tenant %s" % context.tenant_id)

    ipp = ip_policy['ip_policy']

    if not ipp.get("exclude"):
        raise exceptions.BadRequest(resource="ip_policy",
                                    msg="Empty ip_policy.exclude")

    ip_policy_cidrs = ipp.get("exclude", [])
    network_ids = ipp.get("network_ids")
    subnet_ids = ipp.get("subnet_ids")

    if subnet_ids and network_ids:
        raise exceptions.BadRequest(
            resource="ip_policy",
            msg="network_ids and subnet_ids specified. only one allowed")

    if not subnet_ids and not network_ids:
        raise exceptions.BadRequest(
            resource="ip_policy",
            msg="network_ids or subnet_ids not specified")

    with context.session.begin():
        models = []
        if subnet_ids:
            subnets = db_api.subnet_find(
                context, id=subnet_ids, scope=db_api.ALL)
            if not subnets:
                raise exceptions.SubnetNotFound(id=subnet_ids)
            if ip_policy_cidrs:
                _validate_cidrs_fit_into_subnets(ip_policy_cidrs, subnets)
            models.extend(subnets)

        if network_ids:
            nets = db_api.network_find(
                context, id=network_ids, scope=db_api.ALL)
            if not nets:
                raise exceptions.NetworkNotFound(net_id=network_ids)
            subnets = [subnet for net in nets
                       for subnet in net.get("subnets", [])]
            if ip_policy_cidrs and subnets:
                _validate_cidrs_fit_into_subnets(ip_policy_cidrs, subnets)
            models.extend(nets)

        for model in models:
            if model["ip_policy"]:
                raise quark_exceptions.IPPolicyAlreadyExists(
                    id=model["ip_policy"]["id"], n_id=model["id"])
            model["ip_policy"] = db_api.ip_policy_create(context, **ipp)

    return v._make_ip_policy_dict(model["ip_policy"])
示例#12
0
def create_ip_policy(context, ip_policy):
    LOG.info("create_ip_policy for tenant %s" % context.tenant_id)

    ipp = ip_policy['ip_policy']

    if not ipp.get("exclude"):
        raise n_exc.BadRequest(resource="ip_policy",
                               msg="Empty ip_policy.exclude")

    network_ids = ipp.get("network_ids")
    subnet_ids = ipp.get("subnet_ids")

    if subnet_ids and network_ids:
        raise n_exc.BadRequest(
            resource="ip_policy",
            msg="network_ids and subnet_ids specified. only one allowed")

    if not subnet_ids and not network_ids:
        raise n_exc.BadRequest(
            resource="ip_policy",
            msg="network_ids or subnet_ids not specified")

    with context.session.begin():
        if subnet_ids:
            subnets = db_api.subnet_find(
                context, id=subnet_ids, scope=db_api.ALL)
            if not subnets:
                raise n_exc.SubnetNotFound(subnet_id=subnet_ids)
            _check_for_pre_existing_policies_in(subnets)
            ensure_default_policy(ipp["exclude"], subnets)
            _validate_cidrs_fit_into_subnets(ipp["exclude"], subnets)
            ipp.pop("subnet_ids")
            ipp["subnets"] = subnets

        if network_ids:
            nets = db_api.network_find(
                context, id=network_ids, scope=db_api.ALL)
            if not nets:
                raise n_exc.NetworkNotFound(net_id=network_ids)
            _check_for_pre_existing_policies_in(nets)
            subnets = [subnet for net in nets
                       for subnet in net.get("subnets", [])]
            ensure_default_policy(ipp["exclude"], subnets)
            _validate_cidrs_fit_into_subnets(ipp["exclude"], subnets)
            ipp.pop("network_ids")
            ipp["networks"] = nets

        ip_policy = db_api.ip_policy_create(context, **ipp)
    return v._make_ip_policy_dict(ip_policy)
示例#13
0
def delete_network(context, id):
    """Delete a network.

    : param context: neutron api request context
    : param id: UUID representing the network to delete.
    """
    LOG.info("delete_network %s for tenant %s" % (id, context.tenant_id))
    net = db_api.network_find(context, id=id, scope=db_api.ONE)
    if not net:
        raise exceptions.NetworkNotFound(net_id=id)
    if net.ports:
        raise exceptions.NetworkInUse(net_id=id)
    net_driver.delete_network(context, id)
    for subnet in net["subnets"]:
        subnets._delete_subnet(context, subnet)
    db_api.network_delete(context, net)
示例#14
0
def delete_network(context, id):
    """Delete a network.

    : param context: neutron api request context
    : param id: UUID representing the network to delete.
    """
    LOG.info("delete_network %s for tenant %s" % (id, context.tenant_id))
    net = db_api.network_find(context, id=id, scope=db_api.ONE)
    if not net:
        raise exceptions.NetworkNotFound(net_id=id)
    if net.ports:
        raise exceptions.NetworkInUse(net_id=id)
    net_driver.delete_network(context, id)
    for subnet in net["subnets"]:
        subnets._delete_subnet(context, subnet)
    db_api.network_delete(context, net)
示例#15
0
def update_network(context, id, network):
    """Update values of a network.

    : param context: neutron api request context
    : param id: UUID representing the network to update.
    : param network: dictionary with keys indicating fields to update.
        valid keys are those that have a value of True for 'allow_put'
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.
    """
    LOG.info("update_network %s for tenant %s" % (id, context.tenant_id))
    net = db_api.network_find(context, id=id, scope=db_api.ONE)
    if not net:
        raise exceptions.NetworkNotFound(net_id=id)
    net = db_api.network_update(context, net, **network["network"])

    return v._make_network_dict(net)
示例#16
0
def get_network(context, id, fields=None):
    """Retrieve a network.

    : param context: neutron api request context
    : param id: UUID representing the network to fetch.
    : param fields: a list of strings that are valid keys in a
        network dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_network %s for tenant %s fields %s" % (id, context.tenant_id, fields))

    network = db_api.network_find(context, id=id, scope=db_api.ONE)

    if not network:
        raise exceptions.NetworkNotFound(net_id=id)
    return v._make_network_dict(network)
示例#17
0
def get_network(context, id, fields=None):
    """Retrieve a network.

    : param context: neutron api request context
    : param id: UUID representing the network to fetch.
    : param fields: a list of strings that are valid keys in a
        network dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_network %s for tenant %s fields %s" %
            (id, context.tenant_id, fields))

    network = db_api.network_find(context, id=id, scope=db_api.ONE)

    if not network:
        raise exceptions.NetworkNotFound(net_id=id)
    return v._make_network_dict(network)
示例#18
0
def update_network(context, id, network):
    """Update values of a network.

    : param context: neutron api request context
    : param id: UUID representing the network to update.
    : param network: dictionary with keys indicating fields to update.
        valid keys are those that have a value of True for 'allow_put'
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.
    """
    LOG.info("update_network %s for tenant %s" %
            (id, context.tenant_id))
    net = db_api.network_find(context, id=id, scope=db_api.ONE)
    if not net:
        raise exceptions.NetworkNotFound(net_id=id)
    net = db_api.network_update(context, net, **network["network"])

    return v._make_network_dict(net)
示例#19
0
def delete_network(context, id):
    """Delete a network.

    : param context: neutron api request context
    : param id: UUID representing the network to delete.
    """
    LOG.info("delete_network %s for tenant %s" % (id, context.tenant_id))
    with context.session.begin():
        net = db_api.network_find(context, None, None, None, False, id=id,
                                  scope=db_api.ONE)
        if not net:
            raise exceptions.NetworkNotFound(net_id=id)
        if net.ports:
            raise exceptions.NetworkInUse(net_id=id)
        net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])
        net_driver.delete_network(context, id)
        for subnet in net["subnets"]:
            subnets._delete_subnet(context, subnet)
        db_api.network_delete(context, net)
示例#20
0
def update_ip_policy(context, id, ip_policy):
    LOG.info("update_ip_policy for tenant %s" % context.tenant_id)

    ipp = ip_policy["ip_policy"]

    with context.session.begin():
        ipp_db = db_api.ip_policy_find(context, id=id, scope=db_api.ONE)
        if not ipp_db:
            raise quark_exceptions.IPPolicyNotFound(id=id)

        network_ids = ipp.get("network_ids")
        subnet_ids = ipp.get("subnet_ids")

        models = []
        if subnet_ids:
            for subnet in ipp_db["subnets"]:
                subnet["ip_policy"] = None
            subnets = db_api.subnet_find(
                context, id=subnet_ids, scope=db_api.ALL)
            if len(subnets) != len(subnet_ids):
                raise exceptions.SubnetNotFound(id=subnet_ids)
            models.extend(subnets)

        if network_ids:
            for network in ipp_db["networks"]:
                network["ip_policy"] = None
            nets = db_api.network_find(context, id=network_ids,
                                       scope=db_api.ALL)
            if len(nets) != len(network_ids):
                raise exceptions.NetworkNotFound(net_id=network_ids)
            models.extend(nets)

        for model in models:
            if model["ip_policy"]:
                raise quark_exceptions.IPPolicyAlreadyExists(
                    id=model["ip_policy"]["id"], n_id=model["id"])
            model["ip_policy"] = ipp_db

        ipp_db = db_api.ip_policy_update(context, ipp_db, **ipp)
    return v._make_ip_policy_dict(ipp_db)
示例#21
0
def update_network(context, id, network):
    """Update values of a network.

    : param context: neutron api request context
    : param id: UUID representing the network to update.
    : param network: dictionary with keys indicating fields to update.
        valid keys are those that have a value of True for 'allow_put'
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.
    """
    LOG.info("update_network %s for tenant %s" % (id, context.tenant_id))
    with context.session.begin():
        net = db_api.network_find(context, id=id, scope=db_api.ONE)
        if not net:
            raise n_exc.NetworkNotFound(net_id=id)
        net_dict = network["network"]
        utils.pop_param(net_dict, "network_plugin")
        if not context.is_admin and "ipam_strategy" in net_dict:
            utils.pop_param(net_dict, "ipam_strategy")
        net = db_api.network_update(context, net, **net_dict)

    return v._make_network_dict(net)
示例#22
0
def delete_network(context, id):
    """Delete a network.

    : param context: neutron api request context
    : param id: UUID representing the network to delete.
    """
    LOG.info("delete_network %s for tenant %s" % (id, context.tenant_id))
    with context.session.begin():
        net = db_api.network_find(context=context, limit=None, sorts=['id'],
                                  marker=None, page_reverse=False, id=id,
                                  scope=db_api.ONE)
        if not net:
            raise n_exc.NetworkNotFound(net_id=id)
        if not context.is_admin:
            if STRATEGY.is_provider_network(net.id):
                raise n_exc.NotAuthorized(net_id=id)
        if net.ports:
            raise n_exc.NetworkInUse(net_id=id)
        net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])
        net_driver.delete_network(context, id)
        for subnet in net["subnets"]:
            subnets._delete_subnet(context, subnet)
        db_api.network_delete(context, net)
示例#23
0
def get_networks(context, filters=None, fields=None):
    """Retrieve a list of networks.

    The contents of the list depends on the identity of the user
    making the request (as indicated by the context) as well as any
    filters.
    : param context: neutron api request context
    : param filters: a dictionary with keys that are valid keys for
        a network as listed in the RESOURCE_ATTRIBUTE_MAP object
        in neutron/api/v2/attributes.py.  Values in this dictiontary
        are an iterable containing values that will be used for an exact
        match comparison for that value.  Each result returned by this
        function will have matched one of the values for each key in
        filters.
    : param fields: a list of strings that are valid keys in a
        network dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_networks for tenant %s with filters %s, fields %s" %
            (context.tenant_id, filters, fields))
    nets = db_api.network_find(context, **filters)
    return [v._make_network_dict(net) for net in nets]
示例#24
0
def update_network(context, id, network):
    """Update values of a network.

    : param context: neutron api request context
    : param id: UUID representing the network to update.
    : param network: dictionary with keys indicating fields to update.
        valid keys are those that have a value of True for 'allow_put'
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.
    """
    LOG.info("update_network %s for tenant %s" %
             (id, context.tenant_id))
    with context.session.begin():
        net = db_api.network_find(context, id=id, scope=db_api.ONE)
        if not net:
            raise n_exc.NetworkNotFound(net_id=id)
        net_dict = network["network"]
        utils.pop_param(net_dict, "network_plugin")
        if not context.is_admin and "ipam_strategy" in net_dict:
            utils.pop_param(net_dict, "ipam_strategy")
        net = db_api.network_update(context, net, **net_dict)

    return v._make_network_dict(net)
示例#25
0
def delete_network(context, id):
    """Delete a network.

    : param context: neutron api request context
    : param id: UUID representing the network to delete.
    """
    LOG.info("delete_network %s for tenant %s" % (id, context.tenant_id))
    with context.session.begin():
        net = db_api.network_find(context,
                                  None,
                                  None,
                                  None,
                                  False,
                                  id=id,
                                  scope=db_api.ONE)
        if not net:
            raise exceptions.NetworkNotFound(net_id=id)
        if net.ports:
            raise exceptions.NetworkInUse(net_id=id)
        net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])
        net_driver.delete_network(context, id)
        for subnet in net["subnets"]:
            subnets._delete_subnet(context, subnet)
        db_api.network_delete(context, net)
示例#26
0
文件: subnets.py 项目: jkoelker/quark
def create_subnet(context, subnet):
    """Create a subnet.

    Create a subnet which represents a range of IP addresses
    that can be allocated to devices

    : param context: neutron api request context
    : param subnet: dictionary describing the subnet, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_subnet for tenant %s" % context.tenant_id)
    net_id = subnet["subnet"]["network_id"]

    with context.session.begin():
        net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
        if not net:
            raise exceptions.NetworkNotFound(net_id=net_id)

        sub_attrs = subnet["subnet"]

        _validate_subnet_cidr(context, net_id, sub_attrs["cidr"])

        cidr = netaddr.IPNetwork(sub_attrs["cidr"])
        gateway_ip = utils.pop_param(sub_attrs, "gateway_ip", str(cidr[1]))
        dns_ips = utils.pop_param(sub_attrs, "dns_nameservers", [])
        host_routes = utils.pop_param(sub_attrs, "host_routes", [])
        allocation_pools = utils.pop_param(sub_attrs, "allocation_pools", None)
        sub_attrs["network"] = net

        new_subnet = db_api.subnet_create(context, **sub_attrs)

        default_route = None
        for route in host_routes:
            netaddr_route = netaddr.IPNetwork(route["destination"])
            if netaddr_route.value == routes.DEFAULT_ROUTE.value:
                default_route = route
                gateway_ip = default_route["nexthop"]
            new_subnet["routes"].append(db_api.route_create(
                context, cidr=route["destination"], gateway=route["nexthop"]))

        if default_route is None:
            new_subnet["routes"].append(db_api.route_create(
                context, cidr=str(routes.DEFAULT_ROUTE), gateway=gateway_ip))

        for dns_ip in dns_ips:
            new_subnet["dns_nameservers"].append(db_api.dns_create(
                context, ip=netaddr.IPAddress(dns_ip)))

        if isinstance(allocation_pools, list):
            ranges = []
            cidrset = netaddr.IPSet([netaddr.IPNetwork(new_subnet["cidr"])])
            for p in allocation_pools:
                cidrset -= netaddr.IPSet(netaddr.IPRange(p["start"], p["end"]))
            non_allocation_pools = v._pools_from_cidr(cidrset)
            for p in non_allocation_pools:
                r = netaddr.IPRange(p["start"], p["end"])
                ranges.append(dict(
                    length=len(r),
                    offset=int(r[0]) - int(cidr[0])))
            new_subnet["ip_policy"] = db_api.ip_policy_create(context,
                                                              exclude=ranges)

    subnet_dict = v._make_subnet_dict(new_subnet,
                                      default_route=routes.DEFAULT_ROUTE)
    subnet_dict["gateway_ip"] = gateway_ip

    notifier_api.notify(context,
                        notifier_api.publisher_id("network"),
                        "ip_block.create",
                        notifier_api.CONF.default_notification_level,
                        dict(tenant_id=subnet_dict["tenant_id"],
                             ip_block_id=subnet_dict["id"],
                             created_at=new_subnet["created_at"]))

    return subnet_dict
示例#27
0
文件: ports.py 项目: blamarvt/quark
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")
    net_id = port_attrs["network_id"]
    addresses = []

    with context.session.begin():
        port_id = uuidutils.generate_uuid()

        net = db_api.network_find(context, id=net_id, segment_id=segment_id, scope=db_api.ONE)
        if not net:
            # Maybe it's a tenant network
            net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
            if not net:
                raise exceptions.NetworkNotFound(net_id=net_id)

        if not STRATEGY.is_parent_network(net_id):
            quota.QUOTAS.limit_check(context, context.tenant_id, ports_per_network=len(net.get("ports", [])) + 1)

        ipam_driver = ipam.IPAM_REGISTRY.get_strategy(net["ipam_strategy"])
        if fixed_ips:
            for fixed_ip in fixed_ips:
                subnet_id = fixed_ip.get("subnet_id")
                ip_address = fixed_ip.get("ip_address")
                if not (subnet_id and ip_address):
                    raise exceptions.BadRequest(resource="fixed_ips", msg="subnet_id and ip_address required")
                addresses.extend(
                    ipam_driver.allocate_ip_address(
                        context, net["id"], port_id, CONF.QUARK.ipam_reuse_after, ip_address=ip_address
                    )
                )
        else:
            addresses.extend(ipam_driver.allocate_ip_address(context, net["id"], port_id, CONF.QUARK.ipam_reuse_after))

        group_ids, security_groups = v.make_security_group_list(context, port["port"].pop("security_groups", None))
        mac = ipam_driver.allocate_mac_address(
            context, net["id"], port_id, CONF.QUARK.ipam_reuse_after, mac_address=mac_address
        )
        mac_address_string = str(netaddr.EUI(mac["address"], dialect=netaddr.mac_unix))
        address_pairs = [
            {"mac_address": mac_address_string, "ip_address": address.get("address_readable", "")}
            for address in addresses
        ]
        net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])
        backend_port = net_driver.create_port(
            context, net["id"], port_id=port_id, security_groups=group_ids, allowed_pairs=address_pairs
        )

        port_attrs["network_id"] = net["id"]
        port_attrs["id"] = port_id
        port_attrs["security_groups"] = security_groups

        LOG.info("Including extra plugin attrs: %s" % backend_port)
        port_attrs.update(backend_port)
        new_port = db_api.port_create(
            context, addresses=addresses, mac_address=mac["address"], backend_key=backend_port["uuid"], **port_attrs
        )

        # Include any driver specific bits
    return v._make_port_dict(new_port)
示例#28
0
def create_ip_address(context, body):
    LOG.info("create_ip_address for tenant %s" % context.tenant_id)
    iptype = (ip_types.SHARED if _shared_ip_request(body)
              else ip_types.FIXED)
    if 'ip_address' not in body:
        raise n_exc.BadRequest(resource="ip_addresses",
                               msg="Invalid request body.")
    if iptype == ip_types.FIXED and not CONF.QUARK.ipaddr_allow_fixed_ip:
        raise n_exc.BadRequest(resource="ip_addresses",
                               msg="Only shared IPs may be made with "
                                   "this resource.")
    ip_dict = body.get("ip_address")
    port_ids = ip_dict.get('port_ids', [])
    network_id = ip_dict.get('network_id')
    tenant_id = ip_dict.get('tenant_id')
    device_ids = ip_dict.get('device_ids')
    ip_version = ip_dict.get('version')
    ip_address = ip_dict.get('ip_address')
    # If no version is passed, you would get what the network provides,
    # which could be both v4 and v6 addresses. Rather than allow for such
    # an ambiguous outcome, we'll raise instead
    if not ip_version:
        raise n_exc.BadRequest(resource="ip_addresses",
                               msg="version is required.")
    if network_id is None:
        raise n_exc.BadRequest(resource="ip_addresses",
                               msg="network_id is required.")
    if network_id == "":
        raise n_exc.NetworkNotFound(net_id=network_id)
    net = db_api.network_find(context, None, None, None, False,
                              id=network_id, scope=db_api.ONE)
    if not net:
        raise n_exc.NetworkNotFound(net_id=network_id)
    if not port_ids and not device_ids:
        raise n_exc.BadRequest(resource="ip_addresses",
                               msg="port_ids or device_ids required.")

    new_addresses = []
    ports = []
    by_device = False
    with context.session.begin():
        if network_id and device_ids:
            by_device = True
            for device_id in device_ids:
                port = db_api.port_find(
                    context, network_id=network_id, device_id=device_id,
                    tenant_id=tenant_id, scope=db_api.ONE)
                if port is not None:
                    ports.append(port)
        elif port_ids:
            for port_id in port_ids:

                port = db_api.port_find(context, id=port_id,
                                        tenant_id=tenant_id,
                                        scope=db_api.ONE)
                if port is not None:
                    ports.append(port)

        if not ports:
            raise n_exc.PortNotFoundOnNetwork(port_id=port_ids,
                                              net_id=network_id)

    if ((by_device and len(device_ids) != len(ports)) or
            (not by_device and len(port_ids) != len(ports))):
        raise q_exc.NotAllPortOrDeviceFound()

    segment_id = validate_and_fetch_segment(ports, network_id)
    if iptype == ip_types.SHARED:
        old_addresses = db_api.ip_address_find(context,
                                               network_id=network_id,
                                               tenant_id=tenant_id,
                                               address_type=ip_types.SHARED,
                                               scope=db_api.ALL)
        validate_shared_ips_quotas(context, network_id, old_addresses)
    validate_port_ip_quotas(context, network_id, ports)

    # Shared Ips are only new IPs. Two use cases: if we got device_id
    # or if we got port_ids. We should check the case where we got port_ids
    # and device_ids. The device_id must have a port on the network,
    # and any port_ids must also be on that network already. If we have
    # more than one port by this step, it's considered a shared IP,
    # and therefore will be marked as unconfigured (enabled=False)
    # for all ports.
    ipam_driver.allocate_ip_address(context, new_addresses, network_id,
                                    None, CONF.QUARK.ipam_reuse_after,
                                    version=ip_version,
                                    ip_addresses=[ip_address]
                                    if ip_address else [],
                                    segment_id=segment_id,
                                    address_type=iptype)
    with context.session.begin():
        address = new_addresses[0]
        new_address = db_api.port_associate_ip(context, ports, address)
    return v._make_ip_dict(new_address)
示例#29
0
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)
    port_attrs = port["port"]

    admin_only = [
        "mac_address", "device_owner", "bridge", "admin_state_up",
        "use_forbidden_mac_range", "network_plugin", "instance_node_id"
    ]
    utils.filter_body(context, port_attrs, admin_only=admin_only)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    use_forbidden_mac_range = utils.pop_param(port_attrs,
                                              "use_forbidden_mac_range", False)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")

    if "device_id" not in port_attrs:
        port_attrs['device_id'] = ""
    device_id = port_attrs['device_id']

    # NOTE(morgabra) This should be instance.node from nova, only needed
    # for ironic_driver.
    if "instance_node_id" not in port_attrs:
        port_attrs['instance_node_id'] = ""
    instance_node_id = port_attrs['instance_node_id']

    net_id = port_attrs["network_id"]

    port_id = uuidutils.generate_uuid()

    net = db_api.network_find(context=context,
                              limit=None,
                              sorts=['id'],
                              marker=None,
                              page_reverse=False,
                              fields=None,
                              id=net_id,
                              scope=db_api.ONE)

    if not net:
        raise n_exc.NetworkNotFound(net_id=net_id)
    _raise_if_unauthorized(context, net)

    # NOTE (Perkins): If a device_id is given, try to prevent multiple ports
    # from being created for a device already attached to the network
    if device_id:
        existing_ports = db_api.port_find(context,
                                          network_id=net_id,
                                          device_id=device_id,
                                          scope=db_api.ONE)
        if existing_ports:
            raise n_exc.BadRequest(
                resource="port",
                msg="This device is already connected to the "
                "requested network via another port")

    # Try to fail early on quotas and save ourselves some db overhead
    if fixed_ips:
        quota.QUOTAS.limit_check(context,
                                 context.tenant_id,
                                 fixed_ips_per_port=len(fixed_ips))

    if not STRATEGY.is_provider_network(net_id):
        # We don't honor segmented networks when they aren't "shared"
        segment_id = None
        port_count = db_api.port_count_all(context,
                                           network_id=[net_id],
                                           tenant_id=[context.tenant_id])
        quota.QUOTAS.limit_check(context,
                                 context.tenant_id,
                                 ports_per_network=port_count + 1)
    else:
        if not segment_id:
            raise q_exc.AmbiguousNetworkId(net_id=net_id)

    network_plugin = utils.pop_param(port_attrs, "network_plugin")
    if not network_plugin:
        network_plugin = net["network_plugin"]
    port_attrs["network_plugin"] = network_plugin

    ipam_driver = _get_ipam_driver(net, port=port_attrs)
    net_driver = _get_net_driver(net, port=port_attrs)
    # NOTE(morgabra) It's possible that we select a driver different than
    # the one specified by the network. However, we still might need to use
    # this for some operations, so we also fetch it and pass it along to
    # the backend driver we are actually using.
    base_net_driver = _get_net_driver(net)

    # TODO(anyone): security groups are not currently supported on port create.
    #               Please see JIRA:NCP-801
    security_groups = utils.pop_param(port_attrs, "security_groups")
    if security_groups is not None:
        raise q_exc.SecurityGroupsNotImplemented()

    group_ids, security_groups = _make_security_group_list(
        context, security_groups)
    quota.QUOTAS.limit_check(context,
                             context.tenant_id,
                             security_groups_per_port=len(group_ids))
    addresses = []
    backend_port = None

    with utils.CommandManager().execute() as cmd_mgr:

        @cmd_mgr.do
        def _allocate_ips(fixed_ips, net, port_id, segment_id, mac, **kwargs):
            if fixed_ips:
                if (STRATEGY.is_provider_network(net_id)
                        and not context.is_admin):
                    raise n_exc.NotAuthorized()

                ips, subnets = split_and_validate_requested_subnets(
                    context, net_id, segment_id, fixed_ips)
                kwargs["ip_addresses"] = ips
                kwargs["subnets"] = subnets

            ipam_driver.allocate_ip_address(context,
                                            addresses,
                                            net["id"],
                                            port_id,
                                            CONF.QUARK.ipam_reuse_after,
                                            segment_id=segment_id,
                                            mac_address=mac,
                                            **kwargs)

        @cmd_mgr.undo
        def _allocate_ips_undo(addr, **kwargs):
            LOG.info("Rolling back IP addresses...")
            if addresses:
                for address in addresses:
                    try:
                        with context.session.begin():
                            ipam_driver.deallocate_ip_address(
                                context, address, **kwargs)
                    except Exception:
                        LOG.exception("Couldn't release IP %s" % address)

        @cmd_mgr.do
        def _allocate_mac(net,
                          port_id,
                          mac_address,
                          use_forbidden_mac_range=False,
                          **kwargs):
            mac = ipam_driver.allocate_mac_address(
                context,
                net["id"],
                port_id,
                CONF.QUARK.ipam_reuse_after,
                mac_address=mac_address,
                use_forbidden_mac_range=use_forbidden_mac_range,
                **kwargs)
            return mac

        @cmd_mgr.undo
        def _allocate_mac_undo(mac, **kwargs):
            LOG.info("Rolling back MAC address...")
            if mac:
                try:
                    with context.session.begin():
                        ipam_driver.deallocate_mac_address(
                            context, mac["address"])
                except Exception:
                    LOG.exception("Couldn't release MAC %s" % mac)

        @cmd_mgr.do
        def _allocate_backend_port(mac, addresses, net, port_id, **kwargs):
            backend_port = net_driver.create_port(
                context,
                net["id"],
                port_id=port_id,
                security_groups=group_ids,
                device_id=device_id,
                instance_node_id=instance_node_id,
                mac_address=mac,
                addresses=addresses,
                base_net_driver=base_net_driver)
            _filter_backend_port(backend_port)
            return backend_port

        @cmd_mgr.undo
        def _allocate_back_port_undo(backend_port, **kwargs):
            LOG.info("Rolling back backend port...")
            try:
                backend_port_uuid = None
                if backend_port:
                    backend_port_uuid = backend_port.get("uuid")
                net_driver.delete_port(context, backend_port_uuid)
            except Exception:
                LOG.exception("Couldn't rollback backend port %s" %
                              backend_port)

        @cmd_mgr.do
        def _allocate_db_port(port_attrs, backend_port, addresses, mac,
                              **kwargs):
            port_attrs["network_id"] = net["id"]
            port_attrs["id"] = port_id
            port_attrs["security_groups"] = security_groups

            LOG.info("Including extra plugin attrs: %s" % backend_port)
            port_attrs.update(backend_port)
            with context.session.begin():
                new_port = db_api.port_create(context,
                                              addresses=addresses,
                                              mac_address=mac["address"],
                                              backend_key=backend_port["uuid"],
                                              **port_attrs)

            return new_port

        @cmd_mgr.undo
        def _allocate_db_port_undo(new_port, **kwargs):
            LOG.info("Rolling back database port...")
            if not new_port:
                return
            try:
                with context.session.begin():
                    db_api.port_delete(context, new_port)
            except Exception:
                LOG.exception("Couldn't rollback db port %s" % backend_port)

        # addresses, mac, backend_port, new_port
        mac = _allocate_mac(net,
                            port_id,
                            mac_address,
                            use_forbidden_mac_range=use_forbidden_mac_range)
        _allocate_ips(fixed_ips, net, port_id, segment_id, mac)
        backend_port = _allocate_backend_port(mac, addresses, net, port_id)
        new_port = _allocate_db_port(port_attrs, backend_port, addresses, mac)

    return v._make_port_dict(new_port)
示例#30
0
def update_ip_policy(context, id, ip_policy):
    LOG.info("update_ip_policy for tenant %s" % context.tenant_id)

    ipp = ip_policy["ip_policy"]

    with context.session.begin():
        ipp_db = db_api.ip_policy_find(context, id=id, scope=db_api.ONE)
        if not ipp_db:
            raise q_exc.IPPolicyNotFound(id=id)

        ip_policy_cidrs = ipp.get("exclude")
        network_ids = ipp.get("network_ids")
        subnet_ids = ipp.get("subnet_ids")

        if subnet_ids and network_ids:
            raise n_exc.BadRequest(
                resource="ip_policy",
                msg="network_ids and subnet_ids specified. only one allowed")

        models = []
        all_subnets = []
        if subnet_ids:
            for subnet in ipp_db["subnets"]:
                subnet["ip_policy"] = None
            subnets = db_api.subnet_find(context,
                                         id=subnet_ids,
                                         scope=db_api.ALL)
            if len(subnets) != len(subnet_ids):
                raise n_exc.SubnetNotFound(subnet_id=subnet_ids)
            if ip_policy_cidrs is not None:
                ensure_default_policy(ip_policy_cidrs, subnets)
                _validate_cidrs_fit_into_subnets(ip_policy_cidrs, subnets)
            all_subnets.extend(subnets)
            models.extend(subnets)

        if network_ids:
            for network in ipp_db["networks"]:
                network["ip_policy"] = None
            nets = db_api.network_find(context,
                                       id=network_ids,
                                       scope=db_api.ALL)
            if len(nets) != len(network_ids):
                raise n_exc.NetworkNotFound(net_id=network_ids)
            subnets = [
                subnet for net in nets for subnet in net.get("subnets", [])
            ]
            if ip_policy_cidrs is not None:
                ensure_default_policy(ip_policy_cidrs, subnets)
                _validate_cidrs_fit_into_subnets(ip_policy_cidrs, subnets)
            all_subnets.extend(subnets)
            models.extend(nets)

        if not subnet_ids and not network_ids and ip_policy_cidrs is not None:
            ensure_default_policy(ip_policy_cidrs, ipp_db["subnets"])
            _validate_cidrs_fit_into_subnets(ip_policy_cidrs,
                                             ipp_db["subnets"])

        for model in models:
            if model["ip_policy"]:
                raise q_exc.IPPolicyAlreadyExists(id=model["ip_policy"]["id"],
                                                  n_id=model["id"])
            model["ip_policy"] = ipp_db

        if ip_policy_cidrs:
            _validate_policy_with_routes(context, ip_policy_cidrs, all_subnets)
        ipp_db = db_api.ip_policy_update(context, ipp_db, **ipp)
    return v._make_ip_policy_dict(ipp_db)
示例#31
0
def create_ip_address(context, body):
    LOG.info("create_ip_address for tenant %s" % context.tenant_id)
    iptype = (ip_types.SHARED if _shared_ip_request(body) else ip_types.FIXED)
    if 'ip_address' not in body:
        raise n_exc.BadRequest(resource="ip_addresses",
                               msg="Invalid request body.")
    if iptype == ip_types.FIXED and not CONF.QUARK.ipaddr_allow_fixed_ip:
        raise n_exc.BadRequest(resource="ip_addresses",
                               msg="Only shared IPs may be made with "
                               "this resource.")
    ip_dict = body.get("ip_address")
    port_ids = ip_dict.get('port_ids', [])
    network_id = ip_dict.get('network_id')
    device_ids = ip_dict.get('device_ids')
    ip_version = ip_dict.get('version')
    ip_address = ip_dict.get('ip_address')
    # If no version is passed, you would get what the network provides,
    # which could be both v4 and v6 addresses. Rather than allow for such
    # an ambiguous outcome, we'll raise instead
    if not ip_version:
        raise n_exc.BadRequest(resource="ip_addresses",
                               msg="version is required.")
    if network_id is None:
        raise n_exc.BadRequest(resource="ip_addresses",
                               msg="network_id is required.")
    if network_id == "":
        raise n_exc.NetworkNotFound(net_id=network_id)
    net = db_api.network_find(context,
                              None,
                              None,
                              None,
                              False,
                              id=network_id,
                              scope=db_api.ONE)
    if not net:
        raise n_exc.NetworkNotFound(net_id=network_id)
    if not port_ids and not device_ids:
        raise n_exc.BadRequest(resource="ip_addresses",
                               msg="port_ids or device_ids required.")

    new_addresses = []
    ports = []
    by_device = False
    with context.session.begin():
        if network_id and device_ids:
            by_device = True
            for device_id in device_ids:
                port = db_api.port_find(context,
                                        network_id=network_id,
                                        device_id=device_id,
                                        tenant_id=context.tenant_id,
                                        scope=db_api.ONE)
                if port is not None:
                    ports.append(port)
        elif port_ids:
            for port_id in port_ids:

                port = db_api.port_find(context,
                                        id=port_id,
                                        tenant_id=context.tenant_id,
                                        scope=db_api.ONE)
                if port is not None:
                    ports.append(port)

        if not ports:
            raise n_exc.PortNotFoundOnNetwork(port_id=port_ids,
                                              net_id=network_id)

    if ((by_device and len(device_ids) != len(ports))
            or (not by_device and len(port_ids) != len(ports))):
        raise q_exc.NotAllPortOrDeviceFound()

    segment_id = validate_and_fetch_segment(ports, network_id)
    if iptype == ip_types.SHARED:
        old_addresses = db_api.ip_address_find(context,
                                               network_id=network_id,
                                               address_type=ip_types.SHARED,
                                               scope=db_api.ALL)
        validate_shared_ips_quotas(context, network_id, old_addresses)
    validate_port_ip_quotas(context, network_id, ports)

    # Shared Ips are only new IPs. Two use cases: if we got device_id
    # or if we got port_ids. We should check the case where we got port_ids
    # and device_ids. The device_id must have a port on the network,
    # and any port_ids must also be on that network already. If we have
    # more than one port by this step, it's considered a shared IP,
    # and therefore will be marked as unconfigured (enabled=False)
    # for all ports.
    ipam_driver.allocate_ip_address(
        context,
        new_addresses,
        network_id,
        None,
        CONF.QUARK.ipam_reuse_after,
        version=ip_version,
        ip_addresses=[ip_address] if ip_address else [],
        segment_id=segment_id,
        address_type=iptype)
    with context.session.begin():
        address = new_addresses[0]
        new_address = db_api.port_associate_ip(context, ports, address)
    return v._make_ip_dict(new_address)
示例#32
0
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")
    net_id = port_attrs["network_id"]
    device_id = port_attrs["device_id"]

    port_id = uuidutils.generate_uuid()

    net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
    if not net:
        raise exceptions.NetworkNotFound(net_id=net_id)

    if not STRATEGY.is_parent_network(net_id):
        # We don't honor segmented networks when they aren't "shared"
        segment_id = None
        port_count = db_api.port_count_all(context, network_id=[net_id],
                                           tenant_id=[context.tenant_id])

        quota.QUOTAS.limit_check(
            context, context.tenant_id,
            ports_per_network=port_count + 1)
    else:
        if not segment_id:
            raise q_exc.AmbiguousNetworkId(net_id=net_id)

    ipam_driver = ipam.IPAM_REGISTRY.get_strategy(net["ipam_strategy"])
    net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])
    group_ids, security_groups = v.make_security_group_list(
        context, port["port"].pop("security_groups", None))

    addresses = []
    mac = None
    backend_port = None

    with utils.CommandManager().execute() as cmd_mgr:
        @cmd_mgr.do
        def _allocate_ips(fixed_ips, net, port_id, segment_id, mac):
            if fixed_ips:
                for fixed_ip in fixed_ips:
                    subnet_id = fixed_ip.get("subnet_id")
                    ip_address = fixed_ip.get("ip_address")
                    if not (subnet_id and ip_address):
                        raise exceptions.BadRequest(
                            resource="fixed_ips",
                            msg="subnet_id and ip_address required")
                    ipam_driver.allocate_ip_address(
                        context, addresses, net["id"], port_id,
                        CONF.QUARK.ipam_reuse_after, segment_id=segment_id,
                        ip_address=ip_address, subnets=[subnet_id],
                        mac_address=mac)
            else:
                ipam_driver.allocate_ip_address(
                    context, addresses, net["id"], port_id,
                    CONF.QUARK.ipam_reuse_after, segment_id=segment_id,
                    mac_address=mac)

        @cmd_mgr.undo
        def _allocate_ips_undo(addr):
            LOG.info("Rolling back IP addresses...")
            if addresses:
                for address in addresses:
                    try:
                        with context.session.begin():
                            ipam_driver.deallocate_ip_address(context, address)
                    except Exception:
                        LOG.exception("Couldn't release IP %s" % address)

        @cmd_mgr.do
        def _allocate_mac(net, port_id, mac_address):
            mac = ipam_driver.allocate_mac_address(
                context, net["id"], port_id, CONF.QUARK.ipam_reuse_after,
                mac_address=mac_address)
            return mac

        @cmd_mgr.undo
        def _allocate_mac_undo(mac):
            LOG.info("Rolling back MAC address...")
            if mac:
                try:
                    with context.session.begin():
                        ipam_driver.deallocate_mac_address(context,
                                                           mac["address"])
                except Exception:
                    LOG.exception("Couldn't release MAC %s" % mac)

        @cmd_mgr.do
        def _allocate_backend_port(mac, addresses, net, port_id):
            backend_port = net_driver.create_port(context, net["id"],
                                                  port_id=port_id,
                                                  security_groups=group_ids,
                                                  device_id=device_id)
            return backend_port

        @cmd_mgr.undo
        def _allocate_back_port_undo(backend_port):
            LOG.info("Rolling back backend port...")
            try:
                net_driver.delete_port(context, backend_port["uuid"])
            except Exception:
                LOG.exception(
                    "Couldn't rollback backend port %s" % backend_port)

        @cmd_mgr.do
        def _allocate_db_port(port_attrs, backend_port, addresses, mac):
            port_attrs["network_id"] = net["id"]
            port_attrs["id"] = port_id
            port_attrs["security_groups"] = security_groups

            LOG.info("Including extra plugin attrs: %s" % backend_port)
            port_attrs.update(backend_port)
            with context.session.begin():
                new_port = db_api.port_create(
                    context, addresses=addresses, mac_address=mac["address"],
                    backend_key=backend_port["uuid"], **port_attrs)

            return new_port

        @cmd_mgr.undo
        def _allocate_db_port_undo(new_port):
            LOG.info("Rolling back database port...")
            if not new_port:
                return
            try:
                with context.session.begin():
                    db_api.port_delete(context, new_port)
            except Exception:
                LOG.exception(
                    "Couldn't rollback db port %s" % backend_port)

        # addresses, mac, backend_port, new_port
        mac = _allocate_mac(net, port_id, mac_address)
        _allocate_ips(fixed_ips, net, port_id, segment_id, mac)
        backend_port = _allocate_backend_port(mac, addresses, net, port_id)
        new_port = _allocate_db_port(port_attrs, backend_port, addresses, mac)

    return v._make_port_dict(new_port)
示例#33
0
def create_network(context, network):
    """Create a network.

    Create a network which represents an L2 network segment which
    can have a set of subnets and ports associated with it.
    : param context: neutron api request context
    : param network: dictionary describing the network, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_network for tenant %s" % context.tenant_id)

    with context.session.begin():
        net_attrs = network["network"]
        subs = net_attrs.pop("subnets", [])
        # Enforce subnet quotas
        if not context.is_admin:
            if len(subs) > 0:
                v4_count, v6_count = 0, 0
                for s in subs:
                    version = netaddr.IPNetwork(s['subnet']['cidr']).version
                    if version == 6:
                        v6_count += 1
                    else:
                        v4_count += 1
                if v4_count > 0:
                    tenant_q_v4 = context.session.query(qdv.Quota).filter_by(
                        tenant_id=context.tenant_id,
                        resource='v4_subnets_per_network').first()
                    if tenant_q_v4 != -1:
                        quota.QUOTAS.limit_check(
                            context,
                            context.tenant_id,
                            v4_subnets_per_network=v4_count)
                if v6_count > 0:
                    tenant_q_v6 = context.session.query(qdv.Quota).filter_by(
                        tenant_id=context.tenant_id,
                        resource='v6_subnets_per_network').first()
                    if tenant_q_v6 != -1:
                        quota.QUOTAS.limit_check(
                            context,
                            context.tenant_id,
                            v6_subnets_per_network=v6_count)
        # Generate a uuid that we're going to hand to the backend and db
        net_uuid = utils.pop_param(net_attrs, "id", None)
        net_type = None
        if net_uuid and context.is_admin:
            net = db_api.network_find(context=context,
                                      limit=None,
                                      sorts=['id'],
                                      marker=None,
                                      page_reverse=False,
                                      id=net_uuid,
                                      scope=db_api.ONE)
            net_type = utils.pop_param(net_attrs, "network_plugin", None)
            if net:
                raise q_exc.NetworkAlreadyExists(id=net_uuid)
        else:
            net_uuid = uuidutils.generate_uuid()

        # TODO(mdietz) this will be the first component registry hook, but
        #             lets make it work first
        pnet_type, phys_net, seg_id = _adapt_provider_nets(context, network)

        ipam_strategy = utils.pop_param(net_attrs, "ipam_strategy", None)
        if not ipam_strategy or not context.is_admin:
            ipam_strategy = CONF.QUARK.default_ipam_strategy

        if not ipam.IPAM_REGISTRY.is_valid_strategy(ipam_strategy):
            raise q_exc.InvalidIpamStrategy(strat=ipam_strategy)
        net_attrs["ipam_strategy"] = ipam_strategy

        # NOTE(mdietz) I think ideally we would create the providernet
        # elsewhere as a separate driver step that could be
        # kept in a plugin and completely removed if desired. We could
        # have a pre-callback/observer on the netdriver create_network
        # that gathers any additional parameters from the network dict

        default_net_type = net_type or CONF.QUARK.default_network_type
        net_driver = registry.DRIVER_REGISTRY.get_driver(default_net_type)
        net_driver.create_network(context,
                                  net_attrs["name"],
                                  network_id=net_uuid,
                                  phys_type=pnet_type,
                                  phys_net=phys_net,
                                  segment_id=seg_id)

        net_attrs["id"] = net_uuid
        net_attrs["tenant_id"] = context.tenant_id
        net_attrs["network_plugin"] = default_net_type
        new_net = db_api.network_create(context, **net_attrs)

        new_subnets = []
        for sub in subs:
            sub["subnet"]["network_id"] = new_net["id"]
            sub["subnet"]["tenant_id"] = context.tenant_id
            s = db_api.subnet_create(context, **sub["subnet"])
            new_subnets.append(s)
        new_net["subnets"] = new_subnets

        # if not security_groups.get_security_groups(
        #        context,
        #        filters={"id": security_groups.DEFAULT_SG_UUID}):
        #    security_groups._create_default_security_group(context)
    return v._make_network_dict(new_net)
示例#34
0
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")
    net_id = port_attrs["network_id"]
    addresses = []

    port_id = uuidutils.generate_uuid()

    net = db_api.network_find(context,
                              id=net_id,
                              shared=True,
                              segment_id=segment_id,
                              scope=db_api.ONE)
    if not net:
        # Maybe it's a tenant network
        net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
        if not net:
            raise exceptions.NetworkNotFound(net_id=net_id)

    quota.QUOTAS.limit_check(context,
                             context.tenant_id,
                             ports_per_network=len(net.get('ports', [])) + 1)

    if fixed_ips:
        for fixed_ip in fixed_ips:
            subnet_id = fixed_ip.get("subnet_id")
            ip_address = fixed_ip.get("ip_address")
            if not (subnet_id and ip_address):
                raise exceptions.BadRequest(
                    resource="fixed_ips",
                    msg="subnet_id and ip_address required")
            addresses.append(
                ipam_driver.allocate_ip_address(context,
                                                net["id"],
                                                port_id,
                                                CONF.QUARK.ipam_reuse_after,
                                                ip_address=ip_address))
    else:
        addresses.append(
            ipam_driver.allocate_ip_address(context, net["id"], port_id,
                                            CONF.QUARK.ipam_reuse_after))

    group_ids, security_groups = v.make_security_group_list(
        context, port["port"].pop("security_groups", None))
    mac = ipam_driver.allocate_mac_address(context,
                                           net["id"],
                                           port_id,
                                           CONF.QUARK.ipam_reuse_after,
                                           mac_address=mac_address)
    mac_address_string = str(
        netaddr.EUI(mac['address'], dialect=netaddr.mac_unix))
    address_pairs = [{
        'mac_address': mac_address_string,
        'ip_address': address.get('address_readable', '')
    } for address in addresses]
    backend_port = net_driver.create_port(context,
                                          net["id"],
                                          port_id=port_id,
                                          security_groups=group_ids,
                                          allowed_pairs=address_pairs)

    port_attrs["network_id"] = net["id"]
    port_attrs["id"] = port_id
    port_attrs["security_groups"] = security_groups
    new_port = db_api.port_create(context,
                                  addresses=addresses,
                                  mac_address=mac["address"],
                                  backend_key=backend_port["uuid"],
                                  **port_attrs)
    return v._make_port_dict(new_port)
示例#35
0
def create_floatingip(context, content):
    LOG.info("create_floatingip %s for tenant %s and body %s" %
             (id, context.tenant_id, content))
    tenant_id = content.get("tenant_id")
    network_id = content.get("floating_network_id")
    fixed_ip_address = content.get("fixed_ip_address")
    ip_address = content.get("floating_ip_address")
    port_id = content.get("port_id")

    if not tenant_id:
        tenant_id = context.tenant_id

    if not network_id:
        raise exceptions.BadRequest(resource="floating_ip",
                                    msg="floating_network_id is required.")

    network = db_api.network_find(context, id=network_id, scope=db_api.ONE)

    if not network:
        raise exceptions.NetworkNotFound(net_id=network_id)

    fixed_ip = None
    port = None
    if port_id:
        port = db_api.port_find(context, id=port_id, scope=db_api.ONE)

        if not port:
            raise exceptions.PortNotFound(port_id=port_id)

        if not port.ip_addresses or len(port.ip_addresses) == 0:
            raise quark_exceptions.NoAvailableFixedIPsForPort(port_id=port_id)

        if not fixed_ip_address:
            fixed_ip = _get_next_available_fixed_ip(port)
            if not fixed_ip:
                raise quark_exceptions.NoAvailableFixedIPsForPort(
                    port_id=port_id)
        else:
            fixed_ip = next((ip for ip in port.ip_addresses
                            if (ip["address_readable"] == fixed_ip_address and
                                ip.get("address_type") == ip_types.FIXED)),
                            None)

            if not fixed_ip:
                raise quark_exceptions.FixedIpDoesNotExistsForPort(
                    fixed_ip=fixed_ip_address, port_id=port_id)

            if any(ip for ip in port.ip_addresses
                   if (ip.get("address_type") == ip_types.FLOATING and
                       ip.fixed_ip["address_readable"] == fixed_ip_address)):
                raise quark_exceptions.PortAlreadyContainsFloatingIp(
                    port_id=port_id)

    new_addresses = []
    ip_addresses = []
    if ip_address:
        ip_addresses.append(ip_address)

    seg_name = CONF.QUARK.floating_ip_segment_name
    strategy_name = network.get("ipam_strategy")
    ipam_driver = ipam.IPAM_REGISTRY.get_strategy(strategy_name)
    ipam_driver.allocate_ip_address(context, new_addresses, network_id,
                                    port_id, CONF.QUARK.ipam_reuse_after,
                                    seg_name, version=4,
                                    ip_addresses=ip_addresses,
                                    address_type=ip_types.FLOATING)

    floating_ip = new_addresses[0]

    if fixed_ip and port:
        with context.session.begin():
            floating_ip = db_api.floating_ip_associate_fixed_ip(context,
                                                                floating_ip,
                                                                fixed_ip)

        flip_driver_type = CONF.QUARK.default_floating_ip_driver
        flip_driver = registry.DRIVER_REGISTRY.get_driver(flip_driver_type)

        flip_driver.register_floating_ip(floating_ip, port, fixed_ip)

    return v._make_floating_ip_dict(floating_ip)
示例#36
0
def _get_network(context, network_id):
    network = db_api.network_find(context, id=network_id, scope=db_api.ONE)
    if not network:
        raise n_exc.NetworkNotFound(net_id=network_id)
    return network
示例#37
0
文件: ports.py 项目: openstack/quark
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)
    port_attrs = port["port"]

    admin_only = ["mac_address", "device_owner", "bridge", "admin_state_up",
                  "use_forbidden_mac_range", "network_plugin",
                  "instance_node_id"]
    utils.filter_body(context, port_attrs, admin_only=admin_only)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    use_forbidden_mac_range = utils.pop_param(port_attrs,
                                              "use_forbidden_mac_range", False)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")

    if "device_id" not in port_attrs:
        port_attrs['device_id'] = ""
    device_id = port_attrs['device_id']

    # NOTE(morgabra) This should be instance.node from nova, only needed
    # for ironic_driver.
    if "instance_node_id" not in port_attrs:
        port_attrs['instance_node_id'] = ""
    instance_node_id = port_attrs['instance_node_id']

    net_id = port_attrs["network_id"]

    port_id = uuidutils.generate_uuid()

    net = db_api.network_find(context=context, limit=None, sorts=['id'],
                              marker=None, page_reverse=False, fields=None,
                              id=net_id, scope=db_api.ONE)

    if not net:
        raise n_exc.NetworkNotFound(net_id=net_id)
    _raise_if_unauthorized(context, net)

    # NOTE (Perkins): If a device_id is given, try to prevent multiple ports
    # from being created for a device already attached to the network
    if device_id:
        existing_ports = db_api.port_find(context,
                                          network_id=net_id,
                                          device_id=device_id,
                                          scope=db_api.ONE)
        if existing_ports:
            raise n_exc.BadRequest(
                resource="port", msg="This device is already connected to the "
                "requested network via another port")

    # Try to fail early on quotas and save ourselves some db overhead
    if fixed_ips:
        quota.QUOTAS.limit_check(context, context.tenant_id,
                                 fixed_ips_per_port=len(fixed_ips))

    if not STRATEGY.is_provider_network(net_id):
        # We don't honor segmented networks when they aren't "shared"
        segment_id = None
        port_count = db_api.port_count_all(context, network_id=[net_id],
                                           tenant_id=[context.tenant_id])
        quota.QUOTAS.limit_check(
            context, context.tenant_id,
            ports_per_network=port_count + 1)
    else:
        if not segment_id:
            raise q_exc.AmbiguousNetworkId(net_id=net_id)

    network_plugin = utils.pop_param(port_attrs, "network_plugin")
    if not network_plugin:
        network_plugin = net["network_plugin"]
    port_attrs["network_plugin"] = network_plugin

    ipam_driver = _get_ipam_driver(net, port=port_attrs)
    net_driver = _get_net_driver(net, port=port_attrs)
    # NOTE(morgabra) It's possible that we select a driver different than
    # the one specified by the network. However, we still might need to use
    # this for some operations, so we also fetch it and pass it along to
    # the backend driver we are actually using.
    base_net_driver = _get_net_driver(net)

    # TODO(anyone): security groups are not currently supported on port create.
    #               Please see JIRA:NCP-801
    security_groups = utils.pop_param(port_attrs, "security_groups")
    if security_groups is not None:
        raise q_exc.SecurityGroupsNotImplemented()

    group_ids, security_groups = _make_security_group_list(context,
                                                           security_groups)
    quota.QUOTAS.limit_check(context, context.tenant_id,
                             security_groups_per_port=len(group_ids))
    addresses = []
    backend_port = None

    with utils.CommandManager().execute() as cmd_mgr:
        @cmd_mgr.do
        def _allocate_ips(fixed_ips, net, port_id, segment_id, mac,
                          **kwargs):
            if fixed_ips:
                if (STRATEGY.is_provider_network(net_id) and
                        not context.is_admin):
                    raise n_exc.NotAuthorized()

                ips, subnets = split_and_validate_requested_subnets(context,
                                                                    net_id,
                                                                    segment_id,
                                                                    fixed_ips)
                kwargs["ip_addresses"] = ips
                kwargs["subnets"] = subnets

            ipam_driver.allocate_ip_address(
                context, addresses, net["id"], port_id,
                CONF.QUARK.ipam_reuse_after, segment_id=segment_id,
                mac_address=mac, **kwargs)

        @cmd_mgr.undo
        def _allocate_ips_undo(addr, **kwargs):
            LOG.info("Rolling back IP addresses...")
            if addresses:
                for address in addresses:
                    try:
                        with context.session.begin():
                            ipam_driver.deallocate_ip_address(context, address,
                                                              **kwargs)
                    except Exception:
                        LOG.exception("Couldn't release IP %s" % address)

        @cmd_mgr.do
        def _allocate_mac(net, port_id, mac_address,
                          use_forbidden_mac_range=False,
                          **kwargs):
            mac = ipam_driver.allocate_mac_address(
                context, net["id"], port_id, CONF.QUARK.ipam_reuse_after,
                mac_address=mac_address,
                use_forbidden_mac_range=use_forbidden_mac_range, **kwargs)
            return mac

        @cmd_mgr.undo
        def _allocate_mac_undo(mac, **kwargs):
            LOG.info("Rolling back MAC address...")
            if mac:
                try:
                    with context.session.begin():
                        ipam_driver.deallocate_mac_address(context,
                                                           mac["address"])
                except Exception:
                    LOG.exception("Couldn't release MAC %s" % mac)

        @cmd_mgr.do
        def _allocate_backend_port(mac, addresses, net, port_id, **kwargs):
            backend_port = net_driver.create_port(
                context, net["id"],
                port_id=port_id,
                security_groups=group_ids,
                device_id=device_id,
                instance_node_id=instance_node_id,
                mac_address=mac,
                addresses=addresses,
                base_net_driver=base_net_driver)
            _filter_backend_port(backend_port)
            return backend_port

        @cmd_mgr.undo
        def _allocate_back_port_undo(backend_port,
                                     **kwargs):
            LOG.info("Rolling back backend port...")
            try:
                backend_port_uuid = None
                if backend_port:
                    backend_port_uuid = backend_port.get("uuid")
                net_driver.delete_port(context, backend_port_uuid)
            except Exception:
                LOG.exception(
                    "Couldn't rollback backend port %s" % backend_port)

        @cmd_mgr.do
        def _allocate_db_port(port_attrs, backend_port, addresses, mac,
                              **kwargs):
            port_attrs["network_id"] = net["id"]
            port_attrs["id"] = port_id
            port_attrs["security_groups"] = security_groups

            LOG.info("Including extra plugin attrs: %s" % backend_port)
            port_attrs.update(backend_port)
            with context.session.begin():
                new_port = db_api.port_create(
                    context, addresses=addresses, mac_address=mac["address"],
                    backend_key=backend_port["uuid"], **port_attrs)

            return new_port

        @cmd_mgr.undo
        def _allocate_db_port_undo(new_port,
                                   **kwargs):
            LOG.info("Rolling back database port...")
            if not new_port:
                return
            try:
                with context.session.begin():
                    db_api.port_delete(context, new_port)
            except Exception:
                LOG.exception(
                    "Couldn't rollback db port %s" % backend_port)

        # addresses, mac, backend_port, new_port
        mac = _allocate_mac(net, port_id, mac_address,
                            use_forbidden_mac_range=use_forbidden_mac_range)
        _allocate_ips(fixed_ips, net, port_id, segment_id, mac)
        backend_port = _allocate_backend_port(mac, addresses, net, port_id)
        new_port = _allocate_db_port(port_attrs, backend_port, addresses, mac)

    return v._make_port_dict(new_port)
示例#38
0
def _get_network(context, network_id):
    network = db_api.network_find(context, id=network_id, scope=db_api.ONE)
    if not network:
        raise n_exc.NetworkNotFound(net_id=network_id)
    return network
示例#39
0
def create_network(context, network):
    """Create a network.

    Create a network which represents an L2 network segment which
    can have a set of subnets and ports associated with it.
    : param context: neutron api request context
    : param network: dictionary describing the network, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_network for tenant %s" % context.tenant_id)

    with context.session.begin():
        net_attrs = network["network"]
        subs = net_attrs.pop("subnets", [])
        # Enforce subnet quotas
        if not context.is_admin:
            if len(subs) > 0:
                v4_count, v6_count = 0, 0
                for s in subs:
                    version = netaddr.IPNetwork(s['subnet']['cidr']).version
                    if version == 6:
                        v6_count += 1
                    else:
                        v4_count += 1
                if v4_count > 0:
                    tenant_q_v4 = context.session.query(qdb.Quota).filter_by(
                        tenant_id=context.tenant_id,
                        resource='v4_subnets_per_network').first()
                    if tenant_q_v4 != -1:
                        quota.QUOTAS.limit_check(
                            context,
                            context.tenant_id,
                            v4_subnets_per_network=v4_count)
                if v6_count > 0:
                    tenant_q_v6 = context.session.query(qdb.Quota).filter_by(
                        tenant_id=context.tenant_id,
                        resource='v6_subnets_per_network').first()
                    if tenant_q_v6 != -1:
                        quota.QUOTAS.limit_check(
                            context,
                            context.tenant_id,
                            v6_subnets_per_network=v6_count)
        # Generate a uuid that we're going to hand to the backend and db
        net_uuid = utils.pop_param(net_attrs, "id", None)
        net_type = None
        if net_uuid and context.is_admin:
            net = db_api.network_find(context, id=net_uuid, scope=db_api.ONE)
            net_type = utils.pop_param(net_attrs, "network_plugin", None)
            if net:
                raise q_exc.NetworkAlreadyExists(id=net_uuid)
        else:
            net_uuid = uuidutils.generate_uuid()

        # TODO(mdietz) this will be the first component registry hook, but
        #             lets make it work first
        pnet_type, phys_net, seg_id = _adapt_provider_nets(context, network)

        ipam_strategy = utils.pop_param(net_attrs, "ipam_strategy", None)
        if not ipam_strategy or not context.is_admin:
            ipam_strategy = CONF.QUARK.default_ipam_strategy

        if not ipam.IPAM_REGISTRY.is_valid_strategy(ipam_strategy):
            raise q_exc.InvalidIpamStrategy(strat=ipam_strategy)
        net_attrs["ipam_strategy"] = ipam_strategy

        # NOTE(mdietz) I think ideally we would create the providernet
        # elsewhere as a separate driver step that could be
        # kept in a plugin and completely removed if desired. We could
        # have a pre-callback/observer on the netdriver create_network
        # that gathers any additional parameters from the network dict

        default_net_type = net_type or CONF.QUARK.default_network_type
        net_driver = registry.DRIVER_REGISTRY.get_driver(default_net_type)
        net_driver.create_network(context, net_attrs["name"],
                                  network_id=net_uuid, phys_type=pnet_type,
                                  phys_net=phys_net, segment_id=seg_id)

        net_attrs["id"] = net_uuid
        net_attrs["tenant_id"] = context.tenant_id
        net_attrs["network_plugin"] = default_net_type
        new_net = db_api.network_create(context, **net_attrs)

        new_subnets = []
        for sub in subs:
            sub["subnet"]["network_id"] = new_net["id"]
            sub["subnet"]["tenant_id"] = context.tenant_id
            s = db_api.subnet_create(context, **sub["subnet"])
            new_subnets.append(s)
        new_net["subnets"] = new_subnets

        # if not security_groups.get_security_groups(
        #        context,
        #        filters={"id": security_groups.DEFAULT_SG_UUID}):
        #    security_groups._create_default_security_group(context)
    return v._make_network_dict(new_net)
示例#40
0
def create_subnet(context, subnet):
    """Create a subnet.

    Create a subnet which represents a range of IP addresses
    that can be allocated to devices

    : param context: neutron api request context
    : param subnet: dictionary describing the subnet, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_subnet for tenant %s" % context.tenant_id)
    net_id = subnet["subnet"]["network_id"]

    with context.session.begin():
        net = db_api.network_find(context,
                                  None,
                                  None,
                                  None,
                                  False,
                                  id=net_id,
                                  scope=db_api.ONE)
        if not net:
            raise exceptions.NetworkNotFound(net_id=net_id)

        sub_attrs = subnet["subnet"]

        always_pop = [
            "enable_dhcp", "ip_version", "first_ip", "last_ip", "_cidr"
        ]
        admin_only = [
            "segment_id", "do_not_use", "created_at", "next_auto_assign_ip"
        ]
        utils.filter_body(context, sub_attrs, admin_only, always_pop)

        _validate_subnet_cidr(context, net_id, sub_attrs["cidr"])

        cidr = netaddr.IPNetwork(sub_attrs["cidr"])

        err_vals = {'cidr': sub_attrs["cidr"], 'network_id': net_id}
        err = _("Requested subnet with cidr: %(cidr)s for "
                "network: %(network_id)s. Prefix is too small, must be a "
                "larger subnet. A prefix less than /%(prefix)s is required.")

        if cidr.version == 6 and cidr.prefixlen > 64:
            err_vals["prefix"] = 65
            err_msg = err % err_vals
            raise exceptions.InvalidInput(error_message=err_msg)
        elif cidr.version == 4 and cidr.prefixlen > 30:
            err_vals["prefix"] = 31
            err_msg = err % err_vals
            raise exceptions.InvalidInput(error_message=err_msg)
        # Enforce subnet quotas
        net_subnets = get_subnets(context, filters=dict(network_id=net_id))
        if not context.is_admin:
            v4_count, v6_count = 0, 0
            for subnet in net_subnets:
                if netaddr.IPNetwork(subnet['cidr']).version == 6:
                    v6_count += 1
                else:
                    v4_count += 1

            if cidr.version == 6:
                tenant_quota_v6 = context.session.query(qdv.Quota).filter_by(
                    tenant_id=context.tenant_id,
                    resource='v6_subnets_per_network').first()
                if tenant_quota_v6 != -1:
                    quota.QUOTAS.limit_check(context,
                                             context.tenant_id,
                                             v6_subnets_per_network=v6_count +
                                             1)
            else:
                tenant_quota_v4 = context.session.query(qdv.Quota).filter_by(
                    tenant_id=context.tenant_id,
                    resource='v4_subnets_per_network').first()
                if tenant_quota_v4 != -1:
                    quota.QUOTAS.limit_check(context,
                                             context.tenant_id,
                                             v4_subnets_per_network=v4_count +
                                             1)

        # See RM981. The default behavior of setting a gateway unless
        # explicitly asked to not is no longer desirable.
        gateway_ip = utils.pop_param(sub_attrs, "gateway_ip")
        dns_ips = utils.pop_param(sub_attrs, "dns_nameservers", [])
        host_routes = utils.pop_param(sub_attrs, "host_routes", [])
        allocation_pools = utils.pop_param(sub_attrs, "allocation_pools", None)

        sub_attrs["network"] = net
        new_subnet = db_api.subnet_create(context, **sub_attrs)

        cidrs = []
        alloc_pools = allocation_pool.AllocationPools(sub_attrs["cidr"],
                                                      allocation_pools)
        if isinstance(allocation_pools, list):
            cidrs = alloc_pools.get_policy_cidrs()

        quota.QUOTAS.limit_check(context,
                                 context.tenant_id,
                                 alloc_pools_per_subnet=len(alloc_pools))

        ip_policies.ensure_default_policy(cidrs, [new_subnet])
        new_subnet["ip_policy"] = db_api.ip_policy_create(context,
                                                          exclude=cidrs)

        quota.QUOTAS.limit_check(context,
                                 context.tenant_id,
                                 routes_per_subnet=len(host_routes))

        default_route = None
        for route in host_routes:
            netaddr_route = netaddr.IPNetwork(route["destination"])
            if netaddr_route.value == routes.DEFAULT_ROUTE.value:
                if default_route:
                    raise q_exc.DuplicateRouteConflict(
                        subnet_id=new_subnet["id"])

                default_route = route
                gateway_ip = default_route["nexthop"]
                alloc_pools.validate_gateway_excluded(gateway_ip)

            new_subnet["routes"].append(
                db_api.route_create(context,
                                    cidr=route["destination"],
                                    gateway=route["nexthop"]))

        quota.QUOTAS.limit_check(context,
                                 context.tenant_id,
                                 dns_nameservers_per_subnet=len(dns_ips))

        for dns_ip in dns_ips:
            new_subnet["dns_nameservers"].append(
                db_api.dns_create(context, ip=netaddr.IPAddress(dns_ip)))

        # if the gateway_ip is IN the cidr for the subnet and NOT excluded by
        # policies, we should raise a 409 conflict
        if gateway_ip and default_route is None:
            alloc_pools.validate_gateway_excluded(gateway_ip)
            new_subnet["routes"].append(
                db_api.route_create(context,
                                    cidr=str(routes.DEFAULT_ROUTE),
                                    gateway=gateway_ip))

    subnet_dict = v._make_subnet_dict(new_subnet)
    subnet_dict["gateway_ip"] = gateway_ip

    n_rpc.get_notifier("network").info(
        context, "ip_block.create",
        dict(tenant_id=subnet_dict["tenant_id"],
             ip_block_id=subnet_dict["id"],
             created_at=new_subnet["created_at"]))
    return subnet_dict
示例#41
0
def create_subnet(context, subnet):
    """Create a subnet.

    Create a subnet which represents a range of IP addresses
    that can be allocated to devices

    : param context: neutron api request context
    : param subnet: dictionary describing the subnet, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_subnet for tenant %s" % context.tenant_id)
    net_id = subnet["subnet"]["network_id"]

    with context.session.begin():
        net = db_api.network_find(context, None, None, None, False,
                                  id=net_id, scope=db_api.ONE)
        if not net:
            raise exceptions.NetworkNotFound(net_id=net_id)

        sub_attrs = subnet["subnet"]

        always_pop = ["enable_dhcp", "ip_version", "first_ip", "last_ip",
                      "_cidr"]
        admin_only = ["segment_id", "do_not_use", "created_at",
                      "next_auto_assign_ip"]
        utils.filter_body(context, sub_attrs, admin_only, always_pop)

        _validate_subnet_cidr(context, net_id, sub_attrs["cidr"])

        cidr = netaddr.IPNetwork(sub_attrs["cidr"])

        err_vals = {'cidr': sub_attrs["cidr"], 'network_id': net_id}
        err = _("Requested subnet with cidr: %(cidr)s for "
                "network: %(network_id)s. Prefix is too small, must be a "
                "larger subnet. A prefix less than /%(prefix)s is required.")

        if cidr.version == 6 and cidr.prefixlen > 64:
            err_vals["prefix"] = 65
            err_msg = err % err_vals
            raise exceptions.InvalidInput(error_message=err_msg)
        elif cidr.version == 4 and cidr.prefixlen > 30:
            err_vals["prefix"] = 31
            err_msg = err % err_vals
            raise exceptions.InvalidInput(error_message=err_msg)
        # Enforce subnet quotas
        net_subnets = get_subnets(context,
                                  filters=dict(network_id=net_id))
        if not context.is_admin:
            v4_count, v6_count = 0, 0
            for subnet in net_subnets:
                if netaddr.IPNetwork(subnet['cidr']).version == 6:
                    v6_count += 1
                else:
                    v4_count += 1

            if cidr.version == 6:
                tenant_quota_v6 = context.session.query(qdv.Quota).filter_by(
                    tenant_id=context.tenant_id,
                    resource='v6_subnets_per_network').first()
                if tenant_quota_v6 != -1:
                    quota.QUOTAS.limit_check(
                        context, context.tenant_id,
                        v6_subnets_per_network=v6_count + 1)
            else:
                tenant_quota_v4 = context.session.query(qdv.Quota).filter_by(
                    tenant_id=context.tenant_id,
                    resource='v4_subnets_per_network').first()
                if tenant_quota_v4 != -1:
                    quota.QUOTAS.limit_check(
                        context, context.tenant_id,
                        v4_subnets_per_network=v4_count + 1)

        # See RM981. The default behavior of setting a gateway unless
        # explicitly asked to not is no longer desirable.
        gateway_ip = utils.pop_param(sub_attrs, "gateway_ip")
        dns_ips = utils.pop_param(sub_attrs, "dns_nameservers", [])
        host_routes = utils.pop_param(sub_attrs, "host_routes", [])
        allocation_pools = utils.pop_param(sub_attrs, "allocation_pools", None)

        sub_attrs["network"] = net
        new_subnet = db_api.subnet_create(context, **sub_attrs)

        cidrs = []
        alloc_pools = allocation_pool.AllocationPools(sub_attrs["cidr"],
                                                      allocation_pools)
        if isinstance(allocation_pools, list):
            cidrs = alloc_pools.get_policy_cidrs()

        quota.QUOTAS.limit_check(
            context,
            context.tenant_id,
            alloc_pools_per_subnet=len(alloc_pools))

        ip_policies.ensure_default_policy(cidrs, [new_subnet])
        new_subnet["ip_policy"] = db_api.ip_policy_create(context,
                                                          exclude=cidrs)

        quota.QUOTAS.limit_check(context, context.tenant_id,
                                 routes_per_subnet=len(host_routes))

        default_route = None
        for route in host_routes:
            netaddr_route = netaddr.IPNetwork(route["destination"])
            if netaddr_route.value == routes.DEFAULT_ROUTE.value:
                if default_route:
                    raise q_exc.DuplicateRouteConflict(
                        subnet_id=new_subnet["id"])

                default_route = route
                gateway_ip = default_route["nexthop"]
                alloc_pools.validate_gateway_excluded(gateway_ip)

            new_subnet["routes"].append(db_api.route_create(
                context, cidr=route["destination"], gateway=route["nexthop"]))

        quota.QUOTAS.limit_check(context, context.tenant_id,
                                 dns_nameservers_per_subnet=len(dns_ips))

        for dns_ip in dns_ips:
            new_subnet["dns_nameservers"].append(db_api.dns_create(
                context, ip=netaddr.IPAddress(dns_ip)))

        # if the gateway_ip is IN the cidr for the subnet and NOT excluded by
        # policies, we should raise a 409 conflict
        if gateway_ip and default_route is None:
            alloc_pools.validate_gateway_excluded(gateway_ip)
            new_subnet["routes"].append(db_api.route_create(
                context, cidr=str(routes.DEFAULT_ROUTE), gateway=gateway_ip))

    subnet_dict = v._make_subnet_dict(new_subnet)
    subnet_dict["gateway_ip"] = gateway_ip

    n_rpc.get_notifier("network").info(
        context,
        "ip_block.create",
        dict(tenant_id=subnet_dict["tenant_id"],
             ip_block_id=subnet_dict["id"],
             created_at=new_subnet["created_at"]))
    return subnet_dict
示例#42
0
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)
    port_attrs = port["port"]

    admin_only = ["mac_address", "device_owner", "bridge", "admin_state_up"]
    utils.filter_body(context, port_attrs, admin_only=admin_only)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")
    net_id = port_attrs["network_id"]
    device_id = port_attrs["device_id"]

    port_id = uuidutils.generate_uuid()

    net = db_api.network_find(context, id=net_id, scope=db_api.ONE)

    if not net:
        raise exceptions.NetworkNotFound(net_id=net_id)

    # NOTE (Perkins): If a device_id is given, try to prevent multiple ports
    # from being created for a device already attached to the network
    if device_id:
        existing_ports = db_api.port_find(context,
                                          network_id=net_id,
                                          device_id=device_id,
                                          scope=db_api.ONE)
        if existing_ports:
            raise exceptions.BadRequest(
                resource="port",
                msg="This device is already connected to the "
                "requested network via another port")

    if not STRATEGY.is_parent_network(net_id):
        # We don't honor segmented networks when they aren't "shared"
        segment_id = None
        port_count = db_api.port_count_all(context,
                                           network_id=[net_id],
                                           tenant_id=[context.tenant_id])

        quota.QUOTAS.limit_check(context,
                                 context.tenant_id,
                                 ports_per_network=port_count + 1)
    else:
        if not segment_id:
            raise q_exc.AmbiguousNetworkId(net_id=net_id)

    ipam_driver = ipam.IPAM_REGISTRY.get_strategy(net["ipam_strategy"])
    net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])
    group_ids, security_groups = v.make_security_group_list(
        context, port["port"].pop("security_groups", None))

    addresses = []
    mac = None
    backend_port = None

    with utils.CommandManager().execute() as cmd_mgr:

        @cmd_mgr.do
        def _allocate_ips(fixed_ips, net, port_id, segment_id, mac):
            if fixed_ips:
                for fixed_ip in fixed_ips:
                    subnet_id = fixed_ip.get("subnet_id")
                    ip_address = fixed_ip.get("ip_address")
                    if not (subnet_id and ip_address):
                        raise exceptions.BadRequest(
                            resource="fixed_ips",
                            msg="subnet_id and ip_address required")
                    ipam_driver.allocate_ip_address(
                        context,
                        addresses,
                        net["id"],
                        port_id,
                        CONF.QUARK.ipam_reuse_after,
                        segment_id=segment_id,
                        ip_address=ip_address,
                        subnets=[subnet_id],
                        mac_address=mac)
            else:
                ipam_driver.allocate_ip_address(context,
                                                addresses,
                                                net["id"],
                                                port_id,
                                                CONF.QUARK.ipam_reuse_after,
                                                segment_id=segment_id,
                                                mac_address=mac)

        @cmd_mgr.undo
        def _allocate_ips_undo(addr):
            LOG.info("Rolling back IP addresses...")
            if addresses:
                for address in addresses:
                    try:
                        with context.session.begin():
                            ipam_driver.deallocate_ip_address(context, address)
                    except Exception:
                        LOG.exception("Couldn't release IP %s" % address)

        @cmd_mgr.do
        def _allocate_mac(net, port_id, mac_address):
            mac = ipam_driver.allocate_mac_address(context,
                                                   net["id"],
                                                   port_id,
                                                   CONF.QUARK.ipam_reuse_after,
                                                   mac_address=mac_address)
            return mac

        @cmd_mgr.undo
        def _allocate_mac_undo(mac):
            LOG.info("Rolling back MAC address...")
            if mac:
                try:
                    with context.session.begin():
                        ipam_driver.deallocate_mac_address(
                            context, mac["address"])
                except Exception:
                    LOG.exception("Couldn't release MAC %s" % mac)

        @cmd_mgr.do
        def _allocate_backend_port(mac, addresses, net, port_id):
            backend_port = net_driver.create_port(context,
                                                  net["id"],
                                                  port_id=port_id,
                                                  security_groups=group_ids,
                                                  device_id=device_id)
            return backend_port

        @cmd_mgr.undo
        def _allocate_back_port_undo(backend_port):
            LOG.info("Rolling back backend port...")
            try:
                net_driver.delete_port(context, backend_port["uuid"])
            except Exception:
                LOG.exception("Couldn't rollback backend port %s" %
                              backend_port)

        @cmd_mgr.do
        def _allocate_db_port(port_attrs, backend_port, addresses, mac):
            port_attrs["network_id"] = net["id"]
            port_attrs["id"] = port_id
            port_attrs["security_groups"] = security_groups

            LOG.info("Including extra plugin attrs: %s" % backend_port)
            port_attrs.update(backend_port)
            with context.session.begin():
                new_port = db_api.port_create(context,
                                              addresses=addresses,
                                              mac_address=mac["address"],
                                              backend_key=backend_port["uuid"],
                                              **port_attrs)

            return new_port

        @cmd_mgr.undo
        def _allocate_db_port_undo(new_port):
            LOG.info("Rolling back database port...")
            if not new_port:
                return
            try:
                with context.session.begin():
                    db_api.port_delete(context, new_port)
            except Exception:
                LOG.exception("Couldn't rollback db port %s" % backend_port)

        # addresses, mac, backend_port, new_port
        mac = _allocate_mac(net, port_id, mac_address)
        _allocate_ips(fixed_ips, net, port_id, segment_id, mac)
        backend_port = _allocate_backend_port(mac, addresses, net, port_id)
        new_port = _allocate_db_port(port_attrs, backend_port, addresses, mac)

    return v._make_port_dict(new_port)
示例#43
0
文件: ports.py 项目: kilogram/quark
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")
    net_id = port_attrs["network_id"]
    addresses = []

    port_id = uuidutils.generate_uuid()

    net = db_api.network_find(context, id=net_id, shared=True,
                              segment_id=segment_id, scope=db_api.ONE)
    if not net:
        # Maybe it's a tenant network
        net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
        if not net:
            raise exceptions.NetworkNotFound(net_id=net_id)

    quota.QUOTAS.limit_check(
        context, context.tenant_id,
        ports_per_network=len(net.get('ports', [])) + 1)

    if fixed_ips:
        for fixed_ip in fixed_ips:
            subnet_id = fixed_ip.get("subnet_id")
            ip_address = fixed_ip.get("ip_address")
            if not (subnet_id and ip_address):
                raise exceptions.BadRequest(
                    resource="fixed_ips",
                    msg="subnet_id and ip_address required")
            addresses.append(ipam_driver.allocate_ip_address(
                context, net["id"], port_id, CONF.QUARK.ipam_reuse_after,
                ip_address=ip_address))
    else:
        addresses.append(ipam_driver.allocate_ip_address(
            context, net["id"], port_id, CONF.QUARK.ipam_reuse_after))

    group_ids, security_groups = v.make_security_group_list(
        context, port["port"].pop("security_groups", None))
    mac = ipam_driver.allocate_mac_address(context, net["id"], port_id,
                                           CONF.QUARK.ipam_reuse_after,
                                           mac_address=mac_address)
    mac_address_string = str(netaddr.EUI(mac['address'],
                                         dialect=netaddr.mac_unix))
    address_pairs = [{'mac_address': mac_address_string,
                      'ip_address': address.get('address_readable', '')}
                     for address in addresses]
    backend_port = net_driver.create_port(context, net["id"], port_id=port_id,
                                          security_groups=group_ids,
                                          allowed_pairs=address_pairs)

    port_attrs["network_id"] = net["id"]
    port_attrs["id"] = port_id
    port_attrs["security_groups"] = security_groups
    new_port = db_api.port_create(
        context, addresses=addresses, mac_address=mac["address"],
        backend_key=backend_port["uuid"], **port_attrs)
    return v._make_port_dict(new_port)
示例#44
0
def _get_ipam_driver_for_network(context, net_id):
    return ipam.IPAM_REGISTRY.get_strategy(db_api.network_find(
        context, id=net_id, scope=db_api.ONE)['ipam_strategy'])
示例#45
0
def create_floatingip(context, content):
    """Allocate or reallocate a floating IP.

    :param context: neutron api request context.
    :param content: dictionary describing the floating ip, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.

    :returns: Dictionary containing details for the new floating IP.  If values
        are declared in the fields parameter, then only those keys will be
        present.
    """
    LOG.info('create_floatingip %s for tenant %s and body %s' %
             (id, context.tenant_id, content))
    tenant_id = content.get('tenant_id')
    network_id = content.get('floating_network_id')
    fixed_ip_address = content.get('fixed_ip_address')
    ip_address = content.get('floating_ip_address')
    port_id = content.get('port_id')

    if not tenant_id:
        tenant_id = context.tenant_id

    if not network_id:
        raise exceptions.BadRequest(resource='floating_ip',
                                    msg='floating_network_id is required.')

    network = db_api.network_find(context, id=network_id, scope=db_api.ONE)

    if not network:
        raise exceptions.NetworkNotFound(net_id=network_id)

    fixed_ip = None
    port = None
    if port_id:
        port = db_api.port_find(context, id=port_id, scope=db_api.ONE)

        if not port:
            raise exceptions.PortNotFound(port_id=port_id)

        if not port.ip_addresses or len(port.ip_addresses) == 0:
            raise qex.NoAvailableFixedIPsForPort(port_id=port_id)

        if not fixed_ip_address:
            fixed_ip = _get_next_available_fixed_ip(port)
            if not fixed_ip:
                raise qex.NoAvailableFixedIPsForPort(
                    port_id=port_id)
        else:
            fixed_ip = next((ip for ip in port.ip_addresses
                            if (ip['address_readable'] == fixed_ip_address and
                                ip.get('address_type') == ip_types.FIXED)),
                            None)

            if not fixed_ip:
                raise qex.FixedIpDoesNotExistsForPort(
                    fixed_ip=fixed_ip_address, port_id=port_id)

            if any(ip for ip in port.ip_addresses
                   if (ip.get('address_type') == ip_types.FLOATING and
                       ip.fixed_ip['address_readable'] == fixed_ip_address)):
                raise qex.PortAlreadyContainsFloatingIp(
                    port_id=port_id)

    new_addresses = []
    ip_addresses = []
    if ip_address:
        ip_addresses.append(ip_address)

    seg_name = CONF.QUARK.floating_ip_segment_name
    strategy_name = CONF.QUARK.floating_ip_ipam_strategy

    if strategy_name.upper() == 'NETWORK':
        strategy_name = network.get("ipam_strategy")

    ipam_driver = ipam.IPAM_REGISTRY.get_strategy(strategy_name)
    ipam_driver.allocate_ip_address(context, new_addresses, network_id,
                                    port_id, CONF.QUARK.ipam_reuse_after,
                                    seg_name, version=4,
                                    ip_addresses=ip_addresses,
                                    address_type=ip_types.FLOATING)

    flip = new_addresses[0]

    if fixed_ip and port:
        with context.session.begin():
            flip = db_api.port_associate_ip(context, [port], flip, [port_id])
            flip = db_api.floating_ip_associate_fixed_ip(context, flip,
                                                         fixed_ip)

            flip_driver = registry.DRIVER_REGISTRY.get_driver()

            flip_driver.register_floating_ip(flip, port, fixed_ip)

    return v._make_floating_ip_dict(flip, port_id)
示例#46
0
文件: ports.py 项目: insequent/quark
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)
    port_attrs = port["port"]

    admin_only = ["mac_address", "device_owner", "bridge", "admin_state_up",
                  "use_forbidden_mac_range"]
    utils.filter_body(context, port_attrs, admin_only=admin_only)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    use_forbidden_mac_range = utils.pop_param(port_attrs,
                                              "use_forbidden_mac_range", False)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")
    if "device_id" not in port_attrs:
        port_attrs['device_id'] = ""
    device_id = port_attrs['device_id']
    net_id = port_attrs["network_id"]

    port_id = uuidutils.generate_uuid()

    net = db_api.network_find(context, None, None, None, False, id=net_id,
                              scope=db_api.ONE)

    if not net:
        raise exceptions.NetworkNotFound(net_id=net_id)
    _raise_if_unauthorized(context.tenant_id, net)

    # NOTE (Perkins): If a device_id is given, try to prevent multiple ports
    # from being created for a device already attached to the network
    if device_id:
        existing_ports = db_api.port_find(context,
                                          network_id=net_id,
                                          device_id=device_id,
                                          scope=db_api.ONE)
        if existing_ports:
            raise exceptions.BadRequest(
                resource="port", msg="This device is already connected to the "
                "requested network via another port")

    # Try to fail early on quotas and save ourselves some db overhead
    if fixed_ips:
        quota.QUOTAS.limit_check(context, context.tenant_id,
                                 fixed_ips_per_port=len(fixed_ips))

    if not STRATEGY.is_parent_network(net_id):
        # We don't honor segmented networks when they aren't "shared"
        segment_id = None
        port_count = db_api.port_count_all(context, network_id=[net_id],
                                           tenant_id=[context.tenant_id])
        quota.QUOTAS.limit_check(
            context, context.tenant_id,
            ports_per_network=port_count + 1)
    else:
        if not segment_id:
            raise q_exc.AmbiguousNetworkId(net_id=net_id)

    ipam_driver = ipam.IPAM_REGISTRY.get_strategy(net["ipam_strategy"])

    net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])

    # TODO(anyone): security groups are not currently supported on port create,
    #               nor on isolated networks today. Please see RM8615
    security_groups = utils.pop_param(port_attrs, "security_groups")
    if security_groups is not None:
        raise q_exc.SecurityGroupsNotImplemented()

    group_ids, security_groups = _make_security_group_list(context,
                                                           security_groups)
    quota.QUOTAS.limit_check(context, context.tenant_id,
                             security_groups_per_port=len(group_ids))
    addresses = []
    backend_port = None

    with utils.CommandManager().execute() as cmd_mgr:
        @cmd_mgr.do
        def _allocate_ips(fixed_ips, net, port_id, segment_id, mac):
            fixed_ip_kwargs = {}
            if fixed_ips:
                if STRATEGY.is_parent_network(net_id) and not context.is_admin:
                    raise exceptions.NotAuthorized()

                ips, subnets = split_and_validate_requested_subnets(context,
                                                                    net_id,
                                                                    segment_id,
                                                                    fixed_ips)
                fixed_ip_kwargs["ip_addresses"] = ips
                fixed_ip_kwargs["subnets"] = subnets

            ipam_driver.allocate_ip_address(
                context, addresses, net["id"], port_id,
                CONF.QUARK.ipam_reuse_after, segment_id=segment_id,
                mac_address=mac, **fixed_ip_kwargs)

        @cmd_mgr.undo
        def _allocate_ips_undo(addr):
            LOG.info("Rolling back IP addresses...")
            if addresses:
                for address in addresses:
                    try:
                        with context.session.begin():
                            ipam_driver.deallocate_ip_address(context, address)
                    except Exception:
                        LOG.exception("Couldn't release IP %s" % address)

        @cmd_mgr.do
        def _allocate_mac(net, port_id, mac_address,
                          use_forbidden_mac_range=False):
            mac = ipam_driver.allocate_mac_address(
                context, net["id"], port_id, CONF.QUARK.ipam_reuse_after,
                mac_address=mac_address,
                use_forbidden_mac_range=use_forbidden_mac_range)
            return mac

        @cmd_mgr.undo
        def _allocate_mac_undo(mac):
            LOG.info("Rolling back MAC address...")
            if mac:
                try:
                    with context.session.begin():
                        ipam_driver.deallocate_mac_address(context,
                                                           mac["address"])
                except Exception:
                    LOG.exception("Couldn't release MAC %s" % mac)

        @cmd_mgr.do
        def _allocate_backend_port(mac, addresses, net, port_id):
            backend_port = net_driver.create_port(context, net["id"],
                                                  port_id=port_id,
                                                  security_groups=group_ids,
                                                  device_id=device_id)
            return backend_port

        @cmd_mgr.undo
        def _allocate_back_port_undo(backend_port):
            LOG.info("Rolling back backend port...")
            try:
                net_driver.delete_port(context, backend_port["uuid"])
            except Exception:
                LOG.exception(
                    "Couldn't rollback backend port %s" % backend_port)

        @cmd_mgr.do
        def _allocate_db_port(port_attrs, backend_port, addresses, mac):
            port_attrs["network_id"] = net["id"]
            port_attrs["id"] = port_id
            port_attrs["security_groups"] = security_groups

            LOG.info("Including extra plugin attrs: %s" % backend_port)
            port_attrs.update(backend_port)
            with context.session.begin():
                new_port = db_api.port_create(
                    context, addresses=addresses, mac_address=mac["address"],
                    backend_key=backend_port["uuid"], **port_attrs)

            return new_port

        @cmd_mgr.undo
        def _allocate_db_port_undo(new_port):
            LOG.info("Rolling back database port...")
            if not new_port:
                return
            try:
                with context.session.begin():
                    db_api.port_delete(context, new_port)
            except Exception:
                LOG.exception(
                    "Couldn't rollback db port %s" % backend_port)

        # addresses, mac, backend_port, new_port
        mac = _allocate_mac(net, port_id, mac_address,
                            use_forbidden_mac_range=use_forbidden_mac_range)
        _allocate_ips(fixed_ips, net, port_id, segment_id, mac)
        backend_port = _allocate_backend_port(mac, addresses, net, port_id)
        new_port = _allocate_db_port(port_attrs, backend_port, addresses, mac)

    return v._make_port_dict(new_port)
示例#47
0
def create_floatingip(context, content):
    LOG.info("create_floatingip %s for tenant %s and body %s" %
             (id, context.tenant_id, content))
    tenant_id = content.get("tenant_id")
    network_id = content.get("floating_network_id")
    fixed_ip_address = content.get("fixed_ip_address")
    ip_address = content.get("floating_ip_address")
    port_id = content.get("port_id")

    if not tenant_id:
        tenant_id = context.tenant_id

    if not network_id:
        raise exceptions.BadRequest(resource="floating_ip",
                                    msg="floating_network_id is required.")

    network = db_api.network_find(context, id=network_id, scope=db_api.ONE)

    if not network:
        raise exceptions.NetworkNotFound(net_id=network_id)

    fixed_ip = None
    port = None
    if port_id:
        port = db_api.port_find(context, id=port_id, scope=db_api.ONE)

        if not port:
            raise exceptions.PortNotFound(port_id=port_id)

        if not port.ip_addresses or len(port.ip_addresses) == 0:
            raise quark_exceptions.NoAvailableFixedIPsForPort(port_id=port_id)

        if not fixed_ip_address:
            fixed_ip = _get_next_available_fixed_ip(port)
            if not fixed_ip:
                raise quark_exceptions.NoAvailableFixedIPsForPort(
                    port_id=port_id)
        else:
            fixed_ip = next(
                (ip for ip in port.ip_addresses
                 if (ip["address_readable"] == fixed_ip_address
                     and ip.get("address_type") == ip_types.FIXED)), None)

            if not fixed_ip:
                raise quark_exceptions.FixedIpDoesNotExistsForPort(
                    fixed_ip=fixed_ip_address, port_id=port_id)

            if any(ip for ip in port.ip_addresses
                   if (ip.get("address_type") == ip_types.FLOATING and
                       ip.fixed_ip["address_readable"] == fixed_ip_address)):
                raise quark_exceptions.PortAlreadyContainsFloatingIp(
                    port_id=port_id)

    new_addresses = []
    ip_addresses = []
    if ip_address:
        ip_addresses.append(ip_address)

    seg_name = CONF.QUARK.floating_ip_segment_name
    strategy_name = network.get("ipam_strategy")
    ipam_driver = ipam.IPAM_REGISTRY.get_strategy(strategy_name)
    ipam_driver.allocate_ip_address(context,
                                    new_addresses,
                                    network_id,
                                    port_id,
                                    CONF.QUARK.ipam_reuse_after,
                                    seg_name,
                                    version=4,
                                    ip_addresses=ip_addresses,
                                    address_type=ip_types.FLOATING)

    floating_ip = new_addresses[0]

    if fixed_ip and port:
        with context.session.begin():
            floating_ip = db_api.floating_ip_associate_fixed_ip(
                context, floating_ip, fixed_ip)

        flip_driver_type = CONF.QUARK.default_floating_ip_driver
        flip_driver = registry.DRIVER_REGISTRY.get_driver(flip_driver_type)

        flip_driver.register_floating_ip(floating_ip, port, fixed_ip)

    return v._make_floating_ip_dict(floating_ip)
示例#48
0
def create_floatingip(context, content):
    """Allocate or reallocate a floating IP.

    :param context: neutron api request context.
    :param content: dictionary describing the floating ip, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.

    :returns: Dictionary containing details for the new floating IP.  If values
        are declared in the fields parameter, then only those keys will be
        present.
    """
    LOG.info('create_floatingip %s for tenant %s and body %s' %
             (id, context.tenant_id, content))
    tenant_id = content.get('tenant_id')
    network_id = content.get('floating_network_id')
    fixed_ip_address = content.get('fixed_ip_address')
    ip_address = content.get('floating_ip_address')
    port_id = content.get('port_id')

    if not tenant_id:
        tenant_id = context.tenant_id

    if not network_id:
        raise exceptions.BadRequest(resource='floating_ip',
                                    msg='floating_network_id is required.')

    network = db_api.network_find(context, id=network_id, scope=db_api.ONE)

    if not network:
        raise exceptions.NetworkNotFound(net_id=network_id)

    fixed_ip = None
    port = None
    if port_id:
        port = db_api.port_find(context, id=port_id, scope=db_api.ONE)

        if not port:
            raise exceptions.PortNotFound(port_id=port_id)

        if not port.ip_addresses or len(port.ip_addresses) == 0:
            raise qex.NoAvailableFixedIpsForPort(port_id=port_id)

        if not fixed_ip_address:
            fixed_ip = _get_next_available_fixed_ip(port)
            if not fixed_ip:
                raise qex.NoAvailableFixedIpsForPort(
                    port_id=port_id)
        else:
            fixed_ip = next((ip for ip in port.ip_addresses
                            if (ip['address_readable'] == fixed_ip_address and
                                ip.get('address_type') == ip_types.FIXED)),
                            None)

            if not fixed_ip:
                raise qex.FixedIpDoesNotExistsForPort(
                    fixed_ip=fixed_ip_address, port_id=port_id)

            if any(ip for ip in port.ip_addresses
                   if (ip.get('address_type') == ip_types.FLOATING and
                       ip.fixed_ip['address_readable'] == fixed_ip_address)):
                raise qex.PortAlreadyContainsFloatingIp(
                    port_id=port_id)

    new_addresses = []
    ip_addresses = []
    if ip_address:
        ip_addresses.append(ip_address)

    seg_name = CONF.QUARK.floating_ip_segment_name
    strategy_name = CONF.QUARK.floating_ip_ipam_strategy

    if strategy_name.upper() == 'NETWORK':
        strategy_name = network.get("ipam_strategy")

    ipam_driver = ipam.IPAM_REGISTRY.get_strategy(strategy_name)
    ipam_driver.allocate_ip_address(context, new_addresses, network_id,
                                    port_id, CONF.QUARK.ipam_reuse_after,
                                    seg_name, version=4,
                                    ip_addresses=ip_addresses,
                                    address_type=ip_types.FLOATING)

    flip = new_addresses[0]

    if fixed_ip and port:
        context.session.begin()
        try:
            flip = db_api.port_associate_ip(context, [port], flip, [port_id])
            flip = db_api.floating_ip_associate_fixed_ip(context, flip,
                                                         fixed_ip)

            flip_driver = registry.DRIVER_REGISTRY.get_driver()

            flip_driver.register_floating_ip(flip, port, fixed_ip)
            context.session.commit()
        except Exception:
            context.session.rollback()
            raise

    return v._make_floating_ip_dict(flip, port_id)
示例#49
0
文件: subnets.py 项目: kilogram/quark
def create_subnet(context, subnet):
    """Create a subnet.

    Create a subnet which represents a range of IP addresses
    that can be allocated to devices

    : param context: neutron api request context
    : param subnet: dictionary describing the subnet, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_subnet for tenant %s" % context.tenant_id)
    net_id = subnet["subnet"]["network_id"]

    net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
    if not net:
        raise exceptions.NetworkNotFound(net_id=net_id)

    sub_attrs = subnet["subnet"]

    _validate_subnet_cidr(context, net_id, sub_attrs["cidr"])

    cidr = netaddr.IPNetwork(sub_attrs["cidr"])
    gateway_ip = utils.pop_param(sub_attrs, "gateway_ip", str(cidr[1]))
    dns_ips = utils.pop_param(sub_attrs, "dns_nameservers", [])
    host_routes = utils.pop_param(sub_attrs, "host_routes", [])
    allocation_pools = utils.pop_param(sub_attrs, "allocation_pools", [])
    sub_attrs["network"] = net

    new_subnet = db_api.subnet_create(context, **sub_attrs)

    default_route = None
    for route in host_routes:
        netaddr_route = netaddr.IPNetwork(route["destination"])
        if netaddr_route.value == routes.DEFAULT_ROUTE.value:
            default_route = route
            gateway_ip = default_route["nexthop"]
        new_subnet["routes"].append(
            db_api.route_create(context,
                                cidr=route["destination"],
                                gateway=route["nexthop"]))

    if default_route is None:
        new_subnet["routes"].append(
            db_api.route_create(context,
                                cidr=str(routes.DEFAULT_ROUTE),
                                gateway=gateway_ip))

    for dns_ip in dns_ips:
        new_subnet["dns_nameservers"].append(
            db_api.dns_create(context, ip=netaddr.IPAddress(dns_ip)))

    if allocation_pools:
        exclude = netaddr.IPSet([cidr])
        for p in allocation_pools:
            x = netaddr.IPSet(netaddr.IPRange(p["start"], p["end"]))
            exclude = exclude - x
        new_subnet["ip_policy"] = db_api.ip_policy_create(context,
                                                          exclude=exclude)
    subnet_dict = v._make_subnet_dict(new_subnet,
                                      default_route=routes.DEFAULT_ROUTE)
    subnet_dict["gateway_ip"] = gateway_ip
    return subnet_dict
示例#50
0
def create_subnet(context, subnet):
    """Create a subnet.

    Create a subnet which represents a range of IP addresses
    that can be allocated to devices

    : param context: neutron api request context
    : param subnet: dictionary describing the subnet, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_subnet for tenant %s" % context.tenant_id)
    net_id = subnet["subnet"]["network_id"]

    with context.session.begin():
        net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
        if not net:
            raise exceptions.NetworkNotFound(net_id=net_id)

        sub_attrs = subnet["subnet"]

        _validate_subnet_cidr(context, net_id, sub_attrs["cidr"])

        cidr = netaddr.IPNetwork(sub_attrs["cidr"])

        err_vals = {'cidr': sub_attrs["cidr"], 'network_id': net_id}
        err = _("Requested subnet with cidr: %(cidr)s for "
                "network: %(network_id)s. Prefix is too small, must be a "
                "larger subnet. A prefix less than /%(prefix)s is required.")

        if cidr.version == 6 and cidr.prefixlen > 64:
            err_vals["prefix"] = 65
            err_msg = err % err_vals
            raise exceptions.InvalidInput(error_message=err_msg)
        elif cidr.version == 4 and cidr.prefixlen > 30:
            err_vals["prefix"] = 31
            err_msg = err % err_vals
            raise exceptions.InvalidInput(error_message=err_msg)

        gateway_ip = utils.pop_param(sub_attrs, "gateway_ip", str(cidr[1]))
        dns_ips = utils.pop_param(sub_attrs, "dns_nameservers", [])
        host_routes = utils.pop_param(sub_attrs, "host_routes", [])
        allocation_pools = utils.pop_param(sub_attrs, "allocation_pools", None)

        if not context.is_admin and "segment_id" in sub_attrs:
            sub_attrs.pop("segment_id")

        sub_attrs["network"] = net

        new_subnet = db_api.subnet_create(context, **sub_attrs)

        default_route = None
        for route in host_routes:
            netaddr_route = netaddr.IPNetwork(route["destination"])
            if netaddr_route.value == routes.DEFAULT_ROUTE.value:
                if default_route:
                    raise q_exc.DuplicateRouteConflict(
                        subnet_id=new_subnet["id"])

                default_route = route
                gateway_ip = default_route["nexthop"]
            new_subnet["routes"].append(db_api.route_create(
                context, cidr=route["destination"], gateway=route["nexthop"]))

        if gateway_ip and default_route is None:
            new_subnet["routes"].append(db_api.route_create(
                context, cidr=str(routes.DEFAULT_ROUTE), gateway=gateway_ip))

        for dns_ip in dns_ips:
            new_subnet["dns_nameservers"].append(db_api.dns_create(
                context, ip=netaddr.IPAddress(dns_ip)))

        if isinstance(allocation_pools, list) and allocation_pools:
            subnet_net = netaddr.IPNetwork(new_subnet["cidr"])
            cidrset = netaddr.IPSet(
                netaddr.IPRange(
                    netaddr.IPAddress(subnet_net.first),
                    netaddr.IPAddress(subnet_net.last)).cidrs())
            for p in allocation_pools:
                start = netaddr.IPAddress(p["start"])
                end = netaddr.IPAddress(p["end"])
                cidrset -= netaddr.IPSet(netaddr.IPRange(
                    netaddr.IPAddress(start),
                    netaddr.IPAddress(end)).cidrs())
            default_cidrset = models.IPPolicy.get_ip_policy_cidrs(new_subnet)
            cidrset.update(default_cidrset)
            cidrs = [str(x.cidr) for x in cidrset.iter_cidrs()]
            new_subnet["ip_policy"] = db_api.ip_policy_create(context,
                                                              exclude=cidrs)

    subnet_dict = v._make_subnet_dict(new_subnet)
    subnet_dict["gateway_ip"] = gateway_ip

    notifier_api.notify(context,
                        notifier_api.publisher_id("network"),
                        "ip_block.create",
                        notifier_api.CONF.default_notification_level,
                        dict(tenant_id=subnet_dict["tenant_id"],
                             ip_block_id=subnet_dict["id"],
                             created_at=new_subnet["created_at"]))

    return subnet_dict
示例#51
0
文件: plugin.py 项目: ugoring/quark
    def create_port(self, context, port):
        """Create a port

        Create a port which is a connection point of a device (e.g., a VM
        NIC) to attach to a L2 Quantum network.
        : param context: quantum api request context
        : param port: dictionary describing the port, with keys
            as listed in the RESOURCE_ATTRIBUTE_MAP object in
            quantum/api/v2/attributes.py.  All keys will be populated.
        """
        LOG.info("create_port for tenant %s" % context.tenant_id)

        mac_address = port["port"].pop("mac_address", None)
        if mac_address and mac_address is attributes.ATTR_NOT_SPECIFIED:
            mac_address = None
        segment_id = port["port"].pop("segment_id", None)

        addresses = []
        port_id = uuidutils.generate_uuid()
        net_id = port["port"]["network_id"]

        net = db_api.network_find(context, id=net_id, shared=True,
                                  segment_id=segment_id, scope=db_api.ONE)
        if not net:
            # Maybe it's a tenant network
            net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
            if not net:
                raise exceptions.NetworkNotFound(net_id=net_id)

        fixed_ips = port["port"].pop("fixed_ips", None)
        if fixed_ips and fixed_ips is not attributes.ATTR_NOT_SPECIFIED:
            for fixed_ip in fixed_ips:
                subnet_id = fixed_ip.get("subnet_id")
                ip_address = fixed_ip.get("ip_address")
                if not (subnet_id and ip_address):
                    raise exceptions.BadRequest(
                        resource="fixed_ips",
                        msg="subnet_id and ip_address required")
                # Note: we don't allow overlapping subnets, thus subnet_id is
                #       ignored.
                addresses.append(self.ipam_driver.allocate_ip_address(
                    context, net["id"], port_id, self.ipam_reuse_after,
                    ip_address=ip_address))
        else:
            addresses.append(self.ipam_driver.allocate_ip_address(
                context, net["id"], port_id, self.ipam_reuse_after))

        mac = self.ipam_driver.allocate_mac_address(context,
                                                    net["id"],
                                                    port_id,
                                                    self.ipam_reuse_after,
                                                    mac_address=mac_address)
        backend_port = self.net_driver.create_port(context, net["id"],
                                                   port_id=port_id)

        port["port"]["network_id"] = net["id"]
        port["port"]["id"] = port_id
        new_port = db_api.port_create(
            context, addresses=addresses, mac_address=mac["address"],
            backend_key=backend_port["uuid"], **port["port"])
        return self._make_port_dict(new_port)