Files
watcher/watcher/db/sqlalchemy/api.py
Vincent Françoise ac07f35dc7 i18n - Make string translatable
Since internationalization should be enabled in Watcher, this
patchset refactors the Watcher codebase to wrap previously
untranslatable strings with i18n translation functions so we can
import them for translation into the .pot template file.

Partially Implements: blueprint support-translation
Change-Id: I425967a60b5a7957f753894e5d2ba0d2c5009d1d
2015-12-21 10:08:59 +01:00

616 lines
22 KiB
Python

# -*- encoding: utf-8 -*-
#
# Copyright 2013 Hewlett-Packard Development Company, L.P.
#
# 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.
"""SQLAlchemy storage backend."""
from oslo_config import cfg
from oslo_db import exception as db_exc
from oslo_db.sqlalchemy import session as db_session
from oslo_db.sqlalchemy import utils as db_utils
from oslo_log import log
from sqlalchemy.orm import exc
from watcher import _i18n
from watcher.common import exception
from watcher.common import utils
from watcher.db import api
from watcher.db.sqlalchemy import models
from watcher.objects import audit as audit_objects
CONF = cfg.CONF
LOG = log.getLogger(__name__)
_ = _i18n._
_FACADE = None
def _create_facade_lazily():
global _FACADE
if _FACADE is None:
_FACADE = db_session.EngineFacade.from_config(CONF)
return _FACADE
def get_engine():
facade = _create_facade_lazily()
return facade.get_engine()
def get_session(**kwargs):
facade = _create_facade_lazily()
return facade.get_session(**kwargs)
def get_backend():
"""The backend is this module itself."""
return Connection()
def model_query(model, *args, **kwargs):
"""Query helper for simpler session usage.
:param session: if present, the session to use
"""
session = kwargs.get('session') or get_session()
query = session.query(model, *args)
return query
def add_identity_filter(query, value):
"""Adds an identity filter to a query.
Filters results by ID, if supplied value is a valid integer.
Otherwise attempts to filter results by UUID.
:param query: Initial query to add filter to.
:param value: Value for filtering results by.
:return: Modified query.
"""
if utils.is_int_like(value):
return query.filter_by(id=value)
elif utils.is_uuid_like(value):
return query.filter_by(uuid=value)
else:
raise exception.InvalidIdentity(identity=value)
def _paginate_query(model, limit=None, marker=None, sort_key=None,
sort_dir=None, query=None):
if not query:
query = model_query(model)
sort_keys = ['id']
if sort_key and sort_key not in sort_keys:
sort_keys.insert(0, sort_key)
query = db_utils.paginate_query(query, model, limit, sort_keys,
marker=marker, sort_dir=sort_dir)
return query.all()
class Connection(api.BaseConnection):
"""SqlAlchemy connection."""
def __init__(self):
pass
def _add_audit_templates_filters(self, query, filters):
if filters is None:
filters = []
if 'name' in filters:
query = query.filter_by(name=filters['name'])
if 'host_aggregate' in filters:
query = query.filter_by(host_aggregate=filters['host_aggregate'])
if 'goal' in filters:
query = query.filter_by(goal=filters['goal'])
return query
def _add_audits_filters(self, query, filters):
if filters is None:
filters = []
if 'type' in filters:
query = query.filter_by(type=filters['type'])
if 'state' in filters:
query = query.filter_by(state=filters['state'])
if 'audit_template_id' in filters:
query = query.filter_by(
audit_template_id=filters['audit_template_id'])
if 'audit_template_uuid' in filters:
query = query.join(
models.AuditTemplate,
models.Audit.audit_template_id == models.AuditTemplate.id)
query = query.filter(
models.AuditTemplate.uuid == filters['audit_template_uuid'])
if 'audit_template_name' in filters:
query = query.join(
models.AuditTemplate,
models.Audit.audit_template_id == models.AuditTemplate.id)
query = query.filter(
models.AuditTemplate.name ==
filters['audit_template_name'])
return query
def _add_action_plans_filters(self, query, filters):
if filters is None:
filters = []
if 'state' in filters:
query = query.filter_by(state=filters['state'])
if 'audit_id' in filters:
query = query.filter_by(audit_id=filters['audit_id'])
if 'audit_uuid' in filters:
query = query.join(models.Audit,
models.ActionPlan.audit_id == models.Audit.id)
query = query.filter(models.Audit.uuid == filters['audit_uuid'])
return query
def _add_actions_filters(self, query, filters):
if filters is None:
filters = []
if 'action_plan_id' in filters:
query = query.filter_by(action_plan_id=filters['action_plan_id'])
if 'action_plan_uuid' in filters:
query = query.join(
models.ActionPlan,
models.Action.action_plan_id == models.ActionPlan.id)
query = query.filter(
models.ActionPlan.uuid == filters['action_plan_uuid'])
if 'audit_uuid' in filters:
stmt = model_query(models.ActionPlan).join(
models.Audit,
models.Audit.id == models.ActionPlan.audit_id)\
.filter_by(uuid=filters['audit_uuid']).subquery()
query = query.filter_by(action_plan_id=stmt.c.id)
if 'state' in filters:
query = query.filter_by(state=filters['state'])
if 'alarm' in filters:
query = query.filter_by(alarm=filters['alarm'])
return query
def get_audit_template_list(self, context, filters=None, limit=None,
marker=None, sort_key=None, sort_dir=None):
query = model_query(models.AuditTemplate)
query = self._add_audit_templates_filters(query, filters)
if not context.show_deleted:
query = query.filter_by(deleted_at=None)
return _paginate_query(models.AuditTemplate, limit, marker,
sort_key, sort_dir, query)
def create_audit_template(self, values):
# ensure defaults are present for new audit_templates
if not values.get('uuid'):
values['uuid'] = utils.generate_uuid()
audit_template = models.AuditTemplate()
audit_template.update(values)
try:
audit_template.save()
except db_exc.DBDuplicateEntry:
raise exception.AuditTemplateAlreadyExists(uuid=values['uuid'],
name=values['name'])
return audit_template
def get_audit_template_by_id(self, context, audit_template_id):
query = model_query(models.AuditTemplate)
query = query.filter_by(id=audit_template_id)
try:
audit_template = query.one()
if not context.show_deleted:
if audit_template.deleted_at is not None:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_id)
return audit_template
except exc.NoResultFound:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_id)
def get_audit_template_by_uuid(self, context, audit_template_uuid):
query = model_query(models.AuditTemplate)
query = query.filter_by(uuid=audit_template_uuid)
try:
audit_template = query.one()
if not context.show_deleted:
if audit_template.deleted_at is not None:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_uuid)
return audit_template
except exc.NoResultFound:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_uuid)
def get_audit_template_by_name(self, context, audit_template_name):
query = model_query(models.AuditTemplate)
query = query.filter_by(name=audit_template_name)
try:
audit_template = query.one()
if not context.show_deleted:
if audit_template.deleted_at is not None:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_name)
return audit_template
except exc.MultipleResultsFound:
raise exception.Conflict(
_('Multiple audit templates exist with the same name.'
' Please use the audit template uuid instead'))
except exc.NoResultFound:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_name)
def destroy_audit_template(self, audit_template_id):
session = get_session()
with session.begin():
query = model_query(models.AuditTemplate, session=session)
query = add_identity_filter(query, audit_template_id)
try:
query.one()
except exc.NoResultFound:
raise exception.AuditTemplateNotFound(node=audit_template_id)
query.delete()
def update_audit_template(self, audit_template_id, values):
if 'uuid' in values:
msg = _("Cannot overwrite UUID for an existing AuditTemplate.")
raise exception.InvalidParameterValue(err=msg)
return self._do_update_audit_template(audit_template_id, values)
def _do_update_audit_template(self, audit_template_id, values):
session = get_session()
with session.begin():
query = model_query(models.AuditTemplate, session=session)
query = add_identity_filter(query, audit_template_id)
try:
ref = query.with_lockmode('update').one()
except exc.NoResultFound:
raise exception.AuditTemplateNotFound(
audit_template=audit_template_id)
ref.update(values)
return ref
def soft_delete_audit_template(self, audit_template_id):
session = get_session()
with session.begin():
query = model_query(models.AuditTemplate, session=session)
query = add_identity_filter(query, audit_template_id)
try:
query.one()
except exc.NoResultFound:
raise exception.AuditTemplateNotFound(node=audit_template_id)
query.soft_delete()
def get_audit_list(self, context, filters=None, limit=None, marker=None,
sort_key=None, sort_dir=None):
query = model_query(models.Audit)
query = self._add_audits_filters(query, filters)
if not context.show_deleted:
query = query.filter(~(models.Audit.state == 'DELETED'))
return _paginate_query(models.Audit, limit, marker,
sort_key, sort_dir, query)
def create_audit(self, values):
# ensure defaults are present for new audits
if not values.get('uuid'):
values['uuid'] = utils.generate_uuid()
if values.get('state') is None:
values['state'] = audit_objects.AuditStatus.PENDING
audit = models.Audit()
audit.update(values)
try:
audit.save()
except db_exc.DBDuplicateEntry:
raise exception.AuditAlreadyExists(uuid=values['uuid'])
return audit
def get_audit_by_id(self, context, audit_id):
query = model_query(models.Audit)
query = query.filter_by(id=audit_id)
try:
audit = query.one()
if not context.show_deleted:
if audit.state == 'DELETED':
raise exception.AuditNotFound(audit=audit_id)
return audit
except exc.NoResultFound:
raise exception.AuditNotFound(audit=audit_id)
def get_audit_by_uuid(self, context, audit_uuid):
query = model_query(models.Audit)
query = query.filter_by(uuid=audit_uuid)
try:
audit = query.one()
if not context.show_deleted:
if audit.state == 'DELETED':
raise exception.AuditNotFound(audit=audit_uuid)
return audit
except exc.NoResultFound:
raise exception.AuditNotFound(audit=audit_uuid)
def destroy_audit(self, audit_id):
def is_audit_referenced(session, audit_id):
"""Checks whether the audit is referenced by action_plan(s)."""
query = model_query(models.ActionPlan, session=session)
query = self._add_action_plans_filters(
query, {'audit_id': audit_id})
return query.count() != 0
session = get_session()
with session.begin():
query = model_query(models.Audit, session=session)
query = add_identity_filter(query, audit_id)
try:
audit_ref = query.one()
except exc.NoResultFound:
raise exception.AuditNotFound(audit=audit_id)
if is_audit_referenced(session, audit_ref['id']):
raise exception.AuditReferenced(audit=audit_id)
query.delete()
def update_audit(self, audit_id, values):
if 'uuid' in values:
msg = _("Cannot overwrite UUID for an existing Audit.")
raise exception.InvalidParameterValue(err=msg)
return self._do_update_audit(audit_id, values)
def _do_update_audit(self, audit_id, values):
session = get_session()
with session.begin():
query = model_query(models.Audit, session=session)
query = add_identity_filter(query, audit_id)
try:
ref = query.with_lockmode('update').one()
except exc.NoResultFound:
raise exception.AuditNotFound(audit=audit_id)
ref.update(values)
return ref
def soft_delete_audit(self, audit_id):
session = get_session()
with session.begin():
query = model_query(models.Audit, session=session)
query = add_identity_filter(query, audit_id)
try:
query.one()
except exc.NoResultFound:
raise exception.AuditNotFound(node=audit_id)
query.soft_delete()
def get_action_list(self, context, filters=None, limit=None, marker=None,
sort_key=None, sort_dir=None):
query = model_query(models.Action)
query = self._add_actions_filters(query, filters)
if not context.show_deleted:
query = query.filter(~(models.Action.state == 'DELETED'))
return _paginate_query(models.Action, limit, marker,
sort_key, sort_dir, query)
def create_action(self, values):
# ensure defaults are present for new actions
if not values.get('uuid'):
values['uuid'] = utils.generate_uuid()
action = models.Action()
action.update(values)
try:
action.save()
except db_exc.DBDuplicateEntry:
raise exception.ActionAlreadyExists(uuid=values['uuid'])
return action
def get_action_by_id(self, context, action_id):
query = model_query(models.Action)
query = query.filter_by(id=action_id)
try:
action = query.one()
if not context.show_deleted:
if action.state == 'DELETED':
raise exception.ActionNotFound(
action=action_id)
return action
except exc.NoResultFound:
raise exception.ActionNotFound(action=action_id)
def get_action_by_uuid(self, context, action_uuid):
query = model_query(models.Action)
query = query.filter_by(uuid=action_uuid)
try:
action = query.one()
if not context.show_deleted:
if action.state == 'DELETED':
raise exception.ActionNotFound(
action=action_uuid)
return action
except exc.NoResultFound:
raise exception.ActionNotFound(action=action_uuid)
def destroy_action(self, action_id):
session = get_session()
with session.begin():
query = model_query(models.Action, session=session)
query = add_identity_filter(query, action_id)
count = query.delete()
if count != 1:
raise exception.ActionNotFound(action_id)
def update_action(self, action_id, values):
# NOTE(dtantsur): this can lead to very strange errors
if 'uuid' in values:
msg = _("Cannot overwrite UUID for an existing Action.")
raise exception.InvalidParameterValue(err=msg)
return self._do_update_action(action_id, values)
def _do_update_action(self, action_id, values):
session = get_session()
with session.begin():
query = model_query(models.Action, session=session)
query = add_identity_filter(query, action_id)
try:
ref = query.with_lockmode('update').one()
except exc.NoResultFound:
raise exception.ActionNotFound(action=action_id)
ref.update(values)
return ref
def soft_delete_action(self, action_id):
session = get_session()
with session.begin():
query = model_query(models.Action, session=session)
query = add_identity_filter(query, action_id)
try:
query.one()
except exc.NoResultFound:
raise exception.ActionNotFound(node=action_id)
query.soft_delete()
def get_action_plan_list(
self, context, columns=None, filters=None, limit=None,
marker=None, sort_key=None, sort_dir=None):
query = model_query(models.ActionPlan)
query = self._add_action_plans_filters(query, filters)
if not context.show_deleted:
query = query.filter(~(models.ActionPlan.state == 'DELETED'))
return _paginate_query(models.ActionPlan, limit, marker,
sort_key, sort_dir, query)
def create_action_plan(self, values):
# ensure defaults are present for new audits
if not values.get('uuid'):
values['uuid'] = utils.generate_uuid()
action_plan = models.ActionPlan()
action_plan.update(values)
try:
action_plan.save()
except db_exc.DBDuplicateEntry:
raise exception.ActionPlanAlreadyExists(uuid=values['uuid'])
return action_plan
def get_action_plan_by_id(self, context, action_plan_id):
query = model_query(models.ActionPlan)
query = query.filter_by(id=action_plan_id)
try:
action_plan = query.one()
if not context.show_deleted:
if action_plan.state == 'DELETED':
raise exception.ActionPlanNotFound(
action_plan=action_plan_id)
return action_plan
except exc.NoResultFound:
raise exception.ActionPlanNotFound(action_plan=action_plan_id)
def get_action_plan_by_uuid(self, context, action_plan__uuid):
query = model_query(models.ActionPlan)
query = query.filter_by(uuid=action_plan__uuid)
try:
action_plan = query.one()
if not context.show_deleted:
if action_plan.state == 'DELETED':
raise exception.ActionPlanNotFound(
action_plan=action_plan__uuid)
return action_plan
except exc.NoResultFound:
raise exception.ActionPlanNotFound(action_plan=action_plan__uuid)
def destroy_action_plan(self, action_plan_id):
def is_action_plan_referenced(session, action_plan_id):
"""Checks whether the action_plan is referenced by action(s)."""
query = model_query(models.Action, session=session)
query = self._add_actions_filters(
query, {'action_plan_id': action_plan_id})
return query.count() != 0
session = get_session()
with session.begin():
query = model_query(models.ActionPlan, session=session)
query = add_identity_filter(query, action_plan_id)
try:
action_plan_ref = query.one()
except exc.NoResultFound:
raise exception.ActionPlanNotFound(action_plan=action_plan_id)
if is_action_plan_referenced(session, action_plan_ref['id']):
raise exception.ActionPlanReferenced(
action_plan=action_plan_id)
query.delete()
def update_action_plan(self, action_plan_id, values):
if 'uuid' in values:
msg = _("Cannot overwrite UUID for an existing Audit.")
raise exception.InvalidParameterValue(err=msg)
return self._do_update_action_plan(action_plan_id, values)
def _do_update_action_plan(self, action_plan_id, values):
session = get_session()
with session.begin():
query = model_query(models.ActionPlan, session=session)
query = add_identity_filter(query, action_plan_id)
try:
ref = query.with_lockmode('update').one()
except exc.NoResultFound:
raise exception.ActionPlanNotFound(action_plan=action_plan_id)
ref.update(values)
return ref
def soft_delete_action_plan(self, action_plan_id):
session = get_session()
with session.begin():
query = model_query(models.ActionPlan, session=session)
query = add_identity_filter(query, action_plan_id)
try:
query.one()
except exc.NoResultFound:
raise exception.ActionPlanNotFound(node=action_plan_id)
query.soft_delete()