Ejemplo n.º 1
0
def split_and_validate_requested_subnets(context, net_id, segment_id,
                                         fixed_ips):
    subnets = []
    ip_addresses = {}
    for fixed_ip in fixed_ips:
        subnet_id = fixed_ip.get("subnet_id")
        ip_address = fixed_ip.get("ip_address")
        if not subnet_id:
            raise exceptions.BadRequest(resource="fixed_ips",
                                        msg="subnet_id required")
        if ip_address:
            ip_addresses[ip_address] = subnet_id
        else:
            subnets.append(subnet_id)

    subnets = ip_addresses.values() + subnets

    sub_models = db_api.subnet_find(context, id=subnets, scope=db_api.ALL)
    if len(sub_models) == 0:
        raise exceptions.NotFound(msg="Requested subnet(s) not found")

    for s in sub_models:
        if s["network_id"] != net_id:
            raise exceptions.InvalidInput(
                error_message="Requested subnet doesn't belong to requested "
                              "network")

        if segment_id and segment_id != s["segment_id"]:
            raise q_exc.AmbiguousNetworkId(net_id=net_id)

    return ip_addresses, subnets
Ejemplo n.º 2
0
    def test_subnets_get_marked_as_full_retroactively(self):
        models = []
        models.append(
            self._create_models("0.0.0.0/31", 4,
                                netaddr.IPNetwork("0.0.0.0/31").ipv6().last))
        models.append(
            self._create_models("1.1.1.0/31", 4,
                                netaddr.IPNetwork("1.1.1.0/31").ipv6().last))
        models.append(
            self._create_models("2.2.2.0/30", 4,
                                netaddr.IPNetwork("2.2.2.0/30").ipv6().first))

        with self._fixtures(models) as net:
            ipaddress = []
            self.ipam.allocate_ip_address(self.context, ipaddress, net['id'],
                                          0, 0)
            self.assertEqual(ipaddress[0].version, 4)
            self.assertEqual(ipaddress[0].address_readable, "2.2.2.1")

            with self.context.session.begin():
                subnets = db_api.subnet_find(self.context, None, None, None,
                                             False).all()
                self.assertEqual(len(subnets), 3)

                full_subnets = [
                    s for s in subnets if s.next_auto_assign_ip == -1
                ]
                self.assertEqual(len(full_subnets), 2)
                available_subnets = list(set(full_subnets) ^ set(subnets))
                self.assertEqual(len(available_subnets), 1)
                self.assertEqual(available_subnets[0].cidr, "2.2.2.0/30")
                self.assertEqual(available_subnets[0].next_auto_assign_ip,
                                 netaddr.IPAddress("2.2.2.2").ipv6().value)
Ejemplo n.º 3
0
def get_subnets(context, limit=None, page_reverse=False, sorts=None,
                marker=None, filters=None, fields=None):
    """Retrieve a list of subnets.

    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 subnet 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
        subnet dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_subnets for tenant %s with filters %s fields %s" %
             (context.tenant_id, filters, fields))
    filters = filters or {}
    subnets = db_api.subnet_find(context, limit=limit,
                                 page_reverse=page_reverse, sorts=sorts,
                                 marker_obj=marker,
                                 join_dns=True, join_routes=True, **filters)
    for subnet in subnets:
        cache = subnet.get("_allocation_pool_cache")
        if not cache:
            db_api.subnet_update_set_alloc_pool_cache(
                context, subnet, subnet.allocation_pools)
    return v._make_subnets_list(subnets, fields=fields)
Ejemplo n.º 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"])
Ejemplo n.º 5
0
def get_subnet(context, id, fields=None):
    """Retrieve a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to fetch.
    : param fields: a list of strings that are valid keys in a
        subnet dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_subnet %s for tenant %s with fields %s" %
             (id, context.tenant_id, fields))
    subnet = db_api.subnet_find(context, None, None, None, False, id=id,
                                join_dns=True, join_routes=True,
                                scope=db_api.ONE)
    if not subnet:
        raise exceptions.SubnetNotFound(subnet_id=id)

    # Check the network_id against the strategies
    net_id = subnet["network_id"]
    net_id = STRATEGY.get_parent_network(net_id)
    subnet["network_id"] = net_id

    cache = subnet.get("_allocation_pool_cache")
    if not cache:
        new_cache = subnet.allocation_pools
        db_api.subnet_update_set_alloc_pool_cache(context, subnet, new_cache)
    return v._make_subnet_dict(subnet)
Ejemplo n.º 6
0
def get_subnet(context, id, fields=None):
    """Retrieve a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to fetch.
    : param fields: a list of strings that are valid keys in a
        subnet dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_subnet %s for tenant %s with fields %s" %
             (id, context.tenant_id, fields))
    subnet = db_api.subnet_find(context,
                                None,
                                None,
                                None,
                                False,
                                id=id,
                                join_dns=True,
                                join_routes=True,
                                scope=db_api.ONE)
    if not subnet:
        raise exceptions.SubnetNotFound(subnet_id=id)

    cache = subnet.get("_allocation_pool_cache")
    if not cache:
        new_cache = subnet.allocation_pools
        db_api.subnet_update_set_alloc_pool_cache(context, subnet, new_cache)
    return v._make_subnet_dict(subnet)
Ejemplo n.º 7
0
def get_subnet(context, id, fields=None):
    """Retrieve a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to fetch.
    : param fields: a list of strings that are valid keys in a
        subnet dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_subnet %s for tenant %s with fields %s" %
             (id, context.tenant_id, fields))
    subnet = db_api.subnet_find(context,
                                id=id,
                                join_dns=True,
                                join_routes=True,
                                scope=db_api.ONE)
    if not subnet:
        raise exceptions.SubnetNotFound(subnet_id=id)

    # Check the network_id against the strategies
    net_id = subnet["network_id"]
    net_id = STRATEGY.get_parent_network(net_id)
    subnet["network_id"] = net_id

    return v._make_subnet_dict(subnet)
Ejemplo n.º 8
0
def create_route(context, route):
    LOG.info("create_route for tenant %s" % context.tenant_id)
    route = route["route"]
    for key in ["gateway", "cidr", "subnet_id"]:
        if key not in route:
            raise exceptions.BadRequest(resource="routes", msg="%s is required" % key)

    subnet_id = route["subnet_id"]
    with context.session.begin():
        subnet = db_api.subnet_find(context, id=subnet_id, scope=db_api.ONE)
        if not subnet:
            raise exceptions.SubnetNotFound(subnet_id=subnet_id)
        policies = db_models.IPPolicy.get_ip_policy_cidrs(subnet)
        alloc_pools = allocation_pool.AllocationPools(subnet["cidr"], policies=policies)
        alloc_pools.validate_gateway_excluded(route["gateway"])

        # TODO(anyone): May want to denormalize the cidr values into columns
        #               to achieve single db lookup on conflict check
        route_cidr = netaddr.IPNetwork(route["cidr"])
        subnet_routes = db_api.route_find(context, subnet_id=subnet_id, scope=db_api.ALL)

        quota.QUOTAS.limit_check(context, context.tenant_id, routes_per_subnet=len(subnet_routes) + 1)

        for sub_route in subnet_routes:
            sub_route_cidr = netaddr.IPNetwork(sub_route["cidr"])
            if sub_route_cidr.value == DEFAULT_ROUTE.value:
                continue
            if route_cidr in sub_route_cidr or sub_route_cidr in route_cidr:
                raise quark_exceptions.RouteConflict(route_id=sub_route["id"], cidr=str(route_cidr))
        new_route = db_api.route_create(context, **route)
    return v._make_route_dict(new_route)
