Takashi Kajinami 366540033f Bump hacking
hacking 3.0.x is too old. Bump it to the latest version available.

Also remove the note about old pip's behavior because recent pip does
not require specific order.

Change-Id: Ib84f9138bc2b908ce1a76c3dad501328326ffe99
2024-11-17 00:37:12 +09:00

342 lines
14 KiB
Python

# Copyright 2016 - Nokia
#
# 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 queue
import time
from oslo_config import cfg
from testtools import matchers
from vitrage.common.constants import EntityCategory
from vitrage.common.constants import VertexProperties as VProps
from vitrage.datasources.nova.instance import NOVA_INSTANCE_DATASOURCE
from vitrage.entity_graph.consistency.consistency_enforcer \
import ConsistencyEnforcer
from vitrage.entity_graph.processor.processor import Processor
from vitrage.evaluator.scenario_evaluator import ScenarioEvaluator
from vitrage.evaluator.scenario_repository import ScenarioRepository
from vitrage.graph.driver.networkx_graph import NXGraph
from vitrage.tests.functional.base import TestFunctionalBase
from vitrage.tests.functional.test_configuration import TestConfiguration
from vitrage.tests.mocks import utils
from vitrage.utils import datetime
# noinspection PyProtectedMember
class TestConsistencyFunctional(TestFunctionalBase, TestConfiguration):
CONSISTENCY_OPTS = [
cfg.IntOpt('min_time_to_delete',
default=1,
min=1),
]
EVALUATOR_OPTS = [
cfg.StrOpt('templates_dir',
default=utils.get_resources_dir() +
'/templates/consistency',
),
cfg.StrOpt('equivalences_dir',
default='equivalences',
),
cfg.StrOpt('notifier_topic',
default='vitrage.evaluator',
),
]
def setUp(self):
super(TestConsistencyFunctional, self).setUp()
self.conf_reregister_opts(self.CONSISTENCY_OPTS, 'consistency')
self.conf_reregister_opts(self.EVALUATOR_OPTS, 'evaluator')
self.add_db()
self.load_datasources()
self.graph = NXGraph("Entity Graph")
self.processor = Processor(self.graph)
self.event_queue = queue.Queue()
def actions_callback(event_type, data):
"""Mock notify method
Mocks vitrage.messaging.VitrageNotifier.notify(event_type, data)
:param event_type: is currently always the same and is ignored
:param data:
"""
self.event_queue.put(data)
def actions_callback_consistency(data):
for e in data:
self.event_queue.put(e)
scenario_repo = ScenarioRepository()
self.evaluator = ScenarioEvaluator(self.processor.entity_graph,
scenario_repo,
actions_callback)
self.consistency_enforcer = ConsistencyEnforcer(
self.processor.entity_graph,
actions_callback_consistency)
def test_periodic_process(self):
# Setup
consistency_interval = self.conf.datasources.snapshots_interval
self._periodic_process_setup_stage(consistency_interval)
self._add_alarms_by_type(consistency_interval=consistency_interval,
alarm_type='prometheus')
# Action
time.sleep(2 * consistency_interval + 1)
self.consistency_enforcer.periodic_process()
self._process_events()
# Test Assertions
instance_vertices = self.processor.entity_graph.get_vertices({
VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
VProps.VITRAGE_TYPE: NOVA_INSTANCE_DATASOURCE
})
deleted_instance_vertices = \
self.processor.entity_graph.get_vertices({
VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
VProps.VITRAGE_TYPE: NOVA_INSTANCE_DATASOURCE,
VProps.VITRAGE_IS_DELETED: True
})
self.assertThat(instance_vertices,
matchers.HasLength(self.NUM_INSTANCES - 3))
# number of resources:
# number of vertices - 3 (deleted instances)
# number of nics - 1
# number of volumes - 1
# number of prometheus alarms - 1
self.assertThat(self.processor.entity_graph.get_vertices(),
matchers.HasLength(
# 3 instances deleted
self._num_total_expected_vertices() - 3 +
3 - 1 + # one nic deleted
3 - 1 + # one cinder.volume deleted
3 - 1) # one prometheus deleted
)
self.assertThat(deleted_instance_vertices, matchers.HasLength(3))
# one nic was deleted, one marked as deleted, one untouched
# same for cinder.volume
self._assert_vertices_status(EntityCategory.RESOURCE, 'nic', 2, 1)
self._assert_vertices_status(
EntityCategory.RESOURCE, 'cinder.volume', 2, 1)
# one prometheus deleted, other two are untouched
# prometheus vertices should not be marked as deleted, since the
# datasource did not ask to delete outdated vertices.
self._assert_vertices_status(EntityCategory.ALARM, 'prometheus', 2, 0)
def test_should_delete_vertex(self):
# should be deleted because the static datasource asks to delete its
# outdated vertices
static_vertex = {VProps.VITRAGE_DATASOURCE_NAME: 'static'}
self.assertTrue(
self.consistency_enforcer._should_delete_vertex(static_vertex))
# should be deleted because the cinder datasource asks to delete its
# outdated vertices
volume_vertex = {VProps.VITRAGE_DATASOURCE_NAME: 'cinder.volume'}
self.assertTrue(
self.consistency_enforcer._should_delete_vertex(volume_vertex))
# should not be deleted because the prometheus datasource does not ask
# to delete its outdated vertices
prometheus_vertex = {VProps.VITRAGE_DATASOURCE_NAME: 'prometheus'}
self.assertFalse(
self.consistency_enforcer._should_delete_vertex(prometheus_vertex))
# should be deleted because it is a placeholder
placeholder_vertex = {VProps.VITRAGE_IS_PLACEHOLDER: True,
VProps.VITRAGE_TYPE: 'prometheus'}
self.assertTrue(self.consistency_enforcer.
_should_delete_vertex(placeholder_vertex))
# should not be deleted because it is an openstack.cluster
cluster_vertex = {VProps.VITRAGE_IS_PLACEHOLDER: True,
VProps.VITRAGE_TYPE: 'openstack.cluster'}
self.assertFalse(self.consistency_enforcer._should_delete_vertex(
cluster_vertex))
vertices = [static_vertex, volume_vertex, prometheus_vertex,
placeholder_vertex, cluster_vertex]
vertices_to_mark_deleted = self.consistency_enforcer.\
_filter_vertices_to_be_marked_as_deleted(vertices)
self.assertThat(vertices_to_mark_deleted, matchers.HasLength(3))
self.assertIn(static_vertex, vertices_to_mark_deleted)
self.assertIn(placeholder_vertex, vertices_to_mark_deleted)
self.assertIn(volume_vertex, vertices_to_mark_deleted)
self.assertNotIn(prometheus_vertex, vertices_to_mark_deleted)
self.assertNotIn(cluster_vertex, vertices_to_mark_deleted)
def _assert_vertices_status(self, category, vitrage_type,
num_vertices, num_marked_deleted):
vertices = \
self.processor.entity_graph.get_vertices({
VProps.VITRAGE_CATEGORY: category,
VProps.VITRAGE_TYPE: vitrage_type,
})
self.assertThat(vertices, matchers.HasLength(num_vertices))
marked_deleted_vertices = \
self.processor.entity_graph.get_vertices({
VProps.VITRAGE_CATEGORY: category,
VProps.VITRAGE_TYPE: vitrage_type,
VProps.VITRAGE_IS_DELETED: True
})
self.assertThat(marked_deleted_vertices,
matchers.HasLength(num_marked_deleted))
def _periodic_process_setup_stage(self, consistency_interval):
self._create_processor_with_graph(processor=self.processor)
current_timestamp = datetime.utcnow()
current_time = str(datetime.datetime_delta(0, current_timestamp))
time_1_5 = str(datetime.datetime_delta(
1 * consistency_interval, current_timestamp))
time_2 = str(datetime.datetime_delta(
2 * consistency_interval + 1, current_timestamp))
# set all vertices to be have timestamp that consistency won't get
self._update_timestamp(
self.processor.entity_graph.get_vertices(),
time_1_5)
# check number of instances in graph
instance_vertices = self.processor.entity_graph.get_vertices({
VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
VProps.VITRAGE_TYPE: NOVA_INSTANCE_DATASOURCE
})
self.assertThat(instance_vertices,
matchers.HasLength(self.NUM_INSTANCES))
# set current timestamp of part of the instances
self._update_timestamp(instance_vertices[0:3], current_time)
# set part of the instances as deleted
for i in range(3, 6):
instance_vertices[i][VProps.VITRAGE_IS_DELETED] = True
self.processor.entity_graph.update_vertex(instance_vertices[i])
# set part of the instances as deleted
for i in range(6, 9):
instance_vertices[i][VProps.VITRAGE_IS_DELETED] = True
instance_vertices[i][VProps.VITRAGE_SAMPLE_TIMESTAMP] = time_2
self.processor.entity_graph.update_vertex(instance_vertices[i])
self._add_resources_by_type(consistency_interval=consistency_interval,
datasource_name='static',
resource_type='nic')
self._add_resources_by_type(consistency_interval=consistency_interval,
datasource_name='cinder.volume',
resource_type='cinder.volume')
def _update_timestamp(self, lst, timestamp):
for vertex in lst:
vertex[VProps.VITRAGE_SAMPLE_TIMESTAMP] = str(timestamp)
self.processor.entity_graph.update_vertex(vertex)
def _process_events(self):
num_retries = 0
while True:
if self.event_queue.empty():
time.sleep(0.3)
if not self.event_queue.empty():
time.sleep(1)
count = 0
while not self.event_queue.empty():
count += 1
data = self.event_queue.get()
if isinstance(data, list):
for event in data:
self.processor.process_event(event)
else:
self.processor.process_event(data)
return
num_retries += 1
if num_retries == 30:
return
def _add_resources_by_type(self, consistency_interval, resource_type,
datasource_name):
def _create_resource_by_type(v_id, v_type, ds_name, timestamp,
is_deleted=False):
return self._create_resource(
vitrage_id=v_id, resource_type=v_type, datasource_name=ds_name,
sample_timestamp=timestamp, is_deleted=is_deleted)
self._add_entities_with_different_timestamps(
consistency_interval=consistency_interval,
create_func=_create_resource_by_type,
category=EntityCategory.RESOURCE,
datasource_name=datasource_name, resource_type=resource_type)
def _add_alarms_by_type(
self, consistency_interval, alarm_type):
def _create_alarm_by_type(v_id, v_type, ds_name, timestamp,
is_deleted=False):
return self._create_alarm(
vitrage_id=v_id, alarm_type=v_type, datasource_name=ds_name,
project_id=None, vitrage_resource_project_id=None,
metadata=None, vitrage_sample_timestamp=timestamp,
is_deleted=is_deleted)
self._add_entities_with_different_timestamps(
consistency_interval=consistency_interval,
create_func=_create_alarm_by_type,
category=EntityCategory.ALARM,
datasource_name=alarm_type, resource_type=alarm_type)
def _add_entities_with_different_timestamps(self, consistency_interval,
create_func,
category,
datasource_name,
resource_type):
# add resources to the graph:
# - updated_resource
# - outdated_resource with an old timestamp
# - deleted_resource with an old timestamp and is_deleted==true
future_timestamp = str(datetime.datetime_delta(
2 * consistency_interval))
past_timestamp = str(datetime.datetime_delta(
-2 * consistency_interval + 1))
updated_resource = create_func(
v_id=resource_type + '1234', v_type=resource_type,
ds_name=datasource_name, timestamp=future_timestamp)
outdated_resource = create_func(
v_id=resource_type + '5678', v_type=resource_type,
ds_name=datasource_name, timestamp=past_timestamp)
deleted_resource = create_func(
v_id=resource_type + '9999', v_type=resource_type,
ds_name=datasource_name, timestamp=past_timestamp, is_deleted=True)
self.graph.add_vertex(updated_resource)
self.graph.add_vertex(outdated_resource)
self.graph.add_vertex(deleted_resource)
# get the list of vertices
resource_vertices = self.processor.entity_graph.get_vertices({
VProps.VITRAGE_CATEGORY: category,
VProps.VITRAGE_TYPE: resource_type
})
self.assertThat(resource_vertices, matchers.HasLength(3),
'Wrong number of vertices of type %s', resource_type)