Merge pull request #499 from morgabra/add_segment_allocations
Add framework for managing segment id pools.
This commit is contained in:
144
quark/plugin_modules/segment_allocation_ranges.py
Normal file
144
quark/plugin_modules/segment_allocation_ranges.py
Normal file
@@ -0,0 +1,144 @@
|
||||
# Copyright 2013 Openstack Foundation
|
||||
# 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 neutron.common import exceptions
|
||||
from oslo_log import log as logging
|
||||
|
||||
from quark.db import api as db_api
|
||||
from quark import exceptions as quark_exceptions
|
||||
from quark import plugin_views as v
|
||||
|
||||
from quark import segment_allocations
|
||||
|
||||
SA_REGISTRY = segment_allocations.REGISTRY
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_segment_allocation_range(context, id, fields=None):
|
||||
LOG.info("get_segment_allocation_range %s for tenant %s fields %s" %
|
||||
(id, context.tenant_id, fields))
|
||||
|
||||
if not context.is_admin:
|
||||
raise exceptions.NotAuthorized()
|
||||
|
||||
sa_range = db_api.segment_allocation_range_find(
|
||||
context, id=id, scope=db_api.ONE)
|
||||
|
||||
if not sa_range:
|
||||
raise quark_exceptions.SegmentAllocationRangeNotFound(
|
||||
segment_allocation_range_id=id)
|
||||
|
||||
# Count up allocations so we can calculate how many are free.
|
||||
allocs = db_api.segment_allocation_find(
|
||||
context,
|
||||
segment_allocation_range_id=sa_range["id"],
|
||||
deallocated=False).count()
|
||||
return v._make_segment_allocation_range_dict(
|
||||
sa_range, allocations=allocs)
|
||||
|
||||
|
||||
def get_segment_allocation_ranges(context, **filters):
|
||||
LOG.info("get_segment_allocation_ranges for tenant %s" % context.tenant_id)
|
||||
if not context.is_admin:
|
||||
raise exceptions.NotAuthorized()
|
||||
|
||||
sa_ranges = db_api.segment_allocation_range_find(
|
||||
context, scope=db_api.ALL, **filters)
|
||||
return [v._make_segment_allocation_range_dict(m) for m in sa_ranges]
|
||||
|
||||
|
||||
def create_segment_allocation_range(context, sa_range):
|
||||
LOG.info("create_segment_allocation_range for tenant %s"
|
||||
% context.tenant_id)
|
||||
if not context.is_admin:
|
||||
raise exceptions.NotAuthorized()
|
||||
|
||||
sa_range = sa_range.get("segment_allocation_range")
|
||||
if not sa_range:
|
||||
raise exceptions.BadRequest(resource="segment_allocation_range",
|
||||
msg=("segment_allocation_range not in "
|
||||
"request body."))
|
||||
|
||||
# TODO(morgabra) Figure out how to get the api extension to validate this
|
||||
# for us.
|
||||
# parse required fields
|
||||
for k in ["first_id", "last_id", "segment_id", "segment_type"]:
|
||||
sa_range[k] = sa_range.get(k, None)
|
||||
if sa_range[k] is None:
|
||||
raise exceptions.BadRequest(
|
||||
resource="segment_allocation_range",
|
||||
msg=("Missing required key %s in request body." % (k)))
|
||||
|
||||
# parse optional fields
|
||||
for k in ["do_not_use"]:
|
||||
sa_range[k] = sa_range.get(k, None)
|
||||
|
||||
# use the segment registry to validate and create/populate the range
|
||||
if not SA_REGISTRY.is_valid_strategy(sa_range["segment_type"]):
|
||||
raise exceptions.BadRequest(
|
||||
resource="segment_allocation_range",
|
||||
msg=("Unknown segment type '%s'" % (k)))
|
||||
strategy = SA_REGISTRY.get_strategy(sa_range["segment_type"])
|
||||
|
||||
# Create the new range
|
||||
with context.session.begin():
|
||||
new_range = strategy.create_range(context, sa_range)
|
||||
|
||||
# Bulk-populate the range, this could take a while for huge ranges
|
||||
# (millions) so we do this in chunks outside the transaction. That
|
||||
# means we need to rollback the range creation if it fails for
|
||||
# whatever reason (and it will cascade delete any added allocations)
|
||||
try:
|
||||
strategy.populate_range(context, new_range)
|
||||
except Exception:
|
||||
LOG.exception("Failed to populate segment allocation range.")
|
||||
delete_segment_allocation_range(context, new_range["id"])
|
||||
raise
|
||||
|
||||
return v._make_segment_allocation_range_dict(new_range)
|
||||
|
||||
|
||||
def _delete_segment_allocation_range(context, sa_range):
|
||||
|
||||
allocs = db_api.segment_allocation_find(
|
||||
context,
|
||||
segment_allocation_range_id=sa_range["id"],
|
||||
deallocated=False).count()
|
||||
|
||||
if allocs:
|
||||
raise quark_exceptions.SegmentAllocationRangeInUse(
|
||||
segment_allocation_range_id=sa_range["id"])
|
||||
db_api.segment_allocation_range_delete(context, sa_range)
|
||||
|
||||
|
||||
def delete_segment_allocation_range(context, sa_id):
|
||||
"""Delete a segment_allocation_range.
|
||||
|
||||
: param context: neutron api request context
|
||||
: param id: UUID representing the segment_allocation_range to delete.
|
||||
"""
|
||||
LOG.info("delete_segment_allocation_range %s for tenant %s" %
|
||||
(sa_id, context.tenant_id))
|
||||
if not context.is_admin:
|
||||
raise exceptions.NotAuthorized()
|
||||
|
||||
with context.session.begin():
|
||||
sa_range = db_api.segment_allocation_range_find(
|
||||
context, id=sa_id, scope=db_api.ONE)
|
||||
if not sa_range:
|
||||
raise quark_exceptions.SegmentAllocationRangeNotFound(
|
||||
segment_allocation_range_id=sa_id)
|
||||
_delete_segment_allocation_range(context, sa_range)
|
||||
Reference in New Issue
Block a user