Ejemplo n.º 9
0
    def test_subnet_update_set_alloc_pool_cache_concurrency(self):
        subnet = {"cidr": "192.168.10.0/24"}
        subnet_db = db_api.subnet_create(self.context, **subnet)
        self.context.session.flush()

        # establish second session
        old_session = self.context.session
        self.context._session = None

        subnet_to_delete = db_api.subnet_find(
            self.context, id=subnet_db.id, scope=db_api.ONE)
        db_api.subnet_delete(self.context, subnet_to_delete)
        self.context.session.flush()

        # restore first session
        self.context._session = old_session

        try:
            db_api.subnet_update_set_alloc_pool_cache(
                self.context, subnet_db, {"foo": "bar"})
            self.context.session.flush()
        except exc.StaleDataError as e:
            self.fail("Did not expect StaleDataError exception: {0}".format(e))
        self.assertEqual(subnet_db["_allocation_pool_cache"],
                         "{\"foo\": \"bar\"}")
Ejemplo n.º 10
0
def _validate_subnet_cidr(context, network_id, new_subnet_cidr):
    """Validate the CIDR for a subnet.

    Verifies the specified CIDR does not overlap with the ones defined
    for the other subnets specified for this network, or with any other
    CIDR if overlapping IPs are disabled.

    """
    if neutron_cfg.cfg.CONF.allow_overlapping_ips:
        return

    new_subnet_ipset = netaddr.IPSet([new_subnet_cidr])

    # Using admin context here, in case we actually share networks later
    subnet_list = db_api.subnet_find(context.elevated(),
                                     network_id=network_id)
    for subnet in subnet_list:
        if (netaddr.IPSet([subnet.cidr]) & new_subnet_ipset):
            # don't give out details of the overlapping subnet
            err_msg = (_("Requested subnet with cidr: %(cidr)s for "
                         "network: %(network_id)s overlaps with another "
                         "subnet") %
                       {'cidr': new_subnet_cidr,
                        'network_id': network_id})
            LOG.error(_("Validation for CIDR: %(new_cidr)s failed - "
                        "overlaps with subnet %(subnet_id)s "
                        "(CIDR: %(cidr)s)"),
                      {'new_cidr': new_subnet_cidr,
                       'subnet_id': subnet.id,
                       'cidr': subnet.cidr})
            raise exceptions.InvalidInput(error_message=err_msg)
Ejemplo n.º 11
0
def get_subnets(context, filters=None, fields=None):
    """Retrieve a list of subnets.

    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 subnet 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
        subnet dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_subnets for tenant %s with filters %s fields %s" %
             (context.tenant_id, filters, fields))
    subnets = db_api.subnet_find(context, **filters)
    return v._make_subnets_list(subnets,
                                fields=fields,
                                default_route=routes.DEFAULT_ROUTE)
Ejemplo n.º 12
0
def _validate_subnet_cidr(context, network_id, new_subnet_cidr):
    """Validate the CIDR for a subnet.

    Verifies the specified CIDR does not overlap with the ones defined
    for the other subnets specified for this network, or with any other
    CIDR if overlapping IPs are disabled.

    """
    if neutron_cfg.cfg.CONF.allow_overlapping_ips:
        return

    new_subnet_ipset = netaddr.IPSet([new_subnet_cidr])

    # Using admin context here, in case we actually share networks later
    subnet_list = db_api.subnet_find(context.elevated(), network_id=network_id)
    for subnet in subnet_list:
        if (netaddr.IPSet([subnet.cidr]) & new_subnet_ipset):
            # don't give out details of the overlapping subnet
            err_msg = (_("Requested subnet with cidr: %(cidr)s for "
                         "network: %(network_id)s overlaps with another "
                         "subnet") % {
                             'cidr': new_subnet_cidr,
                             'network_id': network_id
                         })
            LOG.error(
                _("Validation for CIDR: %(new_cidr)s failed - "
                  "overlaps with subnet %(subnet_id)s "
                  "(CIDR: %(cidr)s)"), {
                      'new_cidr': new_subnet_cidr,
                      'subnet_id': subnet.id,
                      'cidr': subnet.cidr
                  })
            raise exceptions.InvalidInput(error_message=err_msg)
Ejemplo n.º 13
0
    def test_subnets_get_marked_as_full_retroactively(self):
        models = []
        models.append(self._create_models(
            "0.0.0.0/31",
            4,
            netaddr.IPNetwork("0.0.0.0/31").ipv6().last))
        models.append(self._create_models(
            "1.1.1.0/31",
            4,
            netaddr.IPNetwork("1.1.1.0/31").ipv6().last))
        models.append(self._create_models(
            "2.2.2.0/30",
            4,
            netaddr.IPNetwork("2.2.2.0/30").ipv6().first))

        with self._fixtures(models) as net:
            ipaddress = []
            self.ipam.allocate_ip_address(self.context, ipaddress,
                                          net['id'], 0, 0)
            self.assertEqual(ipaddress[0].version, 4)
            self.assertEqual(ipaddress[0].address_readable, "2.2.2.1")

            with self.context.session.begin():
                subnets = db_api.subnet_find(self.context, None, None, None,
                                             False).all()
                self.assertEqual(len(subnets), 3)

                full_subnets = [s for s in subnets
                                if s.next_auto_assign_ip == -1]
                self.assertEqual(len(full_subnets), 2)
                available_subnets = list(set(full_subnets) ^ set(subnets))
                self.assertEqual(len(available_subnets), 1)
                self.assertEqual(available_subnets[0].cidr, "2.2.2.0/30")
                self.assertEqual(available_subnets[0].next_auto_assign_ip,
                                 netaddr.IPAddress("2.2.2.2").ipv6().value)
Ejemplo n.º 14
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"])
Ejemplo n.º 15
0
def get_subnet(context, id, fields=None):
    """Retrieve a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to fetch.
    : param fields: a list of strings that are valid keys in a
        subnet dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_subnet %s for tenant %s with fields %s" %
             (id, context.tenant_id, fields))
    subnet = db_api.subnet_find(context=context, limit=None,
                                page_reverse=False, sorts=['id'],
                                marker_obj=None, fields=None, id=id,
                                join_dns=True, join_routes=True,
                                scope=db_api.ONE)
    if not subnet:
        raise n_exc.SubnetNotFound(subnet_id=id)

    cache = subnet.get("_allocation_pool_cache")
    if not cache:
        new_cache = subnet.allocation_pools
        db_api.subnet_update_set_alloc_pool_cache(context, subnet, new_cache)
    return v._make_subnet_dict(subnet)
Ejemplo n.º 16
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)
Ejemplo n.º 17
0
def get_subnets_cidr_set(context, network_ids):
    ipset = netaddr.IPSet()
    subnets = db_api.subnet_find(context, network_id=network_ids,
                                 shared=[False])
    for subnet in subnets:
        net = netaddr.IPNetwork(subnet["cidr"])
        ipset.add(net)
    return ipset
