
Also support the sqlalchemy 2.0 in backend. Zaqar has be planing to remove the V1 APIs support for a while. As the first step, this patch will remove the v1 funcational test in wsgi. Change-Id: I0b7b57a5fb4d203441889b0166a4c35180de2466
170 lines
5.7 KiB
Python
170 lines
5.7 KiB
Python
# Copyright (c) 2014 Rackspace, Inc.
|
|
#
|
|
# 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.
|
|
|
|
"""pools: an implementation of the pool management storage
|
|
controller for sqlalchemy.
|
|
|
|
"""
|
|
|
|
import functools
|
|
|
|
import oslo_db.exception
|
|
import sqlalchemy as sa
|
|
|
|
from zaqar.common import utils as common_utils
|
|
from zaqar.storage import base
|
|
from zaqar.storage import errors
|
|
from zaqar.storage.sqlalchemy import tables
|
|
from zaqar.storage.sqlalchemy import utils
|
|
|
|
|
|
class PoolsController(base.PoolsBase):
|
|
|
|
@utils.raises_conn_error
|
|
def _list(self, marker=None, limit=10, detailed=False):
|
|
marker = marker or ''
|
|
|
|
# TODO(cpp-cabrera): optimization - limit the columns returned
|
|
# when detailed=False by specifying them in the select()
|
|
# clause
|
|
stmt = sa.sql.select(tables.Pools.c.name, tables.Pools.c.uri,
|
|
tables.Pools.c.weight,
|
|
tables.Pools.c.options,
|
|
tables.Pools.c.flavor).where(
|
|
tables.Pools.c.name > marker
|
|
)
|
|
if limit > 0:
|
|
stmt = stmt.limit(limit)
|
|
cursor = self.driver.fetch_all(stmt)
|
|
|
|
marker_name = {}
|
|
|
|
def it():
|
|
for cur in cursor:
|
|
marker_name['next'] = cur[0]
|
|
yield _normalize(cur, detailed=detailed)
|
|
|
|
yield it()
|
|
yield marker_name and marker_name['next']
|
|
|
|
@utils.raises_conn_error
|
|
def _get_pools_by_flavor(self, flavor=None, detailed=False):
|
|
flavor_name = flavor.get("name", None) if flavor is not None\
|
|
else None
|
|
if flavor_name is not None:
|
|
stmt = sa.sql.select(tables.Pools.c.name, tables.Pools.c.uri,
|
|
tables.Pools.c.weight,
|
|
tables.Pools.c.options,
|
|
tables.Pools.c.flavor).where(
|
|
tables.Pools.c.flavor == flavor_name
|
|
)
|
|
else:
|
|
stmt = sa.sql.select(tables.Pools.c.name, tables.Pools.c.uri,
|
|
tables.Pools.c.weight,
|
|
tables.Pools.c.options,
|
|
tables.Pools.c.flavor)
|
|
|
|
cursor = self.driver.fetch_all(stmt)
|
|
|
|
normalizer = functools.partial(_normalize, detailed=detailed)
|
|
get_result = (normalizer(v) for v in cursor)
|
|
return get_result
|
|
|
|
@utils.raises_conn_error
|
|
def _get(self, name, detailed=False):
|
|
stmt = sa.sql.select(tables.Pools.c.name, tables.Pools.c.uri,
|
|
tables.Pools.c.weight, tables.Pools.c.options,
|
|
tables.Pools.c.flavor).where(
|
|
tables.Pools.c.name == name
|
|
)
|
|
|
|
pool = self.driver.fetch_one(stmt)
|
|
if pool is None:
|
|
raise errors.PoolDoesNotExist(name)
|
|
|
|
return _normalize(pool, detailed)
|
|
|
|
# TODO(cpp-cabrera): rename to upsert
|
|
@utils.raises_conn_error
|
|
def _create(self, name, weight, uri, flavor=None,
|
|
options=None):
|
|
opts = None if options is None else utils.json_encode(options)
|
|
|
|
try:
|
|
stmt = sa.sql.insert(tables.Pools).values(
|
|
name=name, weight=weight, uri=uri,
|
|
flavor=flavor, options=opts
|
|
)
|
|
self.driver.run(stmt)
|
|
|
|
except oslo_db.exception.DBDuplicateEntry:
|
|
# TODO(cpp-cabrera): merge update/create into a single
|
|
# method with introduction of upsert
|
|
self._update(name, weight=weight, uri=uri,
|
|
flavor=flavor, options=options)
|
|
|
|
@utils.raises_conn_error
|
|
def _exists(self, name):
|
|
stmt = sa.sql.select(tables.Pools.c.name).where(
|
|
tables.Pools.c.name == name).limit(1)
|
|
return self.driver.fetch_one(stmt) is not None
|
|
|
|
@utils.raises_conn_error
|
|
def _update(self, name, **kwargs):
|
|
# NOTE(cpp-cabrera): by pruning None-valued kwargs, we avoid
|
|
# overwriting the existing options field with None, since that
|
|
# one can be null.
|
|
names = ('uri', 'weight', 'flavor', 'options')
|
|
fields = common_utils.fields(kwargs, names,
|
|
pred=lambda x: x is not None)
|
|
|
|
assert fields, ('`weight`, `uri`, `flavor`, '
|
|
'or `options` not found in kwargs')
|
|
|
|
if 'options' in fields:
|
|
fields['options'] = utils.json_encode(fields['options'])
|
|
|
|
stmt = sa.sql.update(tables.Pools).where(
|
|
tables.Pools.c.name == name).values(**fields)
|
|
|
|
res = self.driver.run(stmt)
|
|
if res.rowcount == 0:
|
|
raise errors.PoolDoesNotExist(name)
|
|
|
|
@utils.raises_conn_error
|
|
def _delete(self, name):
|
|
stmt = sa.sql.expression.delete(tables.Pools).where(
|
|
tables.Pools.c.name == name
|
|
)
|
|
self.driver.run(stmt)
|
|
|
|
@utils.raises_conn_error
|
|
def _drop_all(self):
|
|
stmt = sa.sql.expression.delete(tables.Pools)
|
|
self.driver.run(stmt)
|
|
|
|
|
|
def _normalize(pool, detailed=False):
|
|
ret = {
|
|
'name': pool[0],
|
|
'uri': pool[1],
|
|
'weight': pool[2],
|
|
'flavor': pool[4],
|
|
}
|
|
if detailed:
|
|
opts = pool[3]
|
|
ret['options'] = utils.json_decode(opts) if opts else {}
|
|
|
|
return ret
|