implement locking mechanism in rally

Rally is not having locking mechanism to control rally processes
simultaneous access to the same OSP resource. For example, we
don't want two different rally processes to delete the same
floating ip.

In this implementation we create a "RallyLock" table in rally DB
which can store a unique UUID. When a user wants only one process
to modify a OSP resource at a time, take a lock by inserting
resource's (for example floating ip) uuid into this table. If
another process wants to take lock, it will get error as table
won't allow duplicate values for uuid.

Sqlalchemy is throwing errors when this DB code is implemented
as a rally plugin. So we needed to find the alternate option
i.e python package to make this DB changes working.

To acquire and release a lock, rally scenario has to call the
api like

from browbeat_rally.db import api as db_api
from oslo_db import exception as db_exc

net_id = net['network']['id']
try:
    db_api.acquire_lock(net_id)
except db_exc.DBDuplicateEntry:
    LOG.info("This uuid {} is already in use".format(net_id))

db_api.release_lock(net_id)

Change-Id: I0c14a3c0ddb3e2d4e3478e763d2ee4066440b9ac
This commit is contained in:
venkata anil 2021-08-09 22:29:14 +05:30
parent 06f1a7c6c7
commit cf541956e8
8 changed files with 154 additions and 0 deletions

View File

@ -0,0 +1,32 @@
# 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 rally.common import db
from browbeat_rally.db import models
@db.with_session
def get_lock(session, lock_uuid):
lock = models.RallyLock(lock_uuid=lock_uuid)
session.add(lock)
session.commit()
lock = lock.as_dict()
return lock
@db.with_session
def lock_list(session):
locks = []
query = session.query(models.RallyLock)
for lock in query.all():
locks.append(lock.as_dict())
return locks

View File

@ -0,0 +1,23 @@
# 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.
import sqlalchemy as sa
from rally.common.db import models
BASE = models.BASE
class RallyLock(BASE, models.RallyBase):
__tablename__ = "rallylocks"
lock_uuid = sa.Column(sa.String(36), primary_key=True, nullable=False)

View File

@ -0,0 +1,46 @@
# 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.
import tempfile
from sqlalchemy import schema
from oslo_db import options as db_options
from browbeat_rally.db import models
from rally.common import cfg
from oslo_db.sqlalchemy import session as db_session
CONF = cfg.CONF
# rally.conf always uses stack.sqlite database
db_options.set_defaults(
CONF, connection="sqlite:///%s/stack.sqlite" % tempfile.gettempdir())
def _create_facade_lazily():
return db_session.EngineFacade.from_config(CONF)
def get_engine():
facade = _create_facade_lazily()
return facade.get_engine()
# alternate way to create engine is
# from oslo_db.sqlalchemy import engines
# engine = engines.create_engine("sqlite:///%s/stack.sqlite" % tempfile.gettempdir())
def schema_create():
engine = get_engine()
metadata = schema.MetaData()
table = schema.Table("rallylocks", metadata)
# delete rallylocks table
models.BASE.metadata.drop_all(engine, [table], checkfirst=True)
# recreate rallylocks table
models.BASE.metadata.create_all(engine)

View File

@ -0,0 +1,18 @@
# 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 setuptools import setup, find_packages
setup(
name='browbeat_rally',
version='0.0.1',
packages=find_packages(),)

View File

@ -0,0 +1,16 @@
# 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 browbeat_rally.db import schema
if __name__ == "__main__":
schema.schema_create()

View File

@ -56,6 +56,25 @@
- name: Setup rally database
shell: . {{ rally_venv }}/bin/activate; rally db recreate
# Install rally extra code which we develop in browbeat
# as python package. This code can be used in browbeat rally plugins.
# Sqlalchemy giving errors when we run this extra DB code as rally plugin
# so we came up with this python package approach.
- name: install rally browbeat code
shell: |
source {{ rally_venv }}/bin/activate
pip install .
args:
executable: /bin/bash
chdir: "{{ role_path }}/files/browbeat-rally"
when: rhosp_version is version('15.0', '>=')
- name: create lock table in rally db for dynamic workloads
shell: |
source {{ rally_venv }}/bin/activate
python {{ role_path }}/files/create_lock_table.py
when: rhosp_version is version('15.0', '>=')
- block:
- name: copy of stackrc
copy: