b3bf4ec2ce
This patch provides a sample script that allows users to install or delete kubernetes on VMs in the VNF when executing instantiate/terminate/scale/heal through the kubespray ansible server. It also provides script to install and configure Load Balancer for kubernetes cluster in the VNF. When instantiating CNF with service resource whose type is `NodePort` on Kubernetes VIM deployed by kubespray, its port must be added into Load Balancer's configuration and restart it. So this patch also provides a sample MgmtDriver and shell script to fix this problem. At the same time, we found that if instantiate operation fails, after the `instantiate_end` operation, the `terminate_end` operation will not be executed in the rollback, which may cause the modification in `instantiate_end` remains in the environment, so this patch adds a `terminate_end` operation in `post_rollback_vnf`. Implements: blueprint k8s-mgmtdriver-kubespray Change-Id: I45661b5d8006e87db5f46a595756231849723ce6
221 lines
9.0 KiB
Python
221 lines
9.0 KiB
Python
# Copyright (c) 2012 OpenStack Foundation.
|
|
# 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.
|
|
|
|
from datetime import datetime
|
|
import weakref
|
|
|
|
from oslo_log import log as logging
|
|
from sqlalchemy.orm import exc as orm_exc
|
|
from sqlalchemy import sql
|
|
|
|
from tacker._i18n import _
|
|
from tacker.common import exceptions as n_exc
|
|
from tacker.db import sqlalchemyutils
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class CommonDbMixin(object):
|
|
"""Common methods used in core and service plugins."""
|
|
# Plugins, mixin classes implementing extension will register
|
|
# hooks into the dict below for "augmenting" the "core way" of
|
|
# building a query for retrieving objects from a model class.
|
|
# To this aim, the register_model_query_hook and unregister_query_hook
|
|
# from this class should be invoked
|
|
_model_query_hooks = {}
|
|
|
|
# This dictionary will store methods for extending attributes of
|
|
# api resources. Mixins can use this dict for adding their own methods
|
|
# TODO(salvatore-orlando): Avoid using class-level variables
|
|
_dict_extend_functions = {}
|
|
|
|
@classmethod
|
|
def register_model_query_hook(cls, model, name, query_hook, filter_hook,
|
|
result_filters=None):
|
|
"""Register a hook to be invoked when a query is executed.
|
|
|
|
Add the hooks to the _model_query_hooks dict. Models are the keys
|
|
of this dict, whereas the value is another dict mapping hook names to
|
|
callables performing the hook.
|
|
Each hook has a "query" component, used to build the query expression
|
|
and a "filter" component, which is used to build the filter expression.
|
|
|
|
Query hooks take as input the query being built and return a
|
|
transformed query expression.
|
|
|
|
Filter hooks take as input the filter expression being built and return
|
|
a transformed filter expression
|
|
"""
|
|
model_hooks = cls._model_query_hooks.get(model)
|
|
if not model_hooks:
|
|
# add key to dict
|
|
model_hooks = {}
|
|
cls._model_query_hooks[model] = model_hooks
|
|
model_hooks[name] = {'query': query_hook, 'filter': filter_hook,
|
|
'result_filters': result_filters}
|
|
|
|
@property
|
|
def safe_reference(self):
|
|
"""Return a weakref to the instance.
|
|
|
|
Minimize the potential for the instance persisting
|
|
unnecessarily in memory by returning a weakref proxy that
|
|
won't prevent deallocation.
|
|
"""
|
|
return weakref.proxy(self)
|
|
|
|
def _model_query(self, context, model):
|
|
query = context.session.query(model)
|
|
# define basic filter condition for model query
|
|
# NOTE(jkoelker) non-admin queries are scoped to their tenant_id
|
|
# NOTE(salvatore-orlando): unless the model allows for shared objects
|
|
query_filter = None
|
|
if not context.is_admin and hasattr(model, 'tenant_id'):
|
|
if hasattr(model, 'shared'):
|
|
query_filter = ((model.tenant_id == context.tenant_id) |
|
|
(model.shared == sql.true()))
|
|
else:
|
|
query_filter = (model.tenant_id == context.tenant_id)
|
|
|
|
# Execute query hooks registered from mixins and plugins
|
|
model_hooks = self._model_query_hooks.get(model, {})
|
|
for _name, hooks in model_hooks.items():
|
|
query_hook = hooks.get('query')
|
|
if isinstance(query_hook, str):
|
|
query_hook = getattr(self, query_hook, None)
|
|
if query_hook:
|
|
query = query_hook(context, model, query)
|
|
|
|
filter_hook = hooks.get('filter')
|
|
if isinstance(filter_hook, str):
|
|
filter_hook = getattr(self, filter_hook, None)
|
|
if filter_hook:
|
|
query_filter = filter_hook(context, model, query_filter)
|
|
|
|
# NOTE(salvatore-orlando): 'if query_filter' will try to evaluate the
|
|
# condition, raising an exception
|
|
if query_filter is not None:
|
|
query = query.filter(query_filter)
|
|
|
|
# Don't list the deleted entries
|
|
if hasattr(model, 'deleted_at'):
|
|
query = query.filter_by(deleted_at=datetime.min)
|
|
|
|
return query
|
|
|
|
def _fields(self, resource, fields):
|
|
if fields:
|
|
return dict(((key, item) for key, item in resource.items()
|
|
if key in fields))
|
|
return resource
|
|
|
|
def _get_tenant_id_for_create(self, context, resource):
|
|
if context.is_admin and 'tenant_id' in resource:
|
|
tenant_id = resource['tenant_id']
|
|
elif ('tenant_id' in resource and
|
|
resource['tenant_id'] != context.tenant_id):
|
|
reason = _('Cannot create resource for another tenant')
|
|
raise n_exc.AdminRequired(reason=reason)
|
|
else:
|
|
tenant_id = context.tenant_id
|
|
return tenant_id
|
|
|
|
def _get_by_id(self, context, model, id):
|
|
query = self._model_query(context, model)
|
|
return query.filter(model.id == id).one()
|
|
|
|
def _apply_filters_to_query(self, query, model, filters):
|
|
if filters:
|
|
for key, value in filters.items():
|
|
column = getattr(model, key, None)
|
|
if column:
|
|
query = query.filter(column.in_([value]))
|
|
model_hooks = self._model_query_hooks.get(model, {})
|
|
for _name, hooks in model_hooks.items():
|
|
result_filter = hooks.get('result_filters', None)
|
|
if isinstance(result_filter, str):
|
|
result_filter = getattr(self, result_filter, None)
|
|
|
|
if result_filter:
|
|
query = result_filter(query, filters)
|
|
|
|
return query
|
|
|
|
def _apply_dict_extend_functions(self, resource_type,
|
|
response, db_object):
|
|
for func in self._dict_extend_functions.get(
|
|
resource_type, []):
|
|
args = (response, db_object)
|
|
if isinstance(func, str):
|
|
func = getattr(self, func, None)
|
|
else:
|
|
# must call unbound method - use self as 1st argument
|
|
args = (self,) + args
|
|
if func:
|
|
func(*args)
|
|
|
|
def _get_collection_query(self, context, model, filters=None,
|
|
sorts=None, limit=None, marker_obj=None,
|
|
page_reverse=False):
|
|
collection = self._model_query(context, model)
|
|
collection = self._apply_filters_to_query(collection, model, filters)
|
|
if limit and page_reverse and sorts:
|
|
sorts = [(s[0], not s[1]) for s in sorts]
|
|
collection = sqlalchemyutils.paginate_query(collection, model, limit,
|
|
sorts,
|
|
marker_obj=marker_obj)
|
|
return collection
|
|
|
|
def _get_collection(self, context, model, dict_func, filters=None,
|
|
fields=None, sorts=None, limit=None, marker_obj=None,
|
|
page_reverse=False):
|
|
query = self._get_collection_query(context, model, filters=filters,
|
|
sorts=sorts,
|
|
limit=limit,
|
|
marker_obj=marker_obj,
|
|
page_reverse=page_reverse)
|
|
items = [dict_func(c, fields) for c in query]
|
|
if limit and page_reverse:
|
|
items.reverse()
|
|
return items
|
|
|
|
def _get_collection_count(self, context, model, filters=None):
|
|
return self._get_collection_query(context, model, filters).count()
|
|
|
|
def _get_marker_obj(self, context, resource, limit, marker):
|
|
if limit and marker:
|
|
return getattr(self, '_get_%s' % resource)(context, marker)
|
|
return None
|
|
|
|
def _filter_non_model_columns(self, data, model):
|
|
"""Removes attributes from data.
|
|
|
|
Remove all the attributes from data which are not columns of
|
|
the model passed as second parameter.
|
|
"""
|
|
columns = [c.name for c in model.__table__.columns]
|
|
return dict((k, v) for (k, v) in data.items() if k in columns)
|
|
|
|
def _get_by_name(self, context, model, name):
|
|
try:
|
|
query = self._model_query(context, model)
|
|
return query.filter(model.name == name).one()
|
|
except orm_exc.NoResultFound:
|
|
LOG.info("No result found for %(name)s in %(model)s table",
|
|
{'name': name, 'model': model})
|
|
|
|
def get_by_name(self, context, model, name):
|
|
return self._get_by_name(context, model, name)
|