Merge "Remove built-in plugins from database schema"
This commit is contained in:
commit
96e332b130
|
@ -0,0 +1,52 @@
|
|||
# Copyright 2018 StackHPC Ltd
|
||||
#
|
||||
# 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.
|
||||
"""Remove builtin notification types
|
||||
|
||||
Revision ID: 26083b298bb7
|
||||
Revises: f69cb3152a76
|
||||
Create Date: 2018-09-18 13:52:02.170226
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.sql import table
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '26083b298bb7'
|
||||
down_revision = 'f69cb3152a76'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
_nm_types = table(
|
||||
'notification_method_type',
|
||||
sa.Column('name',
|
||||
sa.String(length=20),
|
||||
nullable=False))
|
||||
|
||||
|
||||
def upgrade():
|
||||
# Built-in notification types have been removed. Here, we
|
||||
# remove them and rely on monasca_notification to re-populate
|
||||
# the table according to what is set in its config file.
|
||||
op.execute(_nm_types.delete().where(
|
||||
_nm_types.c.name.in_(('EMAIL', 'WEBHOOK', 'PAGERDUTY'))))
|
||||
|
||||
|
||||
def downgrade():
|
||||
# Some or all of these might be present if they have been explicitly
|
||||
# enabled in monasca-notification.
|
||||
op.execute(_nm_types.insert().prefix_with("IGNORE").values(
|
||||
[{'name': 'EMAIL'},
|
||||
{'name': 'WEBHOOK'},
|
||||
{'name': 'PAGERDUTY'}]))
|
|
@ -14,9 +14,16 @@
|
|||
|
||||
import hashlib
|
||||
|
||||
from oslo_log import log
|
||||
from oslo_utils import encodeutils
|
||||
from sqlalchemy import MetaData
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
# Map of SHA1 fingerprints to alembic revisions.
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
# Map of SHA1 fingerprints to alembic revisions. Note that this is
|
||||
# used in the pre-alembic case and does not need to be updated if a
|
||||
# new revision is introduced.
|
||||
_REVS = {"43e5913b0272077321ab6f25ffbcda7149b6284b": "00597b5c8325",
|
||||
"c4e5c870c705421faa4041405b5a895970faa434": "0cce983d957a",
|
||||
"f7a79c4eea9c9d130277a64eb6d2d16587088dbb": "30181b42434b",
|
||||
|
@ -34,8 +41,17 @@ _REVS = {"43e5913b0272077321ab6f25ffbcda7149b6284b": "00597b5c8325",
|
|||
class Fingerprint(object):
|
||||
|
||||
def __init__(self, engine):
|
||||
metadata = MetaData(bind=engine, reflect=True)
|
||||
metadata = self._get_metadata(engine)
|
||||
self.schema_raw = self._get_schema_raw(metadata)
|
||||
self.sha1 = self._get_schema_sha1(self.schema_raw)
|
||||
self.revision = self._get_revision(metadata, engine, self.sha1)
|
||||
|
||||
@staticmethod
|
||||
def _get_metadata(engine):
|
||||
return MetaData(bind=engine, reflect=True)
|
||||
|
||||
@staticmethod
|
||||
def _get_schema_raw(metadata):
|
||||
schema_strings = []
|
||||
|
||||
for table in metadata.sorted_tables:
|
||||
|
@ -56,11 +72,39 @@ class Fingerprint(object):
|
|||
|
||||
schema_strings.append("")
|
||||
|
||||
self.schema_raw = "\n".join(schema_strings)
|
||||
self.sha1 = hashlib.sha1(self.schema_raw).hexdigest()
|
||||
return "\n".join(schema_strings)
|
||||
|
||||
try:
|
||||
self.revision = _REVS[self.sha1]
|
||||
except KeyError:
|
||||
# Fingerprint does not match any revisions
|
||||
self.revision = None
|
||||
@staticmethod
|
||||
def _get_schema_sha1(schema_raw):
|
||||
return hashlib.sha1(encodeutils.to_utf8(schema_raw)).hexdigest()
|
||||
|
||||
@staticmethod
|
||||
def _get_revision(metadata, engine, sha1):
|
||||
# Alembic stores the current version in the DB so check that first
|
||||
# and fall back to the lookup table for the pre-alembic case.
|
||||
versions_table = metadata.tables.get('alembic_version')
|
||||
if versions_table is not None:
|
||||
return Fingerprint._lookup_version_from_db(versions_table, engine)
|
||||
elif sha1:
|
||||
return Fingerprint._lookup_version_from_table(sha1)
|
||||
|
||||
@staticmethod
|
||||
def _get_db_session(engine):
|
||||
Session = sessionmaker(bind=engine)
|
||||
return Session()
|
||||
|
||||
@staticmethod
|
||||
def _lookup_version_from_db(versions_table, engine):
|
||||
session = Fingerprint._get_db_session(engine)
|
||||
# This will throw an exception for the unexpected case when there is
|
||||
# more than one row. The query returns a tuple which is stripped off
|
||||
# before returning.
|
||||
return session.query(versions_table).one()[0]
|
||||
|
||||
@staticmethod
|
||||
def _lookup_version_from_table(sha1):
|
||||
revision = _REVS.get(sha1)
|
||||
if not revision:
|
||||
LOG.warning("Fingerprint: {} does not match any revisions."
|
||||
.format(sha1))
|
||||
return revision
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
# Copyright 2018 StackHPC Ltd.
|
||||
#
|
||||
# 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 hashlib
|
||||
import mock
|
||||
|
||||
import monasca_api.db.fingerprint as fingerprint
|
||||
from monasca_api.tests import base
|
||||
|
||||
|
||||
class TestFingerprint(base.BaseTestCase):
|
||||
|
||||
@mock.patch('monasca_api.db.fingerprint.Fingerprint._get_metadata')
|
||||
@mock.patch('monasca_api.db.fingerprint.Fingerprint._get_schema_raw')
|
||||
def test_get_schema_raw_pre_alembic(self, mock_schema_raw, mock_metadata):
|
||||
mock_schema_raw.return_value = 'dummy_schema_raw'
|
||||
|
||||
tables = mock.PropertyMock = {
|
||||
'dummy_table': 'dummy_columns'
|
||||
}
|
||||
mock_metadata.return_value.tables = tables
|
||||
|
||||
# No Alembic revision ID exists in the DB so we look it up from the
|
||||
# table of fingerprints. Since we use a dummy schema, we insert a dummy
|
||||
# entry into the lookup table.
|
||||
fingerprint._REVS[
|
||||
hashlib.sha1(b'dummy_schema_raw').hexdigest()] = 'dummy_revision'
|
||||
|
||||
f = fingerprint.Fingerprint('mock_engine')
|
||||
self.assertEqual(f.schema_raw, 'dummy_schema_raw')
|
||||
self.assertEqual(f.sha1, hashlib.sha1(b'dummy_schema_raw').hexdigest())
|
||||
self.assertEqual(f.revision, 'dummy_revision')
|
||||
|
||||
@mock.patch('monasca_api.db.fingerprint.Fingerprint._get_db_session')
|
||||
@mock.patch('monasca_api.db.fingerprint.Fingerprint._get_metadata')
|
||||
@mock.patch('monasca_api.db.fingerprint.Fingerprint._get_schema_raw')
|
||||
def test_get_schema_raw_post_alembic(
|
||||
self, mock_schema_raw, mock_metadata, mock_db_session):
|
||||
mock_schema_raw.return_value = 'dummy_schema_raw'
|
||||
|
||||
tables = mock.PropertyMock = {
|
||||
'alembic_version': 'dummy_version',
|
||||
'dummy_table': 'dummy_columns'
|
||||
}
|
||||
mock_metadata.return_value.tables = tables
|
||||
|
||||
# Alembic sets the version in the DB, so we look it up from there
|
||||
mock_db_session.return_value.query.return_value.one.return_value = (
|
||||
'dummy_revision',)
|
||||
|
||||
f = fingerprint.Fingerprint('mock_engine')
|
||||
self.assertEqual(f.schema_raw, 'dummy_schema_raw')
|
||||
self.assertEqual(f.sha1, hashlib.sha1(b'dummy_schema_raw').hexdigest())
|
||||
self.assertEqual(f.revision, 'dummy_revision')
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
upgrade:
|
||||
- The concept of built-in monasca-notification plugins has been removed
|
||||
and the built-in plugins are no longer pre-populated in the database. If
|
||||
you were using the PAGERDUTY, EMAIL or WEBHOOK notification plugin you
|
||||
should explicitly enable it in the monasca-notification config file.
|
Loading…
Reference in New Issue