Ejemplo n.º 18
0
def update_subnet(context, id, subnet):
    """Update values of a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to update.
    : param subnet: 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_subnet %s for tenant %s" % (id, context.tenant_id))

    subnet_db = db_api.subnet_find(context, id=id, scope=db_api.ONE)
    if not subnet_db:
        raise exceptions.SubnetNotFound(id=id)

    s = subnet["subnet"]

    dns_ips = s.pop("dns_nameservers", [])
    host_routes = s.pop("host_routes", [])
    gateway_ip = s.pop("gateway_ip", None)

    if gateway_ip:
        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
                break
        if default_route is None:
            route_model = db_api.route_find(context,
                                            cidr=str(routes.DEFAULT_ROUTE),
                                            subnet_id=id,
                                            scope=db_api.ONE)
            if route_model:
                db_api.route_update(context, route_model, gateway=gateway_ip)
            else:
                db_api.route_create(context,
                                    cidr=str(routes.DEFAULT_ROUTE),
                                    gateway=gateway_ip,
                                    subnet_id=id)

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

    if host_routes:
        subnet_db["routes"] = []
    for route in host_routes:
        subnet_db["routes"].append(
            db_api.route_create(context,
                                cidr=route["destination"],
                                gateway=route["nexthop"]))

    subnet = db_api.subnet_update(context, subnet_db, **s)
    return v._make_subnet_dict(subnet, default_route=routes.DEFAULT_ROUTE)
Ejemplo n.º 19
0
def update_subnet(context, id, subnet):
    """Update values of a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to update.
    : param subnet: 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_subnet %s for tenant %s" %
             (id, context.tenant_id))

    with context.session.begin():
        subnet_db = db_api.subnet_find(context, id=id, scope=db_api.ONE)
        if not subnet_db:
            raise exceptions.SubnetNotFound(id=id)

        s = subnet["subnet"]

        dns_ips = s.pop("dns_nameservers", [])
        host_routes = s.pop("host_routes", [])
        gateway_ip = s.pop("gateway_ip", None)

        if gateway_ip:
            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
                    break
            if default_route is None:
                route_model = db_api.route_find(
                    context, cidr=str(routes.DEFAULT_ROUTE), subnet_id=id,
                    scope=db_api.ONE)
                if route_model:
                    db_api.route_update(context, route_model,
                                        gateway=gateway_ip)
                else:
                    db_api.route_create(context,
                                        cidr=str(routes.DEFAULT_ROUTE),
                                        gateway=gateway_ip, subnet_id=id)

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

        if host_routes:
            subnet_db["routes"] = []
        for route in host_routes:
            subnet_db["routes"].append(db_api.route_create(
                context, cidr=route["destination"], gateway=route["nexthop"]))

        subnet = db_api.subnet_update(context, subnet_db, **s)
    return v._make_subnet_dict(subnet)
Ejemplo n.º 20
0
def get_subnets_cidr_set(context, network_ids):
    ipset = netaddr.IPSet()
    subnets = db_api.subnet_find(context,
                                 network_id=network_ids,
                                 shared=[False])
    for subnet in subnets:
        net = netaddr.IPNetwork(subnet["cidr"])
        ipset.add(net)
    return ipset
Ejemplo n.º 21
0
 def _create_ip_address(self, ip_address, ip_version, subnet_cidr, net_id):
     with self.context.session.begin():
         subnet = db_api.subnet_find(self.context, None, False, None, None,
                                     cidr=subnet_cidr).all()
         ip = dict(subnet_id=subnet[0].id,
                   network_id=net_id,
                   version=ip_version,
                   address=netaddr.IPAddress(ip_address))
         db_api.ip_address_create(self.context, **ip)
Ejemplo n.º 22
0
    def attempt_to_reallocate_ip(self, context, net_id, port_id, reuse_after,
                                 version=None, ip_address=None,
                                 segment_id=None, subnets=None):
        version = version or [4, 6]
        elevated = context.elevated()

        # We never want to take the chance of an infinite loop here. Instead,
        # we'll clean up multiple bad IPs if we find them (assuming something
        # is really wrong)

        #TODO(mdietz & mpath): Perhaps remove, select for update might quash
        for times in xrange(3):
            with context.session.begin(subtransactions=True):

                sub_ids = []
                if subnets:
                    sub_ids = subnets
                else:
                    if segment_id:
                        subnets = db_api.subnet_find(elevated,
                                                     network_id=net_id,
                                                     segment_id=segment_id)
                        sub_ids = [s["id"] for s in subnets]
                        if not sub_ids:
                            raise exceptions.IpAddressGenerationFailure(
                                net_id=net_id)

                ip_kwargs = {
                    "network_id": net_id, "reuse_after": reuse_after,
                    "deallocated": True, "scope": db_api.ONE,
                    "ip_address": ip_address, "lock_mode": True,
                    "version": version, "order_by": "address"}

                if sub_ids:
                    ip_kwargs["subnet_id"] = sub_ids

                address = db_api.ip_address_find(elevated, **ip_kwargs)

                if address:
                    #NOTE(mdietz): We should always be in the CIDR but we've
                    #              also said that before :-/
                    if address.get("subnet"):
                        cidr = netaddr.IPNetwork(address["subnet"]["cidr"])
                        addr = netaddr.IPAddress(int(address["address"]),
                                                 version=int(cidr.version))
                        if addr in cidr:
                            updated_address = db_api.ip_address_update(
                                elevated, address, deallocated=False,
                                deallocated_at=None,
                                allocated_at=timeutils.utcnow())
                            return [updated_address]
                        else:
                            # Make sure we never find it again
                            context.session.delete(address)
                            continue
                break
        return []
Ejemplo n.º 23
0
def delete_subnet(context, id):
    """Delete a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to delete.
    """
    LOG.info("delete_subnet %s for tenant %s" % (id, context.tenant_id))
    subnet = db_api.subnet_find(context, id=id, scope=db_api.ONE)
    if not subnet:
        raise exceptions.SubnetNotFound(subnet_id=id)
    _delete_subnet(context, subnet)
Ejemplo n.º 24
0
 def _create_ip_address(self, ip_address, ip_version, subnet_cidr, net_id):
     with self.context.session.begin():
         subnet = db_api.subnet_find(context=self.context, limit=None,
                                     page_reverse=False, sorts=['id'],
                                     marker_obj=None,
                                     cidr=subnet_cidr).all()
         ip = dict(subnet_id=subnet[0].id,
                   network_id=net_id,
                   version=ip_version,
                   address=netaddr.IPAddress(ip_address))
         db_api.ip_address_create(self.context, **ip)
Ejemplo n.º 25
0
def delete_subnet(context, id):
    """Delete a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to delete.
    """
    LOG.info("delete_subnet %s for tenant %s" % (id, context.tenant_id))
    subnet = db_api.subnet_find(context, id=id, scope=db_api.ONE)
    if not subnet:
        raise exceptions.SubnetNotFound(subnet_id=id)
    _delete_subnet(context, subnet)
Ejemplo n.º 26
0
 def test_subnet_set_full(self):
     cidr4 = "0.0.0.0/30"  # 2 bits
     net4 = netaddr.IPNetwork(cidr4)
     with self._fixtures([self._create_models(cidr4, 4, net4[0])]) as net:
         subnet = db_api.subnet_find(self.context,
                                     network_id=net['id'],
                                     scope=db_api.ALL)[0]
         with self.context.session.begin():
             updated = db_api.subnet_update_set_full(self.context, subnet)
             self.context.session.refresh(subnet)
             self.assertTrue(updated)
             self.assertEqual(subnet["next_auto_assign_ip"], -1)
