masakari-dashboard/masakaridashboard/api/api.py
Pavlo Shchelokovskyy 57610fce4b Use service list instead of hypervisor list
the host names in them are not necessarily the same,
and Masakari service itself validates the input against
the nova service list, not hypervisor list,
since change I9c591d33f17a8d5950bdb1fc2d686e2301fc6d95 in Masakari.

Closes-Bug: #1944679
Change-Id: Id017b91c59aff54435c35d410fcb56a086a732ef
(cherry picked from commit 021d1c184e)
(cherry picked from commit fae46199bb)
(cherry picked from commit a879b6bbfb)
2021-09-24 16:00:40 +00:00

238 lines
8.0 KiB
Python

# Copyright (C) 2018 NTT DATA
# 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 itertools
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from horizon.utils import functions as utils
from horizon.utils import memoized
from keystoneauth1.identity.generic import token
from keystoneauth1 import session as ks_session
from masakariclient import api_versions
from masakariclient import plugin
from openstack import connection
from openstack_dashboard.api import nova as nova_api
from masakaridashboard.handle_errors import handle_errors
MICROVERSION_FEATURES = {"recovery_workflow_details": ["1.1"]}
@memoized.memoized
def openstack_connection(request, version=None):
interface = getattr(settings, 'OPENSTACK_ENDPOINT_TYPE', 'publicURL')
auth = token.Token(
auth_url=getattr(settings, 'OPENSTACK_KEYSTONE_URL'),
token=request.user.token.id,
project_name=request.user.project_name,
project_id=request.user.tenant_id)
cacert = getattr(settings, 'OPENSTACK_SSL_CACERT')
session = ks_session.Session(auth=auth, verify=cacert or True)
conn = connection.Connection(session=session,
interface=interface,
ha_api_version=version)
return conn.instance_ha
def get_compute_service_list(request):
return nova_api.service_list(request, binary="nova-compute")
@handle_errors(_("Unable to retrieve segments"), [])
def get_segment_list(request, marker='', paginate=False, filters=None):
"""Returns segments as per page size."""
page_size = utils.get_page_size(request)
client = openstack_connection(request)
kwargs = get_request_param(marker, paginate, filters, page_size)
entities_iter = client.segments(**kwargs)
has_prev_data = has_more_data = False
if paginate:
entities, has_more_data, has_prev_data = pagination_process(
entities_iter, kwargs['limit'], page_size, marker)
else:
entities = list(entities_iter)
return entities, has_more_data, has_prev_data
def get_request_param(marker, paginate, filters, page_size):
limit = getattr(settings, 'API_RESULT_LIMIT', 100)
if paginate:
request_size = page_size + 1
else:
request_size = limit
kwargs = {"marker": marker,
"limit": request_size
}
if filters is not None:
kwargs.update(filters)
return kwargs
def pagination_process(data, request_size, page_size, marker):
"""Retrieve a listing of specific entity and handles pagination.
:param request: Request data
:param marker: Pagination marker for large data sets: entity id
:param paginate: If true will perform pagination based on settings.
Default:False
"""
prev_data = more_data = False
entities = list(itertools.islice(data, request_size))
# first and middle page condition
if len(entities) > page_size:
entities.pop()
more_data = True
# middle page condition
if marker is not None:
prev_data = True
elif marker is not None:
prev_data = True
return entities, more_data, prev_data
@handle_errors(_("Unable to retrieve segments"), [])
def segment_list(request):
return list(openstack_connection(request).segments())
def segment_create(request, data):
"""Create segment."""
return openstack_connection(request).create_segment(**data)
@handle_errors(_("Unable to retrieve segment"), [])
def get_segment(request, segment_id):
"""Returns segment by id"""
return openstack_connection(request).get_segment(segment_id)
@handle_errors(_("Unable to delete segment"), [])
def segment_delete(request, segment_id, ignore_missing=True):
return openstack_connection(request).delete_segment(
segment_id, ignore_missing)
@handle_errors(_("Unable to update segment"), [])
def segment_update(request, segment_id, fields_to_update):
"""Update segment."""
return openstack_connection(request).update_segment(
segment_id, **fields_to_update)
def create_host(request, data):
"""Create Host."""
attrs = {'name': data['name'],
'reserved': data['reserved'],
'type': data['type'],
'control_attributes': data['control_attributes'],
'on_maintenance': data['on_maintenance']}
return openstack_connection(request).create_host(
data['segment_id'], **attrs)
@handle_errors(_("Unable to get host list"), [])
def get_host_list(request, segment_id, filters):
"""Returns host list."""
return openstack_connection(request).hosts(segment_id, **filters)
def delete_host(request, host_id, segment_id):
return openstack_connection(request).delete_host(
host_id, segment_id, False)
def update_host(request, host_uuid, failover_segment_id, fields_to_update):
return openstack_connection(request).update_host(
host_uuid, failover_segment_id, **fields_to_update)
def get_host(request, host_id, segment_id):
"""return single host """
return openstack_connection(request).get_host(host_id, segment_id)
def notification_list(request, filters=None, marker='', paginate=False):
"""return notifications list """
page_size = utils.get_page_size(request)
kwargs = get_request_param(marker, paginate, filters, page_size)
entities_iter = openstack_connection(request).notifications(**kwargs)
has_prev_data = has_more_data = False
if paginate:
entities, has_more_data, has_prev_data = pagination_process(
entities_iter, kwargs['limit'], page_size, marker)
else:
entities = list(entities_iter)
return entities, has_more_data, has_prev_data
def get_notification(request, notification_id):
"""return single notifications"""
return openstack_connection(request).get_notification(notification_id)
def get_requested_versions(features):
if not features:
return None
# Convert a single feature string into a list for backward compatibility.
if isinstance(features, str):
features = [features]
service_features = MICROVERSION_FEATURES
feature_versions = set(service_features[features[0]])
for feature in features[1:]:
feature_versions &= set(service_features[feature])
if not feature_versions:
return None
# Sort version candidates from larger versins
feature_versions = sorted(feature_versions, reverse=True,
key=lambda v: [int(i) for i in v.split('.')])
return feature_versions
def get_microversion_for_features(features, wrapper_class, min_ver, max_ver):
"""Retrieves that highest known functional microversion for features"""
feature_versions = get_requested_versions(features)
if not feature_versions:
return None
for version in feature_versions:
microversion = wrapper_class(version)
if microversion.matches(min_ver, max_ver):
return microversion
return None
@memoized.memoized
def get_microversion(features):
min_ver = api_versions.APIVersion(plugin.SUPPORTED_VERSIONS[1])
max_ver = api_versions.APIVersion(plugin.SUPPORTED_VERSIONS[-1])
return (get_microversion_for_features(
features, api_versions.APIVersion, min_ver, max_ver))
def get_notification_with_progress_details(request, notification_id):
microversion = get_microversion("recovery_workflow_details")
return openstack_connection(
request, version=microversion.get_string()).get_notification(
notification_id)