Re-implemented IP policies with offset and length

* Implemented CRUD ip_policies plugin methods
* Implemented plugin ip_policy unit tests
* Added IP Policy logic to ipam.allocate_ip_address
* Implemented ip_policy ipam unit tests
* Implemented ip_policies extension
* Added ip_policies db models
* Implemented db_api ip_policy methods
* Implemented _make_ip_policy_dict view
* Fixed existing tests

An IP Policy is defined on a subnet or network definining what IPs to
exclude from allocation. From a user perspective an IP Policy looks
like the following:

{
  "id": <id>,
  "tenant_id": <tenant_id>,
  "name": "foobar",
  "subnet_ids": [] (list of uuids),
  "network_ids": [] (list of uuids),
  "exclude": list of dictionaries (e.g. [{"offset": -1, "length": 3}])
}

"exclude" is always required. One of "subnet_ids" or "network_ids"
is required. Only one policy is allowed per network.

A default policy is enabled on all subnets if no ip policies are
specified on that subnet or its network. This default policy is
established via JSON configuration as "default_ip_policy". The
default for "default_ip_policy" is no policy.
This commit is contained in:
Amir Sadoughi
2013-07-24 20:57:52 -05:00
parent 7f4c1c7cdc
commit c6ca88568d
12 changed files with 404 additions and 147 deletions

View File

@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import netaddr
from neutron.common import exceptions
from neutron.openstack.common import log as logging
from oslo.config import cfg
@@ -23,10 +21,8 @@ from quark.db import api as db_api
from quark import exceptions as quark_exceptions
from quark import plugin_views as v
CONF = cfg.CONF
LOG = logging.getLogger("neutron.quark")
DEFAULT_SG_UUID = "00000000-0000-0000-0000-000000000000"
def create_ip_policy(context, ip_policy):
@@ -38,29 +34,35 @@ def create_ip_policy(context, ip_policy):
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")
network_ids = ipp.get("network_ids")
subnet_ids = ipp.get("subnet_ids")
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:
if not subnet_ids and not network_ids:
raise exceptions.BadRequest(
resource="ip_policy",
msg="network_id or subnet_id unspecified")
msg="network_ids or subnet_ids not specified")
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)
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)
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)
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"])
@@ -78,9 +80,51 @@ def get_ip_policies(context, **filters):
return [v._make_ip_policy_dict(ipp) for ipp in ipps]
def update_ip_policy(context, id, ip_policy):
LOG.info("update_ip_policy for tenant %s" % context.tenant_id)
ipp = ip_policy["ip_policy"]
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)
def delete_ip_policy(context, id):
LOG.info("delete_ip_policy %s for tenant %s" % (id, context.tenant_id))
ipp = db_api.ip_policy_find(context, id=id, scope=db_api.ONE)
if not ipp:
raise quark_exceptions.IPPolicyNotFound(id=id)
if ipp["networks"] or ipp["subnets"]:
raise quark_exceptions.IPPolicyInUse(id=id)
db_api.ip_policy_delete(context, ipp)

View File

@@ -94,7 +94,7 @@ def create_subnet(context, subnet):
gateway_ip = utils.pop_param(sub_attrs, "gateway_ip", str(cidr[1]))
dns_ips = utils.pop_param(sub_attrs, "dns_nameservers", [])
host_routes = utils.pop_param(sub_attrs, "host_routes", [])
allocation_pools = utils.pop_param(sub_attrs, "allocation_pools", [])
allocation_pools = utils.pop_param(sub_attrs, "allocation_pools", None)
sub_attrs["network"] = net
new_subnet = db_api.subnet_create(context, **sub_attrs)
@@ -116,13 +116,20 @@ def create_subnet(context, subnet):
new_subnet["dns_nameservers"].append(db_api.dns_create(
context, ip=netaddr.IPAddress(dns_ip)))
if allocation_pools:
exclude = netaddr.IPSet([cidr])
if isinstance(allocation_pools, list):
ranges = []
cidrset = netaddr.IPSet([netaddr.IPNetwork(new_subnet["cidr"])])
for p in allocation_pools:
x = netaddr.IPSet(netaddr.IPRange(p["start"], p["end"]))
exclude = exclude - x
cidrset -= netaddr.IPSet(netaddr.IPRange(p["start"], p["end"]))
non_allocation_pools = v._pools_from_cidr(cidrset)
for p in non_allocation_pools:
r = netaddr.IPRange(p["start"], p["end"])
ranges.append(dict(
length=len(r),
offset=int(r[0]) - int(cidr[0])))
new_subnet["ip_policy"] = db_api.ip_policy_create(context,
exclude=exclude)
exclude=ranges)
subnet_dict = v._make_subnet_dict(new_subnet,
default_route=routes.DEFAULT_ROUTE)
subnet_dict["gateway_ip"] = gateway_ip