Ejemplo n.º 27
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)
Ejemplo n.º 28
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"])
Ejemplo n.º 29
0
 def test_subnet_set_full(self):
     cidr4 = "0.0.0.0/30"  # 2 bits
     net4 = netaddr.IPNetwork(cidr4)
     with self._fixtures([
         self._create_models(cidr4, 4, net4[0])
     ]) as net:
         subnet = db_api.subnet_find(self.context, network_id=net['id'],
                                     scope=db_api.ALL)[0]
         with self.context.session.begin():
             updated = db_api.subnet_update_set_full(self.context, subnet)
             self.context.session.refresh(subnet)
             self.assertTrue(updated)
             self.assertEqual(subnet["next_auto_assign_ip"], -1)
Ejemplo n.º 30
0
 def _create_ip_address(self, ip_address, ip_version, subnet_cidr, net_id):
     with self.context.session.begin():
         subnet = db_api.subnet_find(context=self.context,
                                     limit=None,
                                     page_reverse=False,
                                     sorts=['id'],
                                     marker_obj=None,
                                     cidr=subnet_cidr).all()
         ip = dict(subnet_id=subnet[0].id,
                   network_id=net_id,
                   version=ip_version,
                   address=netaddr.IPAddress(ip_address))
         db_api.ip_address_create(self.context, **ip)
Ejemplo n.º 31
0
 def _create_ip_address(self, ip_address, ip_version, subnet_cidr, net_id):
     with self.context.session.begin():
         subnet = db_api.subnet_find(self.context,
                                     None,
                                     False,
                                     None,
                                     None,
                                     cidr=subnet_cidr).all()
         ip = dict(subnet_id=subnet[0].id,
                   network_id=net_id,
                   version=ip_version,
                   address=netaddr.IPAddress(ip_address))
         db_api.ip_address_create(self.context, **ip)
Ejemplo n.º 32
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)
Ejemplo n.º 33
0
def create_route(context, route):
    LOG.info("create_route for tenant %s" % context.tenant_id)
    if not route:
        raise n_exc.BadRequest(resource="routes", msg="Malformed body")
    route = route.get("route")
    if not route:
        raise n_exc.BadRequest(resource="routes", msg="Malformed body")
    for key in ["gateway", "cidr", "subnet_id"]:
        if key not in route:
            raise n_exc.BadRequest(resource="routes",
                                   msg="%s is required" % key)

    subnet_id = route["subnet_id"]
    with context.session.begin():
        subnet = db_api.subnet_find(context, id=subnet_id, scope=db_api.ONE)
        if not subnet:
            raise n_exc.SubnetNotFound(subnet_id=subnet_id)

        if subnet["ip_policy"]:
            policies = subnet["ip_policy"].get_cidrs_ip_set()
        else:
            policies = netaddr.IPSet([])

        alloc_pools = allocation_pool.AllocationPools(subnet["cidr"],
                                                      policies=policies)
        try:
            alloc_pools.validate_gateway_excluded(route["gateway"])
        except neutron_exc.GatewayConflictWithAllocationPools as e:
            LOG.exception(str(e))
            raise n_exc.BadRequest(resource="routes", msg=str(e))

        # TODO(anyone): May want to denormalize the cidr values into columns
        #               to achieve single db lookup on conflict check
        route_cidr = netaddr.IPNetwork(route["cidr"])
        subnet_routes = db_api.route_find(context, subnet_id=subnet_id,
                                          scope=db_api.ALL)

        quota.QUOTAS.limit_check(context, context.tenant_id,
                                 routes_per_subnet=len(subnet_routes) + 1)

        for sub_route in subnet_routes:
            sub_route_cidr = netaddr.IPNetwork(sub_route["cidr"])
            if sub_route_cidr.value == DEFAULT_ROUTE.value:
                continue
            if route_cidr in sub_route_cidr or sub_route_cidr in route_cidr:
                raise q_exc.RouteConflict(route_id=sub_route["id"],
                                          cidr=str(route_cidr))
        new_route = db_api.route_create(context, **route)
    return v._make_route_dict(new_route)
Ejemplo n.º 34
0
def get_subnets(context,
                limit=None,
                page_reverse=False,
                sorts=['id'],
                marker=None,
                filters=None,
                fields=None):
    """Retrieve a list of subnets.

    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 subnet 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
        subnet dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_subnets for tenant %s with filters %s fields %s" %
             (context.tenant_id, filters, fields))
    filters = filters or {}
    subnets = db_api.subnet_find(context,
                                 limit=limit,
                                 page_reverse=page_reverse,
                                 sorts=sorts,
                                 marker_obj=marker,
                                 join_dns=True,
                                 join_routes=True,
                                 join_pool=True,
                                 **filters)
    for subnet in subnets:
        cache = subnet.get("_allocation_pool_cache")
        if not cache:
            db_api.subnet_update_set_alloc_pool_cache(context, subnet,
                                                      subnet.allocation_pools)
    return v._make_subnets_list(subnets, fields=fields)
Ejemplo n.º 35
0
    def create_route(self, context, route):
        LOG.info("create_route for tenant %s" % context.tenant_id)
        route = route["route"]
        subnet_id = route["subnet_id"]
        subnet = db_api.subnet_find(context, id=id)
        if not subnet:
            raise exceptions.SubnetNotFound(subnet_id=subnet_id)

        # TODO(anyone): May need to denormalize the cidr values to achieve
        #               single db lookup
        route_cidr = netaddr.IPNetwork(route["cidr"])
        subnet_routes = db_api.route_find(context, subnet_id=subnet_id)
        for sub_route in subnet_routes:
            sub_route_cidr = netaddr.IPNetwork(sub_route["cidr"])
            if route_cidr in sub_route_cidr or sub_route_cidr in route_cidr:
                raise quark_exceptions.RouteConflict(route_id=sub_route["id"],
                                                     cidr=str(route_cidr))

        new_route = db_api.route_create(context, **route)
        return self._make_route_dict(new_route)
Ejemplo n.º 36
0
def delete_subnet(context, id):
    """Delete a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to delete.
    """
    LOG.info("delete_subnet %s for tenant %s" % (id, context.tenant_id))
    with context.session.begin():
        subnet = db_api.subnet_find(context, id=id, scope=db_api.ONE)
        if not subnet:
            raise exceptions.SubnetNotFound(subnet_id=id)

        payload = dict(tenant_id=subnet["tenant_id"],
                       ip_block_id=subnet["id"],
                       created_at=subnet["created_at"],
                       deleted_at=timeutils.utcnow())

        _delete_subnet(context, subnet)

        n_rpc.get_notifier("network").info(context, "ip_block.delete", payload)
Ejemplo n.º 37
0
def delete_subnet(context, id):
    """Delete a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to delete.
    """
    LOG.info("delete_subnet %s for tenant %s" % (id, context.tenant_id))
    with context.session.begin():
        subnet = db_api.subnet_find(context, id=id, scope=db_api.ONE)
        if not subnet:
            raise exceptions.SubnetNotFound(subnet_id=id)

        payload = dict(tenant_id=subnet["tenant_id"],
                       ip_block_id=subnet["id"],
                       created_at=subnet["created_at"],
                       deleted_at=timeutils.utcnow())

        _delete_subnet(context, subnet)

        n_rpc.get_notifier("network").info(context, "ip_block.delete", payload)
Ejemplo n.º 38
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)
Ejemplo n.º 39
0
def get_subnet(context, id, fields=None):
    """Retrieve a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to fetch.
    : param fields: a list of strings that are valid keys in a
        subnet dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_subnet %s for tenant %s with fields %s" %
            (id, context.tenant_id, fields))
    subnet = db_api.subnet_find(context, id=id, scope=db_api.ONE)
    if not subnet:
        raise exceptions.SubnetNotFound(subnet_id=id)

    # Check the network_id against the strategies
    net_id = subnet["network_id"]
    net_id = STRATEGY.get_parent_network(net_id)
    subnet["network_id"] = net_id

    return v._make_subnet_dict(subnet, default_route=routes.DEFAULT_ROUTE)
