Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add partial specs support in ML2 for vlan provider networks
ML2 provider networks partial specs let admins choose some provider network attributes and let neutron choose remaining attributes. This change provides the implementation for VLAN provider networks. In practice, for VLAN provider networks provider:physical_network and provider:segmentation_id choices can be delegated to neutron, in such case neutron will try to find a network in tenant network pools which respects provided provider attributes. DocImpact Related to blueprint provider-network-partial-specs Partial-Bug: #1330562 Change-Id: I2c52c71167edaa153b2e04681273e2f1be8d03aa
- Loading branch information
Showing
16 changed files
with
424 additions
and
99 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
# Copyright (c) 2014 Thales Services SAS | ||
# All Rights Reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); you may | ||
# not use this file except in compliance with the License. You may obtain | ||
# a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
# License for the specific language governing permissions and limitations | ||
# under the License. | ||
|
||
from oslo.db import exception as db_exc | ||
|
||
from neutron.common import exceptions as exc | ||
from neutron.openstack.common import log | ||
from neutron.plugins.ml2 import driver_api as api | ||
|
||
|
||
# Number of retries to find a valid segment candidate and allocate it | ||
DB_MAX_RETRIES = 10 | ||
|
||
|
||
LOG = log.getLogger(__name__) | ||
|
||
|
||
class TypeDriverHelper(api.TypeDriver): | ||
"""TypeDriver Helper for segment allocation. | ||
Provide methods helping to perform segment allocation fully or partially | ||
specified. | ||
""" | ||
|
||
def __init__(self, model): | ||
self.model = model | ||
self.primary_keys = set(dict(model.__table__.columns)) | ||
self.primary_keys.remove("allocated") | ||
|
||
def allocate_fully_specified_segment(self, session, **raw_segment): | ||
"""Allocate segment fully specified by raw_segment. | ||
If segment exists, then try to allocate it and return db object | ||
If segment does not exists, then try to create it and return db object | ||
If allocation/creation failed, then return None | ||
""" | ||
|
||
network_type = self.get_type() | ||
try: | ||
with session.begin(subtransactions=True): | ||
alloc = (session.query(self.model).filter_by(**raw_segment). | ||
first()) | ||
if alloc: | ||
if alloc.allocated: | ||
# Segment already allocated | ||
return | ||
else: | ||
# Segment not allocated | ||
LOG.debug("%(type)s segment %(segment)s allocate " | ||
"started ", | ||
type=network_type, segment=raw_segment) | ||
count = (session.query(self.model). | ||
filter_by(allocated=False, **raw_segment). | ||
update({"allocated": True})) | ||
if count: | ||
LOG.debug("%(type)s segment %(segment)s allocate " | ||
"done ", | ||
type=network_type, segment=raw_segment) | ||
return alloc | ||
|
||
# Segment allocated or deleted since select | ||
LOG.debug("%(type)s segment %(segment)s allocate " | ||
"failed: segment has been allocated or " | ||
"deleted", | ||
type=network_type, segment=raw_segment) | ||
|
||
# Segment to create or already allocated | ||
LOG.debug("%(type)s segment %(segment)s create started", | ||
type=network_type, segment=raw_segment) | ||
alloc = self.model(allocated=True, **raw_segment) | ||
alloc.save(session) | ||
LOG.debug("%(type)s segment %(segment)s create done", | ||
type=network_type, segment=raw_segment) | ||
|
||
except db_exc.DBDuplicateEntry: | ||
# Segment already allocated (insert failure) | ||
alloc = None | ||
LOG.debug("%(type)s segment %(segment)s create failed", | ||
type=network_type, segment=raw_segment) | ||
|
||
return alloc | ||
|
||
def allocate_partially_specified_segment(self, session, **filters): | ||
"""Allocate model segment from pool partially specified by filters. | ||
Return allocated db object or None. | ||
""" | ||
|
||
network_type = self.get_type() | ||
with session.begin(subtransactions=True): | ||
select = (session.query(self.model). | ||
filter_by(allocated=False, **filters)) | ||
|
||
# Selected segment can be allocated before update by someone else, | ||
# We retry until update success or DB_MAX_RETRIES retries | ||
for attempt in range(1, DB_MAX_RETRIES + 1): | ||
alloc = select.first() | ||
|
||
if not alloc: | ||
# No resource available | ||
return | ||
|
||
raw_segment = dict((k, alloc[k]) for k in self.primary_keys) | ||
LOG.debug("%(type)s segment allocate from pool, attempt " | ||
"%(attempt)s started with %(segment)s ", | ||
type=network_type, attempt=attempt, | ||
segment=raw_segment) | ||
count = (session.query(self.model). | ||
filter_by(allocated=False, **raw_segment). | ||
update({"allocated": True})) | ||
if count: | ||
LOG.debug("%(type)s segment allocate from pool, attempt " | ||
"%(attempt)s success with %(segment)s ", | ||
type=network_type, attempt=attempt, | ||
segment=raw_segment) | ||
return alloc | ||
|
||
# Segment allocated since select | ||
LOG.debug("Allocate %(type)s segment from pool, " | ||
"attempt %(attempt)s failed with segment " | ||
"%(segment)s", | ||
type=network_type, attempt=attempt, | ||
segment=raw_segment) | ||
|
||
LOG.warning(_("Allocate %(type)s segment from pool failed " | ||
"after %(number)s failed attempts"), | ||
{"type": network_type, "number": DB_MAX_RETRIES}) | ||
raise exc.NoNetworkFoundInMaximumAllowedAttempts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.