trove/trove/configuration/models.py

398 lines
14 KiB
Python

# Copyright 2014 Rackspace
# All Rights Reserved.
#
# 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 json
from oslo_log import log as logging
from trove.common import cfg
from trove.common import exception
from trove.common.exception import ModelNotFoundError
from trove.common.i18n import _
from trove.common import timeutils
from trove.common import utils
from trove.datastore import models as dstore_models
from trove.db import get_db_api
from trove.db import models as dbmodels
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
class Configurations(object):
DEFAULT_LIMIT = CONF.configurations_page_size
@staticmethod
def load(context):
if context is None:
raise TypeError(_("Argument context not defined."))
elif id is None:
raise TypeError(_("Argument is not defined."))
if context.is_admin:
db_info = DBConfiguration.find_all(deleted=False)
if db_info.count() == 0:
LOG.debug("No configurations found for admin user")
else:
db_info = DBConfiguration.find_all(tenant_id=context.project_id,
deleted=False)
if db_info.count() == 0:
LOG.debug("No configurations found for tenant %s",
context.project_id)
limit = utils.pagination_limit(context.limit,
Configurations.DEFAULT_LIMIT)
data_view = DBConfiguration.find_by_pagination('configurations',
db_info,
"foo",
limit=limit,
marker=context.marker)
next_marker = data_view.next_page_marker
return data_view.collection, next_marker
class Configuration(object):
def __init__(self, context, configuration_id):
self.context = context
self.configuration_id = configuration_id
@property
def instances(self):
return self.instances
@property
def items(self):
return self.items
@staticmethod
def create(name, description, tenant_id, datastore, datastore_version):
configurationGroup = DBConfiguration.create(
name=name,
description=description,
tenant_id=tenant_id,
datastore_version_id=datastore_version)
return configurationGroup
@staticmethod
def create_items(cfg_id, values):
LOG.debug("Saving configuration values for %(id)s - "
"values: %(values)s", {'id': cfg_id, 'values': values})
config_items = []
for key, val in values.items():
config_item = DBConfigurationParameter.create(
configuration_id=cfg_id,
configuration_key=key,
configuration_value=val)
config_items.append(config_item)
return config_items
@staticmethod
def delete(context, group):
deleted_at = timeutils.utcnow()
Configuration.remove_all_items(context, group.id, deleted_at)
group.deleted = True
group.deleted_at = deleted_at
group.save()
@staticmethod
def remove_all_items(context, id, deleted_at):
items = DBConfigurationParameter.find_all(configuration_id=id,
deleted=False).all()
LOG.debug("Removing all configuration values for %s", id)
for item in items:
item.deleted = True
item.deleted_at = deleted_at
item.save()
@staticmethod
def load_configuration_datastore_version(context, id):
config = Configuration.load(context, id)
datastore_version = dstore_models.DatastoreVersion.load_by_uuid(
config.datastore_version_id)
return datastore_version
@staticmethod
def load(context, id):
try:
if context.is_admin:
return DBConfiguration.find_by(id=id, deleted=False)
else:
return DBConfiguration.find_by(id=id,
tenant_id=context.project_id,
deleted=False)
except ModelNotFoundError:
msg = _("Configuration group with ID %s could not be found.") % id
raise ModelNotFoundError(msg)
@staticmethod
def find_parameter_details(name, detail_list):
for item in detail_list:
if item.name == name:
return item
return None
@staticmethod
def load_items(context, id):
datastore_v = Configuration.load_configuration_datastore_version(
context,
id)
config_items = DBConfigurationParameter.find_all(
configuration_id=id, deleted=False).all()
detail_list = DatastoreConfigurationParameters.load_parameters(
datastore_v.id)
for item in config_items:
rule = Configuration.find_parameter_details(
str(item.configuration_key), detail_list)
if not rule:
continue
if rule.data_type == 'boolean':
item.configuration_value = bool(int(item.configuration_value))
elif rule.data_type == 'integer':
item.configuration_value = int(item.configuration_value)
else:
item.configuration_value = str(item.configuration_value)
return config_items
def get_configuration_overrides(self):
"""Gets the overrides dictionary to apply to an instance."""
overrides = {}
if self.configuration_id:
config_items = Configuration.load_items(self.context,
id=self.configuration_id)
for i in config_items:
overrides[i.configuration_key] = i.configuration_value
return overrides
def does_configuration_need_restart(self):
datastore_v = Configuration.load_configuration_datastore_version(
self.context,
self.configuration_id)
config_items = Configuration.load_items(self.context,
id=self.configuration_id)
LOG.debug("config_items: %s", config_items)
detail_list = DatastoreConfigurationParameters.load_parameters(
datastore_v.id)
for i in config_items:
LOG.debug("config item: %s", i)
details = Configuration.find_parameter_details(
i.configuration_key, detail_list)
LOG.debug("parameter details: %s", details)
if not details:
raise exception.NotFound(uuid=i.configuration_key)
if bool(details.restart_required):
return True
return False
@staticmethod
def save(configuration, configuration_items):
DBConfiguration.save(configuration)
for item in configuration_items:
item["deleted_at"] = None
DBConfigurationParameter.save(item)
@staticmethod
def find(context, configuration_id, datastore_version_id):
try:
info = Configuration.load(context, configuration_id)
if (info.datastore_version_id == datastore_version_id):
return Configuration(context, configuration_id)
except exception.ModelNotFoundError:
raise exception.NotFound(
message='Configuration group id: %s could not be found.'
% configuration_id)
raise exception.ConfigurationDatastoreNotMatchInstance(
config_datastore_version=info.datastore_version_id,
instance_datastore_version=datastore_version_id)
class DBConfiguration(dbmodels.DatabaseModelBase):
_data_fields = ['name', 'description', 'tenant_id', 'datastore_version_id',
'deleted', 'deleted_at', 'created', 'updated']
_table_name = 'configurations'
@property
def datastore(self):
datastore_version = dstore_models.DatastoreVersion.load_by_uuid(
self.datastore_version_id)
datastore = dstore_models.Datastore.load(
datastore_version.datastore_id)
return datastore
@property
def datastore_version(self):
datastore_version = dstore_models.DatastoreVersion.load_by_uuid(
self.datastore_version_id)
return datastore_version
class DBConfigurationParameter(dbmodels.DatabaseModelBase):
_auto_generated_attrs = []
_data_fields = ['configuration_id', 'configuration_key',
'configuration_value', 'deleted',
'deleted_at']
_table_name = 'configuration_parameters'
def __hash__(self):
return self.configuration_key.__hash__()
class DBDatastoreConfigurationParameters(dbmodels.DatabaseModelBase):
"""Model for storing the configuration parameters on a datastore."""
_data_fields = [
'name',
'datastore_version_id',
'restart_required',
'max_size',
'min_size',
'data_type',
]
_table_name = "datastore_configuration_parameters"
class DatastoreConfigurationParameters(object):
def __init__(self, db_info):
self.db_info = db_info
@staticmethod
def create(**kwargs):
"""Create a configuration parameter for a datastore version."""
# Do we already have a parameter in the db?
# yes: and its deleted then modify the param
# yes: and its not deleted then error on create.
# no: then just create the new param
ds_v_id = kwargs.get('datastore_version_id')
config_param_name = kwargs.get('name')
try:
DatastoreConfigurationParameters.load_parameter_by_name(
ds_v_id,
config_param_name)
raise exception.ConfigurationParameterAlreadyExists(
parameter_name=config_param_name,
datastore_version=ds_v_id)
except exception.NotFound:
pass
config_param = DBDatastoreConfigurationParameters.create(
**kwargs)
return config_param
@staticmethod
def delete(version_id, config_param_name):
config_param = DatastoreConfigurationParameters.load_parameter_by_name(
version_id, config_param_name)
config_param.delete()
@classmethod
def load_parameters(cls, datastore_version_id):
return DBDatastoreConfigurationParameters.find_all(
datastore_version_id=datastore_version_id)
@classmethod
def load_parameter(cls, config_id):
try:
return DBDatastoreConfigurationParameters.find_by(
id=config_id, deleted=False
)
except exception.NotFound:
raise exception.NotFound(uuid=config_id)
@classmethod
def load_parameter_by_name(cls, datastore_version_id, config_param_name):
try:
return DBDatastoreConfigurationParameters.find_by(
datastore_version_id=datastore_version_id,
name=config_param_name
)
except exception.NotFound:
raise exception.NotFound(uuid=config_param_name)
def create_or_update_datastore_configuration_parameter(name,
datastore_version_id,
restart_required,
data_type,
max_size,
min_size):
get_db_api().configure_db(CONF)
datastore_version = dstore_models.DatastoreVersion.load_by_uuid(
datastore_version_id)
try:
config = DatastoreConfigurationParameters.load_parameter_by_name(
datastore_version_id, name)
config.restart_required = restart_required
config.max_size = max_size
config.min_size = min_size
config.data_type = data_type
get_db_api().save(config)
except exception.NotFound:
config = DBDatastoreConfigurationParameters(
id=utils.generate_uuid(),
name=name,
datastore_version_id=datastore_version.id,
restart_required=restart_required,
data_type=data_type,
max_size=max_size,
min_size=min_size,
)
get_db_api().save(config)
def load_datastore_configuration_parameters(datastore, datastore_version,
config_file, version_number=None):
get_db_api().configure_db(CONF)
(ds, ds_v) = dstore_models.get_datastore_version(
type=datastore, version=datastore_version, return_inactive=True,
version_number=version_number)
with open(config_file) as f:
config = json.load(f)
for param in config['configuration-parameters']:
create_or_update_datastore_configuration_parameter(
param['name'],
ds_v.id,
param['restart_required'],
param['type'],
param.get('max'),
param.get('min'),
)
def remove_datastore_configuration_parameters(datastore, datastore_version,
version_number=None):
get_db_api().configure_db(CONF)
(ds, ds_version) = dstore_models.get_datastore_version(
type=datastore, version=datastore_version, return_inactive=True,
version_number=version_number)
db_params = DatastoreConfigurationParameters.load_parameters(ds_version.id)
for db_param in db_params:
db_param.delete()
def persisted_models():
return {
'configurations': DBConfiguration,
'configuration_parameters': DBConfigurationParameter,
'datastore_configuration_parameters':
DBDatastoreConfigurationParameters,
}