Ejemplo n.º 40
0
def create_route(context, route):
    LOG.info("create_route for tenant %s" % context.tenant_id)
    route = route["route"]
    subnet_id = route["subnet_id"]
    subnet = db_api.subnet_find(context, id=subnet_id, scope=db_api.ONE)
    if not subnet:
        raise exceptions.SubnetNotFound(subnet_id=subnet_id)

    # TODO(anyone): May want to denormalize the cidr values into columns
    #               to achieve single db lookup on conflict check
    route_cidr = netaddr.IPNetwork(route["cidr"])
    subnet_routes = db_api.route_find(context, subnet_id=subnet_id,
                                      scope=db_api.ALL)
    for sub_route in subnet_routes:
        sub_route_cidr = netaddr.IPNetwork(sub_route["cidr"])
        if sub_route_cidr.value == DEFAULT_ROUTE.value:
            continue
        if route_cidr in sub_route_cidr or sub_route_cidr in route_cidr:
            raise quark_exceptions.RouteConflict(
                route_id=sub_route["id"], cidr=str(route_cidr))
    new_route = db_api.route_create(context, **route)
    return v._make_route_dict(new_route)
Ejemplo n.º 41
0
def create_route(context, route):
    LOG.info("create_route for tenant %s" % context.tenant_id)
    route = route["route"]
    subnet_id = route["subnet_id"]
    subnet = db_api.subnet_find(context, id=subnet_id, scope=db_api.ONE)
    if not subnet:
        raise exceptions.SubnetNotFound(subnet_id=subnet_id)

    # TODO(anyone): May want to denormalize the cidr values into columns
    #               to achieve single db lookup on conflict check
    route_cidr = netaddr.IPNetwork(route["cidr"])
    subnet_routes = db_api.route_find(context,
                                      subnet_id=subnet_id,
                                      scope=db_api.ALL)
    for sub_route in subnet_routes:
        sub_route_cidr = netaddr.IPNetwork(sub_route["cidr"])
        if sub_route_cidr.value == DEFAULT_ROUTE.value:
            continue
        if route_cidr in sub_route_cidr or sub_route_cidr in route_cidr:
            raise quark_exceptions.RouteConflict(route_id=sub_route["id"],
                                                 cidr=str(route_cidr))
    new_route = db_api.route_create(context, **route)
    return v._make_route_dict(new_route)
Ejemplo n.º 42
0
    def get_subnets(self, context, filters=None, fields=None):
        """Retrieve a list of subnets.

        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: quantum api request context
        : param filters: a dictionary with keys that are valid keys for
            a subnet as listed in the RESOURCE_ATTRIBUTE_MAP object
            in quantum/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
            subnet dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
            object in quantum/api/v2/attributes.py. Only these fields
            will be returned.
        """
        LOG.info("get_subnets for tenant %s with filters %s fields %s" %
                (context.tenant_id, filters, fields))
        subnets = db_api.subnet_find(context, **filters)
        return self._make_subnets_list(subnets, fields)
Ejemplo n.º 43
0
def delete_subnet(context, id):
    """Delete a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to delete.
    """
    LOG.info("delete_subnet %s for tenant %s" % (id, context.tenant_id))
    with context.session.begin():
        subnet = db_api.subnet_find(context, id=id, scope=db_api.ONE)
        if not subnet:
            raise n_exc.SubnetNotFound(subnet_id=id)

        if not context.is_admin:
            if STRATEGY.is_provider_network(subnet.network_id):
                if subnet.tenant_id == context.tenant_id:
                    # A tenant can't delete subnets on provider network
                    raise n_exc.NotAuthorized(subnet_id=id)
                else:
                    # Raise a NotFound here because the foreign tenant
                    # does not have to know about other tenant's subnet
                    # existence.
                    raise n_exc.SubnetNotFound(subnet_id=id)

        _delete_subnet(context, subnet)
Ejemplo n.º 44
0
def delete_subnet(context, id):
    """Delete a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to delete.
    """
    LOG.info("delete_subnet %s for tenant %s" % (id, context.tenant_id))
    with context.session.begin():
        subnet = db_api.subnet_find(context, id=id, scope=db_api.ONE)
        if not subnet:
            raise n_exc.SubnetNotFound(subnet_id=id)

        if not context.is_admin:
            if STRATEGY.is_provider_network(subnet.network_id):
                if subnet.tenant_id == context.tenant_id:
                    # A tenant can't delete subnets on provider network
                    raise n_exc.NotAuthorized(subnet_id=id)
                else:
                    # Raise a NotFound here because the foreign tenant
                    # does not have to know about other tenant's subnet
                    # existence.
                    raise n_exc.SubnetNotFound(subnet_id=id)

        _delete_subnet(context, subnet)
Ejemplo n.º 45
0
    def attempt_to_reallocate_ip(self, context, net_id, port_id, reuse_after,
                                 version=None, ip_address=None,
                                 segment_id=None, subnets=None, **kwargs):
        version = version or [4, 6]
        elevated = context.elevated()

        LOG.info("Attempting to reallocate an IP (step 1 of 3) - [{0}]".format(
            utils.pretty_kwargs(network_id=net_id, port_id=port_id,
                                version=version, segment_id=segment_id,
                                subnets=subnets)))

        if version == 6 and "mac_address" in kwargs and kwargs["mac_address"]:
            # Defers to the create case. The reason why is we'd have to look
            # up subnets here to correctly generate the v6. If we split them
            # up into reallocate and create, we'd be looking up the same
            # subnets twice, which is a waste of time.

            # TODO(mdietz): after reviewing this code, this block annoyingly
            #               doesn't trigger in the ANY case, since we end up
            #               using a list of [4, 6]. It works as expected most
            #               of the time, but we can anticipate that isolated
            #               networks will end up using sequential assignment.
            #               Probably want to rework this logic to compensate
            #               at some point. Considering they all come from the
            #               same MAC address pool, nothing bad will happen,
            #               just worth noticing and fixing.
            LOG.info("Identified as v6 case, deferring to IP create path")
            return []

        sub_ids = []
        if subnets:
            sub_ids = subnets
        else:
            if segment_id:
                subnets = db_api.subnet_find(elevated,
                                             network_id=net_id,
                                             segment_id=segment_id)
                sub_ids = [s["id"] for s in subnets]
                if not sub_ids:
                    LOG.info("No subnets matching segment_id {0} could be "
                             "found".format(segment_id))
                    raise exceptions.IpAddressGenerationFailure(
                        net_id=net_id)

        ip_kwargs = {
            "network_id": net_id, "reuse_after": reuse_after,
            "deallocated": True, "scope": db_api.ONE,
            "ip_address": ip_address, "lock_mode": True,
            "version": version, "order_by": "address",
            "do_not_use": False}

        if sub_ids:
            ip_kwargs["subnet_id"] = sub_ids

        # We never want to take the chance of an infinite loop here. Instead,
        # we'll clean up multiple bad IPs if we find them (assuming something
        # is really wrong)
        for retry in xrange(CONF.QUARK.ip_address_retry_max):
            LOG.info("Attempt {0} of {1}".format(
                retry + 1, CONF.QUARK.ip_address_retry_max))
            get_policy = models.IPPolicy.get_ip_policy_cidrs

            try:
                with context.session.begin():
                    # NOTE(mdietz): Before I removed the lazy=joined, this
                    #               raised with an unknown column "address"
                    #               error.
                    address = db_api.ip_address_find(elevated, **ip_kwargs)

                    if address:
                        # NOTE(mdietz): We should always be in the CIDR but we
                        #              also said that before :-/
                        LOG.info("Potentially reallocatable IP found: "
                                 "{0}".format(address["address_readable"]))
                        subnet = address.get('subnet')
                        if subnet:
                            policy = get_policy(subnet)

                            cidr = netaddr.IPNetwork(address["subnet"]["cidr"])
                            addr = netaddr.IPAddress(int(address["address"]))
                            if address["subnet"]["ip_version"] == 4:
                                addr = addr.ipv4()
                            else:
                                addr = addr.ipv6()

                            if policy is not None and addr in policy:
                                LOG.info("Deleting Address {0} due to policy "
                                         "violation".format(
                                             address["address_readable"]))

                                context.session.delete(address)
                                continue
                            if addr in cidr:
                                LOG.info("Marking Address {0} as "
                                         "allocated".format(
                                             address["address_readable"]))
                                updated_address = db_api.ip_address_update(
                                    elevated, address, deallocated=False,
                                    deallocated_at=None,
                                    used_by_tenant_id=context.tenant_id,
                                    allocated_at=timeutils.utcnow(),
                                    port_id=port_id,
                                    address_type=kwargs.get('address_type',
                                                            ip_types.FIXED))
                                return [updated_address]
                            else:
                                # Make sure we never find it again
                                LOG.info("Address {0} isn't in the subnet "
                                         "it claims to be in".format(
                                             address["address_readable"]))
                                context.session.delete(address)
                    else:
                        LOG.info("Couldn't find any reallocatable addresses "
                                 "given the criteria")
                        break
            except Exception:
                LOG.exception("Error in reallocate ip...")
        return []
