0dbf9a64b7
This introduces a new cloudkitty.utils module. Work items: * cloudkitty/utils.py has been moved to cloudkitty/utils/__init__.py . The import path does not change. * cloudkitty.json_utils has been moved to cloudkitty.utils.json * cloudkitty.validation_utils has been moved to cloudkitty.utils.validation * cloudkitty.tzutils has been moved to cloudkitty.utils.tz * Unit test layout has been adapted to the new utils layout Story: 2006941 Task: 37614 Change-Id: I2ba1577eb64e27c1e837ba9e20dec532b46fca8a
190 lines
6.5 KiB
Python
190 lines
6.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2018 Objectif Libre
|
|
#
|
|
# 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 oslo_config import cfg
|
|
from oslo_db.sqlalchemy import utils
|
|
from oslo_log import log
|
|
|
|
from cloudkitty import db
|
|
from cloudkitty.storage_state import migration
|
|
from cloudkitty.storage_state import models
|
|
from cloudkitty.utils import tz as tzutils
|
|
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
CONF = cfg.CONF
|
|
# NOTE(peschk_l): Required for defaults
|
|
CONF.import_opt('backend', 'cloudkitty.fetcher', 'fetcher')
|
|
CONF.import_opt('collector', 'cloudkitty.collector', 'collect')
|
|
CONF.import_opt('scope_key', 'cloudkitty.collector', 'collect')
|
|
|
|
|
|
class StateManager(object):
|
|
"""Class allowing state management in CloudKitty"""
|
|
|
|
model = models.IdentifierState
|
|
|
|
def get_all(self,
|
|
identifier=None,
|
|
fetcher=None,
|
|
collector=None,
|
|
scope_key=None,
|
|
limit=100, offset=0):
|
|
"""Returns the state of all scopes.
|
|
|
|
This function returns the state of all scopes with support for optional
|
|
filters.
|
|
|
|
:param identifier: optional scope identifiers to filter on
|
|
:type identifier: list
|
|
:param fetcher: optional scope fetchers to filter on
|
|
:type fetcher: list
|
|
:param collector: optional collectors to filter on
|
|
:type collector: list
|
|
:param fetcher: optional fetchers to filter on
|
|
:type fetcher: list
|
|
:param scope_key: optional scope_keys to filter on
|
|
:type scope_key: list
|
|
"""
|
|
session = db.get_session()
|
|
session.begin()
|
|
|
|
q = utils.model_query(self.model, session)
|
|
if identifier:
|
|
q = q.filter(self.model.identifier.in_(identifier))
|
|
if fetcher:
|
|
q = q.filter(self.model.fetcher.in_(fetcher))
|
|
if collector:
|
|
q = q.filter(self.model.collector.in_(collector))
|
|
if scope_key:
|
|
q = q.filter(self.model.scope_key.in_(scope_key))
|
|
q = q.offset(offset).limit(limit)
|
|
|
|
r = q.all()
|
|
session.close()
|
|
|
|
for item in r:
|
|
item.state = tzutils.utc_to_local(item.state)
|
|
|
|
return r
|
|
|
|
def _get_db_item(self, session, identifier,
|
|
fetcher=None, collector=None, scope_key=None):
|
|
fetcher = fetcher or CONF.fetcher.backend
|
|
collector = collector or CONF.collect.collector
|
|
scope_key = scope_key or CONF.collect.scope_key
|
|
|
|
q = utils.model_query(self.model, session)
|
|
r = q.filter(self.model.identifier == identifier). \
|
|
filter(self.model.scope_key == scope_key). \
|
|
filter(self.model.fetcher == fetcher). \
|
|
filter(self.model.collector == collector). \
|
|
first()
|
|
|
|
# In case the identifier exists with empty columns, update them
|
|
if not r:
|
|
# NOTE(peschk_l): We must use == instead of 'is' because sqlalchemy
|
|
# overloads this operator
|
|
r = q.filter(self.model.identifier == identifier). \
|
|
filter(self.model.scope_key == None). \
|
|
filter(self.model.fetcher == None). \
|
|
filter(self.model.collector == None). \
|
|
first() # noqa
|
|
if r:
|
|
r.scope_key = scope_key
|
|
r.collector = collector
|
|
r.fetcher = fetcher
|
|
LOG.info('Updating identifier "{i}" with scope_key "{sk}", '
|
|
'collector "{c}" and fetcher "{f}"'.format(
|
|
i=identifier,
|
|
sk=scope_key,
|
|
c=collector,
|
|
f=fetcher))
|
|
session.commit()
|
|
return r
|
|
|
|
def set_state(self, identifier, state,
|
|
fetcher=None, collector=None, scope_key=None):
|
|
"""Set the state of a scope.
|
|
|
|
:param identifier: Identifier of the scope
|
|
:type identifier: str
|
|
:param state: state of the scope
|
|
:type state: datetime.datetime
|
|
:param fetcher: Fetcher associated to the scope
|
|
:type fetcher: str
|
|
:param collector: Collector associated to the scope
|
|
:type collector: str
|
|
:param scope_key: scope_key associated to the scope
|
|
:type scope_key: str
|
|
"""
|
|
state = tzutils.local_to_utc(state, naive=True)
|
|
session = db.get_session()
|
|
session.begin()
|
|
r = self._get_db_item(
|
|
session, identifier, fetcher, collector, scope_key)
|
|
|
|
if r:
|
|
if r.state != state:
|
|
r.state = state
|
|
session.commit()
|
|
else:
|
|
state_object = self.model(
|
|
identifier=identifier,
|
|
state=state,
|
|
fetcher=fetcher,
|
|
collector=collector,
|
|
scope_key=scope_key,
|
|
)
|
|
session.add(state_object)
|
|
session.commit()
|
|
|
|
session.close()
|
|
|
|
def get_state(self, identifier,
|
|
fetcher=None, collector=None, scope_key=None):
|
|
"""Get the state of a scope.
|
|
|
|
:param identifier: Identifier of the scope
|
|
:type identifier: str
|
|
:param fetcher: Fetcher associated to the scope
|
|
:type fetcher: str
|
|
:param collector: Collector associated to the scope
|
|
:type collector: str
|
|
:param scope_key: scope_key associated to the scope
|
|
:type scope_key: str
|
|
:rtype: datetime.datetime
|
|
"""
|
|
session = db.get_session()
|
|
session.begin()
|
|
r = self._get_db_item(
|
|
session, identifier, fetcher, collector, scope_key)
|
|
session.close()
|
|
return tzutils.utc_to_local(r.state) if r else None
|
|
|
|
def init(self):
|
|
migration.upgrade('head')
|
|
|
|
# This is made in order to stay compatible with legacy behavior but
|
|
# shouldn't be used
|
|
def get_tenants(self, begin=None, end=None):
|
|
session = db.get_session()
|
|
session.begin()
|
|
q = utils.model_query(self.model, session)
|
|
session.close()
|
|
return [tenant.identifier for tenant in q]
|