fuel-web/nailgun/nailgun/objects/openstack_config.py

129 lines
4.4 KiB
Python

# Copyright 2015 Mirantis, Inc.
#
# 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 nailgun import consts
from nailgun.db import db
from nailgun.db.sqlalchemy import models
from nailgun import errors
from nailgun.objects import NailgunCollection
from nailgun.objects import NailgunObject
from nailgun.objects.serializers.openstack_config \
import OpenstackConfigSerializer
class OpenstackConfig(NailgunObject):
model = models.OpenstackConfig
serializer = OpenstackConfigSerializer
@classmethod
def create(cls, data):
data['config_type'] = cls._get_config_type(data)
data['is_active'] = True
filters = data.copy()
filters.pop('configuration')
config = OpenstackConfigCollection.filter_by(None, **filters).first()
if config:
cls.disable(config)
return super(OpenstackConfig, cls).create(data)
@classmethod
def disable(cls, instance):
"""Disables configuration.
It is required to track history of previous configurations.
This why disable operation doesn't remove a record from the database,
it sets `is_active` property to False.
"""
if not instance.is_active:
raise errors.CannotUpdate(
"Configuration '{0}' has been already disabled.".format(
instance.id))
instance.is_active = False
db().flush()
@classmethod
def _get_config_type(cls, data):
if data.get('node_id'):
return consts.OPENSTACK_CONFIG_TYPES.node
if data.get('node_role'):
return consts.OPENSTACK_CONFIG_TYPES.role
return consts.OPENSTACK_CONFIG_TYPES.cluster
@classmethod
def disable_by_nodes(cls, nodes):
"""Disactivate all active configurations for specified nodes."""
node_ids = [n.id for n in nodes]
(db().query(cls.model)
.filter_by(
config_type=consts.OPENSTACK_CONFIG_TYPES.node,
is_active=True)
.filter(models.OpenstackConfig.node_id.in_(node_ids))
.update({models.OpenstackConfig.is_active: False},
synchronize_session=False))
class OpenstackConfigCollection(NailgunCollection):
single = OpenstackConfig
@classmethod
def create(cls, data):
configs = []
# If node_ids list is passed, separate OpenstackConfig object
# should be created for each node. For global config (cluster scope or
# specific role scope) single config record is created
# with node_id=None.
node_ids = data.pop('node_ids', [None])
for node_id in node_ids:
config_data = dict(data, node_id=node_id)
configs.append(cls.single.create(config_data))
return configs
@classmethod
def find_configs_for_nodes(cls, cluster, nodes):
"""Returns list of configurations that should be applied.
Returns list of configurations for specified nodes that will be
applied. List is sorted by the config_type and node_role fields.
"""
configs_query = cls.filter_by(
None, cluster_id=cluster.id, is_active=True)
configs_query = configs_query.order_by(cls.single.model.created_at)
node_ids = set(n.id for n in nodes)
node_roles = set()
for node in nodes:
node_roles.update(node.roles)
configs = []
for config in configs_query:
if config.config_type == consts.OPENSTACK_CONFIG_TYPES.cluster:
configs.append(config)
elif (config.config_type == consts.OPENSTACK_CONFIG_TYPES.node and
config.node_id in node_ids):
configs.append(config)
elif (config.config_type ==
consts.OPENSTACK_CONFIG_TYPES.role and
config.node_role in node_roles):
configs.append(config)
return configs