Ejemplo n.º 46
0
Archivo: ipam.py Proyecto: roaet/quark
    def attempt_to_reallocate_ip(self, context, net_id, port_id, reuse_after,
                                 version=None, ip_address=None,
                                 segment_id=None, subnets=None, **kwargs):
        version = version or [4, 6]
        elevated = context.elevated()

        LOG.info("Attempting to reallocate an IP (step 1 of 3) - [{0}]".format(
            utils.pretty_kwargs(network_id=net_id, port_id=port_id,
                                version=version, segment_id=segment_id,
                                subnets=subnets, ip_address=ip_address)))

        if version == 6:
            # Defers to the create case. The reason why is we'd have to look
            # up subnets here to correctly generate the v6. If we split them
            # up into reallocate and create, we'd be looking up the same
            # subnets twice, which is a waste of time.

            # TODO(mdietz): after reviewing this code, this block annoyingly
            #               doesn't trigger in the ANY case, since we end up
            #               using a list of [4, 6]. It works as expected most
            #               of the time, but we can anticipate that isolated
            #               networks will end up using sequential assignment.
            #               Probably want to rework this logic to compensate
            #               at some point. Considering they all come from the
            #               same MAC address pool, nothing bad will happen,
            #               just worth noticing and fixing.
            LOG.info("Identified as v6 case, deferring to IP create path")
            return []

        sub_ids = []
        if subnets:
            sub_ids = subnets
        elif segment_id:
            subnets = db_api.subnet_find(elevated,
                                         network_id=net_id,
                                         segment_id=segment_id)
            sub_ids = [s["id"] for s in subnets]
            if not sub_ids:
                LOG.info("No subnets matching segment_id {0} could be "
                         "found".format(segment_id))
                raise ip_address_failure(net_id)

        ip_kwargs = {
            "network_id": net_id,
            "deallocated": True,
            "version": version,
            "lock_id": None,
        }
        if reuse_after is not None:
            ip_kwargs["reuse_after"] = reuse_after
        if ip_address is not None:
            ip_kwargs["ip_address"] = ip_address
            del ip_kwargs["deallocated"]
        if sub_ids:
            ip_kwargs["subnet_id"] = sub_ids

        ipam_log = kwargs.get('ipam_log', None)

        for retry in xrange(CONF.QUARK.ip_address_retry_max):
            attempt = None
            if ipam_log:
                attempt = ipam_log.make_entry("attempt_to_reallocate_ip")
            LOG.info("Attempt {0} of {1}".format(
                retry + 1, CONF.QUARK.ip_address_retry_max))
            try:
                with context.session.begin():
                    transaction = db_api.transaction_create(context)
                m = models.IPAddress
                update_kwargs = {
                    m.transaction_id: transaction.id,
                    m.address_type: kwargs.get("address_type", ip_types.FIXED),
                    m.deallocated: False,
                    m.deallocated_at: None,
                    m.used_by_tenant_id: context.tenant_id,
                    m.allocated_at: timeutils.utcnow(),
                }
                result = db_api.ip_address_reallocate(
                    elevated, update_kwargs, **ip_kwargs)
                if not result:
                    LOG.info("Couldn't update any reallocatable addresses "
                             "given the criteria")
                    if attempt:
                        attempt.failed()
                    break

                updated_address = db_api.ip_address_reallocate_find(
                    elevated, transaction.id)
                if not updated_address:
                    if attempt:
                        attempt.failed()
                    continue

                LOG.info("Address {0} is reallocated".format(
                    updated_address["address_readable"]))
                return [updated_address]
            except Exception:
                if attempt:
                    attempt.failed()
                LOG.exception("Error in reallocate ip...")
            finally:
                if attempt:
                    attempt.end()
        return []
