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:
@@ -42,6 +42,11 @@ class IPPoliciesController(wsgi.Controller):
|
|||||||
return {RESOURCE_NAME:
|
return {RESOURCE_NAME:
|
||||||
self._plugin.create_ip_policy(request.context, body)}
|
self._plugin.create_ip_policy(request.context, body)}
|
||||||
|
|
||||||
|
def update(self, request, id, body=None):
|
||||||
|
body = self._deserialize(request.body, request.get_content_type())
|
||||||
|
return {RESOURCE_NAME:
|
||||||
|
self._plugin.update_ip_policy(request.context, id, body)}
|
||||||
|
|
||||||
def index(self, request):
|
def index(self, request):
|
||||||
context = request.context
|
context = request.context
|
||||||
return {RESOURCE_COLLECTION:
|
return {RESOURCE_COLLECTION:
|
||||||
|
|||||||
@@ -489,13 +489,14 @@ def security_group_rule_delete(context, rule):
|
|||||||
|
|
||||||
def ip_policy_create(context, **ip_policy_dict):
|
def ip_policy_create(context, **ip_policy_dict):
|
||||||
new_policy = models.IPPolicy()
|
new_policy = models.IPPolicy()
|
||||||
exclude_set = ip_policy_dict.pop("exclude")
|
ranges = ip_policy_dict.pop("exclude")
|
||||||
for ip_cidr in exclude_set.iter_cidrs():
|
for arange in ranges:
|
||||||
new_policy["exclude"].append(models.IPPolicyRule(
|
new_policy["exclude"].append(models.IPPolicyRange(
|
||||||
address=int(ip_cidr.ip),
|
offset=arange["offset"],
|
||||||
prefix=ip_cidr.prefixlen))
|
length=arange["length"]))
|
||||||
|
|
||||||
new_policy.update(ip_policy_dict)
|
new_policy.update(ip_policy_dict)
|
||||||
|
new_policy["tenant_id"] = context.tenant_id
|
||||||
context.session.add(new_policy)
|
context.session.add(new_policy)
|
||||||
return new_policy
|
return new_policy
|
||||||
|
|
||||||
@@ -507,5 +508,19 @@ def ip_policy_find(context, **filters):
|
|||||||
return query.filter(*model_filters)
|
return query.filter(*model_filters)
|
||||||
|
|
||||||
|
|
||||||
|
def ip_policy_update(context, ip_policy, **ip_policy_dict):
|
||||||
|
ranges = ip_policy_dict.pop("exclude", [])
|
||||||
|
if ranges:
|
||||||
|
ip_policy["exclude"] = []
|
||||||
|
for arange in ranges:
|
||||||
|
ip_policy["exclude"].append(models.IPPolicyRange(
|
||||||
|
offset=arange["offset"],
|
||||||
|
length=arange["length"]))
|
||||||
|
|
||||||
|
ip_policy.update(ip_policy_dict)
|
||||||
|
context.session.add(ip_policy)
|
||||||
|
return ip_policy
|
||||||
|
|
||||||
|
|
||||||
def ip_policy_delete(context, ip_policy):
|
def ip_policy_delete(context, ip_policy):
|
||||||
context.session.delete(ip_policy)
|
context.session.delete(ip_policy)
|
||||||
|
|||||||
@@ -27,11 +27,22 @@ from neutron.db import models_v2 as models
|
|||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
from neutron.openstack.common import timeutils
|
from neutron.openstack.common import timeutils
|
||||||
|
|
||||||
|
from oslo.config import cfg
|
||||||
|
|
||||||
from quark.db import custom_types
|
from quark.db import custom_types
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
HasId = models.HasId
|
HasId = models.HasId
|
||||||
|
|
||||||
LOG = logging.getLogger("neutron.quark.db.models")
|
LOG = logging.getLogger("neutron.quark.db.models")
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
quark_opts = [
|
||||||
|
cfg.StrOpt('default_ip_policy', default='{}',
|
||||||
|
help=_("Default IP allocation policy"))
|
||||||
|
]
|
||||||
|
CONF.register_opts(quark_opts, "QUARK")
|
||||||
|
|
||||||
|
|
||||||
def _default_list_getset(collection_class, proxy):
|
def _default_list_getset(collection_class, proxy):
|
||||||
@@ -225,7 +236,8 @@ class Subnet(BASEV2, models.HasId, models.HasTenant, IsHazTags):
|
|||||||
primaryjoin="DNSNameserver.subnet_id==Subnet.id",
|
primaryjoin="DNSNameserver.subnet_id==Subnet.id",
|
||||||
backref='subnet',
|
backref='subnet',
|
||||||
cascade='delete')
|
cascade='delete')
|
||||||
ip_policy = orm.relationship("IPPolicy", uselist=False, backref="subnet")
|
ip_policy_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey("quark_ip_policy.id"))
|
||||||
|
|
||||||
|
|
||||||
port_ip_association_table = sa.Table(
|
port_ip_association_table = sa.Table(
|
||||||
@@ -331,25 +343,68 @@ class MacAddressRange(BASEV2, models.HasId):
|
|||||||
backref="mac_address_range")
|
backref="mac_address_range")
|
||||||
|
|
||||||
|
|
||||||
class IPPolicy(BASEV2, models.HasId):
|
class IPPolicy(BASEV2, models.HasId, models.HasTenant):
|
||||||
__tablename__ = "quark_ip_policy"
|
__tablename__ = "quark_ip_policy"
|
||||||
subnet_id = sa.Column(sa.String(36), sa.ForeignKey("quark_subnets.id",
|
networks = orm.relationship(
|
||||||
ondelete="CASCADE"))
|
"Network",
|
||||||
network_id = sa.Column(sa.String(36), sa.ForeignKey("quark_networks.id",
|
primaryjoin="IPPolicy.id==Network.ip_policy_id",
|
||||||
ondelete="CASCADE"))
|
backref="ip_policy")
|
||||||
|
subnets = orm.relationship(
|
||||||
|
"Subnet",
|
||||||
|
primaryjoin="IPPolicy.id==Subnet.ip_policy_id",
|
||||||
|
backref="ip_policy")
|
||||||
|
exclude = orm.relationship(
|
||||||
|
"IPPolicyRange",
|
||||||
|
primaryjoin="IPPolicy.id==IPPolicyRange.ip_policy_id",
|
||||||
|
backref="ip_policy")
|
||||||
|
name = sa.Column(sa.String(255), nullable=True)
|
||||||
|
|
||||||
join = "IPPolicy.id==IPPolicyRule.ip_policy_id"
|
class JSONIPPolicy(object):
|
||||||
exclude = orm.relationship("IPPolicyRule",
|
def __init__(self, policy=None):
|
||||||
primaryjoin=join,
|
self.policy = {}
|
||||||
backref="ip_policy")
|
if not policy:
|
||||||
|
self._compile_policy(CONF.QUARK.default_ip_policy)
|
||||||
|
else:
|
||||||
|
self._compile_policy(policy)
|
||||||
|
|
||||||
|
def _compile_policy(self, policy):
|
||||||
|
self.policy = json.loads(policy)
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(self.policy, name)
|
||||||
|
|
||||||
|
DEFAULT_POLICY = JSONIPPolicy()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_ip_policy_rule_set(subnet):
|
||||||
|
ip_policy = subnet["ip_policy"] or \
|
||||||
|
subnet["network"]["ip_policy"] or \
|
||||||
|
dict()
|
||||||
|
ip_policy_ranges = ip_policy.get("exclude", []) + \
|
||||||
|
IPPolicy.DEFAULT_POLICY.get("exclude", [])
|
||||||
|
|
||||||
|
ip_policy_rules = netaddr.IPSet()
|
||||||
|
subnet_net = netaddr.IPNetwork(subnet["cidr"])
|
||||||
|
for arange in ip_policy_ranges:
|
||||||
|
end_index = arange["offset"] + arange["length"]
|
||||||
|
end_index_wraps_around = (arange["offset"] < 0 and end_index >= 0)
|
||||||
|
if end_index_wraps_around:
|
||||||
|
second_index = min(end_index, len(subnet_net))
|
||||||
|
end_index = None
|
||||||
|
ip_policy_rules |= netaddr.IPSet(subnet_net[:second_index])
|
||||||
|
ip_policy_rules |= netaddr.IPSet(
|
||||||
|
subnet_net[arange["offset"]:end_index])
|
||||||
|
|
||||||
|
return ip_policy_rules
|
||||||
|
|
||||||
|
|
||||||
class IPPolicyRule(BASEV2, models.HasId):
|
class IPPolicyRange(BASEV2, models.HasId):
|
||||||
__tablename__ = "quark_ip_policy_rules"
|
__tablename__ = "quark_ip_policy_rules"
|
||||||
ip_policy_id = sa.Column(sa.String(36), sa.ForeignKey(
|
ip_policy_id = sa.Column(sa.String(36), sa.ForeignKey(
|
||||||
"quark_ip_policy.id", ondelete="CASCADE"))
|
"quark_ip_policy.id", ondelete="CASCADE"))
|
||||||
address = sa.Column(custom_types.INET())
|
|
||||||
prefix = sa.Column(sa.Integer())
|
offset = sa.Column(sa.Integer())
|
||||||
|
length = sa.Column(sa.Integer())
|
||||||
|
|
||||||
|
|
||||||
class Network(BASEV2, models.HasTenant, models.HasId):
|
class Network(BASEV2, models.HasTenant, models.HasId):
|
||||||
@@ -357,4 +412,5 @@ class Network(BASEV2, models.HasTenant, models.HasId):
|
|||||||
name = sa.Column(sa.String(255))
|
name = sa.Column(sa.String(255))
|
||||||
ports = orm.relationship(Port, backref='network')
|
ports = orm.relationship(Port, backref='network')
|
||||||
subnets = orm.relationship(Subnet, backref='network')
|
subnets = orm.relationship(Subnet, backref='network')
|
||||||
ip_policy = orm.relationship(IPPolicy, uselist=False, backref="network")
|
ip_policy_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey("quark_ip_policy.id"))
|
||||||
|
|||||||
@@ -65,5 +65,9 @@ class IPPolicyAlreadyExists(exceptions.NeutronException):
|
|||||||
message = _("IP Policy %(id)s already exists for %(n_id)s")
|
message = _("IP Policy %(id)s already exists for %(n_id)s")
|
||||||
|
|
||||||
|
|
||||||
|
class IPPolicyInUse(exceptions.InUse):
|
||||||
|
message = _("IP allocation policy %(id) in use.")
|
||||||
|
|
||||||
|
|
||||||
class DriverLimitReached(exceptions.InvalidInput):
|
class DriverLimitReached(exceptions.InvalidInput):
|
||||||
message = _("Driver has reached limit on resource '%(limit)s'")
|
message = _("Driver has reached limit on resource '%(limit)s'")
|
||||||
|
|||||||
@@ -24,25 +24,13 @@ from neutron.openstack.common import log as logging
|
|||||||
from neutron.openstack.common import timeutils
|
from neutron.openstack.common import timeutils
|
||||||
|
|
||||||
from quark.db import api as db_api
|
from quark.db import api as db_api
|
||||||
|
from quark.db import models
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger("neutron")
|
LOG = logging.getLogger("neutron")
|
||||||
|
|
||||||
|
|
||||||
class QuarkIpam(object):
|
class QuarkIpam(object):
|
||||||
@staticmethod
|
|
||||||
def get_ip_policy_rule_set(subnet):
|
|
||||||
ip_policy = subnet["ip_policy"] or \
|
|
||||||
subnet["network"]["ip_policy"] or \
|
|
||||||
dict()
|
|
||||||
ip_policy_rules = ip_policy.get("exclude", [])
|
|
||||||
ip_policy_rules = netaddr.IPSet(
|
|
||||||
[netaddr.IPNetwork((int(ippr["address"]), ippr["prefix"]))
|
|
||||||
for ippr in ip_policy_rules])
|
|
||||||
subnet_set = netaddr.IPSet([netaddr.IPNetwork(subnet["cidr"])])
|
|
||||||
ip_policy_rules = subnet_set & ip_policy_rules
|
|
||||||
return ip_policy_rules
|
|
||||||
|
|
||||||
def _choose_available_subnet(self, context, net_id, version=None,
|
def _choose_available_subnet(self, context, net_id, version=None,
|
||||||
ip_address=None):
|
ip_address=None):
|
||||||
filters = {}
|
filters = {}
|
||||||
@@ -58,7 +46,8 @@ class QuarkIpam(object):
|
|||||||
|
|
||||||
ip_policy_rules = None
|
ip_policy_rules = None
|
||||||
if not ip_address:
|
if not ip_address:
|
||||||
ip_policy_rules = self.get_ip_policy_rule_set(subnet)
|
ip_policy_rules = models.IPPolicy.get_ip_policy_rule_set(
|
||||||
|
subnet)
|
||||||
policy_size = ip_policy_rules.size if ip_policy_rules else 0
|
policy_size = ip_policy_rules.size if ip_policy_rules else 0
|
||||||
if ipnet.size > (ips_in_subnet + policy_size):
|
if ipnet.size > (ips_in_subnet + policy_size):
|
||||||
return subnet
|
return subnet
|
||||||
@@ -118,7 +107,7 @@ class QuarkIpam(object):
|
|||||||
|
|
||||||
subnet = self._choose_available_subnet(
|
subnet = self._choose_available_subnet(
|
||||||
elevated, net_id, ip_address=ip_address, version=version)
|
elevated, net_id, ip_address=ip_address, version=version)
|
||||||
ip_policy_rules = self.get_ip_policy_rule_set(subnet)
|
ip_policy_rules = models.IPPolicy.get_ip_policy_rule_set(subnet)
|
||||||
|
|
||||||
# Creating this IP for the first time
|
# Creating this IP for the first time
|
||||||
next_ip = None
|
next_ip = None
|
||||||
|
|||||||
@@ -149,6 +149,9 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
def get_ip_policies(self, context, **filters):
|
def get_ip_policies(self, context, **filters):
|
||||||
return ip_policies.get_ip_policies(context, **filters)
|
return ip_policies.get_ip_policies(context, **filters)
|
||||||
|
|
||||||
|
def update_ip_policy(self, context, id, ip_policy):
|
||||||
|
return ip_policies.update_ip_policy(context, id, ip_policy)
|
||||||
|
|
||||||
def delete_ip_policy(self, context, id):
|
def delete_ip_policy(self, context, id):
|
||||||
return ip_policies.delete_ip_policy(context, id)
|
return ip_policies.delete_ip_policy(context, id)
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,6 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import netaddr
|
|
||||||
|
|
||||||
from neutron.common import exceptions
|
from neutron.common import exceptions
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
from oslo.config import cfg
|
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 exceptions as quark_exceptions
|
||||||
from quark import plugin_views as v
|
from quark import plugin_views as v
|
||||||
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
LOG = logging.getLogger("neutron.quark")
|
LOG = logging.getLogger("neutron.quark")
|
||||||
DEFAULT_SG_UUID = "00000000-0000-0000-0000-000000000000"
|
|
||||||
|
|
||||||
|
|
||||||
def create_ip_policy(context, ip_policy):
|
def create_ip_policy(context, ip_policy):
|
||||||
@@ -38,29 +34,35 @@ def create_ip_policy(context, ip_policy):
|
|||||||
raise exceptions.BadRequest(resource="ip_policy",
|
raise exceptions.BadRequest(resource="ip_policy",
|
||||||
msg="Empty ip_policy.exclude regions")
|
msg="Empty ip_policy.exclude regions")
|
||||||
|
|
||||||
ipp["exclude"] = netaddr.IPSet(ipp["exclude"])
|
network_ids = ipp.get("network_ids")
|
||||||
network_id = ipp.get("network_id")
|
subnet_ids = ipp.get("subnet_ids")
|
||||||
subnet_id = ipp.get("subnet_id")
|
|
||||||
|
|
||||||
model = None
|
if not subnet_ids and not network_ids:
|
||||||
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(
|
raise exceptions.BadRequest(
|
||||||
resource="ip_policy",
|
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"])
|
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]
|
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):
|
def delete_ip_policy(context, id):
|
||||||
LOG.info("delete_ip_policy %s for tenant %s" % (id, context.tenant_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)
|
ipp = db_api.ip_policy_find(context, id=id, scope=db_api.ONE)
|
||||||
if not ipp:
|
if not ipp:
|
||||||
raise quark_exceptions.IPPolicyNotFound(id=id)
|
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)
|
db_api.ip_policy_delete(context, ipp)
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ def create_subnet(context, subnet):
|
|||||||
gateway_ip = utils.pop_param(sub_attrs, "gateway_ip", str(cidr[1]))
|
gateway_ip = utils.pop_param(sub_attrs, "gateway_ip", str(cidr[1]))
|
||||||
dns_ips = utils.pop_param(sub_attrs, "dns_nameservers", [])
|
dns_ips = utils.pop_param(sub_attrs, "dns_nameservers", [])
|
||||||
host_routes = utils.pop_param(sub_attrs, "host_routes", [])
|
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
|
sub_attrs["network"] = net
|
||||||
|
|
||||||
new_subnet = db_api.subnet_create(context, **sub_attrs)
|
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(
|
new_subnet["dns_nameservers"].append(db_api.dns_create(
|
||||||
context, ip=netaddr.IPAddress(dns_ip)))
|
context, ip=netaddr.IPAddress(dns_ip)))
|
||||||
|
|
||||||
if allocation_pools:
|
if isinstance(allocation_pools, list):
|
||||||
exclude = netaddr.IPSet([cidr])
|
ranges = []
|
||||||
|
cidrset = netaddr.IPSet([netaddr.IPNetwork(new_subnet["cidr"])])
|
||||||
for p in allocation_pools:
|
for p in allocation_pools:
|
||||||
x = netaddr.IPSet(netaddr.IPRange(p["start"], p["end"]))
|
cidrset -= netaddr.IPSet(netaddr.IPRange(p["start"], p["end"]))
|
||||||
exclude = exclude - x
|
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,
|
new_subnet["ip_policy"] = db_api.ip_policy_create(context,
|
||||||
exclude=exclude)
|
exclude=ranges)
|
||||||
|
|
||||||
subnet_dict = v._make_subnet_dict(new_subnet,
|
subnet_dict = v._make_subnet_dict(new_subnet,
|
||||||
default_route=routes.DEFAULT_ROUTE)
|
default_route=routes.DEFAULT_ROUTE)
|
||||||
subnet_dict["gateway_ip"] = gateway_ip
|
subnet_dict["gateway_ip"] = gateway_ip
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import netaddr
|
|||||||
from neutron.extensions import securitygroup as sg_ext
|
from neutron.extensions import securitygroup as sg_ext
|
||||||
|
|
||||||
from quark.db import api as db_api
|
from quark.db import api as db_api
|
||||||
from quark.ipam import QuarkIpam
|
from quark.db import models
|
||||||
from quark import network_strategy
|
from quark import network_strategy
|
||||||
from quark import utils
|
from quark import utils
|
||||||
|
|
||||||
@@ -44,35 +44,38 @@ def _make_network_dict(network, fields=None):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def _pools_from_cidr(cidr):
|
||||||
|
cidrs = cidr.iter_cidrs()
|
||||||
|
if len(cidrs) == 0:
|
||||||
|
return []
|
||||||
|
if len(cidrs) == 1:
|
||||||
|
return [dict(start=str(cidrs[0][0]),
|
||||||
|
end=str(cidrs[0][-1]))]
|
||||||
|
|
||||||
|
pool_start = cidrs[0][0]
|
||||||
|
prev_cidr_end = cidrs[0][-1]
|
||||||
|
pools = []
|
||||||
|
for cidr in cidrs[1:]:
|
||||||
|
cidr_start = cidr[0]
|
||||||
|
if prev_cidr_end + 1 != cidr_start:
|
||||||
|
pools.append(dict(start=str(pool_start),
|
||||||
|
end=str(prev_cidr_end)))
|
||||||
|
pool_start = cidr_start
|
||||||
|
prev_cidr_end = cidr[-1]
|
||||||
|
pools.append(dict(start=str(pool_start), end=str(prev_cidr_end)))
|
||||||
|
return pools
|
||||||
|
|
||||||
|
|
||||||
def _make_subnet_dict(subnet, default_route=None, fields=None):
|
def _make_subnet_dict(subnet, default_route=None, fields=None):
|
||||||
dns_nameservers = [str(netaddr.IPAddress(dns["ip"]))
|
dns_nameservers = [str(netaddr.IPAddress(dns["ip"]))
|
||||||
for dns in subnet.get("dns_nameservers")]
|
for dns in subnet.get("dns_nameservers")]
|
||||||
net_id = STRATEGY.get_parent_network(subnet["network_id"])
|
net_id = STRATEGY.get_parent_network(subnet["network_id"])
|
||||||
|
|
||||||
def _allocation_pools(subnet):
|
def _allocation_pools(subnet):
|
||||||
ip_policy_rules = QuarkIpam.get_ip_policy_rule_set(subnet)
|
ip_policy_rules = models.IPPolicy.get_ip_policy_rule_set(subnet)
|
||||||
cidr = netaddr.IPSet([netaddr.IPNetwork(subnet["cidr"])])
|
cidr = netaddr.IPSet([netaddr.IPNetwork(subnet["cidr"])])
|
||||||
allocatable = cidr - ip_policy_rules
|
allocatable = cidr - ip_policy_rules
|
||||||
|
return _pools_from_cidr(allocatable)
|
||||||
cidrs = allocatable.iter_cidrs()
|
|
||||||
if len(cidrs) == 0:
|
|
||||||
return []
|
|
||||||
if len(cidrs) == 1:
|
|
||||||
return [dict(start=str(cidrs[0][0]),
|
|
||||||
end=str(cidrs[0][-1]))]
|
|
||||||
|
|
||||||
pool_start = cidrs[0][0]
|
|
||||||
prev_cidr_end = cidrs[0][-1]
|
|
||||||
pools = []
|
|
||||||
for cidr in cidrs[1:]:
|
|
||||||
cidr_start = cidr[0]
|
|
||||||
if prev_cidr_end + 1 != cidr_start:
|
|
||||||
pools.append(dict(start=str(pool_start),
|
|
||||||
end=str(prev_cidr_end)))
|
|
||||||
pool_start = cidr_start
|
|
||||||
prev_cidr_end = cidr[-1]
|
|
||||||
pools.append(dict(start=str(pool_start), end=str(prev_cidr_end)))
|
|
||||||
return pools
|
|
||||||
|
|
||||||
res = {"id": subnet.get("id"),
|
res = {"id": subnet.get("id"),
|
||||||
"name": subnet.get("name"),
|
"name": subnet.get("name"),
|
||||||
@@ -200,11 +203,13 @@ def _make_ip_dict(address):
|
|||||||
|
|
||||||
|
|
||||||
def _make_ip_policy_dict(ipp):
|
def _make_ip_policy_dict(ipp):
|
||||||
excludes = [str(netaddr.IPNetwork((int(ippr["address"]), ippr["prefix"])))
|
excludes = [dict(offset=range["offset"], length=range["length"])
|
||||||
for ippr in ipp["exclude"]]
|
for range in ipp["exclude"]]
|
||||||
return {"id": ipp["id"],
|
return {"id": ipp["id"],
|
||||||
"subnet_id": ipp["subnet_id"],
|
"tenant_id": ipp["tenant_id"],
|
||||||
"network_id": ipp["network_id"],
|
"name": ipp["name"],
|
||||||
|
"subnet_ids": [s["id"] for s in ipp["subnets"]],
|
||||||
|
"network_ids": [n["id"] for n in ipp["networks"]],
|
||||||
"exclude": excludes}
|
"exclude": excludes}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -37,36 +37,42 @@ class TestQuarkGetIpPolicies(test_quark_plugin.TestQuarkPlugin):
|
|||||||
self.plugin.get_ip_policy(self.context, 1)
|
self.plugin.get_ip_policy(self.context, 1)
|
||||||
|
|
||||||
def test_get_ip_policy(self):
|
def test_get_ip_policy(self):
|
||||||
address = int(netaddr.IPAddress("1.1.1.1"))
|
|
||||||
ip_policy = dict(
|
ip_policy = dict(
|
||||||
id=1,
|
id=1,
|
||||||
subnet_id=1,
|
tenant_id=1,
|
||||||
network_id=2,
|
name="foo",
|
||||||
exclude=[dict(address=address, prefix=24)])
|
subnets=[dict(id=1)],
|
||||||
|
networks=[dict(id=2)],
|
||||||
|
exclude=[dict(offset=1, length=256)])
|
||||||
with self._stubs(ip_policy):
|
with self._stubs(ip_policy):
|
||||||
resp = self.plugin.get_ip_policy(self.context, 1)
|
resp = self.plugin.get_ip_policy(self.context, 1)
|
||||||
self.assertEqual(len(resp.keys()), 4)
|
self.assertEqual(len(resp.keys()), 6)
|
||||||
self.assertEqual(resp["id"], 1)
|
self.assertEqual(resp["id"], 1)
|
||||||
self.assertEqual(resp["subnet_id"], 1)
|
self.assertEqual(resp["name"], "foo")
|
||||||
self.assertEqual(resp["network_id"], 2)
|
self.assertEqual(resp["subnet_ids"], [1])
|
||||||
self.assertEqual(resp["exclude"], ["1.1.1.1/24"])
|
self.assertEqual(resp["network_ids"], [2])
|
||||||
|
self.assertEqual(resp["exclude"], ip_policy["exclude"])
|
||||||
|
self.assertEqual(resp["tenant_id"], 1)
|
||||||
|
|
||||||
def test_get_ip_policies(self):
|
def test_get_ip_policies(self):
|
||||||
address = int(netaddr.IPAddress("1.1.1.1"))
|
|
||||||
ip_policy = dict(
|
ip_policy = dict(
|
||||||
id=1,
|
id=1,
|
||||||
subnet_id=1,
|
tenant_id=1,
|
||||||
network_id=2,
|
name="foo",
|
||||||
exclude=[dict(address=address, prefix=24)])
|
subnets=[dict(id=1)],
|
||||||
|
networks=[dict(id=2)],
|
||||||
|
exclude=[dict(offset=1, length=256)])
|
||||||
with self._stubs([ip_policy]):
|
with self._stubs([ip_policy]):
|
||||||
resp = self.plugin.get_ip_policies(self.context)
|
resp = self.plugin.get_ip_policies(self.context)
|
||||||
self.assertEqual(len(resp), 1)
|
self.assertEqual(len(resp), 1)
|
||||||
resp = resp[0]
|
resp = resp[0]
|
||||||
self.assertEqual(len(resp.keys()), 4)
|
self.assertEqual(len(resp.keys()), 6)
|
||||||
self.assertEqual(resp["id"], 1)
|
self.assertEqual(resp["id"], 1)
|
||||||
self.assertEqual(resp["subnet_id"], 1)
|
self.assertEqual(resp["subnet_ids"], [1])
|
||||||
self.assertEqual(resp["network_id"], 2)
|
self.assertEqual(resp["network_ids"], [2])
|
||||||
self.assertEqual(resp["exclude"], ["1.1.1.1/24"])
|
self.assertEqual(resp["exclude"], ip_policy["exclude"])
|
||||||
|
self.assertEqual(resp["name"], "foo")
|
||||||
|
self.assertEqual(resp["tenant_id"], 1)
|
||||||
|
|
||||||
|
|
||||||
class TestQuarkCreateIpPolicies(test_quark_plugin.TestQuarkPlugin):
|
class TestQuarkCreateIpPolicies(test_quark_plugin.TestQuarkPlugin):
|
||||||
@@ -78,8 +84,8 @@ class TestQuarkCreateIpPolicies(test_quark_plugin.TestQuarkPlugin):
|
|||||||
mock.patch("%s.network_find" % db_mod),
|
mock.patch("%s.network_find" % db_mod),
|
||||||
mock.patch("%s.ip_policy_create" % db_mod),
|
mock.patch("%s.ip_policy_create" % db_mod),
|
||||||
) as (subnet_find, net_find, ip_policy_create):
|
) as (subnet_find, net_find, ip_policy_create):
|
||||||
subnet_find.return_value = subnet
|
subnet_find.return_value = [subnet] if subnet else None
|
||||||
net_find.return_value = net
|
net_find.return_value = [net] if net else None
|
||||||
ip_policy_create.return_value = ip_policy
|
ip_policy_create.return_value = ip_policy
|
||||||
yield ip_policy_create
|
yield ip_policy_create
|
||||||
|
|
||||||
@@ -99,28 +105,28 @@ class TestQuarkCreateIpPolicies(test_quark_plugin.TestQuarkPlugin):
|
|||||||
with self._stubs(None):
|
with self._stubs(None):
|
||||||
with self.assertRaises(exceptions.SubnetNotFound):
|
with self.assertRaises(exceptions.SubnetNotFound):
|
||||||
self.plugin.create_ip_policy(self.context, dict(
|
self.plugin.create_ip_policy(self.context, dict(
|
||||||
ip_policy=dict(subnet_id=1,
|
ip_policy=dict(subnet_ids=[1],
|
||||||
exclude=["1.1.1.1/24"])))
|
exclude=["1.1.1.1/24"])))
|
||||||
|
|
||||||
def test_create_ip_policy_invalid_network(self):
|
def test_create_ip_policy_invalid_network(self):
|
||||||
with self._stubs(None):
|
with self._stubs(None):
|
||||||
with self.assertRaises(exceptions.NetworkNotFound):
|
with self.assertRaises(exceptions.NetworkNotFound):
|
||||||
self.plugin.create_ip_policy(self.context, dict(
|
self.plugin.create_ip_policy(self.context, dict(
|
||||||
ip_policy=dict(network_id=1,
|
ip_policy=dict(network_ids=[1],
|
||||||
exclude=["1.1.1.1/24"])))
|
exclude=["1.1.1.1/24"])))
|
||||||
|
|
||||||
def test_create_ip_policy_network_ip_policy_already_exists(self):
|
def test_create_ip_policy_network_ip_policy_already_exists(self):
|
||||||
with self._stubs(None, net=dict(id=1, ip_policy=dict(id=2))):
|
with self._stubs(None, net=dict(id=1, ip_policy=dict(id=2))):
|
||||||
with self.assertRaises(quark_exceptions.IPPolicyAlreadyExists):
|
with self.assertRaises(quark_exceptions.IPPolicyAlreadyExists):
|
||||||
self.plugin.create_ip_policy(self.context, dict(
|
self.plugin.create_ip_policy(self.context, dict(
|
||||||
ip_policy=dict(network_id=1,
|
ip_policy=dict(network_ids=[1],
|
||||||
exclude=["1.1.1.1/24"])))
|
exclude=["1.1.1.1/24"])))
|
||||||
|
|
||||||
def test_create_ip_policy_subnet_ip_policy_already_exists(self):
|
def test_create_ip_policy_subnet_ip_policy_already_exists(self):
|
||||||
with self._stubs(None, subnet=dict(id=1, ip_policy=dict(id=2))):
|
with self._stubs(None, subnet=dict(id=1, ip_policy=dict(id=2))):
|
||||||
with self.assertRaises(quark_exceptions.IPPolicyAlreadyExists):
|
with self.assertRaises(quark_exceptions.IPPolicyAlreadyExists):
|
||||||
self.plugin.create_ip_policy(self.context, dict(
|
self.plugin.create_ip_policy(self.context, dict(
|
||||||
ip_policy=dict(subnet_id=1,
|
ip_policy=dict(subnet_ids=[1],
|
||||||
exclude=["1.1.1.1/24"])))
|
exclude=["1.1.1.1/24"])))
|
||||||
|
|
||||||
def test_create_ip_policy_network(self):
|
def test_create_ip_policy_network(self):
|
||||||
@@ -130,12 +136,12 @@ class TestQuarkCreateIpPolicies(test_quark_plugin.TestQuarkPlugin):
|
|||||||
with self._stubs(ipp, net=dict(id=1, ip_policy=dict(id=2))):
|
with self._stubs(ipp, net=dict(id=1, ip_policy=dict(id=2))):
|
||||||
with self.assertRaises(quark_exceptions.IPPolicyAlreadyExists):
|
with self.assertRaises(quark_exceptions.IPPolicyAlreadyExists):
|
||||||
resp = self.plugin.create_ip_policy(self.context, dict(
|
resp = self.plugin.create_ip_policy(self.context, dict(
|
||||||
ip_policy=dict(network_id=1,
|
ip_policy=dict(network_ids=[1],
|
||||||
exclude=["1.1.1.1/24"])))
|
exclude=["1.1.1.1/24"])))
|
||||||
self.assertEqual(len(resp.keys()), 3)
|
self.assertEqual(len(resp.keys()), 3)
|
||||||
self.assertIsNone(resp["subnet_id"])
|
self.assertIsNone(resp["subnet_ids"])
|
||||||
self.assertEqual(resp["network_id"], 1)
|
self.assertEqual(resp["network_ids"], 1)
|
||||||
self.assertEqual(resp["exclude"], ["1.1.1.1/24"])
|
self.assertEqual(resp["exclude"], [dict()])
|
||||||
|
|
||||||
def test_create_ip_policy_subnet(self):
|
def test_create_ip_policy_subnet(self):
|
||||||
ipp = dict(subnet_id=1, network_id=None,
|
ipp = dict(subnet_id=1, network_id=None,
|
||||||
@@ -144,7 +150,7 @@ class TestQuarkCreateIpPolicies(test_quark_plugin.TestQuarkPlugin):
|
|||||||
with self._stubs(ipp, subnet=dict(id=1, ip_policy=dict(id=2))):
|
with self._stubs(ipp, subnet=dict(id=1, ip_policy=dict(id=2))):
|
||||||
with self.assertRaises(quark_exceptions.IPPolicyAlreadyExists):
|
with self.assertRaises(quark_exceptions.IPPolicyAlreadyExists):
|
||||||
resp = self.plugin.create_ip_policy(self.context, dict(
|
resp = self.plugin.create_ip_policy(self.context, dict(
|
||||||
ip_policy=dict(subnet_id=1,
|
ip_policy=dict(subnet_ids=[1],
|
||||||
exclude=["1.1.1.1/24"])))
|
exclude=["1.1.1.1/24"])))
|
||||||
self.assertEqual(len(resp.keys()), 3)
|
self.assertEqual(len(resp.keys()), 3)
|
||||||
self.assertEqual(resp["subnet_id"], 1)
|
self.assertEqual(resp["subnet_id"], 1)
|
||||||
@@ -152,17 +158,109 @@ class TestQuarkCreateIpPolicies(test_quark_plugin.TestQuarkPlugin):
|
|||||||
self.assertEqual(resp["exclude"], ["1.1.1.1/24"])
|
self.assertEqual(resp["exclude"], ["1.1.1.1/24"])
|
||||||
|
|
||||||
def test_create_ip_policy(self):
|
def test_create_ip_policy(self):
|
||||||
ipp = dict(subnet_id=1, network_id=None, id=1,
|
ipp = dict(
|
||||||
exclude=[dict(address=int(netaddr.IPAddress("1.1.1.1")),
|
subnets=[dict(id=1)],
|
||||||
prefix=24)])
|
networks=[],
|
||||||
|
id=1,
|
||||||
|
tenant_id=1,
|
||||||
|
exclude=[dict(offset=0, length=256)],
|
||||||
|
name="foo")
|
||||||
with self._stubs(ipp, subnet=dict(id=1, ip_policy=None)):
|
with self._stubs(ipp, subnet=dict(id=1, ip_policy=None)):
|
||||||
resp = self.plugin.create_ip_policy(self.context, dict(
|
resp = self.plugin.create_ip_policy(self.context, dict(
|
||||||
ip_policy=dict(subnet_id=1,
|
ip_policy=dict(subnet_ids=[1],
|
||||||
exclude=["1.1.1.1/24"])))
|
exclude=[dict(offset=0, length=256)])))
|
||||||
self.assertEqual(len(resp.keys()), 4)
|
self.assertEqual(len(resp.keys()), 6)
|
||||||
self.assertEqual(resp["subnet_id"], 1)
|
self.assertEqual(resp["subnet_ids"], [1])
|
||||||
self.assertIsNone(resp["network_id"])
|
self.assertEqual(resp["network_ids"], [])
|
||||||
self.assertEqual(resp["exclude"], ["1.1.1.1/24"])
|
self.assertEqual(resp["exclude"],
|
||||||
|
[dict(offset=0, length=256)])
|
||||||
|
self.assertEqual(resp["name"], "foo")
|
||||||
|
self.assertEqual(resp["tenant_id"], 1)
|
||||||
|
|
||||||
|
|
||||||
|
class TestQuarkUpdateIpPolicies(test_quark_plugin.TestQuarkPlugin):
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def _stubs(self, ip_policy, subnets=None, networks=None):
|
||||||
|
if not subnets:
|
||||||
|
subnets = []
|
||||||
|
if not networks:
|
||||||
|
networks = []
|
||||||
|
db_mod = "quark.db.api"
|
||||||
|
with contextlib.nested(
|
||||||
|
mock.patch("%s.ip_policy_find" % db_mod),
|
||||||
|
mock.patch("%s.subnet_find" % db_mod),
|
||||||
|
mock.patch("%s.network_find" % db_mod),
|
||||||
|
mock.patch("%s.ip_policy_update" % db_mod),
|
||||||
|
) as (ip_policy_find, subnet_find, network_find, ip_policy_update):
|
||||||
|
ip_policy_find.return_value = ip_policy
|
||||||
|
subnet_find.return_value = subnets
|
||||||
|
network_find.return_value = networks
|
||||||
|
yield ip_policy_update
|
||||||
|
|
||||||
|
def test_update_ip_policy_not_found(self):
|
||||||
|
with self._stubs(None) as (ip_policy_update):
|
||||||
|
with self.assertRaises(quark_exceptions.IPPolicyNotFound):
|
||||||
|
self.plugin.update_ip_policy(self.context, 1,
|
||||||
|
dict(ip_policy=None))
|
||||||
|
self.assertEqual(ip_policy_update.called, 0)
|
||||||
|
|
||||||
|
def test_update_ip_policy_subnets_not_found(self):
|
||||||
|
ipp = dict(id=1, subnets=[])
|
||||||
|
with self._stubs(ipp) as (ip_policy_update):
|
||||||
|
with self.assertRaises(exceptions.SubnetNotFound):
|
||||||
|
self.plugin.update_ip_policy(
|
||||||
|
self.context,
|
||||||
|
1,
|
||||||
|
dict(ip_policy=dict(subnet_ids=[100])))
|
||||||
|
self.assertEqual(ip_policy_update.called, 0)
|
||||||
|
|
||||||
|
def test_update_ip_policy_subnets_already_exists(self):
|
||||||
|
ipp = dict(id=1, subnets=[dict()])
|
||||||
|
with self._stubs(
|
||||||
|
ipp, subnets=[dict(id=1, ip_policy=dict(id=1))]
|
||||||
|
) as (ip_policy_update):
|
||||||
|
with self.assertRaises(quark_exceptions.IPPolicyAlreadyExists):
|
||||||
|
self.plugin.update_ip_policy(
|
||||||
|
self.context,
|
||||||
|
1,
|
||||||
|
dict(ip_policy=dict(subnet_ids=[100])))
|
||||||
|
self.assertEqual(ip_policy_update.called, 0)
|
||||||
|
|
||||||
|
def test_update_ip_policy_subnets(self):
|
||||||
|
ipp = dict(id=1, subnets=[dict()],
|
||||||
|
exclude=[dict(offset=0, length=256)],
|
||||||
|
name="foo", tenant_id=1)
|
||||||
|
with self._stubs(
|
||||||
|
ipp, subnets=[dict(id=1, ip_policy=None)]
|
||||||
|
) as (ip_policy_update):
|
||||||
|
self.plugin.update_ip_policy(
|
||||||
|
self.context,
|
||||||
|
1,
|
||||||
|
dict(ip_policy=dict(subnet_ids=[100])))
|
||||||
|
self.assertEqual(ip_policy_update.called, 1)
|
||||||
|
|
||||||
|
def test_update_ip_policy_networks_not_found(self):
|
||||||
|
ipp = dict(id=1, networks=[])
|
||||||
|
with self._stubs(ipp) as (ip_policy_update):
|
||||||
|
with self.assertRaises(exceptions.NetworkNotFound):
|
||||||
|
self.plugin.update_ip_policy(
|
||||||
|
self.context,
|
||||||
|
1,
|
||||||
|
dict(ip_policy=dict(network_ids=[100])))
|
||||||
|
self.assertEqual(ip_policy_update.called, 0)
|
||||||
|
|
||||||
|
def test_update_ip_policy_networks(self):
|
||||||
|
ipp = dict(id=1, networks=[dict()],
|
||||||
|
exclude=[dict(offset=0, length=256)],
|
||||||
|
name="foo", tenant_id=1)
|
||||||
|
with self._stubs(
|
||||||
|
ipp, networks=[dict(id=1, ip_policy=None)]
|
||||||
|
) as (ip_policy_update):
|
||||||
|
self.plugin.update_ip_policy(
|
||||||
|
self.context,
|
||||||
|
1,
|
||||||
|
dict(ip_policy=dict(network_ids=[100])))
|
||||||
|
self.assertEqual(ip_policy_update.called, 1)
|
||||||
|
|
||||||
|
|
||||||
class TestQuarkDeleteIpPolicies(test_quark_plugin.TestQuarkPlugin):
|
class TestQuarkDeleteIpPolicies(test_quark_plugin.TestQuarkPlugin):
|
||||||
@@ -181,13 +279,16 @@ class TestQuarkDeleteIpPolicies(test_quark_plugin.TestQuarkPlugin):
|
|||||||
with self.assertRaises(quark_exceptions.IPPolicyNotFound):
|
with self.assertRaises(quark_exceptions.IPPolicyNotFound):
|
||||||
self.plugin.delete_ip_policy(self.context, 1)
|
self.plugin.delete_ip_policy(self.context, 1)
|
||||||
|
|
||||||
|
def test_delete_ip_policy_in_use(self):
|
||||||
|
with self._stubs(dict(networks=True)):
|
||||||
|
with self.assertRaises(quark_exceptions.IPPolicyInUse):
|
||||||
|
self.plugin.delete_ip_policy(self.context, 1)
|
||||||
|
|
||||||
def test_delete_ip_policy(self):
|
def test_delete_ip_policy(self):
|
||||||
address = int(netaddr.IPAddress("1.1.1.1"))
|
|
||||||
ip_policy = dict(
|
ip_policy = dict(
|
||||||
id=1,
|
id=1,
|
||||||
subnet_id=1,
|
networks=[],
|
||||||
network_id=2,
|
subnets=[])
|
||||||
exclude=[dict(address=address, prefix=24)])
|
|
||||||
with self._stubs(ip_policy) as (ip_policy_find, ip_policy_delete):
|
with self._stubs(ip_policy) as (ip_policy_find, ip_policy_delete):
|
||||||
self.plugin.delete_ip_policy(self.context, 1)
|
self.plugin.delete_ip_policy(self.context, 1)
|
||||||
self.assertEqual(ip_policy_find.call_count, 1)
|
self.assertEqual(ip_policy_find.call_count, 1)
|
||||||
|
|||||||
@@ -179,22 +179,31 @@ class TestQuarkCreateSubnetAllocationPools(test_quark_plugin.TestQuarkPlugin):
|
|||||||
with contextlib.nested(
|
with contextlib.nested(
|
||||||
mock.patch("quark.db.api.network_find"),
|
mock.patch("quark.db.api.network_find"),
|
||||||
mock.patch("quark.db.api.subnet_find"),
|
mock.patch("quark.db.api.subnet_find"),
|
||||||
mock.patch("quark.db.api.subnet_create")
|
mock.patch("quark.db.api.subnet_create"),
|
||||||
) as (net_find, subnet_find, subnet_create):
|
) as (net_find, subnet_find, subnet_create):
|
||||||
net_find.return_value = s["network"]
|
net_find.return_value = s["network"]
|
||||||
subnet_find.return_value = []
|
subnet_find.return_value = []
|
||||||
subnet_create.return_value = s
|
subnet_create.return_value = s
|
||||||
yield subnet_create
|
yield subnet_create
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestQuarkCreateSubnetAllocationPools, self).setUp()
|
||||||
|
models.IPPolicy.DEFAULT_POLICY = models.IPPolicy(
|
||||||
|
exclude=[models.IPPolicyRange(offset=-1, length=3)])
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(TestQuarkCreateSubnetAllocationPools, self).tearDown()
|
||||||
|
models.IPPolicy.DEFAULT_POLICY = {}
|
||||||
|
|
||||||
def test_create_subnet_allocation_pools_zero(self):
|
def test_create_subnet_allocation_pools_zero(self):
|
||||||
s = dict(subnet=dict(
|
s = dict(subnet=dict(
|
||||||
cidr="192.168.1.1/24",
|
cidr="192.168.1.1/24",
|
||||||
network_id=1))
|
network_id=1))
|
||||||
with self._stubs(s["subnet"]) as subnet_create:
|
with self._stubs(s["subnet"]) as (subnet_create):
|
||||||
resp = self.plugin.create_subnet(self.context, s)
|
resp = self.plugin.create_subnet(self.context, s)
|
||||||
self.assertEqual(subnet_create.call_count, 1)
|
self.assertEqual(subnet_create.call_count, 1)
|
||||||
self.assertEqual(resp["allocation_pools"],
|
self.assertEqual(resp["allocation_pools"],
|
||||||
[dict(start="192.168.1.0", end="192.168.1.255")])
|
[dict(start="192.168.1.2", end="192.168.1.254")])
|
||||||
|
|
||||||
def test_create_subnet_allocation_pools_one(self):
|
def test_create_subnet_allocation_pools_one(self):
|
||||||
pools = [dict(start="192.168.1.10", end="192.168.1.20")]
|
pools = [dict(start="192.168.1.10", end="192.168.1.20")]
|
||||||
@@ -202,7 +211,7 @@ class TestQuarkCreateSubnetAllocationPools(test_quark_plugin.TestQuarkPlugin):
|
|||||||
allocation_pools=pools,
|
allocation_pools=pools,
|
||||||
cidr="192.168.1.1/24",
|
cidr="192.168.1.1/24",
|
||||||
network_id=1))
|
network_id=1))
|
||||||
with self._stubs(s["subnet"]) as subnet_create:
|
with self._stubs(s["subnet"]) as (subnet_create):
|
||||||
resp = self.plugin.create_subnet(self.context, s)
|
resp = self.plugin.create_subnet(self.context, s)
|
||||||
self.assertEqual(subnet_create.call_count, 1)
|
self.assertEqual(subnet_create.call_count, 1)
|
||||||
self.assertEqual(resp["allocation_pools"], pools)
|
self.assertEqual(resp["allocation_pools"], pools)
|
||||||
@@ -214,7 +223,18 @@ class TestQuarkCreateSubnetAllocationPools(test_quark_plugin.TestQuarkPlugin):
|
|||||||
allocation_pools=pools,
|
allocation_pools=pools,
|
||||||
cidr="192.168.1.1/24",
|
cidr="192.168.1.1/24",
|
||||||
network_id=1))
|
network_id=1))
|
||||||
with self._stubs(s["subnet"]) as subnet_create:
|
with self._stubs(s["subnet"]) as (subnet_create):
|
||||||
|
resp = self.plugin.create_subnet(self.context, s)
|
||||||
|
self.assertEqual(subnet_create.call_count, 1)
|
||||||
|
self.assertEqual(resp["allocation_pools"], pools)
|
||||||
|
|
||||||
|
def test_create_subnet_allocation_pools_empty_list(self):
|
||||||
|
pools = []
|
||||||
|
s = dict(subnet=dict(
|
||||||
|
allocation_pools=pools,
|
||||||
|
cidr="192.168.1.1/24",
|
||||||
|
network_id=1))
|
||||||
|
with self._stubs(s["subnet"]) as (subnet_create):
|
||||||
resp = self.plugin.create_subnet(self.context, s)
|
resp = self.plugin.create_subnet(self.context, s)
|
||||||
self.assertEqual(subnet_create.call_count, 1)
|
self.assertEqual(subnet_create.call_count, 1)
|
||||||
self.assertEqual(resp["allocation_pools"], pools)
|
self.assertEqual(resp["allocation_pools"], pools)
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ class TestQuarkIpPoliciesIpAllocation(QuarkIpamBaseTest):
|
|||||||
cidr="0.0.0.0/24", ip_version=4,
|
cidr="0.0.0.0/24", ip_version=4,
|
||||||
next_auto_assign_ip=0, network=dict(ip_policy=None),
|
next_auto_assign_ip=0, network=dict(ip_policy=None),
|
||||||
ip_policy=dict(exclude=
|
ip_policy=dict(exclude=
|
||||||
[dict(address=0, prefix=24)]))
|
[dict(offset=0, length=256)]))
|
||||||
with self._stubs(subnets=[(subnet, 0)], addresses=[None, None]):
|
with self._stubs(subnets=[(subnet, 0)], addresses=[None, None]):
|
||||||
with self.assertRaises(exceptions.IpAddressGenerationFailure):
|
with self.assertRaises(exceptions.IpAddressGenerationFailure):
|
||||||
self.ipam.allocate_ip_address(self.context, 0, 0, 0, version=4)
|
self.ipam.allocate_ip_address(self.context, 0, 0, 0, version=4)
|
||||||
@@ -401,8 +401,18 @@ class TestQuarkIpPoliciesIpAllocation(QuarkIpamBaseTest):
|
|||||||
cidr="0.0.0.0/24", ip_version=4,
|
cidr="0.0.0.0/24", ip_version=4,
|
||||||
next_auto_assign_ip=0, network=dict(ip_policy=None),
|
next_auto_assign_ip=0, network=dict(ip_policy=None),
|
||||||
ip_policy=dict(exclude=
|
ip_policy=dict(exclude=
|
||||||
[dict(address=0, prefix=32),
|
[dict(offset=0, length=2)]))
|
||||||
dict(address=1, prefix=32)]))
|
with self._stubs(subnets=[(subnet, 0)], addresses=[None, None]):
|
||||||
|
address = self.ipam.allocate_ip_address(self.context, 0, 0, 0,
|
||||||
|
version=4)
|
||||||
|
self.assertEqual(address["address"], 2)
|
||||||
|
|
||||||
|
def test_ip_policy_on_subnet_negative_offset(self):
|
||||||
|
subnet = dict(id=1, first_ip=0, last_ip=255,
|
||||||
|
cidr="0.0.0.0/24", ip_version=4,
|
||||||
|
next_auto_assign_ip=0, network=dict(ip_policy=None),
|
||||||
|
ip_policy=dict(exclude=
|
||||||
|
[dict(offset=-1, length=3)]))
|
||||||
with self._stubs(subnets=[(subnet, 0)], addresses=[None, None]):
|
with self._stubs(subnets=[(subnet, 0)], addresses=[None, None]):
|
||||||
address = self.ipam.allocate_ip_address(self.context, 0, 0, 0,
|
address = self.ipam.allocate_ip_address(self.context, 0, 0, 0,
|
||||||
version=4)
|
version=4)
|
||||||
@@ -410,8 +420,7 @@ class TestQuarkIpPoliciesIpAllocation(QuarkIpamBaseTest):
|
|||||||
|
|
||||||
def test_ip_policy_on_network(self):
|
def test_ip_policy_on_network(self):
|
||||||
net = dict(ip_policy=dict(exclude=
|
net = dict(ip_policy=dict(exclude=
|
||||||
[dict(address=0, prefix=32),
|
[dict(offset=0, length=2)]))
|
||||||
dict(address=1, prefix=32)]))
|
|
||||||
subnet = dict(id=1, first_ip=0, last_ip=255,
|
subnet = dict(id=1, first_ip=0, last_ip=255,
|
||||||
cidr="0.0.0.0/24", ip_version=4,
|
cidr="0.0.0.0/24", ip_version=4,
|
||||||
next_auto_assign_ip=0, network=net,
|
next_auto_assign_ip=0, network=net,
|
||||||
@@ -423,9 +432,8 @@ class TestQuarkIpPoliciesIpAllocation(QuarkIpamBaseTest):
|
|||||||
|
|
||||||
def test_ip_policy_on_network_exclusion_intersection(self):
|
def test_ip_policy_on_network_exclusion_intersection(self):
|
||||||
net = dict(ip_policy=dict(exclude=
|
net = dict(ip_policy=dict(exclude=
|
||||||
[dict(address=0, prefix=32),
|
[dict(offset=0, length=2),
|
||||||
dict(address=1, prefix=32),
|
dict(offset=254, length=1)]))
|
||||||
dict(address=254, prefix=32)]))
|
|
||||||
subnet = dict(id=1, first_ip=0, last_ip=63,
|
subnet = dict(id=1, first_ip=0, last_ip=63,
|
||||||
cidr="0.0.0.0/30", ip_version=4,
|
cidr="0.0.0.0/30", ip_version=4,
|
||||||
next_auto_assign_ip=0, network=net,
|
next_auto_assign_ip=0, network=net,
|
||||||
@@ -437,14 +445,14 @@ class TestQuarkIpPoliciesIpAllocation(QuarkIpamBaseTest):
|
|||||||
|
|
||||||
def test_ip_policy_on_both_subnet_preferred(self):
|
def test_ip_policy_on_both_subnet_preferred(self):
|
||||||
net = dict(ip_policy=dict(exclude=
|
net = dict(ip_policy=dict(exclude=
|
||||||
[dict(address=0, prefix=32),
|
[dict(offset=0, length=1),
|
||||||
dict(address=1, prefix=32)]))
|
dict(offset=1, length=1)]))
|
||||||
subnet = dict(id=1, first_ip=0, last_ip=255,
|
subnet = dict(id=1, first_ip=0, last_ip=255,
|
||||||
cidr="0.0.0.0/24", ip_version=4,
|
cidr="0.0.0.0/24", ip_version=4,
|
||||||
next_auto_assign_ip=0, network=net,
|
next_auto_assign_ip=0, network=net,
|
||||||
ip_policy=dict(exclude=
|
ip_policy=dict(exclude=
|
||||||
[dict(address=254, prefix=32),
|
[dict(offset=254, length=1),
|
||||||
dict(address=255, prefix=32)]))
|
dict(offset=255, length=1)]))
|
||||||
with self._stubs(subnets=[(subnet, 0)], addresses=[None, None]):
|
with self._stubs(subnets=[(subnet, 0)], addresses=[None, None]):
|
||||||
address = self.ipam.allocate_ip_address(self.context, 0, 0, 0,
|
address = self.ipam.allocate_ip_address(self.context, 0, 0, 0,
|
||||||
version=4)
|
version=4)
|
||||||
@@ -454,7 +462,7 @@ class TestQuarkIpPoliciesIpAllocation(QuarkIpamBaseTest):
|
|||||||
subnet1 = dict(id=1, first_ip=0, last_ip=255,
|
subnet1 = dict(id=1, first_ip=0, last_ip=255,
|
||||||
cidr="0.0.0.0/24", ip_version=4,
|
cidr="0.0.0.0/24", ip_version=4,
|
||||||
network=dict(ip_policy=None),
|
network=dict(ip_policy=None),
|
||||||
ip_policy=dict(exclude=[dict(address=240, prefix=32)]))
|
ip_policy=dict(exclude=[dict(offset=240, length=1)]))
|
||||||
subnets = [(subnet1, 1)]
|
subnets = [(subnet1, 1)]
|
||||||
with self._stubs(subnets=subnets, addresses=[None, None]):
|
with self._stubs(subnets=subnets, addresses=[None, None]):
|
||||||
address = self.ipam.allocate_ip_address(
|
address = self.ipam.allocate_ip_address(
|
||||||
|
|||||||
Reference in New Issue
Block a user