Ejemplo n.º 47
0
    def attempt_to_reallocate_ip(self, context, net_id, port_id, reuse_after,
                                 version=None, ip_address=None,
                                 segment_id=None, subnets=None, **kwargs):
        version = version or [4, 6]
        elevated = context.elevated()

        LOG.info("Attempting to reallocate an IP (step 1 of 3) - [{0}]".format(
            utils.pretty_kwargs(network_id=net_id, port_id=port_id,
                                version=version, segment_id=segment_id,
                                subnets=subnets)))

        if version == 6:
            # Defers to the create case. The reason why is we'd have to look
            # up subnets here to correctly generate the v6. If we split them
            # up into reallocate and create, we'd be looking up the same
            # subnets twice, which is a waste of time.

            # TODO(mdietz): after reviewing this code, this block annoyingly
            #               doesn't trigger in the ANY case, since we end up
            #               using a list of [4, 6]. It works as expected most
            #               of the time, but we can anticipate that isolated
            #               networks will end up using sequential assignment.
            #               Probably want to rework this logic to compensate
            #               at some point. Considering they all come from the
            #               same MAC address pool, nothing bad will happen,
            #               just worth noticing and fixing.
            LOG.info("Identified as v6 case, deferring to IP create path")
            return []

        sub_ids = []
        if subnets:
            sub_ids = subnets
        elif segment_id:
            subnets = db_api.subnet_find(elevated,
                                         network_id=net_id,
                                         segment_id=segment_id)
            sub_ids = [s["id"] for s in subnets]
            if not sub_ids:
                LOG.info("No subnets matching segment_id {0} could be "
                         "found".format(segment_id))
                raise exceptions.IpAddressGenerationFailure(
                    net_id=net_id)

        ip_kwargs = {
            "network_id": net_id,
            "reuse_after": reuse_after,
            "deallocated": True,
            "ip_address": ip_address,
            "version": version,
        }
        if ip_address:
            del ip_kwargs["deallocated"]
        if sub_ids:
            ip_kwargs["subnet_id"] = sub_ids

        ipam_log = kwargs.get('ipam_log', None)

        for retry in xrange(CONF.QUARK.ip_address_retry_max):
            attempt = None
            if ipam_log:
                attempt = ipam_log.make_entry("attempt_to_reallocate_ip")
            LOG.info("Attempt {0} of {1}".format(
                retry + 1, CONF.QUARK.ip_address_retry_max))
            try:
                with context.session.begin():
                    transaction = db_api.transaction_create(context)
                m = models.IPAddress
                update_kwargs = {
                    m.transaction_id: transaction.id,
                    m.address_type: kwargs.get("address_type", ip_types.FIXED),
                    m.deallocated: False,
                    m.deallocated_at: None,
                    m.used_by_tenant_id: context.tenant_id,
                    m.allocated_at: timeutils.utcnow(),
                }
                result = db_api.ip_address_reallocate(
                    elevated, update_kwargs, **ip_kwargs)
                if not result:
                    LOG.info("Couldn't update any reallocatable addresses "
                             "given the criteria")
                    if attempt:
                        attempt.failed()
                    break

                updated_address = db_api.ip_address_reallocate_find(
                    elevated, transaction.id)
                if not updated_address:
                    if attempt:
                        attempt.failed()
                    continue

                LOG.info("Address {0} is reallocated".format(
                    updated_address["address_readable"]))
                return [updated_address]
            except Exception:
                if attempt:
                    attempt.failed()
                LOG.exception("Error in reallocate ip...")
            finally:
                if attempt:
                    attempt.end()
        return []
Ejemplo n.º 48
0
    def attempt_to_reallocate_ip(self,
                                 context,
                                 net_id,
                                 port_id,
                                 reuse_after,
                                 version=None,
                                 ip_address=None,
                                 segment_id=None,
                                 subnets=None,
                                 **kwargs):
        version = version or [4, 6]
        elevated = context.elevated()

        if version == 6 and "mac_address" in kwargs and kwargs["mac_address"]:
            # Defers to the create case. The reason why is we'd have to look
            # up subnets here to correctly generate the v6. If we split them
            # up into reallocate and create, we'd be looking up the same
            # subnets twice, which is a waste of time.

            # TODO(mdietz): after reviewing this code, this block annoyingly
            #               doesn't trigger in the ANY case, since we end up
            #               using a list of [4, 6]. It works as expected most
            #               of the time, but we can anticipate that isolated
            #               networks will end up using sequential assignment.
            #               Probably want to rework this logic to compensate
            #               at some point. Considering they all come from the
            #               same MAC address pool, nothing bad will happen,
            #               just worth noticing and fixing.
            return []

        sub_ids = []
        if subnets:
            sub_ids = subnets
        else:
            if segment_id:
                subnets = db_api.subnet_find(elevated,
                                             network_id=net_id,
                                             segment_id=segment_id)
                sub_ids = [s["id"] for s in subnets]
                if not sub_ids:
                    raise exceptions.IpAddressGenerationFailure(net_id=net_id)

        ip_kwargs = {
            "network_id": net_id,
            "reuse_after": reuse_after,
            "deallocated": True,
            "scope": db_api.ONE,
            "ip_address": ip_address,
            "lock_mode": True,
            "version": version,
            "order_by": "address",
            "do_not_use": False
        }

        if sub_ids:
            ip_kwargs["subnet_id"] = sub_ids

        # We never want to take the chance of an infinite loop here. Instead,
        # we'll clean up multiple bad IPs if we find them (assuming something
        # is really wrong)
        for retry in xrange(cfg.CONF.QUARK.ip_address_retry_max):
            get_policy = models.IPPolicy.get_ip_policy_cidrs

            try:
                with context.session.begin():
                    # NOTE(mdietz): Before I removed the lazy=joined, this
                    #               raised with an unknown column "address"
                    #               error.
                    address = db_api.ip_address_find(elevated, **ip_kwargs)

                    if address:
                        # NOTE(mdietz): We should always be in the CIDR but we
                        #              also said that before :-/
                        subnet = address.get('subnet')
                        if subnet:
                            policy = get_policy(subnet)

                            cidr = netaddr.IPNetwork(address["subnet"]["cidr"])
                            addr = netaddr.IPAddress(int(address["address"]))
                            if address["subnet"]["ip_version"] == 4:
                                addr = addr.ipv4()
                            else:
                                addr = addr.ipv6()

                            if policy is not None and addr in policy:
                                context.session.delete(address)
                                continue

                            if addr in cidr:
                                updated_address = db_api.ip_address_update(
                                    elevated,
                                    address,
                                    deallocated=False,
                                    deallocated_at=None,
                                    used_by_tenant_id=context.tenant_id,
                                    allocated_at=timeutils.utcnow())
                                return [updated_address]
                            else:
                                # Make sure we never find it again
                                context.session.delete(address)
                    else:
                        break
            except Exception:
                LOG.exception("Error in reallocate ip...")
        return []
Ejemplo n.º 49
0
def update_subnet(context, id, subnet):
    """Update values of a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to update.
    : param subnet: 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_subnet %s for tenant %s" %
             (id, context.tenant_id))

    with context.session.begin():
        subnet_db = db_api.subnet_find(context, None, None, None, False, id=id,
                                       scope=db_api.ONE)
        if not subnet_db:
            raise exceptions.SubnetNotFound(id=id)

        s = subnet["subnet"]
        always_pop = ["_cidr", "cidr", "first_ip", "last_ip", "ip_version",
                      "segment_id", "network_id"]
        admin_only = ["do_not_use", "created_at", "tenant_id",
                      "next_auto_assign_ip", "enable_dhcp"]
        utils.filter_body(context, s, admin_only, always_pop)

        dns_ips = utils.pop_param(s, "dns_nameservers", [])
        host_routes = utils.pop_param(s, "host_routes", [])
        gateway_ip = utils.pop_param(s, "gateway_ip", None)
        allocation_pools = utils.pop_param(s, "allocation_pools", None)
        if not CONF.QUARK.allow_allocation_pool_update:
            if allocation_pools:
                raise exceptions.BadRequest(
                    resource="subnets",
                    msg="Allocation pools cannot be updated.")
            alloc_pools = allocation_pool.AllocationPools(
                subnet_db["cidr"],
                policies=models.IPPolicy.get_ip_policy_cidrs(subnet_db))
        else:
            alloc_pools = allocation_pool.AllocationPools(subnet_db["cidr"],
                                                          allocation_pools)

        quota.QUOTAS.limit_check(
            context,
            context.tenant_id,
            alloc_pools_per_subnet=len(alloc_pools))
        if gateway_ip:
            alloc_pools.validate_gateway_excluded(gateway_ip)
            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
                    break

            if default_route is None:
                route_model = db_api.route_find(
                    context, cidr=str(routes.DEFAULT_ROUTE), subnet_id=id,
                    scope=db_api.ONE)
                if route_model:
                    db_api.route_update(context, route_model,
                                        gateway=gateway_ip)
                else:
                    db_api.route_create(context,
                                        cidr=str(routes.DEFAULT_ROUTE),
                                        gateway=gateway_ip, subnet_id=id)

        if dns_ips:
            subnet_db["dns_nameservers"] = []
            quota.QUOTAS.limit_check(context, context.tenant_id,
                                     dns_nameservers_per_subnet=len(dns_ips))

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

        if host_routes:
            subnet_db["routes"] = []
            quota.QUOTAS.limit_check(context, context.tenant_id,
                                     routes_per_subnet=len(host_routes))

        for route in host_routes:
            subnet_db["routes"].append(db_api.route_create(
                context, cidr=route["destination"], gateway=route["nexthop"]))
        if CONF.QUARK.allow_allocation_pool_update:
            if isinstance(allocation_pools, list):
                cidrs = alloc_pools.get_policy_cidrs()
                ip_policies.ensure_default_policy(cidrs, [subnet_db])
                subnet_db["ip_policy"] = db_api.ip_policy_update(
                    context, subnet_db["ip_policy"], exclude=cidrs)
                # invalidate the cache
                db_api.subnet_update_set_alloc_pool_cache(context, subnet_db)
        subnet = db_api.subnet_update(context, subnet_db, **s)
    return v._make_subnet_dict(subnet)
Ejemplo n.º 50
0
    def attempt_to_reallocate_ip(self, context, net_id, port_id, reuse_after,
                                 version=None, ip_address=None,
                                 segment_id=None, subnets=None, **kwargs):
        version = version or [4, 6]
        elevated = context.elevated()

        if version == 6 and "mac_address" in kwargs and kwargs["mac_address"]:
            # Defers to the create case. The reason why is we'd have to look
            # up subnets here to correctly generate the v6. If we split them
            # up into reallocate and create, we'd be looking up the same
            # subnets twice, which is a waste of time.
            return []

        # We never want to take the chance of an infinite loop here. Instead,
        # we'll clean up multiple bad IPs if we find them (assuming something
        # is really wrong)

        sub_ids = []
        if subnets:
            sub_ids = subnets
        else:
            if segment_id:
                subnets = db_api.subnet_find(elevated,
                                             network_id=net_id,
                                             segment_id=segment_id)
                sub_ids = [s["id"] for s in subnets]
                if not sub_ids:
                    raise exceptions.IpAddressGenerationFailure(
                        net_id=net_id)

        ip_kwargs = {
            "network_id": net_id, "reuse_after": reuse_after,
            "deallocated": True, "scope": db_api.ONE,
            "ip_address": ip_address, "lock_mode": True,
            "version": version, "order_by": "address",
            "do_not_use": False}

        if sub_ids:
            ip_kwargs["subnet_id"] = sub_ids

        for retry in xrange(cfg.CONF.QUARK.ip_address_retry_max):
            get_policy = models.IPPolicy.get_ip_policy_cidrs

            try:
                with context.session.begin():
                    # NOTE(mdietz): Before I removed the lazy=joined, this
                    #               raised with an unknown column "address"
                    #               error.
                    address = db_api.ip_address_find(elevated, **ip_kwargs)

                    if address:
                        # NOTE(mdietz): We should always be in the CIDR but we
                        #              also said that before :-/
                        subnet = address.get('subnet')
                        if subnet:
                            policy = get_policy(subnet)

                            cidr = netaddr.IPNetwork(address["subnet"]["cidr"])
                            addr = netaddr.IPAddress(int(address["address"]))
                            if address["subnet"]["ip_version"] == 4:
                                addr = addr.ipv4()
                            else:
                                addr = addr.ipv6()

                            if policy is not None and addr in policy:
                                context.session.delete(address)
                                continue

                            if addr in cidr:
                                updated_address = db_api.ip_address_update(
                                    elevated, address, deallocated=False,
                                    deallocated_at=None,
                                    used_by_tenant_id=context.tenant_id,
                                    allocated_at=timeutils.utcnow())
                                return [updated_address]
                            else:
                                # Make sure we never find it again
                                context.session.delete(address)
                    else:
                        break
            except Exception:
                LOG.exception("Error in reallocate ip...")
        return []
Ejemplo n.º 51
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)
Ejemplo n.º 52
0
def update_subnet(context, id, subnet):
    """Update values of a subnet.

    : param context: neutron api request context
    : param id: UUID representing the subnet to update.
    : param subnet: 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_subnet %s for tenant %s" % (id, context.tenant_id))

    with context.session.begin():
        subnet_db = db_api.subnet_find(context,
                                       None,
                                       None,
                                       None,
                                       False,
                                       id=id,
                                       scope=db_api.ONE)
        if not subnet_db:
            raise exceptions.SubnetNotFound(id=id)

        s = subnet["subnet"]
        always_pop = [
            "_cidr", "cidr", "first_ip", "last_ip", "ip_version", "segment_id",
            "network_id"
        ]
        admin_only = [
            "do_not_use", "created_at", "tenant_id", "next_auto_assign_ip",
            "enable_dhcp"
        ]
        utils.filter_body(context, s, admin_only, always_pop)

        dns_ips = utils.pop_param(s, "dns_nameservers", [])
        host_routes = utils.pop_param(s, "host_routes", [])
        gateway_ip = utils.pop_param(s, "gateway_ip", None)
        allocation_pools = utils.pop_param(s, "allocation_pools", None)
        if not CONF.QUARK.allow_allocation_pool_update:
            if allocation_pools:
                raise exceptions.BadRequest(
                    resource="subnets",
                    msg="Allocation pools cannot be updated.")
            alloc_pools = allocation_pool.AllocationPools(
                subnet_db["cidr"],
                policies=models.IPPolicy.get_ip_policy_cidrs(subnet_db))
        else:
            alloc_pools = allocation_pool.AllocationPools(
                subnet_db["cidr"], allocation_pools)

        quota.QUOTAS.limit_check(context,
                                 context.tenant_id,
                                 alloc_pools_per_subnet=len(alloc_pools))
        if gateway_ip:
            alloc_pools.validate_gateway_excluded(gateway_ip)
            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
                    break

            if default_route is None:
                route_model = db_api.route_find(context,
                                                cidr=str(routes.DEFAULT_ROUTE),
                                                subnet_id=id,
                                                scope=db_api.ONE)
                if route_model:
                    db_api.route_update(context,
                                        route_model,
                                        gateway=gateway_ip)
                else:
                    db_api.route_create(context,
                                        cidr=str(routes.DEFAULT_ROUTE),
                                        gateway=gateway_ip,
                                        subnet_id=id)

        if dns_ips:
            subnet_db["dns_nameservers"] = []
            quota.QUOTAS.limit_check(context,
                                     context.tenant_id,
                                     dns_nameservers_per_subnet=len(dns_ips))

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

        if host_routes:
            subnet_db["routes"] = []
            quota.QUOTAS.limit_check(context,
                                     context.tenant_id,
                                     routes_per_subnet=len(host_routes))

        for route in host_routes:
            subnet_db["routes"].append(
                db_api.route_create(context,
                                    cidr=route["destination"],
                                    gateway=route["nexthop"]))
        if CONF.QUARK.allow_allocation_pool_update:
            if isinstance(allocation_pools, list):
                cidrs = alloc_pools.get_policy_cidrs()
                ip_policies.ensure_default_policy(cidrs, [subnet_db])
                subnet_db["ip_policy"] = db_api.ip_policy_update(
                    context, subnet_db["ip_policy"], exclude=cidrs)
                # invalidate the cache
                db_api.subnet_update_set_alloc_pool_cache(context, subnet_db)
        subnet = db_api.subnet_update(context, subnet_db, **s)
    return v._make_subnet_dict(subnet)